diff --git a/libraries/base/mm/src/vhdl/mm_bus_pipe.vhd b/libraries/base/mm/src/vhdl/mm_bus_pipe.vhd index 8648f4b5f68b32dca86223006dcfea4fd732f847..d788fe39db036a52a4b2a2535b169021f2557f79 100644 --- a/libraries/base/mm/src/vhdl/mm_bus_pipe.vhd +++ b/libraries/base/mm/src/vhdl/mm_bus_pipe.vhd @@ -37,9 +37,6 @@ -- pulse would yield a different pipelining of the address for write and -- for read, which is akward. Therefore assume that both mosi write and -- mosi read have the same pipelining. --- When g_pipeline_miso_wait = TRUE then it is not necessary to use --- g_pipeline_mosi = TRUE, because the MM latency adapter that recovers --- the timing of the waitrequest also pipelines the mosi. -- -- * g_pipeline_miso_rdval -- Pipelining the miso read data increases the read latency. @@ -57,9 +54,28 @@ -- Usage: -- See mm_bus.vhd -- +-- Remark: +-- * It is not allowed to simultaneously use g_pipeline_miso_wait = TRUE +-- and g_pipeline_mosi = TRUE, because this leads to a combinatorial loop +-- of the miso.waitrequest that is used at the output of the mm_pipeline +-- and at the input of the mm_latency adapter: +-- - at the mm_pipeline output the waitrequest gates the mosi.wr and rd +-- - at the mm_latency_adapter input in common_rl_decrease in the wr or +-- rd strobe is used to set the waitrequest. +-- This combinatorial loop seems unavoidable when the interface between +-- mm_pipeline and mm_latency_adpater is at RL = 0. A solution could be +-- to increase the RL at the output of the mm_pipeline to RL = 1 by +-- registering the waitrequest from the mm_latency_adapter. The total +-- RL for the input of the MM latency adapter then becomes RL = 2, so +-- then the mm_latency_adapter needs t oadapt from RL = 2 to 0. +-- Currently the mm_latency_adapter only supports RL 1 to 0. Is possible +-- to extent this to RL = N to 0, similar as in dp_latency_adapter. +-- However fortunately it is not necessary to support g_pipeline_mosi = +-- TRUE when g_pipeline_miso_wait = TRUE, because g_pipeline_miso_wait = +-- TRUE by itself already also pipeplines the mosi. +-- ------------------------------------------------------------------------------- - LIBRARY IEEE, common_lib; USE IEEE.STD_LOGIC_1164.ALL; USE common_lib.common_pkg.ALL; @@ -101,6 +117,10 @@ ARCHITECTURE str OF mm_bus_pipe IS BEGIN + ASSERT NOT(g_pipeline_miso_wait = TRUE AND g_pipeline_mosi = TRUE) + REPORT "Do not use g_pipeline_mosi = TRUE if g_pipeline_miso_wait = TRUE" + SEVERITY FAILURE; + -- Master side m_mosi <= master_mosi; @@ -145,10 +165,8 @@ BEGIN 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 => pipe_mosi_arr(I), out_miso => pipe_miso_arr(I) ); diff --git a/libraries/base/mm/src/vhdl/mm_pipeline.vhd b/libraries/base/mm/src/vhdl/mm_pipeline.vhd index 09f3cda1a1c471c9d535d561bf7338b9c2a25111..f4d435b08f11124c164a4f19e50dc1ccec1e229e 100644 --- a/libraries/base/mm/src/vhdl/mm_pipeline.vhd +++ b/libraries/base/mm/src/vhdl/mm_pipeline.vhd @@ -25,6 +25,57 @@ -- Description: -- The mm_pipeline mosi registers the in_mosi if g_pipeline = TRUE, else it -- defaults to wires. +-- +-- Background information +-- The MM waitrequest resembles the behaviour of the streaming backpressure +-- ready for ready latency RL = 0. For RL = 0 the ready acts as an +-- acknowledge to pending data. For RL > 0 the ready acts as a request for +-- new data. The miso.waitrequest is defined for RL = 0 but for analysis +-- the timing diagrams below show an example of both RL = 0 and RL = 1. +-- +-- * RL=1 +-- _ _ _ _ _ _ _ _ _ _ _ _ +-- clk _| |_| |_| |_| |_| |_| |_| |_| |_| |_| |_| |_| |_ +-- +-- in_dat |a |b |c |d +-- _________ ___ ___ +-- in_val |_______| |_______| |_______________ +-- _____ ___ _______ ___________ +-- ready |_______| |___|... |_______|........... +-- _________ ___ _______ _______ +-- reg_ready |_______| |___|... |_______|....... +-- +-- reg_dat |a |b |c |d +-- _____________________________ ___________ +-- reg_val |___| |___ +-- _________ ___ ___ ___ +-- out_val |a |_______|b |___|c |___________|d |___ +-- +-- +-- * RL=0 +-- _ _ _ _ _ _ _ _ _ _ _ _ _ +-- clk _| |_| |_| |_| |_| |_| |_| |_| |_| |_| |_| |_| |_| |_ +-- +-- in_dat |a |b |c |d |e +-- _________ _______________ ___ +-- in_val |_______| |_______| |_______ +-- _____________ ___ _______ ___________ +-- ack |_______| |___| |___| +-- +-- reg_dat |a |b |c |d |e +-- _____________ ___________ ___ +-- reg_val |___________| |_______| |___ +-- _____________ _______ ___ +-- out_val |a |b |_______________|c |d |_______|e |___ +-- +-- In these timing diagrams the out_ready is wired to the in_ready, so +-- therefore they are identical and called ready. +-- The ready for RL = 0 or the reg_ready for RL = 1 is used to gate the +-- out_val. The ready/reg_ready is used and not the in_val, because by +-- using the ready/reg_ready the pipeline register is emptied as soon +-- as the ready is active, rather than to wait for a next in_val to push +-- it out. +-- -- Remark: -- * The mm_pipeline could be optimized regarding the miso.waitrequest flow -- control if it would be implemented similar as dp_pipeline.vhd. This @@ -47,10 +98,8 @@ ENTITY mm_pipeline IS PORT ( mm_rst : IN STD_LOGIC; mm_clk : IN STD_LOGIC; - -- MM input RL = 1 in_mosi : IN t_mem_mosi; in_miso : OUT t_mem_miso; - -- MM output RL = 0 out_mosi : OUT t_mem_mosi; out_miso : IN t_mem_miso ); @@ -59,24 +108,42 @@ END mm_pipeline; ARCHITECTURE rtl OF mm_pipeline IS - SIGNAL in_mosi_reg : t_mem_mosi := c_mem_mosi_rst; + SIGNAL mosi_reg : t_mem_mosi := c_mem_mosi_rst; + SIGNAL nxt_mosi_reg : t_mem_mosi; + SIGNAL ready : STD_LOGIC; BEGIN -- Pass on miso in_miso <= out_miso; - -- Optionally pipeline the mosi - --in_mosi_reg <= in_mosi WHEN rising_edge(mm_clk); -- without mm_rst - p_reg : PROCESS(mm_rst, mm_clk) -- with mm_rst - BEGIN - IF mm_rst = '1' THEN - in_mosi_reg <= c_mem_mosi_rst; - ELSIF rising_edge(mm_clk) THEN - in_mosi_reg <= in_mosi; - END IF; - END PROCESS; - - out_mosi <= in_mosi_reg WHEN g_pipeline = TRUE ELSE in_mosi; + -- Pipeline the mosi when g_pipeline = TRUE, else default to wires + gen_wires : IF g_pipeline = FALSE GENERATE + out_mosi <= in_mosi; + END GENERATE; + + gen_pipeline : IF g_pipeline = TRUE GENERATE + p_reg : PROCESS(mm_rst, mm_clk) + BEGIN + IF mm_rst = '1' THEN + mosi_reg <= c_mem_mosi_rst; + ELSIF rising_edge(mm_clk) THEN + mosi_reg <= nxt_mosi_reg; + END IF; + END PROCESS; + + ready <= NOT out_miso.waitrequest; + + nxt_mosi_reg <= in_mosi WHEN ready = '1' ELSE mosi_reg; + + p_out_mosi : PROCESS(mosi_reg, ready) + BEGIN + out_mosi <= mosi_reg; + IF ready /= '1' THEN + out_mosi.wr <= '0'; -- out_mosi.wr = mosi_reg.wr AND ready + out_mosi.rd <= '0'; -- out_mosi.rd = mosi_reg.rd AND ready + END IF; + END PROCESS; + END GENERATE; END rtl; diff --git a/libraries/base/mm/tb/vhdl/tb_tb_mm_bus.vhd b/libraries/base/mm/tb/vhdl/tb_tb_mm_bus.vhd index 9614cff4f5f2cf9a0a0caeaba7c769c13d1ed39f..e399076bb1f973284b4ed38e5a7722a0dbca39e8 100644 --- a/libraries/base/mm/tb/vhdl/tb_tb_mm_bus.vhd +++ b/libraries/base/mm/tb/vhdl/tb_tb_mm_bus.vhd @@ -48,20 +48,20 @@ BEGIN -- g_pipeline_miso_rdval : BOOLEAN := TRUE; -- g_pipeline_miso_wait : BOOLEAN := FALSE - --u_no_pipe : ENTITY work.tb_mm_bus GENERIC MAP (16, 0, 3, 1, FALSE, FALSE, FALSE, FALSE); - --u_no_pipe_base_offset : ENTITY work.tb_mm_bus GENERIC MAP (16, 3*2**4, 4, 1, FALSE, FALSE, FALSE, FALSE); - --u_pipe_mosi : ENTITY work.tb_mm_bus GENERIC MAP ( 3, 0, 4, 1, FALSE, TRUE, FALSE, FALSE); - --u_pipe_mosi_miso_rdval : ENTITY work.tb_mm_bus GENERIC MAP ( 3, 0, 4, 1, FALSE, TRUE, TRUE, FALSE); - --u_waitrequest_no_pipe : ENTITY work.tb_mm_bus GENERIC MAP ( 3, 0, 4, 1, TRUE, FALSE, FALSE, FALSE); - --u_waitrequest_pipe_miso_rdval : ENTITY work.tb_mm_bus GENERIC MAP ( 3, 0, 4, 1, TRUE, FALSE, TRUE, FALSE); - --u_waitrequest_pipe_miso_rdval2 : ENTITY work.tb_mm_bus GENERIC MAP ( 3, 0, 4, 2, TRUE, FALSE, TRUE, FALSE); - --u_waitrequest_pipe_miso_wait : ENTITY work.tb_mm_bus GENERIC MAP ( 2, 0, 4, 1, TRUE, FALSE, FALSE, TRUE); + u_no_pipe : ENTITY work.tb_mm_bus GENERIC MAP (16, 0, 3, 1, FALSE, FALSE, FALSE, FALSE); + u_no_pipe_base_offset : ENTITY work.tb_mm_bus GENERIC MAP (16, 3*2**4, 4, 1, FALSE, FALSE, FALSE, FALSE); + u_pipe_mosi : ENTITY work.tb_mm_bus GENERIC MAP ( 3, 0, 4, 1, FALSE, TRUE, FALSE, FALSE); + u_pipe_mosi_miso_rdval : ENTITY work.tb_mm_bus GENERIC MAP ( 3, 0, 4, 1, FALSE, TRUE, TRUE, FALSE); + u_waitrequest_no_pipe : ENTITY work.tb_mm_bus GENERIC MAP ( 3, 0, 4, 1, TRUE, FALSE, FALSE, FALSE); + u_waitrequest_pipe_miso_rdval : ENTITY work.tb_mm_bus GENERIC MAP ( 3, 0, 4, 1, TRUE, FALSE, TRUE, FALSE); + u_waitrequest_pipe_miso_rdval2 : ENTITY work.tb_mm_bus GENERIC MAP ( 3, 0, 4, 2, TRUE, FALSE, TRUE, FALSE); + u_waitrequest_pipe_miso_wait : ENTITY work.tb_mm_bus GENERIC MAP ( 2, 0, 4, 1, TRUE, FALSE, FALSE, TRUE); + u_waitrequest_pipe_mosi_one : ENTITY work.tb_mm_bus GENERIC MAP ( 1, 0, 4, 1, TRUE, TRUE, FALSE, FALSE); + u_waitrequest_pipe_mosi : ENTITY work.tb_mm_bus GENERIC MAP ( 2, 0, 4, 1, TRUE, TRUE, FALSE, FALSE); + u_waitrequest_pipe_mosi_miso_rdval : ENTITY work.tb_mm_bus GENERIC MAP ( 2, 0, 4, 1, TRUE, TRUE, TRUE, FALSE); - -- To do: - u_waitrequest_pipe_mosi : ENTITY work.tb_mm_bus GENERIC MAP ( 1, 0, 4, 1, TRUE, TRUE, FALSE, FALSE); - --u_waitrequest_pipe_mosi : ENTITY work.tb_mm_bus GENERIC MAP ( 2, 0, 4, 1, TRUE, TRUE, FALSE, FALSE); - --u_waitrequest_pipe_mosi_miso_rdval : ENTITY work.tb_mm_bus GENERIC MAP ( 2, 0, 4, 1, TRUE, TRUE, TRUE, FALSE); + -- Do not support simultaneous g_pipeline_mosi = TRUE and g_pipeline_miso_wait = TRUE, see mm_bus_pipe.vhd. --u_waitrequest_pipe_mosi_miso_wait : ENTITY work.tb_mm_bus GENERIC MAP ( 2, 0, 4, 1, TRUE, TRUE, FALSE, TRUE); - --u_waitrequest_pipe_mosi_miso : ENTITY work.tb_mm_bus GENERIC MAP ( 2, 0, 4, 1, TRUE, TRUE, TRUE, TRUE); + --u_waitrequest_pipe_all : ENTITY work.tb_mm_bus GENERIC MAP ( 2, 0, 4, 1, TRUE, TRUE, TRUE, TRUE); END tb;