1--  Environment definition for synthesis.
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 Types; use Types;
22with Tables;
23
24with Netlists; use Netlists;
25with Netlists.Builders;
26
27with Synth.Source;
28with Synth.Objtypes; use Synth.Objtypes;
29
30package Synth.Environment is
31   --  This package declares the type Wire_Id and its methods.
32   --
33   --  A wire_id represents an HDL signal or variable and keeps the current
34   --  value of it accross control statements.
35   --  This is not a memory storage, because:
36   --  * the current value may not be static.
37   --    e.g.:  a <= b + 1;  --  If B is a port, the value of A is defined but
38   --                        --  not known
39   --  * the current value depends on the control statements.
40   --    e.g.:  a := data;  -- a0
41   --           if cond then
42   --              a := a + 4;  --  Reads a0, but writes to a1
43   --              b := a + 1;  --  Reads a1, writes b1
44   --           else
45   --              b <= a + 2;  --  Reads a0, writes b2
46   --           end if;
47   --           c <= b * 2;     --  b = phi(cond, b1, b2)
48   --
49   --  This is very similar to SSA (static single assignments)
50
51   type Wire_Id is private;
52   No_Wire_Id : constant Wire_Id;
53
54   --  Wire_Id can be ordered, so that merges can be efficient.
55   function Is_Lt (L, R : Wire_Id) return Boolean;
56
57   --  A Wire is either a signal, a variable or a port.  We need to know the
58   --  nature of a wire as the assignment semantic is not the same (a variable
59   --  assignment overwrite the old value, while a signal assignment is
60   --  effective at the next cycle).
61   type Wire_Kind is
62     (
63      Wire_None,
64      Wire_Variable,
65      Wire_Enable,
66      Wire_Signal,
67      Wire_Input, Wire_Output, Wire_Inout
68     );
69
70   --  Create a wire.
71   function Alloc_Wire (Kind : Wire_Kind; Typ : Type_Acc; Obj : Source.Syn_Src)
72                       return Wire_Id;
73
74   --  Mark the wire as free.
75   procedure Free_Wire (Wid : Wire_Id);
76
77   --  Read and write the mark flag.
78   function Get_Wire_Mark (Wid : Wire_Id) return Boolean;
79   procedure Set_Wire_Mark (Wid : Wire_Id; Mark : Boolean := True);
80
81   --  Simple mark & release.  This is a very simple mechanism (will free
82   --  all wires allocated after the mark), but efficient and working well
83   --  for the stack based allocation.
84   --  Not related to the mark flag.
85   procedure Mark (M : out Wire_Id);
86   procedure Release (M : in out Wire_Id);
87
88   --  Check that all the wires have been released.
89   procedure All_Released;
90
91   --  Remove wires WID1 and WID2 from current phi.
92   --  Used for internal wires (exit/quit) when exiting their scope.
93   procedure Phi_Discard_Wires (Wid1 : Wire_Id; Wid2 : Wire_Id);
94
95   --  For signals, only the future value can be assigned.  But the current
96   --  value can be read.  A gate is needed to represent the current value
97   --  (as only a gate can provide a net).  In most cases, this is a virtual
98   --  gate whose output is equal to the input and this virtual gate would be
99   --  later removed during cleanup.
100   --
101   --  Set the gate for a wire.
102   procedure Set_Wire_Gate (Wid : Wire_Id; Gate : Net);
103   function Get_Wire_Gate (Wid : Wire_Id) return Net;
104
105   --  The current value of WID.  For variables, this is the last assigned
106   --  value.  For signals, this is the gate.
107   --  A builder is needed in case of concatenation.
108   function Get_Current_Value (Ctxt : Builders.Context_Acc; Wid : Wire_Id)
109                              return Net;
110
111   --  Get the currently assigned value of WID at OFF/WD.
112   --  Used when assigning as a memory.
113   function Get_Current_Assign_Value
114     (Ctxt : Builders.Context_Acc; Wid : Wire_Id; Off : Uns32; Wd : Width)
115     return Net;
116
117   --  In the current phi context, assign VAL to DEST.
118   procedure Phi_Assign_Net
119     (Ctxt : Builders.Context_Acc; Dest : Wire_Id; Val : Net; Offset : Uns32);
120
121   --  Assign a static value to DEST.  VAL is copied.
122   procedure Phi_Assign_Static (Dest : Wire_Id; Val : Memtyp);
123
124   --  A Phi represent a split in the control flow (two or more branches).
125   type Phi_Type is private;
126
127   --  Create a new phi context.
128   procedure Push_Phi;
129
130   procedure Pop_Phi (Phi : out Phi_Type);
131
132   --  Destroy the current phi context and merge it.  Can apply only for the
133   --  first non-top level phi context.
134   procedure Pop_And_Merge_Phi (Ctxt : Builders.Context_Acc;
135                                Stmt : Source.Syn_Src);
136
137   --  All assignments in PHI to wires below MARK are propagated to the
138   --  current phi.  Used to propagate assignments to wires defined out of
139   --  a subprogram when leaving a subprogram.
140   procedure Propagate_Phi_Until_Mark (Ctxt : Builders.Context_Acc;
141                                       Phi : Phi_Type;
142                                       Mark : Wire_Id);
143
144   --  Handle if statement.  According to SEL, the value of the wires are
145   --  those from T or from F.
146   procedure Merge_Phis (Ctxt : Builders.Context_Acc;
147                         Sel : Net;
148                         T, F : Phi_Type;
149                         Stmt : Source.Syn_Src);
150
151   --  Create or get (if already created) a net that is true iff the current
152   --  phi is selected.  Used to enable sequential assertions.
153   --  Because a wire is created, inference will run on it and therefore
154   --  a dff is created if needed.
155   function Phi_Enable (Ctxt : Builders.Context_Acc; Loc : Source.Syn_Src)
156                       return Net;
157
158   --  Lower level part.
159   --  Currently public to handle case statements.
160
161   --  Within a Phi, assignments are represented as a linked list of
162   --  sequential assignments.
163   type Seq_Assign is private;
164   No_Seq_Assign : constant Seq_Assign;
165
166   --  Sort all seq assign of P by wire id.  Used to more easily merge them.
167   function Sort_Phi (P : Phi_Type) return Seq_Assign;
168
169   --  A sequential assignment represent an assignment to a wire.
170   function Get_Wire_Id (W : Seq_Assign) return Wire_Id;
171   function Get_Assign_Chain (Asgn : Seq_Assign) return Seq_Assign;
172   function Get_Assign_Value (Ctxt : Builders.Context_Acc; Asgn : Seq_Assign)
173                             return Net;
174
175   --  For low-level phi merge.
176   --  A sequential assignment is a linked list of partial assignment.
177   type Partial_Assign is private;
178   No_Partial_Assign : constant Partial_Assign;
179
180   type Seq_Assign_Value is private;
181   No_Seq_Assign_Value : constant Seq_Assign_Value;
182
183   function Get_Assign_Partial (Asgn : Seq_Assign) return Partial_Assign;
184   function Get_Seq_Assign_Value (Asgn : Seq_Assign) return Seq_Assign_Value;
185
186   function New_Partial_Assign (Val : Net; Offset : Uns32)
187                               return Partial_Assign;
188
189   type Partial_Assign_Array is array (Int32 range <>) of Partial_Assign;
190
191   type Seq_Assign_Value_Array is array (Int32 range <>) of Seq_Assign_Value;
192
193   --  Return the unique value from array of Seq_Assign_Value if it exists,
194   --  otherwise return Null_Memtyp.
195   --  To be more precise, a value is returned iff:
196   --   1) All present values in Arr are static
197   --   2) There is no missing values *or* the previous value is static.
198   --   3) All the values are equal.
199   --  then assign directly.
200   --  WID is used in case of unknown value.
201   function Is_Assign_Value_Array_Static
202     (Wid : Wire_Id; Arr : Seq_Assign_Value_Array) return Memtyp;
203
204   type Partial_Assign_List is limited private;
205
206   procedure Partial_Assign_Init (List : out Partial_Assign_List);
207   procedure Partial_Assign_Append (List : in out Partial_Assign_List;
208                                    Pasgn : Partial_Assign);
209
210   --  Phi_Assign for each element of LIST.
211   procedure Merge_Partial_Assigns (Ctxt : Builders.Context_Acc;
212                                    Wid : Wire_Id;
213                                    List : in out Partial_Assign_List);
214
215   --  P is an array of Partial_Assign.  Each element is a list
216   --  of partial assign from a different basic block.
217   --  Extract the value to nets N of the maximal partial assignment starting
218   --  at offset OFF for all partial assignments.  Fully handled partial
219   --  assignments are poped.  Set the offset and width to OFF and WD of the
220   --  result.
221   procedure Extract_Merge_Partial_Assigns (Ctxt : Builders.Context_Acc;
222                                            P : in out Seq_Assign_Value_Array;
223                                            N : out Net_Array;
224                                            Off : in out Uns32;
225                                            Wd : out Width);
226
227   --  Concurrent assignments.
228
229   type Conc_Assign is private;
230   No_Conc_Assign : constant Conc_Assign;
231
232   procedure Add_Conc_Assign
233     (Wid : Wire_Id; Val : Net; Off : Uns32; Stmt : Source.Syn_Src);
234
235   procedure Finalize_Assignment
236     (Ctxt : Builders.Context_Acc; Wid : Wire_Id);
237
238   procedure Finalize_Wires;
239
240   --  A static wire is a wire_signal which has one whole (same width as the
241   --  wire) assignment and whose assignment value is a const net.
242   --  That's rather restrictive but still efficient.
243   function Is_Static_Wire (Wid : Wire_Id) return Boolean;
244
245   --  Return the corresponding net for a static wire.
246   function Get_Static_Wire (Wid : Wire_Id) return Memtyp;
247private
248   type Wire_Id is new Uns32;
249   No_Wire_Id : constant Wire_Id := 0;
250
251   function Is_Lt (L, R : Wire_Id) return Boolean renames "<";
252
253   type Seq_Assign is new Uns32;
254   No_Seq_Assign : constant Seq_Assign := 0;
255
256   type Partial_Assign is new Uns32;
257   No_Partial_Assign : constant Partial_Assign := 0;
258
259   type Partial_Assign_List is record
260      First, Last : Partial_Assign;
261   end record;
262
263   type Conc_Assign is new Uns32;
264   No_Conc_Assign : constant Conc_Assign := 0;
265
266   type Phi_Id is new Uns32;
267   No_Phi_Id : constant Phi_Id := 0;
268
269   --  Get current phi context.
270   function Current_Phi return Phi_Id;
271   pragma Inline (Current_Phi);
272
273   type Wire_Id_Record is record
274      --  Kind of wire: signal, variable...
275      --  Set at initialization and cannot be changed.
276      --  Used to know what is the current value of the wire (could be either
277      --  Gate when it is a signal or Cur_Assign when it is a variable).
278      Kind : Wire_Kind;
279
280      --  Used in various algorithms: a flag on a wire.  This flag must be
281      --  cleared after usage.
282      Mark_Flag : Boolean;
283
284      --  Source node that created the wire.
285      Decl : Source.Syn_Src;
286
287      --  Type of the net.  Only for diagnostic purposes.
288      Typ : Type_Acc;
289
290      --  The initial net for the wire.
291      --  This is a pseudo gate that is needed because the value of the wire
292      --  can be read before anything was assigned to it.
293      Gate : Net;
294
295      --  Current assignment (if there is one).
296      --  This is needed so that the current value (for variable) can be read.
297      Cur_Assign : Seq_Assign;
298
299      --  Chain of concurrent assigns for this wire.
300      --  This is used to detect multiple collision and to handle partial
301      --  assignments.
302      Final_Assign : Conc_Assign;
303      Nbr_Final_Assign : Natural;
304   end record;
305
306   type Seq_Assign_Value (Is_Static : Tri_State_Type := True) is record
307      case Is_Static is
308         when Unknown =>
309            --  Used only for no value (in that case, it will use the previous
310            --  value).
311            --  This is used only for temporary handling, and is never stored
312            --  in Seq_Assign.
313            null;
314         when True =>
315            Val : Memtyp;
316         when False =>
317            --  Values assigned.
318            Asgns : Partial_Assign;
319      end case;
320   end record;
321
322   No_Seq_Assign_Value : constant Seq_Assign_Value := (Is_Static => Unknown);
323
324   type Seq_Assign_Record is record
325      --  Target of the assignment.
326      Id : Wire_Id;
327
328      --  Assignment in the previous phi context.
329      --  Used to restore Cur_Assign of the wire when the phi context is poped.
330      Prev : Seq_Assign;
331
332      --  Corresponding phi context for this wire.
333      Phi : Phi_Id;
334
335      --  Next wire in the phi context.
336      Chain : Seq_Assign;
337
338      --  Current value.
339      Val : Seq_Assign_Value;
340   end record;
341
342   type Partial_Assign_Record is record
343      Next : Partial_Assign;
344
345      --  Assignment at OFFSET.  The width is set by the width of the value.
346      Value : Net;
347      Offset : Uns32;
348   end record;
349
350   type Conc_Assign_Record is record
351      Next : Conc_Assign;
352
353      --  Concurrent assignment at OFFSET.  The width is set by value width.
354      Value : Net;
355      Offset : Uns32;
356
357      --  Source of the assignment.  Useful to report errors.
358      Stmt : Source.Syn_Src;
359   end record;
360
361   type Phi_Type is record
362      --  Chain of sequential assignments in the current phi context (BB).
363      First : Seq_Assign;
364      Last : Seq_Assign;
365      --  Number of assignments.
366      Nbr : Uns32;
367      --  Enable wire created for this phi.
368      En : Wire_Id;
369   end record;
370
371   package Phis_Table is new Tables
372     (Table_Component_Type => Phi_Type,
373      Table_Index_Type => Phi_Id,
374      Table_Low_Bound => No_Phi_Id,
375      Table_Initial => 16);
376
377   package Wire_Id_Table is new Tables
378     (Table_Component_Type => Wire_Id_Record,
379      Table_Index_Type => Wire_Id,
380      Table_Low_Bound => No_Wire_Id,
381      Table_Initial => 1024);
382
383   package Assign_Table is new Tables
384     (Table_Component_Type => Seq_Assign_Record,
385      Table_Index_Type => Seq_Assign,
386      Table_Low_Bound => No_Seq_Assign,
387      Table_Initial => 1024);
388
389   package Partial_Assign_Table is new Tables
390     (Table_Component_Type => Partial_Assign_Record,
391      Table_Index_Type => Partial_Assign,
392      Table_Low_Bound => No_Partial_Assign,
393      Table_Initial => 1024);
394
395   package Conc_Assign_Table is new Tables
396     (Table_Component_Type => Conc_Assign_Record,
397      Table_Index_Type => Conc_Assign,
398      Table_Low_Bound => No_Conc_Assign,
399      Table_Initial => 1024);
400end Synth.Environment;
401