diff options
author | Tristan Gingold <tgingold@free.fr> | 2020-02-10 07:00:31 +0100 |
---|---|---|
committer | Tristan Gingold <tgingold@free.fr> | 2020-02-10 07:00:31 +0100 |
commit | 8f4dda3ded16f2604c070736cbde8849774755a8 (patch) | |
tree | f4f59e0760faf79d9d9f7a625991df655599c8bc | |
parent | 0f7aa39d2c423b27519b541ae04648d5b3277ffd (diff) | |
download | ghdl-8f4dda3ded16f2604c070736cbde8849774755a8.tar.gz ghdl-8f4dda3ded16f2604c070736cbde8849774755a8.tar.bz2 ghdl-8f4dda3ded16f2604c070736cbde8849774755a8.zip |
synth: rework (again) memory inference.
Preliminary work to support multi-clock memories.
Strengthen and fix fallout of Check_Connected.
Rename synth.inference to netlists.inference.
-rw-r--r-- | src/synth/netlists-cleanup.adb | 2 | ||||
-rw-r--r-- | src/synth/netlists-expands.adb | 4 | ||||
-rw-r--r-- | src/synth/netlists-inference.adb (renamed from src/synth/synth-inference.adb) | 28 | ||||
-rw-r--r-- | src/synth/netlists-inference.ads (renamed from src/synth/synth-inference.ads) | 23 | ||||
-rw-r--r-- | src/synth/netlists-memories.adb | 275 | ||||
-rw-r--r-- | src/synth/netlists-memories.ads | 7 | ||||
-rw-r--r-- | src/synth/netlists.adb | 21 | ||||
-rw-r--r-- | src/synth/synth-environment.adb | 32 |
8 files changed, 312 insertions, 80 deletions
diff --git a/src/synth/netlists-cleanup.adb b/src/synth/netlists-cleanup.adb index 4b4360e7f..bb963633a 100644 --- a/src/synth/netlists-cleanup.adb +++ b/src/synth/netlists-cleanup.adb @@ -133,6 +133,8 @@ package body Netlists.Cleanup is -- Only when the output is driven. Disconnect (Inp); Redirect_Inputs (Get_Output (Inst, 0), O); + else + Disconnect (Get_First_Sink (Get_Output (Inst, 0))); end if; Remove_Instance (Inst); end if; diff --git a/src/synth/netlists-expands.adb b/src/synth/netlists-expands.adb index 8794ad722..bab2b9b47 100644 --- a/src/synth/netlists-expands.adb +++ b/src/synth/netlists-expands.adb @@ -209,6 +209,7 @@ package body Netlists.Expands is end; -- 3. build mux tree + Disconnect (Get_Input (Inst, 1)); Extract_Address (Ctxt, Addr_Net, Ndims, Addr); Truncate_Address (Ctxt, Addr, Nbr_Els); Def := No_Net; @@ -216,7 +217,6 @@ package body Netlists.Expands is -- 4. remove old dyn_extract. Disconnect (Get_Input (Inst, 0)); - Disconnect (Get_Input (Inst, 1)); Redirect_Inputs (Get_Output (Inst, 0), Res); Remove_Instance (Inst); @@ -396,6 +396,7 @@ package body Netlists.Expands is -- Generate decoder. Net_Arr := new Net_Array(0 .. Int32 (Nbr_Els - 1)); + Disconnect (Get_Input (Inst, 2)); Extract_Address (Ctxt, Addr_Net, Ndims, Addr); Truncate_Address (Ctxt, Addr, Nbr_Els); Generate_Decoder (Ctxt, Addr, Net_Arr.all); @@ -419,7 +420,6 @@ package body Netlists.Expands is Redirect_Inputs (O, Res); Disconnect (Get_Input (Inst, 0)); Disconnect (Get_Input (Inst, 1)); - Disconnect (Get_Input (Inst, 2)); if En /= No_Net then Disconnect (Get_Input (Inst, 3)); end if; diff --git a/src/synth/synth-inference.adb b/src/synth/netlists-inference.adb index 9bf2e2dbe..3bd1a8f77 100644 --- a/src/synth/synth-inference.adb +++ b/src/synth/netlists-inference.adb @@ -25,12 +25,13 @@ with Netlists.Locations; use Netlists.Locations; with Netlists.Errors; use Netlists.Errors; with Netlists.Internings; with Netlists.Folds; use Netlists.Folds; +with Netlists.Memories; with Synth.Flags; with Synth.Source; use Synth.Source; with Synth.Errors; use Synth.Errors; -package body Synth.Inference is +package body Netlists.Inference is -- DFF inference. -- As an initial implementation, the following 'styles' must be -- supported: @@ -324,7 +325,7 @@ package body Synth.Inference is Last_Mux : Instance; Clk : Net; Clk_Enable : Net; - Stmt : Source.Syn_Src) return Net + Stmt : Synth.Source.Syn_Src) return Net is O : constant Net := Get_Output (Last_Mux, 0); Data : Net; @@ -602,7 +603,7 @@ package body Synth.Inference is function Infere_Latch (Ctxt : Context_Acc; Val : Net; Prev_Val : Net; - Stmt : Source.Syn_Src) return Net + Stmt : Synth.Source.Syn_Src) return Net is Name : Sname; begin @@ -641,13 +642,13 @@ package body Synth.Inference is end Infere_Latch; -- Note: PREV_VAL is the wire gate, so with full width and no offset. - procedure Infere (Ctxt : Context_Acc; - Wid : Wire_Id; - Val : Net; - Off : Uns32; - Prev_Val : Net; - Stmt : Source.Syn_Src) + function Infere (Ctxt : Context_Acc; + Val : Net; + Off : Uns32; + Prev_Val : Net; + Stmt : Synth.Source.Syn_Src) return Net is + use Netlists.Memories; pragma Assert (Val /= No_Net); pragma Assert (Prev_Val /= No_Net); Last_Mux : Instance; @@ -657,7 +658,7 @@ package body Synth.Inference is Enable : Net; Res : Net; begin - if not Flags.Flag_Debug_Noinference then + if not Synth.Flags.Flag_Debug_Noinference then if Get_First_Sink (Prev_Val) = No_Input then -- PREV_VAL is never read, so there cannot be any loop. -- This is an important optimization for control signals. @@ -671,6 +672,9 @@ package body Synth.Inference is if Len <= 0 then -- No logical loop or self assignment. Res := Val; + elsif Can_Infere_RAM (Val, Prev_Val) then + -- Try to infere RAM before FF, because of many ports/clocks. + Res := Infere_RAM (Ctxt, Val); else -- So there is a logical loop. Sel := Get_Mux2_Sel (Last_Mux); @@ -685,6 +689,6 @@ package body Synth.Inference is end if; end if; - Add_Conc_Assign (Wid, Res, Off, Stmt); + return Res; end Infere; -end Synth.Inference; +end Netlists.Inference; diff --git a/src/synth/synth-inference.ads b/src/synth/netlists-inference.ads index 377b481ab..b034ec301 100644 --- a/src/synth/synth-inference.ads +++ b/src/synth/netlists-inference.ads @@ -18,20 +18,23 @@ -- Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, -- MA 02110-1301, USA. -with Types; use Types; with Netlists; use Netlists; with Netlists.Builders; use Netlists.Builders; -with Synth.Environment; use Synth.Environment; with Synth.Source; -package Synth.Inference is +package Netlists.Inference is + -- Walk the And-net N, and extract clock (posedge/negedge) if found. + -- ENABLE is N without the clock. + -- If not found, CLK and ENABLE are set to No_Net. + procedure Extract_Clock + (Ctxt : Context_Acc; N : Net; Clk : out Net; Enable : out Net); + -- To be called when there is an assignment to a signal/output of VAL and -- the previous value is PREV_VAL (an Id_Signal or Id_Output). -- If there is a loop, infere a dff or a latch or emit an error. - procedure Infere (Ctxt : Context_Acc; - Wid : Wire_Id; - Val : Net; - Off : Uns32; - Prev_Val : Net; - Stmt : Source.Syn_Src); -end Synth.Inference; + function Infere (Ctxt : Context_Acc; + Val : Net; + Off : Uns32; + Prev_Val : Net; + Stmt : Synth.Source.Syn_Src) return Net; +end Netlists.Inference; diff --git a/src/synth/netlists-memories.adb b/src/synth/netlists-memories.adb index d5013066a..7037f67cd 100644 --- a/src/synth/netlists-memories.adb +++ b/src/synth/netlists-memories.adb @@ -29,6 +29,7 @@ with Netlists.Locations; use Netlists.Locations; with Netlists.Errors; use Netlists.Errors; with Netlists.Concats; with Netlists.Folds; use Netlists.Folds; +with Netlists.Inference; with Synth.Errors; use Synth.Errors; @@ -1029,6 +1030,44 @@ package body Netlists.Memories is end case; end Validate_RAM; + function Validate_RAM_Simple (Sig : Instance) return Boolean + is + Inst : Instance; + N : Net; + Inp : Input; + Ok : Boolean; + begin + Ok := False; + N := Get_Output (Sig, 0); + while N /= No_Net loop + Inp := Get_First_Sink (N); + N := No_Net; + + while Inp /= No_Input loop + Inst := Get_Input_Parent (Inp); + case Get_Id (Inst) is + when Id_Dyn_Insert_En => + if N /= No_Net then + return False; + end if; + N := Get_Output (Inst, 0); + when Id_Dyn_Extract => + null; + when Id_Isignal + | Id_Signal => + if Inst /= Sig then + return False; + end if; + Ok := True; + when others => + return False; + end case; + Inp := Get_Next_Sink (Inp); + end loop; + end loop; + return Ok; + end Validate_RAM_Simple; + function Add_Enable_To_Dyn_Insert (Ctxt : Context_Acc; Inst : Instance; Sel : Net) return Instance is @@ -1037,7 +1076,6 @@ package body Netlists.Memories is In_Idx : constant Input := Get_Input (Inst, 2); Off : constant Uns32 := Get_Param_Uns32 (Inst, 0); Dest : constant Input := Get_First_Sink (Get_Output (Inst, 0)); - pragma Assert (Has_One_Connection (Get_Output (Inst, 0))); Res : Net; begin Res := Build_Dyn_Insert_En @@ -1048,8 +1086,12 @@ package body Netlists.Memories is Disconnect (In_Mem); Disconnect (In_V); Disconnect (In_Idx); - Disconnect (Dest); - Connect (Dest, Res); + if Dest /= No_Input then + -- Only one connection. + pragma Assert (Get_Next_Sink (Dest) = No_Input); + Disconnect (Dest); + Connect (Dest, Res); + end if; Remove_Instance (Inst); @@ -1058,10 +1100,13 @@ package body Netlists.Memories is -- Remove the mux2 MUX (by adding enable to dyn_insert). -- Return the new head. - function Reduce_Muxes_Mux2 (Ctxt : Context_Acc; Mux : Instance) - return Instance + procedure Reduce_Muxes_Mux2 (Ctxt : Context_Acc; + Psel : Net; + Head : in out Instance; + Tail : out Instance) is - Dest : constant Input := Get_First_Sink (Get_Output (Mux, 0)); + Mux : constant Instance := Head; + Muxout : constant Net := Get_Output (Mux, 0); Sel_Inp : constant Input := Get_Input (Mux, 0); In0 : constant Input := Get_Input (Mux, 1); In1 : constant Input := Get_Input (Mux, 2); @@ -1103,8 +1148,6 @@ package body Netlists.Memories is Disconnect (In0); Disconnect (In1); Disconnect (Sel_Inp); - Disconnect (Dest); - Connect (Dest, Drv0); Drv := Drv0; Src := Drv1; Sel := Build_Monadic (Ctxt, Id_Not, Sel); @@ -1113,8 +1156,6 @@ package body Netlists.Memories is Disconnect (In0); Disconnect (In1); Disconnect (Sel_Inp); - Disconnect (Dest); - Connect (Dest, Drv1); Drv := Drv1; Src := Drv0; else @@ -1122,7 +1163,9 @@ package body Netlists.Memories is raise Internal_Error; end if; - Remove_Instance (Mux); + if Psel /= No_Net then + Sel := Build_Dyadic (Ctxt, Id_And, Psel, Sel); + end if; -- Reduce Drv until Src. -- Transform dyn_insert to dyn_insert_en by adding SEL, or simply add @@ -1134,18 +1177,21 @@ package body Netlists.Memories is case Get_Id (Inst) is when Id_Mux2 => -- Recurse on the mux. - Inst := Reduce_Muxes_Mux2 (Ctxt, Inst); - -- But continue with the result: still need to add the SEL. - Drv := Get_Output (Inst, 0); + Reduce_Muxes_Mux2 (Ctxt, Sel, Inst, Tail); + if Res = No_Instance then + Res := Inst; + end if; + -- Continue the walk with the next element. + Drv := Get_Input_Net (Inst, 0); when Id_Dyn_Insert => -- Transform dyn_insert to dyn_insert_en. - Inst := Add_Enable_To_Dyn_Insert (Ctxt, Inst, Sel); + Tail := Add_Enable_To_Dyn_Insert (Ctxt, Inst, Sel); -- If this is the head, keep it. if Res = No_Instance then - Res := Inst; + Res := Tail; end if; -- Continue the walk with the next element. - Drv := Get_Input_Net (Inst, 0); + Drv := Get_Input_Net (Tail, 0); when Id_Dyn_Insert_En => -- Simply add SEL to the enable input. declare @@ -1162,23 +1208,31 @@ package body Netlists.Memories is Res := Inst; end if; -- Continue the walk with the next element. + Tail := Inst; Drv := Get_Input_Net (Inst, 0); when others => raise Internal_Error; end case; end loop; - return Res; + Redirect_Inputs (Muxout, Get_Output (Res, 0)); + Remove_Instance (Mux); + + Head := Res; end Reduce_Muxes_Mux2; -- From SIG (the signal/isignal for the RAM), move all the muxes to the -- dyn_insert. The dyn_insert may be transformed to dyn_insert_en. -- At the end, the loop is linear and without muxes. - procedure Reduce_Muxes (Ctxt : Context_Acc; Sig : Instance) + -- Return the new head. + function Reduce_Muxes (Ctxt : Context_Acc; Sig : Instance) return Instance is + pragma Assert (not Is_Connected (Get_Output (Sig, 0))); Inst : Instance; + Tail : Instance; + Res : Instance; begin - Inst := Get_Input_Instance (Sig, 0); + Inst := Sig; -- Skip dff/idff. -- FIXME: that should be considered as an implicit mux. @@ -1186,9 +1240,10 @@ package body Netlists.Memories is case Get_Id (Inst) is when Id_Dff | Id_Idff => + Res := Inst; Inst := Get_Input_Instance (Inst, 1); when others => - null; + Res := No_Instance; end case; -- Walk until the reaching SIG again. @@ -1196,18 +1251,22 @@ package body Netlists.Memories is case Get_Id (Inst) is when Id_Mux2 => -- Reduce the mux. - Inst := Reduce_Muxes_Mux2 (Ctxt, Inst); + Reduce_Muxes_Mux2 (Ctxt, No_Net, Inst, Tail); + if Res = No_Instance then + Res := Inst; + end if; + Inst := Tail; when Id_Dyn_Insert | Id_Dyn_Insert_En => + if Res = No_Instance then + Res := Inst; + end if; -- Skip the dyn_insert. Inst := Get_Input_Instance (Inst, 0); when Id_Signal | Id_Isignal => -- Should be done. - if Inst /= Sig then - raise Internal_Error; - end if; - return; + return Res; when others => raise Internal_Error; end case; @@ -1601,6 +1660,7 @@ package body Netlists.Memories is N_Inst : Instance; In_Inst : Instance; Dff_Clk : Net; + Prev_Inst : Instance; begin -- Try to extract clock from dff. Dff_Clk := No_Net; @@ -1613,10 +1673,13 @@ package body Netlists.Memories is null; end case; + Prev_Inst := No_Instance; + -- Do the real work: transform gates to ports. Inst := Sig; loop -- Check gates connected to the output. + -- First the dyn_extract N_Inst := No_Instance; Inp := Get_First_Sink (Get_Output (Inst, 0)); while Inp /= No_Input loop @@ -1677,10 +1740,10 @@ package body Netlists.Memories is end; when Id_Dyn_Insert_En | Id_Dyn_Insert - | Id_Dff - | Id_Idff | Id_Signal | Id_Isignal => + Inp := Get_Input (In_Inst, 0); + Disconnect (Inp); pragma Assert (N_Inst = No_Instance); N_Inst := In_Inst; when others => @@ -1689,6 +1752,10 @@ package body Netlists.Memories is Inp := N_Inp; end loop; + if Prev_Inst /= No_Instance then + Remove_Instance (Prev_Inst); + end if; + -- Handle INST. case Get_Id (Inst) is when Id_Dyn_Insert_En @@ -1704,31 +1771,35 @@ package body Netlists.Memories is Inp2 : Input; Dat : Net; En : Net; + Clk : Net; begin Off_Array_To_Idx (Offs.all, Off, Wd, Idx, Len); Inp2 := Get_Input (Inst, 2); Addr := Get_Driver (Inp2); Disconnect (Inp2); Convert_Memidx (Ctxt, Mem_Sz, Addr, Mem_W); - pragma Assert (Dff_Clk /= No_Net); if Get_Id (Inst) = Id_Dyn_Insert_En then Inp2 := Get_Input (Inst, 3); En := Get_Driver (Inp2); Disconnect (Inp2); + Inference.Extract_Clock (Ctxt, En, Clk, En); else + Clk := Dff_Clk; + En := No_Net; + end if; + pragma Assert (Clk /= No_Net); + if En = No_Net then En := Build_Const_UB32 (Ctxt, 1, 1); end if; for I in Idx .. Idx + Len - 1 loop Inp2 := Get_Input (Inst, 1); Dat := Get_Driver (Inp2); Wr_Inst := Build_Mem_Wr_Sync - (Ctxt, Tails (I), Addr, Dff_Clk, En, Dat); + (Ctxt, Tails (I), Addr, Clk, En, Dat); Disconnect (Inp2); Tails (I) := Get_Output (Wr_Inst, 0); end loop; end; - Inp := Get_Input (Inst, 0); - Disconnect (Inp); Remove_Instance (Inst); when Id_Dff | Id_Idff => @@ -1737,10 +1808,10 @@ package body Netlists.Memories is if Get_Id (Inst) = Id_Idff then Disconnect (Get_Input (Inst, 2)); end if; - Remove_Instance (Inst); + Prev_Inst := Inst; when Id_Signal | Id_Isignal => - null; + Prev_Inst := No_Instance; when others => raise Internal_Error; end case; @@ -1757,8 +1828,9 @@ package body Netlists.Memories is end case; end loop; + pragma Assert (Prev_Inst = No_Instance); + -- Finish to remove the signal/isignal. - Disconnect (Get_Input (Inst, 0)); Remove_Instance (Inst); end; @@ -1796,7 +1868,7 @@ package body Netlists.Memories is while Inst /= No_Instance loop -- Walk all the instances of M: case Get_Id (Inst) is - when Id_Dyn_Insert + when Id_Dyn_Insert_En | Id_Dyn_Extract => Instance_Tables.Append (Dyns, Inst); pragma Assert (Get_Mark_Flag (Inst) = False); @@ -1869,8 +1941,7 @@ package body Netlists.Memories is Replace_ROM_Memory (Ctxt, Inst); end if; else - if Validate_RAM (Inst) then - Reduce_Muxes (Ctxt, Inst); + if Validate_RAM_Simple (Inst) then Convert_To_Memory (Ctxt, Inst); end if; end if; @@ -1879,4 +1950,132 @@ package body Netlists.Memories is Instance_Tables.Free (Mems); end Extract_Memories2; + + function One_Write_Connection (O : Net) return Boolean + is + Inp : Input; + Nbr : Natural; + begin + Inp := Get_First_Sink (O); + Nbr := 0; + while Inp /= No_Input loop + if Get_Id (Get_Input_Parent (Inp)) /= Id_Dyn_Extract then + Nbr := Nbr + 1; + if Nbr > 1 then + return False; + end if; + end if; + Inp := Get_Next_Sink (Inp); + end loop; + return Nbr = 1; + end One_Write_Connection; + + function Can_Infere_RAM_Mux2 (Mux : Instance) return Instance + is + Drv0 : Net; + Drv1 : Net; + Drv : Net; + Src : Net; + Inst : Instance; + begin + -- An enable mux has this shape: + -- _ + -- / |----- dyn_insert ----+----+ + -- out --| | | +---- inp + -- \_|---------------------/ + -- + -- The dyn_insert can be on one input or the other of the mux. + -- The important point is that the output of the dyn_insert is connected + -- only to the mux, while the other mux input is connected to two nodes. + -- + -- There can be several dyn_inserts in a raw, like this: + -- _ + -- / |-- dyn_insert --- dyn_insert ---+----+ + -- out --| | | +---- inp + -- \_|--------------------------------/ + -- + -- Or even nested muxes: + -- _ + -- _ / |----- dyn_insert ----+----+ + -- / |--| | | | + -- out --| | \_|---------------------/ | + -- \_|--------------------------------+----- inp + Drv0 := Get_Input_Net (Mux, 1); + Drv1 := Get_Input_Net (Mux, 2); + if One_Write_Connection (Drv0) + and then not One_Write_Connection (Drv1) + then + Drv := Drv0; + Src := Drv1; + elsif One_Write_Connection (Drv1) + and then not One_Write_Connection (Drv0) + then + Drv := Drv1; + Src := Drv0; + else + -- Not an enable mux. + return No_Instance; + end if; + + -- Walk Drv until Src. + while Drv /= Src loop + Inst := Get_Net_Parent (Drv); + case Get_Id (Inst) is + when Id_Mux2 => + -- Recurse on the mux. + Inst := Can_Infere_RAM_Mux2 (Inst); + if Inst = No_Instance then + return No_Instance; + end if; + -- But continue with the result: still need to add the SEL. + Drv := Get_Output (Inst, 0); + when Id_Dyn_Insert => + -- Continue the walk with the next element. + Drv := Get_Input_Net (Inst, 0); + when others => + return No_Instance; + end case; + end loop; + + return Get_Net_Parent (Src); + end Can_Infere_RAM_Mux2; + + function Can_Infere_RAM (Val : Net; Prev_Val : Net) return Boolean + is + Inst : Instance; + begin + Inst := Get_Net_Parent (Val); + + -- Walk until the reaching Prev_Val. + loop + case Get_Id (Inst) is + when Id_Mux2 => + -- Reduce the mux. + Inst := Can_Infere_RAM_Mux2 (Inst); + if Inst = No_Instance then + return False; + end if; + when Id_Dyn_Insert + | Id_Dyn_Insert_En => + -- Skip the dyn_insert. + Inst := Get_Input_Instance (Inst, 0); + when Id_Signal + | Id_Isignal => + return Get_Output (Inst, 0) = Prev_Val; + when others => + return False; + end case; + end loop; + end Can_Infere_RAM; + + function Infere_RAM (Ctxt : Context_Acc; Val : Net) return Net + is + Inst : Instance; + begin + Inst := Get_Net_Parent (Val); + Inst := Reduce_Muxes (Ctxt, Inst); + return Get_Output (Inst, 0); + end Infere_RAM; + + pragma Unreferenced (Validate_RAM); end Netlists.Memories; diff --git a/src/synth/netlists-memories.ads b/src/synth/netlists-memories.ads index b6b487bf7..8d5e7739e 100644 --- a/src/synth/netlists-memories.ads +++ b/src/synth/netlists-memories.ads @@ -27,4 +27,11 @@ package Netlists.Memories is -- Count the number of memidx in a memory address. function Count_Memidx (Addr : Net) return Natural; + -- True iff a RAM can be infered from VAL (the input of an assignment). + -- TODO: handle partial write (offset) + -- TODO: directly check with assignment target. + function Can_Infere_RAM (Val : Net; Prev_Val : Net) return Boolean; + + -- Transform VAL to a RAM. + function Infere_RAM (Ctxt : Context_Acc; Val : Net) return Net; end Netlists.Memories; diff --git a/src/synth/netlists.adb b/src/synth/netlists.adb index c7c9edb96..7207d6ac0 100644 --- a/src/synth/netlists.adb +++ b/src/synth/netlists.adb @@ -357,7 +357,7 @@ package body Netlists is Nbr_Inputs : constant Port_Idx := Get_Nbr_Inputs (Inst); begin -- Check that all outputs are unused. - if Nbr_Outputs > 1 then + if Nbr_Outputs > 0 then for K in 0 .. Nbr_Outputs - 1 loop if Is_Connected (Get_Output (Inst, K)) then return True; @@ -861,15 +861,16 @@ package body Netlists is procedure Redirect_Inputs (Old : Net; N : Net) is First_I, I : Input; - Prev_I : Input; + Last_I : Input; begin First_I := Get_First_Sink (Old); if First_I = No_Input then + -- Nothing to do if no input. return; end if; I := First_I; - Prev_I := No_Input; + Last_I := No_Input; while I /= No_Input loop declare I_Rec : Input_Record renames Inputs_Table.Table (I); @@ -877,18 +878,16 @@ package body Netlists is pragma Assert (I_Rec.Driver = Old); I_Rec.Driver := N; - if Prev_I /= No_Input then - Inputs_Table.Table (Prev_I).Next_Sink := I; - end if; - Prev_I := I; + Last_I := I; I := I_Rec.Next_Sink; end; end loop; - if Prev_I /= No_Input then - Inputs_Table.Table (Prev_I).Next_Sink := Get_First_Sink (N); - Nets_Table.Table (N).First_Sink := First_I; - end if; + Inputs_Table.Table (Last_I).Next_Sink := Get_First_Sink (N); + Nets_Table.Table (N).First_Sink := First_I; + + -- Also disconnect OLD + Nets_Table.Table (Old).First_Sink := No_Input; end Redirect_Inputs; begin diff --git a/src/synth/synth-environment.adb b/src/synth/synth-environment.adb index 58fd0f0d8..7c3218105 100644 --- a/src/synth/synth-environment.adb +++ b/src/synth/synth-environment.adb @@ -24,10 +24,10 @@ with Netlists.Gates; with Netlists.Gates_Ports; with Netlists.Utils; use Netlists.Utils; with Netlists.Folds; use Netlists.Folds; +with Netlists.Inference; with Errorout; use Errorout; -with Synth.Inference; with Synth.Errors; use Synth.Errors; with Synth.Source; use Synth.Source; @@ -363,9 +363,11 @@ package body Synth.Environment is declare Pa : Partial_Assign_Record renames Partial_Assign_Table.Table (P); + Res : Net; begin - Inference.Infere - (Ctxt, Wid, Pa.Value, Pa.Offset, Outport, Stmt); + Res := Inference.Infere + (Ctxt, Pa.Value, Pa.Offset, Outport, Stmt); + Add_Conc_Assign (Wid, Res, Pa.Offset, Stmt); P := Pa.Next; end; end loop; @@ -1022,10 +1024,26 @@ package body Synth.Environment is if Get_Id (N1_Inst) = Id_Mux2 and then Same_Net (Get_Driver (Get_Mux2_I0 (N1_Inst)), N (0)) then - Res := Build_Mux2 - (Ctxt, Build_Dyadic (Ctxt, Id_And, - Sel, Get_Driver (Get_Mux2_Sel (N1_Inst))), - N (0), Get_Driver (Get_Mux2_I1 (N1_Inst))); + declare + N1_Net : Net; + N1_Sel : Input; + N1_Sel_Net : Net; + begin + N1_Net := Get_Output (N1_Inst, 0); + N1_Sel := Get_Input (N1_Inst, 0); + N1_Sel_Net := Get_Driver (N1_Sel); + if not Is_Connected (N1_Net) then + -- If the previous mux2 is not used, just modify it. + Res := N1_Net; + Disconnect (N1_Sel); + N1_Sel_Net := Build_Dyadic (Ctxt, Id_And, Sel, N1_Sel_Net); + Connect (N1_Sel, N1_Sel_Net); + else + Res := Build_Mux2 + (Ctxt, Build_Dyadic (Ctxt, Id_And, Sel, N1_Sel_Net), + N (0), Get_Driver (Get_Mux2_I1 (N1_Inst))); + end if; + end; else Res := Build_Mux2 (Ctxt, Sel, N (0), N (1)); end if; |