aboutsummaryrefslogtreecommitdiffstats
path: root/src/synth/elab-vhdl_values.adb
diff options
context:
space:
mode:
Diffstat (limited to 'src/synth/elab-vhdl_values.adb')
-rw-r--r--src/synth/elab-vhdl_values.adb500
1 files changed, 500 insertions, 0 deletions
diff --git a/src/synth/elab-vhdl_values.adb b/src/synth/elab-vhdl_values.adb
new file mode 100644
index 000000000..90e72f223
--- /dev/null
+++ b/src/synth/elab-vhdl_values.adb
@@ -0,0 +1,500 @@
+-- Values in 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_Conversion;
+with System;
+
+with Grt.Types; use Grt.Types;
+
+package body Elab.Vhdl_Values is
+ function To_Value_Acc is new Ada.Unchecked_Conversion
+ (System.Address, Value_Acc);
+
+ function Is_Static (Val : Value_Acc) return Boolean is
+ begin
+ case Val.Kind is
+ when Value_Memory =>
+ return True;
+ when Value_Net
+ | Value_Wire
+ | Value_Signal =>
+ return False;
+ when Value_File =>
+ return True;
+ when Value_Alias =>
+ return Is_Static (Val.A_Obj);
+ when Value_Const =>
+ return True;
+ end case;
+ end Is_Static;
+
+ function Strip_Alias_Const (V : Value_Acc) return Value_Acc
+ is
+ Res : Value_Acc;
+ begin
+ Res := V;
+ loop
+ case Res.Kind is
+ when Value_Const =>
+ Res := Res.C_Val;
+ when Value_Alias =>
+ if Res.A_Off /= (0, 0) then
+ raise Internal_Error;
+ end if;
+ Res := Res.A_Obj;
+ when others =>
+ return Res;
+ end case;
+ end loop;
+ end Strip_Alias_Const;
+
+ function Strip_Alias_Const (V : Valtyp) return Valtyp is
+ begin
+ return (V.Typ, Strip_Alias_Const (V.Val));
+ end Strip_Alias_Const;
+
+ function Is_Equal (L, R : Valtyp) return Boolean is
+ begin
+ return Is_Equal (Get_Memtyp (L), Get_Memtyp (R));
+ end Is_Equal;
+
+ function Create_Value_Memtyp (Mt : Memtyp) return Valtyp
+ is
+ subtype Value_Type_Memory is Value_Type (Value_Memory);
+ function Alloc is new Areapools.Alloc_On_Pool_Addr (Value_Type_Memory);
+ Res : Value_Acc;
+ begin
+ Res := To_Value_Acc (Alloc (Current_Pool, (Kind => Value_Memory,
+ Mem => Mt.Mem)));
+ return (Mt.Typ, Res);
+ end Create_Value_Memtyp;
+
+ function Create_Value_Wire (S : Uns32) return Value_Acc
+ is
+ subtype Value_Type_Wire is Value_Type (Value_Wire);
+ function Alloc is new Areapools.Alloc_On_Pool_Addr (Value_Type_Wire);
+ begin
+ return To_Value_Acc
+ (Alloc (Current_Pool, (Kind => Value_Wire, N => S)));
+ end Create_Value_Wire;
+
+ function Create_Value_Net (S : Uns32) return Value_Acc
+ is
+ subtype Value_Type_Net is Value_Type (Value_Net);
+ function Alloc is new Areapools.Alloc_On_Pool_Addr (Value_Type_Net);
+ begin
+ return To_Value_Acc
+ (Alloc (Current_Pool, Value_Type_Net'(Kind => Value_Net, N => S)));
+ end Create_Value_Net;
+
+ function Create_Value_Signal (S : Uns32; Init : Value_Acc) return Value_Acc
+ is
+ subtype Value_Type_Signal is Value_Type (Value_Signal);
+ function Alloc is new Areapools.Alloc_On_Pool_Addr (Value_Type_Signal);
+ begin
+ return To_Value_Acc
+ (Alloc (Current_Pool, Value_Type_Signal'(Kind => Value_Signal,
+ S => S,
+ Init => Init)));
+ end Create_Value_Signal;
+
+ function Create_Value_Memory (Vtype : Type_Acc) return Valtyp
+ is
+ subtype Value_Type_Memory is Value_Type (Value_Memory);
+ function Alloc is new Areapools.Alloc_On_Pool_Addr (Value_Type_Memory);
+ function To_Memory_Ptr is new Ada.Unchecked_Conversion
+ (System.Address, Memory_Ptr);
+ V : Value_Acc;
+ M : System.Address;
+ begin
+ Areapools.Allocate (Current_Pool.all, M,
+ Vtype.Sz, Size_Type (2 ** Natural (Vtype.Al)));
+ V := To_Value_Acc
+ (Alloc (Current_Pool, Value_Type_Memory'(Kind => Value_Memory,
+ Mem => To_Memory_Ptr (M))));
+
+ return (Vtype, V);
+ end Create_Value_Memory;
+
+ function Create_Value_Memory (Mt : Memtyp) return Valtyp
+ is
+ subtype Value_Type_Memory is Value_Type (Value_Memory);
+ function Alloc is new Areapools.Alloc_On_Pool_Addr (Value_Type_Memory);
+ V : Value_Acc;
+ begin
+ V := To_Value_Acc
+ (Alloc (Current_Pool, Value_Type_Memory'(Kind => Value_Memory,
+ Mem => Mt.Mem)));
+
+ return (Mt.Typ, V);
+ end Create_Value_Memory;
+
+ function Create_Value_File (File : File_Index) return Value_Acc
+ is
+ subtype Value_Type_File is Value_Type (Value_File);
+ function Alloc is new Areapools.Alloc_On_Pool_Addr (Value_Type_File);
+ begin
+ return To_Value_Acc (Alloc (Current_Pool,
+ (Kind => Value_File, File => File)));
+ end Create_Value_File;
+
+ function Create_Value_File (Vtype : Type_Acc; File : File_Index)
+ return Valtyp
+ is
+ pragma Assert (Vtype /= null);
+ begin
+ return (Vtype, Create_Value_File (File));
+ end Create_Value_File;
+
+ function Vec_Length (Typ : Type_Acc) return Iir_Index32 is
+ begin
+ return Iir_Index32 (Typ.Vbound.Len);
+ end Vec_Length;
+
+ function Get_Array_Flat_Length (Typ : Type_Acc) return Iir_Index32 is
+ begin
+ case Typ.Kind is
+ when Type_Vector =>
+ return Iir_Index32 (Typ.Vbound.Len);
+ when Type_Array =>
+ declare
+ Len : Uns32;
+ begin
+ Len := 1;
+ for I in Typ.Abounds.D'Range loop
+ Len := Len * Typ.Abounds.D (I).Len;
+ end loop;
+ return Iir_Index32 (Len);
+ end;
+ when others =>
+ raise Internal_Error;
+ end case;
+ end Get_Array_Flat_Length;
+
+ function Create_Value_Alias
+ (Obj : Valtyp; Off : Value_Offsets; Typ : Type_Acc) return Valtyp
+ is
+ pragma Assert (Typ /= null);
+ subtype Value_Type_Alias is Value_Type (Value_Alias);
+ function Alloc is new Areapools.Alloc_On_Pool_Addr (Value_Type_Alias);
+ Val : Value_Acc;
+ begin
+ Val := To_Value_Acc (Alloc (Current_Pool,
+ (Kind => Value_Alias,
+ A_Obj => Obj.Val,
+ A_Typ => Obj.Typ,
+ A_Off => Off)));
+ return (Typ, Val);
+ end Create_Value_Alias;
+
+ function Create_Value_Const (Val : Value_Acc; Loc : Node) return Value_Acc
+ is
+ subtype Value_Type_Const is Value_Type (Value_Const);
+ function Alloc is new Areapools.Alloc_On_Pool_Addr (Value_Type_Const);
+ begin
+ pragma Assert (Val = null or else Val.Kind /= Value_Const);
+ return To_Value_Acc (Alloc (Current_Pool,
+ (Kind => Value_Const,
+ C_Val => Val,
+ C_Loc => Loc,
+ C_Net => 0)));
+ end Create_Value_Const;
+
+ function Create_Value_Const (Val : Valtyp; Loc : Node) return Valtyp is
+ begin
+ return (Val.Typ, Create_Value_Const (Val.Val, Loc));
+ end Create_Value_Const;
+
+ procedure Strip_Const (Vt : in out Valtyp) is
+ begin
+ if Vt.Val.Kind = Value_Const then
+ Vt.Val := Vt.Val.C_Val;
+ end if;
+ end Strip_Const;
+
+ procedure Write_Value (Dest : Memory_Ptr; Vt : Valtyp)
+ is
+ Mt : Memtyp;
+ begin
+ Mt := Get_Memtyp (Vt);
+ Copy_Memory (Dest, Mt.Mem, Mt.Typ.Sz);
+ end Write_Value;
+
+ function Copy (Src : Valtyp) return Valtyp
+ is
+ Res : Valtyp;
+ begin
+ case Src.Val.Kind is
+ when Value_Memory =>
+ Res := Create_Value_Memory (Src.Typ);
+ for I in 1 .. Src.Typ.Sz loop
+ Res.Val.Mem (I - 1) := Src.Val.Mem (I - 1);
+ end loop;
+ when Value_Net =>
+ Res := (Src.Typ, Create_Value_Net (Src.Val.S));
+ when Value_Wire =>
+ Res := (Src.Typ, Create_Value_Wire (Src.Val.S));
+ when Value_File =>
+ Res := Create_Value_File (Src.Typ, Src.Val.File);
+ when Value_Signal =>
+ raise Internal_Error;
+ when Value_Const =>
+ raise Internal_Error;
+ when Value_Alias =>
+ raise Internal_Error;
+ end case;
+ return Res;
+ end Copy;
+
+ function Unshare (Src : Valtyp; Pool : Areapool_Acc) return Valtyp
+ is
+ Prev_Pool : constant Areapool_Acc := Current_Pool;
+ Res : Valtyp;
+ begin
+ Current_Pool := Pool;
+ Res := Copy (Src);
+ Current_Pool := Prev_Pool;
+ return Res;
+ end Unshare;
+
+ procedure Write_Access (Mem : Memory_Ptr; Val : Heap_Index)
+ is
+ V : Heap_Index;
+ for V'Address use Mem.all'Address;
+ pragma Import (Ada, V);
+ begin
+ V := Val;
+ end Write_Access;
+
+ function Read_Access (Mem : Memory_Ptr) return Heap_Index
+ is
+ V : Heap_Index;
+ for V'Address use Mem.all'Address;
+ pragma Import (Ada, V);
+ begin
+ return V;
+ end Read_Access;
+
+ function Read_Access (Mt : Memtyp) return Heap_Index is
+ begin
+ return Read_Access (Mt.Mem);
+ end Read_Access;
+
+ procedure Write_Discrete (Vt : Valtyp; Val : Int64) is
+ begin
+ Write_Discrete (Vt.Val.Mem, Vt.Typ, Val);
+ end Write_Discrete;
+
+ function Read_Discrete (Vt : Valtyp) return Int64 is
+ begin
+ return Read_Discrete (Get_Memtyp (Vt));
+ end Read_Discrete;
+
+ function Create_Value_Float (Val : Fp64; Vtype : Type_Acc) return Valtyp
+ is
+ Res : Valtyp;
+ pragma Assert (Vtype /= null);
+ begin
+ Res := Create_Value_Memory (Vtype);
+ Write_Fp64 (Res.Val.Mem, Val);
+ return Res;
+ end Create_Value_Float;
+
+ function Read_Fp64 (Vt : Valtyp) return Fp64 is
+ begin
+ pragma Assert (Vt.Typ.Kind = Type_Float);
+ pragma Assert (Vt.Typ.Sz = 8);
+ return Read_Fp64 (Vt.Val.Mem);
+ end Read_Fp64;
+
+ function Read_Access (Vt : Valtyp) return Heap_Index is
+ begin
+ pragma Assert (Vt.Typ.Kind = Type_Access);
+ return Read_Access (Vt.Val.Mem);
+ end Read_Access;
+
+ function Create_Value_Discrete (Val : Int64; Vtype : Type_Acc) return Valtyp
+ is
+ Res : Valtyp;
+ begin
+ Res := Create_Value_Memory (Vtype);
+ case Vtype.Sz is
+ when 1 =>
+ Write_U8 (Res.Val.Mem, Ghdl_U8 (Val));
+ when 4 =>
+ Write_I32 (Res.Val.Mem, Ghdl_I32 (Val));
+ when 8 =>
+ Write_I64 (Res.Val.Mem, Ghdl_I64 (Val));
+ when others =>
+ raise Internal_Error;
+ end case;
+ return Res;
+ end Create_Value_Discrete;
+
+ function Create_Value_Uns (Val : Uns64; Vtype : Type_Acc) return Valtyp
+ is
+ Res : Valtyp;
+ begin
+ Res := Create_Value_Memory (Vtype);
+ case Vtype.Sz is
+ when 1 =>
+ Write_U8 (Res.Val.Mem, Ghdl_U8 (Val));
+ when 4 =>
+ Write_U32 (Res.Val.Mem, Ghdl_U32 (Val));
+ when others =>
+ raise Internal_Error;
+ end case;
+ return Res;
+ end Create_Value_Uns;
+
+ function Create_Value_Int (Val : Int64; Vtype : Type_Acc) return Valtyp
+ is
+ Res : Valtyp;
+ begin
+ Res := Create_Value_Memory (Vtype);
+ case Vtype.Sz is
+ when 4 =>
+ Write_I32 (Res.Val.Mem, Ghdl_I32 (Val));
+ when 8 =>
+ Write_I64 (Res.Val.Mem, Ghdl_I64 (Val));
+ when others =>
+ raise Internal_Error;
+ end case;
+ return Res;
+ end Create_Value_Int;
+
+ function Arr_Index (M : Memory_Ptr; Idx : Iir_Index32; El_Typ : Type_Acc)
+ return Memory_Ptr is
+ begin
+ return M + Size_Type (Idx) * El_Typ.Sz;
+ end Arr_Index;
+
+ procedure Write_Value_Default (M : Memory_Ptr; Typ : Type_Acc) is
+ begin
+ case Typ.Kind is
+ when Type_Bit
+ | Type_Logic =>
+ -- FIXME: what about subtype ?
+ Write_U8 (M, 0);
+ when Type_Discrete =>
+ Write_Discrete (M, Typ, Typ.Drange.Left);
+ when Type_Float =>
+ Write_Fp64 (M, Typ.Frange.Left);
+ when Type_Vector =>
+ declare
+ Len : constant Iir_Index32 := Vec_Length (Typ);
+ El_Typ : constant Type_Acc := Typ.Vec_El;
+ begin
+ for I in 1 .. Len loop
+ Write_Value_Default (Arr_Index (M, I - 1, El_Typ), El_Typ);
+ end loop;
+ end;
+ when Type_Unbounded_Vector
+ | Type_Unbounded_Array
+ | Type_Unbounded_Record =>
+ raise Internal_Error;
+ when Type_Slice =>
+ raise Internal_Error;
+ when Type_Array =>
+ declare
+ Len : constant Iir_Index32 := Get_Array_Flat_Length (Typ);
+ El_Typ : constant Type_Acc := Typ.Arr_El;
+ begin
+ for I in 1 .. Len loop
+ Write_Value_Default (Arr_Index (M, I - 1, El_Typ), El_Typ);
+ end loop;
+ end;
+ when Type_Record =>
+ for I in Typ.Rec.E'Range loop
+ Write_Value_Default (M + Typ.Rec.E (I).Moff, Typ.Rec.E (I).Typ);
+ end loop;
+ when Type_Access =>
+ Write_Access (M, Null_Heap_Index);
+ when Type_File
+ | Type_Protected =>
+ raise Internal_Error;
+ end case;
+ end Write_Value_Default;
+
+ function Create_Value_Default (Typ : Type_Acc) return Valtyp
+ is
+ Res : Valtyp;
+ begin
+ Res := Create_Value_Memory (Typ);
+ Write_Value_Default (Res.Val.Mem, Typ);
+ return Res;
+ end Create_Value_Default;
+
+ function Create_Value_Access (Val : Heap_Index; Acc_Typ : Type_Acc)
+ return Valtyp
+ is
+ Res : Valtyp;
+ begin
+ Res := Create_Value_Memory (Acc_Typ);
+ Write_Access (Res.Val.Mem, Val);
+ return Res;
+ end Create_Value_Access;
+
+ function Value_To_String (Val : Valtyp) return String
+ is
+ Str : String (1 .. Natural (Val.Typ.Abounds.D (1).Len));
+ begin
+ for I in Str'Range loop
+ Str (Natural (I)) := Character'Val
+ (Read_U8 (Val.Val.Mem + Size_Type (I - 1)));
+ end loop;
+ return Str;
+ end Value_To_String;
+
+ function Get_Memtyp (V : Valtyp) return Memtyp is
+ begin
+ case V.Val.Kind is
+ when Value_Net
+ | Value_Wire
+ | Value_Signal =>
+ raise Internal_Error;
+ when Value_Memory =>
+ return (V.Typ, V.Val.Mem);
+ when Value_Alias =>
+ declare
+ T : Memtyp;
+ begin
+ T := Get_Memtyp ((V.Typ, V.Val.A_Obj));
+ return (T.Typ, T.Mem + V.Val.A_Off.Mem_Off);
+ end;
+ when Value_Const =>
+ return Get_Memtyp ((V.Typ, V.Val.C_Val));
+ when Value_File =>
+ raise Internal_Error;
+ end case;
+ end Get_Memtyp;
+
+ 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;
+end Elab.Vhdl_Values;