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