alexforencich/cocotbext-axi

AXIStream: self.width = len(self.bus.tdata) TypeError: object of type 'NoneType' has no len()

garmin-brandonb opened this issue · 19 comments

cocotb=1.6.2
cocotbext-axi = 0.1.16
Active HDL 11.1

When I define an
axis_source = AxiStreamSource(AxiStreamBus.from_prefix(dut, "bfm_m_axis"), dut.clk_in, dut.reset)
and axis_sink = AxiStreamSink(AxiStreamBus.from_prefix(dut, "bfm_s_axis"), dut.clk_in, dut.reset)
I get the error self.width = len(self.bus.tdata) TypeError: object of type 'NoneType' has no len() on the axis_sink.

Here is my entity:

port(
    clk_in          : in std_logic := '0';
    reset           : in std_logic := '0';

    bfm_m_axis_tdata    : in std_logic_vector(DATA_WIDTH-1 downto 0) := (others => '0');
    bfm_m_axis_tvalid   : in std_logic := '0';
    bfm_m_axis_tid      : in std_logic_vector(ID_WIDTH-1 downto 0) := (others => '0');
    bfm_m_axis_tdest    : in std_logic_vector(DEST_WIDTH-1 downto 0):= (others => '0');
    bfm_s_axis_tready   : in std_logic := '0';

    bfm_s_axis_tdata    : out std_logic_vector(DATA_WIDTH-1 downto 0) := (others => '0');
    bfm_s_axis_tvalid   : out std_logic := '0';
    bfm_s_axis_tid      : out std_logic_vector(ID_WIDTH-1 downto 0) := (others => '0');
    bfm_s_axis_tdest    : out std_logic_vector(DEST_WIDTH-1 downto 0):= (others => '0');
    bfm_m_axis_tready   : out std_logic := '0'

);
end entity;

However, if I remove either the source or sink object then remove the corresponding signals in the entity it runs fine.

Strange. What does dir(dut) return?

['AXI_ADDR_WIDTH', 'AXI_DATA_WIDTH', 'AXI_ID_WIDTH', 'DATA_WIDTH', 'DEST_WIDTH', 'EMMC_CONTROLLER_INST', 'ID_WIDTH', 'KEEP_WIDTH', 'M_COUNT', 'SLAVE_0', 'SLAVE_1', 'S_COUNT', '_HierarchyObject__get_sub_handle_by_name', '__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattr__', '__getattribute__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__iter__', '__le__', '__len__', '__lt__', '__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__', '_child_path', '_compat_mapping', '_def_file', '_def_name', '_discover_all', '_discovered', '_fullname', '_handle', '_id', '_invalid_sub_handles', '_len', '_log', '_name', '_path', '_sub_handle_key', '_sub_handles', '_type', 'bfm_m_axis_tdata', 'clk_400khz', 'clk_52mhz', 'clk_gen_inst', 'clk_in', 'emmc_clk_i', 'emmc_data_in', 'get_definition_file', 'get_definition_name', 'mmc_tester_inst', 'pll_locked', 'reset', 'sys_clk']

Odd, the only signal I see in that list is bfm_m_axis_tdata. If cocotb doesn't see the signal, then cocotbext-axi can't connect to it. It's not clear if this is a cocotb issue or a simulator issue.

My colleague is using cocotb 1.4 and cocotbext-axi 0.1.4 and it works for him.

We are both using Active HDL

Well, possibly it's a cocotb issue related to VHPI. I think you should take this missing signal issue over to the cocotb github and open an issue there because if cocotb doesn't get all of the signal names from the simulator, then cocotbext-axi simply isn't going to be able to operate on those signals.

I can still access these signals from my python test, for instance I can do print("bfm_s_axis_tdata", dut.bfm_s_axis_tdata) and it will return some value.

Right, I suspect it is some sort of enumeration issue. If you ask for a specific signal, it gives you the signal. But if you ask for all of the signals, something is broken and cocotb doesn't give you all of the signals, only some subset of the signals. cocotbext-axi works by asking for all of the signals and then prefix-matching against those. Well I suppose in this case, it isn't really cocotbext-axi doing that either, instead it's the Bus object in cocotb-bus that does this that cocotbext-axi uses, which is part of cocotb.

I suspect that cocotb and/or activehdl have some sort of issue in how signals are enumerated in VHPI, so you should raise this issue on the cocotb github.

Alright, I posted something in Gitter but they pointed me here, so I'll ping them back with your response :)

So I think it is something to do with the Bus class because if I put a Verilog wrapper around my VHDL testbench then it finds all the signals and works.

If it works with a Verilog wrapper, then that pretty much confirms that this is some sort of VHPI issue between ccootb and activehdl, as cocotb uses VPI when interacting with Verilog code and VHPI when interacting with VHDL code.

Thanks for your speedy responses, I appreciate it!

Hi @jackbpdx

Have you found a way to run VHDL directly? I run into a similar problem while testing Aldec Riviera.

I was able to make my tests work by using the following workaround:

Before defining the my driver, I touch each signal once:

    dut.SAxis_Tstrb.setimmediatevalue(0)
    dut.SAxis_Tdata.setimmediatevalue(0)
    dut.SAxis_Tkeep.setimmediatevalue(0)
    dut.SAxis_Tuser.setimmediatevalue(0)
    dut.SAxis_Tid.setimmediatevalue(0)  

    dut.MAxis_Tstrb.setimmediatevalue(0)
    dut.MAxis_Tdata.setimmediatevalue(0)
    dut.MAxis_Tkeep.setimmediatevalue(0)
    dut.MAxis_Tuser.setimmediatevalue(0)
    dut.MAxis_Tid.setimmediatevalue(0)  

    # Add data drivers
    self.source_driver = AxiStreamSource(AxiStreamBus(dut, "SAxis"), dut.Clk, dut.Rst)
    self.destination_driver = AxiStreamSink(AxiStreamBus(dut, "MAxis"), dut.Clk, dut.Rst)

No Idea why, but it makes the test work again (I used to run the same test with Modelsim before)

yeah, this definitely seems to be some sort of simulator API related issue, not sure if it's on the cocotb end or the simulator end. Has anyone reported this to cocotb? I don't use VHDL or have access to riviera, so I can't test this on my end.

@Botnic Hi yes, I have been using that exact same method as a workout to get cocotb to recognize my bus signals. @alexforencich I made a comment about it in Gitter however, I don't think anyone really responded. I have scoured Gitter and have not seen anyone else reporting this issue. I found it hard to believe I was the only one running into this issue. It worked in cocotb 1.4 as far as I know. Once we upgraded to 1.6 I saw the issue, I also tested 1.5 and it persisted there too. Also, I believe this is an issue with the bus class because cocotb recognizes all other non bus signals in the ports at the top level.

Shot in the dark - does it help to run dut._discover_all() before trying to access the bus?
See e.g. https://github.com/cocotb/cocotb/blob/master/tests/test_cases/test_sv_interface/test_sv_if.py#L12

Shot in the dark - does it help to run dut._discover_all() before trying to access the bus? See e.g. https://github.com/cocotb/cocotb/blob/master/tests/test_cases/test_sv_interface/test_sv_if.py#L12

Hey @cmarqu I tried it and it did not work.

@cmarqu @Botnic @alexforencich I rolled back cocotb-bus to version 0.1.1 and the issue seemed to go away. I don't have use setimmediatevalue to work around the issue.