aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorTristan Gingold <tgingold@free.fr>2019-08-01 04:21:40 +0200
committerTristan Gingold <tgingold@free.fr>2019-08-01 04:21:40 +0200
commitd8daefafb575227a1644b2f24bd604dcbfc76c75 (patch)
tree97c886e5e2534e1af718dd4fb822ff8e09034462
parente02c802538cd52c55f881118380fa0d06da3acce (diff)
downloadghdl-d8daefafb575227a1644b2f24bd604dcbfc76c75.tar.gz
ghdl-d8daefafb575227a1644b2f24bd604dcbfc76c75.tar.bz2
ghdl-d8daefafb575227a1644b2f24bd604dcbfc76c75.zip
synth: refactor inference, add comment, strengthen check.
-rw-r--r--src/synth/synth-environment.adb30
-rw-r--r--src/synth/synth-environment.ads2
-rw-r--r--src/synth/synth-inference.adb53
-rw-r--r--src/synth/synth-inference.ads8
4 files changed, 62 insertions, 31 deletions
diff --git a/src/synth/synth-environment.adb b/src/synth/synth-environment.adb
index 0986d5f69..0051f48fa 100644
--- a/src/synth/synth-environment.adb
+++ b/src/synth/synth-environment.adb
@@ -131,9 +131,22 @@ package body Synth.Environment is
Conc_Assign_Table.Table (Asgn).Next := Chain;
end Set_Conc_Chain;
- procedure Add_Conc_Assign
- (Wire_Rec : in out Wire_Id_Record; Val : Net; Stmt : Source.Syn_Src)
+ procedure Add_Conc_Assign_Partial
+ (Wid : Wire_Id; Val : Net; Off : Uns32; Stmt : Source.Syn_Src)
is
+ Wire_Rec : Wire_Id_Record renames Wire_Id_Table.Table (Wid);
+ begin
+ Conc_Assign_Table.Append ((Next => Wire_Rec.Final_Assign,
+ Value => Val,
+ Offset => Off,
+ Stmt => Stmt));
+ Wire_Rec.Final_Assign := Conc_Assign_Table.Last;
+ Wire_Rec.Nbr_Final_Assign := Wire_Rec.Nbr_Final_Assign + 1;
+ end Add_Conc_Assign_Partial;
+
+ procedure Add_Conc_Assign (Wid : Wire_Id; Val : Net; Stmt : Source.Syn_Src)
+ is
+ Wire_Rec : Wire_Id_Record renames Wire_Id_Table.Table (Wid);
Inst : constant Instance := Get_Parent (Val);
V : Net;
Off : Uns32;
@@ -155,12 +168,7 @@ package body Synth.Environment is
V := Val;
Off := 0;
end if;
- Conc_Assign_Table.Append ((Next => Wire_Rec.Final_Assign,
- Value => V,
- Offset => Off,
- Stmt => Stmt));
- Wire_Rec.Final_Assign := Conc_Assign_Table.Last;
- Wire_Rec.Nbr_Final_Assign := Wire_Rec.Nbr_Final_Assign + 1;
+ Add_Conc_Assign_Partial (Wid, V, Off, Stmt);
end Add_Conc_Assign;
-- This procedure is called after each concurrent statement to assign
@@ -199,9 +207,7 @@ package body Synth.Environment is
raise Internal_Error;
end if;
- Drv := Inference.Infere (Ctxt, Asgn_Rec.Value, Outport);
-
- Add_Conc_Assign (Wire_Rec, Drv, Stmt);
+ Inference.Infere (Ctxt, Wid, Asgn_Rec.Value, Outport, Stmt);
when others =>
raise Internal_Error;
end case;
@@ -284,7 +290,7 @@ package body Synth.Environment is
Last_Asgn := No_Conc_Assign;
Expected_Off := 0;
Last_Off := Get_Width (Wire_Rec.Gate);
- while Expected_Off < Last_Off loop
+ while (Expected_Off < Last_Off) or Asgn /= No_Conc_Assign loop
if Asgn /= No_Conc_Assign then
Next_Off := Get_Conc_Offset (Asgn);
else
diff --git a/src/synth/synth-environment.ads b/src/synth/synth-environment.ads
index 0cdddc08f..c16a3cc0b 100644
--- a/src/synth/synth-environment.ads
+++ b/src/synth/synth-environment.ads
@@ -109,6 +109,8 @@ package Synth.Environment is
function Current_Phi return Phi_Id;
pragma Inline (Current_Phi);
+ procedure Add_Conc_Assign (Wid : Wire_Id; Val : Net; Stmt : Source.Syn_Src);
+
procedure Finalize_Assignments (Ctxt : Builders.Context_Acc);
private
type Wire_Id is new Uns32;
diff --git a/src/synth/synth-inference.adb b/src/synth/synth-inference.adb
index de9ea4dff..ebe478fa7 100644
--- a/src/synth/synth-inference.adb
+++ b/src/synth/synth-inference.adb
@@ -177,11 +177,13 @@ package body Synth.Inference is
end case;
end Extract_Clock;
- function Infere_FF (Ctxt : Context_Acc;
- Prev_Val : Net;
- Last_Mux : Instance;
- Clk : Net;
- Enable : Net) return Net
+ procedure Infere_FF (Ctxt : Context_Acc;
+ Wid : Wire_Id;
+ Prev_Val : Net;
+ Last_Mux : Instance;
+ Clk : Net;
+ Enable : Net;
+ Stmt : Source.Syn_Src)
is
Sel : constant Input := Get_Mux2_Sel (Last_Mux);
I0 : constant Input := Get_Mux2_I0 (Last_Mux);
@@ -196,6 +198,9 @@ package body Synth.Inference is
Rst_Val : Net;
begin
-- Create and return the DFF.
+
+ -- 1. Remove the mux that creates the loop (will be replaced by the
+ -- dff).
Disconnect (Sel);
if Get_Driver (I0) /= Prev_Val then
-- There must be no 'else' part for clock expression.
@@ -206,6 +211,9 @@ package body Synth.Inference is
Data := Get_Driver (I1);
-- Don't try to free driver of I1 as it is reconnected.
Disconnect (I1);
+ -- If there is a condition with the clock, that's an enable which
+ -- keep the previous value if the condition is false. Add the mux
+ -- for it.
if Enable /= No_Net then
Data := Build_Mux2 (Ctxt, Enable, Prev_Val, Data);
end if;
@@ -221,9 +229,10 @@ package body Synth.Inference is
Init := No_Net;
end if;
+ -- Look for asynchronous set/reset. They are muxes after the loop
+ -- mux. In theory, there can be many set/reset with a defined order.
Rst_Val := No_Net;
Rst := No_Net;
-
declare
Mux : Instance;
Sel : Net;
@@ -276,6 +285,7 @@ package body Synth.Inference is
end loop;
end;
+ -- Create the FF.
if Rst = No_Net then
pragma Assert (Rst_Val = No_Net);
if Init /= No_Net then
@@ -305,10 +315,15 @@ package body Synth.Inference is
Redirect_Inputs (O, Res);
Free_Instance (Last_Mux);
- return Res;
+
+ Add_Conc_Assign (Wid, Res, Stmt);
end Infere_FF;
- function Infere (Ctxt : Context_Acc; Val : Net; Prev_Val : Net) return Net
+ procedure Infere (Ctxt : Context_Acc;
+ Wid : Wire_Id;
+ Val : Net;
+ Prev_Val : Net;
+ Stmt : Source.Syn_Src)
is
pragma Assert (Val /= No_Net);
pragma Assert (Prev_Val /= No_Net);
@@ -321,19 +336,21 @@ package body Synth.Inference is
Find_Longest_Loop (Val, Prev_Val, Last_Mux, Len);
if Len < 0 then
-- No logical loop
- return Val;
+ Add_Conc_Assign (Wid, Val, Stmt);
elsif Len = 0 then
-- Self assignment.
- return Val;
- end if;
-
- Sel := Get_Mux2_Sel (Last_Mux);
- Extract_Clock (Get_Driver (Sel), Clk, Enable);
- if Clk = No_Net then
- -- No clock -> latch
- raise Internal_Error;
+ Add_Conc_Assign (Wid, Val, Stmt);
else
- return Infere_FF (Ctxt, Prev_Val, Last_Mux, Clk, Enable);
+ -- So there is a logical loop.
+ Sel := Get_Mux2_Sel (Last_Mux);
+ Extract_Clock (Get_Driver (Sel), Clk, Enable);
+ if Clk = No_Net then
+ -- No clock -> latch
+ raise Internal_Error;
+ else
+ -- Clock -> FF
+ Infere_FF (Ctxt, Wid, Prev_Val, Last_Mux, Clk, Enable, Stmt);
+ end if;
end if;
end Infere;
end Synth.Inference;
diff --git a/src/synth/synth-inference.ads b/src/synth/synth-inference.ads
index 5777e04e4..371932f3e 100644
--- a/src/synth/synth-inference.ads
+++ b/src/synth/synth-inference.ads
@@ -20,10 +20,16 @@
with Netlists; use Netlists;
with Netlists.Builders; use Netlists.Builders;
+with Synth.Environment; use Synth.Environment;
+with Synth.Source;
package Synth.Inference is
-- 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.
- function Infere (Ctxt : Context_Acc; Val : Net; Prev_Val : Net) return Net;
+ procedure Infere (Ctxt : Context_Acc;
+ Wid : Wire_Id;
+ Val : Net;
+ Prev_Val : Net;
+ Stmt : Source.Syn_Src);
end Synth.Inference;