Axi stream receiving 8b chunks when sending 32b data
Closed this issue · 3 comments
Hi!
Before everything, I want to thank you for this fantastic cocotb extension. The axi-lite module helped test for testing my modules. Recently, I wanted to use the AXI stream module for digital filter design. I've checked the test directory, and based on that; I created a simple example of a system verilog module that has a slave and master bus with 32b data width:
`timescale 1ns / 1ns
module axis_if #
(
parameter DATA_WIDTH = 32,
parameter KEEP_WIDTH = (DATA_WIDTH/8)
)
(
input logic clk,
input logic rst,
// Stream slave interface
input logic [DATA_WIDTH-1:0] s_axis_tdata, // optional, needed for data
input logic s_axis_tvalid, // required
output logic s_axis_tready, // optional, highly recommended
input logic [KEEP_WIDTH-1:0] s_axis_tkeep, // optional, needed for simulation
// Stream master interface
output logic [DATA_WIDTH-1:0] m_axis_tdata, // optional, needed for data
output logic m_axis_tvalid, // required
input logic m_axis_tready, // optional, highly recommended
output logic [KEEP_WIDTH-1:0] m_axis_tkeep // optional, needed for simulation
);
initial begin
$dumpfile("axis.vcd");
$dumpvars;
end
assign m_axis_tdata = s_axis_tdata;
assign m_axis_tvalid = s_axis_tvalid;
assign s_axis_tready = s_axis_tready;
assign m_axis_tkeep = s_axis_tkeep;
endmodule
On the python side, I have an equally simple test of sending 3 x 32b data packets, and receiving them:
import os
from pathlib import Path
import cocotb
from cocotb.clock import Clock
from cocotb.triggers import RisingEdge
from cocotb.runner import get_runner
from cocotbext.axi import AxiStreamFrame, AxiStreamBus, AxiStreamSource, AxiStreamSink, AxiStreamMonitor
class TB:
def __init__(self, dut):
self.dut = dut
cocotb.start_soon(Clock(dut.clk, 2, units="ns").start())
self.source = AxiStreamSource(AxiStreamBus.from_prefix(dut, "s_axis"), dut.clk, dut.rst)
self.sink = AxiStreamSink(AxiStreamBus.from_prefix(dut, "m_axis"), dut.clk, dut.rst)
# self.monitor = AxiStreamMonitor(AxiStreamBus.from_prefix(dut, "axis"), dut.clk, dut.rst)
async def reset(self):
self.dut.rst.setimmediatevalue(0)
await RisingEdge(self.dut.clk)
await RisingEdge(self.dut.clk)
self.dut.rst.value = 1
await RisingEdge(self.dut.clk)
await RisingEdge(self.dut.clk)
self.dut.rst.value = 0
await RisingEdge(self.dut.clk)
await RisingEdge(self.dut.clk)
@cocotb.test()
async def run_test(dut):
tb = TB(dut)
await tb.reset()
test_frames = [b'10101010101010101010101010101010', b'11001100110011001100110011001100', b'11110000111100001111000011110000']
for frame in test_frames:
tx_frame = AxiStreamFrame(frame)
await tb.source.send(tx_frame)
print(f"Sent frame {frame}")
for frame in test_frames:
rx_frame = await tb.sink.read()
print(f"Received frame {rx_frame}")
assert tb.sink.empty()
await RisingEdge(dut.clk)
await RisingEdge(dut.clk)
def test_axis_runner():
hdl_toplevel_lang = os.getenv("HDL_TOPLEVEL_LANG", "verilog")
sim = os.getenv("SIM", "icarus")
proj_path = Path(__file__).resolve().parent
verilog_sources = [proj_path / "axis_if.sv"]
runner = get_runner(sim)
runner.build(
verilog_sources=verilog_sources,
hdl_toplevel="axis_if",
always=True,
)
runner.test(hdl_toplevel="axis_if", test_module="test_axis,")
if __name__ == "__main__":
test_axis_runner()
With make file:
TOPLEVEL_LANG ?= verilog
VERILOG_SOURCES += $(PWD)/axis_if.sv
MODULE = test_axis
TOPLEVEL = axis_if
include $(shell cocotb-config --makefiles)/Makefile.sim
In the terminal, the Axi stream correctly detects the data width to be 32b, but the received frame only has 8b of data:
0.00ns INFO cocotb.regression Found test test_axis.run_test
0.00ns INFO cocotb.regression running run_test (1/1)
0.00ns INFO cocotb.axis_if.s_axis AXI stream source
0.00ns INFO cocotb.axis_if.s_axis cocotbext-axi version 0.1.24
0.00ns INFO cocotb.axis_if.s_axis Copyright (c) 2020 Alex Forencich
0.00ns INFO cocotb.axis_if.s_axis https://github.com/alexforencich/cocotbext-axi
0.00ns INFO cocotb.axis_if.s_axis AXI stream source configuration:
0.00ns INFO cocotb.axis_if.s_axis Byte size: 8 bits
0.00ns INFO cocotb.axis_if.s_axis Data width: 32 bits (4 bytes)
0.00ns INFO cocotb.axis_if.s_axis AXI stream source signals:
0.00ns INFO cocotb.axis_if.s_axis tdata width: 32 bits
0.00ns INFO cocotb.axis_if.s_axis tdest: not present
0.00ns INFO cocotb.axis_if.s_axis tid: not present
0.00ns INFO cocotb.axis_if.s_axis tkeep width: 4 bits
0.00ns INFO cocotb.axis_if.s_axis tlast: not present
0.00ns INFO cocotb.axis_if.s_axis tready width: 1 bits
0.00ns INFO cocotb.axis_if.s_axis tuser: not present
0.00ns INFO cocotb.axis_if.s_axis tvalid width: 1 bits
0.00ns INFO cocotb.axis_if.s_axis Reset de-asserted
0.00ns INFO cocotb.axis_if.m_axis AXI stream sink
0.00ns INFO cocotb.axis_if.m_axis cocotbext-axi version 0.1.24
0.00ns INFO cocotb.axis_if.m_axis Copyright (c) 2020 Alex Forencich
0.00ns INFO cocotb.axis_if.m_axis https://github.com/alexforencich/cocotbext-axi
0.00ns INFO cocotb.axis_if.m_axis AXI stream sink configuration:
0.00ns INFO cocotb.axis_if.m_axis Byte size: 8 bits
0.00ns INFO cocotb.axis_if.m_axis Data width: 32 bits (4 bytes)
0.00ns INFO cocotb.axis_if.m_axis AXI stream sink signals:
0.00ns INFO cocotb.axis_if.m_axis tdata width: 32 bits
0.00ns INFO cocotb.axis_if.m_axis tdest: not present
0.00ns INFO cocotb.axis_if.m_axis tid: not present
0.00ns INFO cocotb.axis_if.m_axis tkeep width: 4 bits
0.00ns INFO cocotb.axis_if.m_axis tlast: not present
0.00ns INFO cocotb.axis_if.m_axis tready width: 1 bits
0.00ns INFO cocotb.axis_if.m_axis tuser: not present
0.00ns INFO cocotb.axis_if.m_axis tvalid width: 1 bits
0.00ns INFO cocotb.axis_if.m_axis Reset de-asserted
VCD info: dumpfile axis.vcd opened for output.
VCD warning: $dumpvars: Unsupported argument type (vpiPackage)
2.00ns INFO cocotb.axis_if.s_axis Reset asserted
2.00ns INFO cocotb.axis_if.m_axis Reset asserted
6.00ns INFO cocotb.axis_if.s_axis Reset de-asserted
6.00ns INFO cocotb.axis_if.m_axis Reset de-asserted
Sent frame b'10101010101010101010101010101010'
Sent frame b'11001100110011001100110011001100'
Sent frame b'11110000111100001111000011110000'
12.00ns INFO cocotb.axis_if.s_axis TX frame: AxiStreamFrame(tdata=bytearray(b'10101010101010101010101010101010'), tkeep=None, tid=None, tdest=None, tuser=None, sim_time_start=12000, sim_time_end=None)
14.00ns INFO cocotb.axis_if.m_axis RX frame: AxiStreamFrame(tdata=bytearray(b'1010'), tkeep=[1, 1, 1, 1], tid=[], tdest=[], tuser=[], sim_time_start=14000, sim_time_end=14000)
Received frame [49, 48, 49, 48]
16.00ns INFO cocotb.axis_if.m_axis RX frame: AxiStreamFrame(tdata=bytearray(b'1010'), tkeep=[1, 1, 1, 1], tid=[], tdest=[], tuser=[], sim_time_start=16000, sim_time_end=16000)
Received frame [49, 48, 49, 48]
18.00ns INFO cocotb.axis_if.m_axis RX frame: AxiStreamFrame(tdata=bytearray(b'1010'), tkeep=[1, 1, 1, 1], tid=[], tdest=[], tuser=[], sim_time_start=18000, sim_time_end=18000)
Received frame [49, 48, 49, 48]
20.00ns INFO cocotb.axis_if.m_axis RX frame: AxiStreamFrame(tdata=bytearray(b'1010'), tkeep=[1, 1, 1, 1], tid=[], tdest=[], tuser=[], sim_time_start=20000, sim_time_end=20000)
22.00ns INFO cocotb.axis_if.m_axis RX frame: AxiStreamFrame(tdata=bytearray(b'1010'), tkeep=[1, 1, 1, 1], tid=[], tdest=[], tuser=[], sim_time_start=22000, sim_time_end=22000)
22.00ns INFO cocotb.regression run_test passed
Did I not read the documentation properly, or is there something that I need to set up differently to be able to work with 32b data?
Any help would be greatly appreciated.
Okay, I had a rough few days, and overlooked the byte data. So I had a nap, and my problem was solved by properly using
await tb.source.send((2251122612).to_bytes(4, byteorder='big'))
.
Please disregard my issue. The issue was with me.
I guess one thing you should think about is, do you need to work in terms of bytes or in terms of wider words. If you set KEEP_WIDTH = 1, then the AXI stream models should not slice up the cycles into bytes. Similarly, you can omit the tkeep signal and then specify byte_lanes=1 to get the same behavior.
I guess one thing you should think about is, do you need to work in terms of bytes or in terms of wider words. If you set KEEP_WIDTH = 1, then the AXI stream models should not slice up the cycles into bytes. Similarly, you can omit the tkeep signal and then specify byte_lanes=1 to get the same behavior.
Thanks for this idea. I will re-evaluate the bus characteristics, since I will work with 32b words.