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:
Sean Anderson 2023-03-05 14:23:01 -05:00
parent 1bbb6d7f41
commit 58cebe5ac2
2 changed files with 16 additions and 13 deletions

View File

@ -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

View File

@ -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()