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
|
// 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)
|
* 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 */
|
/* 31 cycles, for 4M baud with a 125 MHz clock */
|
||||||
parameter FAST_VALUE = 11'h68e;
|
parameter FAST_VALUE = 11'h68e;
|
||||||
|
|
||||||
reg [7:0] data_last;
|
reg ready_next;
|
||||||
reg valid_last, ready_next;
|
|
||||||
reg [10:0] lfsr, lfsr_next;
|
reg [10:0] lfsr, lfsr_next;
|
||||||
reg [3:0] counter, counter_next;
|
reg [3:0] counter, counter_next;
|
||||||
reg [8:0] bits, bits_next;
|
reg [8:0] bits, bits_next;
|
||||||
|
@ -48,16 +47,15 @@ module uart_tx (
|
||||||
bits_next = { 1'b1, bits[8:1] };
|
bits_next = { 1'b1, bits[8:1] };
|
||||||
end
|
end
|
||||||
|
|
||||||
if (valid_last && ready) begin
|
if (valid && ready) begin
|
||||||
ready_next = 0;
|
ready_next = 0;
|
||||||
counter_next = 9;
|
counter_next = 9;
|
||||||
lfsr_next = high_speed ? FAST_VALUE : SLOW_VALUE;
|
lfsr_next = high_speed ? FAST_VALUE : SLOW_VALUE;
|
||||||
bits_next = { data_last, 1'b0 };
|
bits_next = { data, 1'b0 };
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
always @(posedge clk) begin
|
always @(posedge clk) begin
|
||||||
data_last <= data;
|
|
||||||
counter <= counter_next;
|
counter <= counter_next;
|
||||||
lfsr <= lfsr_next;
|
lfsr <= lfsr_next;
|
||||||
end
|
end
|
||||||
|
@ -65,14 +63,11 @@ module uart_tx (
|
||||||
always @(posedge clk, posedge rst) begin
|
always @(posedge clk, posedge rst) begin
|
||||||
if (rst) begin
|
if (rst) begin
|
||||||
ready <= 1'b1;
|
ready <= 1'b1;
|
||||||
valid_last <= 1'b0;
|
|
||||||
bits <= 9'h1ff;
|
bits <= 9'h1ff;
|
||||||
end else begin
|
end else begin
|
||||||
ready <= ready_next;
|
ready <= ready_next;
|
||||||
valid_last <= valid;
|
|
||||||
bits <= bits_next;
|
bits <= bits_next;
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
endmodule
|
endmodule
|
||||||
|
|
|
@ -4,10 +4,12 @@
|
||||||
import cocotb
|
import cocotb
|
||||||
from cocotb.binary import BinaryValue
|
from cocotb.binary import BinaryValue
|
||||||
from cocotb.clock import Clock
|
from cocotb.clock import Clock
|
||||||
|
from cocotb.regression import TestFactory
|
||||||
from cocotb.triggers import FallingEdge, Timer
|
from cocotb.triggers import FallingEdge, Timer
|
||||||
from cocotb.utils import get_sim_time, get_sim_steps
|
from cocotb.utils import get_sim_time, get_sim_steps
|
||||||
|
|
||||||
from .axis_replay_buffer import send_packet
|
from .axis_replay_buffer import send_packet
|
||||||
|
from .util import timeout
|
||||||
|
|
||||||
BAUD = 4e6
|
BAUD = 4e6
|
||||||
BIT_STEPS = get_sim_steps(1 / BAUD, 'sec', round_mode='round')
|
BIT_STEPS = get_sim_steps(1 / BAUD, 'sec', round_mode='round')
|
||||||
|
@ -29,8 +31,8 @@ async def getchar(signals):
|
||||||
assert signals['tx'].value
|
assert signals['tx'].value
|
||||||
return result
|
return result
|
||||||
|
|
||||||
@cocotb.test(timeout_time=1, timeout_unit='ms')
|
@timeout(50, 'us')
|
||||||
async def test_tx(uart):
|
async def test_tx(uart, ratio):
|
||||||
uart.clk.value = BinaryValue('Z')
|
uart.clk.value = BinaryValue('Z')
|
||||||
uart.rst.value = 1
|
uart.rst.value = 1
|
||||||
uart.valid.value = 0
|
uart.valid.value = 0
|
||||||
|
@ -43,12 +45,14 @@ async def test_tx(uart):
|
||||||
|
|
||||||
msg = b"Hello"
|
msg = b"Hello"
|
||||||
|
|
||||||
await cocotb.start(send_packet({
|
axis = {
|
||||||
'clk': uart.clk,
|
'clk': uart.clk,
|
||||||
'data': uart.data,
|
'data': uart.data,
|
||||||
'valid': uart.valid,
|
'valid': uart.valid,
|
||||||
'ready': uart.ready,
|
'ready': uart.ready,
|
||||||
}, msg))
|
}
|
||||||
|
|
||||||
|
await cocotb.start(send_packet(axis, msg, ratio))
|
||||||
|
|
||||||
then = get_sim_time()
|
then = get_sim_time()
|
||||||
for c in msg:
|
for c in msg:
|
||||||
|
@ -61,3 +65,7 @@ async def test_tx(uart):
|
||||||
expected = BIT_STEPS * (10 * len(msg) - 0.5)
|
expected = BIT_STEPS * (10 * len(msg) - 0.5)
|
||||||
actual = now - then
|
actual = now - then
|
||||||
assert abs(actual - expected) / expected < 0.01
|
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