aboutsummaryrefslogtreecommitdiffstats
path: root/testsuite
diff options
context:
space:
mode:
authorTristan Gingold <tgingold@free.fr>2022-09-02 18:28:00 +0200
committerTristan Gingold <tgingold@free.fr>2022-09-02 18:28:00 +0200
commit0d6b21c3b5639af8b321cc7f85fbf03da78d7edb (patch)
tree4eeaabab655fbb211620c00a30655ab21bb63535 /testsuite
parent3d7d926280194cdbc437db869e3e96303109a6ee (diff)
downloadghdl-0d6b21c3b5639af8b321cc7f85fbf03da78d7edb.tar.gz
ghdl-0d6b21c3b5639af8b321cc7f85fbf03da78d7edb.tar.bz2
ghdl-0d6b21c3b5639af8b321cc7f85fbf03da78d7edb.zip
testsuite/gna: add a test for #2185
Diffstat (limited to 'testsuite')
-rw-r--r--testsuite/gna/issue2185/avm_arbit.vhd156
-rw-r--r--testsuite/gna/issue2185/avm_master.vhd198
-rw-r--r--testsuite/gna/issue2185/avm_master_general.vhd124
-rw-r--r--testsuite/gna/issue2185/avm_memory.vhd88
-rw-r--r--testsuite/gna/issue2185/avm_pause.vhd74
-rw-r--r--testsuite/gna/issue2185/burst_ctrl.vhd88
-rw-r--r--testsuite/gna/issue2185/tb_avm_arbit.vhd220
-rwxr-xr-xtestsuite/gna/issue2185/testsuite.sh21
8 files changed, 969 insertions, 0 deletions
diff --git a/testsuite/gna/issue2185/avm_arbit.vhd b/testsuite/gna/issue2185/avm_arbit.vhd
new file mode 100644
index 000000000..d1516c669
--- /dev/null
+++ b/testsuite/gna/issue2185/avm_arbit.vhd
@@ -0,0 +1,156 @@
+library ieee;
+use ieee.std_logic_1164.all;
+use ieee.numeric_std.all;
+use ieee.numeric_std_unsigned.all;
+
+-- This arbitrates fairly between two Masters connected to a single Slave
+
+entity avm_arbit is
+ generic (
+ G_ADDRESS_SIZE : integer;
+ G_DATA_SIZE : integer
+ );
+ port (
+ clk_i : in std_logic;
+ rst_i : in std_logic;
+
+ -- Slave interface 0 (input)
+ s0_avm_write_i : in std_logic;
+ s0_avm_read_i : in std_logic;
+ s0_avm_address_i : in std_logic_vector(G_ADDRESS_SIZE-1 downto 0);
+ s0_avm_writedata_i : in std_logic_vector(G_DATA_SIZE-1 downto 0);
+ s0_avm_byteenable_i : in std_logic_vector(G_DATA_SIZE/8-1 downto 0);
+ s0_avm_burstcount_i : in std_logic_vector(7 downto 0);
+ s0_avm_readdata_o : out std_logic_vector(G_DATA_SIZE-1 downto 0);
+ s0_avm_readdatavalid_o : out std_logic;
+ s0_avm_waitrequest_o : out std_logic;
+
+ -- Slave interface 1 (input)
+ s1_avm_write_i : in std_logic;
+ s1_avm_read_i : in std_logic;
+ s1_avm_address_i : in std_logic_vector(G_ADDRESS_SIZE-1 downto 0);
+ s1_avm_writedata_i : in std_logic_vector(G_DATA_SIZE-1 downto 0);
+ s1_avm_byteenable_i : in std_logic_vector(G_DATA_SIZE/8-1 downto 0);
+ s1_avm_burstcount_i : in std_logic_vector(7 downto 0);
+ s1_avm_readdata_o : out std_logic_vector(G_DATA_SIZE-1 downto 0);
+ s1_avm_readdatavalid_o : out std_logic;
+ s1_avm_waitrequest_o : out std_logic;
+
+ -- Master interface (output)
+ m_avm_write_o : out std_logic;
+ m_avm_read_o : out std_logic;
+ m_avm_address_o : out std_logic_vector(G_ADDRESS_SIZE-1 downto 0);
+ m_avm_writedata_o : out std_logic_vector(G_DATA_SIZE-1 downto 0);
+ m_avm_byteenable_o : out std_logic_vector(G_DATA_SIZE/8-1 downto 0);
+ m_avm_burstcount_o : out std_logic_vector(7 downto 0);
+ m_avm_readdata_i : in std_logic_vector(G_DATA_SIZE-1 downto 0);
+ m_avm_readdatavalid_i : in std_logic;
+ m_avm_waitrequest_i : in std_logic
+ );
+end entity avm_arbit;
+
+architecture synthesis of avm_arbit is
+
+ signal s0_active_req : std_logic;
+ signal s1_active_req : std_logic;
+
+ signal s0_active_grant : std_logic := '0';
+ signal s1_active_grant : std_logic := '0';
+ signal active_grants : std_logic_vector(1 downto 0);
+
+ signal last_grant : std_logic := '0';
+
+ signal burstcount : std_logic_vector(7 downto 0);
+
+begin
+
+ s0_avm_waitrequest_o <= not s0_active_grant;
+ s1_avm_waitrequest_o <= not s1_active_grant;
+
+ s0_active_req <= s0_avm_write_i or s0_avm_read_i;
+ s1_active_req <= s1_avm_write_i or s1_avm_read_i;
+
+ p_burstcount : process (clk_i)
+ begin
+ if rising_edge(clk_i) then
+ if burstcount = X"00" then
+ if s0_avm_write_i and not s0_avm_waitrequest_o then
+ burstcount <= s0_avm_burstcount_i;
+ end if;
+ if s1_avm_write_i and not s1_avm_waitrequest_o then
+ burstcount <= s1_avm_burstcount_i;
+ end if;
+ else
+ if (s0_avm_write_i and not s0_avm_waitrequest_o) or
+ s0_avm_readdatavalid_o or
+ (s1_avm_write_i and not s1_avm_waitrequest_o) or
+ s1_avm_readdatavalid_o then
+ burstcount <= burstcount - 1;
+ end if;
+ end if;
+
+ if rst_i = '1' then
+ burstcount <= X"00";
+ end if;
+ end if;
+ end process p_burstcount;
+
+ active_grants <= s0_active_grant & s1_active_grant;
+
+ p_grant : process (clk_i)
+ begin
+ if rising_edge(clk_i) then
+ case active_grants is
+ when "00" =>
+ if s0_active_req = '1' and last_grant = '1' then
+ s0_active_grant <= '1';
+ last_grant <= '1';
+ end if;
+ if s1_active_req = '1' and last_grant = '0' then
+ s1_active_grant <= '1';
+ last_grant <= '0';
+ end if;
+
+ when "01" =>
+ if burstcount = X"01" then
+ if (s1_avm_write_i and not s1_avm_waitrequest_o) or
+ s1_avm_readdatavalid_o then
+ s1_active_grant <= '0';
+ end if;
+ end if;
+ when "10" =>
+ if burstcount = X"01" then
+ if (s0_avm_write_i and not s0_avm_waitrequest_o) or
+ s0_avm_readdatavalid_o then
+ s0_active_grant <= '0';
+ end if;
+ end if;
+
+ when others =>
+ report "S0 and S1 both active"
+ severity failure;
+ end case;
+
+ if rst_i = '1' then
+ s0_active_grant <= '0';
+ s1_active_grant <= '0';
+ last_grant <= '0';
+ end if;
+ end if;
+ end process p_grant;
+
+ m_avm_write_o <= s0_avm_write_i when last_grant = '0' else s1_avm_write_i;
+ m_avm_read_o <= s0_avm_read_i when last_grant = '0' else s1_avm_read_i;
+ m_avm_address_o <= s0_avm_address_i when last_grant = '0' else s1_avm_address_i;
+ m_avm_writedata_o <= s0_avm_writedata_i when last_grant = '0' else s1_avm_writedata_i;
+ m_avm_byteenable_o <= s0_avm_byteenable_i when last_grant = '0' else s1_avm_byteenable_i;
+ m_avm_burstcount_o <= s0_avm_burstcount_i when last_grant = '0' else s1_avm_burstcount_i;
+
+ s0_avm_readdata_o <= m_avm_readdata_i;
+ s0_avm_readdatavalid_o <= m_avm_readdatavalid_i when last_grant = '0' else '0';
+
+ s1_avm_readdata_o <= m_avm_readdata_i;
+ s1_avm_readdatavalid_o <= m_avm_readdatavalid_i when last_grant = '1' else '0';
+
+end architecture synthesis;
+
diff --git a/testsuite/gna/issue2185/avm_master.vhd b/testsuite/gna/issue2185/avm_master.vhd
new file mode 100644
index 000000000..b7de25a72
--- /dev/null
+++ b/testsuite/gna/issue2185/avm_master.vhd
@@ -0,0 +1,198 @@
+-- This module is a simple kind of RAM test.
+--
+-- It generates first a sequence of WRITE operations (writing pseudo-random data),
+-- and then a corresponding sequence of READ operations, verifying that the
+-- correct values are read back again.
+--
+-- Created by Michael Jørgensen in 2022 (mjoergen.github.io/HyperRAM).
+
+library ieee;
+use ieee.std_logic_1164.all;
+use ieee.numeric_std.all;
+
+entity avm_master is
+ generic (
+ G_ADDRESS_SIZE : integer; -- Number of bits
+ G_DATA_SIZE : integer -- Number of bits
+ );
+ port (
+ clk_i : in std_logic;
+ rst_i : in std_logic;
+ start_i : in std_logic;
+ wait_o : out std_logic;
+ write_burstcount_i : in std_logic_vector(7 downto 0);
+ read_burstcount_i : in std_logic_vector(7 downto 0);
+
+ avm_write_o : out std_logic;
+ avm_read_o : out std_logic;
+ avm_address_o : out std_logic_vector(G_ADDRESS_SIZE-1 downto 0);
+ avm_writedata_o : out std_logic_vector(G_DATA_SIZE-1 downto 0);
+ avm_byteenable_o : out std_logic_vector(G_DATA_SIZE/8-1 downto 0);
+ avm_burstcount_o : out std_logic_vector(7 downto 0);
+ avm_readdata_i : in std_logic_vector(G_DATA_SIZE-1 downto 0);
+ avm_readdatavalid_i : in std_logic;
+ avm_waitrequest_i : in std_logic;
+ -- Debug output
+ address_o : out std_logic_vector(G_ADDRESS_SIZE-1 downto 0);
+ data_exp_o : out std_logic_vector(G_DATA_SIZE-1 downto 0);
+ data_read_o : out std_logic_vector(G_DATA_SIZE-1 downto 0);
+ error_o : out std_logic
+ );
+end entity avm_master;
+
+architecture synthesis of avm_master is
+
+ constant C_DATA_INIT : std_logic_vector(63 downto 0) := X"CAFEBABEDEADBEEF";
+
+ signal data_init : std_logic_vector(63 downto 0);
+
+ signal wr_data : std_logic_vector(63 downto 0);
+ signal rd_data : std_logic_vector(63 downto 0);
+ signal burstcount : std_logic_vector(7 downto 0);
+ signal read_burstcount : std_logic_vector(7 downto 0);
+ signal wordcount : integer range 0 to 255;
+ signal new_address : std_logic_vector(G_ADDRESS_SIZE-1 downto 0);
+ signal new_burstcount : std_logic_vector(7 downto 0);
+
+ type state_t is (
+ INIT_ST,
+ WRITING_ST,
+ READING_ST
+ );
+
+ signal state : state_t := INIT_ST;
+ signal reset_verify : std_logic;
+
+ -- The pseudo-random data is generated using a 64-bit maximal-period Galois LFSR,
+ -- see http://users.ece.cmu.edu/~koopman/lfsr/64.txt
+ function lfsr (constant old : std_logic_vector(63 downto 0)) return std_logic_vector is
+ begin
+ if old(63) = '1' then
+ return (old(62 downto 0) & "0") xor x"000000000000001b";
+ else
+ return (old(62 downto 0) & "0");
+ end if;
+ end function lfsr;
+
+begin
+
+ new_address <= avm_address_o when unsigned(avm_burstcount_o) > 1 else
+ std_logic_vector(unsigned(avm_address_o) + wordcount);
+ new_burstcount <= std_logic_vector(unsigned(avm_burstcount_o) - 1) when unsigned(avm_burstcount_o) > 1 else
+ burstcount;
+
+ p_verifier : process (clk_i)
+ begin
+ if rising_edge(clk_i) then
+ if avm_readdatavalid_i = '1' then
+ data_read_o <= avm_readdata_i;
+ data_exp_o <= rd_data(G_DATA_SIZE-1 downto 0);
+
+ if avm_readdata_i /= rd_data(G_DATA_SIZE-1 downto 0) then
+ report "ERROR: Expected " & to_hstring(rd_data(G_DATA_SIZE-1 downto 0)) & ", read " & to_hstring(avm_readdata_i)
+ severity failure;
+ error_o <= '1';
+ else
+ rd_data <= lfsr(rd_data);
+ end if;
+ end if;
+
+ if reset_verify = '1' then
+ rd_data <= data_init;
+ error_o <= '0';
+ end if;
+
+ if rst_i = '1' then
+ error_o <= '0';
+ end if;
+ end if;
+ end process p_verifier;
+
+ p_fsm : process (clk_i)
+ begin
+ if rising_edge(clk_i) then
+ reset_verify <= '0';
+
+ if avm_waitrequest_i = '0' then
+ avm_write_o <= '0';
+ avm_read_o <= '0';
+ end if;
+
+ case state is
+ when INIT_ST =>
+ if start_i = '1' then
+ wait_o <= '1';
+ wr_data <= C_DATA_INIT xor (
+ write_burstcount_i & read_burstcount_i &
+ write_burstcount_i & read_burstcount_i &
+ write_burstcount_i & read_burstcount_i &
+ write_burstcount_i & read_burstcount_i);
+ data_init <= C_DATA_INIT xor (
+ write_burstcount_i & read_burstcount_i &
+ write_burstcount_i & read_burstcount_i &
+ write_burstcount_i & read_burstcount_i &
+ write_burstcount_i & read_burstcount_i);
+ avm_write_o <= '1';
+ avm_read_o <= '0';
+ avm_address_o <= (others => '0');
+ avm_byteenable_o <= (others => '1');
+ avm_burstcount_o <= write_burstcount_i;
+ burstcount <= write_burstcount_i;
+ read_burstcount <= read_burstcount_i;
+ wordcount <= to_integer(unsigned(write_burstcount_i));
+ state <= WRITING_ST;
+ end if;
+
+ when WRITING_ST =>
+ if avm_waitrequest_i = '0' then
+ avm_write_o <= '1';
+ avm_read_o <= '0';
+ avm_address_o <= new_address;
+ avm_byteenable_o <= (others => '1');
+ avm_burstcount_o <= new_burstcount;
+
+ wr_data <= lfsr(wr_data);
+
+ if signed(avm_address_o) = -wordcount and unsigned(avm_burstcount_o) = 1 then
+ wr_data <= data_init;
+ avm_write_o <= '0';
+ avm_address_o <= (others => '0');
+ avm_read_o <= '1';
+ avm_burstcount_o <= read_burstcount;
+ burstcount <= read_burstcount;
+ wordcount <= to_integer(unsigned(read_burstcount));
+ data_read_o <= (others => '0');
+ data_exp_o <= (others => '0');
+ reset_verify <= '1';
+ state <= READING_ST;
+ end if;
+ end if;
+
+ when READING_ST =>
+ if avm_waitrequest_i = '0' then
+
+ if signed(avm_address_o) = -wordcount then
+ wait_o <= '0';
+ state <= INIT_ST;
+ else
+ avm_address_o <= std_logic_vector(unsigned(avm_address_o) + wordcount);
+ avm_read_o <= '1';
+ end if;
+ end if;
+
+ end case;
+
+ if rst_i = '1' then
+ avm_write_o <= '0';
+ avm_read_o <= '0';
+ wait_o <= '0';
+ state <= INIT_ST;
+ end if;
+ end if;
+ end process p_fsm;
+
+ avm_writedata_o <= wr_data(G_DATA_SIZE-1 downto 0);
+ address_o <= avm_address_o;
+
+end architecture synthesis;
+
diff --git a/testsuite/gna/issue2185/avm_master_general.vhd b/testsuite/gna/issue2185/avm_master_general.vhd
new file mode 100644
index 000000000..756465ae3
--- /dev/null
+++ b/testsuite/gna/issue2185/avm_master_general.vhd
@@ -0,0 +1,124 @@
+library ieee;
+use ieee.std_logic_1164.all;
+use ieee.numeric_std.all;
+
+entity avm_master_general is
+ generic (
+ G_ADDRESS_SIZE : integer; -- Number of bits
+ G_DATA_SIZE : integer -- Number of bits
+ );
+ port (
+ clk_i : in std_logic;
+ rst_i : in std_logic;
+ start_i : in std_logic;
+ wait_o : out std_logic;
+ m_avm_write_o : out std_logic;
+ m_avm_read_o : out std_logic;
+ m_avm_address_o : out std_logic_vector(G_ADDRESS_SIZE-1 downto 0);
+ m_avm_writedata_o : out std_logic_vector(G_DATA_SIZE-1 downto 0);
+ m_avm_byteenable_o : out std_logic_vector(G_DATA_SIZE/8-1 downto 0);
+ m_avm_burstcount_o : out std_logic_vector(7 downto 0);
+ m_avm_readdata_i : in std_logic_vector(G_DATA_SIZE-1 downto 0);
+ m_avm_readdatavalid_i : in std_logic;
+ m_avm_waitrequest_i : in std_logic
+ );
+end entity avm_master_general;
+
+architecture synthesis of avm_master_general is
+
+ signal avm_start : std_logic;
+ signal avm_wait : std_logic;
+ signal avm_write_burstcount : std_logic_vector(7 downto 0);
+ signal avm_read_burstcount : std_logic_vector(7 downto 0);
+ signal avm_write : std_logic;
+ signal avm_read : std_logic;
+ signal avm_address : std_logic_vector(G_ADDRESS_SIZE-1 downto 0);
+ signal avm_writedata : std_logic_vector(G_DATA_SIZE-1 downto 0);
+ signal avm_byteenable : std_logic_vector(G_DATA_SIZE/8-1 downto 0);
+ signal avm_burstcount : std_logic_vector(7 downto 0);
+ signal avm_readdata : std_logic_vector(G_DATA_SIZE-1 downto 0);
+ signal avm_readdatavalid : std_logic;
+ signal avm_waitrequest : std_logic;
+
+begin
+
+ ---------------------------------------------------------
+ -- Instantiate burst controller
+ ---------------------------------------------------------
+
+ i_burst_ctrl : entity work.burst_ctrl
+ port map (
+ clk_i => clk_i,
+ rst_i => rst_i,
+ start_i => start_i,
+ wait_o => wait_o,
+ start_o => avm_start,
+ wait_i => avm_wait,
+ write_burstcount_o => avm_write_burstcount,
+ read_burstcount_o => avm_read_burstcount
+ ); -- i_burst_ctrl
+
+
+ ---------------------------------------------------------
+ -- Instantiate Master
+ ---------------------------------------------------------
+
+ i_avm_master : entity work.avm_master
+ generic map (
+ G_ADDRESS_SIZE => G_ADDRESS_SIZE,
+ G_DATA_SIZE => G_DATA_SIZE
+ )
+ port map (
+ clk_i => clk_i,
+ rst_i => rst_i,
+ start_i => avm_start,
+ wait_o => avm_wait,
+ write_burstcount_i => avm_write_burstcount,
+ read_burstcount_i => avm_read_burstcount,
+ avm_write_o => avm_write,
+ avm_read_o => avm_read,
+ avm_address_o => avm_address,
+ avm_writedata_o => avm_writedata,
+ avm_byteenable_o => avm_byteenable,
+ avm_burstcount_o => avm_burstcount,
+ avm_readdata_i => avm_readdata,
+ avm_readdatavalid_i => avm_readdatavalid,
+ avm_waitrequest_i => avm_waitrequest
+ ); -- i_avm_master
+
+
+ ---------------------------------------------------------
+ -- Generate pauses in master trafic
+ ---------------------------------------------------------
+
+ i_avm_pause_master : entity work.avm_pause
+ generic map (
+ G_PAUSE => 0,
+ G_ADDRESS_SIZE => G_ADDRESS_SIZE,
+ G_DATA_SIZE => G_DATA_SIZE
+ )
+ port map (
+ clk_i => clk_i,
+ rst_i => rst_i,
+ s_avm_write_i => avm_write,
+ s_avm_read_i => avm_read,
+ s_avm_address_i => avm_address,
+ s_avm_writedata_i => avm_writedata,
+ s_avm_byteenable_i => avm_byteenable,
+ s_avm_burstcount_i => avm_burstcount,
+ s_avm_readdata_o => avm_readdata,
+ s_avm_readdatavalid_o => avm_readdatavalid,
+ s_avm_waitrequest_o => avm_waitrequest,
+ m_avm_write_o => m_avm_write_o,
+ m_avm_read_o => m_avm_read_o,
+ m_avm_address_o => m_avm_address_o,
+ m_avm_writedata_o => m_avm_writedata_o,
+ m_avm_byteenable_o => m_avm_byteenable_o,
+ m_avm_burstcount_o => m_avm_burstcount_o,
+ m_avm_readdata_i => m_avm_readdata_i,
+ m_avm_readdatavalid_i => m_avm_readdatavalid_i,
+ m_avm_waitrequest_i => m_avm_waitrequest_i
+ ); -- i_avm_pause_master
+
+end architecture synthesis;
+
diff --git a/testsuite/gna/issue2185/avm_memory.vhd b/testsuite/gna/issue2185/avm_memory.vhd
new file mode 100644
index 000000000..9c045d7cb
--- /dev/null
+++ b/testsuite/gna/issue2185/avm_memory.vhd
@@ -0,0 +1,88 @@
+library ieee;
+use ieee.std_logic_1164.all;
+use ieee.numeric_std.all;
+
+entity avm_memory is
+ generic (
+ G_ADDRESS_SIZE : integer; -- Number of bits
+ G_DATA_SIZE : integer -- Number of bits
+ );
+ port (
+ clk_i : in std_logic;
+ rst_i : in std_logic;
+ avm_write_i : in std_logic;
+ avm_read_i : in std_logic;
+ avm_address_i : in std_logic_vector(G_ADDRESS_SIZE-1 downto 0);
+ avm_writedata_i : in std_logic_vector(G_DATA_SIZE-1 downto 0);
+ avm_byteenable_i : in std_logic_vector(G_DATA_SIZE/8-1 downto 0);
+ avm_burstcount_i : in std_logic_vector(7 downto 0);
+ avm_readdata_o : out std_logic_vector(G_DATA_SIZE-1 downto 0);
+ avm_readdatavalid_o : out std_logic;
+ avm_waitrequest_o : out std_logic
+ );
+end entity avm_memory;
+
+architecture simulation of avm_memory is
+
+ -- This defines a type containing an array of bytes
+ type mem_t is array (0 to 2**G_ADDRESS_SIZE-1) of std_logic_vector(G_DATA_SIZE-1 downto 0);
+
+ signal write_burstcount : std_logic_vector(7 downto 0);
+ signal write_address : std_logic_vector(G_ADDRESS_SIZE-1 downto 0);
+
+ signal read_burstcount : std_logic_vector(7 downto 0);
+ signal read_address : std_logic_vector(G_ADDRESS_SIZE-1 downto 0);
+
+ signal mem_write_burstcount : std_logic_vector(7 downto 0);
+ signal mem_read_burstcount : std_logic_vector(7 downto 0);
+ signal mem_write_address : std_logic_vector(G_ADDRESS_SIZE-1 downto 0);
+ signal mem_read_address : std_logic_vector(G_ADDRESS_SIZE-1 downto 0);
+
+begin
+
+ mem_write_address <= avm_address_i when write_burstcount = X"00" else write_address;
+ mem_read_address <= avm_address_i when read_burstcount = X"00" else read_address;
+ mem_write_burstcount <= avm_burstcount_i when write_burstcount = X"00" else write_burstcount;
+ mem_read_burstcount <= avm_burstcount_i when read_burstcount = X"00" else read_burstcount;
+
+ avm_waitrequest_o <= '0' when unsigned(read_burstcount) = 0 else '1';
+
+ p_mem : process (clk_i)
+ variable mem : mem_t;
+ begin
+ if rising_edge(clk_i) then
+ avm_readdatavalid_o <= '0';
+
+ if avm_write_i = '1' and avm_waitrequest_o = '0' then
+ write_address <= std_logic_vector(unsigned(mem_write_address) + 1);
+ write_burstcount <= std_logic_vector(unsigned(mem_write_burstcount) - 1);
+
+ report "Writing 0x" & to_hstring(avm_writedata_i) & " to 0x" & to_hstring(mem_write_address) &
+ " with burstcount " & to_hstring(write_burstcount);
+ for b in 0 to G_DATA_SIZE/8-1 loop
+ if avm_byteenable_i(b) = '1' then
+ mem(to_integer(unsigned(mem_write_address)))(8*b+7 downto 8*b) := avm_writedata_i(8*b+7 downto 8*b);
+ end if;
+ end loop;
+ end if;
+
+ if (avm_read_i = '1' and avm_waitrequest_o = '0') or to_integer(unsigned(read_burstcount)) > 0 then
+ read_address <= std_logic_vector(unsigned(mem_read_address) + 1);
+ read_burstcount <= std_logic_vector(unsigned(mem_read_burstcount) - 1);
+
+ avm_readdata_o <= mem(to_integer(unsigned(mem_read_address)));
+ avm_readdatavalid_o <= '1';
+
+ report "Reading 0x" & to_hstring(mem(to_integer(unsigned(mem_read_address)))) & " from 0x" & to_hstring(mem_read_address) &
+ " with burstcount " & to_hstring(read_burstcount);
+ end if;
+
+ if rst_i = '1' then
+ write_burstcount <= (others => '0');
+ read_burstcount <= (others => '0');
+ end if;
+ end if;
+ end process p_mem;
+
+end architecture simulation;
+
diff --git a/testsuite/gna/issue2185/avm_pause.vhd b/testsuite/gna/issue2185/avm_pause.vhd
new file mode 100644
index 000000000..6cd8baba6
--- /dev/null
+++ b/testsuite/gna/issue2185/avm_pause.vhd
@@ -0,0 +1,74 @@
+-- This module inserts empty wait cycles into an Avalon Memory Map stream.
+-- The throughput is 1 - 1/G_PAUSE.
+-- So a value of 4 results in a 75% throughput.
+--
+-- Created by Michael Jørgensen in 2022 (mjoergen.github.io/HyperRAM).
+
+library ieee;
+use ieee.std_logic_1164.all;
+use ieee.numeric_std.all;
+
+entity avm_pause is
+ generic (
+ G_PAUSE : integer;
+ G_ADDRESS_SIZE : integer; -- Number of bits
+ G_DATA_SIZE : integer -- Number of bits
+ );
+ port (
+ clk_i : in std_logic;
+ rst_i : in std_logic;
+ s_avm_write_i : in std_logic;
+ s_avm_read_i : in std_logic;
+ s_avm_address_i : in std_logic_vector(G_ADDRESS_SIZE-1 downto 0);
+ s_avm_writedata_i : in std_logic_vector(G_DATA_SIZE-1 downto 0);
+ s_avm_byteenable_i : in std_logic_vector(G_DATA_SIZE/8-1 downto 0);
+ s_avm_burstcount_i : in std_logic_vector(7 downto 0);
+ s_avm_readdata_o : out std_logic_vector(G_DATA_SIZE-1 downto 0);
+ s_avm_readdatavalid_o : out std_logic;
+ s_avm_waitrequest_o : out std_logic;
+ m_avm_write_o : out std_logic;
+ m_avm_read_o : out std_logic;
+ m_avm_address_o : out std_logic_vector(G_ADDRESS_SIZE-1 downto 0);
+ m_avm_writedata_o : out std_logic_vector(G_DATA_SIZE-1 downto 0);
+ m_avm_byteenable_o : out std_logic_vector(G_DATA_SIZE/8-1 downto 0);
+ m_avm_burstcount_o : out std_logic_vector(7 downto 0);
+ m_avm_readdata_i : in std_logic_vector(G_DATA_SIZE-1 downto 0);
+ m_avm_readdatavalid_i : in std_logic;
+ m_avm_waitrequest_i : in std_logic
+ );
+end entity avm_pause;
+
+architecture synthesis of avm_pause is
+
+ signal cnt : integer range 0 to G_PAUSE;
+ signal allow : std_logic;
+
+begin
+
+ p_cnt : process (clk_i)
+ begin
+ if rising_edge(clk_i) then
+ if m_avm_waitrequest_i = '0' then
+ cnt <= (cnt + 1) mod G_PAUSE;
+ end if;
+
+ if rst_i = '1' then
+ cnt <= 0;
+ end if;
+ end if;
+ end process p_cnt;
+
+ allow <= '1' when cnt /= 0 or G_PAUSE = 0 else '0';
+
+ m_avm_write_o <= s_avm_write_i and allow;
+ m_avm_read_o <= s_avm_read_i and allow;
+ m_avm_address_o <= s_avm_address_i;
+ m_avm_writedata_o <= s_avm_writedata_i;
+ m_avm_byteenable_o <= s_avm_byteenable_i;
+ m_avm_burstcount_o <= s_avm_burstcount_i;
+ s_avm_readdata_o <= m_avm_readdata_i;
+ s_avm_readdatavalid_o <= m_avm_readdatavalid_i;
+ s_avm_waitrequest_o <= m_avm_waitrequest_i or not allow;
+
+end architecture synthesis;
+
diff --git a/testsuite/gna/issue2185/burst_ctrl.vhd b/testsuite/gna/issue2185/burst_ctrl.vhd
new file mode 100644
index 000000000..56559dd2c
--- /dev/null
+++ b/testsuite/gna/issue2185/burst_ctrl.vhd
@@ -0,0 +1,88 @@
+-- This generates a sequence of commands with varying values
+-- of write_burstcount and read_burstcount.
+-- Signals start_i and wait_o are connected "upstream", in this case
+-- to the keyboard LEDs, while start_o and wait_i are connected "downstream",
+-- in this case to the avm_master entity.
+--
+-- Created by Michael Jørgensen in 2022 (mjoergen.github.io/HyperRAM).
+
+library ieee;
+use ieee.std_logic_1164.all;
+use ieee.numeric_std.all;
+
+entity burst_ctrl is
+ port (
+ clk_i : in std_logic;
+ rst_i : in std_logic;
+ -- Connect "upstream", i.e. to keyboard and LED
+ start_i : in std_logic;
+ wait_o : out std_logic;
+ -- Connect "downstream", i.e. to avm_master
+ start_o : out std_logic;
+ wait_i : in std_logic;
+ write_burstcount_o : out std_logic_vector(7 downto 0);
+ read_burstcount_o : out std_logic_vector(7 downto 0)
+ );
+end entity burst_ctrl;
+
+architecture synthesis of burst_ctrl is
+
+ constant C_MAX_BURST : std_logic_vector(7 downto 0) := X"08";
+
+ type state_t is (
+ IDLE_ST,
+ BUSY_ST
+ );
+
+ signal state : state_t;
+
+begin
+
+ p_fsm : process (clk_i)
+ begin
+ if rising_edge(clk_i) then
+ -- Clear outgoing request when accepted
+ if wait_i = '0' then
+ start_o <= '0';
+ end if;
+
+ case state is
+ when IDLE_ST =>
+ if start_i = '1' then
+ start_o <= '1';
+ state <= BUSY_ST;
+ end if;
+
+ when BUSY_ST =>
+ if wait_i = '0' and start_o = '0' then
+ start_o <= '1';
+
+ if write_burstcount_o /= C_MAX_BURST then
+ write_burstcount_o <= write_burstcount_o(6 downto 0) & "0";
+ else
+ write_burstcount_o <= X"01";
+ if read_burstcount_o /= C_MAX_BURST then
+ read_burstcount_o <= read_burstcount_o(6 downto 0) & "0";
+ else
+ read_burstcount_o <= X"01";
+ start_o <= '0';
+ state <= IDLE_ST;
+ report "Test completed";
+ end if;
+ end if;
+ end if;
+ end case;
+
+ if rst_i = '1' then
+ start_o <= '0';
+ write_burstcount_o <= X"01";
+ read_burstcount_o <= X"01";
+ end if;
+
+ end if;
+ end process p_fsm;
+
+ wait_o <= '0' when state = IDLE_ST else '1';
+
+end architecture synthesis;
+
diff --git a/testsuite/gna/issue2185/tb_avm_arbit.vhd b/testsuite/gna/issue2185/tb_avm_arbit.vhd
new file mode 100644
index 000000000..a4e386c08
--- /dev/null
+++ b/testsuite/gna/issue2185/tb_avm_arbit.vhd
@@ -0,0 +1,220 @@
+library ieee;
+use ieee.std_logic_1164.all;
+use ieee.numeric_std.all;
+
+entity tb_avm_arbit is
+end entity tb_avm_arbit;
+
+architecture simulation of tb_avm_arbit is
+
+ constant C_DATA_SIZE : integer := 16;
+ constant C_ADDRESS_SIZE : integer := 4;
+
+ signal clk : std_logic;
+ signal rst : std_logic;
+ signal tb_start : std_logic;
+ signal tb_wait : std_logic;
+ signal stop_test : std_logic := '0';
+
+ signal m0_avm_wait : std_logic;
+ signal m0_avm_write : std_logic;
+ signal m0_avm_read : std_logic;
+ signal m0_avm_address : std_logic_vector(C_ADDRESS_SIZE-1 downto 0);
+ signal m0_avm_writedata : std_logic_vector(C_DATA_SIZE-1 downto 0);
+ signal m0_avm_byteenable : std_logic_vector(C_DATA_SIZE/8-1 downto 0);
+ signal m0_avm_burstcount : std_logic_vector(7 downto 0);
+ signal m0_avm_readdata : std_logic_vector(C_DATA_SIZE-1 downto 0);
+ signal m0_avm_readdatavalid : std_logic;
+ signal m0_avm_waitrequest : std_logic;
+
+ signal m1_avm_wait : std_logic;
+ signal m1_avm_write : std_logic;
+ signal m1_avm_read : std_logic;
+ signal m1_avm_address : std_logic_vector(C_ADDRESS_SIZE-1 downto 0);
+ signal m1_avm_writedata : std_logic_vector(C_DATA_SIZE-1 downto 0);
+ signal m1_avm_byteenable : std_logic_vector(C_DATA_SIZE/8-1 downto 0);
+ signal m1_avm_burstcount : std_logic_vector(7 downto 0);
+ signal m1_avm_readdata : std_logic_vector(C_DATA_SIZE-1 downto 0);
+ signal m1_avm_readdatavalid : std_logic;
+ signal m1_avm_waitrequest : std_logic;
+
+ signal s_avm_write : std_logic;
+ signal s_avm_read : std_logic;
+ signal s_avm_address : std_logic_vector(C_ADDRESS_SIZE-1 downto 0);
+ signal s_avm_writedata : std_logic_vector(C_DATA_SIZE-1 downto 0);
+ signal s_avm_byteenable : std_logic_vector(C_DATA_SIZE/8-1 downto 0);
+ signal s_avm_burstcount : std_logic_vector(7 downto 0);
+ signal s_avm_readdata : std_logic_vector(C_DATA_SIZE-1 downto 0);
+ signal s_avm_readdatavalid : std_logic;
+ signal s_avm_waitrequest : std_logic;
+
+ constant C_CLK_PERIOD : time := 10 ns;
+
+begin
+
+ ---------------------------------------------------------
+ -- Controller clock and reset
+ ---------------------------------------------------------
+
+ p_clk : process
+ begin
+ clk <= '1';
+ wait for C_CLK_PERIOD/2;
+ clk <= '0';
+ wait for C_CLK_PERIOD/2;
+ if stop_test = '1' then
+ wait;
+ end if;
+ end process p_clk;
+
+ p_rst : process
+ begin
+ rst <= '1';
+ wait for 10*C_CLK_PERIOD;
+ wait until clk = '1';
+ rst <= '0';
+ wait;
+ end process p_rst;
+
+
+ p_tb_start : process
+ begin
+ tb_start <= '0';
+ wait until rst = '0';
+ wait until clk = '1';
+ tb_start <= '1';
+ wait until clk = '1';
+ tb_start <= '0';
+ wait;
+ end process p_tb_start;
+
+ p_stop_test : process
+ begin
+ wait until tb_start = '1';
+ wait until m0_avm_wait = '0' and m1_avm_wait = '0';
+ wait until clk = '1';
+ stop_test <= '1';
+ wait;
+ end process p_stop_test;
+
+
+
+ ---------------------------------------------------------
+ -- Instantiate Master 0
+ ---------------------------------------------------------
+
+ i_avm_master_general0 : entity work.avm_master_general
+ generic map (
+ G_ADDRESS_SIZE => C_ADDRESS_SIZE,
+ G_DATA_SIZE => C_DATA_SIZE
+ )
+ port map (
+ clk_i => clk,
+ rst_i => rst,
+ start_i => tb_start,
+ wait_o => m0_avm_wait,
+ m_avm_write_o => m0_avm_write,
+ m_avm_read_o => m0_avm_read,
+ m_avm_address_o => m0_avm_address,
+ m_avm_writedata_o => m0_avm_writedata,
+ m_avm_byteenable_o => m0_avm_byteenable,
+ m_avm_burstcount_o => m0_avm_burstcount,
+ m_avm_readdata_i => m0_avm_readdata,
+ m_avm_readdatavalid_i => m0_avm_readdatavalid,
+ m_avm_waitrequest_i => m0_avm_waitrequest
+ ); -- i_avm_master_general0
+
+
+ ---------------------------------------------------------
+ -- Instantiate Master 1
+ ---------------------------------------------------------
+
+ i_avm_master_general1 : entity work.avm_master_general
+ generic map (
+ G_ADDRESS_SIZE => C_ADDRESS_SIZE,
+ G_DATA_SIZE => C_DATA_SIZE
+ )
+ port map (
+ clk_i => clk,
+ rst_i => rst,
+ start_i => tb_start,
+ wait_o => m1_avm_wait,
+ m_avm_write_o => m1_avm_write,
+ m_avm_read_o => m1_avm_read,
+ m_avm_address_o => m1_avm_address,
+ m_avm_writedata_o => m1_avm_writedata,
+ m_avm_byteenable_o => m1_avm_byteenable,
+ m_avm_burstcount_o => m1_avm_burstcount,
+ m_avm_readdata_i => m1_avm_readdata,
+ m_avm_readdatavalid_i => m1_avm_readdatavalid,
+ m_avm_waitrequest_i => m1_avm_waitrequest
+ ); -- i_avm_master_general1
+
+
+ ---------------------------------------------------------
+ -- DUT
+ ---------------------------------------------------------
+
+ i_avm_arbit : entity work.avm_arbit
+ generic map (
+ G_ADDRESS_SIZE => C_ADDRESS_SIZE,
+ G_DATA_SIZE => C_DATA_SIZE
+ )
+ port map (
+ clk_i => clk,
+ rst_i => rst,
+ s0_avm_write_i => m0_avm_write ,
+ s0_avm_read_i => m0_avm_read ,
+ s0_avm_address_i => m0_avm_address ,
+ s0_avm_writedata_i => m0_avm_writedata ,
+ s0_avm_byteenable_i => m0_avm_byteenable ,
+ s0_avm_burstcount_i => m0_avm_burstcount ,
+ s0_avm_readdata_o => m0_avm_readdata ,
+ s0_avm_readdatavalid_o => m0_avm_readdatavalid ,
+ s0_avm_waitrequest_o => m0_avm_waitrequest ,
+ s1_avm_write_i => m1_avm_write ,
+ s1_avm_read_i => m1_avm_read ,
+ s1_avm_address_i => m1_avm_address ,
+ s1_avm_writedata_i => m1_avm_writedata ,
+ s1_avm_byteenable_i => m1_avm_byteenable ,
+ s1_avm_burstcount_i => m1_avm_burstcount ,
+ s1_avm_readdata_o => m1_avm_readdata ,
+ s1_avm_readdatavalid_o => m1_avm_readdatavalid ,
+ s1_avm_waitrequest_o => m1_avm_waitrequest ,
+ m_avm_write_o => s_avm_write ,
+ m_avm_read_o => s_avm_read ,
+ m_avm_address_o => s_avm_address ,
+ m_avm_writedata_o => s_avm_writedata ,
+ m_avm_byteenable_o => s_avm_byteenable ,
+ m_avm_burstcount_o => s_avm_burstcount ,
+ m_avm_readdata_i => s_avm_readdata ,
+ m_avm_readdatavalid_i => s_avm_readdatavalid ,
+ m_avm_waitrequest_i => s_avm_waitrequest
+ ); -- i_avm_arbit
+
+
+ ---------------------------------------------------------
+ -- Instantiate Slave
+ ---------------------------------------------------------
+
+ i_avm_memory : entity work.avm_memory
+ generic map (
+ G_ADDRESS_SIZE => C_ADDRESS_SIZE,
+ G_DATA_SIZE => C_DATA_SIZE
+ )
+ port map (
+ clk_i => clk,
+ rst_i => rst,
+ avm_write_i => s_avm_write,
+ avm_read_i => s_avm_read,
+ avm_address_i => s_avm_address,
+ avm_writedata_i => s_avm_writedata,
+ avm_byteenable_i => s_avm_byteenable,
+ avm_burstcount_i => s_avm_burstcount,
+ avm_readdata_o => s_avm_readdata,
+ avm_readdatavalid_o => s_avm_readdatavalid,
+ avm_waitrequest_o => s_avm_waitrequest
+ ); -- i_avm_memory
+
+end architecture simulation;
+
diff --git a/testsuite/gna/issue2185/testsuite.sh b/testsuite/gna/issue2185/testsuite.sh
new file mode 100755
index 000000000..5c3a46d9a
--- /dev/null
+++ b/testsuite/gna/issue2185/testsuite.sh
@@ -0,0 +1,21 @@
+#! /bin/sh
+
+. ../../testenv.sh
+
+export GHDL_STD_FLAGS=--std=08
+
+FILES="
+burst_ctrl.vhd
+avm_master.vhd
+avm_pause.vhd
+avm_master_general.vhd
+avm_arbit.vhd
+avm_memory.vhd
+tb_avm_arbit.vhd
+"
+analyze $FILES
+elab_simulate_failure tb_avm_arbit --assert-level=error --stop-time=50us
+
+clean
+
+echo "Test successful"