aboutsummaryrefslogtreecommitdiffstats
path: root/src/synth
diff options
context:
space:
mode:
authorTristan Gingold <tgingold@free.fr>2019-09-17 02:18:01 +0200
committerTristan Gingold <tgingold@free.fr>2019-09-17 02:18:01 +0200
commitb7a36d7d7838d05b449aa7e23935cd0e3e4213d4 (patch)
treeb50c865a4c0acfb5923e2402578417e5f6accd7c /src/synth
parentb3a28203e95f68bd1007c4c11b44187ecabbf593 (diff)
downloadghdl-b7a36d7d7838d05b449aa7e23935cd0e3e4213d4.tar.gz
ghdl-b7a36d7d7838d05b449aa7e23935cd0e3e4213d4.tar.bz2
ghdl-b7a36d7d7838d05b449aa7e23935cd0e3e4213d4.zip
synth-inference: detect false loop.
Diffstat (limited to 'src/synth')
-rw-r--r--src/synth/netlists-gates.ads2
-rw-r--r--src/synth/netlists.adb5
-rw-r--r--src/synth/netlists.ads4
-rw-r--r--src/synth/synth-inference.adb111
4 files changed, 120 insertions, 2 deletions
diff --git a/src/synth/netlists-gates.ads b/src/synth/netlists-gates.ads
index 124f933a4..b33da9778 100644
--- a/src/synth/netlists-gates.ads
+++ b/src/synth/netlists-gates.ads
@@ -86,6 +86,8 @@ package Netlists.Gates is
-- Output: o
Id_Mux4 : constant Module_Id := 37;
+ subtype Mux_Module_Id is Module_Id range Id_Mux2 .. Id_Mux4;
+
-- Like a wire: the output is equal to the input, but could be elimited
-- at any time. Isignal has an initial value.
Id_Signal : constant Module_Id := 38;
diff --git a/src/synth/netlists.adb b/src/synth/netlists.adb
index 1bde22ac6..66854a714 100644
--- a/src/synth/netlists.adb
+++ b/src/synth/netlists.adb
@@ -297,6 +297,11 @@ package body Netlists is
Table_Low_Bound => No_Param_Idx,
Table_Initial => 256);
+ function Hash (Inst : Instance) return Hash_Value_Type is
+ begin
+ return Hash_Value_Type (Inst);
+ end Hash;
+
procedure Extract_All_Instances (M : Module; First_Instance : out Instance)
is
pragma Assert (Is_Valid (M));
diff --git a/src/synth/netlists.ads b/src/synth/netlists.ads
index 0e7647b79..49c9144db 100644
--- a/src/synth/netlists.ads
+++ b/src/synth/netlists.ads
@@ -19,6 +19,7 @@
-- MA 02110-1301, USA.
with Types; use Types;
+with Hash; use Hash;
package Netlists is
-- Netlists.
@@ -103,6 +104,9 @@ package Netlists is
type Instance is private;
No_Instance : constant Instance;
+ -- Hash INST (simply return its index).
+ function Hash (Inst : Instance) return Hash_Value_Type;
+
-- A net is an output of a gate or a sub-circuit. A net can be connected
-- to several inputs.
type Net is private;
diff --git a/src/synth/synth-inference.adb b/src/synth/synth-inference.adb
index 56f1fca3d..376a48840 100644
--- a/src/synth/synth-inference.adb
+++ b/src/synth/synth-inference.adb
@@ -18,6 +18,8 @@
-- Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston,
-- MA 02110-1301, USA.
+with Dyn_Interning;
+
with Netlists.Utils; use Netlists.Utils;
with Netlists.Gates; use Netlists.Gates;
with Netlists.Gates_Ports; use Netlists.Gates_Ports;
@@ -338,6 +340,111 @@ package body Synth.Inference is
Add_Conc_Assign (Wid, Res, Off, Stmt);
end Infere_FF;
+ function Id_Instance (Param : Instance) return Instance is
+ begin
+ return Param;
+ end Id_Instance;
+
+ package Inst_Interning is new Dyn_Interning
+ (Params_Type => Instance,
+ Object_Type => Instance,
+ Hash => Netlists.Hash,
+ Build => Id_Instance,
+ Equal => "=");
+
+ -- Detect false combinational loop. They can easily appear when variables
+ -- are only used in one branch:
+ -- process (all)
+ -- variable a : std_logic;
+ -- begin
+ -- r <= '1';
+ -- if sel = '1' then
+ -- a := '1';
+ -- r <= '0';
+ -- end if;
+ -- end process;
+ -- There is a combinational path from 'a' to 'a' as
+ -- a := (sel = '1') ? '1' : a;
+ -- But this is a false loop because the value of 'a' is never used. In
+ -- that case, 'a' is assigned to 'x' and all the unused logic will be
+ -- removed during clean-up.
+ --
+ -- Detection is very simple: the closure of readers of 'a' must be only
+ -- muxes (which were inserted by controls).
+ function Is_False_Loop (Prev_Val : Net) return Boolean
+ is
+ use Inst_Interning;
+ T : Inst_Interning.Instance;
+
+ function Add_From_Net (N : Net) return Boolean
+ is
+ Inst : Netlists.Instance;
+ Inp : Input;
+ begin
+ Inp := Get_First_Sink (N);
+ while Inp /= No_Input loop
+ Inst := Get_Input_Parent (Inp);
+ if Get_Id (Inst) not in Mux_Module_Id then
+ return False;
+ end if;
+
+ -- Add to T (if not already).
+ Get (T, Inst, Inst);
+
+ Inp := Get_Next_Sink (Inp);
+ end loop;
+
+ return True;
+ end Add_From_Net;
+
+ function Walk_Nets (N : Net) return Boolean
+ is
+ Inst : Netlists.Instance;
+ begin
+ -- Put gates that read the value.
+ if not Add_From_Net (N) then
+ return False;
+ end if;
+
+ -- Follow the outputs.
+ for I in First_Index .. Index_Type'Last loop
+ exit when I > Inst_Interning.Last_Index (T);
+ Inst := Get_By_Index (T, I);
+ if not Add_From_Net (Get_Output (Inst, 0)) then
+ return False;
+ end if;
+ end loop;
+
+ -- No external readers.
+ return True;
+ end Walk_Nets;
+
+ Res : Boolean;
+ begin
+ Inst_Interning.Init (T);
+
+ Res := Walk_Nets (Prev_Val);
+
+ Inst_Interning.Free (T);
+
+ return Res;
+ end Is_False_Loop;
+
+ procedure Infere_Latch (Ctxt : Context_Acc; Val : Net; Prev_Val : Net)
+ is
+ X : Net;
+ begin
+ -- In case of false loop, do not close the loop but assign X.
+ if Is_False_Loop (Prev_Val) then
+ X := Build_Const_X (Ctxt, Get_Width (Val));
+ Connect (Get_Input (Get_Net_Parent (Prev_Val), 0), X);
+ return;
+ end if;
+
+ -- Latch or combinational loop.
+ raise Internal_Error;
+ end Infere_Latch;
+
procedure Infere (Ctxt : Context_Acc;
Wid : Wire_Id;
Val : Net;
@@ -364,8 +471,8 @@ package body Synth.Inference is
Sel := Get_Mux2_Sel (Last_Mux);
Extract_Clock (Get_Driver (Sel), Clk, Enable);
if Clk = No_Net then
- -- No clock -> latch
- raise Internal_Error;
+ -- No clock -> latch or combinational loop
+ Infere_Latch (Ctxt, Val, Prev_Val);
else
-- Clock -> FF
Infere_FF (Ctxt, Wid, Prev_Val, Off, Last_Mux, Clk, Enable, Stmt);