uart_tx: Fix AXIS handshaking
AXI stream data is transferred based on the current values of the signals,
not the previous ones. This will cause problems if the other end isn't
valid all the time. Fix this, and amend the testbench to test it.
Fixes: e44d381
("Add UART transmit module")
Signed-off-by: Sean Anderson <seanga2@gmail.com>
This commit is contained in:
parent
1bbb6d7f41
commit
58cebe5ac2
|
@ -1,6 +1,6 @@
|
|||
// SPDX-License-Identifier: AGPL-3.0-Only
|
||||
/*
|
||||
* Copyright (C) 2022 Sean Anderson <seanga2@gmail.com>
|
||||
* Copyright (C) 2023 Sean Anderson <seanga2@gmail.com>
|
||||
*
|
||||
* 8n1@115200; no one uses anything else (and neither do I)
|
||||
*/
|
||||
|
@ -25,8 +25,7 @@ module uart_tx (
|
|||
/* 31 cycles, for 4M baud with a 125 MHz clock */
|
||||
parameter FAST_VALUE = 11'h68e;
|
||||
|
||||
reg [7:0] data_last;
|
||||
reg valid_last, ready_next;
|
||||
reg ready_next;
|
||||
reg [10:0] lfsr, lfsr_next;
|
||||
reg [3:0] counter, counter_next;
|
||||
reg [8:0] bits, bits_next;
|
||||
|
@ -48,16 +47,15 @@ module uart_tx (
|
|||
bits_next = { 1'b1, bits[8:1] };
|
||||
end
|
||||
|
||||
if (valid_last && ready) begin
|
||||
if (valid && ready) begin
|
||||
ready_next = 0;
|
||||
counter_next = 9;
|
||||
lfsr_next = high_speed ? FAST_VALUE : SLOW_VALUE;
|
||||
bits_next = { data_last, 1'b0 };
|
||||
bits_next = { data, 1'b0 };
|
||||
end
|
||||
end
|
||||
|
||||
always @(posedge clk) begin
|
||||
data_last <= data;
|
||||
counter <= counter_next;
|
||||
lfsr <= lfsr_next;
|
||||
end
|
||||
|
@ -65,14 +63,11 @@ module uart_tx (
|
|||
always @(posedge clk, posedge rst) begin
|
||||
if (rst) begin
|
||||
ready <= 1'b1;
|
||||
valid_last <= 1'b0;
|
||||
bits <= 9'h1ff;
|
||||
end else begin
|
||||
ready <= ready_next;
|
||||
valid_last <= valid;
|
||||
bits <= bits_next;
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
endmodule
|
||||
|
|
|
@ -4,10 +4,12 @@
|
|||
import cocotb
|
||||
from cocotb.binary import BinaryValue
|
||||
from cocotb.clock import Clock
|
||||
from cocotb.regression import TestFactory
|
||||
from cocotb.triggers import FallingEdge, Timer
|
||||
from cocotb.utils import get_sim_time, get_sim_steps
|
||||
|
||||
from .axis_replay_buffer import send_packet
|
||||
from .util import timeout
|
||||
|
||||
BAUD = 4e6
|
||||
BIT_STEPS = get_sim_steps(1 / BAUD, 'sec', round_mode='round')
|
||||
|
@ -29,8 +31,8 @@ async def getchar(signals):
|
|||
assert signals['tx'].value
|
||||
return result
|
||||
|
||||
@cocotb.test(timeout_time=1, timeout_unit='ms')
|
||||
async def test_tx(uart):
|
||||
@timeout(50, 'us')
|
||||
async def test_tx(uart, ratio):
|
||||
uart.clk.value = BinaryValue('Z')
|
||||
uart.rst.value = 1
|
||||
uart.valid.value = 0
|
||||
|
@ -43,12 +45,14 @@ async def test_tx(uart):
|
|||
|
||||
msg = b"Hello"
|
||||
|
||||
await cocotb.start(send_packet({
|
||||
axis = {
|
||||
'clk': uart.clk,
|
||||
'data': uart.data,
|
||||
'valid': uart.valid,
|
||||
'ready': uart.ready,
|
||||
}, msg))
|
||||
}
|
||||
|
||||
await cocotb.start(send_packet(axis, msg, ratio))
|
||||
|
||||
then = get_sim_time()
|
||||
for c in msg:
|
||||
|
@ -61,3 +65,7 @@ async def test_tx(uart):
|
|||
expected = BIT_STEPS * (10 * len(msg) - 0.5)
|
||||
actual = now - then
|
||||
assert abs(actual - expected) / expected < 0.01
|
||||
|
||||
uart_tests = TestFactory(test_tx)
|
||||
uart_tests.add_option('ratio', (1, int(125e6 / BAUD * 10)))
|
||||
uart_tests.generate_tests()
|
||||
|
|
Loading…
Reference in New Issue