aboutsummaryrefslogtreecommitdiffstats
path: root/src/synth/synth-inference.ads
blob: 5777e04e477e404356123213b63d85fb95eab81d (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
--  Inference 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, write to the Free Software
--  Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston,
--  MA 02110-1301, USA.

with Netlists; use Netlists;
with Netlists.Builders; use Netlists.Builders;

package Synth.Inference is
   --  To be called when there is an assignment to a signal/output of VAL and
   --  the previous value is PREV_VAL (an Id_Signal or Id_Output).
   --  If there is a loop, infere a dff or a latch or emit an error.
   function Infere (Ctxt : Context_Acc; Val : Net; Prev_Val : Net) return Net;
end Synth.Inference;
href='#n279'>279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338
--  GHDL Run Time (GRT) -  RTI address handling.
--  Copyright (C) 2002 - 2014 Tristan Gingold
--
--  GHDL 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, or (at your option) any later
--  version.
--
--  GHDL 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 GCC; see the file COPYING.  If not, write to the Free
--  Software Foundation, 59 Temple Place - Suite 330, Boston, MA
--  02111-1307, USA.
--
--  As a special exception, if other files instantiate generics from this
--  unit, or you link this unit with other files to produce an executable,
--  this unit does not by itself cause the resulting executable to be
--  covered by the GNU General Public License. This exception does not
--  however invalidate any other reasons why the executable file might be
--  covered by the GNU Public License.
with Grt.Errors; use Grt.Errors;

package body Grt.Rtis_Addr is
   function "+" (L : Address; R : Ghdl_Rti_Loc) return Address
   is
   begin
      return To_Address (To_Integer (L) + R);
   end "+";

   function "+" (L : Address; R : Ghdl_Index_Type) return Address
   is
   begin
      return To_Address (To_Integer (L) + Integer_Address (R));
   end "+";

   function "-" (L : Address; R : Ghdl_Rti_Loc) return Address
   is
   begin
      return To_Address (To_Integer (L) - R);
   end "-";

   function Align (L : Address; R : Ghdl_Rti_Loc) return Address
   is
      Nad : Integer_Address;
   begin
      Nad := To_Integer (L + (R - 1));
      return To_Address (Nad - (Nad mod R));
   end Align;

   function Get_Parent_Context (Ctxt : Rti_Context) return Rti_Context
   is
      Blk : constant Ghdl_Rtin_Block_Acc :=
        To_Ghdl_Rtin_Block_Acc (Ctxt.Block);
   begin
      case Ctxt.Block.Kind is
         when Ghdl_Rtik_Process
           | Ghdl_Rtik_Block =>
            return (Base => Ctxt.Base - Blk.Loc,
                    Block => Blk.Parent);
         when Ghdl_Rtik_Architecture =>
            if Blk.Loc /= Null_Rti_Loc then
               Internal_Error ("get_parent_context(3)");
            end if;
            return (Base => Ctxt.Base + Blk.Loc,
                    Block => Blk.Parent);
         when Ghdl_Rtik_Generate_Body =>
            declare
               Nbase : Address;
               Nblk : Ghdl_Rti_Access;
               Parent : Ghdl_Rti_Access;
            begin
               --  Read the pointer to the parent.
               --  This is the first field.
               Nbase := To_Addr_Acc (Ctxt.Base).all;
               --  Parent (by default).
               Nblk := Blk.Parent;
               --  Since the parent may be a grant-parent, adjust
               --  the base (so that the substraction above will work).
               Parent := Blk.Parent;
               loop
                  case Parent.Kind is
                     when Ghdl_Rtik_Architecture
                       | Ghdl_Rtik_Generate_Body =>
                        exit;
                     when Ghdl_Rtik_Block =>
                        declare
                           Blk1 : constant Ghdl_Rtin_Block_Acc :=
                             To_Ghdl_Rtin_Block_Acc (Parent);
                        begin
                           Nbase := Nbase + Blk1.Loc;
                           Parent := Blk1.Parent;
                        end;
                     when Ghdl_Rtik_For_Generate
                       | Ghdl_Rtik_If_Generate =>
                        declare
                           Gen : constant Ghdl_Rtin_Generate_Acc :=
                             To_Ghdl_Rtin_Generate_Acc (Parent);
                        begin
                           Parent := Gen.Parent;
                           --  For/If generate statement are not blocks.  Skip
                           --  them.
                           Nblk := Gen.Parent;
                        end;
                     when others =>
                        Internal_Error ("get_parent_context(2)");
                  end case;
               end loop;
               return (Base => Nbase,
                       Block => Nblk);
            end;
         when others =>
            Internal_Error ("get_parent_context(1)");
      end case;
   end Get_Parent_Context;

   procedure Get_Instance_Link (Link : Ghdl_Entity_Link_Acc;
                                Ctxt : out Rti_Context;
                                Stmt : out Ghdl_Rti_Access)
   is
      Obj : Ghdl_Rtin_Instance_Acc;
   begin
      if Link.Parent = null then
         --  Top entity.
         Stmt := null;
         Ctxt := (Base => Null_Address, Block => null);
      else
         Stmt := Link.Parent.Stmt;
         Obj := To_Ghdl_Rtin_Instance_Acc (Stmt);
         Ctxt := (Base => Link.Parent.all'Address - Obj.Loc,
                  Block => Obj.Parent);
      end if;
   end Get_Instance_Link;

   function Get_If_Case_Generate_Child
     (Ctxt : Rti_Context; Gen : Ghdl_Rti_Access) return Rti_Context
   is
      pragma Assert (Gen.Kind = Ghdl_Rtik_If_Generate
                       or Gen.Kind = Ghdl_Rtik_Case_Generate);
      Blk : constant Ghdl_Rtin_Block_Acc := To_Ghdl_Rtin_Block_Acc (Gen);
      Base_Addr : constant Address := Ctxt.Base + Blk.Loc;

      --  Address of the block_id field.  It is just after the instance field.
      --  Assume alignment is ok (it is on 32 and 64 bit platforms).
      Id_Addr : constant Address :=
        Base_Addr + Ghdl_Index_Type'(Address'Size / Storage_Unit);
      Id : Ghdl_Index_Type;
      pragma Import (Ada, Id);
      for Id'Address use Id_Addr;
   begin
      return (Base => To_Addr_Acc (Base_Addr).all,
              Block => Blk.Children (Id));
   end Get_If_Case_Generate_Child;

   function Loc_To_Addr (Depth : Ghdl_Rti_Depth;
                         Loc : Ghdl_Rti_Loc;
                         Ctxt : Rti_Context)
                        return Address
   is
      Cur_Ctxt : Rti_Context;
      Nctxt : Rti_Context;
   begin
      if Depth = 0 then
         return To_Address (Loc);
      elsif Ctxt.Block.Depth = Depth then
         --Addr := Base + Storage_Offset (Obj.Loc.Off);
         return Ctxt.Base + Loc;
      else
         if Ctxt.Block.Depth < Depth then
            Internal_Error ("loc_to_addr");
         end if;
         Cur_Ctxt := Ctxt;
         loop
            Nctxt := Get_Parent_Context (Cur_Ctxt);
            if Nctxt.Block.Depth = Depth then
               return Nctxt.Base + Loc;
            end if;
            Cur_Ctxt := Nctxt;
         end loop;
      end if;
   end Loc_To_Addr;

   function Range_To_Length (Rng : Ghdl_Range_Ptr; Base_Type : Ghdl_Rti_Access)
                            return Ghdl_Index_Type
   is
   begin
      case Base_Type.Kind is
         when Ghdl_Rtik_Type_B1 =>
            return Rng.B1.Len;
         when Ghdl_Rtik_Type_E8 =>
            return Rng.E8.Len;
         when Ghdl_Rtik_Type_E32 =>
            return Rng.E32.Len;
         when Ghdl_Rtik_Type_I32 =>
            return Rng.I32.Len;
         when others =>
            Internal_Error ("range_to_length");
      end case;
   end Range_To_Length;

   function Get_For_Generate_Length (Gen : Ghdl_Rtin_Generate_Acc;
                                     Ctxt : Rti_Context)
                                    return Ghdl_Index_Type
   is
      Bod : constant Ghdl_Rtin_Block_Acc :=
        To_Ghdl_Rtin_Block_Acc (Gen.Child);
      Iter_Type : Ghdl_Rtin_Subtype_Scalar_Acc;
      Rng : Ghdl_Range_Ptr;
   begin
      Iter_Type := To_Ghdl_Rtin_Subtype_Scalar_Acc
        (To_Ghdl_Rtin_Object_Acc (Bod.Children (0)).Obj_Type);
      if Iter_Type.Common.Kind /= Ghdl_Rtik_Subtype_Scalar then
         Internal_Error ("get_for_generate_length(1)");
      end if;
      Rng := To_Ghdl_Range_Ptr
        (Loc_To_Addr (Iter_Type.Common.Depth, Iter_Type.Range_Loc, Ctxt));
      return Range_To_Length (Rng, Iter_Type.Basetype);
   end Get_For_Generate_Length;

   procedure Get_Instance_Context (Inst : Ghdl_Rtin_Instance_Acc;
                                   Ctxt : Rti_Context;
                                   Sub_Ctxt : out Rti_Context)
   is
      --  Address of the field containing the address of the instance.
      Inst_Addr : constant Address := Ctxt.Base + Inst.Loc;
      --  Read sub instance address.
      Inst_Base : constant Address := To_Addr_Acc (Inst_Addr).all;
   begin
      --  Read instance RTI.
      if Inst_Base = Null_Address then
         --  No instance.
         Sub_Ctxt := (Base => Null_Address, Block => null);
      else
         Sub_Ctxt := (Base => Inst_Base,
                      Block => To_Ghdl_Rti_Acc_Acc (Inst_Base).all);
      end if;
   end Get_Instance_Context;

   procedure Extract_Range (Bounds : in out Address;
                            Def : Ghdl_Rti_Access;
                            Rng : out Ghdl_Range_Ptr)
   is
      procedure Align (A : Ghdl_Index_Type) is
      begin
         Bounds := Align (Bounds, Ghdl_Rti_Loc (A));
      end Align;

      procedure Update (S : Ghdl_Index_Type) is
      begin
         Bounds := Bounds + (S / Storage_Unit);
      end Update;
   begin
      if Bounds = Null_Address then
         --  Propagate failure.
         Rng := null;
         return;
      end if;

      case Def.Kind is
         when Ghdl_Rtik_Type_I32 =>
            Align (Ghdl_Range_I32'Alignment);
            Rng := To_Ghdl_Range_Ptr (Bounds);
            Update (Ghdl_Range_I32'Size);
         when Ghdl_Rtik_Type_B1 =>
            Align (Ghdl_Range_B1'Alignment);
            Rng := To_Ghdl_Range_Ptr (Bounds);
            Update (Ghdl_Range_B1'Size);
         when Ghdl_Rtik_Type_E8 =>
            Align (Ghdl_Range_E8'Alignment);
            Rng := To_Ghdl_Range_Ptr (Bounds);
            Update (Ghdl_Range_E8'Size);
         when others =>
            --  Bounds are not known anymore.
            Rng := null;
      end case;
   end Extract_Range;

   procedure Bound_To_Range (Bounds_Addr : Address;
                             Def : Ghdl_Rtin_Type_Array_Acc;
                             Res : out Ghdl_Range_Array)
   is
      Bounds : Address;
      Idx_Def : Ghdl_Rti_Access;
   begin
      if Res'Length /= Def.Nbr_Dim or else Res'First /= 0 then
         Internal_Error ("disp_rti.bound_to_range");
      end if;

      Bounds := Bounds_Addr;

      for I in 0 .. Def.Nbr_Dim - 1 loop
         Idx_Def := Def.Indexes (I);
         Idx_Def := Get_Base_Type (Idx_Def);
         Extract_Range (Bounds, Idx_Def, Res (I));
      end loop;
   end Bound_To_Range;

   function Get_Base_Type (Atype : Ghdl_Rti_Access) return Ghdl_Rti_Access is
   begin
      case Atype.Kind is
         when Ghdl_Rtik_Subtype_Scalar =>
            return To_Ghdl_Rtin_Subtype_Scalar_Acc (Atype).Basetype;
         when Ghdl_Rtik_Subtype_Array =>
            return To_Ghdl_Rtin_Subtype_Composite_Acc (Atype).Basetype;
         when Ghdl_Rtik_Type_E8
           | Ghdl_Rtik_Type_E32
           | Ghdl_Rtik_Type_B1 =>
            return Atype;
         when others =>
            Internal_Error ("rtis_addr.get_base_type");
      end case;
   end Get_Base_Type;

   function Rti_Complex_Type (Atype : Ghdl_Rti_Access) return Boolean is
   begin
      return (Atype.Mode and Ghdl_Rti_Type_Complex_Mask)
        = Ghdl_Rti_Type_Complex;
   end Rti_Complex_Type;

   function Rti_Anonymous_Type (Atype : Ghdl_Rti_Access) return Boolean is
   begin
      return (Atype.Mode and Ghdl_Rti_Type_Anonymous_Mask)
        = Ghdl_Rti_Type_Anonymous;
   end Rti_Anonymous_Type;

   function Get_Top_Context return Rti_Context
   is
      Ctxt : Rti_Context;
   begin
      Ctxt := (Base => Ghdl_Rti_Top_Instance,
               Block => Ghdl_Rti_Top.Parent);
      return Ctxt;
   end Get_Top_Context;

end Grt.Rtis_Addr;