1--  Synthesis context.
2--  Copyright (C) 2017 Tristan Gingold
3--
4--  This file is part of GHDL.
5--
6--  This program is free software; you can redistribute it and/or modify
7--  it under the terms of the GNU General Public License as published by
8--  the Free Software Foundation; either version 2 of the License, or
9--  (at your option) any later version.
10--
11--  This program is distributed in the hope that it will be useful,
12--  but WITHOUT ANY WARRANTY; without even the implied warranty of
13--  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14--  GNU General Public License for more details.
15--
16--  You should have received a copy of the GNU General Public License
17--  along with this program; if not, write to the Free Software
18--  Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston,
19--  MA 02110-1301, USA.
20
21with Ada.Unchecked_Deallocation;
22
23with Name_Table; use Name_Table;
24with Types_Utils; use Types_Utils;
25
26with Vhdl.Errors; use Vhdl.Errors;
27with Vhdl.Utils;
28
29with Netlists.Folds; use Netlists.Folds;
30
31with Synth.Expr; use Synth.Expr;
32with Netlists.Locations;
33
34package body Synth.Context is
35   function Make_Base_Instance return Synth_Instance_Acc
36   is
37      Base : Base_Instance_Acc;
38      Top_Module : Module;
39      Res : Synth_Instance_Acc;
40      Ctxt : Context_Acc;
41   begin
42      Top_Module :=
43        New_Design (New_Sname_Artificial (Get_Identifier ("top"), No_Sname));
44      Ctxt := Build_Builders (Top_Module);
45
46      Base := new Base_Instance_Type'(Builder => Ctxt,
47                                      Top_Module => Top_Module,
48                                      Cur_Module => No_Module);
49
50      Res := new Synth_Instance_Type'(Max_Objs => Global_Info.Nbr_Objects,
51                                      Is_Const => False,
52                                      Is_Error => False,
53                                      Base => Base,
54                                      Name => No_Sname,
55                                      Block_Scope => Global_Info,
56                                      Up_Block => null,
57                                      Uninst_Scope => null,
58                                      Source_Scope => Null_Node,
59                                      Elab_Objects => 0,
60                                      Objects => (others =>
61                                                    (Kind => Obj_None)));
62      return Res;
63   end Make_Base_Instance;
64
65   procedure Free_Base_Instance is
66   begin
67      --  TODO: really free.
68      null;
69   end Free_Base_Instance;
70
71   function Make_Instance (Parent : Synth_Instance_Acc;
72                           Blk : Node;
73                           Name : Sname := No_Sname)
74                          return Synth_Instance_Acc
75   is
76      Info : constant Sim_Info_Acc := Get_Info (Blk);
77      Scope : Sim_Info_Acc;
78      Res : Synth_Instance_Acc;
79   begin
80      if Get_Kind (Blk) = Iir_Kind_Architecture_Body then
81         --  Architectures are extensions of entities.
82         Scope := Get_Info (Vhdl.Utils.Get_Entity (Blk));
83      else
84         Scope := Info;
85      end if;
86
87      Res := new Synth_Instance_Type'(Max_Objs => Info.Nbr_Objects,
88                                      Is_Const => False,
89                                      Is_Error => False,
90                                      Base => Parent.Base,
91                                      Name => Name,
92                                      Block_Scope => Scope,
93                                      Up_Block => Parent,
94                                      Uninst_Scope => null,
95                                      Source_Scope => Blk,
96                                      Elab_Objects => 0,
97                                      Objects => (others =>
98                                                    (Kind => Obj_None)));
99      return Res;
100   end Make_Instance;
101
102   procedure Set_Instance_Base (Inst : Synth_Instance_Acc;
103                                Base : Synth_Instance_Acc) is
104   begin
105      Inst.Base := Base.Base;
106   end Set_Instance_Base;
107
108   procedure Free_Instance (Synth_Inst : in out Synth_Instance_Acc)
109   is
110      procedure Deallocate is new Ada.Unchecked_Deallocation
111        (Synth_Instance_Type, Synth_Instance_Acc);
112   begin
113      Deallocate (Synth_Inst);
114   end Free_Instance;
115
116   procedure Set_Instance_Module (Inst : Synth_Instance_Acc; M : Module)
117   is
118      Prev_Base : constant Base_Instance_Acc := Inst.Base;
119      Base : Base_Instance_Acc;
120      Self_Inst : Instance;
121   begin
122      Base := new Base_Instance_Type'(Builder => Prev_Base.Builder,
123                                      Top_Module => Prev_Base.Top_Module,
124                                      Cur_Module => M);
125      Builders.Set_Parent (Base.Builder, M);
126
127      Self_Inst := Create_Self_Instance (M);
128      pragma Unreferenced (Self_Inst);
129
130      Inst.Base := Base;
131   end Set_Instance_Module;
132
133   function Is_Error (Inst : Synth_Instance_Acc) return Boolean is
134   begin
135      return Inst.Is_Error;
136   end Is_Error;
137
138   procedure Set_Error (Inst : Synth_Instance_Acc) is
139   begin
140      Inst.Is_Error := True;
141   end Set_Error;
142
143   function Get_Instance_Module (Inst : Synth_Instance_Acc) return Module is
144   begin
145      return Inst.Base.Cur_Module;
146   end Get_Instance_Module;
147
148   function Get_Source_Scope (Inst : Synth_Instance_Acc) return Node is
149   begin
150      return Inst.Source_Scope;
151   end Get_Source_Scope;
152
153   function Get_Top_Module (Inst : Synth_Instance_Acc) return Module is
154   begin
155      return Inst.Base.Top_Module;
156   end Get_Top_Module;
157
158   function Get_Sname (Inst : Synth_Instance_Acc) return Sname is
159   begin
160      return Inst.Name;
161   end Get_Sname;
162
163   function Get_Build (Inst : Synth_Instance_Acc)
164                      return Netlists.Builders.Context_Acc is
165   begin
166      return Inst.Base.Builder;
167   end Get_Build;
168
169   function Get_Instance_Const (Inst : Synth_Instance_Acc) return Boolean is
170   begin
171      return Inst.Is_Const;
172   end Get_Instance_Const;
173
174   function Check_Set_Instance_Const (Inst : Synth_Instance_Acc)
175                                     return Boolean is
176   begin
177      for I in 1 .. Inst.Elab_Objects loop
178         if Inst.Objects (I).Kind /= Obj_Subtype then
179            return False;
180         end if;
181      end loop;
182      return True;
183   end Check_Set_Instance_Const;
184
185   procedure Set_Instance_Const (Inst : Synth_Instance_Acc; Val : Boolean) is
186   begin
187      pragma Assert (not Val or else Check_Set_Instance_Const (Inst));
188      Inst.Is_Const := Val;
189   end Set_Instance_Const;
190
191   procedure Create_Object (Syn_Inst : Synth_Instance_Acc;
192                            Slot : Object_Slot_Type;
193                            Num : Object_Slot_Type := 1) is
194   begin
195      --  Check elaboration order.
196      --  Note: this is not done for package since objects from package are
197      --  commons (same scope), and package annotation order can be different
198      --  from package elaboration order (eg: body).
199      if Slot /= Syn_Inst.Elab_Objects + 1
200        or else Syn_Inst.Objects (Slot).Kind /= Obj_None
201      then
202         Error_Msg_Elab ("synth: bad elaboration order of objects");
203         raise Internal_Error;
204      end if;
205      Syn_Inst.Elab_Objects := Slot + Num - 1;
206   end Create_Object;
207
208   procedure Create_Object_Force
209     (Syn_Inst : Synth_Instance_Acc; Decl : Node; Vt : Valtyp)
210   is
211      Info : constant Sim_Info_Acc := Get_Info (Decl);
212   begin
213      pragma Assert
214        (Syn_Inst.Objects (Info.Slot).Kind = Obj_None
215           or else Vt = (null, null)
216           or else Syn_Inst.Objects (Info.Slot) = (Kind => Obj_Object,
217                                                   Obj => No_Valtyp));
218      Syn_Inst.Objects (Info.Slot) := (Kind => Obj_Object, Obj => Vt);
219   end Create_Object_Force;
220
221   procedure Create_Object
222     (Syn_Inst : Synth_Instance_Acc; Decl : Node; Vt : Valtyp)
223   is
224      Info : constant Sim_Info_Acc := Get_Info (Decl);
225   begin
226      Create_Object (Syn_Inst, Info.Slot, 1);
227      Create_Object_Force (Syn_Inst, Decl, Vt);
228   end Create_Object;
229
230   procedure Create_Subtype_Object
231     (Syn_Inst : Synth_Instance_Acc; Decl : Node; Typ : Type_Acc)
232   is
233      pragma Assert (Typ /= null);
234      Info : constant Sim_Info_Acc := Get_Info (Decl);
235   begin
236      Create_Object (Syn_Inst, Info.Slot, 1);
237      pragma Assert (Syn_Inst.Objects (Info.Slot).Kind = Obj_None);
238      Syn_Inst.Objects (Info.Slot) := (Kind => Obj_Subtype, T_Typ => Typ);
239   end Create_Subtype_Object;
240
241   procedure Create_Package_Object (Syn_Inst : Synth_Instance_Acc;
242                                    Decl : Node;
243                                    Inst : Synth_Instance_Acc;
244                                    Is_Global : Boolean)
245   is
246      Info : constant Sim_Info_Acc := Get_Info (Decl);
247   begin
248      if Is_Global then
249         pragma Assert (Syn_Inst.Objects (Info.Pkg_Slot).Kind = Obj_None);
250         pragma Assert (Syn_Inst.Up_Block = null);
251         null;
252      else
253         pragma Assert (Syn_Inst.Up_Block /= null);
254         Create_Object (Syn_Inst, Info.Slot, 1);
255      end if;
256      Syn_Inst.Objects (Info.Pkg_Slot) := (Kind => Obj_Instance,
257                                           I_Inst => Inst);
258   end Create_Package_Object;
259
260   procedure Create_Package_Interface (Syn_Inst : Synth_Instance_Acc;
261                                       Decl     : Node;
262                                       Inst     : Synth_Instance_Acc)
263   is
264      Info : constant Sim_Info_Acc := Get_Info (Decl);
265   begin
266      pragma Assert (Syn_Inst.Up_Block /= null);
267      Create_Object (Syn_Inst, Info.Pkg_Slot, 1);
268      Syn_Inst.Objects (Info.Pkg_Slot) := (Kind => Obj_Instance,
269                                           I_Inst => Inst);
270   end Create_Package_Interface;
271
272   function Get_Package_Object
273     (Syn_Inst : Synth_Instance_Acc; Info : Sim_Info_Acc)
274     return Synth_Instance_Acc
275   is
276      Parent : Synth_Instance_Acc;
277   begin
278      Parent := Get_Instance_By_Scope (Syn_Inst, Info.Pkg_Parent);
279      return Parent.Objects (Info.Pkg_Slot).I_Inst;
280   end Get_Package_Object;
281
282   function Get_Package_Object
283     (Syn_Inst : Synth_Instance_Acc; Pkg : Node) return Synth_Instance_Acc is
284   begin
285      return Get_Package_Object (Syn_Inst, Get_Info (Pkg));
286   end Get_Package_Object;
287
288   procedure Set_Uninstantiated_Scope
289     (Syn_Inst : Synth_Instance_Acc; Bod : Node) is
290   begin
291      Syn_Inst.Uninst_Scope := Get_Info (Bod);
292   end Set_Uninstantiated_Scope;
293
294   procedure Destroy_Object
295     (Syn_Inst : Synth_Instance_Acc; Decl : Node)
296   is
297      Info : constant Sim_Info_Acc := Get_Info (Decl);
298      Slot : constant Object_Slot_Type := Info.Slot;
299   begin
300      if Slot /= Syn_Inst.Elab_Objects
301        or else Info.Obj_Scope /= Syn_Inst.Block_Scope
302      then
303         Error_Msg_Elab ("synth: bad destroy order");
304      end if;
305      Syn_Inst.Objects (Slot) := (Kind => Obj_None);
306      Syn_Inst.Elab_Objects := Slot - 1;
307   end Destroy_Object;
308
309   procedure Create_Wire_Object (Syn_Inst : Synth_Instance_Acc;
310                                 Kind : Wire_Kind;
311                                 Obj : Node)
312   is
313      Obj_Type : constant Node := Get_Type (Obj);
314      Otyp : constant Type_Acc := Get_Subtype_Object (Syn_Inst, Obj_Type);
315      Val : Valtyp;
316      Wid : Wire_Id;
317   begin
318      if Kind = Wire_None then
319         Wid := No_Wire_Id;
320      else
321         Wid := Alloc_Wire (Kind, Otyp, Obj);
322      end if;
323      Val := Create_Value_Wire (Wid, Otyp);
324
325      Create_Object (Syn_Inst, Obj, Val);
326   end Create_Wire_Object;
327
328   function Get_Instance_By_Scope
329     (Syn_Inst: Synth_Instance_Acc; Scope: Sim_Info_Acc)
330     return Synth_Instance_Acc is
331   begin
332      case Scope.Kind is
333         when Kind_Block
334           | Kind_Frame
335           | Kind_Process =>
336            declare
337               Current : Synth_Instance_Acc;
338            begin
339               Current := Syn_Inst;
340               while Current /= null loop
341                  if Current.Block_Scope = Scope then
342                     return Current;
343                  end if;
344                  Current := Current.Up_Block;
345               end loop;
346               raise Internal_Error;
347            end;
348         when Kind_Package =>
349            if Scope.Pkg_Parent = null then
350               --  This is a scope for an uninstantiated package.
351               declare
352                  Current : Synth_Instance_Acc;
353               begin
354                  Current := Syn_Inst;
355                  while Current /= null loop
356                     if Current.Uninst_Scope = Scope then
357                        return Current;
358                     end if;
359                  Current := Current.Up_Block;
360                  end loop;
361                  raise Internal_Error;
362               end;
363            else
364               --  Instantiated package.
365               return Get_Package_Object (Syn_Inst, Scope);
366            end if;
367         when others =>
368            raise Internal_Error;
369      end case;
370   end Get_Instance_By_Scope;
371
372   function Get_Parent_Scope (Blk : Node) return Sim_Info_Acc
373   is
374      Parent : Node;
375   begin
376      Parent := Get_Parent (Blk);
377      if Get_Kind (Parent) = Iir_Kind_Architecture_Body then
378         Parent := Vhdl.Utils.Get_Entity (Parent);
379      end if;
380      return Get_Info (Parent);
381   end Get_Parent_Scope;
382
383   function Get_Value (Syn_Inst: Synth_Instance_Acc; Obj : Node)
384                      return Valtyp
385   is
386      Info : constant Sim_Info_Acc := Get_Info (Obj);
387      Obj_Inst : Synth_Instance_Acc;
388   begin
389      Obj_Inst := Get_Instance_By_Scope (Syn_Inst, Info.Obj_Scope);
390      return Obj_Inst.Objects (Info.Slot).Obj;
391   end Get_Value;
392
393   function Get_Subtype_Object
394     (Syn_Inst : Synth_Instance_Acc; Decl : Node) return Type_Acc
395   is
396      Info : constant Sim_Info_Acc := Get_Info (Decl);
397      Obj_Inst : Synth_Instance_Acc;
398   begin
399      Obj_Inst := Get_Instance_By_Scope (Syn_Inst, Info.Obj_Scope);
400      return Obj_Inst.Objects (Info.Slot).T_Typ;
401   end Get_Subtype_Object;
402
403   --  Set Is_0 to True iff VEC is 000...
404   --  Set Is_X to True iff VEC is XXX...
405   procedure Is_Full (Vec : Logvec_Array;
406                      Is_0 : out Boolean;
407                      Is_X : out Boolean;
408                      Is_Z : out Boolean)
409   is
410      Val : Uns32;
411      Zx : Uns32;
412   begin
413      Val := Vec (0).Val;
414      Zx := Vec (0).Zx;
415      Is_0 := False;
416      Is_X := False;
417      Is_Z := False;
418      if Val = 0 and Zx = 0 then
419         Is_0 := True;
420      elsif Zx = not 0 then
421         if Val = not 0 then
422            Is_X := True;
423         elsif Val = 0 then
424            Is_Z := True;
425         else
426            return;
427         end if;
428      else
429         return;
430      end if;
431
432      for I in 1 .. Vec'Last loop
433         if Vec (I).Val /= Val or else Vec (I).Zx /= Zx then
434            --  Clear flags.
435            Is_0 := False;
436            Is_X := False;
437            Is_Z := False;
438            return;
439         end if;
440      end loop;
441   end Is_Full;
442
443   procedure Value2net (Ctxt : Context_Acc;
444                        Val : Memtyp;
445                        Off : Uns32;
446                        W : Width;
447                        Vec : in out Logvec_Array;
448                        Res : out Net)
449   is
450      Vec_Off : Uns32;
451      Has_Zx : Boolean;
452      Inst : Instance;
453      Is_0, Is_X, Is_Z : Boolean;
454   begin
455      --  First convert to logvec.
456      Has_Zx := False;
457      Vec_Off := 0;
458      Value2logvec (Val, Off, W, Vec, Vec_Off, Has_Zx);
459      pragma Assert (Vec_Off = W);
460
461      --  Then convert logvec to net.
462      if W = 0 then
463         --  For null range (like the null string literal "")
464         Res := Build_Const_UB32 (Ctxt, 0, 0);
465      elsif W <= 32 then
466         --  32 bit result.
467         if not Has_Zx then
468            Res := Build_Const_UB32 (Ctxt, Vec (0).Val, W);
469         elsif Vec (0).Val = 0 and then Sext (Vec (0).Zx, Natural (W)) = not 0
470         then
471            Res := Build_Const_Z (Ctxt, W);
472         else
473            Res := Build_Const_UL32 (Ctxt, Vec (0).Val, Vec (0).Zx, W);
474         end if;
475         return;
476      else
477         Is_Full (Vec, Is_0, Is_X, Is_Z);
478         if Is_0 then
479            Res := Build_Const_UB32 (Ctxt, 0, W);
480         elsif Is_X then
481            Res := Build_Const_X (Ctxt, W);
482         elsif Is_Z then
483            Res := Build_Const_Z (Ctxt, W);
484         elsif not Has_Zx then
485            Inst := Build_Const_Bit (Ctxt, W);
486            for I in Vec'Range loop
487               Set_Param_Uns32 (Inst, Param_Idx (I), Vec (I).Val);
488            end loop;
489            Res := Get_Output (Inst, 0);
490         else
491            Inst := Build_Const_Log (Ctxt, W);
492            for I in Vec'Range loop
493               Set_Param_Uns32 (Inst, Param_Idx (2 * I), Vec (I).Val);
494               Set_Param_Uns32 (Inst, Param_Idx (2 * I + 1), Vec (I).Zx);
495            end loop;
496            Res := Get_Output (Inst, 0);
497         end if;
498      end if;
499   end Value2net;
500
501   function Get_Partial_Memtyp_Net
502     (Ctxt : Context_Acc; Val : Memtyp; Off : Uns32; Wd : Width) return Net
503   is
504      Nd : constant Digit_Index := Digit_Index ((Wd + 31) / 32);
505      Res : Net;
506   begin
507      if Nd > 64 then
508         declare
509            Vecp : Logvec_Array_Acc;
510         begin
511            Vecp := new Logvec_Array'(0 .. Nd - 1 => (0, 0));
512            Value2net (Ctxt, Val, Off, Wd, Vecp.all, Res);
513            Free_Logvec_Array (Vecp);
514            return Res;
515         end;
516      else
517         declare
518            Vec : Logvec_Array (0 .. Nd - 1) := (others => (0, 0));
519         begin
520            Value2net (Ctxt, Val, Off, Wd, Vec, Res);
521            return Res;
522         end;
523      end if;
524   end Get_Partial_Memtyp_Net;
525
526   function Get_Memtyp_Net (Ctxt : Context_Acc; Val : Memtyp) return Net is
527   begin
528      return Get_Partial_Memtyp_Net (Ctxt, Val, 0, Val.Typ.W);
529   end Get_Memtyp_Net;
530
531   function Get_Net (Ctxt : Context_Acc; Val : Valtyp) return Net is
532   begin
533      case Val.Val.Kind is
534         when Value_Wire =>
535            return Get_Current_Value (Ctxt, Val.Val.W);
536         when Value_Net =>
537            return Val.Val.N;
538         when Value_Alias =>
539            declare
540               Res : Net;
541            begin
542               if Val.Val.A_Obj.Kind = Value_Wire then
543                  Res := Get_Current_Value (Ctxt, Val.Val.A_Obj.W);
544                  return Build2_Extract
545                    (Ctxt, Res, Val.Val.A_Off.Net_Off, Val.Typ.W);
546               else
547                  pragma Assert (Val.Val.A_Off.Net_Off = 0);
548                  return Get_Net (Ctxt, (Val.Typ, Val.Val.A_Obj));
549               end if;
550            end;
551         when Value_Const =>
552            if Val.Val.C_Net = No_Net then
553               Val.Val.C_Net := Get_Net (Ctxt, (Val.Typ, Val.Val.C_Val));
554               Locations.Set_Location (Get_Net_Parent (Val.Val.C_Net),
555                                       Get_Location (Val.Val.C_Loc));
556            end if;
557            return Val.Val.C_Net;
558         when Value_Memory =>
559            return Get_Memtyp_Net (Ctxt, Get_Memtyp (Val));
560         when others =>
561            raise Internal_Error;
562      end case;
563   end Get_Net;
564end Synth.Context;
565