diff options
author | Tristan Gingold <tgingold@free.fr> | 2020-04-12 09:56:43 +0200 |
---|---|---|
committer | Tristan Gingold <tgingold@free.fr> | 2020-04-12 09:56:43 +0200 |
commit | a5a8b0cfe7d754a424f79ab82310db73e98d14fd (patch) | |
tree | 034862a2b9583d773b08d12053c3bc7eb70bfcbd /src | |
parent | bc269c6a47da7aaefb0bfb85cea3ad08447ab1b0 (diff) | |
download | ghdl-a5a8b0cfe7d754a424f79ab82310db73e98d14fd.tar.gz ghdl-a5a8b0cfe7d754a424f79ab82310db73e98d14fd.tar.bz2 ghdl-a5a8b0cfe7d754a424f79ab82310db73e98d14fd.zip |
netlists-inference: refactoring for #1211
Diffstat (limited to 'src')
-rw-r--r-- | src/synth/netlists-inference.adb | 86 |
1 files changed, 51 insertions, 35 deletions
diff --git a/src/synth/netlists-inference.adb b/src/synth/netlists-inference.adb index 0526988ca..e7e027078 100644 --- a/src/synth/netlists-inference.adb +++ b/src/synth/netlists-inference.adb @@ -467,18 +467,18 @@ package body Netlists.Inference is return Res; end Infere_FF_Else; - -- LAST_MUX is the mux whose input 0 is the loop and clock for selector. + -- CLOCK_MUX is the mux whose input 0 is the loop and clock for selector. function Infere_FF (Ctxt : Context_Acc; Val : Net; Prev_Val : Net; Off : Uns32; - Last_Mux : Instance; + Clock_Mux : Instance; Clk : Net; Clk_Enable : Net; Stmt : Synth.Source.Syn_Src) return Net is - O : constant Net := Get_Output (Last_Mux, 0); - Mux_Loc : constant Location_Type := Get_Location (Last_Mux); + O : constant Net := Get_Output (Clock_Mux, 0); + Mux_Loc : constant Location_Type := Get_Location (Clock_Mux); Data : Net; Res : Net; Sig : Instance; @@ -487,12 +487,15 @@ package body Netlists.Inference is Rst_Val : Net; Enable : Net; Els : Net; + Last_Mux : Instance; + -- Previous mux to be free. + Prev_Mux : Instance; begin -- Create and return the DFF. -- 1. Remove the mux that creates the loop (will be replaced by the -- dff). - Infere_FF_Mux (Ctxt, Prev_Val, Off, Last_Mux, Stmt, Els, Data); + Infere_FF_Mux (Ctxt, Prev_Val, Off, Clock_Mux, Stmt, Els, Data); -- If the signal declaration has an initial value, get it. Sig := Get_Net_Parent (Prev_Val); @@ -505,6 +508,8 @@ package body Netlists.Inference is Init := No_Net; end case; + -- As an enable signal, start with the enable extracted from the clock + -- to handle conditions like: `rising_edge(clk) and en` Enable := Clk_Enable; -- Look for asynchronous set/reset. They are muxes after the loop @@ -514,15 +519,17 @@ package body Netlists.Inference is declare Done : Boolean; Mux : Instance; - -- Previous mux to be free. - Prev_Mux : Instance; Sel : Net; Last_Out : Net; Mux_Not_Rst : Net; Mux_Rst : Net; Mux_Rst_Val : Net; + Prev_Input : Input; begin - Prev_Mux := No_Instance; + Prev_Mux := Clock_Mux; + + -- LAST_MUX is the last handled mux and LAST_OUT its output. + Last_Mux := Clock_Mux; Last_Out := O; -- Initially, the final output is not connected. So walk from the @@ -539,19 +546,33 @@ package body Netlists.Inference is -- The parent must be a mux (it's a chain of muxes). Mux := Get_Input_Parent (Get_First_Sink (Last_Out)); + if Get_Id (Mux) = Id_Nop then + -- Should have stopped. + exit; + end if; pragma Assert (Get_Id (Mux) = Id_Mux2); -- Extract the reset condition and the reset value. Sel := Get_Driver (Get_Mux2_Sel (Mux)); - if Get_Driver (Get_Mux2_I0 (Mux)) = Last_Out then + Prev_Input := Get_Mux2_I0 (Mux); + if Get_Driver (Prev_Input) = Last_Out then + -- Normal reset Mux_Rst_Val := Get_Driver (Get_Mux2_I1 (Mux)); Mux_Rst := Sel; else - pragma Assert (Get_Driver (Get_Mux2_I1 (Mux)) = Last_Out); + -- Inverted reset. + Prev_Input := Get_Mux2_I1 (Mux); + pragma Assert (Get_Driver (Prev_Input) = Last_Out); Mux_Rst_Val := Get_Driver (Get_Mux2_I0 (Mux)); Mux_Rst := Build_Monadic (Ctxt, Id_Not, Sel); end if; + -- Disconnect this mux. + Disconnect (Get_Mux2_I0 (Mux)); + Disconnect (Get_Mux2_I1 (Mux)); + Disconnect (Get_Mux2_Sel (Mux)); + + Last_Mux := Mux; Last_Out := Get_Output (Mux, 0); Done := not Is_Connected (Last_Out); @@ -565,11 +586,6 @@ package body Netlists.Inference is -- q1 <= d1; -- end if; - -- Remove the mux - Disconnect (Get_Mux2_I0 (Mux)); - Disconnect (Get_Mux2_I1 (Mux)); - Disconnect (Get_Mux2_Sel (Mux)); - -- Add the negation of the condition to the enable signal. -- Negate the condition for the current reset. Mux_Not_Rst := Build_Monadic (Ctxt, Id_Not, Mux_Rst); @@ -591,38 +607,36 @@ package body Netlists.Inference is -- FIXME: check for no logical loop. if Rst = No_Net then - -- Remove the last mux. Dedicated inputs on the FF - -- are used. - Disconnect (Get_Mux2_I0 (Mux)); - Disconnect (Get_Mux2_I1 (Mux)); - Disconnect (Get_Mux2_Sel (Mux)); + -- First async reset condition. - -- The output of the mux is now the reset value. - Redirect_Inputs (Last_Out, Mux_Rst_Val); + -- Keep reset value and condition + Rst := Mux_Rst; + Rst_Val := Mux_Rst_Val; + -- Remove the last mux. Will free this mux. if Prev_Mux /= No_Instance then Remove_Instance (Prev_Mux); end if; Prev_Mux := Mux; - - Rst := Mux_Rst; - Rst_Val := Mux_Rst_Val; - Last_Out := Mux_Rst_Val; else + -- New async reset condition. Rst := Build_Dyadic (Ctxt, Id_Or, Mux_Rst, Rst); - Rst_Val := Last_Out; - if Prev_Mux /= No_Instance then - Remove_Instance (Prev_Mux); - end if; - Prev_Mux := No_Instance; + -- Use prev_mux to select the reset value. + Connect (Get_Mux2_Sel (Prev_Mux), Mux_Rst); + Connect (Get_Mux2_I0 (Prev_Mux), Rst_Val); + Connect (Get_Mux2_I1 (Prev_Mux), Mux_Rst_Val); + + -- The reset value is the output of prev_mux. + Rst_Val := Get_Output (Prev_Mux, 0); + + -- Allow to free this mux. + Prev_Mux := Mux; end if; end if; end loop; - if Prev_Mux /= No_Instance then - Free_Instance (Mux); - end if; + pragma Assert (Prev_Mux = No_Instance or else Prev_Mux = Last_Mux); end; if Off = 0 @@ -651,7 +665,9 @@ package body Netlists.Inference is -- The output may already be used (if the target is a variable that -- is read). So redirect the net. Redirect_Inputs (Get_Output (Last_Mux, 0), Res); - Free_Instance (Last_Mux); + if Prev_Mux /= No_Instance then + Free_Instance (Prev_Mux); + end if; return Res; end Infere_FF; |