diff --git a/libraries/base/mm/tb/vhdl/tb_mm_bus.vhd b/libraries/base/mm/tb/vhdl/tb_mm_bus.vhd index de97abd7f027f5b624a3ac5cdbd389f939311511..0f2004618996296869492ed7badca472b843b59a 100644 --- a/libraries/base/mm/tb/vhdl/tb_mm_bus.vhd +++ b/libraries/base/mm/tb/vhdl/tb_mm_bus.vhd @@ -27,7 +27,7 @@ -- . g_nof_slaves >= 1 -- . g_waitrequest for g_pipeline_miso_wait = FALSE -- . g_pipeline_mosi --- . g_pipeline_miso_rd +-- . g_pipeline_miso_rdval -- . g_pipeline_miso_wait = FALSE -- . g_rd_latency >= 1 (using 0 is supported by mm_bus, but not by -- the common_ram_r_w in u_slaves) @@ -54,14 +54,14 @@ USE common_lib.tb_common_mem_pkg.ALL; ENTITY tb_mm_bus IS GENERIC ( - g_nof_slaves : POSITIVE := 1; -- Number of slave memory interfaces on the MM bus array. - g_base_offset : NATURAL := 0; -- Address of first slave on the MM bus - g_width_w : POSITIVE := 4; -- Address width of each slave memory in the MM bus array. - g_rd_latency : NATURAL := 1; -- Read latency of the slaves slave - g_waitrequest : BOOLEAN := TRUE; -- When TRUE model waitrequest by MM slaves, else fixed '0' - g_pipeline_mosi : BOOLEAN := FALSE; - g_pipeline_miso_rd : BOOLEAN := TRUE; - g_pipeline_miso_wait : BOOLEAN := FALSE + g_nof_slaves : POSITIVE := 2; -- Number of slave memory interfaces on the MM bus array. + g_base_offset : NATURAL := 0; -- Address of first slave on the MM bus + g_width_w : POSITIVE := 4; -- Address width of each slave memory in the MM bus array. + g_rd_latency : NATURAL := 1; -- Read latency of the slaves + g_waitrequest : BOOLEAN := FALSE; -- When TRUE model waitrequest by MM slaves, else fixed '0' + g_pipeline_mosi : BOOLEAN := FALSE; + g_pipeline_miso_rdval : BOOLEAN := FALSE; + g_pipeline_miso_wait : BOOLEAN := FALSE ); END tb_mm_bus; @@ -80,10 +80,13 @@ ARCHITECTURE tb OF tb_mm_bus IS CONSTANT c_width_arr : t_nat_natural_arr := array_init( g_width_w, g_nof_slaves); -- Address width per slave CONSTANT c_rd_latency_arr : t_nat_natural_arr := array_init( g_rd_latency, g_nof_slaves); -- Read latency per slave - CONSTANT c_pipeline_mosi : NATURAL := sel_a_b(g_pipeline_mosi, 1, 0); - CONSTANT c_pipeline_miso_rd : NATURAL := sel_a_b(g_pipeline_miso_rd, 1, 0); - CONSTANT c_pipeline_miso_wait : NATURAL := sel_a_b(g_pipeline_miso_wait, 1, 0); - CONSTANT c_read_latency : NATURAL := c_pipeline_mosi + g_rd_latency + c_pipeline_miso_rd; + CONSTANT c_bus_pipelining : BOOLEAN := g_pipeline_mosi OR g_pipeline_miso_rdval OR g_pipeline_miso_wait; + CONSTANT c_pipeline_mosi : NATURAL := sel_a_b(g_pipeline_mosi, 1, 0); + CONSTANT c_pipeline_miso_rdval : NATURAL := sel_a_b(g_pipeline_miso_rdval, 1, 0); + CONSTANT c_pipeline_miso_wait : NATURAL := sel_a_b(g_pipeline_miso_wait, 1, 0); + CONSTANT c_read_latency : NATURAL := c_pipeline_mosi + g_rd_latency + c_pipeline_miso_rdval; + + CONSTANT c_adapt_waitrequest : BOOLEAN := g_waitrequest AND g_pipeline_miso_wait; CONSTANT c_data_w : NATURAL := 32; CONSTANT c_test_ram : t_c_mem := (latency => g_rd_latency, @@ -95,12 +98,19 @@ ARCHITECTURE tb OF tb_mm_bus IS SIGNAL mm_clk : STD_LOGIC := '1'; SIGNAL tb_end : STD_LOGIC; - SIGNAL master_mosi : t_mem_mosi := c_mem_mosi_rst; - SIGNAL master_miso : t_mem_miso := c_mem_miso_rst; - SIGNAL slave_mosi_arr : t_mem_mosi_arr(0 TO g_nof_slaves-1) := (OTHERS=>c_mem_mosi_rst); - SIGNAL slave_miso_arr : t_mem_miso_arr(0 TO g_nof_slaves-1) := (OTHERS=>c_mem_miso_rst); - SIGNAL ram_mosi_arr : t_mem_mosi_arr(0 TO g_nof_slaves-1) := (OTHERS=>c_mem_mosi_rst); - SIGNAL ram_miso_arr : t_mem_miso_arr(0 TO g_nof_slaves-1) := (OTHERS=>c_mem_miso_rst); + -- MM bus + SIGNAL master_mosi : t_mem_mosi := c_mem_mosi_rst; + SIGNAL master_miso : t_mem_miso := c_mem_miso_rst; + SIGNAL bus_mosi_arr : t_mem_mosi_arr(0 TO g_nof_slaves-1) := (OTHERS=>c_mem_mosi_rst); + SIGNAL bus_miso_arr : t_mem_miso_arr(0 TO g_nof_slaves-1) := (OTHERS=>c_mem_miso_rst); + -- MM slaves with waitrequest latency adapters for ports that have pipelined flow control + SIGNAL busw_mosi_arr : t_mem_mosi_arr(0 TO g_nof_slaves-1) := (OTHERS=>c_mem_mosi_rst); + SIGNAL busw_miso_arr : t_mem_miso_arr(0 TO g_nof_slaves-1) := (OTHERS=>c_mem_miso_rst); + -- MM slaves with waitrequest for ports that are enabled and NC for ports that are not connected + SIGNAL slave_mosi_arr : t_mem_mosi_arr(0 TO g_nof_slaves-1) := (OTHERS=>c_mem_mosi_rst); + SIGNAL slave_miso_arr : t_mem_miso_arr(0 TO g_nof_slaves-1) := (OTHERS=>c_mem_miso_rst); + SIGNAL ram_mosi_arr : t_mem_mosi_arr(0 TO g_nof_slaves-1) := (OTHERS=>c_mem_mosi_rst); + SIGNAL ram_miso_arr : t_mem_miso_arr(0 TO g_nof_slaves-1) := (OTHERS=>c_mem_miso_rst); -- Debug signals for monitoring in simulation Wave window SIGNAL dbg_c_base_arr : t_nat_natural_arr(0 TO g_nof_slaves-1) := c_base_arr; @@ -109,13 +119,16 @@ ARCHITECTURE tb OF tb_mm_bus IS BEGIN + ASSERT NOT(g_nof_slaves=1 AND c_bus_pipelining=TRUE) REPORT "No support for MM bus pipelining with g_nof_slaves=1, because then the mm_bus reduces to wires." SEVERITY FAILURE; + mm_clk <= NOT mm_clk OR tb_end AFTER mm_clk_period/2; mm_rst <= '1', '0' AFTER mm_clk_period*5; + ----------------------------------------------------------------------------- + -- Write stimuli and readback to verify + ----------------------------------------------------------------------------- p_stimuli : PROCESS VARIABLE v_wrdata : INTEGER; -- write data - VARIABLE v_rddata : INTEGER; -- read data - VARIABLE v_expdata : INTEGER; -- expected data BEGIN tb_end <= '0'; master_mosi <= c_mem_mosi_rst; @@ -126,7 +139,6 @@ BEGIN -- Repeat twice to have wr all, rd all, wr all, rd all v_wrdata := 0; - v_expdata := 0; FOR vR IN 0 TO c_repeat-1 LOOP -- Write the whole memory range FOR vI IN 0 TO g_nof_slaves-1 LOOP @@ -134,21 +146,16 @@ BEGIN proc_mem_mm_bus_wr(g_base_offset + vI*c_slave_span + vJ, v_wrdata, mm_clk, master_miso, master_mosi); v_wrdata := v_wrdata + 1; END LOOP; - --proc_common_wait_some_cycles(mm_clk, 10); + proc_common_wait_some_cycles(mm_clk, 10); END LOOP; -- Read back the whole range and check if data is as expected FOR vI IN 0 TO g_nof_slaves-1 LOOP FOR vJ IN 0 TO c_slave_span-1 LOOP proc_mem_mm_bus_rd(g_base_offset + vI*c_slave_span + vJ, mm_clk, master_miso, master_mosi); - proc_common_wait_some_cycles(mm_clk, c_read_latency); - v_rddata := TO_UINT(master_miso.rddata(c_data_w-1 DOWNTO 0)); - IF v_rddata /= v_expdata THEN - REPORT "Error! Readvalue is not as expected" SEVERITY ERROR; - END IF; - v_expdata := v_expdata + 1; - --proc_common_wait_some_cycles(mm_clk, 10); + --proc_common_wait_some_cycles(mm_clk, c_read_latency); -- not needed, see p_verify END LOOP; + proc_common_wait_some_cycles(mm_clk, 10); END LOOP; END LOOP; @@ -157,7 +164,91 @@ BEGIN WAIT; END PROCESS; - u_slaves : FOR I IN 0 TO g_nof_slaves-1 GENERATE + -- Use miso.rdval to know when to verify the rddata, rather than to wait for a fixed c_read_latency after + -- the mosi.rd. The advantage is that then rd accesses can be done on every mm_clk, without having to + -- wait for the c_read_latency. In case of g_pipeline_mosi = TRUE or g_pipeline_miso_wait = TRUE it is + -- even essential to use rdval, because then the latency between rd and rdval can become larger than + -- c_read_latency and even variable (in case of g_waitrequest = TRUE). The disadvantage is that the MM + -- slave must support rdval, but that is ensured by mm_slave_enable. + p_verify : PROCESS + VARIABLE v_expdata : INTEGER := 0; -- expected data + VARIABLE v_rddata : INTEGER; -- read data + BEGIN + WAIT UNTIL rising_edge(mm_clk); + IF master_miso.rdval = '1' THEN + v_rddata := TO_UINT(master_miso.rddata(c_data_w-1 DOWNTO 0)); + IF v_rddata /= v_expdata THEN + REPORT "Error! Readvalue is not as expected" SEVERITY ERROR; + END IF; + v_expdata := v_expdata + 1; + END IF; + END PROCESS; + + + ----------------------------------------------------------------------------- + -- The MM bus + ----------------------------------------------------------------------------- + u_mm_bus: ENTITY work.mm_bus + GENERIC MAP ( + g_nof_slaves => g_nof_slaves, + g_base_arr => c_base_arr, + g_width_arr => c_width_arr, + g_rd_latency_arr => c_rd_latency_arr, + g_pipeline_mosi => g_pipeline_mosi, + g_pipeline_miso_rdval => g_pipeline_miso_rdval, + g_pipeline_miso_wait => g_pipeline_miso_wait + ) + PORT MAP ( + mm_clk => mm_clk, + master_mosi => master_mosi, + master_miso => master_miso, + slave_mosi_arr => bus_mosi_arr, + slave_miso_arr => bus_miso_arr + ); + + ----------------------------------------------------------------------------- + -- The MM bus interface with the MM slaves + ----------------------------------------------------------------------------- + gen_slave_ports : FOR I IN 0 TO g_nof_slaves-1 GENERATE + -- Adapt the miso.waitrequest for slaves that use mosi flow control if the miso.waitrequest is pipelined in the mm_bus + u_slave_latency_adapter : ENTITY work.mm_latency_adapter + GENERIC MAP ( + g_adapt => c_adapt_waitrequest + ) + PORT MAP ( + mm_rst => mm_rst, + mm_clk => mm_clk, + -- MM input RL = 1 + in_mosi => bus_mosi_arr(I), + in_miso => bus_miso_arr(I), + -- MM output RL = 0 + out_mosi => busw_mosi_arr(I), + out_miso => busw_miso_arr(I) + ); + + -- Rewire not connected slaves and slave that do not need mosi flow control via miso.waitrequest + u_slave_enable : ENTITY work.mm_slave_enable + GENERIC MAP ( + g_enable => TRUE, + g_waitrequest => g_waitrequest, + g_rd_latency => c_rd_latency_arr(I) + ) + PORT MAP ( + mm_rst => mm_rst, + mm_clk => mm_clk, + -- MM input RL = 1 + in_mosi => busw_mosi_arr(I), + in_miso => busw_miso_arr(I), + -- MM output RL = 0 + out_mosi => slave_mosi_arr(I), + out_miso => slave_miso_arr(I) + ); + END GENERATE; + + ----------------------------------------------------------------------------- + -- Model the MM slaves + ----------------------------------------------------------------------------- + gen_slaves : FOR I IN 0 TO g_nof_slaves-1 GENERATE u_waitrequest_model : ENTITY work.mm_waitrequest_model GENERIC MAP ( g_waitrequest => g_waitrequest, @@ -190,22 +281,4 @@ BEGIN ); END GENERATE; - d_dut: ENTITY work.mm_bus - GENERIC MAP ( - g_nof_slaves => g_nof_slaves, - g_base_arr => c_base_arr, - g_width_arr => c_width_arr, - g_rd_latency_arr => c_rd_latency_arr, - g_pipeline_mosi => g_pipeline_mosi, - g_pipeline_miso_rd => g_pipeline_miso_rd, - g_pipeline_miso_wait => g_pipeline_miso_wait - ) - PORT MAP ( - mm_clk => mm_clk, - master_mosi => master_mosi, - master_miso => master_miso, - slave_mosi_arr => slave_mosi_arr, - slave_miso_arr => slave_miso_arr - ); - END tb;