cancel
Showing results for 
Search instead for 
Did you mean: 
Highlighted
Explorer
Explorer
3,745 Views
Registered: ‎02-27-2008

Vivado AXI Interconnect "tricell" errors with wide buses

Jump to solution

I have a Vivado 2013.2 design with a Microblaze, MIG DDR memory, custom DMA interface, and AXI Interconnect.  The MIG and Interconnect are set to bus widths of 256 bits.  The Microblaze AXI bus widths are the usual 32 bits.  The custom DMA is writing occasional bursts into memory.  The custom DMA module is external to the block design - I give the Interconnect 3 slave slots (2 microblaze, 1 dma) and 1 master slot (DDR), and make the DMA AXI interface ports external.  I was attempting to give it as wide a bus as possible to minimize the time a burst takes.  I discovered the following strange (to me) behavior:

 

If the DMA AXI bus width is 64 bits, the block design passes validation, and everything compiles and works.

 

If the DMA AXI bus width is set to 128 or 256 bits, compiling the design fails, giving errors such as:

 

[Project 1-486] Could not resolve non-primitive black box cell 'tricell' instantiated as 'xbar_i_16' [".../sources_1/bd/cpu/hdl/cpu.vhd":1568]

The errors are occurring in the VHDL files the block design auto-generates, and are all related to the various internal crossbars and interconnects.  Many of them appear to be on the interfaces to the Microblaze, which should not be changing as a function of the external DMA width.

 

Has anyone else seen similar behavior, or found a work-around?

 

Thanks,

 

-Greg

0 Kudos
1 Solution

Accepted Solutions
Highlighted
Explorer
Explorer
4,732 Views
Registered: ‎02-27-2008

Re: Vivado AXI Interconnect "tricell" errors with wide buses

Jump to solution

Changing the CONFIG setting for the AXI DMA port from READ_WRITE to WRITE_ONLY eliminated the tricell errors (my custom DMA is only writing to RAM). I do not understand why this change should matter for 128/256 bit buses but not for 64 bit buses. Oh well, onwards.

-Greg

View solution in original post

0 Kudos
3 Replies
Highlighted
Explorer
Explorer
4,733 Views
Registered: ‎02-27-2008

Re: Vivado AXI Interconnect "tricell" errors with wide buses

Jump to solution

Changing the CONFIG setting for the AXI DMA port from READ_WRITE to WRITE_ONLY eliminated the tricell errors (my custom DMA is only writing to RAM). I do not understand why this change should matter for 128/256 bit buses but not for 64 bit buses. Oh well, onwards.

-Greg

View solution in original post

0 Kudos
Highlighted
Contributor
Contributor
3,709 Views
Registered: ‎07-19-2013

Re: Vivado AXI Interconnect "tricell" errors with wide buses

Jump to solution

Greg,

 

I just started running into this error yesterday after I added an VDMA and AXI interconnect block to my design. I was able to build once by changing the VDMA parameters but now it won't build at all.

 

I saw on another post that you got around the error by creating custom IP that basically passes the Master to the Slave. Are there any more details you can add or is it really that simple?

 

Thanks,

 

Jeff

 

0 Kudos
Highlighted
Explorer
Explorer
3,704 Views
Registered: ‎02-27-2008

Re: Vivado AXI Interconnect "tricell" errors with wide buses

Jump to solution

Hi Jeff,

 

You have my sympathy!  These tricell errors have been very frustrating.  I've been trying whatever I can think of to work around them.  They seem to stem from some bug in the automatic bus connections in block designs.  Making a custom IP passthrough fixed it in one instance for me - possibly because it was forcing the data/address/id widths?  It really was simple, the code follows:

 

library ieee;
use ieee.std_logic_1164.all;

entity axi_link is
	port (
		-- System
		M_AXI_ACLK: in std_logic;
--		M_AXI_ARESETN: in std_logic;
		-- Write address
		M_AXI_AWADDR: out std_logic_vector(31 downto 0);
		M_AXI_AWLEN: out std_logic_vector(7 downto 0);
		M_AXI_AWSIZE: out std_logic_vector(2 downto 0);
		M_AXI_AWBURST: out std_logic_vector(1 downto 0);
		M_AXI_AWCACHE: out std_logic_vector(3 downto 0);
		M_AXI_AWVALID: out std_logic;
		M_AXI_AWREADY: in std_logic;
		-- Write data
		M_AXI_WDATA: out std_logic_vector(63 downto 0);
		M_AXI_WSTRB: out std_logic_vector(7 downto 0);
		M_AXI_WLAST: out std_logic;
		M_AXI_WVALID: out std_logic;
		M_AXI_WREADY: in std_logic;
		-- Write response
		M_AXI_BRESP: in std_logic_vector(1 downto 0);
		M_AXI_BVALID: in std_logic;
		M_AXI_BREADY: out std_logic;
		-- Read address
		M_AXI_ARADDR: out std_logic_vector(31 downto 0);
		M_AXI_ARLEN: out std_logic_vector(7 downto 0);
		M_AXI_ARSIZE: out std_logic_vector(2 downto 0);
		M_AXI_ARBURST: out std_logic_vector(1 downto 0);
		M_AXI_ARCACHE: out std_logic_vector(3 downto 0);
		M_AXI_ARVALID: out std_logic;
		M_AXI_ARREADY: in std_logic;
		-- Read data
		M_AXI_RDATA: in std_logic_vector(63 downto 0);
		M_AXI_RRESP: in std_logic_vector(1 downto 0);
		M_AXI_RLAST: in std_logic;
		M_AXI_RVALID: in std_logic;
		M_AXI_RREADY: out std_logic;

		-- System
		S_AXI_ACLK: in std_logic;
--		S_AXI_ARESETN: in std_logic;
		-- Write address
		S_AXI_AWADDR: in std_logic_vector(31 downto 0);
		S_AXI_AWLEN: in std_logic_vector(7 downto 0);
		S_AXI_AWSIZE: in std_logic_vector(2 downto 0);
		S_AXI_AWBURST: in std_logic_vector(1 downto 0);
		S_AXI_AWCACHE: in std_logic_vector(3 downto 0);
		S_AXI_AWVALID: in std_logic;
		S_AXI_AWREADY: out std_logic;
		-- Write data
		S_AXI_WDATA: in std_logic_vector(63 downto 0);
		S_AXI_WSTRB: in std_logic_vector(7 downto 0);
		S_AXI_WLAST: in std_logic;
		S_AXI_WVALID: in std_logic;
		S_AXI_WREADY: out std_logic;
		-- Write response
		S_AXI_BRESP: out std_logic_vector(1 downto 0);
		S_AXI_BVALID: out std_logic;
		S_AXI_BREADY: in std_logic;
		-- Read address
		S_AXI_ARADDR: in std_logic_vector(31 downto 0);
		S_AXI_ARLEN: in std_logic_vector(7 downto 0);
		S_AXI_ARSIZE: in std_logic_vector(2 downto 0);
		S_AXI_ARBURST: in std_logic_vector(1 downto 0);
		S_AXI_ARCACHE: in std_logic_vector(3 downto 0);
		S_AXI_ARVALID: in std_logic;
		S_AXI_ARREADY: out std_logic;
		-- Read data
		S_AXI_RDATA: out std_logic_vector(63 downto 0);
		S_AXI_RRESP: out std_logic_vector(1 downto 0);
		S_AXI_RLAST: out std_logic;
		S_AXI_RVALID: out std_logic;
		S_AXI_RREADY: in std_logic
	);
end axi_link;

architecture Behavioral of axi_link is

begin

	-- System
--	S_AXI_ACLK <= M_AXI_ACLK;
--	S_AXI_ARESETN <= M_AXI_ARESETN;
	-- Write address
	M_AXI_AWADDR <= S_AXI_AWADDR;
	M_AXI_AWLEN <= S_AXI_AWLEN;
	M_AXI_AWSIZE <= S_AXI_AWSIZE;
	M_AXI_AWBURST <= S_AXI_AWBURST;
	M_AXI_AWCACHE <= S_AXI_AWCACHE;
	M_AXI_AWVALID <= S_AXI_AWVALID;
	S_AXI_AWREADY <= M_AXI_AWREADY;
	-- Write data
	M_AXI_WDATA <= S_AXI_WDATA;
	M_AXI_WSTRB <= S_AXI_WSTRB; 
	M_AXI_WLAST <= S_AXI_WLAST;
	M_AXI_WVALID <= S_AXI_WVALID;
	S_AXI_WREADY <= M_AXI_WREADY;
	-- Write response
	S_AXI_BRESP <= M_AXI_BRESP;
	S_AXI_BVALID <= M_AXI_BVALID;
	M_AXI_BREADY <= S_AXI_BREADY;
	-- Read address
	M_AXI_ARADDR <= S_AXI_ARADDR;
	M_AXI_ARLEN <= S_AXI_ARLEN;
	M_AXI_ARSIZE <= S_AXI_ARSIZE;
	M_AXI_ARBURST <= S_AXI_ARBURST;
	M_AXI_ARCACHE <= S_AXI_ARCACHE;
	M_AXI_ARVALID <= S_AXI_ARVALID;
	S_AXI_ARREADY <= M_AXI_ARREADY;
	-- Read data
	S_AXI_RDATA <= M_AXI_RDATA; 
	S_AXI_RRESP <= M_AXI_RRESP;
	S_AXI_RLAST <= M_AXI_RLAST;
	S_AXI_RVALID <= M_AXI_RVALID;
	M_AXI_RREADY <= S_AXI_RREADY;

end Behavioral;

 I'm not sure if this approach works in all instances - in my more recent experiments, I was not using the passthrough, and eventually got it to work.  I have not been able to create a simple test case demonstrating the fault.  So far, it's always been with more complex designs, wider buses, etc.  This kind of monkeying around should not be necessary for just connecting an AXI bus.  Hopefully Xilinx is looking into it.

 

-Greg

0 Kudos