aboutsummaryrefslogtreecommitdiffstats
path: root/src/synth/synth-inference.adb
diff options
context:
space:
mode:
authorTristan Gingold <tgingold@free.fr>2019-10-08 06:28:03 +0200
committerTristan Gingold <tgingold@free.fr>2019-10-08 06:28:24 +0200
commit5c029fecafa67b4d47ce904a9ce8c52a07e479f7 (patch)
treeccfa1ea63084bb937b013dac19c9c2709b463f1f /src/synth/synth-inference.adb
parent7b2ccbe3cb679eb16bc5149a4ff282c9bc76dc43 (diff)
downloadghdl-5c029fecafa67b4d47ce904a9ce8c52a07e479f7.tar.gz
ghdl-5c029fecafa67b4d47ce904a9ce8c52a07e479f7.tar.bz2
ghdl-5c029fecafa67b4d47ce904a9ce8c52a07e479f7.zip
synth: infere_ff: handle pre-enable. Fix #964
Diffstat (limited to 'src/synth/synth-inference.adb')
-rw-r--r--src/synth/synth-inference.adb86
1 files changed, 63 insertions, 23 deletions
diff --git a/src/synth/synth-inference.adb b/src/synth/synth-inference.adb
index 3dd919404..643b2d124 100644
--- a/src/synth/synth-inference.adb
+++ b/src/synth/synth-inference.adb
@@ -221,19 +221,16 @@ package body Synth.Inference is
end if;
end Check_FF_Else;
- -- LAST_MUX is the mux whose input 0 is the loop.
+ -- LAST_MUX is the mux whose input 0 is the loop and clock for selector.
procedure Infere_FF (Ctxt : Context_Acc;
Wid : Wire_Id;
Prev_Val : Net;
Off : Uns32;
Last_Mux : Instance;
Clk : Net;
- Enable : Net;
+ Clk_Enable : Net;
Stmt : Source.Syn_Src)
is
- Sel : constant Input := Get_Mux2_Sel (Last_Mux);
- I0 : constant Input := Get_Mux2_I0 (Last_Mux);
- I1 : constant Input := Get_Mux2_I1 (Last_Mux);
O : constant Net := Get_Output (Last_Mux, 0);
Data : Net;
Res : Net;
@@ -241,19 +238,27 @@ package body Synth.Inference is
Init : Net;
Rst : Net;
Rst_Val : Net;
+ Enable : Net;
begin
-- Create and return the DFF.
-- 1. Remove the mux that creates the loop (will be replaced by the
-- dff).
- Disconnect (Sel);
- -- There must be no 'else' part for clock expression.
- Check_FF_Else (Get_Driver (I0), Prev_Val, Off);
- -- Don't try to free driver of I0 as this is Prev_Val.
- Disconnect (I0);
- Data := Get_Driver (I1);
- -- Don't try to free driver of I1 as it is reconnected.
- Disconnect (I1);
+ declare
+ Sel : constant Input := Get_Mux2_Sel (Last_Mux);
+ I0 : constant Input := Get_Mux2_I0 (Last_Mux);
+ I1 : constant Input := Get_Mux2_I1 (Last_Mux);
+ begin
+ Disconnect (Sel);
+ -- There must be no 'else' part for clock expression.
+ Check_FF_Else (Get_Driver (I0), Prev_Val, Off);
+ -- 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);
+ end;
-- If the signal declaration has an initial value, get it.
Sig := Get_Net_Parent (Prev_Val);
@@ -264,6 +269,8 @@ package body Synth.Inference is
Init := No_Net;
end if;
+ Enable := Clk_Enable;
+
-- 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;
@@ -272,6 +279,7 @@ package body Synth.Inference is
Mux : Instance;
Sel : Net;
Last_Out : Net;
+ Mux_Not_Rst : Net;
Mux_Rst : Net;
Mux_Rst_Val : Net;
begin
@@ -302,21 +310,53 @@ package body Synth.Inference is
Last_Out := Get_Output (Mux, 0);
- if Rst = No_Net then
- -- Remove the last mux. Dedicated inputs on the FF are used.
+ if Mux_Rst_Val = Prev_Val then
+ -- The mux is like an enable. Like in this example, q2 is not
+ -- assigned when RST is true:
+ -- if rst then
+ -- q1 <= '0';
+ -- elsif rising_edge(clk) then
+ -- q2 <= d2;
+ -- q1 <= d1;
+ -- end if;
+
+ -- Remove the mux
Disconnect (Get_Mux2_I0 (Mux));
Disconnect (Get_Mux2_I1 (Mux));
Disconnect (Get_Mux2_Sel (Mux));
- Redirect_Inputs (Last_Out, Mux_Rst_Val);
- Free_Instance (Mux);
-
- Rst := Mux_Rst;
- Rst_Val := Mux_Rst_Val;
- Last_Out := Mux_Rst_Val;
+ -- Add the negation of the condition to the enable signal.
+ -- Negate the condition for the current reset.
+ Mux_Not_Rst := Build_Monadic (Ctxt, Id_Not, Mux_Rst);
+ if Rst /= No_Net then
+ Rst := Build_Dyadic (Ctxt, Id_And, Rst, Mux_Not_Rst);
+ end if;
+ if Enable = No_Net then
+ Enable := Mux_Not_Rst;
+ else
+ Enable := Build_Dyadic (Ctxt, Id_And, Enable, Mux_Not_Rst);
+ end if;
else
- Rst := Build_Dyadic (Ctxt, Id_Or, Mux_Rst, Rst);
- Rst_Val := Last_Out;
+ -- Assume this is a reset value.
+ -- FIXME: check for no logical loop.
+
+ if Rst = No_Net then
+ -- Remove the last mux. Dedicated inputs on the FF
+ -- are used.
+ Disconnect (Get_Mux2_I0 (Mux));
+ Disconnect (Get_Mux2_I1 (Mux));
+ Disconnect (Get_Mux2_Sel (Mux));
+
+ Redirect_Inputs (Last_Out, Mux_Rst_Val);
+ Free_Instance (Mux);
+
+ Rst := Mux_Rst;
+ Rst_Val := Mux_Rst_Val;
+ Last_Out := Mux_Rst_Val;
+ else
+ Rst := Build_Dyadic (Ctxt, Id_Or, Mux_Rst, Rst);
+ Rst_Val := Last_Out;
+ end if;
end if;
end loop;
end;