diff options
author | Tristan Gingold <tgingold@free.fr> | 2020-05-09 11:21:33 +0200 |
---|---|---|
committer | Tristan Gingold <tgingold@free.fr> | 2020-05-09 16:31:19 +0200 |
commit | c9d2cccb38b985783108f187398a0a0af9f6ab62 (patch) | |
tree | 684fdf84839136d4f94609392c847bfb4eb56f23 /src/synth | |
parent | 1a65ac6bbbaf6cdaf1ea93c0c46f2e97e12e9dcc (diff) | |
download | ghdl-c9d2cccb38b985783108f187398a0a0af9f6ab62.tar.gz ghdl-c9d2cccb38b985783108f187398a0a0af9f6ab62.tar.bz2 ghdl-c9d2cccb38b985783108f187398a0a0af9f6ab62.zip |
synth-stmts: use pmux to implement case statements.
Diffstat (limited to 'src/synth')
-rw-r--r-- | src/synth/netlists-inference.adb | 10 | ||||
-rw-r--r-- | src/synth/synth-stmts.adb | 254 |
2 files changed, 134 insertions, 130 deletions
diff --git a/src/synth/netlists-inference.adb b/src/synth/netlists-inference.adb index 7016f1f57..6ba244888 100644 --- a/src/synth/netlists-inference.adb +++ b/src/synth/netlists-inference.adb @@ -709,9 +709,13 @@ package body Netlists.Inference is 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; + case Get_Id (Inst) is + when Mux_Module_Id + | Id_Pmux => + null; + when others => + return False; + end case; -- Add to T (if not already). Get (T, Inst, Inst); diff --git a/src/synth/synth-stmts.adb b/src/synth/synth-stmts.adb index f9fe69cdf..0686cd39b 100644 --- a/src/synth/synth-stmts.adb +++ b/src/synth/synth-stmts.adb @@ -57,7 +57,6 @@ with Netlists.Folds; use Netlists.Folds; with Netlists.Gates; use Netlists.Gates; with Netlists.Utils; use Netlists.Utils; with Netlists.Locations; use Netlists.Locations; -with Netlists.Butils; use Netlists.Butils; package body Synth.Stmts is procedure Synth_Sequential_Statements @@ -790,41 +789,32 @@ package body Synth.Stmts is end if; end Synth_If_Statement; - -- EXPR is a choice, so a locally static literal. - function Convert_To_Uns64 (Syn_Inst : Synth_Instance_Acc; Expr : Node) - return Uns64 - is - Expr_Val : Valtyp; - Vec : Logvec_Array (0 .. 1); - Off : Uns32; - Has_Zx : Boolean; - begin - Expr_Val := Synth_Expression_With_Basetype (Syn_Inst, Expr); - Off := 0; - Has_Zx := False; - Vec := (others => (0, 0)); - Value2logvec (Get_Memtyp (Expr_Val), 0, Expr_Val.Typ.W, - Vec, Off, Has_Zx); - if Has_Zx then - Error_Msg_Synth (+Expr, "meta-values never match"); - end if; - return Uns64 (Vec (0).Val) or Shift_Left (Uns64 (Vec (1).Val), 32); - end Convert_To_Uns64; - type Alternative_Index is new Int32; - type Choice_Data_Type is record - -- Value of the choice - Val : Uns64; - - -- Corresponding alternative - Alt : Alternative_Index; - end record; - - type Choice_Data_Array is array (Natural range <>) of Choice_Data_Type; - type Choice_Data_Array_Acc is access Choice_Data_Array; - procedure Free_Choice_Data_Array is new Ada.Unchecked_Deallocation - (Choice_Data_Array, Choice_Data_Array_Acc); + function Synth_Choice (Syn_Inst : Synth_Instance_Acc; + Sel : Net; + Choice_Typ : Type_Acc; + Choice : Node) return Net + is + Ctxt : constant Context_Acc := Get_Build (Syn_Inst); + Expr_Val : Valtyp; + Cond : Net; + begin + case Get_Kind (Choice) is + when Iir_Kind_Choice_By_Expression => + Expr_Val := Synth_Expression_With_Basetype + (Syn_Inst, Get_Choice_Expression (Choice)); + Expr_Val := Synth_Subtype_Conversion + (Ctxt, Expr_Val, Choice_Typ, False, Choice); + Cond := Build_Compare (Ctxt, Id_Eq, Sel, Get_Net (Ctxt, Expr_Val)); + Set_Location (Cond, Choice); + when Iir_Kind_Choice_By_Others => + raise Internal_Error; + when others => + raise Internal_Error; + end case; + return Cond; + end Synth_Choice; type Alternative_Data_Type is record Asgns : Seq_Assign; @@ -920,23 +910,19 @@ package body Synth.Stmts is use Vhdl.Sem_Expr; Ctxt : constant Context_Acc := Get_Build (C.Inst); - Expr : constant Node := Get_Expression (Stmt); Choices : constant Node := Get_Case_Statement_Alternative_Chain (Stmt); Choice : Node; Case_Info : Choice_Info_Type; - Annex_Arr : Annex_Array_Acc; -- Array of alternatives Alts : Alternative_Data_Acc; Alt_Idx : Alternative_Index; Others_Alt_Idx : Alternative_Index; - -- Array of choices. Contains tuple of (Value, Alternative). - Choice_Data : Choice_Data_Array_Acc; - Choice_Idx : Natural; + Choice_Idx : Nat32; + Nbr_Choices : Nat32; - Case_El : Case_Element_Array_Acc; Pasgns : Seq_Assign_Value_Array_Acc; Nets : Net_Array_Acc; @@ -963,24 +949,33 @@ package body Synth.Stmts is -- Count choices and alternatives. Count_Choices (Case_Info, Choices); - Fill_Choices_Array (Case_Info, Choices); + --Fill_Choices_Array (Case_Info, Choices); -- Allocate structures. -- Because there is no 1-1 link between choices and alternatives, -- create an array for the choices and an array for the alternatives. Alts := new Alternative_Data_Array (1 .. Alternative_Index (Case_Info.Nbr_Alternatives)); - Choice_Data := new Choice_Data_Array (1 .. Case_Info.Nbr_Choices); - Annex_Arr := new Annex_Array (1 .. Case_Info.Nbr_Choices); - Case_Info.Annex_Arr := Annex_Arr; - -- Synth statements, extract choice value. + -- Compute number of non-default alternatives. + Nbr_Choices := Nat32 (Case_Info.Nbr_Alternatives); + if Case_Info.Others_Choice /= Null_Node then + Nbr_Choices := Nbr_Choices - 1; + end if; + + Nets := new Net_Array (1 .. Int32 (Alts'Last)); + + Sel_Net := Get_Net (Ctxt, Sel); + + -- Synth statements and keep list of assignments. + -- Also synth choices. Alt_Idx := 0; Others_Alt_Idx := 0; Choice_Idx := 0; Choice := Choices; while Is_Valid (Choice) loop if not Get_Same_Alternative_Flag (Choice) then + -- A new sequence of statements. Alt_Idx := Alt_Idx + 1; declare @@ -993,28 +988,33 @@ package body Synth.Stmts is end; end if; - case Get_Kind (Choice) is - when Iir_Kind_Choice_By_Expression => - Choice_Idx := Choice_Idx + 1; - Annex_Arr (Choice_Idx) := Int32 (Choice_Idx); - Choice_Data (Choice_Idx) := - (Val => Convert_To_Uns64 (C.Inst, - Get_Choice_Expression (Choice)), - Alt => Alt_Idx); + case Iir_Kinds_Case_Choice (Get_Kind (Choice)) is + when Iir_Kind_Choice_By_Expression + | Iir_Kind_Choice_By_Range => + declare + N : Net; + begin + N := Synth_Choice (C.Inst, Sel_Net, Sel.Typ, Choice); + if not Get_Same_Alternative_Flag (Choice) then + Choice_Idx := Choice_Idx + 1; + else + N := Build_Dyadic (Ctxt, Id_Or, Nets (Choice_Idx), N); + Set_Location (N, Choice); + end if; + Nets (Choice_Idx) := N; + end; when Iir_Kind_Choice_By_Others => Others_Alt_Idx := Alt_Idx; - when others => - raise Internal_Error; end case; Choice := Get_Chain (Choice); end loop; - pragma Assert (Choice_Idx = Choice_Data'Last); + pragma Assert (Choice_Idx = Nbr_Choices); - -- Sort by order. - if Get_Kind (Get_Type (Expr)) in Iir_Kinds_Discrete_Type_Definition then - Sort_Discrete_Choices (Case_Info); + -- Create the one-hot vector. + if Nbr_Choices = 0 then + Sel_Net := No_Net; else - Sort_String_Choices (Case_Info); + Sel_Net := Build2_Concat (Ctxt, Nets (1 .. Nbr_Choices)); end if; -- Create list of wire_id, sort it. @@ -1026,21 +1026,16 @@ package body Synth.Stmts is -- Associate each choice with the assign node -- For each wire_id: -- Build mux2/mux4 tree (group by 4) - Case_El := new Case_Element_Array (1 .. Case_Info.Nbr_Choices); - Pasgns := new Seq_Assign_Value_Array (1 .. Int32 (Alts'Last)); - Nets := new Net_Array (1 .. Int32 (Alts'Last)); - - Sel_Net := Get_Net (Ctxt, Sel); -- For each wire, compute the result. for I in Wires'Range loop declare Wi : constant Wire_Id := Wires (I); Last_Val : Net; + Res_Inst : Instance; Res : Net; Default : Net; - Ch : Natural; Min_Off, Off : Uns32; Wd : Width; List : Partial_Assign_List; @@ -1083,6 +1078,7 @@ package body Synth.Stmts is exit when Off = Uns32'Last and Wd = Width'Last; -- If a branch has no value, use the value before the case. + -- Also do it for the default value! Last_Val := No_Net; for I in Nets'Range loop if Nets (I) = No_Net then @@ -1094,24 +1090,26 @@ package body Synth.Stmts is end if; end loop; - -- Build the map between choices and values. - for J in Annex_Arr'Range loop - Ch := Natural (Annex_Arr (J)); - Case_El (J) := - (Sel => Choice_Data (Ch).Val, - Val => Nets (Int32 (Choice_Data (Ch).Alt))); - end loop; - -- Extract default value (for missing alternative). if Others_Alt_Idx /= 0 then Default := Nets (Int32 (Others_Alt_Idx)); else - Default := No_Net; + Default := Build_Const_X (Ctxt, Wd); end if; - -- Generate the muxes tree. - Synth_Case (Ctxt, Sel_Net, Case_El.all, Default, Res, - Get_Location (Expr)); + if Nbr_Choices = 0 then + Res := Default; + else + Res := Build_Pmux (Ctxt, Sel_Net, Default); + Res_Inst := Get_Net_Parent (Res); + Set_Location (Res_Inst, Get_Location (Stmt)); + + for I in 1 .. Nbr_Choices loop + Connect + (Get_Input (Res_Inst, Port_Nbr (2 + I - Nets'First)), + Nets (I)); + end loop; + end if; Partial_Assign_Append (List, New_Partial_Assign (Res, Off)); Min_Off := Off + Wd; @@ -1123,10 +1121,7 @@ package body Synth.Stmts is end loop; -- free. - Free_Case_Element_Array (Case_El); Free_Wire_Id_Array (Wires); - Free_Choice_Data_Array (Choice_Data); - Free_Annex_Array (Annex_Arr); Free_Alternative_Data_Array (Alts); Free_Seq_Assign_Value_Array (Pasgns); Free_Net_Array (Nets); @@ -1259,7 +1254,6 @@ package body Synth.Stmts is Targ_Type : Type_Acc; Case_Info : Choice_Info_Type; - Annex_Arr : Annex_Array_Acc; -- Array of alternatives Alts : Alternative_Data_Acc; @@ -1267,10 +1261,11 @@ package body Synth.Stmts is Others_Alt_Idx : Alternative_Index; -- Array of choices. Contains tuple of (Value, Alternative). - Choice_Data : Choice_Data_Array_Acc; - Choice_Idx : Natural; + Choice_Idx : Nat32; + Nbr_Choices : Nat32; + + Nets : Net_Array_Acc; - Case_El : Case_Element_Array_Acc; Sel : Valtyp; Sel_Net : Net; @@ -1280,19 +1275,25 @@ package body Synth.Stmts is -- Create a net for the expression. Sel := Synth_Expression_With_Basetype (Syn_Inst, Expr); + Sel_Net := Get_Net (Ctxt, Sel); -- Count choices and alternatives. Count_Choices (Case_Info, Choices); - Fill_Choices_Array (Case_Info, Choices); + -- Fill_Choices_Array (Case_Info, Choices); -- Allocate structures. -- Because there is no 1-1 link between choices and alternatives, -- create an array for the choices and an array for the alternatives. Alts := new Alternative_Data_Array (1 .. Alternative_Index (Case_Info.Nbr_Alternatives)); - Choice_Data := new Choice_Data_Array (1 .. Case_Info.Nbr_Choices); - Annex_Arr := new Annex_Array (1 .. Case_Info.Nbr_Choices); - Case_Info.Annex_Arr := Annex_Arr; + + -- Compute number of non-default alternatives. + Nbr_Choices := Nat32 (Case_Info.Nbr_Alternatives); + if Case_Info.Others_Choice /= Null_Node then + Nbr_Choices := Nbr_Choices - 1; + end if; + + Nets := new Net_Array (1 .. Nbr_Choices); -- Synth statements, extract choice value. Alt_Idx := 0; @@ -1308,69 +1309,68 @@ package body Synth.Stmts is (Syn_Inst, Get_Associated_Chain (Choice), Targ_Type)); end if; - case Get_Kind (Choice) is - when Iir_Kind_Choice_By_Expression => - Choice_Idx := Choice_Idx + 1; - Annex_Arr (Choice_Idx) := Int32 (Choice_Idx); - Choice_Data (Choice_Idx) := - (Val => Convert_To_Uns64 (Syn_Inst, - Get_Choice_Expression (Choice)), - Alt => Alt_Idx); + case Iir_Kinds_Case_Choice (Get_Kind (Choice)) is + when Iir_Kind_Choice_By_Expression + | Iir_Kind_Choice_By_Range => + declare + N : Net; + begin + N := Synth_Choice (Syn_Inst, Sel_Net, Sel.Typ, Choice); + if not Get_Same_Alternative_Flag (Choice) then + Choice_Idx := Choice_Idx + 1; + else + N := Build_Dyadic (Ctxt, Id_Or, Nets (Choice_Idx), N); + Set_Location (N, Choice); + end if; + Nets (Choice_Idx) := N; + end; when Iir_Kind_Choice_By_Others => Others_Alt_Idx := Alt_Idx; - when others => - raise Internal_Error; end case; Choice := Get_Chain (Choice); end loop; - pragma Assert (Choice_Idx = Choice_Data'Last); + pragma Assert (Choice_Idx = Nbr_Choices); - -- Sort by order. - if Get_Kind (Get_Type (Expr)) in Iir_Kinds_Discrete_Type_Definition then - Sort_Discrete_Choices (Case_Info); + -- Create the one-hot vector. + if Nbr_Choices = 0 then + Sel_Net := No_Net; else - Sort_String_Choices (Case_Info); + Sel_Net := Build2_Concat (Ctxt, Nets (1 .. Nbr_Choices)); end if; - -- Associate each choice with the assign node - -- For each wire_id: - -- Build mux2/mux4 tree (group by 4) - Case_El := new Case_Element_Array (1 .. Case_Info.Nbr_Choices); - - Sel_Net := Get_Net (Ctxt, Sel); - declare Res : Net; + Res_Inst : Instance; Default : Net; - C : Natural; begin - -- Build the map between choices and values. - for J in Annex_Arr'Range loop - C := Natural (Annex_Arr (J)); - Case_El (J) := (Sel => Choice_Data (C).Val, - Val => Alts (Choice_Data (C).Alt).Val); - end loop; - -- Extract default value (for missing alternative). if Others_Alt_Idx /= 0 then Default := Alts (Others_Alt_Idx).Val; else - Default := No_Net; + Default := Build_Const_X (Ctxt, Targ_Type.W); + end if; + + if Nbr_Choices = 0 then + Res := Default; + else + Res := Build_Pmux (Ctxt, Sel_Net, Default); + Res_Inst := Get_Net_Parent (Res); + Set_Location (Res_Inst, Get_Location (Stmt)); + + for I in 1 .. Nbr_Choices loop + Connect + (Get_Input (Res_Inst, Port_Nbr (2 + I - Nets'First)), + Alts (Alternative_Index (I)).Val); + end loop; end if; - -- Generate the muxes tree. - Synth_Case (Get_Build (Syn_Inst), - Sel_Net, Case_El.all, Default, Res, - Get_Location (Expr)); Synth_Assignment (Syn_Inst, Targ, Create_Value_Net (Res, Targ_Type), Stmt); end; -- free. - Free_Case_Element_Array (Case_El); - Free_Choice_Data_Array (Choice_Data); - Free_Annex_Array (Annex_Arr); Free_Alternative_Data_Array (Alts); + Free_Net_Array (Nets); end Synth_Selected_Signal_Assignment; function Synth_Label (Stmt : Node) return Sname |