aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorTristan Gingold <tgingold@free.fr>2020-02-10 07:00:31 +0100
committerTristan Gingold <tgingold@free.fr>2020-02-10 07:00:31 +0100
commit8f4dda3ded16f2604c070736cbde8849774755a8 (patch)
treef4f59e0760faf79d9d9f7a625991df655599c8bc
parent0f7aa39d2c423b27519b541ae04648d5b3277ffd (diff)
downloadghdl-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.adb2
-rw-r--r--src/synth/netlists-expands.adb4
-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.adb275
-rw-r--r--src/synth/netlists-memories.ads7
-rw-r--r--src/synth/netlists.adb21
-rw-r--r--src/synth/synth-environment.adb32
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;