aboutsummaryrefslogtreecommitdiffstats
path: root/src/synth/netlists-memories.adb
diff options
context:
space:
mode:
authorTristan Gingold <tgingold@free.fr>2020-02-20 07:37:42 +0100
committerTristan Gingold <tgingold@free.fr>2020-02-20 07:48:33 +0100
commitedfe8e0915a640537617d0afb3876ce2603bda81 (patch)
treed390676ebe4f9ae2edd5e33ea17931fc2859e565 /src/synth/netlists-memories.adb
parente53164cb18f4cb2b26f19f33c4a9ed672c35d5b1 (diff)
downloadghdl-edfe8e0915a640537617d0afb3876ce2603bda81.tar.gz
ghdl-edfe8e0915a640537617d0afb3876ce2603bda81.tar.bz2
ghdl-edfe8e0915a640537617d0afb3876ce2603bda81.zip
netlists-memories: factorize code.
Diffstat (limited to 'src/synth/netlists-memories.adb')
-rw-r--r--src/synth/netlists-memories.adb426
1 files changed, 191 insertions, 235 deletions
diff --git a/src/synth/netlists-memories.adb b/src/synth/netlists-memories.adb
index 358877674..27b5d4da6 100644
--- a/src/synth/netlists-memories.adb
+++ b/src/synth/netlists-memories.adb
@@ -771,232 +771,6 @@ package body Netlists.Memories is
return Ok;
end Validate_RAM_Simple;
- function Add_Enable_To_Dyn_Insert
- (Ctxt : Context_Acc; Inst : Instance; Sel : Net) return Instance
- is
- In_Mem : constant Input := Get_Input (Inst, 0);
- In_V : constant Input := Get_Input (Inst, 1);
- 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));
- Res : Net;
- begin
- Res := Build_Dyn_Insert_En
- (Ctxt, Get_Driver (In_Mem), Get_Driver (In_V), Get_Driver (In_Idx),
- Sel, Off);
- Set_Location (Res, Get_Location (Inst));
-
- Disconnect (In_Mem);
- Disconnect (In_V);
- Disconnect (In_Idx);
- 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);
-
- return Get_Net_Parent (Res);
- end Add_Enable_To_Dyn_Insert;
-
- -- Remove the mux2 MUX (by adding enable to dyn_insert).
- -- Return the new head.
- procedure Reduce_Muxes_Mux2 (Ctxt : Context_Acc;
- Psel : Net;
- Head : in out Instance;
- Tail : out Instance)
- is
- 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);
- Sel : Net;
- Drv0 : Net;
- Drv1 : Net;
- Drv : Net;
- Src : Net;
- Res : Instance;
- Inst : Instance;
- begin
- Drv0 := Get_Driver (In0);
- Drv1 := Get_Driver (In1);
- Sel := Get_Driver (Sel_Inp);
-
- -- 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
- if Has_One_Connection (Drv0) and then not Has_One_Connection (Drv1) then
- Disconnect (In0);
- Disconnect (In1);
- Disconnect (Sel_Inp);
- Drv := Drv0;
- Src := Drv1;
- Sel := Build_Monadic (Ctxt, Id_Not, Sel);
- elsif Has_One_Connection (Drv1) and then not Has_One_Connection (Drv0)
- then
- Disconnect (In0);
- Disconnect (In1);
- Disconnect (Sel_Inp);
- Drv := Drv1;
- Src := Drv0;
- else
- -- Not an enable mux.
- raise Internal_Error;
- end if;
-
- 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
- -- SEL to existing dyn_insert_en.
- -- RES is the head of the result chain.
- Res := No_Instance;
- while Drv /= Src loop
- Inst := Get_Net_Parent (Drv);
- case Get_Id (Inst) is
- when Id_Mux2 =>
- -- Recurse on the mux.
- 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.
- Tail := Add_Enable_To_Dyn_Insert (Ctxt, Inst, Sel);
- -- If this is the head, keep it.
- if Res = No_Instance then
- Res := Tail;
- end if;
- -- Continue the walk with the next element.
- Drv := Get_Input_Net (Tail, 0);
- when Id_Dyn_Insert_En =>
- -- Simply add SEL to the enable input.
- declare
- En_Inp : constant Input := Get_Input (Inst, 3);
- En : Net;
- begin
- En := Get_Driver (En_Inp);
- Disconnect (En_Inp);
- En := Build_Dyadic (Ctxt, Id_And, En, Sel);
- Connect (En_Inp, En);
- end;
- -- If this is the head, keep it.
- if Res = No_Instance then
- 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;
-
- 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.
- -- Return the new head.
- function Reduce_Muxes (Ctxt : Context_Acc; Sig : Instance; En : Net)
- return Instance
- is
- pragma Assert (not Is_Connected (Get_Output (Sig, 0)));
- Inst : Instance;
- Tail : Instance;
- Res : Instance;
- begin
- Inst := Sig;
-
- -- Skip dff/idff.
- -- FIXME: that should be considered as an implicit mux.
- -- FIXME: what about dual-port RAMS with two different clocks ?
- case Get_Id (Inst) is
- when Id_Dff
- | Id_Idff =>
- Res := Inst;
- Inst := Get_Input_Instance (Inst, 1);
- when others =>
- Res := No_Instance;
- end case;
-
- -- Walk until the reaching SIG again.
- loop
- case Get_Id (Inst) is
- when Id_Mux2 =>
- -- Reduce the mux.
- Reduce_Muxes_Mux2 (Ctxt, En, Inst, Tail);
- if Res = No_Instance then
- Res := Inst;
- end if;
- Inst := Tail;
- when Id_Dyn_Insert =>
- if En /= No_Net then
- Inst := Add_Enable_To_Dyn_Insert (Ctxt, Inst, En);
- end if;
- if Res = No_Instance then
- Res := Inst;
- end if;
- -- Skip the dyn_insert.
- Inst := Get_Input_Instance (Inst, 0);
- when Id_Dyn_Insert_En =>
- if En /= No_Net then
- declare
- En_Inp : Input;
- En2 : Net;
- begin
- En_Inp := Get_Input (Inst, 3);
- En2 := Build_Dyadic (Ctxt, Id_And,
- Get_Driver (En_Inp), En);
- Disconnect (En_Inp);
- Connect (En_Inp, En2);
- end;
- end if;
- 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.
- return Res;
- when others =>
- raise Internal_Error;
- end case;
- end loop;
- end Reduce_Muxes;
-
-- Extract the step (equivalent to data width) of a dyn_insert/dyn_extract
-- address. This is either a memidx or an addidx gate.
function Extract_Memidx_Step (Memidx : Instance) return Width
@@ -1685,6 +1459,197 @@ package body Netlists.Memories is
Instance_Tables.Free (Mems);
end Extract_Memories2;
+ function Add_Enable_To_Dyn_Insert
+ (Ctxt : Context_Acc; Inst : Instance; Sel : Net) return Instance
+ is
+ In_Mem : constant Input := Get_Input (Inst, 0);
+ In_V : constant Input := Get_Input (Inst, 1);
+ 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));
+ Res : Net;
+ begin
+ Res := Build_Dyn_Insert_En
+ (Ctxt, Get_Driver (In_Mem), Get_Driver (In_V), Get_Driver (In_Idx),
+ Sel, Off);
+ Set_Location (Res, Get_Location (Inst));
+
+ Disconnect (In_Mem);
+ Disconnect (In_V);
+ Disconnect (In_Idx);
+ 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);
+
+ return Get_Net_Parent (Res);
+ end Add_Enable_To_Dyn_Insert;
+
+ procedure Reduce_Muxes_Mux2 (Ctxt : Context_Acc;
+ Psel : Net;
+ Head : in out Instance;
+ Tail : out Instance);
+
+ -- Remove the mux2 MUX (by adding enable to dyn_insert).
+ -- Return the new head.
+ procedure Reduce_Muxes (Ctxt : Context_Acc;
+ Sel : Net;
+ Head_In : Net;
+ Tail_In : Net;
+ Head_Out : out Instance;
+ Tail_Out : out Instance)
+ is
+ Inst : Instance;
+ N : Net;
+ begin
+ -- Reduce Drv until Src.
+ -- Transform dyn_insert to dyn_insert_en by adding SEL, or simply add
+ -- SEL to existing dyn_insert_en.
+ -- RES is the head of the result chain.
+ N := Head_In;
+ Head_Out := No_Instance;
+ while N /= Tail_In loop
+ Inst := Get_Net_Parent (N);
+ case Get_Id (Inst) is
+ when Id_Mux2 =>
+ -- Recurse on the mux.
+ Reduce_Muxes_Mux2 (Ctxt, Sel, Inst, Tail_Out);
+ when Id_Dyn_Insert =>
+ -- Transform dyn_insert to dyn_insert_en.
+ if Sel /= No_Net then
+ Tail_Out := Add_Enable_To_Dyn_Insert (Ctxt, Inst, Sel);
+ Inst := Tail_Out;
+ else
+ Tail_Out := Inst;
+ end if;
+ when Id_Dyn_Insert_En =>
+ -- Simply add SEL to the enable input.
+ if Sel /= No_Net then
+ declare
+ En_Inp : constant Input := Get_Input (Inst, 3);
+ En : Net;
+ begin
+ En := Get_Driver (En_Inp);
+ Disconnect (En_Inp);
+ En := Build_Dyadic (Ctxt, Id_And, En, Sel);
+ Connect (En_Inp, En);
+ end;
+ end if;
+ Tail_Out := Inst;
+ when Id_Signal
+ | Id_Isignal =>
+ pragma Assert (Tail_In = No_Net);
+ return;
+ when others =>
+ raise Internal_Error;
+ end case;
+ -- If this is the head, keep it.
+ if Head_Out = No_Instance then
+ Head_Out := Inst;
+ end if;
+ -- Continue the walk with the next element.
+ N := Get_Input_Net (Tail_Out, 0);
+ end loop;
+ end Reduce_Muxes;
+
+ -- Remove the mux2 MUX (by adding enable to dyn_insert).
+ -- Return the new head.
+ procedure Reduce_Muxes_Mux2 (Ctxt : Context_Acc;
+ Psel : Net;
+ Head : in out Instance;
+ Tail : out Instance)
+ is
+ 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);
+ Sel : Net;
+ Drv0 : Net;
+ Drv1 : Net;
+ Drv : Net;
+ Src : Net;
+ Res : Instance;
+ begin
+ Drv0 := Get_Driver (In0);
+ Drv1 := Get_Driver (In1);
+ Sel := Get_Driver (Sel_Inp);
+
+ -- 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
+ if Has_One_Connection (Drv0) and then not Has_One_Connection (Drv1) then
+ Disconnect (In0);
+ Disconnect (In1);
+ Disconnect (Sel_Inp);
+ Drv := Drv0;
+ Src := Drv1;
+ Sel := Build_Monadic (Ctxt, Id_Not, Sel);
+ elsif Has_One_Connection (Drv1) and then not Has_One_Connection (Drv0)
+ then
+ Disconnect (In0);
+ Disconnect (In1);
+ Disconnect (Sel_Inp);
+ Drv := Drv1;
+ Src := Drv0;
+ else
+ -- Not an enable mux.
+ raise Internal_Error;
+ end if;
+
+ 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
+ -- SEL to existing dyn_insert_en.
+ -- RES is the head of the result chain.
+ Reduce_Muxes (Ctxt, Sel, Drv, Src, Res, Tail);
+
+ Redirect_Inputs (Muxout, Get_Output (Res, 0));
+ Remove_Instance (Mux);
+
+ Head := Res;
+ end Reduce_Muxes_Mux2;
+
+ function Infere_RAM (Ctxt : Context_Acc; Val : Net; En : Net) return Net
+ is
+ pragma Assert (not Is_Connected (Val));
+ Tail : Instance;
+ Res : Instance;
+ begin
+ -- From VAL, 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.
+ -- Return the new head.
+ Reduce_Muxes (Ctxt, En, Val, No_Net, Res, Tail);
+ return Get_Output (Res, 0);
+ end Infere_RAM;
+
function One_Write_Connection (O : Net; Mux : Instance) return Boolean
is
Inp : Input;
@@ -1829,13 +1794,4 @@ package body Netlists.Memories is
end case;
end loop;
end Can_Infere_RAM;
-
- function Infere_RAM (Ctxt : Context_Acc; Val : Net; En : Net) return Net
- is
- Inst : Instance;
- begin
- Inst := Get_Net_Parent (Val);
- Inst := Reduce_Muxes (Ctxt, Inst, En);
- return Get_Output (Inst, 0);
- end Infere_RAM;
end Netlists.Memories;