1-- GHDL driver for synthesis 2-- Copyright (C) 2016 Tristan Gingold 3-- 4-- This program is free software: you can redistribute it and/or modify 5-- it under the terms of the GNU General Public License as published by 6-- the Free Software Foundation, either version 2 of the License, or 7-- (at your option) any later version. 8-- 9-- This program is distributed in the hope that it will be useful, 10-- but WITHOUT ANY WARRANTY; without even the implied warranty of 11-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12-- GNU General Public License for more details. 13-- 14-- You should have received a copy of the GNU General Public License 15-- along with this program. If not, see <gnu.org/licenses>. 16 17with GNAT.OS_Lib; use GNAT.OS_Lib; 18 19with Types; use Types; 20with Name_Table; 21with Files_Map; 22with Ghdllocal; use Ghdllocal; 23with Ghdlcomp; use Ghdlcomp; 24with Ghdlmain; use Ghdlmain; 25with Options; use Options; 26with Errorout; 27with Errorout.Console; 28with Version; 29with Default_Paths; 30with Bug; 31with Simple_IO; 32 33with Libraries; 34with Flags; 35with Vhdl.Nodes; use Vhdl.Nodes; 36with Vhdl.Errors; 37with Vhdl.Scanner; 38with Vhdl.Std_Package; 39with Vhdl.Canon; 40with Vhdl.Configuration; 41with Vhdl.Annotations; 42with Vhdl.Utils; 43 44with Netlists.Dump; 45with Netlists.Disp_Vhdl; 46with Netlists.Disp_Dot; 47with Netlists.Errors; 48 49with Synthesis; 50with Synth.Disp_Vhdl; 51with Synth.Context; use Synth.Context; 52with Synth.Flags; use Synth.Flags; 53 54package body Ghdlsynth is 55 type Out_Format is 56 (Format_Default, 57 Format_Raw, Format_Dump, Format_Dot, 58 Format_Vhdl, 59 Format_None); 60 61 type Name_Id_Array is array (Natural range <>) of Name_Id; 62 63 -- Command --synth 64 type Command_Synth is new Command_Lib with record 65 -- Control format of the output. 66 Disp_Inline : Boolean := True; 67 Disp_Id : Boolean := True; 68 Oformat : Out_Format := Format_Default; 69 70 Flag_Stats : Boolean := False; 71 72 -- Control name encoding of the top-entity. 73 Top_Encoding : Name_Encoding := Name_Asis; 74 75 -- If True, a failure is expected. For tests. 76 Expect_Failure : Boolean := False; 77 78 Nbr_Vendor_Libraries : Natural := 0; 79 Vendor_Libraries : Name_Id_Array (1 .. 8) := (others => No_Name_Id); 80 end record; 81 function Decode_Command (Cmd : Command_Synth; Name : String) 82 return Boolean; 83 function Get_Short_Help (Cmd : Command_Synth) return String; 84 procedure Disp_Long_Help (Cmd : Command_Synth); 85 procedure Decode_Option (Cmd : in out Command_Synth; 86 Option : String; 87 Arg : String; 88 Res : out Option_State); 89 procedure Perform_Action (Cmd : in out Command_Synth; 90 Args : Argument_List); 91 92 function Decode_Command (Cmd : Command_Synth; Name : String) 93 return Boolean 94 is 95 pragma Unreferenced (Cmd); 96 begin 97 return Name = "synth" 98 or else Name = "--synth"; 99 end Decode_Command; 100 101 function Get_Short_Help (Cmd : Command_Synth) return String 102 is 103 pragma Unreferenced (Cmd); 104 begin 105 return "synth [FILES... -e] UNIT [ARCH]" 106 & ASCII.LF & " Synthesis from UNIT" 107 & ASCII.LF & " alias: --synth"; 108 end Get_Short_Help; 109 110 procedure Disp_Long_Help (Cmd : Command_Synth) 111 is 112 pragma Unreferenced (Cmd); 113 procedure P (Str : String) renames Simple_IO.Put_Line; 114 begin 115 P ("You can directly pass the list of files to synthesize:"); 116 P (" --synth [OPTIONS] { [--work=NAME] FILE } -e [UNIT]"); 117 P (" If UNIT is not present, the top unit is automatically found"); 118 P (" You can use --work=NAME to change the library between files"); 119 P ("Or use already analysed files:"); 120 P (" --synth [OPTIONS] -e UNIT"); 121 P ("In addition to analyze options, you can use:"); 122 P (" -gNAME=VALUE"); 123 P (" Override the generic NAME of the top unit"); 124 P (" --vendor-library=NAME"); 125 P (" Any unit from library NAME is a black boxe"); 126 P (" --no-formal"); 127 P (" Neither synthesize assert nor PSL"); 128 P (" --no-assert-cover"); 129 P (" Cover PSL assertion activation"); 130 P (" --assert-assumes"); 131 P (" Treat all PSL asserts like PSL assumes"); 132 P (" --assume-asserts"); 133 P (" Treat all PSL assumes like PSL asserts"); 134 end Disp_Long_Help; 135 136 procedure Decode_Option (Cmd : in out Command_Synth; 137 Option : String; 138 Arg : String; 139 Res : out Option_State) 140 is 141 pragma Assert (Option'First = 1); 142 begin 143 Res := Option_Ok; 144 145 if Option'Last > 3 146 and then Option (2) = 'g' 147 and then Is_Generic_Override_Option (Option) 148 then 149 Res := Decode_Generic_Override_Option (Option); 150 elsif Option = "--no-formal" then 151 Synth.Flags.Flag_Formal := False; 152 elsif Option = "--formal" then 153 Synth.Flags.Flag_Formal := True; 154 elsif Option = "--no-assert-cover" then 155 Synth.Flags.Flag_Assert_Cover := False; 156 elsif Option = "--assert-cover" then 157 Synth.Flags.Flag_Assert_Cover := True; 158 elsif Option = "--assert-assumes" then 159 Synth.Flags.Flag_Assert_As_Assume := True; 160 elsif Option = "--assume-asserts" then 161 Synth.Flags.Flag_Assume_As_Assert := True; 162 elsif Option = "--top-name=hash" then 163 Cmd.Top_Encoding := Name_Hash; 164 elsif Option = "--top-name=asis" then 165 Cmd.Top_Encoding := Name_Asis; 166 elsif Option'Last > 17 167 and then Option (1 .. 17) = "--vendor-library=" 168 then 169 if Cmd.Nbr_Vendor_Libraries >= Cmd.Vendor_Libraries'Last then 170 -- FIXME: use a table/vector ? 171 Errorout.Error_Msg_Option ("too many vendor libraries"); 172 Res := Option_Err; 173 else 174 declare 175 Name : String := Option (18 .. Option'Last); 176 Err : Boolean; 177 begin 178 Vhdl.Scanner.Convert_Identifier (Name, Err); 179 if Err then 180 Res := Option_Err; 181 else 182 Cmd.Nbr_Vendor_Libraries := Cmd.Nbr_Vendor_Libraries + 1; 183 Cmd.Vendor_Libraries (Cmd.Nbr_Vendor_Libraries) := 184 Name_Table.Get_Identifier (Name); 185 end if; 186 end; 187 end if; 188 elsif Option = "--expect-failure" then 189 Cmd.Expect_Failure := True; 190 elsif Option = "--disp-noinline" then 191 Cmd.Disp_Inline := False; 192 elsif Option = "--disp-noid" then 193 Cmd.Disp_Id := False; 194 elsif Option = "--out=raw" then 195 Cmd.Oformat := Format_Raw; 196 elsif Option = "--out=dump" then 197 Cmd.Oformat := Format_Dump; 198 elsif Option = "--out=dot" then 199 Cmd.Oformat := Format_Dot; 200 elsif Option = "--out=none" then 201 Cmd.Oformat := Format_None; 202 elsif Option = "--out=vhdl" then 203 Cmd.Oformat := Format_Vhdl; 204 elsif Option = "-di" then 205 Flag_Debug_Noinference := True; 206 elsif Option = "-dc" then 207 Flag_Debug_Nocleanup := True; 208 elsif Option = "-dm" then 209 Flag_Debug_Nomemory1 := True; 210 Flag_Debug_Nomemory2 := True; 211 elsif Option = "-dm2" then 212 -- Reduce muxes, but do not create memories. 213 Flag_Debug_Nomemory2 := True; 214 elsif Option = "-de" then 215 Flag_Debug_Noexpand := True; 216 elsif Option = "-t" then 217 Flag_Trace_Statements := True; 218 elsif Option = "-i" then 219 Flag_Debug_Init := True; 220 elsif Option = "-g" then 221 Flag_Debug_Enable := True; 222 elsif Option = "-v" then 223 if not Synth.Flags.Flag_Verbose then 224 Synth.Flags.Flag_Verbose := True; 225 else 226 Flags.Verbose := True; 227 end if; 228 elsif Option = "--stats" then 229 Cmd.Flag_Stats := True; 230 else 231 Decode_Option (Command_Lib (Cmd), Option, Arg, Res); 232 end if; 233 end Decode_Option; 234 235 -- Init, analyze and configure. 236 -- Return the top configuration. 237 function Ghdl_Synth_Configure 238 (Init : Boolean; Cmd : Command_Synth; Args : Argument_List) return Node 239 is 240 use Vhdl.Errors; 241 use Vhdl.Configuration; 242 use Errorout; 243 E_Opt : Integer; 244 Opt_Arg : Natural; 245 Design_File : Iir; 246 Config : Iir; 247 Top : Iir; 248 Prim_Id : Name_Id; 249 Sec_Id : Name_Id; 250 begin 251 -- If the '-e' switch is present, there is a list of files. 252 E_Opt := Args'First - 1; 253 for I in Args'Range loop 254 if Args (I).all = "-e" then 255 E_Opt := I; 256 exit; 257 end if; 258 end loop; 259 260 if Init then 261 Vhdl.Annotations.Flag_Synthesis := True; 262 Vhdl.Scanner.Flag_Comment_Keyword := True; 263 Vhdl.Scanner.Flag_Pragma_Comment := True; 264 265 Common_Compile_Init (False); 266 -- Will elaborate. 267 Flags.Flag_Elaborate := True; 268 269 -- Load content only if there are no files. 270 Libraries.Load_Work_Library (E_Opt >= Args'First); 271 272 -- Do not canon concurrent statements. 273 Vhdl.Canon.Canon_Flag_Concurrent_Stmts := False; 274 275 -- Do not create concurrent signal assignment for inertial 276 -- association. They are handled directly. 277 Vhdl.Canon.Canon_Flag_Inertial_Associations := False; 278 end if; 279 280 -- Mark vendor libraries. 281 for I in 1 .. Cmd.Nbr_Vendor_Libraries loop 282 declare 283 Lib : Node; 284 begin 285 Lib := Libraries.Get_Library 286 (Cmd.Vendor_Libraries (I), No_Location); 287 Set_Vendor_Library_Flag (Lib, True); 288 end; 289 end loop; 290 291 Flags.Flag_Elaborate_With_Outdated := E_Opt >= Args'First; 292 293 -- Analyze files (if any) 294 for I in Args'First .. E_Opt - 1 loop 295 declare 296 Arg : String renames Args (I).all; 297 pragma Assert (Arg'First = 1); 298 Id : Name_Id; 299 begin 300 if Arg'Last > 7 and then Arg (1 .. 7) = "--work=" then 301 Id := Libraries.Decode_Work_Option (Arg); 302 if Id = Null_Identifier then 303 return Null_Iir; 304 end if; 305 Libraries.Work_Library_Name := Id; 306 Libraries.Load_Work_Library (True); 307 else 308 if Files_Map.Find_Language (Arg) /= Language_Vhdl then 309 Errorout.Report_Msg 310 (Warnid_Library, Option, No_Source_Coord, 311 "unexpected extension for vhdl file %i", 312 (1 => +Name_Table.Get_Identifier (Arg))); 313 end if; 314 315 Ghdlcomp.Compile_Load_File (Arg); 316 end if; 317 end; 318 end loop; 319 pragma Unreferenced (Design_File); 320 321 if Nbr_Errors > 0 then 322 -- No need to configure if there are missing units. 323 return Null_Iir; 324 end if; 325 326 -- Elaborate 327 if E_Opt = Args'Last then 328 -- No unit. 329 Top := Vhdl.Configuration.Find_Top_Entity 330 (Libraries.Work_Library, Libraries.Command_Line_Location); 331 if Top = Null_Node then 332 Ghdlmain.Error ("no top unit found"); 333 return Null_Iir; 334 end if; 335 Errorout.Report_Msg (Msgid_Note, Option, No_Source_Coord, 336 "top entity is %i", (1 => +Top)); 337 if Nbr_Errors > 0 then 338 -- No need to configure if there are missing units. 339 return Null_Iir; 340 end if; 341 Prim_Id := Get_Identifier (Top); 342 Sec_Id := Null_Identifier; 343 else 344 Extract_Elab_Unit ("--synth", Args (E_Opt + 1 .. Args'Last), Opt_Arg, 345 Prim_Id, Sec_Id); 346 if Opt_Arg <= Args'Last then 347 Ghdlmain.Error ("extra options ignored"); 348 return Null_Iir; 349 end if; 350 end if; 351 352 Config := Vhdl.Configuration.Configure (Prim_Id, Sec_Id); 353 354 if Nbr_Errors > 0 then 355 -- No need to configure if there are missing units. 356 return Null_Iir; 357 end if; 358 359 Vhdl.Configuration.Add_Verification_Units; 360 361 -- Check (and possibly abandon) if entity can be at the top of the 362 -- hierarchy. 363 declare 364 Entity : constant Iir := 365 Vhdl.Utils.Get_Entity_From_Configuration (Config); 366 begin 367 Vhdl.Configuration.Apply_Generic_Override (Entity); 368 Vhdl.Configuration.Check_Entity_Declaration_Top (Entity, False); 369 if Nbr_Errors > 0 then 370 return Null_Iir; 371 end if; 372 end; 373 374 -- Annotate all units. 375 Vhdl.Annotations.Initialize_Annotate; 376 Vhdl.Annotations.Annotate (Vhdl.Std_Package.Std_Standard_Unit); 377 for I in Design_Units.First .. Design_Units.Last loop 378 Vhdl.Annotations.Annotate (Design_Units.Table (I)); 379 end loop; 380 381 return Config; 382 end Ghdl_Synth_Configure; 383 384 procedure Disp_Design (Cmd : Command_Synth; 385 Default : Out_Format; 386 Res : Module; 387 Config : Iir; 388 Inst : Synth_Instance_Acc) 389 is 390 Format : Out_Format; 391 Ent : Iir; 392 begin 393 Format := Cmd.Oformat; 394 if Format = Format_Default then 395 Format := Default; 396 end if; 397 398 case Format is 399 when Format_Default => 400 raise Internal_Error; 401 when Format_None => 402 null; 403 when Format_Raw => 404 Netlists.Dump.Flag_Disp_Inline := Cmd.Disp_Inline; 405 Netlists.Dump.Flag_Disp_Id := Cmd.Disp_Id; 406 Netlists.Dump.Disp_Module (Res); 407 when Format_Dump => 408 Netlists.Dump.Flag_Disp_Inline := Cmd.Disp_Inline; 409 Netlists.Dump.Dump_Module (Res); 410 when Format_Dot => 411 Netlists.Disp_Dot.Disp_Dot_Top_Module (Res); 412 when Format_Vhdl => 413 if Boolean'(True) then 414 Ent := Vhdl.Utils.Get_Entity_From_Configuration (Config); 415 Synth.Disp_Vhdl.Disp_Vhdl_Wrapper (Ent, Res, Inst); 416 else 417 Netlists.Disp_Vhdl.Disp_Vhdl (Res); 418 end if; 419 end case; 420 end Disp_Design; 421 422 function Ghdl_Synth 423 (Init : Natural; Argc : Natural; Argv : C_String_Array_Acc) 424 return Module 425 is 426 use Vhdl.Configuration; 427 Args : Argument_List (1 .. Argc); 428 Res : Module; 429 Cmd : Command_Synth; 430 First_Arg : Natural; 431 Config : Node; 432 Inst : Synth_Instance_Acc; 433 begin 434 -- Create arguments list. 435 for I in 0 .. Argc - 1 loop 436 declare 437 Arg : constant Ghdl_C_String := Argv (I); 438 begin 439 Args (I + 1) := new String'(Arg (1 .. strlen (Arg))); 440 end; 441 end loop; 442 443 -- Forget any previous errors. 444 Errorout.Nbr_Errors := 0; 445 446 -- Find the command. This is a little bit convoluted... 447 Decode_Command_Options (Cmd, Args, First_Arg); 448 449 -- Do the real work! 450 Config := Ghdl_Synth_Configure 451 (Init /= 0, Cmd, Args (First_Arg .. Args'Last)); 452 if Config = Null_Iir then 453 return No_Module; 454 end if; 455 456 Synthesis.Synth_Design (Config, Cmd.Top_Encoding, Res, Inst); 457 if Res = No_Module then 458 return No_Module; 459 end if; 460 461 Disp_Design (Cmd, Format_None, Res, Config, Inst); 462 463 -- De-elaborate all packages, so that they could be re-used for 464 -- synthesis of a second design. 465 -- FIXME: move to vhdl.configure ? 466 for I in Design_Units.First .. Design_Units.Last loop 467 Set_Elab_Flag (Design_Units.Table (I), False); 468 end loop; 469 Set_Elab_Flag (Vhdl.Std_Package.Std_Standard_Unit, False); 470 471 Vhdl.Annotations.Finalize_Annotate; 472 Synth.Context.Free_Base_Instance; 473 return Res; 474 475 exception 476 when Option_Error 477 | Errorout.Compilation_Error => 478 return No_Module; 479 when E: others => 480 -- Avoid possible issues with exceptions... 481 Bug.Disp_Bug_Box (E); 482 return No_Module; 483 end Ghdl_Synth; 484 485 procedure Perform_Action (Cmd : in out Command_Synth; 486 Args : Argument_List) 487 is 488 Res : Module; 489 Inst : Synth_Instance_Acc; 490 Config : Iir; 491 begin 492 Config := Ghdl_Synth_Configure (True, Cmd, Args); 493 494 if Config = Null_Iir then 495 if Cmd.Expect_Failure then 496 return; 497 else 498 raise Errorout.Compilation_Error; 499 end if; 500 end if; 501 502 Netlists.Errors.Initialize; 503 504 Synthesis.Synth_Design (Config, Cmd.Top_Encoding, Res, Inst); 505 if Res = No_Module then 506 if Cmd.Expect_Failure then 507 return; 508 else 509 raise Errorout.Compilation_Error; 510 end if; 511 elsif Cmd.Expect_Failure then 512 raise Errorout.Compilation_Error; 513 end if; 514 515 Disp_Design (Cmd, Format_Vhdl, Res, Config, Inst); 516 517 if Cmd.Flag_Stats then 518 Netlists.Disp_Stats; 519 end if; 520 end Perform_Action; 521 522 function Get_Libghdl_Name return String 523 is 524 Libghdl_Version : String := Version.Ghdl_Ver; 525 begin 526 for I in Libghdl_Version'Range loop 527 if Libghdl_Version (I) = '.' or Libghdl_Version (I) = '-' then 528 Libghdl_Version (I) := '_'; 529 end if; 530 end loop; 531 return "libghdl-" & Libghdl_Version 532 & Default_Paths.Shared_Library_Extension; 533 end Get_Libghdl_Name; 534 535 function Get_Libghdl_Path return String is 536 begin 537 if Ghdllocal.Exec_Prefix = null then 538 -- Compute install path (only once). 539 Ghdllocal.Set_Exec_Prefix_From_Program_Name; 540 end if; 541 542 return Ghdllocal.Exec_Prefix.all & Directory_Separator & "lib" 543 & Directory_Separator & Get_Libghdl_Name; 544 end Get_Libghdl_Path; 545 546 function Get_Libghdl_Include_Dir return String is 547 begin 548 -- Compute install path 549 Ghdllocal.Set_Exec_Prefix_From_Program_Name; 550 551 return Ghdllocal.Exec_Prefix.all & Directory_Separator & "include"; 552 end Get_Libghdl_Include_Dir; 553 554 procedure Register_Commands is 555 begin 556 Ghdlmain.Register_Command (new Command_Synth); 557 Register_Command 558 (new Command_Str_Disp' 559 (Command_Type with 560 Cmd_Str => new String' 561 ("--libghdl-name"), 562 Help_Str => new String' 563 ("--libghdl-name" 564 & ASCII.LF & " Display libghdl name"), 565 Disp => Get_Libghdl_Name'Access)); 566 Register_Command 567 (new Command_Str_Disp' 568 (Command_Type with 569 Cmd_Str => new String' 570 ("--libghdl-library-path"), 571 Help_Str => new String' 572 ("--libghdl-library-path" 573 & ASCII.LF & " Display libghdl library path"), 574 Disp => Get_Libghdl_Path'Access)); 575 Register_Command 576 (new Command_Str_Disp' 577 (Command_Type with 578 Cmd_Str => new String' 579 ("--libghdl-include-dir"), 580 Help_Str => new String' 581 ("--libghdl-include-dir" 582 & ASCII.LF & " Display libghdl include directory"), 583 Disp => Get_Libghdl_Include_Dir'Access)); 584 end Register_Commands; 585 586 procedure Init_For_Ghdl_Synth is 587 begin 588 Ghdlsynth.Register_Commands; 589 Errorout.Console.Install_Handler; 590 Options.Initialize; 591 Netlists.Errors.Initialize; 592 end Init_For_Ghdl_Synth; 593end Ghdlsynth; 594