axis_wb_bridge: Fix AXIS master

The AXI stream master doesn't cope with slaves that aren't ready all the
time. There are two separate issues: first, the data was only valid for one
cycle. Second, the handshake logic was incorrect. Rectify these, and modify
the testbench to test for this condition.

Fixes: 7514231 ("Add AXIS-Wishbone bridge")
Signed-off-by: Sean Anderson <seanga2@gmail.com>
This commit is contained in:
Sean Anderson 2023-03-04 14:32:04 -05:00
parent d2b4351899
commit 10a4199381
2 changed files with 17 additions and 12 deletions

View File

@ -46,7 +46,7 @@ module axis_wb_bridge (
localparam RESP1 = 9; localparam RESP1 = 9;
localparam RESP0 = 10; localparam RESP0 = 10;
reg s_axis_ready_next, s_axis_valid_last, m_axis_ready_last, m_axis_valid_next; reg s_axis_ready_next, s_axis_valid_last, m_axis_valid_next;
reg [7:0] s_axis_data_last, m_axis_data_next; reg [7:0] s_axis_data_last, m_axis_data_next;
reg wb_ack_last, wb_err_last; reg wb_ack_last, wb_err_last;
reg wb_stb_next, wb_we_next; reg wb_stb_next, wb_we_next;
@ -58,7 +58,7 @@ module axis_wb_bridge (
always @(*) begin always @(*) begin
s_axis_ready_next = s_axis_ready; s_axis_ready_next = s_axis_ready;
m_axis_valid_next = m_axis_valid; m_axis_valid_next = m_axis_valid;
m_axis_data_next = 8'bX; m_axis_data_next = m_axis_data;
wb_cyc = wb_stb; wb_cyc = wb_stb;
wb_stb_next = wb_stb; wb_stb_next = wb_stb;
@ -137,15 +137,15 @@ module axis_wb_bridge (
overflow_latch_next = 0; overflow_latch_next = 0;
state_next = wb_we || wb_err ? RESP0 : RESP2; state_next = wb_we || wb_err ? RESP0 : RESP2;
end end
RESP2: if (m_axis_ready_last) begin RESP2: if (m_axis_ready && m_axis_valid) begin
m_axis_data_next = wb_data_latch[15:8]; m_axis_data_next = wb_data_latch[15:8];
state_next = RESP1; state_next = RESP1;
end end
RESP1: if (m_axis_ready_last) begin RESP1: if (m_axis_ready && m_axis_valid) begin
m_axis_data_next = wb_data_latch[7:0]; m_axis_data_next = wb_data_latch[7:0];
state_next = RESP0; state_next = RESP0;
end end
RESP0: if (m_axis_ready_last) begin RESP0: if (m_axis_ready && m_axis_valid) begin
m_axis_valid_next = 0; m_axis_valid_next = 0;
s_axis_ready_next = 1; s_axis_ready_next = 1;
state_next = IDLE; state_next = IDLE;
@ -167,7 +167,6 @@ module axis_wb_bridge (
if (rst) begin if (rst) begin
s_axis_ready <= 1; s_axis_ready <= 1;
s_axis_valid_last <= 0; s_axis_valid_last <= 0;
m_axis_ready_last <= 0;
m_axis_valid <= 0; m_axis_valid <= 0;
wb_ack_last <= 0; wb_ack_last <= 0;
wb_err_last <= 0; wb_err_last <= 0;
@ -177,7 +176,6 @@ module axis_wb_bridge (
end else begin end else begin
s_axis_ready <= s_axis_ready_next; s_axis_ready <= s_axis_ready_next;
s_axis_valid_last <= s_axis_valid; s_axis_valid_last <= s_axis_valid;
m_axis_ready_last <= m_axis_ready;
m_axis_valid <= m_axis_valid_next; m_axis_valid <= m_axis_valid_next;
wb_ack_last <= wb_ack; wb_ack_last <= wb_ack;
wb_err_last <= wb_err; wb_err_last <= wb_err;

View File

@ -4,11 +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 .axis_replay_buffer import send_packet, recv_packet from .axis_replay_buffer import send_packet, recv_packet
from .mdio import wb_read, wb_write, wb_err from .mdio import wb_read, wb_write, wb_err
from .util import BIT, GENMASK from .util import BIT, ClockEnable, GENMASK, timeout
CMD_CLEAR = BIT(0) CMD_CLEAR = BIT(0)
CMD_WE = BIT(1) CMD_WE = BIT(1)
@ -68,8 +69,8 @@ class Encoder:
self.last_addr = (addr & ~GENMASK(7, 0)) | ((addr + postinc) & GENMASK(7, 0)) self.last_addr = (addr & ~GENMASK(7, 0)) | ((addr + postinc) & GENMASK(7, 0))
return (cmd, *addr_bytes, *data_bytes) return (cmd, *addr_bytes, *data_bytes)
@cocotb.test(timeout_time=10, timeout_unit='us') @timeout(10, 'us')
async def test_bridge(bridge): async def test_bridge(bridge, in_ratio, out_ratio):
bridge.clk.value = BinaryValue('Z') bridge.clk.value = BinaryValue('Z')
bridge.rst.value = 1 bridge.rst.value = 1
bridge.s_axis_valid.value = 0 bridge.s_axis_valid.value = 0
@ -82,6 +83,7 @@ async def test_bridge(bridge):
bridge.rst.value = 0 bridge.rst.value = 0
await cocotb.start(Clock(bridge.clk, 8, units='ns').start()) await cocotb.start(Clock(bridge.clk, 8, units='ns').start())
await FallingEdge(bridge.clk) await FallingEdge(bridge.clk)
await cocotb.start(ClockEnable(bridge.clk, bridge.m_axis_ready, out_ratio))
s_axis = { s_axis = {
'clk': bridge.clk, 'clk': bridge.clk,
@ -112,7 +114,7 @@ async def test_bridge(bridge):
e = Encoder() e = Encoder()
async def read(addr, data, postinc=False, resp=0): async def read(addr, data, postinc=False, resp=0):
await send_packet(s_axis, e.encode(addr, None, postinc)) await send_packet(s_axis, e.encode(addr, None, postinc), in_ratio)
bridge.overflow.value = bool(resp & STATUS_OVERFLOW) bridge.overflow.value = bool(resp & STATUS_OVERFLOW)
if resp & STATUS_ERR: if resp & STATUS_ERR:
@ -125,7 +127,7 @@ async def test_bridge(bridge):
await recv_packet(m_axis, (resp, *data.to_bytes(2, 'big'))) await recv_packet(m_axis, (resp, *data.to_bytes(2, 'big')))
async def write(addr, data, postinc=False, resp=STATUS_WE): async def write(addr, data, postinc=False, resp=STATUS_WE):
await send_packet(s_axis, e.encode(addr, data, postinc)) await send_packet(s_axis, e.encode(addr, data, postinc), in_ratio)
bridge.overflow.value = bool(resp & STATUS_OVERFLOW) bridge.overflow.value = bool(resp & STATUS_OVERFLOW)
if resp & STATUS_ERR: if resp & STATUS_ERR:
@ -164,3 +166,8 @@ async def test_bridge(bridge):
await read(7, 8, resp=STATUS_ERR) await read(7, 8, resp=STATUS_ERR)
await read(9, 10, resp=STATUS_OVERFLOW) await read(9, 10, resp=STATUS_OVERFLOW)
await write(11, 12) await write(11, 12)
bridge_tests = TestFactory(test_bridge)
bridge_tests.add_option('in_ratio', (1, 4))
bridge_tests.add_option('out_ratio', (1, 4))
bridge_tests.generate_tests()