cancel
Showing results for 
Show  only  | Search instead for 
Did you mean: 
stmartin81
Adventurer
Adventurer
3,503 Views
Registered: ‎12-09-2010

Is the Xilinx provided solution for AXI4 wrapping bursts address calculation correct?

Hello,

 

I want to implement an AXI4 burst capable slave interface. When using the generator from "Create and Package IP" the logic for generating the wrap signal looks like this:

aw_wrap_en <= '1' when (((axi_awaddr AND CONV_STD_LOGIC_VECTOR(aw_wrap_size,C_S_AXI_ADDR_WIDTH)) XOR CONV_STD_LOGIC_VECTOR(aw_wrap_size,C_S_AXI_ADDR_WIDTH)) = low) else '0';

and this is the same as

aw_wrap_en <= '1' when (((axi_awaddr AND CONV_STD_LOGIC_VECTOR(aw_wrap_size,C_S_AXI_ADDR_WIDTH))) = CONV_STD_LOGIC_VECTOR(aw_wrap_size,C_S_AXI_ADDR_WIDTH)) else '0';

which looks strange to me. So that means that expression is true if the address masked by aw_wrap_size equals aw_wrap_size. When looking at the ARM specification for AXI4 (ARM IHI 0022E ID 022613, p. A3-49) it says:

Wrap_Boundary = (INT(Start_Address / (Number_Bytes * Burst_Length)) * (Number_Bytes * Burst_Length)

with

  • Start_Address = AxADDR
  • Number_Bytes = 2^AxSize
  • Burst_Length = AxLEN + 1

aw_wrap_size is defined in the template as

aw_wrap_size <= (C_S_AXI_DATA_WIDTH/8 * CONV_INTEGER(S_AXI_AWLEN));  

where I would expect it to be dependend on S_AXI_AWSIZE.

 

But let's assume that C_S_AXI_DATA_WIDTH/8 = 2^S_AXI_AWSIZE it still doesn't make a lot of sense to me:

Assume that

  • S_AXI_DATA_WIDTH = 32
  • S_AXI_AWSIZE = 2
  • S_AXI_AWLEN = 8
  • Start_Address = 96

According to the AXI4 specification this would result in a upper burst wrap boundary of:

Upper_Wrap_Boundary = (Start_Address / (2^S_AXI_AWSIZE * (S_AXI_AWLEN + 1))) * (2^S_AXI_AWSIZE * (S_AXI_AWLEN + 1)) + (2^S_AXI_AWSIZE * (S_AXI_AWLEN + 1))
Upper_Wrap_Boundary = 108

but when I put these numbers into the aw_wrap_en expression it would result in the expression to resolve to true although the wrap boundary wasn't reached.

 

The upper wrapping boundary has to be a multiple of (2^S_AXI_AWSIZE + (S_AXI_AWLEN + 1)) so I would need an algorithm which checks if the current address is:

address(aligned) rem (2^S_AXI_AWSIZE + (S_AXI_AWLEN + 1)) = 0

So how can this be checked without a divider?

 

And there are other places in the code I think are confusing:

constant low : std_logic_vector (C_S_AXI_ADDR_WIDTH - 1 downto 0) := "000000";

 why not use

constant low : std_logic_vector (C_S_AXI_ADDR_WIDTH - 1 downto 0) := (others => '0');

instead, so that it would work with arbitrary address widths?

 

And another construct which looks strange to me:

constant ADDR_LSB  : integer := (C_S_AXI_DATA_WIDTH/32)+ 1;

as this only works for 16, 32 and 64 bits. This is pseudo code which would work for every 2^N data width:

constant ADDR_LSB  : integer := log2(C_S_AXI_DATA_WIDTH/8)

 

I've attached my testbench if you want to play with the wrap generation logic yourself.

 

To make a long story short: Is the Xilinx provided implementation correct and are my assumptions wrong? If the Xilinx provided solution is wrong does anyone have a working solution?

 

 

Regards

Martin

 

0 Kudos
2 Replies
stmartin81
Adventurer
Adventurer
3,471 Views
Registered: ‎12-09-2010

Fixed testbench so that it works with XSIM.

0 Kudos
stmartin81
Adventurer
Adventurer
3,365 Views
Registered: ‎12-09-2010

This problem was confirmed by the Xilinx support and should be fixed in a later version of Vivado. Unfortunately I don't know for which release the error will be fixed.

Tags (1)
0 Kudos