alexforencich / cocotbext-axi

AXI interface modules for Cocotb
MIT License
209 stars 68 forks source link

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

Open garmin-brandonb opened 2 years ago

garmin-brandonb commented 2 years ago

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.

alexforencich commented 2 years ago

Strange. What does dir(dut) return?

garmin-brandonb commented 2 years ago

['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']

alexforencich commented 2 years ago

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.

garmin-brandonb commented 2 years ago

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

garmin-brandonb commented 2 years ago

We are both using Active HDL

alexforencich commented 2 years ago

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.

garmin-brandonb commented 2 years ago

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.

alexforencich commented 2 years ago

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.

garmin-brandonb commented 2 years ago

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

garmin-brandonb commented 2 years ago

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.

alexforencich commented 2 years ago

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.

garmin-brandonb commented 2 years ago

Thanks for your speedy responses, I appreciate it!

Botnic commented 2 years ago

Hi @jackbpdx

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

Botnic commented 2 years ago

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)

alexforencich commented 2 years ago

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.

garmin-brandonb commented 2 years ago

@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.

cmarqu commented 2 years ago

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

garmin-brandonb commented 2 years ago

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.

garmin-brandonb commented 1 year ago

@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.