This article is an explanation of the AXI4-Lite "non-compliance" warning included in the axi_cmd#_mux Star Documents. The Abaco Systems axi_cmd_mux is a simple answer to the more complex AXI interconnect from Xilinx. It can be replaced with the Xilinx AXI Interconnect IP core if desired, but this will require modification of the reference BSP firmware and a full comprehension of the AXI4-Lite register mapping within the constellation. Please refer to Xilinx PG059 for more information regarding the AXI Interconnect IP core.
1) AMBA IHI0022E AXI4-Lite Compliance in Abaco axi_cmd.vhd “AXI4-Lite Slave”
Section A3.3.1 of AMBA IHI0022E defines the read and write transaction dependencies between master and slave. When implementing an AXI4-Lite slave, there is some flexibility in maintaining compliance. Abaco Systems implements a basic AXI4-Lite slave, compliant to the following dependencies quoted from the standard:
Write transaction dependencies
- the slave can wait for AWVALID or WVALID, or both, before asserting AWREADY
- Abaco Slave waits for both AWVALID and WVALID before asserting AWREADY
- the slave can wait for AWVALID or WVALID, or both, before asserting WREADY
- Abaco Slave waits for both AWVALID and WVALID before asserting WREADY
- the slave must wait for AWVALID, AWREADY, WVALID, and WREADY to be asserted before asserting BVALID
- Abaco Slave is compliant
- the slave must not wait for the master to assert BREADY before asserting BVALID
- Abaco Slave is compliant
Read transaction dependencies
- the slave can wait for ARVALID to be asserted before it asserts ARREADY
- Abaco Slave waits for ARVALID to be asserted before it asserts ARREADY
- the slave must wait for both ARVALID and ARREADY to be asserted before it asserts RVALID to indicate that valid data is available
- Abaco Slave is compliant
- the slave must not wait for the master to assert RREADY before asserting RVALID
- Abaco Slave is compliant
2) Abaco cmdXX_mux.vhd used in all AXI4-Lite “Command MUX” blocks
This implementation is a passive 1-to-many fanout of a single AXI4-Lite Slave bus (connected to an upstream Master) into multiple Master buses (connected to downstream Slaves). There is no assignment of address space to any of the Master buses which means every Slave access is routed to every Master output. All of the ready handshakes coming back from downstream are OR’ed together which works correctly when everything downstream acts as described in #1 above in the Abaco axi_cmd.vhd, in accordance with the specification.
3) Non-compliance Warning
Because of the flexibility / ambiguity in the behavior of the Slave’s *READY signals, the cmdXX_mux.vhd implementation described in #2 above is vulnerable in the following situation:
One of the outputs of the “Command MUX” Master buses is connected to an AXI4-Lite Slave which asserts any of its *READY signals before the corresponding *VALID signal as described in Section A3.3.1 of IHI0022E:
- the slave can assert ARREADY before ARVALID is asserted
- the slave can assert AWREADY before AWVALID or WVALID, or both, are asserted
- the slave can assert WREADY before AWVALID or WVALID, or both, are asserted
The resulting behavior in this situation is that the asserted *READY signal from such a Slave will be OR-ed together back upstream to the single AXI4-Lite Master and will handshake every access put on the bus, including accesses not addressing that Slave.
4) Work-around
The solution to this current architecture, when connecting a Slave described in #3 above, is to add *READY gating between the Slave and the cmdXX_mux which ONLY passes the *READY signal from Slave back to cmdXX_mux when that Slave’s address space is being addressed. This requires that the work-around knows about the Slave’s address space, which the cmdXX_mux does not and is the source of the issue.
Here is an example of such an implementation which ONLY passes the *READY signals back when address 0x0 – 0x7FF is accessed:
write_valid_gate <= '1' when (unsigned(s00_s_axi.awaddr(27 downto 0)) < 2048) else '0';
awvalid_into_slave <= s00_s_axi.awvalid when write_valid_gate = '1' else '0';
wvalid_into_slave <= s00_s_axi.wvalid when write_valid_gate = '1' else '0';
s00_r_axi.awready <= awready_from_slave when write_valid_gate = '1' else '0';
s00_r_axi.wready <= wready_from_slave when write_valid_gate = '1' else '0';
read_valid_gate <= '1' when (unsigned(s00_s_axi.araddr(27 downto 0)) < 2048) else '0';
arvalid_into_slave <= s00_s_axi.arvalid when read_valid_gate = '1' else '0';
s00_r_axi.arready <= arready_from_slave when read_valid_gate = '1' else '0';