Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

AXI Lite interconnect in N to 1 configuration #54

Open
Twistix opened this issue May 2, 2023 · 2 comments
Open

AXI Lite interconnect in N to 1 configuration #54

Twistix opened this issue May 2, 2023 · 2 comments

Comments

@Twistix
Copy link

Twistix commented May 2, 2023

Hi Mr Forencich,

First of all, thank you very much for all your work on this repository and for publishing this.

I'm currently trying tu use your axil_interconnect IP in a N to 1 configuration, in order to connect several Masters outputs to a single Slave input.

However, I have a problem using this module. I tried to do a test-bench with Cocotb with the following setup for the axil_interconnect component :

S_COUNT = 2,
M_COUNT = 1,
DATA_WITH = 32,
ADDR_WIDTH = 32,
M_BASE_ADDR = 0,
M_ADDR_WIDTH = 32

In the Cocotb test-bench I then defined 2 AxiLiteMaster connected to the 2 input ports and an AxiLiteRam on the output bus. But during the execution of the test, it blocks when writing on the input ports.

I guess I'm setting up the parameters wrong, I'm having trouble understanding the purpose of M_BASE_ADDR and M_ADDR_WIDTH. Could you please give me some advice on how to get the AXI Lite interconnect to work in an N to 1 configuration?

Thanks in advance :)

@alexforencich
Copy link
Owner

Odd, the integration tests definitely test the module in a similar configuration: https://github.com/alexforencich/verilog-axi/blob/master/tb/axil_interconnect/test_axil_interconnect.py#L215-L216 . Well, S_COUNT 4, M_COUNT 1 is definitely tested, although M_ADDR_WIDTH I think is set to 24 instead of 32. I did just test this configuration on my end, and it seems to work fine. Can you perhaps post your whole testbench or a waveform dump or something that I can take a look at? Only thing I can think of maybe is some sort of X-propagation issue or something in the simulator. Does it make any difference if you explicitly specify the widths, M_BASE_ADDR = 32'd0, M_ADDR_WIDTH = 32'd32?

M_BASE_ADDR and M_ADDR_WIDTH control the address decoding for the various downstream components. Effectively, M_BASE_ADDR defines the mask of which bits are used for routing, and M_BASE_ADDR provides the addresses. All regions for all downstream components need to have non-overlapping assignments so that requests can be routed appropriately. If you set M_BASE_ADDR to 0, then there is a routine that will compute base addresses automatically based on M_ADDR_WIDTH. In your case with M_COUNT and M_REGIONS set to 1 and M_ADDR_WIDTH = ADDR_WIDTH, this is basically a degenerate case where there is no address decoding - no routing needs to be done, and all of the address bits get passed through to the single downstream device.

@Twistix
Copy link
Author

Twistix commented May 24, 2023

Hi,
Thank you for your feedback.

I tested by setting 32'd32 and 32'd24 for M_ADDR_WIDTH but without success either.

Here is the wrapper I made for axil_interconnect :

`timescale 1ns / 1ps

module axi_interconnect_ip #(
	parameter AXI_DATA_WIDTH = 32,
	parameter AXI_ADDR_WIDTH = 32
)
(
	// Clock and reset
	input			clk,
	input			rst,

	// AXI Slave in 0
	input [AXI_ADDR_WIDTH-1:0]	S00_AXI_awaddr,  
	input [2:0]					S00_AXI_awprot,  
	input						S00_AXI_awvalid, 
	output						S00_AXI_awready, 
	input [AXI_DATA_WIDTH-1:0]		S00_AXI_wdata, 	
	input [AXI_DATA_WIDTH/8-1:0]	S00_AXI_wstrb, 	
	input						S00_AXI_wvalid,  
	output						S00_AXI_wready,  
	output [1:0]					S00_AXI_bresp, 	
	output						S00_AXI_bvalid,  
	input						S00_AXI_bready,  
	input [AXI_ADDR_WIDTH-1:0]	S00_AXI_araddr,  
	input [2:0]					S00_AXI_arprot,  
	input						S00_AXI_arvalid, 
	output						S00_AXI_arready, 
	output [AXI_DATA_WIDTH-1:0]	S00_AXI_rdata, 	
	output [1:0]					S00_AXI_rresp, 	
	output						S00_AXI_rvalid,  
	input						S00_AXI_rready,

	// AXI Slave in 1
	input [AXI_ADDR_WIDTH-1:0]	S01_AXI_awaddr,  
	input [2:0]					S01_AXI_awprot,  
	input						S01_AXI_awvalid, 
	output						S01_AXI_awready, 
	input [AXI_DATA_WIDTH-1:0]		S01_AXI_wdata, 	
	input [AXI_DATA_WIDTH/8-1:0]	S01_AXI_wstrb, 	
	input						S01_AXI_wvalid,  
	output						S01_AXI_wready,  
	output [1:0]					S01_AXI_bresp, 	
	output						S01_AXI_bvalid,  
	input						S01_AXI_bready,  
	input [AXI_ADDR_WIDTH-1:0]	S01_AXI_araddr,  
	input [2:0]					S01_AXI_arprot,  
	input						S01_AXI_arvalid, 
	output						S01_AXI_arready, 
	output [AXI_DATA_WIDTH-1:0]	S01_AXI_rdata, 	
	output [1:0]					S01_AXI_rresp, 	
	output						S01_AXI_rvalid,  
	input						S01_AXI_rready,  

	// AXI Master out
	output [AXI_ADDR_WIDTH-1:0]	M_AXI_awaddr,  
	output [2:0]					M_AXI_awprot,  
	output						M_AXI_awvalid, 
	input						M_AXI_awready, 
	output [AXI_DATA_WIDTH-1:0]	M_AXI_wdata, 	
	output [AXI_DATA_WIDTH/8-1:0]	M_AXI_wstrb, 	
	output						M_AXI_wvalid,  
	input						M_AXI_wready,  
	input [1:0]					M_AXI_bresp, 	
	input						M_AXI_bvalid,  
	output						M_AXI_bready,  
	output [AXI_ADDR_WIDTH-1:0]	M_AXI_araddr,  
	output [2:0]					M_AXI_arprot,  
	output						M_AXI_arvalid, 
	input						M_AXI_arready, 
	input [AXI_DATA_WIDTH-1:0]		M_AXI_rdata, 	
	input [1:0]					M_AXI_rresp, 	
	input						M_AXI_rvalid,  
	output						M_AXI_rready
);


axil_interconnect #( 
	.S_COUNT(2), 
	.M_COUNT(1), 
	.DATA_WIDTH(AXI_DATA_WIDTH), 
	.ADDR_WIDTH(AXI_ADDR_WIDTH),
	.M_BASE_ADDR(32'd0),
	.M_ADDR_WIDTH(32'd32)
)
axil_interconnect_inst (
	.clk				(clk),
	.rst				(rst),

	.s_axil_awaddr		({S01_AXI_awaddr,S00_AXI_awaddr}),
	.s_axil_awprot		({S01_AXI_awprot,S00_AXI_awprot}),
	.s_axil_awvalid		({S01_AXI_awvalid,S00_AXI_awvalid}),
	.s_axil_awready	({S01_AXI_awready,S00_AXI_awready}),
	.s_axil_wdata		({S01_AXI_wdata,S00_AXI_wdata}),
	.s_axil_wstrb		({S01_AXI_wstrb,S00_AXI_wstrb}),
	.s_axil_wvalid		({S01_AXI_wvalid,S00_AXI_wvalid}),
	.s_axil_wready		({S01_AXI_wready,S00_AXI_wready}),
	.s_axil_bresp		({S01_AXI_bresp,S00_AXI_bresp}),
	.s_axil_bvalid		({S01_AXI_bvalid,S00_AXI_bvalid}),
	.s_axil_bready		({S01_AXI_bready,S00_AXI_bready}),
	.s_axil_araddr		({S01_AXI_araddr,S00_AXI_araddr}),
	.s_axil_arprot		({S01_AXI_arprot,S00_AXI_arprot}),
	.s_axil_arvalid		({S01_AXI_arvalid,S00_AXI_arvalid}),
	.s_axil_arready		({S01_AXI_arready,S00_AXI_arready}),
	.s_axil_rdata		({S01_AXI_rdata,S00_AXI_rdata}),
	.s_axil_rresp		({S01_AXI_rresp,S00_AXI_rresp}),
	.s_axil_rvalid		({S01_AXI_rvalid,S00_AXI_rvalid}),
	.s_axil_rready		({S01_AXI_rready,S00_AXI_rready}),

	.m_axil_awaddr	(M_AXI_awaddr),
	.m_axil_awprot	(M_AXI_awprot),
	.m_axil_awvalid	(M_AXI_awvalid),
	.m_axil_awready	(M_AXI_awready),
	.m_axil_wdata		(M_AXI_wdata),
	.m_axil_wstrb		(M_AXI_wstrb),
	.m_axil_wvalid		(M_AXI_wvalid),
	.m_axil_wready	(M_AXI_wready),
	.m_axil_bresp		(M_AXI_bresp),
	.m_axil_bvalid		(M_AXI_bvalid),
	.m_axil_bready	(M_AXI_bready),
	.m_axil_araddr		(M_AXI_araddr),
	.m_axil_arprot		(M_AXI_arprot),
	.m_axil_arvalid		(M_AXI_arvalid),
	.m_axil_arready	(M_AXI_arready),
	.m_axil_rdata		(M_AXI_rdata),
	.m_axil_rresp		(M_AXI_rresp),
	.m_axil_rvalid		(M_AXI_rvalid),
	.m_axil_rready		(M_AXI_rready)
);

endmodule

And here is the CocoTB test bench:

import cocotb
from cocotb.triggers import RisingEdge, FallingEdge
from cocotb.clock import Clock
from cocotbext.axi import AxiLiteBus, AxiLiteMaster, AxiLiteRam


# Test routine
@cocotb.test()
async def test_axi_interconnect(dut):
	# DUT ports
	clk = dut.clk
	rst = dut.rst

	# AXI Lite Bus
	master0 = AxiLiteMaster(AxiLiteBus.from_prefix(dut, "S00_AXI"), clk, rst)
	ram0 = AxiLiteRam(AxiLiteBus.from_prefix(dut, "M_AXI"), clk, rst, size=2**32)

	# Clock Generation
	cocotb.start_soon(Clock(clk, period=10, units="ns").start())

	# Reseting the DUT
	rst.value = 1
	for i in range(5):
		await FallingEdge(clk)
	rst.value = 0
	await FallingEdge(clk)

	# Testing the DUT
	await master0.write(0x2, b'test')

In the waveform I get, it seems that the slave inputs of the interconnect never pass awready to 1, so maybe that's why the master connected to the input waits forever when writing?

image

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants