aboutsummaryrefslogtreecommitdiffstats
path: root/src/synth/synth-vhdl_context.adb
diff options
context:
space:
mode:
authorTristan Gingold <tgingold@free.fr>2021-04-16 06:42:48 +0200
committerTristan Gingold <tgingold@free.fr>2021-04-16 06:58:03 +0200
commita677e3cc38d1f5e3813bc1e5bd424ee0b59319ed (patch)
treef62fa5971c0e326294b02a84bb18c826937654f0 /src/synth/synth-vhdl_context.adb
parent12d6069e3b48a6ce129914e728d88789d1d8f5a1 (diff)
downloadghdl-a677e3cc38d1f5e3813bc1e5bd424ee0b59319ed.tar.gz
ghdl-a677e3cc38d1f5e3813bc1e5bd424ee0b59319ed.tar.bz2
ghdl-a677e3cc38d1f5e3813bc1e5bd424ee0b59319ed.zip
synth: rename synth-context to synth-vhdl_context
Diffstat (limited to 'src/synth/synth-vhdl_context.adb')
-rw-r--r--src/synth/synth-vhdl_context.adb562
1 files changed, 562 insertions, 0 deletions
diff --git a/src/synth/synth-vhdl_context.adb b/src/synth/synth-vhdl_context.adb
new file mode 100644
index 000000000..2a497ae0f
--- /dev/null
+++ b/src/synth/synth-vhdl_context.adb
@@ -0,0 +1,562 @@
+-- Synthesis context.
+-- 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 Name_Table; use Name_Table;
+with Types_Utils; use Types_Utils;
+
+with Vhdl.Errors; use Vhdl.Errors;
+with Vhdl.Utils;
+
+with Netlists.Folds; use Netlists.Folds;
+
+with Synth.Expr; use Synth.Expr;
+with Netlists.Locations;
+
+package body Synth.Vhdl_Context is
+ function Make_Base_Instance return Synth_Instance_Acc
+ is
+ Base : Base_Instance_Acc;
+ Top_Module : Module;
+ Res : Synth_Instance_Acc;
+ Ctxt : Context_Acc;
+ begin
+ Top_Module :=
+ New_Design (New_Sname_Artificial (Get_Identifier ("top"), No_Sname));
+ Ctxt := Build_Builders (Top_Module);
+
+ Base := new Base_Instance_Type'(Builder => Ctxt,
+ Top_Module => Top_Module,
+ Cur_Module => No_Module);
+
+ Res := new Synth_Instance_Type'(Max_Objs => Global_Info.Nbr_Objects,
+ Is_Const => False,
+ Is_Error => False,
+ Base => Base,
+ Name => No_Sname,
+ Block_Scope => Global_Info,
+ Up_Block => null,
+ Uninst_Scope => null,
+ Source_Scope => Null_Node,
+ Elab_Objects => 0,
+ Objects => (others =>
+ (Kind => Obj_None)));
+ return Res;
+ end Make_Base_Instance;
+
+ procedure Free_Base_Instance is
+ begin
+ -- TODO: really free.
+ null;
+ end Free_Base_Instance;
+
+ function Make_Instance (Parent : Synth_Instance_Acc;
+ Blk : Node;
+ Name : Sname := No_Sname)
+ return Synth_Instance_Acc
+ is
+ Info : constant Sim_Info_Acc := Get_Info (Blk);
+ Scope : Sim_Info_Acc;
+ Res : Synth_Instance_Acc;
+ begin
+ if Get_Kind (Blk) = Iir_Kind_Architecture_Body then
+ -- Architectures are extensions of entities.
+ Scope := Get_Info (Vhdl.Utils.Get_Entity (Blk));
+ else
+ Scope := Info;
+ end if;
+
+ Res := new Synth_Instance_Type'(Max_Objs => Info.Nbr_Objects,
+ Is_Const => False,
+ Is_Error => False,
+ Base => Parent.Base,
+ Name => Name,
+ Block_Scope => Scope,
+ Up_Block => Parent,
+ Uninst_Scope => null,
+ Source_Scope => Blk,
+ Elab_Objects => 0,
+ Objects => (others =>
+ (Kind => Obj_None)));
+ return Res;
+ end Make_Instance;
+
+ procedure Set_Instance_Base (Inst : Synth_Instance_Acc;
+ Base : Synth_Instance_Acc) is
+ begin
+ Inst.Base := Base.Base;
+ end Set_Instance_Base;
+
+ procedure Free_Instance (Synth_Inst : in out Synth_Instance_Acc)
+ is
+ procedure Deallocate is new Ada.Unchecked_Deallocation
+ (Synth_Instance_Type, Synth_Instance_Acc);
+ begin
+ Deallocate (Synth_Inst);
+ end Free_Instance;
+
+ procedure Set_Instance_Module (Inst : Synth_Instance_Acc; M : Module)
+ is
+ Prev_Base : constant Base_Instance_Acc := Inst.Base;
+ Base : Base_Instance_Acc;
+ Self_Inst : Instance;
+ begin
+ Base := new Base_Instance_Type'(Builder => Prev_Base.Builder,
+ Top_Module => Prev_Base.Top_Module,
+ Cur_Module => M);
+ Builders.Set_Parent (Base.Builder, M);
+
+ Self_Inst := Create_Self_Instance (M);
+ pragma Unreferenced (Self_Inst);
+
+ Inst.Base := Base;
+ end Set_Instance_Module;
+
+ function Is_Error (Inst : Synth_Instance_Acc) return Boolean is
+ begin
+ return Inst.Is_Error;
+ end Is_Error;
+
+ procedure Set_Error (Inst : Synth_Instance_Acc) is
+ begin
+ Inst.Is_Error := True;
+ end Set_Error;
+
+ function Get_Instance_Module (Inst : Synth_Instance_Acc) return Module is
+ begin
+ return Inst.Base.Cur_Module;
+ end Get_Instance_Module;
+
+ function Get_Source_Scope (Inst : Synth_Instance_Acc) return Node is
+ begin
+ return Inst.Source_Scope;
+ end Get_Source_Scope;
+
+ function Get_Top_Module (Inst : Synth_Instance_Acc) return Module is
+ begin
+ return Inst.Base.Top_Module;
+ end Get_Top_Module;
+
+ function Get_Sname (Inst : Synth_Instance_Acc) return Sname is
+ begin
+ return Inst.Name;
+ end Get_Sname;
+
+ function Get_Build (Inst : Synth_Instance_Acc)
+ return Netlists.Builders.Context_Acc is
+ begin
+ return Inst.Base.Builder;
+ end Get_Build;
+
+ function Get_Instance_Const (Inst : Synth_Instance_Acc) return Boolean is
+ begin
+ return Inst.Is_Const;
+ end Get_Instance_Const;
+
+ function Check_Set_Instance_Const (Inst : Synth_Instance_Acc)
+ return Boolean is
+ begin
+ for I in 1 .. Inst.Elab_Objects loop
+ if Inst.Objects (I).Kind /= Obj_Subtype then
+ return False;
+ end if;
+ end loop;
+ return True;
+ end Check_Set_Instance_Const;
+
+ procedure Set_Instance_Const (Inst : Synth_Instance_Acc; Val : Boolean) is
+ begin
+ pragma Assert (not Val or else Check_Set_Instance_Const (Inst));
+ Inst.Is_Const := Val;
+ end Set_Instance_Const;
+
+ procedure Create_Object (Syn_Inst : Synth_Instance_Acc;
+ Slot : Object_Slot_Type;
+ Num : Object_Slot_Type := 1) is
+ begin
+ -- Check elaboration order.
+ -- Note: this is not done for package since objects from package are
+ -- commons (same scope), and package annotation order can be different
+ -- from package elaboration order (eg: body).
+ if Slot /= Syn_Inst.Elab_Objects + 1
+ or else Syn_Inst.Objects (Slot).Kind /= Obj_None
+ then
+ Error_Msg_Elab ("synth: bad elaboration order of objects");
+ raise Internal_Error;
+ end if;
+ Syn_Inst.Elab_Objects := Slot + Num - 1;
+ end Create_Object;
+
+ procedure Create_Object_Force
+ (Syn_Inst : Synth_Instance_Acc; Decl : Node; Vt : Valtyp)
+ is
+ Info : constant Sim_Info_Acc := Get_Info (Decl);
+ begin
+ pragma Assert
+ (Syn_Inst.Objects (Info.Slot).Kind = Obj_None
+ or else Vt = (null, null)
+ or else Syn_Inst.Objects (Info.Slot) = (Kind => Obj_Object,
+ Obj => No_Valtyp));
+ Syn_Inst.Objects (Info.Slot) := (Kind => Obj_Object, Obj => Vt);
+ end Create_Object_Force;
+
+ procedure Create_Object
+ (Syn_Inst : Synth_Instance_Acc; Decl : Node; Vt : Valtyp)
+ is
+ Info : constant Sim_Info_Acc := Get_Info (Decl);
+ begin
+ Create_Object (Syn_Inst, Info.Slot, 1);
+ Create_Object_Force (Syn_Inst, Decl, Vt);
+ end Create_Object;
+
+ procedure Create_Subtype_Object
+ (Syn_Inst : Synth_Instance_Acc; Decl : Node; Typ : Type_Acc)
+ is
+ pragma Assert (Typ /= null);
+ Info : constant Sim_Info_Acc := Get_Info (Decl);
+ begin
+ Create_Object (Syn_Inst, Info.Slot, 1);
+ pragma Assert (Syn_Inst.Objects (Info.Slot).Kind = Obj_None);
+ Syn_Inst.Objects (Info.Slot) := (Kind => Obj_Subtype, T_Typ => Typ);
+ end Create_Subtype_Object;
+
+ procedure Create_Package_Object (Syn_Inst : Synth_Instance_Acc;
+ Decl : Node;
+ Inst : Synth_Instance_Acc;
+ Is_Global : Boolean)
+ is
+ Info : constant Sim_Info_Acc := Get_Info (Decl);
+ begin
+ if Is_Global then
+ pragma Assert (Syn_Inst.Objects (Info.Pkg_Slot).Kind = Obj_None);
+ pragma Assert (Syn_Inst.Up_Block = null);
+ null;
+ else
+ pragma Assert (Syn_Inst.Up_Block /= null);
+ Create_Object (Syn_Inst, Info.Slot, 1);
+ end if;
+ Syn_Inst.Objects (Info.Pkg_Slot) := (Kind => Obj_Instance,
+ I_Inst => Inst);
+ end Create_Package_Object;
+
+ procedure Create_Package_Interface (Syn_Inst : Synth_Instance_Acc;
+ Decl : Node;
+ Inst : Synth_Instance_Acc)
+ is
+ Info : constant Sim_Info_Acc := Get_Info (Decl);
+ begin
+ pragma Assert (Syn_Inst.Up_Block /= null);
+ Create_Object (Syn_Inst, Info.Pkg_Slot, 1);
+ Syn_Inst.Objects (Info.Pkg_Slot) := (Kind => Obj_Instance,
+ I_Inst => Inst);
+ end Create_Package_Interface;
+
+ function Get_Package_Object
+ (Syn_Inst : Synth_Instance_Acc; Info : Sim_Info_Acc)
+ return Synth_Instance_Acc
+ is
+ Parent : Synth_Instance_Acc;
+ begin
+ Parent := Get_Instance_By_Scope (Syn_Inst, Info.Pkg_Parent);
+ return Parent.Objects (Info.Pkg_Slot).I_Inst;
+ end Get_Package_Object;
+
+ function Get_Package_Object
+ (Syn_Inst : Synth_Instance_Acc; Pkg : Node) return Synth_Instance_Acc is
+ begin
+ return Get_Package_Object (Syn_Inst, Get_Info (Pkg));
+ end Get_Package_Object;
+
+ procedure Set_Uninstantiated_Scope
+ (Syn_Inst : Synth_Instance_Acc; Bod : Node) is
+ begin
+ Syn_Inst.Uninst_Scope := Get_Info (Bod);
+ end Set_Uninstantiated_Scope;
+
+ procedure Destroy_Object
+ (Syn_Inst : Synth_Instance_Acc; Decl : Node)
+ is
+ Info : constant Sim_Info_Acc := Get_Info (Decl);
+ Slot : constant Object_Slot_Type := Info.Slot;
+ begin
+ if Slot /= Syn_Inst.Elab_Objects
+ or else Info.Obj_Scope /= Syn_Inst.Block_Scope
+ then
+ Error_Msg_Elab ("synth: bad destroy order");
+ end if;
+ Syn_Inst.Objects (Slot) := (Kind => Obj_None);
+ Syn_Inst.Elab_Objects := Slot - 1;
+ end Destroy_Object;
+
+ procedure Create_Wire_Object (Syn_Inst : Synth_Instance_Acc;
+ Kind : Wire_Kind;
+ Obj : Node)
+ is
+ Obj_Type : constant Node := Get_Type (Obj);
+ Otyp : constant Type_Acc := Get_Subtype_Object (Syn_Inst, Obj_Type);
+ Val : Valtyp;
+ Wid : Wire_Id;
+ begin
+ if Kind = Wire_None then
+ Wid := No_Wire_Id;
+ else
+ Wid := Alloc_Wire (Kind, Otyp, Obj);
+ end if;
+ Val := Create_Value_Wire (Wid, Otyp);
+
+ Create_Object (Syn_Inst, Obj, Val);
+ end Create_Wire_Object;
+
+ function Get_Instance_By_Scope
+ (Syn_Inst: Synth_Instance_Acc; Scope: Sim_Info_Acc)
+ return Synth_Instance_Acc is
+ begin
+ case Scope.Kind is
+ when Kind_Block
+ | Kind_Frame
+ | Kind_Process =>
+ declare
+ Current : Synth_Instance_Acc;
+ begin
+ Current := Syn_Inst;
+ while Current /= null loop
+ if Current.Block_Scope = Scope then
+ return Current;
+ end if;
+ Current := Current.Up_Block;
+ end loop;
+ raise Internal_Error;
+ end;
+ when Kind_Package =>
+ if Scope.Pkg_Parent = null then
+ -- This is a scope for an uninstantiated package.
+ declare
+ Current : Synth_Instance_Acc;
+ begin
+ Current := Syn_Inst;
+ while Current /= null loop
+ if Current.Uninst_Scope = Scope then
+ return Current;
+ end if;
+ Current := Current.Up_Block;
+ end loop;
+ raise Internal_Error;
+ end;
+ else
+ -- Instantiated package.
+ return Get_Package_Object (Syn_Inst, Scope);
+ end if;
+ when others =>
+ raise Internal_Error;
+ end case;
+ end Get_Instance_By_Scope;
+
+ function Get_Parent_Scope (Blk : Node) return Sim_Info_Acc
+ is
+ Parent : Node;
+ begin
+ Parent := Get_Parent (Blk);
+ if Get_Kind (Parent) = Iir_Kind_Architecture_Body then
+ Parent := Vhdl.Utils.Get_Entity (Parent);
+ end if;
+ return Get_Info (Parent);
+ end Get_Parent_Scope;
+
+ function Get_Value (Syn_Inst: Synth_Instance_Acc; Obj : Node)
+ return Valtyp
+ is
+ Info : constant Sim_Info_Acc := Get_Info (Obj);
+ Obj_Inst : Synth_Instance_Acc;
+ begin
+ Obj_Inst := Get_Instance_By_Scope (Syn_Inst, Info.Obj_Scope);
+ return Obj_Inst.Objects (Info.Slot).Obj;
+ end Get_Value;
+
+ function Get_Subtype_Object
+ (Syn_Inst : Synth_Instance_Acc; Decl : Node) return Type_Acc
+ is
+ Info : constant Sim_Info_Acc := Get_Info (Decl);
+ Obj_Inst : Synth_Instance_Acc;
+ begin
+ Obj_Inst := Get_Instance_By_Scope (Syn_Inst, Info.Obj_Scope);
+ return Obj_Inst.Objects (Info.Slot).T_Typ;
+ end Get_Subtype_Object;
+
+ -- Set Is_0 to True iff VEC is 000...
+ -- Set Is_X to True iff VEC is XXX...
+ procedure Is_Full (Vec : Logvec_Array;
+ Is_0 : out Boolean;
+ Is_X : out Boolean;
+ Is_Z : out Boolean)
+ is
+ Val : Uns32;
+ Zx : Uns32;
+ begin
+ Val := Vec (0).Val;
+ Zx := Vec (0).Zx;
+ Is_0 := False;
+ Is_X := False;
+ Is_Z := False;
+ if Val = 0 and Zx = 0 then
+ Is_0 := True;
+ elsif Zx = not 0 then
+ if Val = not 0 then
+ Is_X := True;
+ elsif Val = 0 then
+ Is_Z := True;
+ else
+ return;
+ end if;
+ else
+ return;
+ end if;
+
+ for I in 1 .. Vec'Last loop
+ if Vec (I).Val /= Val or else Vec (I).Zx /= Zx then
+ -- Clear flags.
+ Is_0 := False;
+ Is_X := False;
+ Is_Z := False;
+ return;
+ end if;
+ end loop;
+ end Is_Full;
+
+ procedure Value2net (Ctxt : Context_Acc;
+ Val : Memtyp;
+ Off : Uns32;
+ W : Width;
+ Vec : in out Logvec_Array;
+ Res : out Net)
+ is
+ Vec_Off : Uns32;
+ Has_Zx : Boolean;
+ Inst : Instance;
+ Is_0, Is_X, Is_Z : Boolean;
+ begin
+ -- First convert to logvec.
+ Has_Zx := False;
+ Vec_Off := 0;
+ Value2logvec (Val, Off, W, Vec, Vec_Off, Has_Zx);
+ pragma Assert (Vec_Off = W);
+
+ -- Then convert logvec to net.
+ if W = 0 then
+ -- For null range (like the null string literal "")
+ Res := Build_Const_UB32 (Ctxt, 0, 0);
+ elsif W <= 32 then
+ -- 32 bit result.
+ if not Has_Zx then
+ Res := Build_Const_UB32 (Ctxt, Vec (0).Val, W);
+ elsif Vec (0).Val = 0 and then Sext (Vec (0).Zx, Natural (W)) = not 0
+ then
+ Res := Build_Const_Z (Ctxt, W);
+ else
+ Res := Build_Const_UL32 (Ctxt, Vec (0).Val, Vec (0).Zx, W);
+ end if;
+ return;
+ else
+ Is_Full (Vec, Is_0, Is_X, Is_Z);
+ if Is_0 then
+ Res := Build_Const_UB32 (Ctxt, 0, W);
+ elsif Is_X then
+ Res := Build_Const_X (Ctxt, W);
+ elsif Is_Z then
+ Res := Build_Const_Z (Ctxt, W);
+ elsif not Has_Zx then
+ Inst := Build_Const_Bit (Ctxt, W);
+ for I in Vec'Range loop
+ Set_Param_Uns32 (Inst, Param_Idx (I), Vec (I).Val);
+ end loop;
+ Res := Get_Output (Inst, 0);
+ else
+ Inst := Build_Const_Log (Ctxt, W);
+ for I in Vec'Range loop
+ Set_Param_Uns32 (Inst, Param_Idx (2 * I), Vec (I).Val);
+ Set_Param_Uns32 (Inst, Param_Idx (2 * I + 1), Vec (I).Zx);
+ end loop;
+ Res := Get_Output (Inst, 0);
+ end if;
+ end if;
+ end Value2net;
+
+ function Get_Partial_Memtyp_Net
+ (Ctxt : Context_Acc; Val : Memtyp; Off : Uns32; Wd : Width) return Net
+ is
+ Nd : constant Digit_Index := Digit_Index ((Wd + 31) / 32);
+ Res : Net;
+ begin
+ if Nd > 64 then
+ declare
+ Vecp : Logvec_Array_Acc;
+ begin
+ Vecp := new Logvec_Array'(0 .. Nd - 1 => (0, 0));
+ Value2net (Ctxt, Val, Off, Wd, Vecp.all, Res);
+ Free_Logvec_Array (Vecp);
+ return Res;
+ end;
+ else
+ declare
+ Vec : Logvec_Array (0 .. Nd - 1) := (others => (0, 0));
+ begin
+ Value2net (Ctxt, Val, Off, Wd, Vec, Res);
+ return Res;
+ end;
+ end if;
+ end Get_Partial_Memtyp_Net;
+
+ function Get_Memtyp_Net (Ctxt : Context_Acc; Val : Memtyp) return Net is
+ begin
+ return Get_Partial_Memtyp_Net (Ctxt, Val, 0, Val.Typ.W);
+ end Get_Memtyp_Net;
+
+ function Get_Net (Ctxt : Context_Acc; Val : Valtyp) return Net is
+ begin
+ case Val.Val.Kind is
+ when Value_Wire =>
+ return Get_Current_Value (Ctxt, Val.Val.W);
+ when Value_Net =>
+ return Val.Val.N;
+ when Value_Alias =>
+ declare
+ Res : Net;
+ begin
+ if Val.Val.A_Obj.Kind = Value_Wire then
+ Res := Get_Current_Value (Ctxt, Val.Val.A_Obj.W);
+ return Build2_Extract
+ (Ctxt, Res, Val.Val.A_Off.Net_Off, Val.Typ.W);
+ else
+ pragma Assert (Val.Val.A_Off.Net_Off = 0);
+ return Get_Net (Ctxt, (Val.Typ, Val.Val.A_Obj));
+ end if;
+ end;
+ when Value_Const =>
+ if Val.Val.C_Net = No_Net then
+ Val.Val.C_Net := Get_Net (Ctxt, (Val.Typ, Val.Val.C_Val));
+ Locations.Set_Location (Get_Net_Parent (Val.Val.C_Net),
+ Get_Location (Val.Val.C_Loc));
+ end if;
+ return Val.Val.C_Net;
+ when Value_Memory =>
+ return Get_Memtyp_Net (Ctxt, Get_Memtyp (Val));
+ when others =>
+ raise Internal_Error;
+ end case;
+ end Get_Net;
+end Synth.Vhdl_Context;