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