cocotbext-axi: Correct timeout approach for AxiMaster class

Hey @alexforencich,

what’s the correct approach to using a timeout timer in an AxiMaster for writes/reads? I tried the following seq. but it’s doesn’t work, it complains about wait method not being a trigger type, so it can’t be used in conjunction with with_timeout…

taxi
axi_if = AxiMaster(AxiBus.from_prefix(dut, "axi"), dut.clk, dut.arst)
axi_if.init_write(address, data)
await with_timeout(axi_if.wait(), *timeout_val)

If it’s not clear, I want to have the timer to ensure the slave doesn’t hang in the transaction request. Thanks!

About this issue

  • Original URL
  • State: closed
  • Created 3 years ago
  • Comments: 68 (34 by maintainers)

Most upvoted comments

But what you can do is have a couple of different ways of issuing operations. One of them could be via AXI lite registers, especially if you just need 1 flit. Then all you need to do is merge AXI stream traffic from the config register interface (single flits or maybe flit with 1 data word or something) with traffic from the DMA module.

The write response must not end up in the wrong queue. This is an AXI protocol violation with no way to recover and will screw up all future write operations on that interface. I have not used array interfaces. Previously, I have used concatenated interfaces, but this is not supported well by cocotb right now, so instead I have been using wrappers generated with jinja2. I opened an issue for functionality that would be required for concatenated buses here https://github.com/cocotb/cocotb/issues/2302 but that hasn’t gone anywhere yet.

For the index thing, I didn’t validate that anywhere. It’s a feature of the cocotb Bus object, I just exposed it so it’s usable as someone was asking about it. Well, I also wanted to reorganize that code anyway for other reasons. It would make sense to add some more test cases with some of these interface variations at some point.

Another option to consider is to not use top-level ports at all, and instead connect directly to instances inside of the top-level module, possibly with an HDL top-level testbench. This could potentially be easier as you can just stick everything in a generate block and then use hierarchical references from cocotb to connect to the signals in question inside the generate block. Although this does depend on the generate block being handled correctly by the PLI, which is not always the case.

Also, I removed the get_read_data/get_write_resp methods and set up init_read and init_write to return the operation complete event so you don’t need to create one manually. So with the new setup, instead of doing

event = Event()
axi_master.init_write(0x0000, b'test', event=event)
await event.wait()
resp = event.data
event = Event()
axi_master.init_read(0x0000, 4, event=event)
await event.wait()
resp = event.data

you can do

event = axi_master.init_write(0x0000, b'test')
await event.wait()
resp = event.data
event = axi_master.init_read(0x0000, 4)
await event.wait()
resp = event.data

Just released a new version of cocotbext-axi with these changes. Additionally, the AXI master now uses one coroutine per AXI ID so it can handle read data and write completions out-of-order (well, according to AXI ordering rules - reordering must be maintained within each ID, but is allowed between different IDs). Previously it was strictly FIFO order and any operations that completed early would be stored and processed in-order. Not sure if this makes much of a difference for your NoC.

OK, current version in git does all reset processing on the assert edge, so you should be able to queue up operations before releasing reset. Try that, let me know how it works.

well, it’s still not terminating; not sure where the issue is. Log files stop at Reset DUT.