From 15539c0af43cc63d99239e3b65d936955cde3226 Mon Sep 17 00:00:00 2001 From: Tristan Gingold Date: Wed, 15 Apr 2020 07:35:24 +0200 Subject: synth: rework edge handling to properly support falling edge. Fix #1227 --- src/synth/ghdlsynth_gates.h | 11 +++--- src/synth/netlists-builders.adb | 35 +++++++++++++------ src/synth/netlists-builders.ads | 6 ++-- src/synth/netlists-disp_vhdl.adb | 73 +++++++++++++++++++++++++++++----------- src/synth/netlists-gates.ads | 17 +++++----- src/synth/netlists-inference.adb | 19 +++++------ src/synth/synth-expr.adb | 13 +++---- src/synth/synth-oper.adb | 13 +++---- src/synth/synth-stmts.adb | 4 +-- 9 files changed, 118 insertions(+), 73 deletions(-) (limited to 'src') diff --git a/src/synth/ghdlsynth_gates.h b/src/synth/ghdlsynth_gates.h index fd45445a2..03bd87499 100644 --- a/src/synth/ghdlsynth_gates.h +++ b/src/synth/ghdlsynth_gates.h @@ -81,11 +81,12 @@ enum Module_Id { Id_Mem_Rd_Sync = 77, Id_Mem_Wr_Sync = 78, Id_Mem_Multiport = 79, - Id_Edge = 80, - Id_Assert = 81, - Id_Assume = 82, - Id_Cover = 83, - Id_Assert_Cover = 84, + Id_Posedge = 80, + Id_Negedge = 81, + Id_Assert = 82, + Id_Assume = 83, + Id_Cover = 84, + Id_Assert_Cover = 85, Id_Allconst = 90, Id_Anyconst = 91, Id_Allseq = 92, diff --git a/src/synth/netlists-builders.adb b/src/synth/netlists-builders.adb index ac1115af7..15d570a70 100644 --- a/src/synth/netlists-builders.adb +++ b/src/synth/netlists-builders.adb @@ -385,19 +385,22 @@ package body Netlists.Builders is Set_Ports_Desc (Res, Inputs (0 .. 1), Outputs (0 .. 0)); end Create_Memory_Modules; - procedure Create_Edge_Module (Ctxt : Context_Acc; - Res : out Module; - Name : Name_Id) - + procedure Create_Edge_Module (Ctxt : Context_Acc) is Outputs : Port_Desc_Array (0 .. 0); Inputs : Port_Desc_Array (0 .. 0); begin - Res := New_User_Module - (Ctxt.Design, New_Sname_Artificial (Name, No_Sname), Id_Edge, 1, 1, 0); + Ctxt.M_Posedge := New_User_Module + (Ctxt.Design, New_Sname_Artificial (Name_Posedge, No_Sname), + Id_Posedge, 1, 1, 0); Inputs := (0 => Create_Input ("i", 1)); Outputs := (0 => Create_Output ("o", 1)); - Set_Ports_Desc (Res, Inputs, Outputs); + Set_Ports_Desc (Ctxt.M_Posedge, Inputs, Outputs); + + Ctxt.M_Negedge := New_User_Module + (Ctxt.Design, New_Sname_Artificial (Name_Negedge, No_Sname), + Id_Negedge, 1, 1, 0); + Set_Ports_Desc (Ctxt.M_Negedge, Inputs, Outputs); end Create_Edge_Module; procedure Create_Mux_Modules (Ctxt : Context_Acc) @@ -707,7 +710,7 @@ package body Netlists.Builders is Create_Monadic_Module (Design, Res.M_Reduce (Id_Red_And), Get_Identifier ("red_and"), Id_Red_And); - Create_Edge_Module (Res, Res.M_Edge, Name_Edge); + Create_Edge_Module (Res); Create_Mux_Modules (Res); Create_Objects_Module (Res); @@ -932,19 +935,31 @@ package body Netlists.Builders is return Inst; end Build_Const_Log; - function Build_Edge (Ctxt : Context_Acc; Src : Net) return Net + function Build_Edge (Ctxt : Context_Acc; M : Module; Src : Net) return Net is pragma Assert (Get_Width (Src) = 1); Inst : Instance; O : Net; begin - Inst := New_Internal_Instance (Ctxt, Ctxt.M_Edge); + Inst := New_Internal_Instance (Ctxt, M); O := Get_Output (Inst, 0); pragma Assert (Get_Width (O) = 1); Connect (Get_Input (Inst, 0), Src); return O; end Build_Edge; + pragma Inline (Build_Edge); + + function Build_Posedge (Ctxt : Context_Acc; Src : Net) return Net is + begin + return Build_Edge (Ctxt, Ctxt.M_Posedge, Src); + end Build_Posedge; + + function Build_Negedge (Ctxt : Context_Acc; Src : Net) return Net is + begin + return Build_Edge (Ctxt, Ctxt.M_Negedge, Src); + end Build_Negedge; + function Build_Mux2 (Ctxt : Context_Acc; Sel : Net; I0, I1 : Net) return Net diff --git a/src/synth/netlists-builders.ads b/src/synth/netlists-builders.ads index 5c67384be..a58f1bba9 100644 --- a/src/synth/netlists-builders.ads +++ b/src/synth/netlists-builders.ads @@ -86,7 +86,8 @@ package Netlists.Builders is function Build_Const_Log (Ctxt : Context_Acc; W : Width) return Instance; - function Build_Edge (Ctxt : Context_Acc; Src : Net) return Net; + function Build_Posedge (Ctxt : Context_Acc; Src : Net) return Net; + function Build_Negedge (Ctxt : Context_Acc; Src : Net) return Net; function Build_Mux2 (Ctxt : Context_Acc; Sel : Net; @@ -222,7 +223,8 @@ private M_Const_Z : Module; M_Const_Bit : Module; M_Const_Log : Module; - M_Edge : Module; + M_Posedge : Module; + M_Negedge : Module; M_Mux2 : Module; M_Mux4 : Module; M_Nop : Module; diff --git a/src/synth/netlists-disp_vhdl.adb b/src/synth/netlists-disp_vhdl.adb index 172e9d921..8fdffbdc5 100644 --- a/src/synth/netlists-disp_vhdl.adb +++ b/src/synth/netlists-disp_vhdl.adb @@ -507,7 +507,8 @@ package body Netlists.Disp_Vhdl is return False; end Need_Signal; - type Conv_Type is (Conv_None, Conv_Slv, Conv_Unsigned, Conv_Signed); + type Conv_Type is + (Conv_None, Conv_Slv, Conv_Unsigned, Conv_Signed, Conv_Edge, Conv_Clock); procedure Disp_Net_Expr (N : Net; Inst : Instance; Conv : Conv_Type) is @@ -542,12 +543,27 @@ package body Netlists.Disp_Vhdl is Put ("signed'("); Disp_Constant_Inline (Net_Inst); Put (")"); + when Conv_Edge + | Conv_Clock => + -- Not expected: a constant is not an edge. + raise Internal_Error; end case; else case Conv is when Conv_None | Conv_Slv => Disp_Net_Name (N); + when Conv_Edge => + case Edge_Module_Id (Get_Id (Net_Inst)) is + when Id_Posedge => + Put ("rising_edge ("); + when Id_Negedge => + Put ("falling_edge ("); + end case; + Disp_Net_Name (Get_Input_Net (Net_Inst, 0)); + Put (")"); + when Conv_Clock => + Disp_Net_Name (Get_Input_Net (Net_Inst, 0)); when Conv_Unsigned => Put ("unsigned"); if Get_Width (N) = 1 then @@ -597,18 +613,25 @@ package body Netlists.Disp_Vhdl is if C = '\' then I := I + 1; -- Conversion (optional). - if S (I) = 'u' then - Conv := Conv_Unsigned; - I := I + 1; - elsif S (I) = 's' then - Conv := Conv_Signed; - I := I + 1; - elsif S (I) = 'f' then - Conv := Conv_Slv; - I := I + 1; - else - Conv := Conv_None; - end if; + case S (I) is + when 'u' => + Conv := Conv_Unsigned; + I := I + 1; + when 's' => + Conv := Conv_Signed; + I := I + 1; + when 'f' => + Conv := Conv_Slv; + I := I + 1; + when 'e' => + Conv := Conv_Edge; + I := I + 1; + when 'c' => + Conv := Conv_Clock; + I := I + 1; + when others => + Conv := Conv_None; + end case; Idx := Character'Pos (S (I + 1)) - Character'Pos ('0'); case S (I) is when 'o' => @@ -630,6 +653,9 @@ package body Netlists.Disp_Vhdl is Put_Uns32 (V); when Conv_Signed => Put_Int32 (To_Int32 (V)); + when Conv_Edge + | Conv_Clock => + raise Internal_Error; end case; when 'l' => pragma Assert (Idx = 0); @@ -691,6 +717,8 @@ package body Netlists.Disp_Vhdl is when Id_Mem_Wr_Sync => -- Clock S := Get_Input_Net (Port_Inst, 2); + -- Strip the edge. + S := Get_Input_Net (Get_Net_Parent (S), 0); Data_W := Get_Width (Get_Input_Net (Port_Inst, 4)); when Id_Mem_Rd => -- Address @@ -699,6 +727,8 @@ package body Netlists.Disp_Vhdl is when Id_Mem_Rd_Sync => -- Clock S := Get_Input_Net (Port_Inst, 2); + -- Strip the edge. + S := Get_Input_Net (Get_Net_Parent (S), 0); Data_W := Get_Width (Get_Output (Port_Inst, 1)); when Id_Memory | Id_Memory_Init => @@ -750,7 +780,7 @@ package body Netlists.Disp_Vhdl is case Get_Id (Port_Inst) is when Id_Mem_Wr_Sync => Disp_Template - (" if rising_edge(\i2) and (\fi3 = '1') then" & NL, + (" if \ei2 and (\fi3 = '1') then" & NL, Port_Inst); Disp_Template (" \o0 (", Mem); Disp_Template ("to_integer (\ui1)) := \i4;" & NL, Port_Inst); @@ -761,7 +791,7 @@ package body Netlists.Disp_Vhdl is Disp_Template ("(to_integer (\ui1));" & NL, Port_Inst); when Id_Mem_Rd_Sync => Disp_Template - (" if rising_edge(\i2) and (\fi3 = '1') then" & NL, + (" if \ei2 and (\fi3 = '1') then" & NL, Port_Inst); Disp_Template (" \o1 <= ", Port_Inst); Disp_Template ("\o0", Mem); @@ -969,19 +999,19 @@ package body Netlists.Disp_Vhdl is null; when Id_Adff | Id_Iadff => - Disp_Template (" process (\i0, \i2)" & NL & + Disp_Template (" process (\ci0, \i2)" & NL & " begin" & NL & " if \i2 = '1' then" & NL & " \o0 <= \i3;" & NL & - " elsif rising_edge (\i0) then" & NL & + " elsif \ei0 then" & NL & " \o0 <= \i1;" & NL & " end if;" & NL & " end process;" & NL, Inst); when Id_Dff | Id_Idff => - Disp_Template (" process (\i0)" & NL & + Disp_Template (" process (\ci0)" & NL & " begin" & NL & - " if rising_edge (\i0) then" & NL & + " if \ei0 then" & NL & " \o0 <= \i1;" & NL & " end if;" & NL & " end process;" & NL, Inst); @@ -1202,9 +1232,12 @@ package body Netlists.Disp_Vhdl is (" \o0 <= \i0; -- reduce and" & NL, Inst); end if; end; - when Id_Edge => + when Id_Posedge => Disp_Template (" \o0 <= '1' when rising_edge (\i0) else '0';" & NL, Inst); + when Id_Negedge => + Disp_Template + (" \o0 <= '1' when falling_edge (\i0) else '0';" & NL, Inst); when Id_Assert => Disp_Template (" \l0: assert \i0 = '1' severity error;" & NL, Inst); diff --git a/src/synth/netlists-gates.ads b/src/synth/netlists-gates.ads index 04920b224..8dcb65cce 100644 --- a/src/synth/netlists-gates.ads +++ b/src/synth/netlists-gates.ads @@ -275,19 +275,20 @@ package Netlists.Gates is -- Virtual gate to gather 2 dffs of a multiport memory. Id_Mem_Multiport : constant Module_Id := 79; - -- Positive/rising edge detector. This is a pseudo gate. - -- A negative edge detector can be made using by negating the clock before - -- the detector. - Id_Edge : constant Module_Id := 80; + -- Positive/rising edge and negative/falling edge detector. + -- These are pseudo gates. + Id_Posedge : constant Module_Id := 80; + Id_Negedge : constant Module_Id := 81; + subtype Edge_Module_Id is Module_Id range Id_Posedge .. Id_Negedge; -- Input signal must always be true. - Id_Assert : constant Module_Id := 81; - Id_Assume : constant Module_Id := 82; + Id_Assert : constant Module_Id := 82; + Id_Assume : constant Module_Id := 83; -- Input is true when a sequence is covered. - Id_Cover : constant Module_Id := 83; + Id_Cover : constant Module_Id := 84; -- Use to cover the precedent of an assertion. - Id_Assert_Cover : constant Module_Id := 84; + Id_Assert_Cover : constant Module_Id := 85; -- Formal gates. Id_Allconst : constant Module_Id := 90; diff --git a/src/synth/netlists-inference.adb b/src/synth/netlists-inference.adb index b0a660ec5..1155a6047 100644 --- a/src/synth/netlists-inference.adb +++ b/src/synth/netlists-inference.adb @@ -83,7 +83,7 @@ package body Netlists.Inference is Inst : constant Instance := Get_Net_Parent (N); begin case Get_Id (Inst) is - when Id_Edge => + when Edge_Module_Id => return True; when Id_And => -- Assume the condition is canonicalized, ie of the form: @@ -160,7 +160,7 @@ package body Netlists.Inference is Inst0 : constant Instance := Get_Net_Parent (N0); begin case Get_Id (Inst0) is - when Id_Edge => + when Edge_Module_Id => null; when Id_And => Extract_Clock_And (Ctxt, Inst0); @@ -175,7 +175,7 @@ package body Netlists.Inference is N3 : constant Net := Get_Driver (I3); Inst3 : constant Instance := Get_Net_Parent (N3); begin - if Get_Id (Inst3) = Id_Edge then + if Get_Id (Inst3) in Edge_Module_Id then declare Can_Rotate : constant Boolean := Has_One_Connection (N0); @@ -213,7 +213,7 @@ package body Netlists.Inference is Inst0 : constant Instance := Get_Net_Parent (N0); begin case Get_Id (Inst0) is - when Id_Edge => + when Edge_Module_Id => -- Swap inputs 0 and 1. declare I1 : constant Input := Get_Input (Inst, 0); @@ -236,7 +236,7 @@ package body Netlists.Inference is I3 : constant Input := Get_Input (Inst0, 0); N3 : constant Net := Get_Driver (I3); begin - if Get_Id (Get_Net_Parent (N3)) = Id_Edge then + if Get_Id (Get_Net_Parent (N3)) in Edge_Module_Id then declare Can_Rotate : constant Boolean := Has_One_Connection (N0); @@ -275,9 +275,8 @@ package body Netlists.Inference is Enable := No_Net; case Get_Id (Inst) is - when Id_Edge => - -- Get rid of the edge gate, just return the signal. - Clk := Get_Input_Net (Inst, 0); + when Edge_Module_Id => + Clk := N; when Id_And => -- Canonicalize conditions. Extract_Clock_And (Ctxt, Inst); @@ -287,12 +286,12 @@ package body Netlists.Inference is I0 : constant Net := Get_Input_Net (Inst, 0); Inst0 : constant Instance := Get_Net_Parent (I0); begin - if Get_Id (Inst0) = Id_Edge then + if Get_Id (Inst0) in Edge_Module_Id then -- INST is clearly not synthesizable (boolean operation on -- an edge). Will be removed at the end by -- remove_unused_instances. Do not remove it now as its -- output may be used by other nets. - Clk := Get_Input_Net (Inst0, 0); + Clk := I0; Enable := Get_Input_Net (Inst, 1); return; end if; diff --git a/src/synth/synth-expr.adb b/src/synth/synth-expr.adb index ef1d4cdab..a256cbe09 100644 --- a/src/synth/synth-expr.adb +++ b/src/synth/synth-expr.adb @@ -1510,19 +1510,19 @@ package body Synth.Expr is Clk := Get_Net (Synth_Name (Syn_Inst, Prefix)); if Get_Kind (Expr) /= Iir_Kind_Equality_Operator then Error_Msg_Synth (+Expr, "ill-formed clock-level, '=' expected"); - return Build_Edge (Build_Context, Clk); + return Build_Posedge (Build_Context, Clk); end if; Imp := Get_Implementation (Expr); if Get_Implicit_Definition (Imp) /= Iir_Predefined_Enum_Equality then Error_Msg_Synth (+Expr, "ill-formed clock-level, '=' expected"); - return Build_Edge (Build_Context, Clk); + return Build_Posedge (Build_Context, Clk); end if; Left := Get_Left (Expr); Right := Get_Right (Expr); if Get_Kind (Right) /= Iir_Kind_Character_Literal then Error_Msg_Synth (+Expr, "ill-formed clock-level, '0' or '1' expected"); - return Build_Edge (Build_Context, Clk); + return Build_Posedge (Build_Context, Clk); end if; Lit := Get_Named_Entity (Right); if Lit = Vhdl.Std_Package.Bit_0 @@ -1542,10 +1542,11 @@ package body Synth.Expr is Error_Msg_Synth (+Left, "clock signal name doesn't match"); end if; - if not Posedge then - Clk := Build_Monadic (Build_Context, Id_Not, Clk); + if Posedge then + return Build_Posedge (Build_Context, Clk); + else + return Build_Negedge (Build_Context, Clk); end if; - return Build_Edge (Build_Context, Clk); end Extract_Clock_Level; -- Try to match: clk'event and clk = X diff --git a/src/synth/synth-oper.adb b/src/synth/synth-oper.adb index 4845c6237..819331e39 100644 --- a/src/synth/synth-oper.adb +++ b/src/synth/synth-oper.adb @@ -1500,22 +1500,17 @@ package body Synth.Oper is case Def is when Iir_Predefined_Ieee_1164_Rising_Edge => declare - Clk : Net; Edge : Net; begin - Clk := Get_Net (L); - Edge := Build_Edge (Ctxt, Clk); - return Create_Value_Net (Edge, Boolean_Type); + Edge := Build_Posedge (Ctxt, Get_Net (L)); + return Create_Value_Net (Edge, Res_Typ); end; when Iir_Predefined_Ieee_1164_Falling_Edge => declare - Clk : Net; Edge : Net; begin - Clk := Get_Net (L); - Clk := Build_Monadic (Ctxt, Id_Not, Clk); - Edge := Build_Edge (Ctxt, Clk); - return Create_Value_Net (Edge, Boolean_Type); + Edge := Build_Negedge (Ctxt, Get_Net (L)); + return Create_Value_Net (Edge, Res_Typ); end; when Iir_Predefined_Ieee_1164_Scalar_Is_X | Iir_Predefined_Ieee_1164_Vector_Is_X => diff --git a/src/synth/synth-stmts.adb b/src/synth/synth-stmts.adb index e1d25384b..d994bc0ff 100644 --- a/src/synth/synth-stmts.adb +++ b/src/synth/synth-stmts.adb @@ -2934,14 +2934,12 @@ package body Synth.Stmts is -- Check the clock is an edge and extract it. Clk_Inst := Get_Net_Parent (Clk); - if Get_Id (Clk_Inst) /= Id_Edge then + if Get_Id (Clk_Inst) not in Edge_Module_Id then Error_Msg_Synth (+Stmt, "clock is not an edge"); Next_States := No_Net; return; end if; - Clk := Get_Input_Net (Clk_Inst, 0); - -- build idff States := Build_Idff (Build_Context, Clk, No_Net, Init); -- cgit v1.2.3