From 58cebe5ac2d35e7c26211be2aa5e13b68f69f35f Mon Sep 17 00:00:00 2001 From: Sean Anderson Date: Sun, 5 Mar 2023 14:23:01 -0500 Subject: [PATCH] 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 --- rtl/uart_tx.v | 13 ++++--------- tb/uart_tx.py | 16 ++++++++++++---- 2 files changed, 16 insertions(+), 13 deletions(-) diff --git a/rtl/uart_tx.v b/rtl/uart_tx.v index a03f2cb..57f7aa9 100644 --- a/rtl/uart_tx.v +++ b/rtl/uart_tx.v @@ -1,6 +1,6 @@ // SPDX-License-Identifier: AGPL-3.0-Only /* - * Copyright (C) 2022 Sean Anderson + * Copyright (C) 2023 Sean Anderson * * 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 diff --git a/tb/uart_tx.py b/tb/uart_tx.py index dfe7eb0..3169403 100644 --- a/tb/uart_tx.py +++ b/tb/uart_tx.py @@ -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()