aboutsummaryrefslogtreecommitdiffstats
path: root/src/synth/synth-vhdl_stmts.adb
diff options
context:
space:
mode:
Diffstat (limited to 'src/synth/synth-vhdl_stmts.adb')
-rw-r--r--src/synth/synth-vhdl_stmts.adb3856
1 files changed, 3856 insertions, 0 deletions
diff --git a/src/synth/synth-vhdl_stmts.adb b/src/synth/synth-vhdl_stmts.adb
new file mode 100644
index 000000000..0f2694e06
--- /dev/null
+++ b/src/synth/synth-vhdl_stmts.adb
@@ -0,0 +1,3856 @@
+-- Statements synthesis.
+-- Copyright (C) 2017 Tristan Gingold
+--
+-- This file is part of GHDL.
+--
+-- This program is free software: you can redistribute it and/or modify
+-- it under the terms of the GNU General Public License as published by
+-- the Free Software Foundation, either version 2 of the License, or
+-- (at your option) any later version.
+--
+-- This program is distributed in the hope that it will be useful,
+-- but WITHOUT ANY WARRANTY; without even the implied warranty of
+-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+-- GNU General Public License for more details.
+--
+-- You should have received a copy of the GNU General Public License
+-- along with this program. If not, see <gnu.org/licenses>.
+
+with Ada.Unchecked_Deallocation;
+
+with Grt.Types; use Grt.Types;
+with Grt.Algos;
+with Grt.Severity; use Grt.Severity;
+with Areapools;
+with Name_Table;
+with Std_Names;
+with Errorout; use Errorout;
+with Files_Map;
+with Simple_IO;
+
+with Vhdl.Errors; use Vhdl.Errors;
+with Vhdl.Sem_Expr;
+with Vhdl.Sem_Inst;
+with Vhdl.Utils; use Vhdl.Utils;
+with Vhdl.Std_Package;
+with Vhdl.Evaluation;
+with Vhdl.Ieee.Std_Logic_1164;
+
+with PSL.Types;
+with PSL.NFAs;
+
+with Synth.Memtype; use Synth.Memtype;
+with Synth.Errors; use Synth.Errors;
+with Synth.Vhdl_Decls; use Synth.Vhdl_Decls;
+with Synth.Vhdl_Expr; use Synth.Vhdl_Expr;
+with Synth.Vhdl_Insts; use Synth.Vhdl_Insts;
+with Synth.Source;
+with Synth.Vhdl_Static_Proc;
+with Synth.Vhdl_Heap;
+with Synth.Flags;
+with Synth.Debugger;
+
+with Netlists.Builders; use Netlists.Builders;
+with Netlists.Folds; use Netlists.Folds;
+with Netlists.Gates; use Netlists.Gates;
+with Netlists.Utils; use Netlists.Utils;
+with Netlists.Locations; use Netlists.Locations;
+
+package body Synth.Vhdl_Stmts is
+ procedure Synth_Sequential_Statements
+ (C : in out Seq_Context; Stmts : Node);
+
+ procedure Set_Location (N : Net; Loc : Node)
+ renames Synth.Source.Set_Location;
+
+ function Synth_Waveform (Syn_Inst : Synth_Instance_Acc;
+ Wf : Node;
+ Targ_Type : Type_Acc) return Valtyp
+ is
+ Res : Valtyp;
+ begin
+ if Get_Kind (Wf) = Iir_Kind_Unaffected_Waveform then
+ -- TODO
+ raise Internal_Error;
+ end if;
+ if Get_Chain (Wf) /= Null_Node then
+ -- Warning.
+ null;
+ end if;
+ if Get_Time (Wf) /= Null_Node then
+ -- Warning
+ null;
+ end if;
+ if Targ_Type = null then
+ return Synth_Expression (Syn_Inst, Get_We_Value (Wf));
+ else
+ Res := Synth_Expression_With_Type
+ (Syn_Inst, Get_We_Value (Wf), Targ_Type);
+ Res := Synth_Subtype_Conversion
+ (Get_Build (Syn_Inst), Res, Targ_Type, False, Wf);
+ return Res;
+ end if;
+ end Synth_Waveform;
+
+ procedure Synth_Assignment_Prefix (Syn_Inst : Synth_Instance_Acc;
+ Pfx : Node;
+ Dest_Base : out Valtyp;
+ Dest_Typ : out Type_Acc;
+ Dest_Off : out Value_Offsets;
+ Dest_Dyn : out Dyn_Name) is
+ begin
+ case Get_Kind (Pfx) is
+ when Iir_Kind_Simple_Name =>
+ Synth_Assignment_Prefix (Syn_Inst, Get_Named_Entity (Pfx),
+ Dest_Base, Dest_Typ, Dest_Off, Dest_Dyn);
+ when Iir_Kind_Interface_Signal_Declaration
+ | Iir_Kind_Variable_Declaration
+ | Iir_Kind_Interface_Variable_Declaration
+ | Iir_Kind_Signal_Declaration
+ | Iir_Kind_Anonymous_Signal_Declaration
+ | Iir_Kind_Interface_Constant_Declaration
+ | Iir_Kind_Constant_Declaration
+ | Iir_Kind_File_Declaration
+ | Iir_Kind_Interface_File_Declaration
+ | Iir_Kind_Object_Alias_Declaration =>
+ declare
+ Targ : constant Valtyp := Get_Value (Syn_Inst, Pfx);
+ begin
+ Dest_Dyn := No_Dyn_Name;
+ Dest_Typ := Targ.Typ;
+
+ if Targ.Val.Kind = Value_Alias then
+ -- Replace alias by the aliased name.
+ Dest_Base := (Targ.Val.A_Typ, Targ.Val.A_Obj);
+ Dest_Off := Targ.Val.A_Off;
+ else
+ Dest_Base := Targ;
+ Dest_Off := (0, 0);
+ end if;
+ end;
+ when Iir_Kind_Function_Call =>
+ Dest_Base := Synth_Expression (Syn_Inst, Pfx);
+ Dest_Typ := Dest_Base.Typ;
+ Dest_Off := (0, 0);
+ Dest_Dyn := No_Dyn_Name;
+
+ when Iir_Kind_Indexed_Name =>
+ declare
+ Voff : Net;
+ Off : Value_Offsets;
+ begin
+ Synth_Assignment_Prefix
+ (Syn_Inst, Get_Prefix (Pfx),
+ Dest_Base, Dest_Typ, Dest_Off, Dest_Dyn);
+ Strip_Const (Dest_Base);
+ Synth_Indexed_Name (Syn_Inst, Pfx, Dest_Typ, Voff, Off);
+
+ if Voff = No_Net then
+ -- Static index.
+ Dest_Off := Dest_Off + Off;
+ else
+ -- Dynamic index.
+ if Dest_Dyn.Voff = No_Net then
+ -- The first one.
+ Dest_Dyn := (Pfx_Off => Dest_Off,
+ Pfx_Typ => Dest_Typ,
+ Voff => Voff);
+ Dest_Off := Off;
+ else
+ -- Nested one.
+ -- FIXME
+ Dest_Off := Dest_Off + Off;
+ -- if Dest_Off /= (0, 0) then
+ -- Error_Msg_Synth (+Pfx, "nested memory not supported");
+ -- end if;
+
+ Dest_Dyn.Voff := Build_Addidx
+ (Get_Build (Syn_Inst), Dest_Dyn.Voff, Voff);
+ end if;
+ end if;
+
+ Dest_Typ := Get_Array_Element (Dest_Typ);
+ end;
+
+ when Iir_Kind_Selected_Element =>
+ declare
+ Idx : constant Iir_Index32 :=
+ Get_Element_Position (Get_Named_Entity (Pfx));
+ begin
+ Synth_Assignment_Prefix
+ (Syn_Inst, Get_Prefix (Pfx),
+ Dest_Base, Dest_Typ, Dest_Off, Dest_Dyn);
+ Dest_Off.Net_Off :=
+ Dest_Off.Net_Off + Dest_Typ.Rec.E (Idx + 1).Boff;
+ Dest_Off.Mem_Off :=
+ Dest_Off.Mem_Off + Dest_Typ.Rec.E (Idx + 1).Moff;
+
+ Dest_Typ := Dest_Typ.Rec.E (Idx + 1).Typ;
+ end;
+
+ when Iir_Kind_Slice_Name =>
+ declare
+ Pfx_Bnd : Bound_Type;
+ El_Typ : Type_Acc;
+ Res_Bnd : Bound_Type;
+ Sl_Voff : Net;
+ Sl_Off : Value_Offsets;
+ begin
+ Synth_Assignment_Prefix
+ (Syn_Inst, Get_Prefix (Pfx),
+ Dest_Base, Dest_Typ, Dest_Off, Dest_Dyn);
+ Strip_Const (Dest_Base);
+
+ Get_Onedimensional_Array_Bounds (Dest_Typ, Pfx_Bnd, El_Typ);
+ Synth_Slice_Suffix (Syn_Inst, Pfx, Pfx_Bnd, El_Typ,
+ Res_Bnd, Sl_Voff, Sl_Off);
+
+
+ if Sl_Voff = No_Net then
+ -- Fixed slice.
+ Dest_Typ := Create_Onedimensional_Array_Subtype
+ (Dest_Typ, Res_Bnd);
+ Dest_Off.Net_Off := Dest_Off.Net_Off + Sl_Off.Net_Off;
+ Dest_Off.Mem_Off := Dest_Off.Mem_Off + Sl_Off.Mem_Off;
+ else
+ -- Variable slice.
+ if Dest_Dyn.Voff = No_Net then
+ -- First one.
+ Dest_Dyn := (Pfx_Off => Dest_Off,
+ Pfx_Typ => Dest_Typ,
+ Voff => Sl_Voff);
+ Dest_Off := Sl_Off;
+ else
+ -- Nested.
+ if Dest_Off /= (0, 0) then
+ Error_Msg_Synth (+Pfx, "nested memory not supported");
+ end if;
+
+ Dest_Dyn.Voff := Build_Addidx
+ (Get_Build (Syn_Inst), Dest_Dyn.Voff, Sl_Voff);
+ end if;
+ Dest_Typ := Create_Slice_Type (Res_Bnd.Len, El_Typ);
+ end if;
+ end;
+
+ when Iir_Kind_Implicit_Dereference
+ | Iir_Kind_Dereference =>
+ Synth_Assignment_Prefix
+ (Syn_Inst, Get_Prefix (Pfx),
+ Dest_Base, Dest_Typ, Dest_Off, Dest_Dyn);
+ if Dest_Off /= (0, 0) and then Dest_Dyn.Voff /= No_Net then
+ raise Internal_Error;
+ end if;
+ Dest_Base := Vhdl_Heap.Synth_Dereference (Read_Access (Dest_Base));
+ Dest_Typ := Dest_Base.Typ;
+
+ when others =>
+ Error_Kind ("synth_assignment_prefix", Pfx);
+ end case;
+ end Synth_Assignment_Prefix;
+
+ type Target_Kind is
+ (
+ -- The target is an object or a static part of it.
+ Target_Simple,
+
+ -- The target is an aggregate.
+ Target_Aggregate,
+
+ -- The assignment is dynamically indexed.
+ Target_Memory
+ );
+
+ type Target_Info (Kind : Target_Kind := Target_Simple) is record
+ -- In all cases, the type of the target is known or computed.
+ Targ_Type : Type_Acc;
+
+ case Kind is
+ when Target_Simple =>
+ -- For a simple target, the destination is known.
+ Obj : Valtyp;
+ Off : Value_Offsets;
+ when Target_Aggregate =>
+ -- For an aggregate: the type is computed and the details will
+ -- be handled at the assignment.
+ Aggr : Node;
+ when Target_Memory =>
+ -- For a memory: the destination is known.
+ Mem_Obj : Valtyp;
+ -- The dynamic offset.
+ Mem_Dyn : Dyn_Name;
+ -- Offset of the data to be accessed from the memory.
+ Mem_Doff : Uns32;
+ end case;
+ end record;
+
+ type Target_Info_Array is array (Natural range <>) of Target_Info;
+
+ function Synth_Aggregate_Target_Type (Syn_Inst : Synth_Instance_Acc;
+ Target : Node) return Type_Acc
+ is
+ Targ_Type : constant Node := Get_Type (Target);
+ Base_Type : constant Node := Get_Base_Type (Targ_Type);
+ Base_Typ : Type_Acc;
+ Bnd : Bound_Type;
+ Len : Uns32;
+ Res : Type_Acc;
+ begin
+ Base_Typ := Get_Subtype_Object (Syn_Inst, Base_Type);
+ -- It's a basetype, so not bounded.
+ pragma Assert (Base_Typ.Kind = Type_Unbounded_Vector);
+
+ if Is_Fully_Constrained_Type (Targ_Type) then
+ -- If the aggregate subtype is known, just use it.
+ Bnd := Vhdl_Expr.Synth_Array_Bounds (Syn_Inst, Targ_Type, 1);
+ else
+ -- Ok, so the subtype of the aggregate is not known, in general
+ -- because the length of an element is not known. That's with
+ -- vhdl-2008.
+ Len := 0;
+ declare
+ Choice : Node;
+ El : Node;
+ El_Typ : Type_Acc;
+ begin
+ Choice := Get_Association_Choices_Chain (Target);
+ while Choice /= Null_Node loop
+ pragma Assert (Get_Kind (Choice) = Iir_Kind_Choice_By_None);
+ El := Get_Associated_Expr (Choice);
+ El_Typ := Synth_Type_Of_Object (Syn_Inst, El);
+ Bnd := Get_Array_Bound (El_Typ, 1);
+ Len := Len + Bnd.Len;
+ Choice := Get_Chain (Choice);
+ end loop;
+ end;
+
+ -- Compute the range.
+ declare
+ Idx_Type : constant Node := Get_Index_Type (Base_Type, 0);
+ Idx_Typ : Type_Acc;
+ begin
+ Idx_Typ := Get_Subtype_Object (Syn_Inst, Idx_Type);
+ Bnd := (Dir => Idx_Typ.Drange.Dir,
+ Left => Int32 (Idx_Typ.Drange.Left),
+ Right => 0,
+ Len => Len);
+ case Bnd.Dir is
+ when Dir_To =>
+ Bnd.Right := Bnd.Left + Int32 (Len);
+ when Dir_Downto =>
+ Bnd.Right := Bnd.Left - Int32 (Len);
+ end case;
+ end;
+ end if;
+
+ -- Compute the type.
+ case Base_Typ.Kind is
+ when Type_Unbounded_Vector =>
+ Res := Create_Vector_Type (Bnd, Base_Typ.Uvec_El);
+ when others =>
+ raise Internal_Error;
+ end case;
+ return Res;
+ end Synth_Aggregate_Target_Type;
+
+ function Synth_Target (Syn_Inst : Synth_Instance_Acc;
+ Target : Node) return Target_Info is
+ begin
+ case Get_Kind (Target) is
+ when Iir_Kind_Aggregate =>
+ return Target_Info'(Kind => Target_Aggregate,
+ Targ_Type => Synth_Aggregate_Target_Type
+ (Syn_Inst, Target),
+ Aggr => Target);
+ when Iir_Kind_Simple_Name
+ | Iir_Kind_Selected_Element
+ | Iir_Kind_Interface_Signal_Declaration
+ | Iir_Kind_Variable_Declaration
+ | Iir_Kind_Signal_Declaration
+ | Iir_Kind_Anonymous_Signal_Declaration
+ | Iir_Kind_Indexed_Name
+ | Iir_Kind_Slice_Name
+ | Iir_Kind_Dereference =>
+ declare
+ Base : Valtyp;
+ Typ : Type_Acc;
+ Off : Value_Offsets;
+
+ Dyn : Dyn_Name;
+ begin
+ Synth_Assignment_Prefix (Syn_Inst, Target, Base, Typ, Off, Dyn);
+ if Dyn.Voff = No_Net then
+ -- FIXME: check index.
+ return Target_Info'(Kind => Target_Simple,
+ Targ_Type => Typ,
+ Obj => Base,
+ Off => Off);
+ else
+ return Target_Info'(Kind => Target_Memory,
+ Targ_Type => Typ,
+ Mem_Obj => Base,
+ Mem_Dyn => Dyn,
+ Mem_Doff => Off.Net_Off);
+ end if;
+ end;
+ when others =>
+ Error_Kind ("synth_target", Target);
+ end case;
+ end Synth_Target;
+
+ procedure Synth_Assignment (Syn_Inst : Synth_Instance_Acc;
+ Target : Target_Info;
+ Val : Valtyp;
+ Loc : Node);
+
+ -- Extract a part of VAL from a target aggregate at offset OFF (offset
+ -- in the array).
+ function Aggregate_Extract (Ctxt : Context_Acc;
+ Val : Valtyp;
+ Off : Uns32;
+ Typ : Type_Acc;
+ Loc : Node) return Valtyp
+ is
+ El_Typ : constant Type_Acc := Get_Array_Element (Val.Typ);
+ begin
+ case Val.Val.Kind is
+ when Value_Net
+ | Value_Wire =>
+ declare
+ N : Net;
+ begin
+ N := Build2_Extract
+ (Ctxt, Get_Net (Ctxt, Val), Off * El_Typ.W, Typ.W);
+ Set_Location (N, Loc);
+ return Create_Value_Net (N, Typ);
+ end;
+ when Value_Memory =>
+ declare
+ Res : Valtyp;
+ begin
+ Res := Create_Value_Memory (Typ);
+ -- Need to reverse offsets.
+ Copy_Memory
+ (Res.Val.Mem,
+ Val.Val.Mem + (Val.Typ.Sz - Size_Type (Off + 1) * El_Typ.Sz),
+ Typ.Sz);
+ return Res;
+ end;
+ when others =>
+ raise Internal_Error;
+ end case;
+ end Aggregate_Extract;
+
+ procedure Synth_Assignment_Aggregate (Syn_Inst : Synth_Instance_Acc;
+ Target : Node;
+ Target_Typ : Type_Acc;
+ Val : Valtyp;
+ Loc : Node)
+ is
+ Ctxt : constant Context_Acc := Get_Build (Syn_Inst);
+ Targ_Bnd : constant Bound_Type := Get_Array_Bound (Target_Typ, 1);
+ Choice : Node;
+ Assoc : Node;
+ Pos : Uns32;
+ Targ_Info : Target_Info;
+ begin
+ Choice := Get_Association_Choices_Chain (Target);
+ Pos := Targ_Bnd.Len;
+ while Is_Valid (Choice) loop
+ Assoc := Get_Associated_Expr (Choice);
+ case Get_Kind (Choice) is
+ when Iir_Kind_Choice_By_None =>
+ Targ_Info := Synth_Target (Syn_Inst, Assoc);
+ if Get_Element_Type_Flag (Choice) then
+ Pos := Pos - 1;
+ else
+ Pos := Pos - Get_Array_Bound (Targ_Info.Targ_Type, 1).Len;
+ end if;
+ Synth_Assignment
+ (Syn_Inst, Targ_Info,
+ Aggregate_Extract (Ctxt, Val, Pos,
+ Targ_Info.Targ_Type, Assoc),
+ Loc);
+ when others =>
+ Error_Kind ("synth_assignment_aggregate", Choice);
+ end case;
+ Choice := Get_Chain (Choice);
+ end loop;
+ end Synth_Assignment_Aggregate;
+
+ procedure Synth_Assignment (Syn_Inst : Synth_Instance_Acc;
+ Target : Target_Info;
+ Val : Valtyp;
+ Loc : Node)
+ is
+ Ctxt : constant Context_Acc := Get_Build (Syn_Inst);
+ V : Valtyp;
+ begin
+ V := Synth_Subtype_Conversion (Ctxt, Val, Target.Targ_Type, False, Loc);
+ pragma Unreferenced (Val);
+ if V = No_Valtyp then
+ -- In case of error.
+ return;
+ end if;
+
+ case Target.Kind is
+ when Target_Aggregate =>
+ Synth_Assignment_Aggregate
+ (Syn_Inst, Target.Aggr, Target.Targ_Type, V, Loc);
+ when Target_Simple =>
+ if V.Typ.Sz = 0 then
+ -- If there is nothing to assign (like a null slice),
+ -- return now.
+ return;
+ end if;
+
+ if Target.Obj.Val.Kind = Value_Wire then
+ if Is_Static (V.Val)
+ and then V.Typ.Sz = Target.Obj.Typ.Sz
+ then
+ pragma Assert (Target.Off = (0, 0));
+ Phi_Assign_Static
+ (Target.Obj.Val.W, Unshare (Get_Memtyp (V)));
+ else
+ if V.Typ.W = 0 then
+ -- Forget about null wires.
+ return;
+ end if;
+ Phi_Assign_Net (Ctxt, Target.Obj.Val.W,
+ Get_Net (Ctxt, V), Target.Off.Net_Off);
+ end if;
+ else
+ if not Is_Static (V.Val) then
+ -- Maybe the error message is too cryptic ?
+ Error_Msg_Synth
+ (+Loc, "cannot assign a net to a static value");
+ else
+ Strip_Const (V);
+ Copy_Memory (Target.Obj.Val.Mem + Target.Off.Mem_Off,
+ V.Val.Mem, V.Typ.Sz);
+ end if;
+ end if;
+ when Target_Memory =>
+ declare
+ Ctxt : constant Context_Acc := Get_Build (Syn_Inst);
+ N : Net;
+ begin
+ N := Get_Current_Assign_Value
+ (Ctxt, Target.Mem_Obj.Val.W,
+ Target.Mem_Dyn.Pfx_Off.Net_Off, Target.Mem_Dyn.Pfx_Typ.W);
+ N := Build_Dyn_Insert (Ctxt, N, Get_Net (Ctxt, V),
+ Target.Mem_Dyn.Voff, Target.Mem_Doff);
+ Set_Location (N, Loc);
+ Phi_Assign_Net (Ctxt, Target.Mem_Obj.Val.W, N,
+ Target.Mem_Dyn.Pfx_Off.Net_Off);
+ end;
+ end case;
+ end Synth_Assignment;
+
+ procedure Synth_Assignment (Syn_Inst : Synth_Instance_Acc;
+ Target : Node;
+ Val : Valtyp;
+ Loc : Node)
+ is
+ Info : Target_Info;
+ begin
+ Info := Synth_Target (Syn_Inst, Target);
+ Synth_Assignment (Syn_Inst, Info, Val, Loc);
+ end Synth_Assignment;
+
+ function Synth_Read_Memory (Syn_Inst : Synth_Instance_Acc;
+ Obj : Valtyp;
+ Res_Typ : Type_Acc;
+ Off : Uns32;
+ Dyn : Dyn_Name;
+ Loc : Node) return Valtyp
+ is
+ Ctxt : constant Context_Acc := Get_Build (Syn_Inst);
+ N : Net;
+ begin
+ N := Get_Net (Ctxt, Obj);
+ if Dyn.Voff /= No_Net then
+ Synth.Source.Set_Location_Maybe (N, Loc);
+ if Dyn.Pfx_Off.Net_Off /= 0 then
+ N := Build2_Extract (Ctxt, N, Dyn.Pfx_Off.Net_Off, Dyn.Pfx_Typ.W);
+ end if;
+ if Res_Typ.W /= 0 then
+ -- Do not try to extract if the net is null.
+ N := Build_Dyn_Extract (Ctxt, N, Dyn.Voff, Off, Res_Typ.W);
+ end if;
+ else
+ pragma Assert (not Is_Static (Obj.Val));
+ N := Build2_Extract (Ctxt, N, Off, Res_Typ.W);
+ end if;
+ Set_Location (N, Loc);
+ return Create_Value_Net (N, Res_Typ);
+ end Synth_Read_Memory;
+
+ function Synth_Read (Syn_Inst : Synth_Instance_Acc;
+ Targ : Target_Info;
+ Loc : Node) return Valtyp
+ is
+ Ctxt : constant Context_Acc := Get_Build (Syn_Inst);
+ N : Net;
+ begin
+ case Targ.Kind is
+ when Target_Simple =>
+ N := Build2_Extract (Ctxt, Get_Net (Ctxt, Targ.Obj),
+ Targ.Off.Net_Off, Targ.Targ_Type.W);
+ return Create_Value_Net (N, Targ.Targ_Type);
+ when Target_Aggregate =>
+ raise Internal_Error;
+ when Target_Memory =>
+ return Synth_Read_Memory (Syn_Inst, Targ.Mem_Obj, Targ.Targ_Type,
+ 0, Targ.Mem_Dyn, Loc);
+ end case;
+ end Synth_Read;
+
+ -- Concurrent or sequential simple signal assignment
+ procedure Synth_Simple_Signal_Assignment
+ (Syn_Inst : Synth_Instance_Acc; Stmt : Node)
+ is
+ Targ : Target_Info;
+ Val : Valtyp;
+ begin
+ Targ := Synth_Target (Syn_Inst, Get_Target (Stmt));
+ Val := Synth_Waveform
+ (Syn_Inst, Get_Waveform_Chain (Stmt), Targ.Targ_Type);
+ Synth_Assignment (Syn_Inst, Targ, Val, Stmt);
+ end Synth_Simple_Signal_Assignment;
+
+ procedure Synth_Conditional_Signal_Assignment
+ (Syn_Inst : Synth_Instance_Acc; Stmt : Node)
+ is
+ Ctxt : constant Context_Acc := Get_Build (Syn_Inst);
+ Targ : Target_Info;
+ Cond : Node;
+ Cwf : Node;
+ Inp : Input;
+ Val, Cond_Val : Valtyp;
+ Cond_Net : Net;
+ First, Last : Net;
+ V : Net;
+ begin
+ Targ := Synth_Target (Syn_Inst, Get_Target (Stmt));
+ Last := No_Net;
+ Cwf := Get_Conditional_Waveform_Chain (Stmt);
+ Cond := Null_Node;
+ while Cwf /= Null_Node loop
+ Val := Synth_Waveform
+ (Syn_Inst, Get_Waveform_Chain (Cwf), Targ.Targ_Type);
+ if Val = No_Valtyp then
+ -- Mark the error, but try to continue.
+ Set_Error (Syn_Inst);
+ else
+ V := Get_Net (Ctxt, Val);
+ Cond := Get_Condition (Cwf);
+ if Cond /= Null_Node then
+ Cond_Val := Synth_Expression (Syn_Inst, Cond);
+ if Cond_Val = No_Valtyp then
+ Cond_Net := Build_Const_UB32 (Ctxt, 0, 1);
+ else
+ Cond_Net := Get_Net (Ctxt, Cond_Val);
+ end if;
+
+ V := Build_Mux2 (Ctxt, Cond_Net, No_Net, V);
+ Set_Location (V, Cwf);
+ end if;
+
+ if Last /= No_Net then
+ Inp := Get_Input (Get_Net_Parent (Last), 1);
+ Connect (Inp, V);
+ else
+ First := V;
+ end if;
+ Last := V;
+ end if;
+ Cwf := Get_Chain (Cwf);
+ end loop;
+ if Cond /= Null_Node then
+ pragma Assert (Last /= No_Net);
+ Inp := Get_Input (Get_Net_Parent (Last), 1);
+ if Get_Driver (Inp) = No_Net then
+ -- No else.
+ Val := Synth_Read (Syn_Inst, Targ, Stmt);
+ Connect (Inp, Get_Net (Ctxt, Val));
+ end if;
+ end if;
+ Val := Create_Value_Net (First, Targ.Targ_Type);
+ Synth_Assignment (Syn_Inst, Targ, Val, Stmt);
+ end Synth_Conditional_Signal_Assignment;
+
+ procedure Synth_Variable_Assignment (C : Seq_Context; Stmt : Node)
+ is
+ Targ : Target_Info;
+ Val : Valtyp;
+ begin
+ Targ := Synth_Target (C.Inst, Get_Target (Stmt));
+ Val := Synth_Expression_With_Type
+ (C.Inst, Get_Expression (Stmt), Targ.Targ_Type);
+ if Val = No_Valtyp then
+ Set_Error (C.Inst);
+ return;
+ end if;
+ Synth_Assignment (C.Inst, Targ, Val, Stmt);
+ end Synth_Variable_Assignment;
+
+ procedure Synth_Conditional_Variable_Assignment
+ (C : Seq_Context; Stmt : Node)
+ is
+ Ctxt : constant Context_Acc := Get_Build (C.Inst);
+ Target : constant Node := Get_Target (Stmt);
+ Targ_Type : Type_Acc;
+ Cond : Node;
+ Ce : Node;
+ Val, Cond_Val : Valtyp;
+ V : Net;
+ First, Last : Net;
+ begin
+ Targ_Type := Get_Subtype_Object (C.Inst, Get_Type (Target));
+ Last := No_Net;
+ Ce := Get_Conditional_Expression_Chain (Stmt);
+ while Ce /= Null_Node loop
+ Val := Synth_Expression_With_Type
+ (C.Inst, Get_Expression (Ce), Targ_Type);
+ V := Get_Net (Ctxt, Val);
+ Cond := Get_Condition (Ce);
+ if Cond /= Null_Node then
+ Cond_Val := Synth_Expression (C.Inst, Cond);
+ V := Build_Mux2 (Ctxt, Get_Net (Ctxt, Cond_Val), No_Net, V);
+ Set_Location (V, Ce);
+ end if;
+
+ if Last /= No_Net then
+ Connect (Get_Input (Get_Net_Parent (Last), 1), V);
+ else
+ First := V;
+ end if;
+ Last := V;
+ Ce := Get_Chain (Ce);
+ end loop;
+ Val := Create_Value_Net (First, Targ_Type);
+ Synth_Assignment (C.Inst, Target, Val, Stmt);
+ end Synth_Conditional_Variable_Assignment;
+
+ procedure Synth_If_Statement (C : in out Seq_Context; Stmt : Node)
+ is
+ Cond : constant Node := Get_Condition (Stmt);
+ Els : constant Node := Get_Else_Clause (Stmt);
+ Ctxt : constant Context_Acc := Get_Build (C.Inst);
+ Cond_Val : Valtyp;
+ Cond_Net : Net;
+ Phi_True : Phi_Type;
+ Phi_False : Phi_Type;
+ begin
+ Cond_Val := Synth_Expression (C.Inst, Cond);
+ if Cond_Val = No_Valtyp then
+ Set_Error (C.Inst);
+ return;
+ end if;
+ if Is_Static_Val (Cond_Val.Val) then
+ Strip_Const (Cond_Val);
+ if Read_Discrete (Get_Value_Memtyp (Cond_Val)) = 1 then
+ -- True.
+ Synth_Sequential_Statements
+ (C, Get_Sequential_Statement_Chain (Stmt));
+ else
+ pragma Assert (Read_Discrete (Get_Value_Memtyp (Cond_Val)) = 0);
+ if Is_Valid (Els) then
+ -- Else part
+ if Is_Null (Get_Condition (Els)) then
+ -- Final else part.
+ Synth_Sequential_Statements
+ (C, Get_Sequential_Statement_Chain (Els));
+ else
+ -- Elsif. Handled as a nested if.
+ Synth_If_Statement (C, Els);
+ end if;
+ end if;
+ end if;
+ else
+ -- The statements for the 'then' part.
+ Push_Phi;
+ Synth_Sequential_Statements
+ (C, Get_Sequential_Statement_Chain (Stmt));
+ Pop_Phi (Phi_True);
+
+ Push_Phi;
+
+ if Is_Valid (Els) then
+ if Is_Null (Get_Condition (Els)) then
+ -- Final else part.
+ Synth_Sequential_Statements
+ (C, Get_Sequential_Statement_Chain (Els));
+ else
+ -- Elsif. Handled as a nested if.
+ Synth_If_Statement (C, Els);
+ end if;
+ end if;
+
+ Pop_Phi (Phi_False);
+
+ Cond_Net := Get_Net (Ctxt, Cond_Val);
+ Merge_Phis (Ctxt, Cond_Net, Phi_True, Phi_False, Get_Location (Stmt));
+ end if;
+ end Synth_If_Statement;
+
+ type Alternative_Index is new Int32;
+
+ -- Only keep '0' and '1' in choices for std_logic.
+ function Ignore_Choice_Logic (V : Ghdl_U8; Loc : Node) return Boolean is
+ begin
+ case V is
+ when Vhdl.Ieee.Std_Logic_1164.Std_Logic_0_Pos
+ | Vhdl.Ieee.Std_Logic_1164.Std_Logic_1_Pos =>
+ return False;
+ when Vhdl.Ieee.Std_Logic_1164.Std_Logic_L_Pos
+ | Vhdl.Ieee.Std_Logic_1164.Std_Logic_H_Pos =>
+ Warning_Msg_Synth
+ (+Loc, "choice with 'L' or 'H' value is ignored");
+ return True;
+ when Vhdl.Ieee.Std_Logic_1164.Std_Logic_U_Pos
+ | Vhdl.Ieee.Std_Logic_1164.Std_Logic_X_Pos
+ | Vhdl.Ieee.Std_Logic_1164.Std_Logic_D_Pos
+ | Vhdl.Ieee.Std_Logic_1164.Std_Logic_Z_Pos
+ | Vhdl.Ieee.Std_Logic_1164.Std_Logic_W_Pos =>
+ Warning_Msg_Synth (+Loc, "choice with meta-value is ignored");
+ return True;
+ when others =>
+ -- Only 9 values.
+ raise Internal_Error;
+ end case;
+ end Ignore_Choice_Logic;
+
+ function Ignore_Choice_Expression (V : Valtyp; Loc : Node) return Boolean is
+ begin
+ case V.Typ.Kind is
+ when Type_Bit =>
+ return False;
+ when Type_Logic =>
+ if V.Typ = Logic_Type then
+ return Ignore_Choice_Logic (Read_U8 (V.Val.Mem), Loc);
+ else
+ return False;
+ end if;
+ when Type_Discrete =>
+ return False;
+ when Type_Vector =>
+ if V.Typ.Vec_El = Logic_Type then
+ for I in 1 .. Size_Type (V.Typ.Vbound.Len) loop
+ if Ignore_Choice_Logic (Read_U8 (V.Val.Mem + (I - 1)), Loc)
+ then
+ return True;
+ end if;
+ end loop;
+ return False;
+ else
+ return False;
+ end if;
+ when Type_Array =>
+ return False;
+ when others =>
+ raise Internal_Error;
+ end case;
+ end Ignore_Choice_Expression;
+
+ -- Create the condition for choices of CHOICE chain belonging to the same
+ -- alternative. Update CHOICE to the next alternative.
+ procedure Synth_Choice (Syn_Inst : Synth_Instance_Acc;
+ Sel : Net;
+ Choice_Typ : Type_Acc;
+ Nets : in out Net_Array;
+ Other_Choice : in out Nat32;
+ Choice_Idx : in out Nat32;
+ Choice : in out Node)
+ is
+ Ctxt : constant Context_Acc := Get_Build (Syn_Inst);
+ Cond : Net;
+ Res : Net;
+ begin
+ Res := No_Net;
+ loop
+ case Iir_Kinds_Case_Choice (Get_Kind (Choice)) is
+ when Iir_Kind_Choice_By_Expression =>
+ declare
+ V : Valtyp;
+ begin
+ V := Synth_Expression_With_Basetype
+ (Syn_Inst, Get_Choice_Expression (Choice));
+ V := Synth_Subtype_Conversion
+ (Ctxt, V, Choice_Typ, False, Choice);
+ if Ignore_Choice_Expression (V, Choice) then
+ Cond := No_Net;
+ else
+ Cond := Build_Compare
+ (Ctxt, Id_Eq, Sel, Get_Net (Ctxt, V));
+ Set_Location (Cond, Choice);
+ end if;
+ end;
+
+ when Iir_Kind_Choice_By_Range =>
+ declare
+ Rng : Discrete_Range_Type;
+ Cmp_L, Cmp_R : Module_Id;
+ L, R : Net;
+ begin
+ Synth_Discrete_Range
+ (Syn_Inst, Get_Choice_Range (Choice), Rng);
+
+ if Rng.Is_Signed then
+ case Rng.Dir is
+ when Dir_To =>
+ Cmp_L := Id_Sge;
+ Cmp_R := Id_Sle;
+ when Dir_Downto =>
+ Cmp_L := Id_Sle;
+ Cmp_R := Id_Sge;
+ end case;
+ L := Build2_Const_Int (Ctxt, Rng.Left, Choice_Typ.W);
+ R := Build2_Const_Int (Ctxt, Rng.Right, Choice_Typ.W);
+ else
+ case Rng.Dir is
+ when Dir_To =>
+ Cmp_L := Id_Uge;
+ Cmp_R := Id_Ule;
+ when Dir_Downto =>
+ Cmp_L := Id_Ule;
+ Cmp_R := Id_Uge;
+ end case;
+ L := Build2_Const_Uns
+ (Ctxt, Uns64 (Rng.Left), Choice_Typ.W);
+ R := Build2_Const_Uns
+ (Ctxt, Uns64 (Rng.Right), Choice_Typ.W);
+ end if;
+
+ L := Build_Compare (Ctxt, Cmp_L, Sel, L);
+ Set_Location (L, Choice);
+
+ R := Build_Compare (Ctxt, Cmp_R, Sel, R);
+ Set_Location (R, Choice);
+
+ Cond := Build_Dyadic (Ctxt, Id_And, L, R);
+ Set_Location (Cond, Choice);
+ end;
+
+ when Iir_Kind_Choice_By_Others =>
+ -- Last and only one.
+ pragma Assert (Res = No_Net);
+ Other_Choice := Choice_Idx + 1;
+ pragma Assert (Get_Chain (Choice) = Null_Node);
+ Choice := Null_Node;
+ return;
+ end case;
+
+ if not Get_Same_Alternative_Flag (Choice) then
+ -- First choice.
+ Choice_Idx := Choice_Idx + 1;
+ Res := Cond;
+ else
+ if Cond = No_Net then
+ -- No new condition.
+ null;
+ else
+ if Res /= No_Net then
+ Res := Build_Dyadic (Ctxt, Id_Or, Res, Cond);
+ Set_Location (Res, Choice);
+ else
+ Res := Cond;
+ end if;
+ end if;
+ end if;
+
+ Choice := Get_Chain (Choice);
+ exit when Choice = Null_Node
+ or else not Get_Same_Alternative_Flag (Choice);
+ end loop;
+ if Res = No_Net then
+ Res := Build_Const_UB32 (Ctxt, 0, 1);
+ end if;
+ Nets (Choice_Idx) := Res;
+ end Synth_Choice;
+
+ type Alternative_Data_Type is record
+ Asgns : Seq_Assign;
+ Val : Net;
+ end record;
+ type Alternative_Data_Array is
+ array (Alternative_Index range <>) of Alternative_Data_Type;
+ type Alternative_Data_Acc is access Alternative_Data_Array;
+ procedure Free_Alternative_Data_Array is new Ada.Unchecked_Deallocation
+ (Alternative_Data_Array, Alternative_Data_Acc);
+
+ type Wire_Id_Array is array (Natural range <>) of Wire_Id;
+ type Wire_Id_Array_Acc is access Wire_Id_Array;
+ procedure Free_Wire_Id_Array is new Ada.Unchecked_Deallocation
+ (Wire_Id_Array, Wire_Id_Array_Acc);
+
+ procedure Sort_Wire_Id_Array (Arr : in out Wire_Id_Array)
+ is
+ function Lt (Op1, Op2 : Natural) return Boolean is
+ begin
+ return Is_Lt (Arr (Op1), Arr (Op2));
+ end Lt;
+
+ procedure Swap (From : Natural; To : Natural)
+ is
+ T : Wire_Id;
+ begin
+ T := Arr (From);
+ Arr (From) := Arr (To);
+ Arr (To) := T;
+ end Swap;
+
+ procedure Wid_Heap_Sort is
+ new Grt.Algos.Heap_Sort (Lt => Lt, Swap => Swap);
+ begin
+ Wid_Heap_Sort (Arr'Length);
+ end Sort_Wire_Id_Array;
+
+ -- Count the number of wires used in all the alternatives.
+ function Count_Wires_In_Alternatives (Alts : Alternative_Data_Array)
+ return Natural
+ is
+ Res : Natural;
+ Asgn : Seq_Assign;
+ W : Wire_Id;
+ begin
+ Res := 0;
+ for I in Alts'Range loop
+ Asgn := Alts (I).Asgns;
+ while Asgn /= No_Seq_Assign loop
+ W := Get_Wire_Id (Asgn);
+ if not Get_Wire_Mark (W) then
+ Res := Res + 1;
+ Set_Wire_Mark (W, True);
+ end if;
+ Asgn := Get_Assign_Chain (Asgn);
+ end loop;
+ end loop;
+ return Res;
+ end Count_Wires_In_Alternatives;
+
+ -- Fill ARR from wire_id of ALTS.
+ procedure Fill_Wire_Id_Array (Arr : out Wire_Id_Array;
+ Alts : Alternative_Data_Array)
+ is
+ Idx : Natural;
+ Asgn : Seq_Assign;
+ W : Wire_Id;
+ begin
+ Idx := Arr'First;
+ for I in Alts'Range loop
+ Asgn := Alts (I).Asgns;
+ while Asgn /= No_Seq_Assign loop
+ W := Get_Wire_Id (Asgn);
+ if Get_Wire_Mark (W) then
+ Arr (Idx) := W;
+ Idx := Idx + 1;
+ Set_Wire_Mark (W, False);
+ end if;
+ Asgn := Get_Assign_Chain (Asgn);
+ end loop;
+ end loop;
+ pragma Assert (Idx = Arr'Last + 1);
+ end Fill_Wire_Id_Array;
+
+ type Seq_Assign_Value_Array_Acc is access Seq_Assign_Value_Array;
+ procedure Free_Seq_Assign_Value_Array is new Ada.Unchecked_Deallocation
+ (Seq_Assign_Value_Array, Seq_Assign_Value_Array_Acc);
+
+ function Is_Assign_Value_Array_Static
+ (Wid : Wire_Id; Arr : Seq_Assign_Value_Array) return Memtyp
+ is
+ Res : Memtyp;
+ Prev_Val : Memtyp;
+ begin
+ Prev_Val := Null_Memtyp;
+ for I in Arr'Range loop
+ case Arr (I).Is_Static is
+ when False =>
+ -- A value is not static.
+ return Null_Memtyp;
+ when Unknown =>
+ if Prev_Val = Null_Memtyp then
+ -- First use of previous value.
+ if not Is_Static_Wire (Wid) then
+ -- The previous value is not static.
+ return Null_Memtyp;
+ end if;
+ Prev_Val := Get_Static_Wire (Wid);
+ if Res /= Null_Memtyp then
+ -- There is already a result.
+ if not Is_Equal (Res, Prev_Val) then
+ -- The previous value is different from the result.
+ return Null_Memtyp;
+ end if;
+ else
+ Res := Prev_Val;
+ end if;
+ end if;
+ when True =>
+ if Res = Null_Memtyp then
+ -- First value. Keep it.
+ Res := Arr (I).Val;
+ else
+ if not Is_Equal (Res, Arr (I).Val) then
+ -- Value is different.
+ return Null_Memtyp;
+ end if;
+ end if;
+ end case;
+ end loop;
+ return Res;
+ end Is_Assign_Value_Array_Static;
+
+ procedure Synth_Case_Statement_Dynamic
+ (C : in out Seq_Context; Stmt : Node; Sel : Valtyp)
+ is
+ use Vhdl.Sem_Expr;
+ Ctxt : constant Context_Acc := Get_Build (C.Inst);
+
+ Choices : constant Node := Get_Case_Statement_Alternative_Chain (Stmt);
+
+ Case_Info : Choice_Info_Type;
+
+ -- Array of alternatives
+ Alts : Alternative_Data_Acc;
+ Alt_Idx : Alternative_Index;
+ Others_Alt_Idx : Alternative_Index;
+
+ Nbr_Choices : Nat32;
+
+ Pasgns : Seq_Assign_Value_Array_Acc;
+ Nets : Net_Array_Acc;
+
+ Nbr_Wires : Natural;
+ Wires : Wire_Id_Array_Acc;
+
+ Sel_Net : Net;
+ begin
+ -- Strategies to synthesize a case statement. Assume the selector is
+ -- a net of W bits
+ -- - a large mux, with 2**W inputs
+ -- - if the number of choices is dense
+ -- - if W is small
+ -- - a onehot mux. Each choice is converted to an single bit condition
+ -- by adding a comparison operator (equal for single choice,
+ -- inequalities for ranges, or for multiple choices). Only one of
+ -- these conditions is true (plus 'others').
+ -- - if the number of choices is sparse
+ -- - large range choices
+ -- - a tree of mux/mux2
+ -- - large number of choices, densily grouped but sparsed compared
+ -- to 2**W (eg: a partially filled memory)
+ -- - divide and conquier
+
+ -- Count choices and alternatives.
+ Count_Choices (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));
+
+ -- 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.
+ declare
+ Choice : Node;
+ Choice_Idx, Other_Choice : Nat32;
+ Phi : Phi_Type;
+ begin
+ Alt_Idx := 0;
+ Choice_Idx := 0;
+ Other_Choice := 0;
+
+ Choice := Choices;
+ while Is_Valid (Choice) loop
+ -- Must be a choice for a new alternative.
+ pragma Assert (not Get_Same_Alternative_Flag (Choice));
+
+ -- A new sequence of statements.
+ Alt_Idx := Alt_Idx + 1;
+
+ Push_Phi;
+ Synth_Sequential_Statements (C, Get_Associated_Chain (Choice));
+ Pop_Phi (Phi);
+ Alts (Alt_Idx).Asgns := Sort_Phi (Phi);
+
+ Synth_Choice (C.Inst, Sel_Net, Sel.Typ,
+ Nets.all, Other_Choice, Choice_Idx, Choice);
+ end loop;
+ pragma Assert (Choice_Idx = Nbr_Choices);
+ Others_Alt_Idx := Alternative_Index (Other_Choice);
+ end;
+
+ -- Create the one-hot vector.
+ if Nbr_Choices = 0 then
+ Sel_Net := No_Net;
+ else
+ Sel_Net := Build2_Concat (Ctxt, Nets (1 .. Nbr_Choices));
+ end if;
+
+ -- Create list of wire_id, sort it.
+ Nbr_Wires := Count_Wires_In_Alternatives (Alts.all);
+ Wires := new Wire_Id_Array (1 .. Nbr_Wires);
+ Fill_Wire_Id_Array (Wires.all, Alts.all);
+ Sort_Wire_Id_Array (Wires.all);
+
+ -- Associate each choice with the assign node
+ -- For each wire_id:
+ -- Build mux2/mux4 tree (group by 4)
+ Pasgns := new Seq_Assign_Value_Array (1 .. Int32 (Alts'Last));
+
+ -- 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;
+ Min_Off, Off : Uns32;
+ Wd : Width;
+ List : Partial_Assign_List;
+ Sval : Memtyp;
+ begin
+ -- Extract the value for each branch.
+ for I in Alts'Range loop
+ -- If there is an assignment to Wi in Alt, it will define the
+ -- value.
+ if Get_Wire_Id (Alts (I).Asgns) = Wi then
+ Pasgns (Int32 (I)) :=
+ Get_Seq_Assign_Value (Alts (I).Asgns);
+ Alts (I).Asgns := Get_Assign_Chain (Alts (I).Asgns);
+ else
+ Pasgns (Int32 (I)) := (Is_Static => Unknown);
+ end if;
+ end loop;
+
+ -- If:
+ -- 1) All present values in PASGNS are static
+ -- 2) There is no missing values *or* the previous value is
+ -- static.
+ -- 3) The default value is unused *or* it is static
+ -- 4) All the values are equal.
+ -- then assign directly.
+ Sval := Is_Assign_Value_Array_Static (Wi, Pasgns.all);
+ if Sval /= Null_Memtyp then
+ -- Use static assignment.
+ Phi_Assign_Static (Wi, Sval);
+ else
+ -- Compute the final value for each partial part of the wire.
+ Partial_Assign_Init (List);
+ Min_Off := 0;
+ loop
+ Off := Min_Off;
+
+ -- Extract value of partial assignments to NETS.
+ Extract_Merge_Partial_Assigns
+ (Ctxt, Pasgns.all, Nets.all, Off, Wd);
+ 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
+ if Last_Val = No_Net then
+ Last_Val := Get_Current_Assign_Value
+ (Ctxt, Wi, Off, Wd);
+ end if;
+ Nets (I) := Last_Val;
+ end if;
+ end loop;
+
+ -- Extract default value (for missing alternative).
+ if Others_Alt_Idx /= 0 then
+ Default := Nets (Int32 (Others_Alt_Idx));
+ else
+ Default := Build_Const_X (Ctxt, Wd);
+ 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)),
+ Nets (I));
+ end loop;
+ end if;
+
+ Partial_Assign_Append (List, New_Partial_Assign (Res, Off));
+ Min_Off := Off + Wd;
+ end loop;
+
+ Merge_Partial_Assigns (Ctxt, Wi, List);
+ end if;
+ end;
+ end loop;
+
+ -- free.
+ Free_Wire_Id_Array (Wires);
+ Free_Alternative_Data_Array (Alts);
+ Free_Seq_Assign_Value_Array (Pasgns);
+ Free_Net_Array (Nets);
+ end Synth_Case_Statement_Dynamic;
+
+ procedure Synth_Case_Statement_Static_Array
+ (C : in out Seq_Context; Stmt : Node; Sel : Valtyp)
+ is
+ Choices : constant Node := Get_Case_Statement_Alternative_Chain (Stmt);
+ Choice : Node;
+ Stmts : Node;
+ Sel_Expr : Node;
+ Sel_Val : Valtyp;
+ begin
+ -- Synth statements, extract choice value.
+ Stmts := Null_Node;
+ Choice := Choices;
+ loop
+ pragma Assert (Is_Valid (Choice));
+ if not Get_Same_Alternative_Flag (Choice) then
+ Stmts := Get_Associated_Chain (Choice);
+ end if;
+
+ case Get_Kind (Choice) is
+ when Iir_Kind_Choice_By_Expression =>
+ Sel_Expr := Get_Choice_Expression (Choice);
+ Sel_Val := Synth_Expression_With_Basetype (C.Inst, Sel_Expr);
+ if Is_Equal (Sel_Val, Sel) then
+ Synth_Sequential_Statements (C, Stmts);
+ exit;
+ end if;
+ when Iir_Kind_Choice_By_Others =>
+ Synth_Sequential_Statements (C, Stmts);
+ exit;
+ when others =>
+ raise Internal_Error;
+ end case;
+ Choice := Get_Chain (Choice);
+ end loop;
+ end Synth_Case_Statement_Static_Array;
+
+ procedure Synth_Case_Statement_Static_Scalar
+ (C : in out Seq_Context; Stmt : Node; Sel : Int64)
+ is
+ Choices : constant Node := Get_Case_Statement_Alternative_Chain (Stmt);
+ Choice : Node;
+ Stmts : Node;
+ Sel_Expr : Node;
+ begin
+ -- Synth statements, extract choice value.
+ Stmts := Null_Node;
+ Choice := Choices;
+ loop
+ pragma Assert (Is_Valid (Choice));
+ if not Get_Same_Alternative_Flag (Choice) then
+ Stmts := Get_Associated_Chain (Choice);
+ end if;
+
+ case Get_Kind (Choice) is
+ when Iir_Kind_Choice_By_Expression =>
+ Sel_Expr := Get_Choice_Expression (Choice);
+ if Vhdl.Evaluation.Eval_Pos (Sel_Expr) = Sel then
+ Synth_Sequential_Statements (C, Stmts);
+ exit;
+ end if;
+ when Iir_Kind_Choice_By_Others =>
+ Synth_Sequential_Statements (C, Stmts);
+ exit;
+ when Iir_Kind_Choice_By_Range =>
+ declare
+ Bnd : Discrete_Range_Type;
+ Is_In : Boolean;
+ begin
+ Synth_Discrete_Range
+ (C.Inst, Get_Choice_Range (Choice), Bnd);
+ case Bnd.Dir is
+ when Dir_To =>
+ Is_In := Sel >= Bnd.Left and Sel <= Bnd.Right;
+ when Dir_Downto =>
+ Is_In := Sel <= Bnd.Left and Sel >= Bnd.Right;
+ end case;
+ if Is_In then
+ Synth_Sequential_Statements (C, Stmts);
+ exit;
+ end if;
+ end;
+ when others =>
+ raise Internal_Error;
+ end case;
+ Choice := Get_Chain (Choice);
+ end loop;
+ end Synth_Case_Statement_Static_Scalar;
+
+ procedure Synth_Case_Statement (C : in out Seq_Context; Stmt : Node)
+ is
+ Expr : constant Node := Get_Expression (Stmt);
+ Sel : Valtyp;
+ begin
+ Sel := Synth_Expression_With_Basetype (C.Inst, Expr);
+ Strip_Const (Sel);
+ if Is_Static (Sel.Val) then
+ case Sel.Typ.Kind is
+ when Type_Bit
+ | Type_Logic
+ | Type_Discrete =>
+ Synth_Case_Statement_Static_Scalar (C, Stmt,
+ Read_Discrete (Sel));
+ when Type_Vector
+ | Type_Array =>
+ Synth_Case_Statement_Static_Array (C, Stmt, Sel);
+ when others =>
+ raise Internal_Error;
+ end case;
+ else
+ Synth_Case_Statement_Dynamic (C, Stmt, Sel);
+ end if;
+ end Synth_Case_Statement;
+
+ procedure Synth_Selected_Signal_Assignment
+ (Syn_Inst : Synth_Instance_Acc; Stmt : Node)
+ is
+ use Vhdl.Sem_Expr;
+ Ctxt : constant Context_Acc := Get_Build (Syn_Inst);
+
+ Expr : constant Node := Get_Expression (Stmt);
+ Choices : constant Node := Get_Selected_Waveform_Chain (Stmt);
+
+ Targ : Target_Info;
+ Targ_Type : Type_Acc;
+
+ Case_Info : Choice_Info_Type;
+
+ -- Array of alternatives
+ Alts : Alternative_Data_Acc;
+ Alt_Idx : Alternative_Index;
+ Others_Alt_Idx : Alternative_Index;
+
+ -- Array of choices. Contains tuple of (Value, Alternative).
+ Nbr_Choices : Nat32;
+
+ Nets : Net_Array_Acc;
+
+
+ Sel : Valtyp;
+ Sel_Net : Net;
+ begin
+ Targ := Synth_Target (Syn_Inst, Get_Target (Stmt));
+ Targ_Type := Targ.Targ_Type;
+
+ -- 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);
+
+ -- 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));
+
+ -- 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.
+ declare
+ Choice, Wf : Node;
+ Val : Valtyp;
+ Choice_Idx, Other_Choice : Nat32;
+ begin
+ Alt_Idx := 0;
+ Choice_Idx := 0;
+ Other_Choice := 0;
+
+ Choice := Choices;
+ while Is_Valid (Choice) loop
+ pragma Assert (not Get_Same_Alternative_Flag (Choice));
+
+ Wf := Get_Associated_Chain (Choice);
+ Val := Synth_Waveform (Syn_Inst, Wf, Targ_Type);
+
+ Alt_Idx := Alt_Idx + 1;
+ Alts (Alt_Idx).Val := Get_Net (Ctxt, Val);
+
+ Synth_Choice (Syn_Inst, Sel_Net, Sel.Typ,
+ Nets.all, Other_Choice, Choice_Idx, Choice);
+ end loop;
+ pragma Assert (Choice_Idx = Nbr_Choices);
+ Others_Alt_Idx := Alternative_Index (Other_Choice);
+ end;
+
+ -- Create the one-hot vector.
+ if Nbr_Choices = 0 then
+ Sel_Net := No_Net;
+ else
+ Sel_Net := Build2_Concat (Ctxt, Nets (1 .. Nbr_Choices));
+ end if;
+
+ declare
+ Res : Net;
+ Res_Inst : Instance;
+ Default : Net;
+ begin
+ -- Extract default value (for missing alternative).
+ if Others_Alt_Idx /= 0 then
+ Default := Alts (Others_Alt_Idx).Val;
+ else
+ 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;
+
+ Synth_Assignment
+ (Syn_Inst, Targ, Create_Value_Net (Res, Targ_Type), Stmt);
+ end;
+
+ -- free.
+ Free_Alternative_Data_Array (Alts);
+ Free_Net_Array (Nets);
+ end Synth_Selected_Signal_Assignment;
+
+ function Synth_Label (Syn_Inst : Synth_Instance_Acc; Stmt : Node)
+ return Sname
+ is
+ Label : constant Name_Id := Get_Label (Stmt);
+ begin
+ if Label = Null_Identifier then
+ return No_Sname;
+ else
+ return New_Sname_User (Label, Get_Sname (Syn_Inst));
+ end if;
+ end Synth_Label;
+
+ function Is_Copyback_Interface (Inter : Node) return Boolean is
+ begin
+ case Iir_Parameter_Modes (Get_Mode (Inter)) is
+ when Iir_In_Mode =>
+ return False;
+ when Iir_Out_Mode | Iir_Inout_Mode =>
+ return Get_Kind (Inter) = Iir_Kind_Interface_Variable_Declaration;
+ end case;
+ end Is_Copyback_Interface;
+
+ type Association_Iterator_Kind is
+ (Association_Function,
+ Association_Operator);
+
+ type Association_Iterator_Init
+ (Kind : Association_Iterator_Kind := Association_Function) is
+ record
+ Inter_Chain : Node;
+ case Kind is
+ when Association_Function =>
+ Assoc_Chain : Node;
+ when Association_Operator =>
+ Left : Node;
+ Right : Node;
+ end case;
+ end record;
+
+ function Association_Iterator_Build (Inter_Chain : Node; Assoc_Chain : Node)
+ return Association_Iterator_Init is
+ begin
+ return Association_Iterator_Init'(Kind => Association_Function,
+ Inter_Chain => Inter_Chain,
+ Assoc_Chain => Assoc_Chain);
+ end Association_Iterator_Build;
+
+ function Association_Iterator_Build
+ (Inter_Chain : Node; Left : Node; Right : Node)
+ return Association_Iterator_Init is
+ begin
+ return Association_Iterator_Init'(Kind => Association_Operator,
+ Inter_Chain => Inter_Chain,
+ Left => Left,
+ Right => Right);
+ end Association_Iterator_Build;
+
+ function Count_Associations (Init : Association_Iterator_Init)
+ return Natural
+ is
+ Assoc : Node;
+ Assoc_Inter : Node;
+ Inter : Node;
+ Nbr_Inout : Natural;
+ begin
+ case Init.Kind is
+ when Association_Function =>
+ Nbr_Inout := 0;
+
+ Assoc := Init.Assoc_Chain;
+ Assoc_Inter := Init.Inter_Chain;
+ while Is_Valid (Assoc) loop
+ Inter := Get_Association_Interface (Assoc, Assoc_Inter);
+
+ if Is_Copyback_Interface (Inter) then
+ Nbr_Inout := Nbr_Inout + 1;
+ end if;
+
+ Next_Association_Interface (Assoc, Assoc_Inter);
+ end loop;
+
+ return Nbr_Inout;
+ when Association_Operator =>
+ return 0;
+ end case;
+ end Count_Associations;
+
+ type Association_Iterator
+ (Kind : Association_Iterator_Kind := Association_Function) is
+ record
+ Inter : Node;
+ case Kind is
+ when Association_Function =>
+ First_Named_Assoc : Node;
+ Next_Assoc : Node;
+ when Association_Operator =>
+ Op1 : Node;
+ Op2 : Node;
+ end case;
+ end record;
+
+ procedure Association_Iterate_Init (Iterator : out Association_Iterator;
+ Init : Association_Iterator_Init) is
+ begin
+ case Init.Kind is
+ when Association_Function =>
+ Iterator := (Kind => Association_Function,
+ Inter => Init.Inter_Chain,
+ First_Named_Assoc => Null_Node,
+ Next_Assoc => Init.Assoc_Chain);
+ when Association_Operator =>
+ Iterator := (Kind => Association_Operator,
+ Inter => Init.Inter_Chain,
+ Op1 => Init.Left,
+ Op2 => Init.Right);
+ end case;
+ end Association_Iterate_Init;
+
+ -- Return the next association.
+ -- ASSOC can be:
+ -- * an Iir_Kind_Association_By_XXX node (normal case)
+ -- * Null_Iir if INTER is not associated (and has a default value).
+ -- * an expression (for operator association).
+ procedure Association_Iterate_Next (Iterator : in out Association_Iterator;
+ Inter : out Node;
+ Assoc : out Node)
+ is
+ Formal : Node;
+ begin
+ Inter := Iterator.Inter;
+ if Inter = Null_Node then
+ -- End of iterator.
+ Assoc := Null_Node;
+ return;
+ else
+ -- Advance to the next interface for the next call.
+ Iterator.Inter := Get_Chain (Iterator.Inter);
+ end if;
+
+ case Iterator.Kind is
+ when Association_Function =>
+ if Iterator.First_Named_Assoc = Null_Node then
+ Assoc := Iterator.Next_Assoc;
+ if Assoc = Null_Node then
+ -- No more association: open association.
+ return;
+ end if;
+ Formal := Get_Formal (Assoc);
+ if Formal = Null_Node then
+ -- Association by position.
+ -- Update for the next call.
+ Iterator.Next_Assoc := Get_Chain (Assoc);
+ return;
+ end if;
+ Iterator.First_Named_Assoc := Assoc;
+ end if;
+
+ -- Search by name.
+ Assoc := Iterator.First_Named_Assoc;
+ while Assoc /= Null_Node loop
+ Formal := Get_Formal (Assoc);
+ pragma Assert (Formal /= Null_Node);
+ Formal := Get_Interface_Of_Formal (Formal);
+ if Formal = Inter then
+ -- Found.
+ -- Optimize in case assocs are in order.
+ if Assoc = Iterator.First_Named_Assoc then
+ Iterator.First_Named_Assoc := Get_Chain (Assoc);
+ end if;
+ return;
+ end if;
+ Assoc := Get_Chain (Assoc);
+ end loop;
+
+ -- Not found: open association.
+ return;
+
+ when Association_Operator =>
+ Assoc := Iterator.Op1;
+ Iterator.Op1 := Iterator.Op2;
+ Iterator.Op2 := Null_Node;
+ end case;
+ end Association_Iterate_Next;
+
+ procedure Synth_Subprogram_Association (Subprg_Inst : Synth_Instance_Acc;
+ Caller_Inst : Synth_Instance_Acc;
+ Init : Association_Iterator_Init;
+ Infos : out Target_Info_Array)
+ is
+ pragma Assert (Infos'First = 1);
+ Ctxt : constant Context_Acc := Get_Build (Caller_Inst);
+ Inter : Node;
+ Inter_Type : Type_Acc;
+ Assoc : Node;
+ Actual : Node;
+ Val : Valtyp;
+ Nbr_Inout : Natural;
+ Iterator : Association_Iterator;
+ Info : Target_Info;
+ begin
+ Set_Instance_Const (Subprg_Inst, True);
+
+ Nbr_Inout := 0;
+
+ -- Process in INTER order.
+ Association_Iterate_Init (Iterator, Init);
+ loop
+ Association_Iterate_Next (Iterator, Inter, Assoc);
+ exit when Inter = Null_Node;
+
+ Inter_Type := Get_Subtype_Object (Caller_Inst, Get_Type (Inter));
+
+ case Iir_Parameter_Modes (Get_Mode (Inter)) is
+ when Iir_In_Mode =>
+ if Assoc = Null_Node
+ or else Get_Kind (Assoc) = Iir_Kind_Association_Element_Open
+ then
+ Actual := Get_Default_Value (Inter);
+ Val := Synth_Expression_With_Type
+ (Subprg_Inst, Actual, Inter_Type);
+ else
+ if Get_Kind (Assoc) =
+ Iir_Kind_Association_Element_By_Expression
+ then
+ Actual := Get_Actual (Assoc);
+ else
+ Actual := Assoc;
+ end if;
+ Val := Synth_Expression_With_Type
+ (Caller_Inst, Actual, Inter_Type);
+ end if;
+ when Iir_Out_Mode | Iir_Inout_Mode =>
+ Actual := Get_Actual (Assoc);
+ Info := Synth_Target (Caller_Inst, Actual);
+
+ case Iir_Kinds_Interface_Object_Declaration (Get_Kind (Inter))
+ is
+ when Iir_Kind_Interface_Constant_Declaration =>
+ raise Internal_Error;
+ when Iir_Kind_Interface_Variable_Declaration =>
+ -- Always pass by value.
+ Nbr_Inout := Nbr_Inout + 1;
+ Infos (Nbr_Inout) := Info;
+ if Info.Kind /= Target_Memory
+ and then Is_Static (Info.Obj.Val)
+ then
+ Val := Create_Value_Memory (Info.Targ_Type);
+ Copy_Memory (Val.Val.Mem,
+ Info.Obj.Val.Mem + Info.Off.Mem_Off,
+ Info.Targ_Type.Sz);
+ else
+ Val := Synth_Read (Caller_Inst, Info, Assoc);
+ end if;
+ when Iir_Kind_Interface_Signal_Declaration =>
+ -- Always pass by reference (use an alias).
+ if Info.Kind = Target_Memory then
+ raise Internal_Error;
+ end if;
+ Val := Create_Value_Alias
+ (Info.Obj, Info.Off, Info.Targ_Type);
+ when Iir_Kind_Interface_File_Declaration =>
+ Val := Info.Obj;
+ when Iir_Kind_Interface_Quantity_Declaration =>
+ raise Internal_Error;
+ end case;
+ end case;
+
+ if Val = No_Valtyp then
+ Set_Error (Subprg_Inst);
+ return;
+ end if;
+
+ -- FIXME: conversion only for constants, reshape for all.
+ Val := Synth_Subtype_Conversion (Ctxt, Val, Inter_Type, True, Assoc);
+
+ if Get_Instance_Const (Subprg_Inst) and then not Is_Static (Val.Val)
+ then
+ Set_Instance_Const (Subprg_Inst, False);
+ end if;
+
+ case Iir_Kinds_Interface_Object_Declaration (Get_Kind (Inter)) is
+ when Iir_Kind_Interface_Constant_Declaration =>
+ -- Pass by reference.
+ Create_Object (Subprg_Inst, Inter, Val);
+ when Iir_Kind_Interface_Variable_Declaration =>
+ -- Arguments are passed by copy.
+ if Is_Static (Val.Val) or else Get_Mode (Inter) = Iir_In_Mode
+ then
+ Val := Unshare (Val, Current_Pool);
+ else
+ -- Will be changed to a wire.
+ null;
+ end if;
+ Create_Object (Subprg_Inst, Inter, Val);
+ when Iir_Kind_Interface_Signal_Declaration =>
+ Create_Object (Subprg_Inst, Inter, Val);
+ when Iir_Kind_Interface_File_Declaration =>
+ Create_Object (Subprg_Inst, Inter, Val);
+ when Iir_Kind_Interface_Quantity_Declaration =>
+ raise Internal_Error;
+ end case;
+ end loop;
+ end Synth_Subprogram_Association;
+
+ procedure Synth_Subprogram_Association (Subprg_Inst : Synth_Instance_Acc;
+ Caller_Inst : Synth_Instance_Acc;
+ Inter_Chain : Node;
+ Assoc_Chain : Node)
+ is
+ Infos : Target_Info_Array (1 .. 0);
+ pragma Unreferenced (Infos);
+ Init : Association_Iterator_Init;
+ begin
+ Init := Association_Iterator_Build (Inter_Chain, Assoc_Chain);
+ Synth_Subprogram_Association (Subprg_Inst, Caller_Inst, Init, Infos);
+ end Synth_Subprogram_Association;
+
+ -- Create wires for out and inout interface variables.
+ procedure Synth_Subprogram_Association_Wires
+ (Subprg_Inst : Synth_Instance_Acc; Init : Association_Iterator_Init)
+ is
+ Ctxt : constant Context_Acc := Get_Build (Subprg_Inst);
+ Inter : Node;
+ Assoc : Node;
+ Val : Valtyp;
+ Iterator : Association_Iterator;
+ Wire : Wire_Id;
+ begin
+ -- Process in INTER order.
+ Association_Iterate_Init (Iterator, Init);
+ loop
+ Association_Iterate_Next (Iterator, Inter, Assoc);
+ exit when Inter = Null_Node;
+
+ if Get_Mode (Inter) in Iir_Out_Modes
+ and then Get_Kind (Inter) = Iir_Kind_Interface_Variable_Declaration
+ then
+ Val := Get_Value (Subprg_Inst, Inter);
+ -- Arguments are passed by copy.
+ Wire := Alloc_Wire (Wire_Variable, (Inter, Val.Typ));
+ Set_Wire_Gate (Wire, Get_Net (Ctxt, Val));
+
+ Val := Create_Value_Wire (Wire, Val.Typ);
+ Create_Object_Force (Subprg_Inst, Inter, No_Valtyp);
+ Create_Object_Force (Subprg_Inst, Inter, Val);
+ end if;
+ end loop;
+ end Synth_Subprogram_Association_Wires;
+
+ procedure Synth_Subprogram_Back_Association
+ (Subprg_Inst : Synth_Instance_Acc;
+ Caller_Inst : Synth_Instance_Acc;
+ Init : Association_Iterator_Init;
+ Infos : Target_Info_Array)
+ is
+ pragma Assert (Infos'First = 1);
+ Inter : Node;
+ Assoc : Node;
+ Assoc_Inter : Node;
+ Val : Valtyp;
+ Nbr_Inout : Natural;
+ begin
+ Nbr_Inout := 0;
+ pragma Assert (Init.Kind = Association_Function);
+ Assoc := Init.Assoc_Chain;
+ Assoc_Inter := Init.Inter_Chain;
+ while Is_Valid (Assoc) loop
+ Inter := Get_Association_Interface (Assoc, Assoc_Inter);
+
+ if Is_Copyback_Interface (Inter) then
+ if not Get_Whole_Association_Flag (Assoc) then
+ raise Internal_Error;
+ end if;
+ Nbr_Inout := Nbr_Inout + 1;
+ Val := Get_Value (Subprg_Inst, Inter);
+ Synth_Assignment (Caller_Inst, Infos (Nbr_Inout), Val, Assoc);
+
+ -- Free wire used for out/inout interface variables.
+ if Val.Val.Kind = Value_Wire then
+ Phi_Discard_Wires (Val.Val.W, No_Wire_Id);
+ Free_Wire (Val.Val.W);
+ end if;
+ end if;
+
+ Next_Association_Interface (Assoc, Assoc_Inter);
+ end loop;
+ pragma Assert (Nbr_Inout = Infos'Last);
+ end Synth_Subprogram_Back_Association;
+
+ function Build_Control_Signal (Syn_Inst : Synth_Instance_Acc;
+ W : Width;
+ Loc : Source.Syn_Src) return Net
+ is
+ Ctxt : constant Context_Acc := Get_Build (Syn_Inst);
+ Res : Net;
+ begin
+ Res := Build_Signal (Ctxt, New_Internal_Name (Ctxt), W);
+ Set_Location (Res, Loc);
+ return Res;
+ end Build_Control_Signal;
+
+ function Synth_Dynamic_Subprogram_Call (Syn_Inst : Synth_Instance_Acc;
+ Sub_Inst : Synth_Instance_Acc;
+ Call : Node;
+ Init : Association_Iterator_Init;
+ Infos : Target_Info_Array)
+ return Valtyp
+ is
+ Imp : constant Node := Get_Implementation (Call);
+ Is_Func : constant Boolean := Is_Function_Declaration (Imp);
+ Bod : constant Node := Vhdl.Sem_Inst.Get_Subprogram_Body_Origin (Imp);
+ Ctxt : constant Context_Acc := Get_Build (Syn_Inst);
+ Res : Valtyp;
+ C : Seq_Context (Mode_Dynamic);
+ Wire_Mark : Wire_Id;
+ Subprg_Phi : Phi_Type;
+ begin
+ Mark (Wire_Mark);
+ C := (Mode => Mode_Dynamic,
+ Inst => Sub_Inst,
+ Cur_Loop => null,
+ W_En => No_Wire_Id,
+ W_Ret => No_Wire_Id,
+ W_Val => No_Wire_Id,
+ Ret_Init => No_Net,
+ Ret_Value => No_Valtyp,
+ Ret_Typ => null,
+ Nbr_Ret => 0);
+
+ C.W_En := Alloc_Wire (Wire_Variable, (Imp, Bit_Type));
+ C.W_Ret := Alloc_Wire (Wire_Variable, (Imp, Bit_Type));
+
+ if Is_Func then
+ C.W_Val := Alloc_Wire (Wire_Variable, (Imp, null));
+ end if;
+
+ -- Create a phi so that all assignments are gathered.
+ Push_Phi;
+
+ Synth_Subprogram_Association_Wires (Sub_Inst, Init);
+
+ if Is_Func then
+ -- Set a default value for the return.
+ C.Ret_Typ := Get_Subtype_Object (Syn_Inst, Get_Return_Type (Imp));
+
+ Set_Wire_Gate (C.W_Val,
+ Build_Control_Signal (Sub_Inst, C.Ret_Typ.W, Imp));
+ C.Ret_Init := Build_Const_X (Ctxt, C.Ret_Typ.W);
+ Phi_Assign_Net (Ctxt, C.W_Val, C.Ret_Init, 0);
+ end if;
+
+ Set_Wire_Gate
+ (C.W_En, Build_Control_Signal (Sub_Inst, 1, Imp));
+ Phi_Assign_Static (C.W_En, Bit1);
+
+ Set_Wire_Gate
+ (C.W_Ret, Build_Control_Signal (Sub_Inst, 1, Imp));
+ Phi_Assign_Static (C.W_Ret, Bit1);
+
+ Vhdl_Decls.Synth_Declarations
+ (C.Inst, Get_Declaration_Chain (Bod), True);
+ if not Is_Error (C.Inst) then
+ Synth_Sequential_Statements (C, Get_Sequential_Statement_Chain (Bod));
+ end if;
+
+ if Is_Error (C.Inst) then
+ Res := No_Valtyp;
+ else
+ if Is_Func then
+ if C.Nbr_Ret = 0 then
+ raise Internal_Error;
+ elsif C.Nbr_Ret = 1 and then Is_Static (C.Ret_Value.Val) then
+ Res := C.Ret_Value;
+ else
+ Res := Create_Value_Net
+ (Get_Current_Value (Ctxt, C.W_Val), C.Ret_Value.Typ);
+ end if;
+ else
+ Res := No_Valtyp;
+ Synth_Subprogram_Back_Association (C.Inst, Syn_Inst, Init, Infos);
+ end if;
+ end if;
+
+ Pop_Phi (Subprg_Phi);
+
+ Vhdl_Decls.Finalize_Declarations
+ (C.Inst, Get_Declaration_Chain (Bod), True);
+ pragma Unreferenced (Infos);
+
+ -- Propagate assignments.
+ -- Wires that have been created for this subprogram will be destroyed.
+ -- But assignment for outer wires (passed through parameters) have
+ -- to be kept. We cannot merge phi because this won't be allowed for
+ -- local wires.
+ Propagate_Phi_Until_Mark (Ctxt, Subprg_Phi, Wire_Mark);
+
+ -- Free wires.
+ -- These wires are currently unassigned because they were created
+ -- within the Phi.
+ Free_Wire (C.W_En);
+ Free_Wire (C.W_Ret);
+ if Is_Func then
+ Free_Wire (C.W_Val);
+ end if;
+
+ Release (Wire_Mark);
+
+ return Res;
+ end Synth_Dynamic_Subprogram_Call;
+
+ function Synth_Static_Subprogram_Call (Syn_Inst : Synth_Instance_Acc;
+ Sub_Inst : Synth_Instance_Acc;
+ Call : Node;
+ Bod : Node;
+ Init : Association_Iterator_Init;
+ Infos : Target_Info_Array)
+ return Valtyp
+ is
+ Imp : constant Node := Get_Implementation (Call);
+ Is_Func : constant Boolean := Is_Function_Declaration (Imp);
+ Res : Valtyp;
+ C : Seq_Context (Mode_Static);
+ begin
+ C := (Mode_Static,
+ Inst => Sub_Inst,
+ Cur_Loop => null,
+ S_En => True,
+ Ret_Value => No_Valtyp,
+ Ret_Typ => null,
+ Nbr_Ret => 0);
+
+ if Is_Func then
+ -- Set a default value for the return.
+ C.Ret_Typ := Get_Subtype_Object (Syn_Inst, Get_Return_Type (Imp));
+ end if;
+
+ Synth_Declarations (C.Inst, Get_Declaration_Chain (Bod), True);
+
+ if not Is_Error (C.Inst) then
+ Synth_Sequential_Statements (C, Get_Sequential_Statement_Chain (Bod));
+ end if;
+
+ if Is_Error (C.Inst) then
+ Res := No_Valtyp;
+ else
+ if Is_Func then
+ if C.Nbr_Ret = 0 then
+ Error_Msg_Synth
+ (+Call, "function call completed without a return statement");
+ Res := No_Valtyp;
+ else
+ pragma Assert (C.Nbr_Ret = 1);
+ pragma Assert (Is_Static (C.Ret_Value.Val));
+ Res := C.Ret_Value;
+ end if;
+ else
+ Res := No_Valtyp;
+ Synth_Subprogram_Back_Association (C.Inst, Syn_Inst, Init, Infos);
+ end if;
+ end if;
+
+ Vhdl_Decls.Finalize_Declarations
+ (C.Inst, Get_Declaration_Chain (Bod), True);
+ pragma Unreferenced (Infos);
+
+ return Res;
+ end Synth_Static_Subprogram_Call;
+
+ function Synth_Subprogram_Call (Syn_Inst : Synth_Instance_Acc;
+ Call : Node;
+ Init : Association_Iterator_Init)
+ return Valtyp
+ is
+ Ctxt : constant Context_Acc := Get_Build (Syn_Inst);
+ Imp : constant Node := Get_Implementation (Call);
+ Is_Func : constant Boolean := Is_Function_Declaration (Imp);
+ Bod : constant Node := Vhdl.Sem_Inst.Get_Subprogram_Body_Origin (Imp);
+ Nbr_Inout : constant Natural := Count_Associations (Init);
+ Infos : Target_Info_Array (1 .. Nbr_Inout);
+ Area_Mark : Areapools.Mark_Type;
+ Res : Valtyp;
+ Sub_Inst : Synth_Instance_Acc;
+ Up_Inst : Synth_Instance_Acc;
+ begin
+ Areapools.Mark (Area_Mark, Instance_Pool.all);
+
+ Up_Inst := Get_Instance_By_Scope (Syn_Inst, Get_Parent_Scope (Imp));
+ Sub_Inst := Make_Instance (Up_Inst, Bod, New_Internal_Name (Ctxt));
+ Set_Instance_Base (Sub_Inst, Syn_Inst);
+
+ Synth_Subprogram_Association (Sub_Inst, Syn_Inst, Init, Infos);
+
+ if Is_Error (Sub_Inst) then
+ Res := No_Valtyp;
+ else
+ if not Is_Func then
+ if Get_Purity_State (Imp) /= Pure then
+ Set_Instance_Const (Sub_Inst, False);
+ end if;
+ end if;
+
+ if Get_Instance_Const (Sub_Inst) then
+ Res := Synth_Static_Subprogram_Call
+ (Syn_Inst, Sub_Inst, Call, Bod, Init, Infos);
+ else
+ Res := Synth_Dynamic_Subprogram_Call
+ (Syn_Inst, Sub_Inst, Call, Init, Infos);
+ end if;
+ end if;
+
+ -- Propagate error.
+ if Is_Error (Sub_Inst) then
+ Set_Error (Syn_Inst);
+ end if;
+
+ if Debugger.Flag_Need_Debug then
+ Debugger.Debug_Leave (Sub_Inst);
+ end if;
+
+ Free_Instance (Sub_Inst);
+ Areapools.Release (Area_Mark, Instance_Pool.all);
+
+ return Res;
+ end Synth_Subprogram_Call;
+
+ function Synth_Subprogram_Call
+ (Syn_Inst : Synth_Instance_Acc; Call : Node) return Valtyp
+ is
+ Imp : constant Node := Get_Implementation (Call);
+ Assoc_Chain : constant Node := Get_Parameter_Association_Chain (Call);
+ Inter_Chain : constant Node := Get_Interface_Declaration_Chain (Imp);
+ Init : Association_Iterator_Init;
+ begin
+ Init := Association_Iterator_Build (Inter_Chain, Assoc_Chain);
+ return Synth_Subprogram_Call (Syn_Inst, Call, Init);
+ end Synth_Subprogram_Call;
+
+ function Synth_User_Operator (Syn_Inst : Synth_Instance_Acc;
+ Left_Expr : Node;
+ Right_Expr : Node;
+ Expr : Node) return Valtyp
+ is
+ Imp : constant Node := Get_Implementation (Expr);
+ Inter_Chain : constant Node := Get_Interface_Declaration_Chain (Imp);
+ Init : Association_Iterator_Init;
+ begin
+ Init := Association_Iterator_Build (Inter_Chain, Left_Expr, Right_Expr);
+ return Synth_Subprogram_Call (Syn_Inst, Expr, Init);
+ end Synth_User_Operator;
+
+ procedure Synth_Implicit_Procedure_Call
+ (Syn_Inst : Synth_Instance_Acc; Call : Node)
+ is
+ Ctxt : constant Context_Acc := Get_Build (Syn_Inst);
+ Imp : constant Node := Get_Implementation (Call);
+ Assoc_Chain : constant Node := Get_Parameter_Association_Chain (Call);
+ Inter_Chain : constant Node := Get_Interface_Declaration_Chain (Imp);
+ Init : constant Association_Iterator_Init :=
+ Association_Iterator_Build (Inter_Chain, Assoc_Chain);
+ Nbr_Inout : constant Natural := Count_Associations (Init);
+ Infos : Target_Info_Array (1 .. Nbr_Inout);
+ Area_Mark : Areapools.Mark_Type;
+ Sub_Inst : Synth_Instance_Acc;
+ begin
+ Areapools.Mark (Area_Mark, Instance_Pool.all);
+ Sub_Inst := Make_Instance (Syn_Inst, Imp, New_Internal_Name (Ctxt));
+
+ Synth_Subprogram_Association (Sub_Inst, Syn_Inst, Init, Infos);
+
+ Synth.Vhdl_Static_Proc.Synth_Static_Procedure (Sub_Inst, Imp, Call);
+
+ Synth_Subprogram_Back_Association (Sub_Inst, Syn_Inst, Init, Infos);
+
+ Free_Instance (Sub_Inst);
+ Areapools.Release (Area_Mark, Instance_Pool.all);
+ end Synth_Implicit_Procedure_Call;
+
+ procedure Synth_Procedure_Call
+ (Syn_Inst : Synth_Instance_Acc; Stmt : Node)
+ is
+ Call : constant Node := Get_Procedure_Call (Stmt);
+ Imp : constant Node := Get_Implementation (Call);
+ Res : Valtyp;
+ begin
+ case Get_Implicit_Definition (Imp) is
+ when Iir_Predefined_None =>
+ if Get_Foreign_Flag (Imp) then
+ Error_Msg_Synth
+ (+Stmt, "call to foreign %n is not supported", +Imp);
+ else
+ Res := Synth_Subprogram_Call (Syn_Inst, Call);
+ pragma Assert (Res = No_Valtyp);
+ end if;
+ when others =>
+ Synth_Implicit_Procedure_Call (Syn_Inst, Call);
+ end case;
+ end Synth_Procedure_Call;
+
+ procedure Update_Index (Rng : Discrete_Range_Type; V : in out Valtyp)
+ is
+ T : Int64;
+ begin
+ T := Read_Discrete (V);
+ case Rng.Dir is
+ when Dir_To =>
+ T := T + 1;
+ when Dir_Downto =>
+ T := T - 1;
+ end case;
+ Write_Discrete (V, T);
+ end Update_Index;
+
+ -- Return True iff WID is a static wire and its value is V.
+ function Is_Static_Bit (Wid : Wire_Id; V : Ghdl_U8) return Boolean
+ is
+ M : Memtyp;
+ begin
+ if not Is_Static_Wire (Wid) then
+ return False;
+ end if;
+ M := Get_Static_Wire (Wid);
+ return Read_U8 (M) = V;
+ end Is_Static_Bit;
+
+ function Is_Static_Bit0 (Wid : Wire_Id) return Boolean is
+ begin
+ return Is_Static_Bit (Wid, 0);
+ end Is_Static_Bit0;
+
+ function Is_Static_Bit1 (Wid : Wire_Id) return Boolean is
+ begin
+ return Is_Static_Bit (Wid, 1);
+ end Is_Static_Bit1;
+
+ pragma Inline (Is_Static_Bit0);
+ pragma Inline (Is_Static_Bit1);
+
+ procedure Loop_Control_Init (C : Seq_Context; Stmt : Node)
+ is
+ Lc : constant Loop_Context_Acc := C.Cur_Loop;
+ begin
+ -- We might create new wires that will be destroy at the end of the
+ -- loop. Use mark and sweep to control their lifetime.
+ Mark (C.Cur_Loop.Wire_Mark);
+
+ if Lc.Prev_Loop /= null and then Lc.Prev_Loop.Need_Quit then
+ -- An exit or next statement that targets an outer loop may suspend
+ -- the execution of this loop.
+ Lc.W_Quit := Alloc_Wire (Wire_Variable, (Lc.Loop_Stmt, Bit_Type));
+ Set_Wire_Gate (Lc.W_Quit, Build_Control_Signal (C.Inst, 1, Stmt));
+ Phi_Assign_Static (Lc.W_Quit, Bit1);
+ end if;
+
+ if Get_Exit_Flag (Stmt) or else Get_Next_Flag (Stmt) then
+ -- There is an exit or next statement that target this loop.
+ -- We need to save W_En, as if the execution is suspended due to
+ -- exit or next, it will resume at the end of the loop.
+ if Is_Static_Wire (C.W_En) then
+ pragma Assert (Is_Static_Bit1 (C.W_En));
+ Lc.Saved_En := No_Net;
+ else
+ Lc.Saved_En := Get_Current_Value (null, C.W_En);
+ end if;
+ -- Subloops may be suspended if there is an exit or a next statement
+ -- for this loop within subloops.
+ Lc.Need_Quit := True;
+ end if;
+
+ if Get_Exit_Flag (Stmt) then
+ -- There is an exit statement for this loop. Create the wire.
+ Lc.W_Exit := Alloc_Wire (Wire_Variable, (Lc.Loop_Stmt, Bit_Type));
+ Set_Wire_Gate (Lc.W_Exit, Build_Control_Signal (C.Inst, 1, Stmt));
+ Phi_Assign_Static (Lc.W_Exit, Bit1);
+ end if;
+ end Loop_Control_Init;
+
+ procedure Loop_Control_And_Start (Is_Net : out Boolean;
+ S : out Boolean;
+ N : out Net;
+ En : Net) is
+ begin
+ if En = No_Net then
+ Is_Net := False;
+ N := No_Net;
+ S := True;
+ else
+ Is_Net := True;
+ N := En;
+ S := True;
+ end if;
+ end Loop_Control_And_Start;
+
+ procedure Loop_Control_And (C : Seq_Context;
+ Is_Net : in out Boolean;
+ S : in out Boolean;
+ N : in out Net;
+ R : Wire_Id)
+ is
+ Res : Net;
+ begin
+ if R = No_Wire_Id or else Is_Static_Bit1 (R) then
+ -- No change.
+ return;
+ end if;
+
+ if Is_Static_Bit0 (R) then
+ -- Stays 0.
+ Is_Net := False;
+ S := False;
+ N := No_Net;
+ return;
+ end if;
+
+ if not Is_Net and then not S then
+ -- Was 0, remains 0.
+ return;
+ end if;
+
+ pragma Assert (Is_Net or else S);
+
+ -- Optimize common cases.
+ Res := Get_Current_Value (null, R);
+
+ if Is_Net then
+ N := Build_Dyadic (Get_Build (C.Inst), Id_And, N, Res);
+ Set_Location (N, C.Cur_Loop.Loop_Stmt);
+ else
+ N := Res;
+ end if;
+
+ Is_Net := True;
+ end Loop_Control_And;
+
+ procedure Loop_Control_And_Assign (C : Seq_Context;
+ Is_Net : Boolean;
+ S : Boolean;
+ N : Net;
+ W : Wire_Id) is
+ begin
+ if Is_Net then
+ Phi_Assign_Net (Get_Build (C.Inst), W, N, 0);
+ else
+ if S then
+ Phi_Assign_Static (W, Bit1);
+ else
+ Phi_Assign_Static (W, Bit0);
+ end if;
+ end if;
+ end Loop_Control_And_Assign;
+
+ procedure Loop_Control_Update (C : Seq_Context)
+ is
+ Lc : constant Loop_Context_Acc := C.Cur_Loop;
+ N : Net;
+ S : Boolean;
+ Is_Net : Boolean;
+ begin
+ if not Lc.Need_Quit then
+ -- No next/exit statement for this loop. So no control.
+ return;
+ end if;
+
+ -- Execution continue iff:
+ -- 1. Loop was enabled (Lc.Saved_En)
+ Loop_Control_And_Start (Is_Net, S, N, Lc.Saved_En);
+
+ -- 2. No return (C.W_Ret)
+ Loop_Control_And (C, Is_Net, S, N, C.W_Ret);
+
+ -- 3. No exit.
+ Loop_Control_And (C, Is_Net, S, N, Lc.W_Exit);
+
+ -- 4. No quit.
+ Loop_Control_And (C, Is_Net, S, N, Lc.W_Quit);
+
+ Loop_Control_And_Assign (C, Is_Net, S, N, C.W_En);
+ end Loop_Control_Update;
+
+ procedure Loop_Control_Finish (C : Seq_Context)
+ is
+ Lc : constant Loop_Context_Acc := C.Cur_Loop;
+ N : Net;
+ S : Boolean;
+ Is_Net : Boolean;
+ begin
+ -- Execution continue after this loop iff:
+ -- 1. Loop was enabled (Lc.Saved_En)
+ Loop_Control_And_Start (Is_Net, S, N, Lc.Saved_En);
+
+ -- 2. No return (C.W_Ret)
+ Loop_Control_And (C, Is_Net, S, N, C.W_Ret);
+
+ -- 3. No quit (C.W_Quit)
+ Loop_Control_And (C, Is_Net, S, N, Lc.W_Quit);
+
+ Phi_Discard_Wires (Lc.W_Quit, Lc.W_Exit);
+
+ if Lc.W_Quit /= No_Wire_Id then
+ Free_Wire (Lc.W_Quit);
+ end if;
+
+ if Lc.W_Exit /= No_Wire_Id then
+ Free_Wire (Lc.W_Exit);
+ end if;
+
+ Release (C.Cur_Loop.Wire_Mark);
+
+ Loop_Control_And_Assign (C, Is_Net, S, N, C.W_En);
+ end Loop_Control_Finish;
+
+ procedure Synth_Dynamic_Exit_Next_Statement
+ (C : in out Seq_Context; Stmt : Node)
+ is
+ Ctxt : constant Context_Acc := Get_Build (C.Inst);
+ Cond : constant Node := Get_Condition (Stmt);
+ Is_Exit : constant Boolean := Get_Kind (Stmt) = Iir_Kind_Exit_Statement;
+ Static_Cond : Boolean;
+ Loop_Label : Node;
+ Lc : Loop_Context_Acc;
+ Cond_Val : Valtyp;
+ Phi_True : Phi_Type;
+ Phi_False : Phi_Type;
+ begin
+ if Cond /= Null_Node then
+ Cond_Val := Synth_Expression (C.Inst, Cond);
+ Static_Cond := Is_Static_Val (Cond_Val.Val);
+ if Static_Cond then
+ if Get_Static_Discrete (Cond_Val) = 0 then
+ -- Not executed.
+ return;
+ end if;
+ else
+ -- Create a branch for the True case.
+ Push_Phi;
+ end if;
+ end if;
+
+ -- Execution is suspended for the current sequence of statements.
+ Phi_Assign_Static (C.W_En, Bit0);
+
+ Lc := C.Cur_Loop;
+
+ -- Compute the loop statement indicated by the exit/next statement.
+ Loop_Label := Get_Loop_Label (Stmt);
+ if Loop_Label = Null_Node then
+ Loop_Label := Lc.Loop_Stmt;
+ else
+ Loop_Label := Get_Named_Entity (Loop_Label);
+ end if;
+
+ -- Update the W_Exit and W_Quit flags for the loops. All the loops
+ -- until the label are canceled.
+ loop
+ if Lc.Loop_Stmt = Loop_Label then
+ -- Final loop.
+ if Is_Exit then
+ Phi_Assign_Static (Lc.W_Exit, Bit0);
+ end if;
+ exit;
+ else
+ Phi_Assign_Static (Lc.W_Quit, Bit0);
+ end if;
+ Lc := Lc.Prev_Loop;
+ end loop;
+
+ if Cond /= Null_Node and not Static_Cond then
+ Pop_Phi (Phi_True);
+
+ -- If the condition is false, do nothing.
+ Push_Phi;
+ Pop_Phi (Phi_False);
+
+ Merge_Phis (Ctxt, Get_Net (Ctxt, Cond_Val), Phi_True, Phi_False,
+ Get_Location (Stmt));
+ end if;
+ end Synth_Dynamic_Exit_Next_Statement;
+
+ procedure Synth_Static_Exit_Next_Statement
+ (C : in out Seq_Context; Stmt : Node)
+ is
+ Cond : constant Node := Get_Condition (Stmt);
+ Is_Exit : constant Boolean := Get_Kind (Stmt) = Iir_Kind_Exit_Statement;
+ Loop_Label : Node;
+ Lc : Loop_Context_Acc;
+ Cond_Val : Valtyp;
+ begin
+ if Cond /= Null_Node then
+ Cond_Val := Synth_Expression (C.Inst, Cond);
+ if Cond_Val = No_Valtyp then
+ Set_Error (C.Inst);
+ return;
+ end if;
+ pragma Assert (Is_Static_Val (Cond_Val.Val));
+ if Get_Static_Discrete (Cond_Val) = 0 then
+ -- Not executed.
+ return;
+ end if;
+ end if;
+
+ -- Execution is suspended.
+ C.S_En := False;
+
+ Lc := C.Cur_Loop;
+
+ Loop_Label := Get_Loop_Label (Stmt);
+ if Loop_Label = Null_Node then
+ Loop_Label := Lc.Loop_Stmt;
+ else
+ Loop_Label := Get_Named_Entity (Loop_Label);
+ end if;
+
+ loop
+ if Lc.Loop_Stmt = Loop_Label then
+ if Is_Exit then
+ Lc.S_Exit := True;
+ end if;
+ exit;
+ else
+ Lc.S_Quit := True;
+ end if;
+ Lc := Lc.Prev_Loop;
+ end loop;
+ end Synth_Static_Exit_Next_Statement;
+
+ procedure Init_For_Loop_Statement (C : in out Seq_Context;
+ Stmt : Node;
+ Val : out Valtyp)
+ is
+ Iterator : constant Node := Get_Parameter_Specification (Stmt);
+ It_Type : constant Node := Get_Declaration_Type (Iterator);
+ It_Rng : Type_Acc;
+ begin
+ if It_Type /= Null_Node then
+ Synth_Subtype_Indication (C.Inst, It_Type);
+ end if;
+
+ -- Initial value.
+ It_Rng := Get_Subtype_Object (C.Inst, Get_Type (Iterator));
+ Val := Create_Value_Discrete (It_Rng.Drange.Left, It_Rng);
+ Create_Object (C.Inst, Iterator, Val);
+ end Init_For_Loop_Statement;
+
+ procedure Finish_For_Loop_Statement (C : in out Seq_Context;
+ Stmt : Node)
+ is
+ Iterator : constant Node := Get_Parameter_Specification (Stmt);
+ It_Type : constant Node := Get_Declaration_Type (Iterator);
+ begin
+ Destroy_Object (C.Inst, Iterator);
+ if It_Type /= Null_Node then
+ Destroy_Object (C.Inst, It_Type);
+ end if;
+ end Finish_For_Loop_Statement;
+
+ procedure Synth_Dynamic_For_Loop_Statement
+ (C : in out Seq_Context; Stmt : Node)
+ is
+ Stmts : constant Node := Get_Sequential_Statement_Chain (Stmt);
+ Val : Valtyp;
+ Lc : aliased Loop_Context (Mode_Dynamic);
+ begin
+ Lc := (Mode => Mode_Dynamic,
+ Prev_Loop => C.Cur_Loop,
+ Loop_Stmt => Stmt,
+ Need_Quit => False,
+ Saved_En => No_Net,
+ W_Exit => No_Wire_Id,
+ W_Quit => No_Wire_Id,
+ Wire_Mark => No_Wire_Id);
+ C.Cur_Loop := Lc'Unrestricted_Access;
+
+ Loop_Control_Init (C, Stmt);
+
+ Init_For_Loop_Statement (C, Stmt, Val);
+
+ while In_Range (Val.Typ.Drange, Read_Discrete (Val)) loop
+ Synth_Sequential_Statements (C, Stmts);
+
+ Update_Index (Val.Typ.Drange, Val);
+ Loop_Control_Update (C);
+
+ -- Constant exit.
+ exit when Is_Static_Bit0 (C.W_En);
+
+ -- FIXME: dynamic exits.
+ end loop;
+ Loop_Control_Finish (C);
+
+ Finish_For_Loop_Statement (C, Stmt);
+
+ C.Cur_Loop := Lc.Prev_Loop;
+ end Synth_Dynamic_For_Loop_Statement;
+
+ procedure Synth_Static_For_Loop_Statement
+ (C : in out Seq_Context; Stmt : Node)
+ is
+ Stmts : constant Node := Get_Sequential_Statement_Chain (Stmt);
+ Val : Valtyp;
+ Lc : aliased Loop_Context (Mode_Static);
+ begin
+ Lc := (Mode_Static,
+ Prev_Loop => C.Cur_Loop,
+ Loop_Stmt => Stmt,
+ S_Exit => False,
+ S_Quit => False);
+ C.Cur_Loop := Lc'Unrestricted_Access;
+
+ Init_For_Loop_Statement (C, Stmt, Val);
+
+ while In_Range (Val.Typ.Drange, Read_Discrete (Val)) loop
+ Synth_Sequential_Statements (C, Stmts);
+ C.S_En := True;
+
+ Update_Index (Val.Typ.Drange, Val);
+
+ exit when Lc.S_Exit or Lc.S_Quit or C.Nbr_Ret > 0;
+ end loop;
+
+ Finish_For_Loop_Statement (C, Stmt);
+
+ C.Cur_Loop := Lc.Prev_Loop;
+ end Synth_Static_For_Loop_Statement;
+
+ procedure Synth_Dynamic_While_Loop_Statement
+ (C : in out Seq_Context; Stmt : Node)
+ is
+ Stmts : constant Node := Get_Sequential_Statement_Chain (Stmt);
+ Cond : constant Node := Get_Condition (Stmt);
+ Val : Valtyp;
+ Lc : aliased Loop_Context (Mode_Dynamic);
+ Iter_Nbr : Natural;
+ begin
+ Lc := (Mode => Mode_Dynamic,
+ Prev_Loop => C.Cur_Loop,
+ Loop_Stmt => Stmt,
+ Need_Quit => False,
+ Saved_En => No_Net,
+ W_Exit => No_Wire_Id,
+ W_Quit => No_Wire_Id,
+ Wire_Mark => No_Wire_Id);
+ C.Cur_Loop := Lc'Unrestricted_Access;
+
+ Iter_Nbr := 0;
+
+ Loop_Control_Init (C, Stmt);
+
+ loop
+ if Cond /= Null_Node then
+ Val := Synth_Expression_With_Type (C.Inst, Cond, Boolean_Type);
+ if not Is_Static (Val.Val) then
+ Error_Msg_Synth (+Cond, "loop condition must be static");
+ exit;
+ end if;
+ exit when Read_Discrete (Val) = 0;
+ end if;
+
+ Synth_Sequential_Statements (C, Stmts);
+
+ Loop_Control_Update (C);
+
+ -- Exit from the loop if W_Exit/W_Ret/W_Quit = 0
+ exit when Lc.W_Exit /= No_Wire_Id and then Is_Static_Bit0 (Lc.W_Exit);
+ exit when C.W_Ret /= No_Wire_Id and then Is_Static_Bit0 (C.W_Ret);
+ exit when Lc.W_Quit /= No_Wire_Id and then Is_Static_Bit0 (Lc.W_Quit);
+
+ Iter_Nbr := Iter_Nbr + 1;
+ if Iter_Nbr > Flags.Flag_Max_Loop and Flags.Flag_Max_Loop /= 0 then
+ Error_Msg_Synth
+ (+Stmt, "maximum number of iterations (%v) reached",
+ +Uns32 (Flags.Flag_Max_Loop));
+ exit;
+ end if;
+ end loop;
+ Loop_Control_Finish (C);
+
+ C.Cur_Loop := Lc.Prev_Loop;
+ end Synth_Dynamic_While_Loop_Statement;
+
+ procedure Synth_Static_While_Loop_Statement
+ (C : in out Seq_Context; Stmt : Node)
+ is
+ Stmts : constant Node := Get_Sequential_Statement_Chain (Stmt);
+ Cond : constant Node := Get_Condition (Stmt);
+ Val : Valtyp;
+ Lc : aliased Loop_Context (Mode_Static);
+ begin
+ Lc := (Mode => Mode_Static,
+ Prev_Loop => C.Cur_Loop,
+ Loop_Stmt => Stmt,
+ S_Exit => False,
+ S_Quit => False);
+ C.Cur_Loop := Lc'Unrestricted_Access;
+
+ loop
+ if Cond /= Null_Node then
+ Val := Synth_Expression_With_Type (C.Inst, Cond, Boolean_Type);
+ pragma Assert (Is_Static (Val.Val));
+ exit when Read_Discrete (Val) = 0;
+ end if;
+
+ Synth_Sequential_Statements (C, Stmts);
+ C.S_En := True;
+
+ -- Exit from the loop if S_Exit/S_Quit
+ exit when Lc.S_Exit or Lc.S_Quit or C.Nbr_Ret > 0;
+ end loop;
+
+ C.Cur_Loop := Lc.Prev_Loop;
+ end Synth_Static_While_Loop_Statement;
+
+ procedure Synth_Return_Statement (C : in out Seq_Context; Stmt : Node)
+ is
+ Is_Dyn : constant Boolean := not Get_Instance_Const (C.Inst);
+ Ctxt : constant Context_Acc := Get_Build (C.Inst);
+ Val : Valtyp;
+ Expr : constant Node := Get_Expression (Stmt);
+ begin
+ if Expr /= Null_Node then
+ -- Return in function.
+ Val := Synth_Expression_With_Type (C.Inst, Expr, C.Ret_Typ);
+ if Val = No_Valtyp then
+ Set_Error (C.Inst);
+ return;
+ end if;
+
+ Val := Synth_Subtype_Conversion (Ctxt, Val, C.Ret_Typ, True, Stmt);
+
+ if C.Nbr_Ret = 0 then
+ C.Ret_Value := Val;
+ if not Is_Bounded_Type (C.Ret_Typ) then
+ -- The function was declared with an unconstrained return type.
+ -- Now that a value has been returned, we know the subtype of
+ -- the returned values. So adjust it.
+ -- All the returned values must have the same length.
+ C.Ret_Typ := Val.Typ;
+ if Is_Dyn then
+ Set_Width (Get_Wire_Gate (C.W_Val), C.Ret_Typ.W);
+ Set_Width (C.Ret_Init, C.Ret_Typ.W);
+ end if;
+ end if;
+ end if;
+ if Is_Dyn then
+ Phi_Assign_Net (Ctxt, C.W_Val, Get_Net (Ctxt, Val), 0);
+ end if;
+ end if;
+
+ if Is_Dyn then
+ -- The subprogram has returned. Do not execute further statements.
+ Phi_Assign_Static (C.W_En, Bit0);
+
+ if C.W_Ret /= No_Wire_Id then
+ Phi_Assign_Static (C.W_Ret, Bit0);
+ end if;
+ end if;
+
+ C.Nbr_Ret := C.Nbr_Ret + 1;
+ end Synth_Return_Statement;
+
+ procedure Synth_Static_Report (Syn_Inst : Synth_Instance_Acc; Stmt : Node)
+ is
+ use Simple_IO;
+
+ Is_Report : constant Boolean :=
+ Get_Kind (Stmt) = Iir_Kind_Report_Statement;
+ Rep_Expr : constant Node := Get_Report_Expression (Stmt);
+ Sev_Expr : constant Node := Get_Severity_Expression (Stmt);
+ Rep : Valtyp;
+ Sev : Valtyp;
+ Sev_V : Natural;
+ begin
+ if Rep_Expr /= Null_Node then
+ Rep := Synth_Expression_With_Basetype (Syn_Inst, Rep_Expr);
+ if Rep = No_Valtyp then
+ Set_Error (Syn_Inst);
+ return;
+ end if;
+ Strip_Const (Rep);
+ end if;
+ if Sev_Expr /= Null_Node then
+ Sev := Synth_Expression (Syn_Inst, Sev_Expr);
+ if Sev = No_Valtyp then
+ Set_Error (Syn_Inst);
+ return;
+ end if;
+ Strip_Const (Sev);
+ end if;
+
+ Put_Err (Disp_Location (Stmt));
+ Put_Err (":(");
+ if Is_Report then
+ Put_Err ("report");
+ else
+ Put_Err ("assertion");
+ end if;
+ Put_Err (' ');
+ if Sev = No_Valtyp then
+ if Is_Report then
+ Sev_V := 0;
+ else
+ Sev_V := 2;
+ end if;
+ else
+ Sev_V := Natural (Read_Discrete (Sev));
+ end if;
+ case Sev_V is
+ when Note_Severity =>
+ Put_Err ("note");
+ when Warning_Severity =>
+ Put_Err ("warning");
+ when Error_Severity =>
+ Put_Err ("error");
+ when Failure_Severity =>
+ Put_Err ("failure");
+ when others =>
+ Put_Err ("??");
+ end case;
+ Put_Err ("): ");
+
+ if Rep = No_Valtyp then
+ Put_Line_Err ("assertion failure");
+ else
+ Put_Line_Err (Value_To_String (Rep));
+ end if;
+
+ if Sev_V >= Flags.Severity_Level then
+ Error_Msg_Synth (+Stmt, "error due to assertion failure");
+ end if;
+ end Synth_Static_Report;
+
+ procedure Synth_Static_Report_Statement (C : Seq_Context; Stmt : Node) is
+ begin
+ Synth_Static_Report (C.Inst, Stmt);
+ end Synth_Static_Report_Statement;
+
+ procedure Synth_Static_Assertion_Statement (C : Seq_Context; Stmt : Node)
+ is
+ Cond : Valtyp;
+ begin
+ Cond := Synth_Expression (C.Inst, Get_Assertion_Condition (Stmt));
+ if Cond = No_Valtyp then
+ Set_Error (C.Inst);
+ return;
+ end if;
+ pragma Assert (Is_Static (Cond.Val));
+ Strip_Const (Cond);
+ if Read_Discrete (Cond) = 1 then
+ return;
+ end if;
+ Synth_Static_Report (C.Inst, Stmt);
+ end Synth_Static_Assertion_Statement;
+
+ procedure Synth_Dynamic_Assertion_Statement (C : Seq_Context; Stmt : Node)
+ is
+ Ctxt : constant Context_Acc := Get_Build (C.Inst);
+ Loc : constant Location_Type := Get_Location (Stmt);
+ Cond : Valtyp;
+ N : Net;
+ En : Net;
+ Inst : Instance;
+ begin
+ if not Flags.Flag_Formal then
+ return;
+ end if;
+
+ Cond := Synth_Expression (C.Inst, Get_Assertion_Condition (Stmt));
+ if Cond = No_Valtyp then
+ Set_Error (C.Inst);
+ return;
+ end if;
+ N := Get_Net (Ctxt, Cond);
+ En := Phi_Enable (Ctxt, (Stmt, Bit_Type), Bit0, Bit1,
+ Get_Location (Stmt));
+ if En /= No_Net then
+ -- Build: En -> Cond
+ N := Build2_Imp (Ctxt, En, N, Loc);
+ end if;
+ Inst := Build_Assert (Ctxt, Synth_Label (C.Inst, Stmt), N);
+ Set_Location (Inst, Loc);
+ end Synth_Dynamic_Assertion_Statement;
+
+ procedure Synth_Sequential_Statements
+ (C : in out Seq_Context; Stmts : Node)
+ is
+ Is_Dyn : constant Boolean := not Get_Instance_Const (C.Inst);
+ Ctxt : constant Context_Acc := Get_Build (C.Inst);
+ Stmt : Node;
+ Phi_T, Phi_F : Phi_Type;
+ Has_Phi : Boolean;
+ begin
+ Stmt := Stmts;
+ while Is_Valid (Stmt) loop
+ if Is_Dyn then
+ pragma Assert (not Is_Static_Bit0 (C.W_En));
+ Has_Phi := not Is_Static_Bit1 (C.W_En);
+ if Has_Phi then
+ Push_Phi;
+ end if;
+ end if;
+
+ if Flags.Flag_Trace_Statements then
+ declare
+ Name : Name_Id;
+ Line : Natural;
+ Col : Natural;
+ begin
+ Files_Map.Location_To_Position
+ (Get_Location (Stmt), Name, Line, Col);
+ Simple_IO.Put_Line ("Execute statement at "
+ & Name_Table.Image (Name)
+ & Natural'Image (Line));
+ end;
+ end if;
+ if Synth.Debugger.Flag_Need_Debug then
+ Synth.Debugger.Debug_Break (C.Inst, Stmt);
+ end if;
+
+ case Get_Kind (Stmt) is
+ when Iir_Kind_If_Statement =>
+ Synth_If_Statement (C, Stmt);
+ when Iir_Kind_Simple_Signal_Assignment_Statement =>
+ Synth_Simple_Signal_Assignment (C.Inst, Stmt);
+ when Iir_Kind_Conditional_Signal_Assignment_Statement =>
+ Synth_Conditional_Signal_Assignment (C.Inst, Stmt);
+ when Iir_Kind_Variable_Assignment_Statement =>
+ Synth_Variable_Assignment (C, Stmt);
+ when Iir_Kind_Conditional_Variable_Assignment_Statement =>
+ Synth_Conditional_Variable_Assignment (C, Stmt);
+ when Iir_Kind_Case_Statement =>
+ Synth_Case_Statement (C, Stmt);
+ when Iir_Kind_For_Loop_Statement =>
+ if Is_Dyn then
+ Synth_Dynamic_For_Loop_Statement (C, Stmt);
+ else
+ Synth_Static_For_Loop_Statement (C, Stmt);
+ end if;
+ when Iir_Kind_While_Loop_Statement =>
+ if Is_Dyn then
+ Synth_Dynamic_While_Loop_Statement (C, Stmt);
+ else
+ Synth_Static_While_Loop_Statement (C, Stmt);
+ end if;
+ when Iir_Kind_Null_Statement =>
+ -- Easy
+ null;
+ when Iir_Kind_Return_Statement =>
+ Synth_Return_Statement (C, Stmt);
+ when Iir_Kind_Procedure_Call_Statement =>
+ Synth_Procedure_Call (C.Inst, Stmt);
+ when Iir_Kind_Report_Statement =>
+ if not Is_Dyn then
+ Synth_Static_Report_Statement (C, Stmt);
+ end if;
+ when Iir_Kind_Assertion_Statement =>
+ if not Is_Dyn then
+ Synth_Static_Assertion_Statement (C, Stmt);
+ else
+ Synth_Dynamic_Assertion_Statement (C, Stmt);
+ end if;
+ when Iir_Kind_Exit_Statement
+ | Iir_Kind_Next_Statement =>
+ if Is_Dyn then
+ Synth_Dynamic_Exit_Next_Statement (C, Stmt);
+ else
+ Synth_Static_Exit_Next_Statement (C, Stmt);
+ end if;
+ when others =>
+ Error_Kind ("synth_sequential_statements", Stmt);
+ end case;
+ if Is_Dyn then
+ if Has_Phi then
+ Pop_Phi (Phi_T);
+ Push_Phi;
+ Pop_Phi (Phi_F);
+ Merge_Phis (Ctxt, Get_Current_Value (Ctxt, C.W_En),
+ Phi_T, Phi_F, Get_Location (Stmt));
+ end if;
+ if Is_Static_Bit0 (C.W_En) then
+ -- Not more execution.
+ return;
+ end if;
+ else
+ if not C.S_En or C.Nbr_Ret /= 0 then
+ return;
+ end if;
+ end if;
+ Stmt := Get_Chain (Stmt);
+ end loop;
+ end Synth_Sequential_Statements;
+
+ Proc_Pool : aliased Areapools.Areapool;
+
+ -- Synthesis of statements of a non-sensitized process.
+ procedure Synth_Process_Sequential_Statements
+ (C : in out Seq_Context; Proc : Node)
+ is
+ Ctxt : constant Context_Acc := Get_Build (C.Inst);
+ Stmt : Node;
+ Cond : Node;
+ Cond_Val : Valtyp;
+ Phi_True : Phi_Type;
+ Phi_False : Phi_Type;
+ begin
+ Stmt := Get_Sequential_Statement_Chain (Proc);
+
+ -- The first statement must be a wait statement.
+ if Get_Kind (Stmt) /= Iir_Kind_Wait_Statement then
+ Error_Msg_Synth (+Stmt, "expect wait as the first statement");
+ return;
+ end if;
+
+ -- Handle the condition as an if.
+ Cond := Get_Condition_Clause (Stmt);
+ if Cond = Null_Node then
+ Error_Msg_Synth (+Stmt, "expect wait condition");
+ return;
+ end if;
+ Cond_Val := Synth_Expression (C.Inst, Cond);
+
+ Push_Phi;
+ Synth_Sequential_Statements (C, Get_Chain (Stmt));
+ Pop_Phi (Phi_True);
+ Push_Phi;
+ Pop_Phi (Phi_False);
+
+ Merge_Phis (Ctxt, Get_Net (Ctxt, Cond_Val), Phi_True, Phi_False,
+ Get_Location (Stmt));
+ end Synth_Process_Sequential_Statements;
+
+ procedure Synth_Process_Statement
+ (Syn_Inst : Synth_Instance_Acc; Proc : Node)
+ is
+ use Areapools;
+ Label : constant Name_Id := Get_Identifier (Proc);
+ Decls_Chain : constant Node := Get_Declaration_Chain (Proc);
+ Prev_Instance_Pool : constant Areapool_Acc := Instance_Pool;
+ Ctxt : constant Context_Acc := Get_Build (Syn_Inst);
+ M : Areapools.Mark_Type;
+ C_Sname : Sname;
+ C : Seq_Context (Mode_Dynamic);
+ begin
+ if Label = Null_Identifier then
+ C_Sname := New_Internal_Name (Ctxt, Get_Sname (Syn_Inst));
+ else
+ C_Sname := New_Sname_User (Label, Get_Sname (Syn_Inst));
+ end if;
+ C := (Mode => Mode_Dynamic,
+ Inst => Make_Instance (Syn_Inst, Proc, C_Sname),
+ Cur_Loop => null,
+ W_En => Alloc_Wire (Wire_Variable, (Proc, Bit_Type)),
+ W_Ret => No_Wire_Id,
+ W_Val => No_Wire_Id,
+ Ret_Init => No_Net,
+ Ret_Value => No_Valtyp,
+ Ret_Typ => null,
+ Nbr_Ret => 0);
+
+ Mark (M, Proc_Pool);
+ Instance_Pool := Proc_Pool'Access;
+
+ Push_Phi;
+
+ Synth_Declarations (C.Inst, Decls_Chain);
+
+ Set_Wire_Gate (C.W_En, Build_Control_Signal (Syn_Inst, 1, Proc));
+ Phi_Assign_Static (C.W_En, Bit1);
+
+ if not Is_Error (C.Inst) then
+ case Iir_Kinds_Process_Statement (Get_Kind (Proc)) is
+ when Iir_Kind_Sensitized_Process_Statement =>
+ Synth_Sequential_Statements
+ (C, Get_Sequential_Statement_Chain (Proc));
+ -- FIXME: check sensitivity list.
+ when Iir_Kind_Process_Statement =>
+ Synth_Process_Sequential_Statements (C, Proc);
+ end case;
+ end if;
+
+ Pop_And_Merge_Phi (Ctxt, Get_Location (Proc));
+
+ Finalize_Declarations (C.Inst, Decls_Chain);
+
+ Free_Instance (C.Inst);
+ Release (M, Proc_Pool);
+ Instance_Pool := Prev_Instance_Pool;
+
+ Finalize_Assignment (Ctxt, C.W_En);
+ Free_Wire (C.W_En);
+ end Synth_Process_Statement;
+
+ function Synth_User_Function_Call
+ (Syn_Inst : Synth_Instance_Acc; Expr : Node) return Valtyp is
+ begin
+ -- Is it a call to an ieee function ?
+ declare
+ Imp : constant Node := Get_Implementation (Expr);
+ Pkg : constant Node := Get_Parent (Imp);
+ Unit : Node;
+ Lib : Node;
+ begin
+ if Get_Kind (Pkg) = Iir_Kind_Package_Declaration
+ and then not Is_Uninstantiated_Package (Pkg)
+ then
+ Unit := Get_Parent (Pkg);
+ if Get_Kind (Unit) = Iir_Kind_Design_Unit then
+ Lib := Get_Library (Get_Design_File (Unit));
+ if Get_Identifier (Lib) = Std_Names.Name_Ieee then
+ Error_Msg_Synth
+ (+Expr, "unhandled call to ieee function %i", +Imp);
+ Set_Error (Syn_Inst);
+ return No_Valtyp;
+ end if;
+ end if;
+ end if;
+ end;
+
+ return Synth_Subprogram_Call (Syn_Inst, Expr);
+ end Synth_User_Function_Call;
+
+ procedure Synth_Concurrent_Assertion_Statement
+ (Syn_Inst : Synth_Instance_Acc; Stmt : Node)
+ is
+ Ctxt : constant Context_Acc := Get_Build (Syn_Inst);
+ Cond : constant Node := Get_Assertion_Condition (Stmt);
+ Val : Valtyp;
+ Inst : Instance;
+ begin
+ Val := Synth_Expression (Syn_Inst, Cond);
+ if Val = No_Valtyp then
+ Set_Error (Syn_Inst);
+ return;
+ end if;
+ if Is_Static (Val.Val) then
+ if Read_Discrete (Val) /= 1 then
+ Synth_Static_Report (Syn_Inst, Stmt);
+ end if;
+ return;
+ end if;
+
+ if not Flags.Flag_Formal then
+ -- Ignore the net.
+ return;
+ end if;
+
+ Inst := Build_Assert
+ (Ctxt, Synth_Label (Syn_Inst, Stmt), Get_Net (Ctxt, Val));
+ Set_Location (Inst, Get_Location (Stmt));
+ end Synth_Concurrent_Assertion_Statement;
+
+ procedure Synth_Block_Statement (Syn_Inst : Synth_Instance_Acc; Blk : Node)
+ is
+ use Areapools;
+ Prev_Instance_Pool : constant Areapool_Acc := Instance_Pool;
+ Blk_Inst : Synth_Instance_Acc;
+ Blk_Sname : Sname;
+ M : Areapools.Mark_Type;
+ begin
+ -- No support for guard or header.
+ if Get_Block_Header (Blk) /= Null_Node
+ or else Get_Guard_Decl (Blk) /= Null_Node
+ then
+ raise Internal_Error;
+ end if;
+
+ Apply_Block_Configuration
+ (Get_Block_Block_Configuration (Blk), Blk);
+
+ Blk_Sname := New_Sname_User (Get_Identifier (Blk), Get_Sname (Syn_Inst));
+ Blk_Inst := Make_Instance (Syn_Inst, Blk, Blk_Sname);
+ Mark (M, Proc_Pool);
+ Instance_Pool := Proc_Pool'Access;
+
+ Synth_Declarations (Blk_Inst, Get_Declaration_Chain (Blk));
+ Synth_Concurrent_Statements
+ (Blk_Inst, Get_Concurrent_Statement_Chain (Blk));
+
+ Synth_Attribute_Values (Blk_Inst, Blk);
+
+ Finalize_Declarations (Blk_Inst, Get_Declaration_Chain (Blk));
+
+ Free_Instance (Blk_Inst);
+ Release (M, Proc_Pool);
+ Instance_Pool := Prev_Instance_Pool;
+ end Synth_Block_Statement;
+
+ function Synth_Psl_NFA (Syn_Inst : Synth_Instance_Acc;
+ NFA : PSL.Types.PSL_NFA;
+ Nbr_States : Int32;
+ States : Net;
+ Loc : Source.Syn_Src) return Net
+ is
+ use PSL.NFAs;
+ Ctxt : constant Context_Acc := Get_Build (Syn_Inst);
+ S : NFA_State;
+ S_Num : Int32;
+ D_Num : Int32;
+ I : Net;
+ Cond : Net;
+ E : NFA_Edge;
+ D_Arr : Net_Array_Acc;
+ Res : Net;
+ begin
+ D_Arr := new Net_Array'(0 .. Nbr_States - 1 => No_Net);
+
+ -- For each state:
+ S := Get_First_State (NFA);
+ while S /= No_State loop
+ S_Num := Get_State_Label (S);
+ I := Build_Extract_Bit (Ctxt, States, Uns32 (S_Num));
+ Set_Location (I, Loc);
+
+ -- For each edge:
+ E := Get_First_Src_Edge (S);
+ while E /= No_Edge loop
+ -- Edge condition.
+ Cond := Build_Dyadic
+ (Ctxt, Id_And,
+ I, Synth_PSL_Expression (Syn_Inst, Get_Edge_Expr (E)));
+ Set_Location (Cond, Loc);
+
+ -- TODO: if EOS is present, then this is a live state.
+
+ -- Reverse order for final concatenation.
+ D_Num := Nbr_States - 1 - Get_State_Label (Get_Edge_Dest (E));
+ if D_Arr (D_Num) /= No_Net then
+ Cond := Build_Dyadic (Ctxt, Id_Or, D_Arr (D_Num), Cond);
+ Set_Location (Cond, Loc);
+ end if;
+ D_Arr (D_Num) := Cond;
+
+ E := Get_Next_Src_Edge (E);
+ end loop;
+
+ S := Get_Next_State (S);
+ end loop;
+
+ if D_Arr (Nbr_States - 1) = No_Net then
+ D_Arr (Nbr_States - 1) := Build_Const_UB32 (Ctxt, 0, 1);
+ end if;
+
+ Concat_Array (Ctxt, D_Arr.all, Res);
+ Free_Net_Array (D_Arr);
+
+ return Res;
+ end Synth_Psl_NFA;
+
+ procedure Synth_Psl_Dff (Syn_Inst : Synth_Instance_Acc;
+ Stmt : Node;
+ Next_States : out Net)
+ is
+ Ctxt : constant Context_Acc := Get_Build (Syn_Inst);
+ Nbr_States : constant Int32 := Get_PSL_Nbr_States (Stmt);
+ States : Net;
+ Init : Net;
+ Clk : Net;
+ Clk_Inst : Instance;
+ begin
+ -- create init net, clock net
+ Init := Build_Const_UB32 (Ctxt, 1, Uns32 (Nbr_States));
+ Set_Location (Init, Stmt);
+ Clk := Synth_PSL_Expression (Syn_Inst, Get_PSL_Clock (Stmt));
+
+ -- Check the clock is an edge and extract it.
+ Clk_Inst := Get_Net_Parent (Clk);
+ 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;
+
+ -- build idff
+ States := Build_Idff (Ctxt, Clk, No_Net, Init);
+ Set_Location (States, Stmt);
+
+ -- create update nets
+ -- For each state: if set, evaluate all outgoing edges.
+ Next_States :=
+ Synth_Psl_NFA (Syn_Inst, Get_PSL_NFA (Stmt), Nbr_States, States, Stmt);
+ Connect (Get_Input (Get_Net_Parent (States), 1), Next_States);
+ end Synth_Psl_Dff;
+
+ function Synth_Psl_Final
+ (Syn_Inst : Synth_Instance_Acc; Stmt : Node; Next_States : Net) return Net
+ is
+ use PSL.Types;
+ use PSL.NFAs;
+ NFA : constant PSL_NFA := Get_PSL_NFA (Stmt);
+ Res : Net;
+ begin
+ Res := Build_Extract_Bit
+ (Get_Build (Syn_Inst), Next_States,
+ Uns32 (Get_State_Label (Get_Final_State (NFA))));
+ Set_Location (Res, Stmt);
+ return Res;
+ end Synth_Psl_Final;
+
+ function Synth_Psl_Not_Final
+ (Syn_Inst : Synth_Instance_Acc; Stmt : Node; Next_States : Net)
+ return Net
+ is
+ Res : Net;
+ begin
+ Res := Build_Monadic (Get_Build (Syn_Inst), Id_Not,
+ Synth_Psl_Final (Syn_Inst, Stmt, Next_States));
+ Set_Location (Res, Stmt);
+ return Res;
+ end Synth_Psl_Not_Final;
+
+ procedure Synth_Psl_Restrict_Directive
+ (Syn_Inst : Synth_Instance_Acc; Stmt : Node)
+ is
+ Ctxt : constant Context_Acc := Get_Build (Syn_Inst);
+ Next_States : Net;
+ Res : Net;
+ Inst : Instance;
+ begin
+ if not Flags.Flag_Formal then
+ return;
+ end if;
+
+ -- Build assume gate.
+ -- Note: for synthesis, we assume the next state will be correct.
+ -- (If we assume on States, then the first cycle is ignored).
+ Synth_Psl_Dff (Syn_Inst, Stmt, Next_States);
+ if Next_States /= No_Net then
+ -- The restriction holds as long as there is a 1 in the NFA state.
+ Res := Build_Reduce (Ctxt, Id_Red_Or, Next_States);
+ Set_Location (Res, Stmt);
+ Inst := Build_Assume (Ctxt, Synth_Label (Syn_Inst, Stmt), Res);
+ Set_Location (Inst, Get_Location (Stmt));
+ end if;
+ end Synth_Psl_Restrict_Directive;
+
+ procedure Synth_Psl_Cover_Directive
+ (Syn_Inst : Synth_Instance_Acc; Stmt : Node)
+ is
+ Next_States : Net;
+ Res : Net;
+ Inst : Instance;
+ begin
+ if not Flags.Flag_Formal then
+ return;
+ end if;
+
+ -- Build cover gate.
+ -- Note: for synthesis, we assume the next state will be correct.
+ -- (If we assume on States, then the first cycle is ignored).
+ Synth_Psl_Dff (Syn_Inst, Stmt, Next_States);
+ if Next_States /= No_Net then
+ -- The sequence is covered as soon as the final state is reached.
+ Res := Synth_Psl_Final (Syn_Inst, Stmt, Next_States);
+ Inst := Build_Cover
+ (Get_Build (Syn_Inst), Synth_Label (Syn_Inst, Stmt), Res);
+ Set_Location (Inst, Get_Location (Stmt));
+ end if;
+ end Synth_Psl_Cover_Directive;
+
+ procedure Synth_Psl_Assume_Directive
+ (Syn_Inst : Synth_Instance_Acc; Stmt : Node)
+ is
+ Ctxt : constant Context_Acc := Get_Build (Syn_Inst);
+ Next_States : Net;
+ Inst : Instance;
+ begin
+ if not Flags.Flag_Formal then
+ return;
+ end if;
+
+ -- Build assume gate.
+ -- Note: for synthesis, we assume the next state will be correct.
+ -- (If we assume on States, then the first cycle is ignored).
+ Synth_Psl_Dff (Syn_Inst, Stmt, Next_States);
+ if Next_States /= No_Net then
+ Inst := Build_Assume
+ (Ctxt, Synth_Label (Syn_Inst, Stmt),
+ Synth_Psl_Not_Final (Syn_Inst, Stmt, Next_States));
+ Set_Location (Inst, Get_Location (Stmt));
+ end if;
+ end Synth_Psl_Assume_Directive;
+
+ procedure Synth_Psl_Assert_Directive
+ (Syn_Inst : Synth_Instance_Acc; Stmt : Node)
+ is
+ use PSL.Types;
+ use PSL.NFAs;
+ Ctxt : constant Context_Acc := Get_Build (Syn_Inst);
+ NFA : constant PSL_NFA := Get_PSL_NFA (Stmt);
+ Active : NFA_State;
+ Next_States : Net;
+ Inst : Instance;
+ Lab : Sname;
+ begin
+ if not Flags.Flag_Formal then
+ return;
+ end if;
+
+ -- Build assert gate.
+ -- Note: for synthesis, we assume the next state will be correct.
+ -- (If we assert on States, then the first cycle is ignored).
+ Synth_Psl_Dff (Syn_Inst, Stmt, Next_States);
+ if Next_States = No_Net then
+ return;
+ end if;
+ Lab := Synth_Label (Syn_Inst, Stmt);
+
+ Inst := Build_Assert
+ (Ctxt, Lab, Synth_Psl_Not_Final (Syn_Inst, Stmt, Next_States));
+ Set_Location (Inst, Get_Location (Stmt));
+
+ -- Also add a cover gate to cover assertion activation.
+ if Flags.Flag_Assert_Cover then
+ Active := Get_Active_State (NFA);
+ if Active /= No_State then
+ if Lab /= No_Sname then
+ Lab := New_Sname_User (Std_Names.Name_Cover, Lab);
+ end if;
+ Inst := Build_Assert_Cover
+ (Get_Build (Syn_Inst), Lab,
+ Build_Extract_Bit (Get_Build (Syn_Inst), Next_States,
+ Uns32 (Get_State_Label (Active))));
+ Set_Location (Inst, Get_Location (Stmt));
+ end if;
+ end if;
+ end Synth_Psl_Assert_Directive;
+
+ procedure Synth_Generate_Statement_Body
+ (Syn_Inst : Synth_Instance_Acc;
+ Bod : Node;
+ Name : Sname;
+ Iterator : Node := Null_Node;
+ Iterator_Val : Valtyp := No_Valtyp)
+ is
+ use Areapools;
+ Decls_Chain : constant Node := Get_Declaration_Chain (Bod);
+ Prev_Instance_Pool : constant Areapool_Acc := Instance_Pool;
+ Bod_Inst : Synth_Instance_Acc;
+ M : Areapools.Mark_Type;
+ begin
+ Bod_Inst := Make_Instance (Syn_Inst, Bod, Name);
+ Mark (M, Proc_Pool);
+ Instance_Pool := Proc_Pool'Access;
+
+ if Iterator /= Null_Node then
+ -- Add the iterator (for for-generate).
+ Create_Object (Bod_Inst, Iterator, Iterator_Val);
+ end if;
+
+ Synth_Declarations (Bod_Inst, Decls_Chain);
+
+ Synth_Concurrent_Statements
+ (Bod_Inst, Get_Concurrent_Statement_Chain (Bod));
+
+ Synth_Attribute_Values (Bod_Inst, Bod);
+
+ Finalize_Declarations (Bod_Inst, Decls_Chain);
+
+ Free_Instance (Bod_Inst);
+ Release (M, Proc_Pool);
+ Instance_Pool := Prev_Instance_Pool;
+ end Synth_Generate_Statement_Body;
+
+ procedure Synth_If_Generate_Statement
+ (Syn_Inst : Synth_Instance_Acc; Stmt : Node)
+ is
+ Gen : Node;
+ Bod : Node;
+ Icond : Node;
+ Cond : Valtyp;
+ Name : Sname;
+ begin
+ Gen := Stmt;
+ Name := New_Sname_User (Get_Identifier (Stmt), Get_Sname (Syn_Inst));
+ loop
+ Icond := Get_Condition (Gen);
+ if Icond /= Null_Node then
+ Cond := Synth_Expression (Syn_Inst, Icond);
+ Strip_Const (Cond);
+ else
+ -- It is the else generate.
+ Cond := No_Valtyp;
+ end if;
+ if Cond = No_Valtyp or else Read_Discrete (Cond) = 1 then
+ Bod := Get_Generate_Statement_Body (Gen);
+ Apply_Block_Configuration
+ (Get_Generate_Block_Configuration (Bod), Bod);
+ Synth_Generate_Statement_Body (Syn_Inst, Bod, Name);
+ exit;
+ end if;
+ Gen := Get_Generate_Else_Clause (Gen);
+ exit when Gen = Null_Node;
+ end loop;
+ end Synth_If_Generate_Statement;
+
+ procedure Synth_For_Generate_Statement
+ (Syn_Inst : Synth_Instance_Acc; Stmt : Node)
+ is
+ Iterator : constant Node := Get_Parameter_Specification (Stmt);
+ Bod : constant Node := Get_Generate_Statement_Body (Stmt);
+ Configs : constant Node := Get_Generate_Block_Configuration (Bod);
+ It_Type : constant Node := Get_Declaration_Type (Iterator);
+ Config : Node;
+ It_Rng : Type_Acc;
+ Val : Valtyp;
+ Name : Sname;
+ Lname : Sname;
+ begin
+ if It_Type /= Null_Node then
+ Synth_Subtype_Indication (Syn_Inst, It_Type);
+ end if;
+
+ -- Initial value.
+ It_Rng := Get_Subtype_Object (Syn_Inst, Get_Type (Iterator));
+ Val := Create_Value_Discrete (It_Rng.Drange.Left, It_Rng);
+
+ Name := New_Sname_User (Get_Identifier (Stmt), Get_Sname (Syn_Inst));
+
+ while In_Range (It_Rng.Drange, Read_Discrete (Val)) loop
+ -- Find and apply the config block.
+ declare
+ Spec : Node;
+ begin
+ Config := Configs;
+ while Config /= Null_Node loop
+ Spec := Get_Block_Specification (Config);
+ case Get_Kind (Spec) is
+ when Iir_Kind_Simple_Name =>
+ exit;
+ when others =>
+ Error_Kind ("synth_for_generate_statement", Spec);
+ end case;
+ Config := Get_Prev_Block_Configuration (Config);
+ end loop;
+ if Config = Null_Node then
+ raise Internal_Error;
+ end if;
+ Apply_Block_Configuration (Config, Bod);
+ end;
+
+ -- FIXME: get position ?
+ Lname := New_Sname_Version (Uns32 (Read_Discrete (Val)), Name);
+
+ Synth_Generate_Statement_Body (Syn_Inst, Bod, Lname, Iterator, Val);
+ Update_Index (It_Rng.Drange, Val);
+ end loop;
+ end Synth_For_Generate_Statement;
+
+ procedure Synth_Concurrent_Statement
+ (Syn_Inst : Synth_Instance_Acc; Stmt : Node)
+ is
+ Ctxt : constant Context_Acc := Get_Build (Syn_Inst);
+ begin
+ case Get_Kind (Stmt) is
+ when Iir_Kind_Concurrent_Simple_Signal_Assignment =>
+ Push_Phi;
+ Synth_Simple_Signal_Assignment (Syn_Inst, Stmt);
+ Pop_And_Merge_Phi (Ctxt, Get_Location (Stmt));
+ when Iir_Kind_Concurrent_Conditional_Signal_Assignment =>
+ Push_Phi;
+ Synth_Conditional_Signal_Assignment (Syn_Inst, Stmt);
+ Pop_And_Merge_Phi (Ctxt, Get_Location (Stmt));
+ when Iir_Kind_Concurrent_Selected_Signal_Assignment =>
+ Push_Phi;
+ Synth_Selected_Signal_Assignment (Syn_Inst, Stmt);
+ Pop_And_Merge_Phi (Ctxt, Get_Location (Stmt));
+ when Iir_Kind_Concurrent_Procedure_Call_Statement =>
+ Push_Phi;
+ Synth_Procedure_Call (Syn_Inst, Stmt);
+ Pop_And_Merge_Phi (Ctxt, Get_Location (Stmt));
+ when Iir_Kinds_Process_Statement =>
+ Synth_Process_Statement (Syn_Inst, Stmt);
+ when Iir_Kind_If_Generate_Statement =>
+ Synth_If_Generate_Statement (Syn_Inst, Stmt);
+ when Iir_Kind_For_Generate_Statement =>
+ Synth_For_Generate_Statement (Syn_Inst, Stmt);
+ when Iir_Kind_Component_Instantiation_Statement =>
+ if Is_Component_Instantiation (Stmt) then
+ declare
+ Comp_Config : constant Node :=
+ Get_Component_Configuration (Stmt);
+ begin
+ if Get_Binding_Indication (Comp_Config) = Null_Node then
+ -- Not bound.
+ Synth_Blackbox_Instantiation_Statement (Syn_Inst, Stmt);
+ else
+ Synth_Component_Instantiation_Statement (Syn_Inst, Stmt);
+ end if;
+ end;
+ -- Un-apply configuration.
+ Set_Component_Configuration (Stmt, Null_Node);
+ else
+ Synth_Design_Instantiation_Statement (Syn_Inst, Stmt);
+ end if;
+ when Iir_Kind_Block_Statement =>
+ Synth_Block_Statement (Syn_Inst, Stmt);
+ when Iir_Kind_Psl_Default_Clock =>
+ null;
+ when Iir_Kind_Psl_Restrict_Directive =>
+ Synth_Psl_Restrict_Directive (Syn_Inst, Stmt);
+ when Iir_Kind_Psl_Assume_Directive =>
+ if Flags.Flag_Assume_As_Assert then
+ Synth_Psl_Assert_Directive (Syn_Inst, Stmt);
+ else
+ Synth_Psl_Assume_Directive (Syn_Inst, Stmt);
+ end if;
+ when Iir_Kind_Psl_Cover_Directive =>
+ Synth_Psl_Cover_Directive (Syn_Inst, Stmt);
+ when Iir_Kind_Psl_Assert_Directive =>
+ if Flags.Flag_Assert_As_Assume then
+ Synth_Psl_Assume_Directive (Syn_Inst, Stmt);
+ else
+ Synth_Psl_Assert_Directive (Syn_Inst, Stmt);
+ end if;
+ when Iir_Kind_Concurrent_Assertion_Statement =>
+ -- Passive statement.
+ Synth_Concurrent_Assertion_Statement (Syn_Inst, Stmt);
+ when others =>
+ Error_Kind ("synth_concurrent_statement", Stmt);
+ end case;
+ end Synth_Concurrent_Statement;
+
+ procedure Synth_Concurrent_Statements
+ (Syn_Inst : Synth_Instance_Acc; Stmts : Node)
+ is
+ Stmt : Node;
+ begin
+ Stmt := Stmts;
+ while Is_Valid (Stmt) loop
+ Synth_Concurrent_Statement (Syn_Inst, Stmt);
+ Stmt := Get_Chain (Stmt);
+ end loop;
+ end Synth_Concurrent_Statements;
+
+ -- For allconst/allseq/...
+ procedure Synth_Attribute_Formal (Syn_Inst : Synth_Instance_Acc;
+ Val : Node;
+ Id : Formal_Module_Id)
+ is
+ Spec : constant Node := Get_Attribute_Specification (Val);
+ Sig : constant Node := Get_Designated_Entity (Val);
+ V : Valtyp;
+ begin
+ -- The type must be boolean
+ if (Get_Base_Type (Get_Type (Val)) /=
+ Vhdl.Std_Package.Boolean_Type_Definition)
+ then
+ Error_Msg_Synth (+Val, "type of attribute %i must be boolean",
+ (1 => +Get_Attribute_Designator (Spec)));
+ return;
+ end if;
+
+ -- The designated entity must be a signal.
+ if Get_Kind (Sig) /= Iir_Kind_Signal_Declaration then
+ Error_Msg_Synth (+Val, "attribute %i only applies to signals",
+ (1 => +Get_Attribute_Designator (Spec)));
+ return;
+ end if;
+
+ -- The value must be true
+ V := Synth_Expression_With_Type
+ (Syn_Inst, Get_Expression (Spec), Boolean_Type);
+ if Read_Discrete (V) /= 1 then
+ return;
+ end if;
+
+ declare
+ Off : Value_Offsets;
+ Dyn : Dyn_Name;
+ N : Net;
+ Base : Valtyp;
+ Typ : Type_Acc;
+ begin
+ Synth_Assignment_Prefix (Syn_Inst, Sig, Base, Typ, Off, Dyn);
+ pragma Assert (Off = (0, 0));
+ pragma Assert (Dyn.Voff = No_Net);
+ pragma Assert (Base.Val.Kind = Value_Wire);
+ pragma Assert (Base.Typ = Typ);
+
+ N := Build_Formal_Input (Get_Build (Syn_Inst), Id, Typ.W);
+ Set_Location (N, Val);
+ Add_Conc_Assign (Base.Val.W, N, 0);
+ end;
+ end Synth_Attribute_Formal;
+
+ procedure Synth_Attribute_Values
+ (Syn_Inst : Synth_Instance_Acc; Unit : Node)
+ is
+ use Std_Names;
+
+ Val : Node;
+ Spec : Node;
+ Id : Name_Id;
+ begin
+ Val := Get_Attribute_Value_Chain (Unit);
+ while Val /= Null_Node loop
+ Spec := Get_Attribute_Specification (Val);
+ Id := Get_Identifier (Get_Attribute_Designator (Spec));
+ case Id is
+ when Name_Allconst =>
+ Synth_Attribute_Formal (Syn_Inst, Val, Id_Allconst);
+ when Name_Allseq =>
+ Synth_Attribute_Formal (Syn_Inst, Val, Id_Allseq);
+ when Name_Anyconst =>
+ Synth_Attribute_Formal (Syn_Inst, Val, Id_Anyconst);
+ when Name_Anyseq =>
+ Synth_Attribute_Formal (Syn_Inst, Val, Id_Anyseq);
+ when Name_Loc =>
+ -- Applies to nets/ports.
+ null;
+ when others =>
+ Warning_Msg_Synth (+Spec, "unhandled attribute %i", (1 => +Id));
+ end case;
+ Val := Get_Value_Chain (Val);
+ end loop;
+ end Synth_Attribute_Values;
+
+ procedure Synth_Verification_Unit
+ (Syn_Inst : Synth_Instance_Acc; Unit : Node)
+ is
+ use Areapools;
+ Prev_Instance_Pool : constant Areapool_Acc := Instance_Pool;
+ Unit_Inst : Synth_Instance_Acc;
+ Unit_Sname : Sname;
+ M : Areapools.Mark_Type;
+ Item : Node;
+ Last_Type : Node;
+ begin
+ Unit_Sname := New_Sname_User (Get_Identifier (Unit),
+ Get_Sname (Syn_Inst));
+ Unit_Inst := Make_Instance (Syn_Inst, Unit, Unit_Sname);
+ Mark (M, Proc_Pool);
+ Instance_Pool := Proc_Pool'Access;
+
+ Apply_Block_Configuration
+ (Get_Verification_Block_Configuration (Unit), Unit);
+
+ Last_Type := Null_Node;
+ Item := Get_Vunit_Item_Chain (Unit);
+ while Item /= Null_Node loop
+ case Get_Kind (Item) is
+ when Iir_Kind_Psl_Default_Clock =>
+ null;
+ when Iir_Kind_Psl_Assert_Directive =>
+ Synth_Psl_Assert_Directive (Unit_Inst, Item);
+ when Iir_Kind_Psl_Assume_Directive =>
+ Synth_Psl_Assume_Directive (Unit_Inst, Item);
+ when Iir_Kind_Psl_Restrict_Directive =>
+ Synth_Psl_Restrict_Directive (Unit_Inst, Item);
+ when Iir_Kind_Psl_Cover_Directive =>
+ Synth_Psl_Cover_Directive (Unit_Inst, Item);
+ when Iir_Kind_Signal_Declaration
+ | Iir_Kind_Function_Declaration
+ | Iir_Kind_Procedure_Declaration
+ | Iir_Kind_Function_Body
+ | Iir_Kind_Procedure_Body
+ | Iir_Kind_Attribute_Declaration
+ | Iir_Kind_Attribute_Specification =>
+ Synth_Declaration (Unit_Inst, Item, False, Last_Type);
+ when Iir_Kinds_Concurrent_Signal_Assignment
+ | Iir_Kinds_Process_Statement
+ | Iir_Kinds_Generate_Statement
+ | Iir_Kind_Block_Statement
+ | Iir_Kind_Concurrent_Procedure_Call_Statement
+ | Iir_Kind_Component_Instantiation_Statement =>
+ Synth_Concurrent_Statement (Unit_Inst, Item);
+ when others =>
+ Error_Kind ("synth_verification_unit", Item);
+ end case;
+ Item := Get_Chain (Item);
+ end loop;
+
+ Synth_Attribute_Values (Unit_Inst, Unit);
+
+ -- Finalize
+ Item := Get_Vunit_Item_Chain (Unit);
+ while Item /= Null_Node loop
+ case Get_Kind (Item) is
+ when Iir_Kind_Psl_Default_Clock
+ | Iir_Kind_Psl_Assert_Directive
+ | Iir_Kind_Psl_Assume_Directive
+ | Iir_Kind_Psl_Restrict_Directive
+ | Iir_Kind_Psl_Cover_Directive =>
+ null;
+ when Iir_Kinds_Concurrent_Signal_Assignment
+ | Iir_Kinds_Process_Statement
+ | Iir_Kinds_Generate_Statement
+ | Iir_Kind_Block_Statement
+ | Iir_Kind_Concurrent_Procedure_Call_Statement
+ | Iir_Kind_Component_Instantiation_Statement =>
+ null;
+ when Iir_Kind_Signal_Declaration
+ | Iir_Kind_Function_Declaration
+ | Iir_Kind_Procedure_Declaration
+ | Iir_Kind_Function_Body
+ | Iir_Kind_Procedure_Body
+ | Iir_Kind_Attribute_Declaration
+ | Iir_Kind_Attribute_Specification =>
+ Finalize_Declaration (Unit_Inst, Item, False);
+ when others =>
+ Error_Kind ("synth_verification_unit(2)", Item);
+ end case;
+ Item := Get_Chain (Item);
+ end loop;
+
+ Free_Instance (Unit_Inst);
+ Release (M, Proc_Pool);
+ Instance_Pool := Prev_Instance_Pool;
+ end Synth_Verification_Unit;
+end Synth.Vhdl_Stmts;