diff options
author | Tristan Gingold <tgingold@free.fr> | 2019-04-16 19:03:15 +0200 |
---|---|---|
committer | Tristan Gingold <tgingold@free.fr> | 2019-04-16 19:03:15 +0200 |
commit | 93570afad886f29339ef6a2c3eca6e9fcaa6a234 (patch) | |
tree | c8539f99c77f561263548922da6d34abe911e4b0 | |
parent | 6b71fbf805d5534f68b32f3248d8aecf65bb00ec (diff) | |
download | ghdl-93570afad886f29339ef6a2c3eca6e9fcaa6a234.tar.gz ghdl-93570afad886f29339ef6a2c3eca6e9fcaa6a234.tar.bz2 ghdl-93570afad886f29339ef6a2c3eca6e9fcaa6a234.zip |
synth: support async reset in inference.
-rw-r--r-- | src/synth/synth-environment.adb | 3 | ||||
-rw-r--r-- | src/synth/synth-inference.adb | 209 |
2 files changed, 117 insertions, 95 deletions
diff --git a/src/synth/synth-environment.adb b/src/synth/synth-environment.adb index e02cf12d3..fd91f1f2e 100644 --- a/src/synth/synth-environment.adb +++ b/src/synth/synth-environment.adb @@ -50,6 +50,7 @@ package body Synth.Environment is Nbr => 0)); end Push_Phi; + -- Get list of assignments for this current block. procedure Pop_Phi (Phi : out Phi_Type) is Cur_Phi : constant Phi_Id := Current_Phi; @@ -74,6 +75,7 @@ package body Synth.Environment is Asgn : Assign; begin Pop_Phi (Phi); + Asgn := Phi.First; while Asgn /= No_Assign loop declare @@ -230,6 +232,7 @@ package body Synth.Environment is end if; end Get_Last_Assigned_Value; + -- Add muxes for two lists T and F of assignments. procedure Merge_Phis (Ctxt : Builders.Context_Acc; Sel : Net; T, F : Phi_Type) diff --git a/src/synth/synth-inference.adb b/src/synth/synth-inference.adb index 1a7b92a35..726d67ec5 100644 --- a/src/synth/synth-inference.adb +++ b/src/synth/synth-inference.adb @@ -71,13 +71,6 @@ package body Synth.Inference is -- This is a memorizing element as there is a loop. It is an asynchronous -- reset as Q is forced to '0' when RST is asserted. - type Mux_Info_Type is record - Mux : Instance; - Chain : Port_Nbr; - end record; - - type Mux_Info_Arr is array (Natural range <>) of Mux_Info_Type; - -- 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. -- RES is the last mux in the chain, DIST the number of mux in the chain. @@ -180,113 +173,139 @@ package body Synth.Inference is return Val; end if; - -- Create the array of mux till the last one. - -- Find the one with clock edge. - -- If none -> latch (not yet supported) - -- If found -> previous mux2 (if any) are either asynch set/reset or - -- enable. declare - Mux_Info : Mux_Info_Arr (1 .. Len); + 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; + Clk : Net; + Enable : Net; + Res : Net; + Sig : Instance; + Init : Net; + Init_Input : Input; + Rst : Net; + Rst_Val : Net; begin - -- Fill array. - declare - Mux : Instance; - O : Net; - begin - -- Start with the last mux. - Mux := Last_Mux; - for I in reverse Mux_Info'Range loop - -- The chain of mux consists only of muxes! - pragma Assert (Get_Id (Mux) = Id_Mux2); + Extract_Clock (Get_Driver (Sel), Clk, Enable); + if Clk = No_Net then + -- No clock -> latch + raise Internal_Error; + else + -- Create and return the DFF. + Disconnect (Sel); + if Get_Driver (I0) /= Prev_Val then + -- There must be no 'else' part for clock expression. + raise Internal_Error; + end if; + -- 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); + if Enable /= No_Net then + Data := Build_Mux2 (Ctxt, Enable, Prev_Val, Data); + end if; + + -- If the signal declaration has an initial value, move it + -- to the dff. + Sig := Get_Parent (Prev_Val); + if Get_Id (Get_Module (Sig)) = Id_Isignal then + Init_Input := Get_Input (Sig, 1); + Init := Get_Driver (Init_Input); + Disconnect (Init_Input); + else + Init := No_Net; + end if; - Mux_Info (I) := (Mux => Mux, Chain => 0); - exit when I = Mux_Info'First; - -- The next mux is connected to the output. - O := Get_Output (Mux, 0); - pragma Assert (Has_One_Connection (O)); - Mux := Get_Parent (Get_First_Sink (O)); - end loop; - end; + Rst_Val := No_Net; + Rst := No_Net; - -- Classify. - for I in Mux_Info'Range loop declare - Mi : Mux_Info_Type renames Mux_Info (I); - Sel : constant Input := Get_Mux2_Sel (Mi.Mux); - I0 : constant Input := Get_Mux2_I0 (Mi.Mux); - I1 : constant Input := Get_Mux2_I1 (Mi.Mux); - Data : Net; - Clk : Net; - Enable : Net; - Res : Net; - Sig : Instance; - Init : Net; - Init_Input : Input; + Mux : Instance; + Sel : Net; + Last_Out : Net; + Mux_Rst : Net; + Mux_Rst_Val : Net; begin - Extract_Clock (Get_Driver (Sel), Clk, Enable); - if Clk = No_Net then - -- Enable or async reset/set. - if Get_Driver (I0) = Prev_Val then - -- Enable - raise Internal_Error; - elsif Get_Driver (I1) = Prev_Val then - -- /Enable - raise Internal_Error; - else - -- Set or reset. - -- The value must be a constant. + Last_Out := O; + + while Is_Connected (Last_Out) loop + if not Has_One_Connection (Last_Out) then + -- TODO. raise Internal_Error; end if; - else - -- Create and return the DFF. - Disconnect (Sel); - if Get_Driver (I0) /= Prev_Val then - -- There must be no 'else' part for clock expression. + + Mux := Get_Parent (Get_First_Sink (Last_Out)); + if Get_Id (Mux) /= Id_Mux2 then raise Internal_Error; end if; - -- 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); - if Enable /= No_Net then - Data := Build_Mux2 (Ctxt, Enable, Prev_Val, Data); - end if; - -- If the signal declaration has an initial value, move it - -- to the dff. - Sig := Get_Parent (Prev_Val); - if Get_Id (Get_Module (Sig)) = Id_Isignal then - Init_Input := Get_Input (Sig, 1); - Init := Get_Driver (Init_Input); - Disconnect (Init_Input); + Sel := Get_Driver (Get_Mux2_Sel (Mux)); + if Get_Driver (Get_Mux2_I0 (Mux)) = O then + Mux_Rst_Val := Get_Driver (Get_Mux2_I1 (Mux)); + Mux_Rst := Sel; + elsif Get_Driver (Get_Mux2_I1 (Mux)) = O then + Mux_Rst_Val := Get_Driver (Get_Mux2_I0 (Mux)); + Mux_Rst := Build_Monadic (Ctxt, Id_Not, Sel); else - Init := No_Net; + -- Cannot happen. + raise Internal_Error; end if; - if Init /= No_Net then - Res := Build_Idff (Ctxt, Clk, D => Data, Init => Init); + Last_Out := Get_Output (Mux, 0); + + if Rst = No_Net then + -- Remove the last 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; else - Res := Build_Dff (Ctxt, Clk, D => Data); + Rst := Build_Dyadic (Ctxt, Id_Or, Mux_Rst, Rst); + Rst_Val := Last_Out; end if; + end loop; + end; - -- The output of the mux may be read later in the process, - -- like this: - -- if clk'event and clk = '1' then - -- d := i + 1; - -- end if; - -- d1 := d + 1; - -- So connections to the mux output are redirected to dff - -- output. - Redirect_Inputs (Get_Output (Mi.Mux, 0), Res); - - Free_Instance (Mi.Mux); - return Res; + if Rst = No_Net then + pragma Assert (Rst_Val = No_Net); + if Init /= No_Net then + Res := Build_Idff (Ctxt, Clk, D => Data, Init => Init); + else + Res := Build_Dff (Ctxt, Clk, D => Data); end if; - end; - end loop; + else + if Init /= No_Net then + Res := Build_Iadff (Ctxt, Clk, D => Data, + Rst => Rst, Rst_Val => Rst_Val, + Init => Init); + else + Res := Build_Adff (Ctxt, Clk, D => Data, + Rst => Rst, Rst_Val => Rst_Val); + end if; + end if; + + -- The output of the mux may be read later in the process, + -- like this: + -- if clk'event and clk = '1' then + -- d := i + 1; + -- end if; + -- d1 := d + 1; + -- So connections to the mux output are redirected to dff + -- output. + Redirect_Inputs (O, Res); + + Free_Instance (Last_Mux); + return Res; + end if; end; - raise Internal_Error; end Infere; end Synth.Inference; |