aboutsummaryrefslogtreecommitdiffstats
path: root/src/synth
diff options
context:
space:
mode:
authorTristan Gingold <tgingold@free.fr>2022-10-30 17:50:14 +0100
committerTristan Gingold <tgingold@free.fr>2022-10-30 17:50:14 +0100
commit2a05b90eb163a582fce9f9dd91ef07d0d77fb47c (patch)
treea80304905bb36fcdb159f53deb89951d4611a20b /src/synth
parent498b58b45dafb3b38ef0711170dba606c08c37b8 (diff)
downloadghdl-2a05b90eb163a582fce9f9dd91ef07d0d77fb47c.tar.gz
ghdl-2a05b90eb163a582fce9f9dd91ef07d0d77fb47c.tar.bz2
ghdl-2a05b90eb163a582fce9f9dd91ef07d0d77fb47c.zip
netlists-inference: handle flip-flop with different patterns.
Fix #2231
Diffstat (limited to 'src/synth')
-rw-r--r--src/synth/netlists-inference.adb98
1 files changed, 75 insertions, 23 deletions
diff --git a/src/synth/netlists-inference.adb b/src/synth/netlists-inference.adb
index 2c50648e9..747731a11 100644
--- a/src/synth/netlists-inference.adb
+++ b/src/synth/netlists-inference.adb
@@ -94,13 +94,30 @@ package body Netlists.Inference is
end Has_Clock;
-- Find the longest chain of mux starting from VAL with a final input
- -- of PREV_VAL. Such a chain means this is a memorising element.
+ -- of PREV_VAL (assigned at OFF).
+ -- Such a chain means this is a memorising element.
-- RES is the last mux in the chain, DIST the number of mux in the chain.
- procedure Find_Longest_Loop
- (Val : Net; Prev_Val : Net; Res : out Instance; Dist : out Integer)
+ procedure Find_Longest_Loop (Val : Net;
+ Prev_Val : Net;
+ Off : Uns32;
+ Res : out Instance;
+ Dist : out Integer)
is
- Inst : constant Instance := Get_Net_Parent (Val);
+ Inst : Instance;
+ Noff : Uns32;
begin
+ Inst := Get_Net_Parent (Val);
+ Noff := Off;
+
+ -- Skip extract (if any).
+ if Get_Id (Inst) = Id_Extract
+ and then Get_Param_Uns32 (Inst, 0) = Noff
+ and then Get_Width (Get_Input_Net (Inst, 0)) = Get_Width (Prev_Val)
+ then
+ Inst := Get_Net_Parent (Get_Input_Net (Inst, 0));
+ Noff := 0;
+ end if;
+
if Get_Id (Inst) = Id_Mux2 then
declare
Res0, Res1 : Instance;
@@ -111,9 +128,11 @@ package body Netlists.Inference is
Dist := 1;
else
Find_Longest_Loop
- (Get_Driver (Get_Mux2_I0 (Inst)), Prev_Val, Res0, Dist0);
+ (Get_Driver (Get_Mux2_I0 (Inst)), Prev_Val, Noff,
+ Res0, Dist0);
Find_Longest_Loop
- (Get_Driver (Get_Mux2_I1 (Inst)), Prev_Val, Res1, Dist1);
+ (Get_Driver (Get_Mux2_I1 (Inst)), Prev_Val, Noff,
+ Res1, Dist1);
-- Input1 has an higher priority than input0 in case
-- the selector is a clock.
-- FIXME: improve algorithm.
@@ -306,7 +325,6 @@ package body Netlists.Inference is
Inst : Instance;
begin
if V = Prev_Val then
- pragma Assert (Off = 0);
return True;
end if;
Inst := Get_Net_Parent (V);
@@ -418,6 +436,7 @@ package body Netlists.Inference is
procedure Infere_FF_Mux (Ctxt : Context_Acc;
Prev_Val : Net;
Off : Uns32;
+ W : Width;
Last_Mux : Instance;
Els : out Net;
Data : out Net)
@@ -455,7 +474,8 @@ package body Netlists.Inference is
-- 1. Remove the mux that creates the loop (will be replaced by
-- the dff).
- Infere_FF_Mux (Ctxt, Prev_Val, Off, Els_Inst, Els_Els, Els_Data);
+ Infere_FF_Mux
+ (Ctxt, Prev_Val, Off, W, Els_Inst, Els_Els, Els_Data);
Els := Infere_FF_Create (Ctxt, Prev_Val, Off, Els_Inst, No_Net,
No_Net, No_Net, Els_Data, Els_Els,
@@ -464,13 +484,18 @@ package body Netlists.Inference is
end if;
end if;
- Disconnect (Sel);
- -- Don't try to free driver of I0 as this is Prev_Val or a selection
- -- of it.
- Disconnect (I0);
Data := Get_Driver (I1);
- -- Don't try to free driver of I1 as it is reconnected.
- Disconnect (I1);
+ if Get_Width (Data) > W then
+ Data := Build2_Extract (Ctxt, Data, Off, W);
+ -- Do not disconnect as this mux is certainly used somewhere else.
+ else
+ Disconnect (Sel);
+ -- Don't try to free driver of I0 as this is Prev_Val or a selection
+ -- of it.
+ Disconnect (I0);
+ -- Don't try to free driver of I1 as it is reconnected.
+ Disconnect (I1);
+ end if;
end Infere_FF_Mux;
-- A Mux2 with a logical loop and a clock has been found.
@@ -489,6 +514,8 @@ package body Netlists.Inference is
is
O : constant Net := Get_Output (Clock_Mux, 0);
Mux_Loc : constant Location_Type := Get_Location (Clock_Mux);
+ W : constant Width := Get_Width (Val);
+ Loop_Off : Uns32;
Data : Net;
Res : Net;
Sig : Instance;
@@ -505,7 +532,7 @@ package body Netlists.Inference is
-- 1. Remove the mux that creates the loop (will be replaced by the
-- dff).
- Infere_FF_Mux (Ctxt, Prev_Val, Off, Clock_Mux, Els, Data);
+ Infere_FF_Mux (Ctxt, Prev_Val, Off, W, Clock_Mux, Els, Data);
-- If the signal declaration has an initial value, get it.
Sig := Get_Net_Parent (Prev_Val);
@@ -526,6 +553,7 @@ package body Netlists.Inference is
-- mux. In theory, there can be many set/reset with a defined order.
Rst_Val := No_Net;
Rst := No_Net;
+ Loop_Off := Off;
declare
Mux : Instance;
Sel : Net;
@@ -534,6 +562,7 @@ package body Netlists.Inference is
Mux_Rst : Net;
Mux_Rst_Val : Net;
Prev_Input : Input;
+ Snk : Input;
begin
Prev_Mux := Clock_Mux;
@@ -544,15 +573,38 @@ package body Netlists.Inference is
-- Initially, the final output is not connected. So walk from the
-- clocked mux until reaching the final output.
while Last_Out /= Val loop
- if not Has_One_Connection (Last_Out)
- and then not Is_Const_Net (Last_Out)
- then
- -- TODO.
- raise Internal_Error;
- end if;
+ Snk := Get_First_Sink (Last_Out);
+
+ loop
+ Mux := Get_Input_Parent (Snk);
+ case Get_Id (Mux) is
+ when Id_Nop | Id_Mux2 =>
+ exit;
+ when Id_Extract =>
+ if Get_Param_Uns32 (Mux, 0) = Loop_Off then
+ -- Skip extract.
+ Last_Out := Get_Output (Mux, 0);
+ Mux := Get_Input_Parent (Get_First_Sink (Last_Out));
+ pragma Assert (Get_Id (Mux) = Id_Mux2);
+ Prev_Mux := No_Instance;
+ Loop_Off := 0;
+ exit;
+ end if;
+ when others =>
+ raise Internal_Error;
+ end case;
+ Snk := Get_Next_Sink (Snk);
+ end loop;
+
+ -- Search for the 'right' driver.
+ -- if not Has_One_Connection (Last_Out)
+ -- and then not Is_Const_Net (Last_Out)
+ -- then
+ -- -- TODO.
+ -- raise Internal_Error;
+ -- end if;
-- The parent must be a mux (it's a chain of muxes).
- Mux := Get_Input_Parent (Get_First_Sink (Last_Out));
if Get_Id (Mux) = Id_Nop then
-- Should have stopped.
exit;
@@ -917,7 +969,7 @@ package body Netlists.Inference is
end;
end if;
- Find_Longest_Loop (Val, Prev_Val, Last_Mux, Len);
+ Find_Longest_Loop (Val, Prev_Val, Off, Last_Mux, Len);
if Len <= 0 then
-- No logical loop or self assignment.
return Val;