Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

AxiLiteMaster reads forever #53

Open
vacagonzalo opened this issue Jan 1, 2023 · 8 comments
Open

AxiLiteMaster reads forever #53

vacagonzalo opened this issue Jan 1, 2023 · 8 comments

Comments

@vacagonzalo
Copy link

I wrote a simple test for a slave. It has a register with a hard-coded version number (1).
The source code is in VHDL.

The master's read operation never ends.

import cocotb
from cocotb.clock import Clock
from cocotbext.axi import AxiLiteBus, AxiLiteMaster

PERIOD = 8  # ns


@cocotb.test()
async def test_axi_read_version(dut):
    """Version test"""
    clk = dut.s00_axi_aclk
    rst = dut.s00_axi_aresetn
    cocotb.start_soon(Clock(clk, period=PERIOD, units="ns").start())
    bus = AxiLiteBus.from_prefix(dut, "s00_axi")
    master = AxiLiteMaster(bus, clk, rst)
    version = await master.read(0x000c, 1)
    assert version.data == b'1', f"The version {version.data} is not 1."

This is my console output:

/usr/local/bin/ghdl -i   --workdir=sim_build --work=work /workspaces/MSE-Tesis/fpga/test/axi_data_generator/../../src/data_generator.vhdl /workspaces/MSE-Tesis/fpga/test/axi_data_generator/../../src/axi_data_generator_v1_0_AXI.vhd /workspaces/MSE-Tesis/fpga/test/axi_data_generator/../../src/axi_data_generator_v1_0.vhd && \
/usr/local/bin/ghdl -m   --workdir=sim_build -Psim_build --work=work axi_data_generator_v1_0
/workspaces/MSE-Tesis/fpga/test/axi_data_generator/../../src/axi_data_generator_v1_0_AXI.vhd:248:33:warning: declaration of "byte_index" hides signal "byte_index" [-Whide]
                            FOR byte_index IN 0 TO (C_S_AXI_DATA_WIDTH/8 - 1) LOOP
                                ^
/workspaces/MSE-Tesis/fpga/test/axi_data_generator/../../src/axi_data_generator_v1_0_AXI.vhd:256:33:warning: declaration of "byte_index" hides signal "byte_index" [-Whide]
                            FOR byte_index IN 0 TO (C_S_AXI_DATA_WIDTH/8 - 1) LOOP
                                ^
/workspaces/MSE-Tesis/fpga/test/axi_data_generator/../../src/axi_data_generator_v1_0_AXI.vhd:264:33:warning: declaration of "byte_index" hides signal "byte_index" [-Whide]
                            FOR byte_index IN 0 TO (C_S_AXI_DATA_WIDTH/8 - 1) LOOP
                                ^
/workspaces/MSE-Tesis/fpga/test/axi_data_generator/../../src/axi_data_generator_v1_0_AXI.vhd:272:33:warning: declaration of "byte_index" hides signal "byte_index" [-Whide]
                            FOR byte_index IN 0 TO (C_S_AXI_DATA_WIDTH/8 - 1) LOOP
                                ^
../../src/ieee/math_real-body.vhdl:830:14:warning: declaration of "real_vector" hides type "real_vector" [-Whide]
        type REAL_VECTOR is array (NATURAL range <>) of REAL;
             ^
analyze /workspaces/MSE-Tesis/fpga/test/axi_data_generator/../../src/axi_data_generator_v1_0.vhd
analyze /workspaces/MSE-Tesis/fpga/test/axi_data_generator/../../src/axi_data_generator_v1_0_AXI.vhd
/workspaces/MSE-Tesis/fpga/test/axi_data_generator/../../src/axi_data_generator_v1_0_AXI.vhd:248:33:warning: declaration of "byte_index" hides signal "byte_index" [-Whide]
                            FOR byte_index IN 0 TO (C_S_AXI_DATA_WIDTH/8 - 1) LOOP
                                ^
/workspaces/MSE-Tesis/fpga/test/axi_data_generator/../../src/axi_data_generator_v1_0_AXI.vhd:256:33:warning: declaration of "byte_index" hides signal "byte_index" [-Whide]
                            FOR byte_index IN 0 TO (C_S_AXI_DATA_WIDTH/8 - 1) LOOP
                                ^
/workspaces/MSE-Tesis/fpga/test/axi_data_generator/../../src/axi_data_generator_v1_0_AXI.vhd:264:33:warning: declaration of "byte_index" hides signal "byte_index" [-Whide]
                            FOR byte_index IN 0 TO (C_S_AXI_DATA_WIDTH/8 - 1) LOOP
                                ^
/workspaces/MSE-Tesis/fpga/test/axi_data_generator/../../src/axi_data_generator_v1_0_AXI.vhd:272:33:warning: declaration of "byte_index" hides signal "byte_index" [-Whide]
                            FOR byte_index IN 0 TO (C_S_AXI_DATA_WIDTH/8 - 1) LOOP
                                ^
analyze /workspaces/MSE-Tesis/fpga/test/axi_data_generator/../../src/data_generator.vhdl
elaborate axi_data_generator_v1_0
rm -f results.xml
MODULE=test_axi_data_generator TESTCASE= TOPLEVEL=axi_data_generator_v1_0 TOPLEVEL_LANG=vhdl \
 /usr/local/bin/ghdl -r  --workdir=sim_build -Psim_build --work=work axi_data_generator_v1_0 --vpi=/usr/local/lib/python3.9/dist-packages/cocotb/libs/libcocotbvpi_ghdl.so --vcd=axi_data_generator_v1_0.vcd 
loading VPI module '/usr/local/lib/python3.9/dist-packages/cocotb/libs/libcocotbvpi_ghdl.so'
     -.--ns INFO     gpi                                ..mbed/gpi_embed.cpp:76   in set_program_name_in_venv        Did not detect Python virtual environment. Using system-wide Python interpreter
     -.--ns INFO     gpi                                ../gpi/GpiCommon.cpp:101  in gpi_print_registered_impl       VPI registered
VPI module loaded!
     0.00ns INFO     cocotb                             Running on GHDL version 3.0.0-dev (v2.0.0-952-gd908ceeed) [Dunoon edition]
     0.00ns INFO     cocotb                             Running tests with cocotb v1.8.0.dev0 from /usr/local/lib/python3.9/dist-packages/cocotb
     0.00ns INFO     cocotb                             Seeding Python random module with 1672608203
     0.00ns INFO     cocotb.regression                  Found test test_axi_data_generator.test_axi_read_version
     0.00ns INFO     cocotb.regression                  running test_axi_read_version (1/1)
                                                          Testing the
vpi_get_str: unhandled property
vpi_get_str: unhandled property
     0.00ns INFO     ...axi_data_generator_v1_0.s00_axi AXI lite master (write)
     0.00ns INFO     ...axi_data_generator_v1_0.s00_axi cocotbext-axi version 0.1.18
     0.00ns INFO     ...axi_data_generator_v1_0.s00_axi Copyright (c) 2020 Alex Forencich
     0.00ns INFO     ...axi_data_generator_v1_0.s00_axi https://github.com/alexforencich/cocotbext-axi
     0.00ns INFO     ...axi_data_generator_v1_0.s00_axi Reset de-asserted
     0.00ns INFO     ...axi_data_generator_v1_0.s00_axi Reset de-asserted
     0.00ns INFO     ...axi_data_generator_v1_0.s00_axi Reset de-asserted
     0.00ns INFO     ...axi_data_generator_v1_0.s00_axi AXI lite master configuration:
     0.00ns INFO     ...axi_data_generator_v1_0.s00_axi   Address width: 4 bits
     0.00ns INFO     ...axi_data_generator_v1_0.s00_axi   Byte size: 8 bits
     0.00ns INFO     ...axi_data_generator_v1_0.s00_axi   Data width: 32 bits (4 bytes)
     0.00ns INFO     ...axi_data_generator_v1_0.s00_axi AXI lite master signals:
     0.00ns INFO     ...axi_data_generator_v1_0.s00_axi   awaddr width: 4 bits
     0.00ns INFO     ...axi_data_generator_v1_0.s00_axi   awprot width: 3 bits
     0.00ns INFO     ...axi_data_generator_v1_0.s00_axi   awready width: 1 bits
     0.00ns INFO     ...axi_data_generator_v1_0.s00_axi   awvalid width: 1 bits
     0.00ns INFO     ...axi_data_generator_v1_0.s00_axi   wdata width: 32 bits
     0.00ns INFO     ...axi_data_generator_v1_0.s00_axi   wready width: 1 bits
     0.00ns INFO     ...axi_data_generator_v1_0.s00_axi   wstrb width: 4 bits
     0.00ns INFO     ...axi_data_generator_v1_0.s00_axi   wvalid width: 1 bits
     0.00ns INFO     ...axi_data_generator_v1_0.s00_axi   bready width: 1 bits
     0.00ns INFO     ...axi_data_generator_v1_0.s00_axi   bresp width: 2 bits
     0.00ns INFO     ...axi_data_generator_v1_0.s00_axi   bvalid width: 1 bits
     0.00ns INFO     ...axi_data_generator_v1_0.s00_axi Reset de-asserted
     0.00ns INFO     ...axi_data_generator_v1_0.s00_axi AXI lite master (read)
     0.00ns INFO     ...axi_data_generator_v1_0.s00_axi cocotbext-axi version 0.1.18
     0.00ns INFO     ...axi_data_generator_v1_0.s00_axi Copyright (c) 2020 Alex Forencich
     0.00ns INFO     ...axi_data_generator_v1_0.s00_axi https://github.com/alexforencich/cocotbext-axi
     0.00ns INFO     ...axi_data_generator_v1_0.s00_axi Reset de-asserted
     0.00ns INFO     ...axi_data_generator_v1_0.s00_axi Reset de-asserted
     0.00ns INFO     ...axi_data_generator_v1_0.s00_axi AXI lite master configuration:
     0.00ns INFO     ...axi_data_generator_v1_0.s00_axi   Address width: 4 bits
     0.00ns INFO     ...axi_data_generator_v1_0.s00_axi   Byte size: 8 bits
     0.00ns INFO     ...axi_data_generator_v1_0.s00_axi   Data width: 32 bits (4 bytes)
     0.00ns INFO     ...axi_data_generator_v1_0.s00_axi AXI lite master signals:
     0.00ns INFO     ...axi_data_generator_v1_0.s00_axi   araddr width: 4 bits
     0.00ns INFO     ...axi_data_generator_v1_0.s00_axi   arprot width: 3 bits
     0.00ns INFO     ...axi_data_generator_v1_0.s00_axi   arready width: 1 bits
     0.00ns INFO     ...axi_data_generator_v1_0.s00_axi   arvalid width: 1 bits
     0.00ns INFO     ...axi_data_generator_v1_0.s00_axi   rdata width: 32 bits
     0.00ns INFO     ...axi_data_generator_v1_0.s00_axi   rready width: 1 bits
     0.00ns INFO     ...axi_data_generator_v1_0.s00_axi   rresp width: 2 bits
     0.00ns INFO     ...axi_data_generator_v1_0.s00_axi   rvalid width: 1 bits
     0.00ns INFO     ...axi_data_generator_v1_0.s00_axi Reset de-asserted
     0.00ns INFO     ...axi_data_generator_v1_0.s00_axi Read start addr: 0x0000000c prot: AxiProt.NONSECURE length: 1
@vacagonzalo
Copy link
Author

After some help I have a working minimal example:

import cocotb
from cocotb.triggers import RisingEdge, FallingEdge
from cocotb.clock import Clock
from cocotbext.axi import AxiLiteBus, AxiLiteMaster

PERIOD = 8  # ns


@cocotb.test()
async def test_axi_read_version(dut):

    """Testing the """
    clk = dut.s00_axi_aclk
    rst = dut.s00_axi_aresetn

    cocotb.start_soon(Clock(clk, period=PERIOD, units="ns").start())

    bus = AxiLiteBus.from_prefix(dut, "s00_axi")
    master = AxiLiteMaster(bus, clk, rst, False)

    rst.value = 0
    for _ in range(5):
        await FallingEdge(clk)
    rst.value = 1
    await FallingEdge(clk)

    version = await master.read(0x000c, 1)

    print(f"The version is {version.data}.")
    assert version.data == b'\x01', f"The version {version.data} is not 1."

There is something strange going on with the reset. Is there a prettier way to do this?

@Gatherer
Copy link

Gatherer commented Feb 5, 2023

Hello,

I did run into the same problem after reinstalling my system.
I had a Linux Mint 20.3 which I upgrade to Linux Mint 21.1 and with this the simulation setup after cocotb/cocotb#2300 is finally closed.

cocotb 1.6.2 updated to 1.7.2
cocotb-bus 0.1.1 updated to 0.2.1
cocotbext-ax 0.1.18 updated to 0.1.20
cocotbext-eth 0.1.18 updated to 0.1.20
scapy 2.4.5 updated to 2.5.0
verilator 4.106 updated to 5.006

With the updated configuration I did run into the same endless loop. After testing some combinations I found a working one.

cocotb 1.7.2
cocotb-bus 0.1.1
cocotbext-ax 0.1.20
cocotbext-eth 0.1.20
scapy 2.5.0
verilator 5.006

The error can be reliably reproduced by switching out cocotb-bus versions. Haven´t dig deeper yet. It's maybe a issue with the cocotb-bus extension.

@alexforencich
Copy link
Owner

@Gatherer you're probably seeing a known verilator bug: verilator/verilator#3919

@alexforencich
Copy link
Owner

@vacagonzalo if you can post the HDL code, I'll take a look. Hard to say what's going on without seeing what the simulation models are interacting with.

@vacagonzalo
Copy link
Author

@alexforencich data_generator.vhdl

LIBRARY ieee;
USE ieee.std_logic_1164.ALL;
USE ieee.numeric_std.ALL;
USE ieee.math_real.ALL;

ENTITY data_generator IS
    GENERIC (DATA_WITH : INTEGER := 32);
    PORT (
        -- Common control signals
        clk_i : IN STD_LOGIC;
        en_i : IN STD_LOGIC;
        srst_i : IN STD_LOGIC;

        -- Data generation
        read_i : IN STD_LOGIC;
        data_o : OUT STD_LOGIC_VECTOR(DATA_WITH - 1 DOWNTO 0);

        -- Core version
        version_o : OUT STD_LOGIC_VECTOR(DATA_WITH - 1 DOWNTO 0)
    );
END ENTITY data_generator;

ARCHITECTURE behavioral OF data_generator IS

    TYPE edge_t IS (WAITING, DETECTED);
    SIGNAL read_edge : edge_t;

    SIGNAL data_s : STD_LOGIC_VECTOR(DATA_WITH - 1 DOWNTO 0);

BEGIN

    data_o <= data_s;
    version_o <= x"00000001";

    behavior : PROCESS (clk_i, srst_i)
    BEGIN
        IF srst_i = '0' THEN
            data_s <= (OTHERS => '0');
            read_edge <= WAITING;
        ELSIF rising_edge(clk_i) THEN
            IF en_i = '1' THEN
                CASE read_edge IS
                    WHEN WAITING =>
                        IF read_i = '1' THEN
                            read_edge <= DETECTED;
                            data_s <= STD_LOGIC_VECTOR(unsigned(data_s) + 1);
                        END IF;

                    WHEN DETECTED =>
                        IF read_i = '0' THEN
                            read_edge <= WAITING;
                        END IF;

                END CASE;
            END IF;
        END IF;
    END PROCESS behavior;

END ARCHITECTURE behavioral;

@vacagonzalo
Copy link
Author

@alexforencich axi_data_generator_v1_0_AXI.vhd

LIBRARY ieee;
USE ieee.std_logic_1164.ALL;
USE ieee.numeric_std.ALL;

ENTITY axi_data_generator_v1_0_S00_AXI IS
    GENERIC (
        -- Users to add parameters here

        -- User parameters ends
        -- Do not modify the parameters beyond this line

        -- Width of S_AXI data bus
        C_S_AXI_DATA_WIDTH : INTEGER := 32;
        -- Width of S_AXI address bus
        C_S_AXI_ADDR_WIDTH : INTEGER := 4
    );
    PORT (
        -- Users to add ports here

        -- User ports ends
        -- Do not modify the ports beyond this line

        -- Global Clock Signal
        S_AXI_ACLK : IN STD_LOGIC;
        -- Global Reset Signal. This Signal is Active LOW
        S_AXI_ARESETN : IN STD_LOGIC;
        -- Write address (issued by master, acceped by Slave)
        S_AXI_AWADDR : IN STD_LOGIC_VECTOR(C_S_AXI_ADDR_WIDTH - 1 DOWNTO 0);
        -- Write channel Protection type. This signal indicates the
        -- privilege and security level of the transaction, and whether
        -- the transaction is a data access or an instruction access.
        S_AXI_AWPROT : IN STD_LOGIC_VECTOR(2 DOWNTO 0);
        -- Write address valid. This signal indicates that the master signaling
        -- valid write address and control information.
        S_AXI_AWVALID : IN STD_LOGIC;
        -- Write address ready. This signal indicates that the slave is ready
        -- to accept an address and associated control signals.
        S_AXI_AWREADY : OUT STD_LOGIC;
        -- Write data (issued by master, acceped by Slave)
        S_AXI_WDATA : IN STD_LOGIC_VECTOR(C_S_AXI_DATA_WIDTH - 1 DOWNTO 0);
        -- Write strobes. This signal indicates which byte lanes hold
        -- valid data. There is one write strobe bit for each eight
        -- bits of the write data bus.
        S_AXI_WSTRB : IN STD_LOGIC_VECTOR((C_S_AXI_DATA_WIDTH/8) - 1 DOWNTO 0);
        -- Write valid. This signal indicates that valid write
        -- data and strobes are available.
        S_AXI_WVALID : IN STD_LOGIC;
        -- Write ready. This signal indicates that the slave
        -- can accept the write data.
        S_AXI_WREADY : OUT STD_LOGIC;
        -- Write response. This signal indicates the status
        -- of the write transaction.
        S_AXI_BRESP : OUT STD_LOGIC_VECTOR(1 DOWNTO 0);
        -- Write response valid. This signal indicates that the channel
        -- is signaling a valid write response.
        S_AXI_BVALID : OUT STD_LOGIC;
        -- Response ready. This signal indicates that the master
        -- can accept a write response.
        S_AXI_BREADY : IN STD_LOGIC;
        -- Read address (issued by master, acceped by Slave)
        S_AXI_ARADDR : IN STD_LOGIC_VECTOR(C_S_AXI_ADDR_WIDTH - 1 DOWNTO 0);
        -- Protection type. This signal indicates the privilege
        -- and security level of the transaction, and whether the
        -- transaction is a data access or an instruction access.
        S_AXI_ARPROT : IN STD_LOGIC_VECTOR(2 DOWNTO 0);
        -- Read address valid. This signal indicates that the channel
        -- is signaling valid read address and control information.
        S_AXI_ARVALID : IN STD_LOGIC;
        -- Read address ready. This signal indicates that the slave is
        -- ready to accept an address and associated control signals.
        S_AXI_ARREADY : OUT STD_LOGIC;
        -- Read data (issued by slave)
        S_AXI_RDATA : OUT STD_LOGIC_VECTOR(C_S_AXI_DATA_WIDTH - 1 DOWNTO 0);
        -- Read response. This signal indicates the status of the
        -- read transfer.
        S_AXI_RRESP : OUT STD_LOGIC_VECTOR(1 DOWNTO 0);
        -- Read valid. This signal indicates that the channel is
        -- signaling the required read data.
        S_AXI_RVALID : OUT STD_LOGIC;
        -- Read ready. This signal indicates that the master can
        -- accept the read data and response information.
        S_AXI_RREADY : IN STD_LOGIC
    );
END axi_data_generator_v1_0_S00_AXI;

ARCHITECTURE arch_imp OF axi_data_generator_v1_0_S00_AXI IS

    -- AXI4LITE signals
    SIGNAL axi_awaddr : STD_LOGIC_VECTOR(C_S_AXI_ADDR_WIDTH - 1 DOWNTO 0);
    SIGNAL axi_awready : STD_LOGIC;
    SIGNAL axi_wready : STD_LOGIC;
    SIGNAL axi_bresp : STD_LOGIC_VECTOR(1 DOWNTO 0);
    SIGNAL axi_bvalid : STD_LOGIC;
    SIGNAL axi_araddr : STD_LOGIC_VECTOR(C_S_AXI_ADDR_WIDTH - 1 DOWNTO 0);
    SIGNAL axi_arready : STD_LOGIC;
    SIGNAL axi_rdata : STD_LOGIC_VECTOR(C_S_AXI_DATA_WIDTH - 1 DOWNTO 0);
    SIGNAL axi_rresp : STD_LOGIC_VECTOR(1 DOWNTO 0);
    SIGNAL axi_rvalid : STD_LOGIC;

    -- Example-specific design signals
    -- local parameter for addressing 32 bit / 64 bit C_S_AXI_DATA_WIDTH
    -- ADDR_LSB is used for addressing 32/64 bit registers/memories
    -- ADDR_LSB = 2 for 32 bits (n downto 2)
    -- ADDR_LSB = 3 for 64 bits (n downto 3)
    CONSTANT ADDR_LSB : INTEGER := (C_S_AXI_DATA_WIDTH/32) + 1;
    CONSTANT OPT_MEM_ADDR_BITS : INTEGER := 1;
    ------------------------------------------------
    ---- Signals for user logic register space example
    --------------------------------------------------
    ---- Number of Slave Registers 4
    SIGNAL slv_reg0 : STD_LOGIC_VECTOR(C_S_AXI_DATA_WIDTH - 1 DOWNTO 0);
    SIGNAL slv_reg1 : STD_LOGIC_VECTOR(C_S_AXI_DATA_WIDTH - 1 DOWNTO 0);
    SIGNAL slv_reg2 : STD_LOGIC_VECTOR(C_S_AXI_DATA_WIDTH - 1 DOWNTO 0);
    SIGNAL slv_reg3 : STD_LOGIC_VECTOR(C_S_AXI_DATA_WIDTH - 1 DOWNTO 0);
    SIGNAL slv_reg_rden : STD_LOGIC;
    SIGNAL slv_reg_wren : STD_LOGIC;
    SIGNAL reg_data_out : STD_LOGIC_VECTOR(C_S_AXI_DATA_WIDTH - 1 DOWNTO 0);
    SIGNAL byte_index : INTEGER;
    SIGNAL aw_en : STD_LOGIC;

    -- Output signals for the AXI slave
    SIGNAL slv_data_o : STD_LOGIC_VECTOR(C_S_AXI_DATA_WIDTH - 1 DOWNTO 0);
    SIGNAL slv_version_o : STD_LOGIC_VECTOR(C_S_AXI_DATA_WIDTH - 1 DOWNTO 0);
    SIGNAL read_axi_i : STD_LOGIC;

    COMPONENT data_generator IS
        GENERIC (DATA_WITH : INTEGER := 32);
        PORT (
            -- Common control signals
            clk_i : IN STD_LOGIC;
            en_i : IN STD_LOGIC;
            srst_i : IN STD_LOGIC;

            -- Data generation
            read_i : IN STD_LOGIC;
            data_o : OUT STD_LOGIC_VECTOR(DATA_WITH - 1 DOWNTO 0);

            -- Core version
            version_o : OUT STD_LOGIC_VECTOR(DATA_WITH - 1 DOWNTO 0)
        );
    END COMPONENT data_generator;

BEGIN
    -- I/O Connections assignments

    S_AXI_AWREADY <= axi_awready;
    S_AXI_WREADY <= axi_wready;
    S_AXI_BRESP <= axi_bresp;
    S_AXI_BVALID <= axi_bvalid;
    S_AXI_ARREADY <= axi_arready;
    S_AXI_RDATA <= axi_rdata;
    S_AXI_RRESP <= axi_rresp;
    S_AXI_RVALID <= axi_rvalid;
    -- Implement axi_awready generation
    -- axi_awready is asserted for one S_AXI_ACLK clock cycle when both
    -- S_AXI_AWVALID and S_AXI_WVALID are asserted. axi_awready is
    -- de-asserted when reset is low.

    PROCESS (S_AXI_ACLK)
    BEGIN
        IF rising_edge(S_AXI_ACLK) THEN
            IF S_AXI_ARESETN = '0' THEN
                axi_awready <= '0';
                aw_en <= '1';
            ELSE
                IF (axi_awready = '0' AND S_AXI_AWVALID = '1' AND S_AXI_WVALID = '1' AND aw_en = '1') THEN
                    -- slave is ready to accept write address when
                    -- there is a valid write address and write data
                    -- on the write address and data bus. This design
                    -- expects no outstanding transactions.
                    axi_awready <= '1';
                    aw_en <= '0';
                ELSIF (S_AXI_BREADY = '1' AND axi_bvalid = '1') THEN
                    aw_en <= '1';
                    axi_awready <= '0';
                ELSE
                    axi_awready <= '0';
                END IF;
            END IF;
        END IF;
    END PROCESS;

    -- Implement axi_awaddr latching
    -- This process is used to latch the address when both
    -- S_AXI_AWVALID and S_AXI_WVALID are valid.

    PROCESS (S_AXI_ACLK)
    BEGIN
        IF rising_edge(S_AXI_ACLK) THEN
            IF S_AXI_ARESETN = '0' THEN
                axi_awaddr <= (OTHERS => '0');
            ELSE
                IF (axi_awready = '0' AND S_AXI_AWVALID = '1' AND S_AXI_WVALID = '1' AND aw_en = '1') THEN
                    -- Write Address latching
                    axi_awaddr <= S_AXI_AWADDR;
                END IF;
            END IF;
        END IF;
    END PROCESS;

    -- Implement axi_wready generation
    -- axi_wready is asserted for one S_AXI_ACLK clock cycle when both
    -- S_AXI_AWVALID and S_AXI_WVALID are asserted. axi_wready is
    -- de-asserted when reset is low.

    PROCESS (S_AXI_ACLK)
    BEGIN
        IF rising_edge(S_AXI_ACLK) THEN
            IF S_AXI_ARESETN = '0' THEN
                axi_wready <= '0';
            ELSE
                IF (axi_wready = '0' AND S_AXI_WVALID = '1' AND S_AXI_AWVALID = '1' AND aw_en = '1') THEN
                    -- slave is ready to accept write data when
                    -- there is a valid write address and write data
                    -- on the write address and data bus. This design
                    -- expects no outstanding transactions.
                    axi_wready <= '1';
                ELSE
                    axi_wready <= '0';
                END IF;
            END IF;
        END IF;
    END PROCESS;

    -- Implement memory mapped register select and write logic generation
    -- The write data is accepted and written to memory mapped registers when
    -- axi_awready, S_AXI_WVALID, axi_wready and S_AXI_WVALID are asserted. Write strobes are used to
    -- select byte enables of slave registers while writing.
    -- These registers are cleared when reset (active low) is applied.
    -- Slave register write enable is asserted when valid address and data are available
    -- and the slave is ready to accept the write address and write data.
    slv_reg_wren <= axi_wready AND S_AXI_WVALID AND axi_awready AND S_AXI_AWVALID;

    PROCESS (S_AXI_ACLK)
        VARIABLE loc_addr : STD_LOGIC_VECTOR(OPT_MEM_ADDR_BITS DOWNTO 0);
    BEGIN
        IF rising_edge(S_AXI_ACLK) THEN
            IF S_AXI_ARESETN = '0' THEN
                slv_reg0 <= (OTHERS => '0');
                slv_reg1 <= (OTHERS => '0');
                slv_reg2 <= (OTHERS => '0');
                slv_reg3 <= (OTHERS => '0');
            ELSE
                loc_addr := axi_awaddr(ADDR_LSB + OPT_MEM_ADDR_BITS DOWNTO ADDR_LSB);
                IF (slv_reg_wren = '1') THEN
                    CASE loc_addr IS
                        WHEN b"00" =>
                            FOR byte_index IN 0 TO (C_S_AXI_DATA_WIDTH/8 - 1) LOOP
                                IF (S_AXI_WSTRB(byte_index) = '1') THEN
                                    -- Respective byte enables are asserted as per write strobes
                                    -- slave registor 0
                                    slv_reg0(byte_index * 8 + 7 DOWNTO byte_index * 8) <= S_AXI_WDATA(byte_index * 8 + 7 DOWNTO byte_index * 8);
                                END IF;
                            END LOOP;
                        WHEN b"01" =>
                            FOR byte_index IN 0 TO (C_S_AXI_DATA_WIDTH/8 - 1) LOOP
                                IF (S_AXI_WSTRB(byte_index) = '1') THEN
                                    -- Respective byte enables are asserted as per write strobes
                                    -- slave registor 1
                                    slv_reg1(byte_index * 8 + 7 DOWNTO byte_index * 8) <= S_AXI_WDATA(byte_index * 8 + 7 DOWNTO byte_index * 8);
                                END IF;
                            END LOOP;
                        WHEN b"10" =>
                            FOR byte_index IN 0 TO (C_S_AXI_DATA_WIDTH/8 - 1) LOOP
                                IF (S_AXI_WSTRB(byte_index) = '1') THEN
                                    -- Respective byte enables are asserted as per write strobes
                                    -- slave registor 2
                                    slv_reg2(byte_index * 8 + 7 DOWNTO byte_index * 8) <= S_AXI_WDATA(byte_index * 8 + 7 DOWNTO byte_index * 8);
                                END IF;
                            END LOOP;
                        WHEN b"11" =>
                            FOR byte_index IN 0 TO (C_S_AXI_DATA_WIDTH/8 - 1) LOOP
                                IF (S_AXI_WSTRB(byte_index) = '1') THEN
                                    -- Respective byte enables are asserted as per write strobes
                                    -- slave registor 3
                                    slv_reg3(byte_index * 8 + 7 DOWNTO byte_index * 8) <= S_AXI_WDATA(byte_index * 8 + 7 DOWNTO byte_index * 8);
                                END IF;
                            END LOOP;
                        WHEN OTHERS =>
                            slv_reg0 <= slv_reg0;
                            slv_reg1 <= slv_reg1;
                            slv_reg2 <= slv_reg2;
                            slv_reg3 <= slv_reg3;
                    END CASE;
                END IF;
            END IF;
        END IF;
    END PROCESS;

    -- Implement write response logic generation
    -- The write response and response valid signals are asserted by the slave
    -- when axi_wready, S_AXI_WVALID, axi_wready and S_AXI_WVALID are asserted.
    -- This marks the acceptance of address and indicates the status of
    -- write transaction.

    PROCESS (S_AXI_ACLK)
    BEGIN
        IF rising_edge(S_AXI_ACLK) THEN
            IF S_AXI_ARESETN = '0' THEN
                axi_bvalid <= '0';
                axi_bresp <= "00"; --need to work more on the responses
            ELSE
                IF (axi_awready = '1' AND S_AXI_AWVALID = '1' AND axi_wready = '1' AND S_AXI_WVALID = '1' AND axi_bvalid = '0') THEN
                    axi_bvalid <= '1';
                    axi_bresp <= "00";
                ELSIF (S_AXI_BREADY = '1' AND axi_bvalid = '1') THEN --check if bready is asserted while bvalid is high)
                    axi_bvalid <= '0'; -- (there is a possibility that bready is always asserted high)
                END IF;
            END IF;
        END IF;
    END PROCESS;

    -- Implement axi_arready generation
    -- axi_arready is asserted for one S_AXI_ACLK clock cycle when
    -- S_AXI_ARVALID is asserted. axi_awready is
    -- de-asserted when reset (active low) is asserted.
    -- The read address is also latched when S_AXI_ARVALID is
    -- asserted. axi_araddr is reset to zero on reset assertion.

    PROCESS (S_AXI_ACLK)
    BEGIN
        IF rising_edge(S_AXI_ACLK) THEN
            IF S_AXI_ARESETN = '0' THEN
                axi_arready <= '0';
                axi_araddr <= (OTHERS => '1');
            ELSE
                IF (axi_arready = '0' AND S_AXI_ARVALID = '1') THEN
                    -- indicates that the slave has acceped the valid read address
                    axi_arready <= '1';
                    -- Read Address latching
                    axi_araddr <= S_AXI_ARADDR;
                ELSE
                    axi_arready <= '0';
                END IF;
            END IF;
        END IF;
    END PROCESS;

    -- Implement axi_arvalid generation
    -- axi_rvalid is asserted for one S_AXI_ACLK clock cycle when both
    -- S_AXI_ARVALID and axi_arready are asserted. The slave registers
    -- data are available on the axi_rdata bus at this instance. The
    -- assertion of axi_rvalid marks the validity of read data on the
    -- bus and axi_rresp indicates the status of read transaction.axi_rvalid
    -- is deasserted on reset (active low). axi_rresp and axi_rdata are
    -- cleared to zero on reset (active low).
    PROCESS (S_AXI_ACLK)
    BEGIN
        IF rising_edge(S_AXI_ACLK) THEN
            IF S_AXI_ARESETN = '0' THEN
                axi_rvalid <= '0';
                axi_rresp <= "00";
            ELSE
                IF (axi_arready = '1' AND S_AXI_ARVALID = '1' AND axi_rvalid = '0') THEN
                    -- Valid read data is available at the read data bus
                    axi_rvalid <= '1';
                    axi_rresp <= "00"; -- 'OKAY' response
                ELSIF (axi_rvalid = '1' AND S_AXI_RREADY = '1') THEN
                    -- Read data is accepted by the master
                    axi_rvalid <= '0';
                END IF;
            END IF;
        END IF;
    END PROCESS;

    -- Implement memory mapped register select and read logic generation
    -- Slave register read enable is asserted when valid address is available
    -- and the slave is ready to accept the read address.
    slv_reg_rden <= axi_arready AND S_AXI_ARVALID AND (NOT axi_rvalid);

    PROCESS (slv_reg0, slv_reg1, slv_data_o, slv_version_o, axi_araddr, S_AXI_ARESETN, slv_reg_rden)
        VARIABLE loc_addr : STD_LOGIC_VECTOR(OPT_MEM_ADDR_BITS DOWNTO 0);
    BEGIN
        -- Address decoding for reading registers
        loc_addr := axi_araddr(ADDR_LSB + OPT_MEM_ADDR_BITS DOWNTO ADDR_LSB);
        CASE loc_addr IS
            WHEN b"00" =>
                reg_data_out <= slv_reg0;
            WHEN b"01" =>
                reg_data_out <= slv_reg1;
            WHEN b"10" =>
                reg_data_out <= slv_data_o;
            WHEN b"11" =>
                reg_data_out <= slv_version_o;
            WHEN OTHERS =>
                reg_data_out <= (OTHERS => '0');
        END CASE;
    END PROCESS;

    -- Output register or memory read data
    PROCESS (S_AXI_ACLK) IS
    BEGIN
        IF (rising_edge (S_AXI_ACLK)) THEN
            IF (S_AXI_ARESETN = '0') THEN
                axi_rdata <= (OTHERS => '0');
            ELSE
                IF (slv_reg_rden = '1') THEN
                    -- When there is a valid read address (S_AXI_ARVALID) with
                    -- acceptance of read address by the slave (axi_arready),
                    -- output the read dada
                    -- Read address mux
                    axi_rdata <= reg_data_out; -- register read data
                END IF;
            END IF;
        END IF;
    END PROCESS;

    -- Add user logic here

    data_generator_inst : data_generator
    GENERIC MAP(DATA_WITH => C_S_AXI_DATA_WIDTH)
    PORT MAP(
        -- Common control signals
        clk_i => S_AXI_ACLK,
        en_i => slv_reg0(0),
        srst_i => slv_reg1(0),

        -- Data generation
        read_i => read_axi_i,
        data_o => slv_data_o,

        -- Core version
        version_o => slv_version_o
    );

    data_generator_process : PROCESS (S_AXI_ACLK)
        TYPE states_t IS (UNINITIALIZED, WAITING, DETECTED);
        VARIABLE state : states_t := UNINITIALIZED;
        VARIABLE holder : STD_LOGIC := '0';
    BEGIN

        IF (rising_edge(S_AXI_ACLK)) THEN
            CASE state IS

                WHEN UNINITIALIZED =>
                    holder := '0';
                    read_axi_i <= '0';
                    state := WAITING;

                WHEN WAITING =>
                    IF (S_AXI_ARVALID = '1' AND S_AXI_ARADDR = x"8") THEN
                        holder := '0';
                        read_axi_i <= '1';
                        state := DETECTED;
                    END IF;

                WHEN DETECTED =>
                    IF (holder = '1') THEN
                        read_axi_i <= '0';
                        state := WAITING;
                    ELSE
                        holder := '1';
                    END IF;

                WHEN OTHERS =>
                    holder := '0';
                    read_axi_i <= '0';
                    state := WAITING;

            END CASE;
        END IF;

    END PROCESS data_generator_process;

    -- User logic ends

END arch_imp;

@vacagonzalo
Copy link
Author

@alexforencich axi_data_generator_v1_0.vhd

LIBRARY ieee;
USE ieee.std_logic_1164.ALL;
USE ieee.numeric_std.ALL;

ENTITY axi_data_generator_v1_0 IS
    GENERIC (
        -- Users to add parameters here

        -- User parameters ends
        -- Do not modify the parameters beyond this line
        -- Parameters of Axi Slave Bus Interface S00_AXI
        C_S00_AXI_DATA_WIDTH : INTEGER := 32;
        C_S00_AXI_ADDR_WIDTH : INTEGER := 4
    );
    PORT (
        -- Users to add ports here

        -- User ports ends
        -- Do not modify the ports beyond this line
        -- Ports of Axi Slave Bus Interface S00_AXI
        s00_axi_aclk : IN STD_LOGIC;
        s00_axi_aresetn : IN STD_LOGIC;
        s00_axi_awaddr : IN STD_LOGIC_VECTOR(C_S00_AXI_ADDR_WIDTH - 1 DOWNTO 0);
        s00_axi_awprot : IN STD_LOGIC_VECTOR(2 DOWNTO 0);
        s00_axi_awvalid : IN STD_LOGIC;
        s00_axi_awready : OUT STD_LOGIC;
        s00_axi_wdata : IN STD_LOGIC_VECTOR(C_S00_AXI_DATA_WIDTH - 1 DOWNTO 0);
        s00_axi_wstrb : IN STD_LOGIC_VECTOR((C_S00_AXI_DATA_WIDTH/8) - 1 DOWNTO 0);
        s00_axi_wvalid : IN STD_LOGIC;
        s00_axi_wready : OUT STD_LOGIC;
        s00_axi_bresp : OUT STD_LOGIC_VECTOR(1 DOWNTO 0);
        s00_axi_bvalid : OUT STD_LOGIC;
        s00_axi_bready : IN STD_LOGIC;
        s00_axi_araddr : IN STD_LOGIC_VECTOR(C_S00_AXI_ADDR_WIDTH - 1 DOWNTO 0);
        s00_axi_arprot : IN STD_LOGIC_VECTOR(2 DOWNTO 0);
        s00_axi_arvalid : IN STD_LOGIC;
        s00_axi_arready : OUT STD_LOGIC;
        s00_axi_rdata : OUT STD_LOGIC_VECTOR(C_S00_AXI_DATA_WIDTH - 1 DOWNTO 0);
        s00_axi_rresp : OUT STD_LOGIC_VECTOR(1 DOWNTO 0);
        s00_axi_rvalid : OUT STD_LOGIC;
        s00_axi_rready : IN STD_LOGIC
    );
END axi_data_generator_v1_0;

ARCHITECTURE arch_imp OF axi_data_generator_v1_0 IS

    -- component declaration
    COMPONENT axi_data_generator_v1_0_S00_AXI IS
        GENERIC (
            C_S_AXI_DATA_WIDTH : INTEGER := 32;
            C_S_AXI_ADDR_WIDTH : INTEGER := 4
        );
        PORT (
            S_AXI_ACLK : IN STD_LOGIC;
            S_AXI_ARESETN : IN STD_LOGIC;
            S_AXI_AWADDR : IN STD_LOGIC_VECTOR(C_S_AXI_ADDR_WIDTH - 1 DOWNTO 0);
            S_AXI_AWPROT : IN STD_LOGIC_VECTOR(2 DOWNTO 0);
            S_AXI_AWVALID : IN STD_LOGIC;
            S_AXI_AWREADY : OUT STD_LOGIC;
            S_AXI_WDATA : IN STD_LOGIC_VECTOR(C_S_AXI_DATA_WIDTH - 1 DOWNTO 0);
            S_AXI_WSTRB : IN STD_LOGIC_VECTOR((C_S_AXI_DATA_WIDTH/8) - 1 DOWNTO 0);
            S_AXI_WVALID : IN STD_LOGIC;
            S_AXI_WREADY : OUT STD_LOGIC;
            S_AXI_BRESP : OUT STD_LOGIC_VECTOR(1 DOWNTO 0);
            S_AXI_BVALID : OUT STD_LOGIC;
            S_AXI_BREADY : IN STD_LOGIC;
            S_AXI_ARADDR : IN STD_LOGIC_VECTOR(C_S_AXI_ADDR_WIDTH - 1 DOWNTO 0);
            S_AXI_ARPROT : IN STD_LOGIC_VECTOR(2 DOWNTO 0);
            S_AXI_ARVALID : IN STD_LOGIC;
            S_AXI_ARREADY : OUT STD_LOGIC;
            S_AXI_RDATA : OUT STD_LOGIC_VECTOR(C_S_AXI_DATA_WIDTH - 1 DOWNTO 0);
            S_AXI_RRESP : OUT STD_LOGIC_VECTOR(1 DOWNTO 0);
            S_AXI_RVALID : OUT STD_LOGIC;
            S_AXI_RREADY : IN STD_LOGIC
        );
    END COMPONENT axi_data_generator_v1_0_S00_AXI;

BEGIN

    -- Instantiation of Axi Bus Interface S00_AXI
    axi_data_generator_v1_0_S00_AXI_inst : axi_data_generator_v1_0_S00_AXI
    GENERIC MAP(
        C_S_AXI_DATA_WIDTH => C_S00_AXI_DATA_WIDTH,
        C_S_AXI_ADDR_WIDTH => C_S00_AXI_ADDR_WIDTH
    )
    PORT MAP(
        S_AXI_ACLK => s00_axi_aclk,
        S_AXI_ARESETN => s00_axi_aresetn,
        S_AXI_AWADDR => s00_axi_awaddr,
        S_AXI_AWPROT => s00_axi_awprot,
        S_AXI_AWVALID => s00_axi_awvalid,
        S_AXI_AWREADY => s00_axi_awready,
        S_AXI_WDATA => s00_axi_wdata,
        S_AXI_WSTRB => s00_axi_wstrb,
        S_AXI_WVALID => s00_axi_wvalid,
        S_AXI_WREADY => s00_axi_wready,
        S_AXI_BRESP => s00_axi_bresp,
        S_AXI_BVALID => s00_axi_bvalid,
        S_AXI_BREADY => s00_axi_bready,
        S_AXI_ARADDR => s00_axi_araddr,
        S_AXI_ARPROT => s00_axi_arprot,
        S_AXI_ARVALID => s00_axi_arvalid,
        S_AXI_ARREADY => s00_axi_arready,
        S_AXI_RDATA => s00_axi_rdata,
        S_AXI_RRESP => s00_axi_rresp,
        S_AXI_RVALID => s00_axi_rvalid,
        S_AXI_RREADY => s00_axi_rready
    );

    -- Add user logic here

    -- User logic ends

END arch_imp;

@alexforencich
Copy link
Owner

Ah, I see your "minimal working example" is actually working, I though it was also hanging. That reset operation looks fine to me - assert it for a few cycles, then release it. Not sure if there is a "better" way of doing that, all of my reset drivers look pretty much just like that.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants