diff --git a/BUGS.txt b/BUGS.txt index 14e39b774..3d201b240 100644 --- a/BUGS.txt +++ b/BUGS.txt @@ -116,13 +116,17 @@ programs. RESEARCHING EXISTING/PAST BUGS, AND FILING REPORTS -The URL is the main -bug tracking system. Once you believe you have found a bug, you may -browse the bugs database for existing bugs that may be related to -yours. You might find that your bug has already been fixed in a later -release or snapshot. If that's the case, then you are set. Also, -consider if you are reporting a bug or really asking for a new -feature, and use the appropriate tracker. +The URL is the main +bug tracking system, although some users have reported bugs at +. Once you believe +you have found a bug, you may browse the bugs database for existing +bugs that may be related to yours. You might find that your bug has +already been fixed in a later release or snapshot. If that's the case, +then you are set. Also, consider if you are reporting a bug or really +asking for a new feature, and use the appropriate tracker. + + system (although you will also find bug rep + The bug database supports basic keyword searches, and you can optionally limit your search to active bugs, or fixed bugs. You may @@ -145,7 +149,7 @@ version from git. Please see the developer documentation for more detailed instructions -- . When you make a patch, submit it to the "Patches" tracker at -. Patches added to +. Patches added to the "Patches" tracker enter the developer workflow, are checked, applied to the appropriate git branch, and are pushed. Then the tracker item is closed. @@ -158,7 +162,7 @@ clarification before applying it.) COPYRIGHT ISSUES -Icarus Verilog is Copyright (c) 1998-2008 Stephen Williams except +Icarus Verilog is Copyright (c) 1998-2018 Stephen Williams except where otherwise noted. Minor patches are covered as derivative works (or editorial comment or whatever the appropriate legal term is) and folded into the rest of ivl. However, if a submission can reasonably diff --git a/Module.cc b/Module.cc index 7c2d14dfb..c5980637e 100644 --- a/Module.cc +++ b/Module.cc @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998-2016 Stephen Williams (steve@icarus.com) + * Copyright (c) 1998-2017 Stephen Williams (steve@icarus.com) * * This source code is free software; you can redistribute it * and/or modify it in source code form under the terms of the GNU @@ -35,7 +35,6 @@ Module::Module(LexicalScope*parent, perm_string n) is_interface = false; program_block = false; uc_drive = UCD_NONE; - timescale_warn_done = false; } Module::~Module() diff --git a/Module.h b/Module.h index 66c60af4f..411c99f9f 100644 --- a/Module.h +++ b/Module.h @@ -1,7 +1,7 @@ #ifndef IVL_Module_H #define IVL_Module_H /* - * Copyright (c) 1998-2016 Stephen Williams (steve@icarus.com) + * Copyright (c) 1998-2017 Stephen Williams (steve@icarus.com) * * This source code is free software; you can redistribute it * and/or modify it in source code form under the terms of the GNU @@ -121,8 +121,6 @@ class Module : public PScopeExtra, public LineInfo { map attributes; - bool timescale_warn_done; - /* The module has a list of generate schemes that appear in the module definition. These are used at elaboration time. */ list generate_schemes; diff --git a/PDelays.cc b/PDelays.cc index 5fd72a37b..3759d39fe 100644 --- a/PDelays.cc +++ b/PDelays.cc @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999-2011 Stephen Williams (steve@icarus.com) + * Copyright (c) 1999-2017 Stephen Williams (steve@icarus.com) * * This source code is free software; you can redistribute it * and/or modify it in source code form under the terms of the GNU @@ -26,11 +26,6 @@ # include "verinum.h" # include "netmisc.h" -bool dly_used_no_timescale = false; -bool dly_used_timescale = false; -bool display_ts_dly_warning = true; - - PDelays::PDelays() { delete_flag_ = true; @@ -80,19 +75,7 @@ static NetExpr*calculate_val(Design*des, NetScope*scope, PExpr*expr) { NetExpr*dex = elab_and_eval(des, scope, expr, -1); - /* Print a warning if we find default and `timescale based - * delays in the design, since this is likely an error. */ - if (scope->time_from_timescale()) dly_used_timescale = true; - else dly_used_no_timescale = true; - - if (display_ts_dly_warning && - dly_used_no_timescale && dly_used_timescale) { - cerr << "warning: Found both default and " - "`timescale based delays. Use" << endl; - cerr << " -Wtimescale to find the " - "module(s) with no `timescale." << endl; - display_ts_dly_warning = false; - } + check_for_inconsistent_delays(scope); /* If the delay expression is a real constant or vector constant, then evaluate it, scale it to the local time diff --git a/PGate.h b/PGate.h index 5d9bde9f2..ee6f10f79 100644 --- a/PGate.h +++ b/PGate.h @@ -217,6 +217,8 @@ class PGModule : public PGate { // method to pass the range to the pform. void set_range(PExpr*msb, PExpr*lsb); + map attributes; + virtual void dump(ostream&out, unsigned ind =4) const; virtual void elaborate(Design*, NetScope*scope) const; virtual void elaborate_scope(Design*des, NetScope*sc) const; diff --git a/PScope.cc b/PScope.cc index 0b6a132d3..c0738cc29 100644 --- a/PScope.cc +++ b/PScope.cc @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008,2016 Stephen Williams (steve@icarus.com) + * Copyright (c) 2008-2017 Stephen Williams (steve@icarus.com) * * This source code is free software; you can redistribute it * and/or modify it in source code form under the terms of the GNU @@ -38,7 +38,8 @@ PScope::PScope(perm_string n, LexicalScope*parent) { time_unit = 0; time_precision = 0; - time_from_timescale = false; + time_unit_is_default = true; + time_prec_is_default = true; } PScope::~PScope() @@ -51,6 +52,8 @@ PScope::~PScope() PScopeExtra::PScopeExtra(perm_string n, LexicalScope*parent) : PScope(n, parent) { + time_unit_is_local = false; + time_prec_is_local = false; } PScopeExtra::~PScopeExtra() diff --git a/PScope.h b/PScope.h index 7e4fd6fa3..24674d6df 100644 --- a/PScope.h +++ b/PScope.h @@ -1,7 +1,7 @@ #ifndef IVL_PScope_H #define IVL_PScope_H /* - * Copyright (c) 2008-2016 Stephen Williams (steve@icarus.com) + * Copyright (c) 2008-2017 Stephen Williams (steve@icarus.com) * * This source code is free software; you can redistribute it * and/or modify it in source code form under the terms of the GNU @@ -164,11 +164,18 @@ class PScope : public LexicalScope { perm_string pscope_name() const { return name_; } - /* These are the timescale for this scope. The default is + /* These are the timescale for this scope. The value is set by the `timescale directive or, in SystemVerilog, by timeunit and timeprecision statements. */ int time_unit, time_precision; - bool time_from_timescale; + + /* Flags used to support warnings about timescales. */ + bool time_unit_is_default; + bool time_prec_is_default; + + bool has_explicit_timescale() const { + return !(time_unit_is_default || time_prec_is_default); + } protected: bool elaborate_sig_wires_(Design*des, NetScope*scope) const; @@ -199,6 +206,10 @@ class PScopeExtra : public PScope { elaboration to choose an elaboration order. */ std::vector classes_lexical; + /* Flags used to support warnings about timescales. */ + bool time_unit_is_local; + bool time_prec_is_local; + protected: void dump_classes_(ostream&out, unsigned indent) const; void dump_tasks_(ostream&out, unsigned indent) const; diff --git a/README.txt b/README.txt index ffb6ed38d..d44a106e5 100644 --- a/README.txt +++ b/README.txt @@ -1,5 +1,5 @@ THE ICARUS VERILOG COMPILATION SYSTEM - Copyright 2000-2004 Stephen Williams + Copyright 2000-2019 Stephen Williams 1.0 What is ICARUS Verilog? @@ -47,7 +47,7 @@ on a UNIX-like system: - bison and flex - - gperf 2.7 + - gperf 2.7 or later The lexical analyzer doesn't recognize keywords directly, but instead matches symbols and looks them up in a hash table in order to get the proper lexical code. The gperf @@ -56,7 +56,7 @@ on a UNIX-like system: A version problem with this program is the most common cause of difficulty. See the Icarus Verilog FAQ. - - readline 4.2 + - readline 4.2 or later On Linux systems, this usually means the readline-devel rpm. In any case, it is the development headers of readline that are needed. @@ -67,7 +67,7 @@ on a UNIX-like system: If you are building from git, you will also need software to generate the configure scripts. - - autoconf 2.53 + - autoconf 2.53 or later This generates configure scripts from configure.in. The 2.53 or later versions are known to work, autoconf 2.13 is reported to *not* work. @@ -81,6 +81,12 @@ with the commands: ./configure make +If you are building from git, you have to run the command below before +compile the source. This will generate the "configure" file, which is +automatically done when building from tarball. + + sh autoconf.sh + Normally, this command automatically figures out everything it needs to know. It generally works pretty well. There are a few flags to the configure script that modify its behavior: diff --git a/Statement.cc b/Statement.cc index 942558107..92a87a12d 100644 --- a/Statement.cc +++ b/Statement.cc @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998-2013 Stephen Williams (steve@icarus.com) + * Copyright (c) 1998-2017 Stephen Williams (steve@icarus.com) * * This source code is free software; you can redistribute it * and/or modify it in source code form under the terms of the GNU @@ -294,20 +294,20 @@ PDoWhile::~PDoWhile() } PEventStatement::PEventStatement(const svector&ee) -: expr_(ee), statement_(0) +: expr_(ee), statement_(0), search_funcs_(false) { assert(expr_.count() > 0); } PEventStatement::PEventStatement(PEEvent*ee) -: expr_(1), statement_(0) +: expr_(1), statement_(0), search_funcs_(false) { expr_[0] = ee; } -PEventStatement::PEventStatement(void) -: statement_(0) +PEventStatement::PEventStatement(bool search_funcs) +: statement_(0), search_funcs_(search_funcs) { } diff --git a/Statement.h b/Statement.h index a6835b03e..30f3b8229 100644 --- a/Statement.h +++ b/Statement.h @@ -1,7 +1,7 @@ #ifndef IVL_Statement_H #define IVL_Statement_H /* - * Copyright (c) 1998-2014 Stephen Williams (steve@icarus.com) + * Copyright (c) 1998-2017 Stephen Williams (steve@icarus.com) * * This source code is free software; you can redistribute it * and/or modify it in source code form under the terms of the GNU @@ -402,8 +402,9 @@ class PEventStatement : public Statement { explicit PEventStatement(const svector&ee); explicit PEventStatement(PEEvent*ee); - // Make an @* statement. - explicit PEventStatement(void); + // Make an @* statement or make a special @* version with the items + // from functions added and ouputs removed for always_comb/latch. + explicit PEventStatement(bool search_funcs = false); ~PEventStatement(); @@ -429,6 +430,7 @@ class PEventStatement : public Statement { private: svectorexpr_; Statement*statement_; + bool search_funcs_; }; ostream& operator << (ostream&o, const PEventStatement&obj); diff --git a/compiler.h b/compiler.h index b847b6f05..6eccc8743 100644 --- a/compiler.h +++ b/compiler.h @@ -1,7 +1,7 @@ #ifndef IVL_compiler_H #define IVL_compiler_H /* - * Copyright (c) 1999-2016 Stephen Williams (steve@icarus.com) + * Copyright (c) 1999-2017 Stephen Williams (steve@icarus.com) * * This source code is free software; you can redistribute it * and/or modify it in source code form under the terms of the GNU @@ -117,6 +117,13 @@ extern bool debug_emit; extern bool debug_synth2; extern bool debug_optimizer; +/* Ignore errors about missing modules */ +extern bool ignore_missing_modules; + +/* Treat each source file as a separate compilation unit (as defined + by SystemVerilog). */ +extern bool separate_compilation; + /* Control evaluation of functions at compile time: * 0 = only for functions in constant expressions * 1 = only for automatic functions diff --git a/cppcheck.sup b/cppcheck.sup index c3648b228..500f28945 100644 --- a/cppcheck.sup +++ b/cppcheck.sup @@ -1,613 +1,619 @@ // These are correct and are used to find the base (zero) pin. -thisSubtraction:netlist.h:5081 -thisSubtraction:netlist.h:5090 +thisSubtraction:netlist.h:5082 +thisSubtraction:netlist.h:5091 // These are the functions that the compiler exports to the targets. //ivl_branch_island() -unusedFunction:t-dll-api.cc:38 +unusedFunction:t-dll-api.cc:39 //ivl_branch_terminal() -unusedFunction:t-dll-api.cc:43 +unusedFunction:t-dll-api.cc:45 //ivl_const_bits() -unusedFunction:t-dll-api.cc:180 +unusedFunction:t-dll-api.cc:196 //ivl_const_delay() -unusedFunction:t-dll-api.cc:198 +unusedFunction:t-dll-api.cc:214 //ivl_const_file() -unusedFunction:t-dll-api.cc:204 +unusedFunction:t-dll-api.cc:221 //ivl_const_lineno() -unusedFunction:t-dll-api.cc:210 +unusedFunction:t-dll-api.cc:227 //ivl_const_nex() -unusedFunction:t-dll-api.cc:216 +unusedFunction:t-dll-api.cc:233 //ivl_const_real() -unusedFunction:t-dll-api.cc:222 +unusedFunction:t-dll-api.cc:239 //ivl_const_scope() -unusedFunction:t-dll-api.cc:229 +unusedFunction:t-dll-api.cc:246 //ivl_const_signed() -unusedFunction:t-dll-api.cc:235 +unusedFunction:t-dll-api.cc:252 //ivl_const_type() -unusedFunction:t-dll-api.cc:174 +unusedFunction:t-dll-api.cc:190 //ivl_const_width() -unusedFunction:t-dll-api.cc:241 +unusedFunction:t-dll-api.cc:258 //ivl_design_const() -unusedFunction:t-dll-api.cc:116 +unusedFunction:t-dll-api.cc:127 //ivl_design_consts() -unusedFunction:t-dll-api.cc:111 +unusedFunction:t-dll-api.cc:121 //ivl_design_delay_sel() -unusedFunction:t-dll-api.cc:49 +unusedFunction:t-dll-api.cc:52 //ivl_design_discipline() -unusedFunction:t-dll-api.cc:128 +unusedFunction:t-dll-api.cc:140 //ivl_design_disciplines() -unusedFunction:t-dll-api.cc:122 +unusedFunction:t-dll-api.cc:134 //ivl_design_flag() -unusedFunction:t-dll-api.cc:54 -//ivl_design_process() unusedFunction:t-dll-api.cc:59 +//ivl_design_process() +unusedFunction:t-dll-api.cc:66 //ivl_design_root() -unusedFunction:t-dll-api.cc:72 +unusedFunction:t-dll-api.cc:80 //ivl_design_roots() -unusedFunction:t-dll-api.cc:81 +unusedFunction:t-dll-api.cc:89 //ivl_design_time_precision() -unusedFunction:t-dll-api.cc:106 +unusedFunction:t-dll-api.cc:115 //ivl_discipline_domain() -unusedFunction:t-dll-api.cc:135 +unusedFunction:t-dll-api.cc:147 //ivl_discipline_flow() -unusedFunction:t-dll-api.cc:140 +unusedFunction:t-dll-api.cc:153 //ivl_discipline_name() -unusedFunction:t-dll-api.cc:145 +unusedFunction:t-dll-api.cc:159 //ivl_discipline_potential() -unusedFunction:t-dll-api.cc:150 +unusedFunction:t-dll-api.cc:165 //ivl_enum_bits() -unusedFunction:t-dll-api.cc:260 +unusedFunction:t-dll-api.cc:277 //ivl_enum_file() -unusedFunction:t-dll-api.cc:285 +unusedFunction:t-dll-api.cc:302 //ivl_enum_lineno() -unusedFunction:t-dll-api.cc:291 +unusedFunction:t-dll-api.cc:308 //ivl_enum_name() -unusedFunction:t-dll-api.cc:253 +unusedFunction:t-dll-api.cc:270 //ivl_enum_names() -unusedFunction:t-dll-api.cc:247 +unusedFunction:t-dll-api.cc:264 //ivl_enum_signed() -unusedFunction:t-dll-api.cc:279 +unusedFunction:t-dll-api.cc:296 //ivl_enum_type() -unusedFunction:t-dll-api.cc:267 +unusedFunction:t-dll-api.cc:284 //ivl_enum_width() -unusedFunction:t-dll-api.cc:273 +unusedFunction:t-dll-api.cc:290 //ivl_event_any() -unusedFunction:t-dll-api.cc:349 -//ivl_event_file() -unusedFunction:t-dll-api.cc:326 -//ivl_event_lineno() -unusedFunction:t-dll-api.cc:332 -//ivl_event_name() -unusedFunction:t-dll-api.cc:297 -//ivl_event_nany() -unusedFunction:t-dll-api.cc:343 -//ivl_event_neg() -unusedFunction:t-dll-api.cc:362 -//ivl_event_nneg() -unusedFunction:t-dll-api.cc:356 -//ivl_event_npos() unusedFunction:t-dll-api.cc:369 +//ivl_event_file() +unusedFunction:t-dll-api.cc:345 +//ivl_event_lineno() +unusedFunction:t-dll-api.cc:351 +//ivl_event_name() +unusedFunction:t-dll-api.cc:314 +//ivl_event_nany() +unusedFunction:t-dll-api.cc:363 +//ivl_event_neg() +unusedFunction:t-dll-api.cc:382 +//ivl_event_nneg() +unusedFunction:t-dll-api.cc:376 +//ivl_event_npos() +unusedFunction:t-dll-api.cc:389 //ivl_event_pos() -unusedFunction:t-dll-api.cc:375 +unusedFunction:t-dll-api.cc:395 //ivl_event_scope() -unusedFunction:t-dll-api.cc:338 +unusedFunction:t-dll-api.cc:357 //ivl_expr_bits() -unusedFunction:t-dll-api.cc:382 +unusedFunction:t-dll-api.cc:402 //ivl_expr_branch() -unusedFunction:t-dll-api.cc:388 +unusedFunction:t-dll-api.cc:409 //ivl_expr_def() -unusedFunction:t-dll-api.cc:394 -//ivl_expr_delay_val() -unusedFunction:t-dll-api.cc:410 -//ivl_expr_dvalue() unusedFunction:t-dll-api.cc:416 +//ivl_expr_delay_val() +unusedFunction:t-dll-api.cc:432 +//ivl_expr_dvalue() +unusedFunction:t-dll-api.cc:439 //ivl_expr_enumtype() -unusedFunction:t-dll-api.cc:422 +unusedFunction:t-dll-api.cc:446 //ivl_expr_event() -unusedFunction:t-dll-api.cc:628 +unusedFunction:t-dll-api.cc:656 //ivl_expr_file() -unusedFunction:t-dll-api.cc:162 +unusedFunction:t-dll-api.cc:178 //ivl_expr_lineno() -unusedFunction:t-dll-api.cc:168 +unusedFunction:t-dll-api.cc:184 //ivl_expr_name() -unusedFunction:t-dll-api.cc:433 +unusedFunction:t-dll-api.cc:459 //ivl_expr_nature() -unusedFunction:t-dll-api.cc:456 +unusedFunction:t-dll-api.cc:483 //ivl_expr_net_type() -unusedFunction:t-dll-api.cc:428 +unusedFunction:t-dll-api.cc:453 //ivl_expr_opcode() -unusedFunction:t-dll-api.cc:462 +unusedFunction:t-dll-api.cc:490 //ivl_expr_oper1() -unusedFunction:t-dll-api.cc:478 +unusedFunction:t-dll-api.cc:506 //ivl_expr_oper2() -unusedFunction:t-dll-api.cc:516 +unusedFunction:t-dll-api.cc:544 //ivl_expr_oper3() -unusedFunction:t-dll-api.cc:542 +unusedFunction:t-dll-api.cc:570 //ivl_expr_parameter() -unusedFunction:t-dll-api.cc:556 +unusedFunction:t-dll-api.cc:584 //ivl_expr_parm() -unusedFunction:t-dll-api.cc:571 +unusedFunction:t-dll-api.cc:599 //ivl_expr_parms() -unusedFunction:t-dll-api.cc:598 +unusedFunction:t-dll-api.cc:626 //ivl_expr_repeat() -unusedFunction:t-dll-api.cc:621 -//ivl_expr_scope() -unusedFunction:t-dll-api.cc:642 -//ivl_expr_sel_type() unusedFunction:t-dll-api.cc:649 +//ivl_expr_scope() +unusedFunction:t-dll-api.cc:670 +//ivl_expr_sel_type() +unusedFunction:t-dll-api.cc:677 //ivl_expr_signed() -unusedFunction:t-dll-api.cc:674 +unusedFunction:t-dll-api.cc:702 //ivl_expr_sized() -unusedFunction:t-dll-api.cc:680 +unusedFunction:t-dll-api.cc:708 //ivl_expr_string() -unusedFunction:t-dll-api.cc:686 +unusedFunction:t-dll-api.cc:714 //ivl_expr_type() -unusedFunction:t-dll-api.cc:155 +unusedFunction:t-dll-api.cc:171 //ivl_expr_uvalue() -unusedFunction:t-dll-api.cc:692 +unusedFunction:t-dll-api.cc:721 //ivl_expr_value() -unusedFunction:t-dll-api.cc:717 +unusedFunction:t-dll-api.cc:747 //ivl_expr_width() +unusedFunction:t-dll-api.cc:753 -unusedFunction:t-dll-api.cc:723 //ivl_file_table_index() -unusedFunction:t-dll-api.cc:765 +unusedFunction:t-dll-api.cc:795 //ivl_file_table_item() -unusedFunction:t-dll-api.cc:755 +unusedFunction:t-dll-api.cc:785 //ivl_file_table_size() -unusedFunction:t-dll-api.cc:783 +unusedFunction:t-dll-api.cc:813 //ivl_island_flag_set() -unusedFunction:t-dll-api.cc:792 +unusedFunction:t-dll-api.cc:822 //ivl_island_flag_test() -unusedFunction:t-dll-api.cc:806 +unusedFunction:t-dll-api.cc:837 //ivl_logic_attr() -unusedFunction:t-dll-api.cc:832 +unusedFunction:t-dll-api.cc:864 //ivl_logic_attr_cnt() -unusedFunction:t-dll-api.cc:848 +unusedFunction:t-dll-api.cc:880 //ivl_logic_attr_val() -unusedFunction:t-dll-api.cc:853 +unusedFunction:t-dll-api.cc:886 //ivl_logic_basename() -unusedFunction:t-dll-api.cc:901 +unusedFunction:t-dll-api.cc:935 //ivl_logic_delay() -unusedFunction:t-dll-api.cc:936 +unusedFunction:t-dll-api.cc:974 //ivl_logic_drive0() -unusedFunction:t-dll-api.cc:860 -//ivl_logic_drive1() -unusedFunction:t-dll-api.cc:877 -//ivl_logic_file() -unusedFunction:t-dll-api.cc:814 -//ivl_logic_is_cassign() -unusedFunction:t-dll-api.cc:826 -//ivl_logic_lineno() -unusedFunction:t-dll-api.cc:820 -//ivl_logic_name() unusedFunction:t-dll-api.cc:894 +//ivl_logic_drive1() +unusedFunction:t-dll-api.cc:911 +//ivl_logic_file() +unusedFunction:t-dll-api.cc:846 +//ivl_logic_is_cassign() +unusedFunction:t-dll-api.cc:858 +//ivl_logic_lineno() +unusedFunction:t-dll-api.cc:852 +//ivl_logic_name() +unusedFunction:t-dll-api.cc:928 //ivl_logic_pins() -unusedFunction:t-dll-api.cc:918 +unusedFunction:t-dll-api.cc:953 //ivl_logic_scope() -unusedFunction:t-dll-api.cc:907 +unusedFunction:t-dll-api.cc:941 //ivl_logic_type() -unusedFunction:t-dll-api.cc:913 +unusedFunction:t-dll-api.cc:947 //ivl_logic_udp() -unusedFunction:t-dll-api.cc:929 +unusedFunction:t-dll-api.cc:966 //ivl_logic_width() -unusedFunction:t-dll-api.cc:942 +unusedFunction:t-dll-api.cc:981 //ivl_lpm_array() -unusedFunction:t-dll-api.cc:1059 +unusedFunction:t-dll-api.cc:1109 //ivl_lpm_aset_value() -unusedFunction:t-dll-api.cc:1110 +unusedFunction:t-dll-api.cc:1160 //ivl_lpm_async_clr() -unusedFunction:t-dll-api.cc:1005 +unusedFunction:t-dll-api.cc:1054 //ivl_lpm_async_set() -unusedFunction:t-dll-api.cc:1035 +unusedFunction:t-dll-api.cc:1085 //ivl_lpm_base() -unusedFunction:t-dll-api.cc:1071 -//ivl_lpm_basename() -unusedFunction:t-dll-api.cc:1000 -//ivl_lpm_clk() -unusedFunction:t-dll-api.cc:1098 -//ivl_lpm_data() -unusedFunction:t-dll-api.cc:1167 -//ivl_lpm_datab() -unusedFunction:t-dll-api.cc:1264 -//ivl_lpm_define() -unusedFunction:t-dll-api.cc:1133 -//ivl_lpm_delay() -unusedFunction:t-dll-api.cc:1029 -//ivl_lpm_drive0() -unusedFunction:t-dll-api.cc:1393 -//ivl_lpm_drive1() -unusedFunction:t-dll-api.cc:1410 -//ivl_lpm_enable() -unusedFunction:t-dll-api.cc:1145 -//ivl_lpm_file() -unusedFunction:t-dll-api.cc:1157 -//ivl_lpm_lineno() -unusedFunction:t-dll-api.cc:1162 -//ivl_lpm_name() -unusedFunction:t-dll-api.cc:1298 -//ivl_lpm_negedge() -unusedFunction:t-dll-api.cc:1086 -//ivl_lpm_select() -unusedFunction:t-dll-api.cc:1433 -//ivl_lpm_selects() -unusedFunction:t-dll-api.cc:1449 -//ivl_lpm_signed() -unusedFunction:t-dll-api.cc:1466 -//ivl_lpm_size() -unusedFunction:t-dll-api.cc:1525 -//ivl_lpm_sset_value() unusedFunction:t-dll-api.cc:1121 +//ivl_lpm_basename() +unusedFunction:t-dll-api.cc:1048 +//ivl_lpm_clk() +unusedFunction:t-dll-api.cc:1148 +//ivl_lpm_data() +unusedFunction:t-dll-api.cc:1221 +//ivl_lpm_datab() +unusedFunction:t-dll-api.cc:1321 +//ivl_lpm_define() +unusedFunction:t-dll-api.cc:1183 +//ivl_lpm_delay() +unusedFunction:t-dll-api.cc:1078 +//ivl_lpm_drive0() +unusedFunction:t-dll-api.cc:1453 +//ivl_lpm_drive1() +unusedFunction:t-dll-api.cc:1470 +//ivl_lpm_enable() +unusedFunction:t-dll-api.cc:1195 +//ivl_lpm_file() +unusedFunction:t-dll-api.cc:1209 +//ivl_lpm_lineno() +unusedFunction:t-dll-api.cc:1215 +//ivl_lpm_name() +unusedFunction:t-dll-api.cc:1355 +//ivl_lpm_negedge() +unusedFunction:t-dll-api.cc:1136 +//ivl_lpm_select() +unusedFunction:t-dll-api.cc:1493 +//ivl_lpm_selects() +unusedFunction:t-dll-api.cc:1510 +//ivl_lpm_signed() +unusedFunction:t-dll-api.cc:1528 +//ivl_lpm_size() +unusedFunction:t-dll-api.cc:1587 +//ivl_lpm_sset_value() +unusedFunction:t-dll-api.cc:1171 //ivl_lpm_string() -unusedFunction:t-dll-api.cc:1577 +unusedFunction:t-dll-api.cc:1640 //ivl_lpm_sync_clr() -unusedFunction:t-dll-api.cc:1017 +unusedFunction:t-dll-api.cc:1066 //ivl_lpm_sync_set() -unusedFunction:t-dll-api.cc:1047 +unusedFunction:t-dll-api.cc:1097 //ivl_lpm_trigger() -unusedFunction:t-dll-api.cc:1594 +unusedFunction:t-dll-api.cc:1659 //ivl_lpm_type() -unusedFunction:t-dll-api.cc:1583 +unusedFunction:t-dll-api.cc:1647 //ivl_lpm_width() -unusedFunction:t-dll-api.cc:1588 +unusedFunction:t-dll-api.cc:1653 //ivl_lval_idx() -unusedFunction:t-dll-api.cc:1616 +unusedFunction:t-dll-api.cc:1681 //ivl_lval_mux() -unusedFunction:t-dll-api.cc:1611 +unusedFunction:t-dll-api.cc:1676 //ivl_lval_nest() -unusedFunction:t-dll-api.cc:1661 +unusedFunction:t-dll-api.cc:1726 //ivl_lval_part_off() -unusedFunction:t-dll-api.cc:1625 +unusedFunction:t-dll-api.cc:1690 //ivl_lval_property_idx() -unusedFunction:t-dll-api.cc:1643 +unusedFunction:t-dll-api.cc:1708 //ivl_lval_sel_type() -unusedFunction:t-dll-api.cc:1631 +unusedFunction:t-dll-api.cc:1696 //ivl_lval_sig() -unusedFunction:t-dll-api.cc:1649 +unusedFunction:t-dll-api.cc:1714 //ivl_nature_name() -unusedFunction:t-dll-api.cc:1670 +unusedFunction:t-dll-api.cc:1735 //ivl_nexus_get_private() -unusedFunction:t-dll-api.cc:1690 +unusedFunction:t-dll-api.cc:1756 //ivl_nexus_name() -unusedFunction:t-dll-api.cc:1679 +unusedFunction:t-dll-api.cc:1745 //ivl_nexus_ptr_branch() -unusedFunction:t-dll-api.cc:1733 +unusedFunction:t-dll-api.cc:1799 //ivl_nexus_ptr_con() -unusedFunction:t-dll-api.cc:1742 +unusedFunction:t-dll-api.cc:1808 //ivl_nexus_ptr_sig() -unusedFunction:t-dll-api.cc:1769 +unusedFunction:t-dll-api.cc:1835 //ivl_nexus_ptr_switch() -unusedFunction:t-dll-api.cc:1778 +unusedFunction:t-dll-api.cc:1844 //ivl_nexus_set_private() -unusedFunction:t-dll-api.cc:1696 +unusedFunction:t-dll-api.cc:1762 //ivl_parameter_basename() -unusedFunction:t-dll-api.cc:1787 +unusedFunction:t-dll-api.cc:1853 //ivl_parameter_expr() -unusedFunction:t-dll-api.cc:1830 +unusedFunction:t-dll-api.cc:1896 //ivl_parameter_file() -unusedFunction:t-dll-api.cc:1836 +unusedFunction:t-dll-api.cc:1902 //ivl_parameter_lineno() -unusedFunction:t-dll-api.cc:1842 +unusedFunction:t-dll-api.cc:1908 //ivl_parameter_local() -unusedFunction:t-dll-api.cc:1793 +unusedFunction:t-dll-api.cc:1859 //ivl_parameter_lsb() -unusedFunction:t-dll-api.cc:1811 +unusedFunction:t-dll-api.cc:1877 //ivl_parameter_msb() -unusedFunction:t-dll-api.cc:1805 +unusedFunction:t-dll-api.cc:1871 //ivl_parameter_scope() -unusedFunction:t-dll-api.cc:1848 +unusedFunction:t-dll-api.cc:1914 //ivl_parameter_signed() -unusedFunction:t-dll-api.cc:1799 +unusedFunction:t-dll-api.cc:1865 //ivl_parameter_width() -unusedFunction:t-dll-api.cc:1821 +unusedFunction:t-dll-api.cc:1887 //ivl_path_condit() -unusedFunction:t-dll-api.cc:1854 +unusedFunction:t-dll-api.cc:1920 //ivl_path_delay() -unusedFunction:t-dll-api.cc:1866 +unusedFunction:t-dll-api.cc:1932 //ivl_path_is_condit() -unusedFunction:t-dll-api.cc:1860 +unusedFunction:t-dll-api.cc:1926 //ivl_path_scope() -unusedFunction:t-dll-api.cc:1872 +unusedFunction:t-dll-api.cc:1938 //ivl_path_source() -unusedFunction:t-dll-api.cc:1879 +unusedFunction:t-dll-api.cc:1945 //ivl_path_source_negedge() -unusedFunction:t-dll-api.cc:1889 +unusedFunction:t-dll-api.cc:1957 //ivl_path_source_posedge() -unusedFunction:t-dll-api.cc:1884 +unusedFunction:t-dll-api.cc:1951 //ivl_process_analog() -unusedFunction:t-dll-api.cc:1911 +unusedFunction:t-dll-api.cc:1981 //ivl_process_attr_cnt() -unusedFunction:t-dll-api.cc:1926 +unusedFunction:t-dll-api.cc:1999 //ivl_process_attr_val() -unusedFunction:t-dll-api.cc:1931 +unusedFunction:t-dll-api.cc:2005 //ivl_process_file() -unusedFunction:t-dll-api.cc:1894 +unusedFunction:t-dll-api.cc:1963 //ivl_process_lineno() -unusedFunction:t-dll-api.cc:1900 +unusedFunction:t-dll-api.cc:1969 //ivl_process_scope() -unusedFunction:t-dll-api.cc:1916 +unusedFunction:t-dll-api.cc:1987 //ivl_process_stmt() -unusedFunction:t-dll-api.cc:1921 +unusedFunction:t-dll-api.cc:1993 //ivl_process_type() -unusedFunction:t-dll-api.cc:1906 +unusedFunction:t-dll-api.cc:1975 //ivl_scope_attr_cnt() -unusedFunction:t-dll-api.cc:1938 +unusedFunction:t-dll-api.cc:2013 //ivl_scope_attr_val() -unusedFunction:t-dll-api.cc:1944 +unusedFunction:t-dll-api.cc:2019 //ivl_scope_basename() -unusedFunction:t-dll-api.cc:1951 -//ivl_scope_child() -unusedFunction:t-dll-api.cc:1978 -//ivl_scope_children() -unusedFunction:t-dll-api.cc:1958 -//ivl_scope_childs() -unusedFunction:t-dll-api.cc:1972 -//ivl_scope_class() -unusedFunction:t-dll-api.cc:1984 -//ivl_scope_classes() -unusedFunction:t-dll-api.cc:1990 -//ivl_scope_def() -unusedFunction:t-dll-api.cc:1996 -//ivl_scope_def_file() -unusedFunction:t-dll-api.cc:2002 -//ivl_scope_def_lineno() -unusedFunction:t-dll-api.cc:2008 -//ivl_scope_enumerate() -unusedFunction:t-dll-api.cc:2020 -//ivl_scope_enumerates() -unusedFunction:t-dll-api.cc:2014 -//ivl_scope_event() -unusedFunction:t-dll-api.cc:2033 -//ivl_scope_events() unusedFunction:t-dll-api.cc:2027 +//ivl_scope_child() +unusedFunction:t-dll-api.cc:2054 +//ivl_scope_children() +unusedFunction:t-dll-api.cc:2033 +//ivl_scope_childs() +unusedFunction:t-dll-api.cc:2047 +//ivl_scope_class() +unusedFunction:t-dll-api.cc:2061 +//ivl_scope_classes() +unusedFunction:t-dll-api.cc:2068 +//ivl_scope_def() +unusedFunction:t-dll-api.cc:2075 +//ivl_scope_def_file() +unusedFunction:t-dll-api.cc:2081 +//ivl_scope_def_lineno() +unusedFunction:t-dll-api.cc:2087 +//ivl_scope_enumerate() +unusedFunction:t-dll-api.cc:2099 +//ivl_scope_enumerates() +unusedFunction:t-dll-api.cc:2093 +//ivl_scope_event() +unusedFunction:t-dll-api.cc:2112 +//ivl_scope_events() +unusedFunction:t-dll-api.cc:2106 //ivl_scope_file() -unusedFunction:t-dll-api.cc:2040 +unusedFunction:t-dll-api.cc:2119 +//ivl_scope_func_signed +unusedFunction:t-dll-api.cc:2132 +//ivl_scope_func_type +unusedFunction:t-dll-api.cc:2125 +//ivl_scope_func_width +unusedFunction:t-dll-api.cc:2140 //ivl_scope_is_auto() -unusedFunction:t-dll-api.cc:2046 +unusedFunction:t-dll-api.cc:2148 //ivl_scope_is_cell() -unusedFunction:t-dll-api.cc:2052 +unusedFunction:t-dll-api.cc:2154 //ivl_scope_lineno() -unusedFunction:t-dll-api.cc:2058 -//ivl_scope_log() -unusedFunction:t-dll-api.cc:2070 -//ivl_scope_logs() -unusedFunction:t-dll-api.cc:2064 -//ivl_scope_lpm() -unusedFunction:t-dll-api.cc:2083 -//ivl_scope_lpms() -unusedFunction:t-dll-api.cc:2077 -//ivl_scope_mod_module_port_name() unusedFunction:t-dll-api.cc:2160 +//ivl_scope_log() +unusedFunction:t-dll-api.cc:2172 +//ivl_scope_logs() +unusedFunction:t-dll-api.cc:2166 +//ivl_scope_lpm() +unusedFunction:t-dll-api.cc:2185 +//ivl_scope_lpms() +unusedFunction:t-dll-api.cc:2179 +//ivl_scope_mod_module_port_name() +unusedFunction:t-dll-api.cc:2264 //ivl_scope_mod_module_port_type() -unusedFunction:t-dll-api.cc:2169 +unusedFunction:t-dll-api.cc:2273 //ivl_scope_mod_module_port_width() -unusedFunction:t-dll-api.cc:2180 +unusedFunction:t-dll-api.cc:2285 //ivl_scope_mod_module_ports() -unusedFunction:t-dll-api.cc:2153 +unusedFunction:t-dll-api.cc:2257 //ivl_scope_mod_port() -unusedFunction:t-dll-api.cc:2204 +unusedFunction:t-dll-api.cc:2310 //ivl_scope_param() -unusedFunction:t-dll-api.cc:2139 +unusedFunction:t-dll-api.cc:2243 //ivl_scope_params() -unusedFunction:t-dll-api.cc:2133 +unusedFunction:t-dll-api.cc:2237 //ivl_scope_parent() -unusedFunction:t-dll-api.cc:2146 -//ivl_scope_port() -unusedFunction:t-dll-api.cc:2195 -//ivl_scope_ports() -unusedFunction:t-dll-api.cc:2186 -//ivl_scope_sig() -unusedFunction:t-dll-api.cc:2218 -//ivl_scope_sigs() -unusedFunction:t-dll-api.cc:2212 -//ivl_scope_switch() -unusedFunction:t-dll-api.cc:2231 -//ivl_scope_switches() -unusedFunction:t-dll-api.cc:2225 -//ivl_scope_time_precision() -unusedFunction:t-dll-api.cc:2238 -//ivl_scope_time_units() -unusedFunction:t-dll-api.cc:2244 -//ivl_scope_tname() -unusedFunction:t-dll-api.cc:2256 -//ivl_scope_type() unusedFunction:t-dll-api.cc:2250 +//ivl_scope_port() +unusedFunction:t-dll-api.cc:2301 +//ivl_scope_ports() +unusedFunction:t-dll-api.cc:2292 +//ivl_scope_sig() +unusedFunction:t-dll-api.cc:2324 +//ivl_scope_sigs() +unusedFunction:t-dll-api.cc:2318 +//ivl_scope_switch() +unusedFunction:t-dll-api.cc:2337 +//ivl_scope_switches() +unusedFunction:t-dll-api.cc:2331 +//ivl_scope_time_precision() +unusedFunction:t-dll-api.cc:2344 +//ivl_scope_time_units() +unusedFunction:t-dll-api.cc:2350 +//ivl_scope_tname() +unusedFunction:t-dll-api.cc:2362 +//ivl_scope_type() +unusedFunction:t-dll-api.cc:2356 //ivl_signal_array_addr_swapped() -unusedFunction:t-dll-api.cc:2272 -//ivl_signal_array_base() -unusedFunction:t-dll-api.cc:2262 -//ivl_signal_array_count() -unusedFunction:t-dll-api.cc:2267 -//ivl_signal_attr() -unusedFunction:t-dll-api.cc:2287 -//ivl_signal_attr_cnt() -unusedFunction:t-dll-api.cc:2302 -//ivl_signal_attr_val() -unusedFunction:t-dll-api.cc:2307 -//ivl_signal_basename() -unusedFunction:t-dll-api.cc:2313 -//ivl_signal_data_type() -unusedFunction:t-dll-api.cc:2447 -//ivl_signal_dimensions() -unusedFunction:t-dll-api.cc:2277 -//ivl_signal_discipline() -unusedFunction:t-dll-api.cc:2282 -//ivl_signal_file() -unusedFunction:t-dll-api.cc:2425 -//ivl_signal_forced_net() -unusedFunction:t-dll-api.cc:2420 -//ivl_signal_integer() -unusedFunction:t-dll-api.cc:2437 -//ivl_signal_lineno() -unusedFunction:t-dll-api.cc:2431 -//ivl_signal_local() -unusedFunction:t-dll-api.cc:2410 -//ivl_signal_lsb() unusedFunction:t-dll-api.cc:2380 +//ivl_signal_array_base() +unusedFunction:t-dll-api.cc:2368 +//ivl_signal_array_count() +unusedFunction:t-dll-api.cc:2374 +//ivl_signal_attr() +unusedFunction:t-dll-api.cc:2398 +//ivl_signal_attr_cnt() +unusedFunction:t-dll-api.cc:2414 +//ivl_signal_attr_val() +unusedFunction:t-dll-api.cc:2420 +//ivl_signal_basename() +unusedFunction:t-dll-api.cc:2427 +//ivl_signal_data_type() +unusedFunction:t-dll-api.cc:2578 +//ivl_signal_dimensions() +unusedFunction:t-dll-api.cc:2386 +//ivl_signal_discipline() +unusedFunction:t-dll-api.cc:2392 +//ivl_signal_file() +unusedFunction:t-dll-api.cc:2555 +//ivl_signal_forced_net() +unusedFunction:t-dll-api.cc:2549 +//ivl_signal_integer() +unusedFunction:t-dll-api.cc:2567 +//ivl_signal_lineno() +unusedFunction:t-dll-api.cc:2561 +//ivl_signal_local() +unusedFunction:t-dll-api.cc:2536 +//ivl_signal_lsb() +unusedFunction:t-dll-api.cc:2501 //ivl_signal_module_port_index() -unusedFunction:t-dll-api.cc:2405 +unusedFunction:t-dll-api.cc:2530 //ivl_signal_msb() -unusedFunction:t-dll-api.cc:2371 +unusedFunction:t-dll-api.cc:2491 //ivl_signal_name() -unusedFunction:t-dll-api.cc:2318 +unusedFunction:t-dll-api.cc:2433 //ivl_signal_nex() -unusedFunction:t-dll-api.cc:2338 +unusedFunction:t-dll-api.cc:2454 //ivl_signal_npath() -unusedFunction:t-dll-api.cc:2457 +unusedFunction:t-dll-api.cc:2591 //ivl_signal_packed_dimensions() -unusedFunction:t-dll-api.cc:2354 +unusedFunction:t-dll-api.cc:2471 //ivl_signal_packed_lsb() -unusedFunction:t-dll-api.cc:2365 +unusedFunction:t-dll-api.cc:2484 //ivl_signal_packed_msb() -unusedFunction:t-dll-api.cc:2359 +unusedFunction:t-dll-api.cc:2477 //ivl_signal_path() -unusedFunction:t-dll-api.cc:2462 +unusedFunction:t-dll-api.cc:2597 //ivl_signal_port() -unusedFunction:t-dll-api.cc:2400 +unusedFunction:t-dll-api.cc:2524 //ivl_signal_scope() -unusedFunction:t-dll-api.cc:2389 +unusedFunction:t-dll-api.cc:2511 //ivl_signal_signed() -unusedFunction:t-dll-api.cc:2415 +unusedFunction:t-dll-api.cc:2542 //ivl_signal_width() -unusedFunction:t-dll-api.cc:2395 +unusedFunction:t-dll-api.cc:2517 //ivl_statement_type() -unusedFunction:t-dll-api.cc:2473 +unusedFunction:t-dll-api.cc:2610 //ivl_stmt_block_count() -unusedFunction:t-dll-api.cc:2502 +unusedFunction:t-dll-api.cc:2643 //ivl_stmt_block_scope() -unusedFunction:t-dll-api.cc:2488 +unusedFunction:t-dll-api.cc:2628 //ivl_stmt_block_stmt() -unusedFunction:t-dll-api.cc:2516 +unusedFunction:t-dll-api.cc:2658 //ivl_stmt_call() -unusedFunction:t-dll-api.cc:2531 +unusedFunction:t-dll-api.cc:2674 //ivl_stmt_case_count() -unusedFunction:t-dll-api.cc:2551 +unusedFunction:t-dll-api.cc:2695 //ivl_stmt_case_expr() -unusedFunction:t-dll-api.cc:2565 +unusedFunction:t-dll-api.cc:2710 //ivl_stmt_case_stmt() -unusedFunction:t-dll-api.cc:2581 +unusedFunction:t-dll-api.cc:2727 //ivl_stmt_cond_expr() -unusedFunction:t-dll-api.cc:2597 +unusedFunction:t-dll-api.cc:2744 //ivl_stmt_cond_false() -unusedFunction:t-dll-api.cc:2623 +unusedFunction:t-dll-api.cc:2771 //ivl_stmt_cond_true() -unusedFunction:t-dll-api.cc:2632 +unusedFunction:t-dll-api.cc:2781 //ivl_stmt_delay_expr() -unusedFunction:t-dll-api.cc:2641 +unusedFunction:t-dll-api.cc:2791 //ivl_stmt_delay_val() -unusedFunction:t-dll-api.cc:2657 +unusedFunction:t-dll-api.cc:2808 //ivl_stmt_events() -unusedFunction:t-dll-api.cc:2681 +unusedFunction:t-dll-api.cc:2834 //ivl_stmt_file() -unusedFunction:t-dll-api.cc:2478 +unusedFunction:t-dll-api.cc:2616 //ivl_stmt_lexp() -unusedFunction:t-dll-api.cc:2708 -//ivl_stmt_lineno() -unusedFunction:t-dll-api.cc:2483 -//ivl_stmt_lval() -unusedFunction:t-dll-api.cc:2719 -//ivl_stmt_lvals() -unusedFunction:t-dll-api.cc:2737 -//ivl_stmt_lwidth() -unusedFunction:t-dll-api.cc:2754 -//ivl_stmt_name() -unusedFunction:t-dll-api.cc:2786 -//ivl_stmt_nevent() -unusedFunction:t-dll-api.cc:2663 -//ivl_stmt_opcode() -unusedFunction:t-dll-api.cc:2798 -//ivl_stmt_parm() -unusedFunction:t-dll-api.cc:2809 -//ivl_stmt_parm_count() -unusedFunction:t-dll-api.cc:2822 -//ivl_stmt_rval() -unusedFunction:t-dll-api.cc:2833 -//ivl_stmt_sfunc_as_task() -unusedFunction:t-dll-api.cc:2850 -//ivl_stmt_sub_stmt() unusedFunction:t-dll-api.cc:2862 +//ivl_stmt_lineno() +unusedFunction:t-dll-api.cc:2622 +//ivl_stmt_lval() +unusedFunction:t-dll-api.cc:2874 +//ivl_stmt_lvals() +unusedFunction:t-dll-api.cc:2893 +//ivl_stmt_lwidth() +unusedFunction:t-dll-api.cc:2911 +//ivl_stmt_name() +unusedFunction:t-dll-api.cc:2944 +//ivl_stmt_nevent() +unusedFunction:t-dll-api.cc:2815 +//ivl_stmt_opcode() +unusedFunction:t-dll-api.cc:2957 +//ivl_stmt_parm() +unusedFunction:t-dll-api.cc:2969 +//ivl_stmt_parm_count() +unusedFunction:t-dll-api.cc:2983 +//ivl_stmt_rval() +unusedFunction:t-dll-api.cc:2995 +//ivl_stmt_sfunc_as_task() +unusedFunction:t-dll-api.cc:3013 +//ivl_stmt_sub_stmt() +unusedFunction:t-dll-api.cc:3026 //ivl_switch_a() -unusedFunction:t-dll-api.cc:2899 +unusedFunction:t-dll-api.cc:3067 //ivl_switch_b() -unusedFunction:t-dll-api.cc:2904 +unusedFunction:t-dll-api.cc:3073 //ivl_switch_basename() -unusedFunction:t-dll-api.cc:2884 +unusedFunction:t-dll-api.cc:3049 //ivl_switch_delay() -unusedFunction:t-dll-api.cc:2929 +unusedFunction:t-dll-api.cc:3103 //ivl_switch_enable() -unusedFunction:t-dll-api.cc:2909 +unusedFunction:t-dll-api.cc:3079 //ivl_switch_file() -unusedFunction:t-dll-api.cc:2935 +unusedFunction:t-dll-api.cc:3110 //ivl_switch_island() -unusedFunction:t-dll-api.cc:2940 +unusedFunction:t-dll-api.cc:3116 //ivl_switch_lineno() -unusedFunction:t-dll-api.cc:2945 +unusedFunction:t-dll-api.cc:3122 //ivl_switch_offset() -unusedFunction:t-dll-api.cc:2924 +unusedFunction:t-dll-api.cc:3097 //ivl_switch_part() -unusedFunction:t-dll-api.cc:2919 +unusedFunction:t-dll-api.cc:3091 //ivl_switch_scope() -unusedFunction:t-dll-api.cc:2889 +unusedFunction:t-dll-api.cc:3055 //ivl_switch_type() -unusedFunction:t-dll-api.cc:2894 +unusedFunction:t-dll-api.cc:3061 //ivl_switch_width() -unusedFunction:t-dll-api.cc:2914 +unusedFunction:t-dll-api.cc:3085 //ivl_type_base() -unusedFunction:t-dll-api.cc:2950 +unusedFunction:t-dll-api.cc:3128 //ivl_type_element() -unusedFunction:t-dll-api.cc:2956 +unusedFunction:t-dll-api.cc:3134 //ivl_type_name() -unusedFunction:t-dll-api.cc:2985 +unusedFunction:t-dll-api.cc:3166 //ivl_type_packed_dimensions() -unusedFunction:t-dll-api.cc:2965 +unusedFunction:t-dll-api.cc:3143 //ivl_type_packed_lsb() -unusedFunction:t-dll-api.cc:2971 +unusedFunction:t-dll-api.cc:3150 //ivl_type_packed_msb() -unusedFunction:t-dll-api.cc:2978 +unusedFunction:t-dll-api.cc:3158 //ivl_type_prop_type() -unusedFunction:t-dll-api.cc:3011 +unusedFunction:t-dll-api.cc:3191 //ivl_type_properties() -unusedFunction:t-dll-api.cc:2994 +unusedFunction:t-dll-api.cc:3174 //ivl_type_signed() -unusedFunction:t-dll-api.cc:3019 +unusedFunction:t-dll-api.cc:3199 //ivl_udp_file() -unusedFunction:t-dll-api.cc:990 +unusedFunction:t-dll-api.cc:1036 //ivl_udp_init() -unusedFunction:t-dll-api.cc:958 +unusedFunction:t-dll-api.cc:999 //ivl_udp_lineno() -unusedFunction:t-dll-api.cc:995 +unusedFunction:t-dll-api.cc:1042 //ivl_udp_name() -unusedFunction:t-dll-api.cc:984 +unusedFunction:t-dll-api.cc:1029 //ivl_udp_nin() -unusedFunction:t-dll-api.cc:953 +unusedFunction:t-dll-api.cc:993 //ivl_udp_port() -unusedFunction:t-dll-api.cc:963 +unusedFunction:t-dll-api.cc:1005 //ivl_udp_row() -unusedFunction:t-dll-api.cc:971 +unusedFunction:t-dll-api.cc:1014 //ivl_udp_rows() -unusedFunction:t-dll-api.cc:979 +unusedFunction:t-dll-api.cc:1023 // ivl_udp_sequ() -unusedFunction:t-dll-api.cc:948 +unusedFunction:t-dll-api.cc:987 diff --git a/design_dump.cc b/design_dump.cc index 44a9b8ddc..b5f52cfad 100644 --- a/design_dump.cc +++ b/design_dump.cc @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998-2016 Stephen Williams (steve@icarus.com) + * Copyright (c) 1998-2017 Stephen Williams (steve@icarus.com) * * This source code is free software; you can redistribute it * and/or modify it in source code form under the terms of the GNU @@ -187,9 +187,15 @@ ostream& operator << (ostream&fd, NetCaseCmp::kind_t that) case NetCaseCmp::NEQ: fd << "!=="; break; - case NetCaseCmp::XEQ: + case NetCaseCmp::WEQ: fd << "==?"; break; + case NetCaseCmp::WNE: + fd << "!=?"; + break; + case NetCaseCmp::XEQ: + fd << "==x?"; + break; case NetCaseCmp::ZEQ: fd << "==z?"; break; @@ -984,6 +990,18 @@ void NetProcTop::dump(ostream&o, unsigned ind) const o << "always /* " << get_fileline() << " in " << scope_path(scope_) << " */" << endl; break; + case IVL_PR_ALWAYS_COMB: + o << "always_comb /* " << get_fileline() << " in " + << scope_path(scope_) << " */" << endl; + break; + case IVL_PR_ALWAYS_FF: + o << "always_ff /* " << get_fileline() << " in " + << scope_path(scope_) << " */" << endl; + break; + case IVL_PR_ALWAYS_LATCH: + o << "always_latch /* " << get_fileline() << " in " + << scope_path(scope_) << " */" << endl; + break; case IVL_PR_FINAL: o << "final /* " << get_fileline() << " in " << scope_path(scope_) << " */" << endl; @@ -1011,6 +1029,13 @@ void NetAnalogTop::dump(ostream&o, unsigned ind) const << scope_path(scope_) << " */" << endl; break; + // These are not used in an analog context. + case IVL_PR_ALWAYS_COMB: + case IVL_PR_ALWAYS_FF: + case IVL_PR_ALWAYS_LATCH: + assert(0); + break; + case IVL_PR_FINAL: o << "analog final /* " << get_fileline() << " in " << scope_path(scope_) << " */" << endl; @@ -1390,6 +1415,8 @@ void NetScope::dump(ostream&o) const if (is_interface()) o << " (interface)"; o << " " << children_.size() << " children, " << classes_.size() << " classes" << endl; + if (unit() && !is_unit()) + o << " in compilation unit " << unit()->basename() << endl; for (unsigned idx = 0 ; idx < attr_cnt() ; idx += 1) o << " (* " << attr_key(idx) << " = " @@ -1629,11 +1656,14 @@ void NetEBinary::dump(ostream&o) const case 'A': o << "~&"; break; + case 'e': + o << "=="; + break; case 'E': o << "==="; break; - case 'e': - o << "=="; + case 'w': + o << "==?"; break; case 'G': o << ">="; @@ -1650,6 +1680,9 @@ void NetEBinary::dump(ostream&o) const case 'N': o << "!=="; break; + case 'W': + o << "!=?"; + break; case 'o': o << "||"; break; @@ -1902,18 +1935,6 @@ void Design::dump(ostream&o) const cur->second->dump(o); } - o << "$ROOT CLASSES:" << endl; - for (map::const_iterator cur = classes_.begin() - ; cur != classes_.end() ; ++cur) { - cur->second->dump_scope(o); - } - - o << "$ROOT TASKS/FUNCTIONS:" << endl; - for (map::const_iterator cur = root_tasks_.begin() - ; cur != root_tasks_.end() ; ++ cur) { - cur->first->dump(o); - } - o << "SCOPES:" << endl; for (list::const_iterator scope = root_scopes_.begin(); scope != root_scopes_.end(); ++ scope ) { diff --git a/driver/cflexor.lex b/driver/cflexor.lex index 3f3e46e80..c6e3eb860 100644 --- a/driver/cflexor.lex +++ b/driver/cflexor.lex @@ -4,7 +4,7 @@ %{ /* - * Copyright (c) 2001-2016 Stephen Williams (steve@icarus.com) + * Copyright (c) 2001-2017 Stephen Williams (steve@icarus.com) * * This source code is free software; you can redistribute it * and/or modify it in source code form under the terms of the GNU @@ -252,7 +252,7 @@ void destroy_lexor(void) { # ifdef FLEX_SCANNER # if YY_FLEX_MAJOR_VERSION >= 2 && YY_FLEX_MINOR_VERSION >= 5 -# if defined(YY_FLEX_SUBMINOR_VERSION) && YY_FLEX_SUBMINOR_VERSION >= 9 +# if YY_FLEX_MINOR_VERSION > 5 || defined(YY_FLEX_SUBMINOR_VERSION) && YY_FLEX_SUBMINOR_VERSION >= 9 yylex_destroy(); # endif # endif diff --git a/driver/iverilog.man.in b/driver/iverilog.man.in index ba05d2a0a..e315e1825 100644 --- a/driver/iverilog.man.in +++ b/driver/iverilog.man.in @@ -1,10 +1,10 @@ -.TH iverilog 1 "Oct 2nd, 2016" "" "Version %M.%n%E" +.TH iverilog 1 "Nov 8th, 2017" "" "Version %M.%n%E" .SH NAME iverilog - Icarus Verilog compiler .SH SYNOPSIS .B iverilog -[\-ESVv] [\-Bpath] [\-ccmdfile|\-fcmdfile] [\-Dmacro[=defn]] +[\-ESuVv] [\-Bpath] [\-ccmdfile|\-fcmdfile] [\-Dmacro[=defn]] [\-Pparameter=value] [\-pflag=value] [\-dname] [\-g1995\:|\-g2001\:|\-g2005\:|\-g2005-sv\:|\-g2009\:|\-g2012\:|\-g] [\-Iincludedir] [\-mmodule] [\-M[mode=]file] [\-Nfile] [\-ooutputfilename] @@ -222,6 +222,12 @@ will suppress the warning that the compiler is making a choice. Use this switch to specify the target output format. See the \fBTARGETS\fP section below for a list of valid output formats. .TP 8 +.B -u +Treat each source file as a separate compilation unit (as defined in +SystemVerilog). If compiling for an \fIIEEE1364\fP generation, this +will just reset all compiler directives (including macro definitions) +before each new file is processed. +.TP 8 .B -v Turn on verbose messages. This will print the command lines that are executed to perform the actual compilation, along with version @@ -264,7 +270,7 @@ that contain Verilog source files. During elaboration, the compiler notices the instantiation of undefined module types. If the user specifies library search directories, the compiler will search the directory for files with the name of the missing module type. If it -finds such a file, it loads it as a Verilog source file, they tries +finds such a file, it loads it as a Verilog source file, then tries again to elaborate the module. Library module files should contain only a single module, but this is @@ -310,8 +316,9 @@ after a \fB\-Wall\fP argument to suppress isolated warning types. .TP 8 .B all -This enables the anachronisms, implicit, portbind, select\-range, -timescale, and sensitivity\-entire\-array warning categories. +This enables the anachronisms, implicit, macro-replacement, portbind, +select\-range, timescale, and sensitivity\-entire\-array warning +categories. .TP 8 .B anachronisms @@ -324,6 +331,13 @@ This enables warnings for creation of implicit declarations. For example, if a scalar wire X is used but not declared in the Verilog source, this will print a warning at its first use. +.TP 8 +.B macro-redefinition\fI | \fPmacro-replacement +This enables preprocessor warnings when a macro is being redefined. +The first variant prints a warning any time a macro is redefined. +The second variant only prints a warning if the macro text changes. +Use \fBno-macro-redefinition\fP to turn off all warnings of this type. + .TP 8 .B portbind This enables warnings for ports of module instantiations that are not @@ -564,7 +578,7 @@ Tips on using, debugging, and developing the compiler can be found at .SH COPYRIGHT .nf -Copyright \(co 2002\-2016 Stephen Williams +Copyright \(co 2002\-2017 Stephen Williams This document can be freely redistributed according to the terms of the GNU General Public License version 2.0 diff --git a/driver/main.c b/driver/main.c index a15235a98..b723d7ff3 100644 --- a/driver/main.c +++ b/driver/main.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000-2016 Stephen Williams (steve@icarus.com) + * Copyright (c) 2000-2017 Stephen Williams (steve@icarus.com) * * This source code is free software; you can redistribute it * and/or modify it in source code form under the terms of the GNU @@ -38,7 +38,7 @@ const char NOTICE[] = ; const char HELP[] = -"Usage: iverilog [-ESvV] [-B base] [-c cmdfile|-f cmdfile]\n" +"Usage: iverilog [-EiSuvV] [-B base] [-c cmdfile|-f cmdfile]\n" " [-g1995|-g2001|-g2005|-g2005-sv|-g2009|-g2012] [-g]\n" " [-D macro[=defn]] [-I includedir]\n" " [-M [mode=]depfile] [-m module]\n" @@ -138,7 +138,12 @@ int gen_std_include = 1; of the include list. */ int gen_relative_include = 0; -char warning_flags[16] = "n"; +char warning_flags[17] = "n"; + +int separate_compilation_flag = 0; + +/* Boolean: true means ignore errors about missing modules */ +int ignore_missing_modules = 0; unsigned integer_width = 32; @@ -341,10 +346,15 @@ static int t_version_only(void) static void build_preprocess_command(int e_flag) { - snprintf(tmp, sizeof tmp, "%s%civlpp %s%s -F\"%s\" -f\"%s\" -p\"%s\" ", - ivlpp_dir, sep, verbose_flag?" -v":"", - e_flag?"":" -L", defines_path, source_path, - compiled_defines_path); + snprintf(tmp, sizeof tmp, "%s%civlpp %s%s%s -F\"%s\" -f\"%s\" -p\"%s\"%s", + ivlpp_dir, sep, + verbose_flag ? " -v" : "", + e_flag ? "" : " -L", + strchr(warning_flags, 'r') ? " -Wredef-all " : + strchr(warning_flags, 'R') ? " -Wredef-chg " : "", + defines_path, source_path, + compiled_defines_path, + e_flag ? "" : " | "); } static int t_preprocess_only(void) @@ -407,8 +417,12 @@ static int t_compile(void) { unsigned rc; - /* Start by building the preprocess command line. */ - build_preprocess_command(0); + /* Start by building the preprocess command line, if required. + This pipes into the main ivl command. */ + if (!separate_compilation_flag) + build_preprocess_command(0); + else + strcpy(tmp, ""); size_t ncmd = strlen(tmp); char*cmd = malloc(ncmd + 1); @@ -418,8 +432,8 @@ static int t_compile(void) int rtn; #endif - /* Build the ivl command and pipe it to the preprocessor. */ - snprintf(tmp, sizeof tmp, " | %s%civl", base, sep); + /* Build the ivl command. */ + snprintf(tmp, sizeof tmp, "%s%civl", base, sep); rc = strlen(tmp); cmd = realloc(cmd, ncmd+rc+1); strcpy(cmd+ncmd, tmp); @@ -447,7 +461,16 @@ static int t_compile(void) strcpy(cmd+ncmd, tmp); ncmd += rc; - snprintf(tmp, sizeof tmp, " -C\"%s\" -- -", iconfig_common_path); + snprintf(tmp, sizeof tmp, " -C\"%s\"", iconfig_common_path); + rc = strlen(tmp); + cmd = realloc(cmd, ncmd+rc+1); + strcpy(cmd+ncmd, tmp); + ncmd += rc; + + if (separate_compilation_flag) + snprintf(tmp, sizeof tmp, " -F\"%s\"", source_path); + else + snprintf(tmp, sizeof tmp, " -- -"); rc = strlen(tmp); cmd = realloc(cmd, ncmd+rc+1); strcpy(cmd+ncmd, tmp); @@ -498,6 +521,7 @@ static void process_warning_switch(const char*name) process_warning_switch("anachronisms"); process_warning_switch("implicit"); process_warning_switch("implicit-dimensions"); + process_warning_switch("macro-replacement"); process_warning_switch("portbind"); process_warning_switch("select-range"); process_warning_switch("timescale"); @@ -514,6 +538,12 @@ static void process_warning_switch(const char*name) } else if (strcmp(name,"implicit-dimensions") == 0) { if (! strchr(warning_flags, 'd')) strcat(warning_flags, "d"); + } else if (strcmp(name,"macro-redefinition") == 0) { + if (! strchr(warning_flags, 'r')) + strcat(warning_flags, "r"); + } else if (strcmp(name,"macro-replacement") == 0) { + if (! strchr(warning_flags, 'R')) + strcat(warning_flags, "R"); } else if (strcmp(name,"portbind") == 0) { if (! strchr(warning_flags, 'p')) strcat(warning_flags, "p"); @@ -558,6 +588,17 @@ static void process_warning_switch(const char*name) cp[0] = cp[1]; cp += 1; } + } else if (strcmp(name,"no-macro-redefinition") == 0) { + char*cp = strchr(warning_flags, 'r'); + if (cp) while (*cp) { + cp[0] = cp[1]; + cp += 1; + } + cp = strchr(warning_flags, 'R'); + if (cp) while (*cp) { + cp[0] = cp[1]; + cp += 1; + } } else if (strcmp(name,"no-portbind") == 0) { char*cp = strchr(warning_flags, 'p'); if (cp) while (*cp) { @@ -987,7 +1028,7 @@ int main(int argc, char **argv) } } - while ((opt = getopt(argc, argv, "B:c:D:d:Ef:g:hl:I:M:m:N:o:P:p:Ss:T:t:vVW:y:Y:")) != EOF) { + while ((opt = getopt(argc, argv, "B:c:D:d:Ef:g:hl:I:iM:m:N:o:P:p:Ss:T:t:uvVW:y:Y:")) != EOF) { switch (opt) { case 'B': @@ -1042,6 +1083,10 @@ int main(int argc, char **argv) process_include_dir(optarg); break; + case 'i': + ignore_missing_modules = 1; + break; + case 'l': process_file_name(optarg, 1); break; @@ -1086,6 +1131,9 @@ int main(int argc, char **argv) case 't': targ = optarg; break; + case 'u': + separate_compilation_flag = 1; + break; case 'v': verbose_flag = 1; break; @@ -1128,7 +1176,7 @@ int main(int argc, char **argv) if (version_flag || verbose_flag) { printf("Icarus Verilog version " VERSION " (" VERSION_TAG ")\n\n"); - printf("Copyright 1998-2015 Stephen Williams\n\n"); + printf("Copyright 1998-2017 Stephen Williams\n\n"); puts(NOTICE); } @@ -1184,6 +1232,7 @@ int main(int argc, char **argv) fprintf(iconfig_file, "generation:%s\n", gen_verilog_ams); fprintf(iconfig_file, "generation:%s\n", gen_icarus); fprintf(iconfig_file, "warnings:%s\n", warning_flags); + fprintf(iconfig_file, "ignore_missing_modules:%s\n", ignore_missing_modules ? "true" : "false"); fprintf(iconfig_file, "out:%s\n", opath); if (depfile) { fprintf(iconfig_file, "depfile:%s\n", depfile); @@ -1260,8 +1309,12 @@ int main(int argc, char **argv) will append to the file, so this is necessary to make sure it starts out empty. */ if (depfile) { - FILE*fd = fopen(depfile, "w"); - fclose(fd); + FILE *fd = fopen(depfile, "w"); + if (!fd) { + fprintf(stderr, "%s: can't open %s file.\n\n%s\n", argv[0], depfile, HELP); + return 1; + } + fclose(fd); } if (source_count == 0 && !version_flag) { @@ -1276,8 +1329,12 @@ int main(int argc, char **argv) /* Write the preprocessor command needed to preprocess a single file. This may be used to preprocess library files. */ - fprintf(iconfig_file, "ivlpp:%s%civlpp -L -F\"%s\" -P\"%s\"\n", - ivlpp_dir, sep, defines_path, compiled_defines_path); + fprintf(iconfig_file, "ivlpp:%s%civlpp %s -L -F\"%s\" -P\"%s\"\n", + ivlpp_dir, sep, + strchr(warning_flags, 'r') ? "-Wredef-all" : + strchr(warning_flags, 'R') ? "-Wredef-chg" : "", + defines_path, compiled_defines_path + ); /* Done writing to the iconfig file. Close it now. */ fclose(iconfig_file); diff --git a/elab_expr.cc b/elab_expr.cc index 453f91b02..f8a46bb5d 100644 --- a/elab_expr.cc +++ b/elab_expr.cc @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999-2016 Stephen Williams (steve@icarus.com) + * Copyright (c) 1999-2018 Stephen Williams (steve@icarus.com) * Copyright CERN 2013 / Stephen Williams (steve@icarus.com) * * This source code is free software; you can redistribute it @@ -329,10 +329,12 @@ unsigned PEBinary::test_width(Design*des, NetScope*scope, width_mode_t&mode) case '>': // > Should be handled by PEBComp case 'e': // == Should be handled by PEBComp case 'E': // === Should be handled by PEBComp + case 'w': // ==? Should be handled by PEBComp case 'L': // <= Should be handled by PEBComp case 'G': // >= Should be handled by PEBComp case 'n': // != Should be handled by PEBComp case 'N': // !== Should be handled by PEBComp + case 'W': // !=? Should be handled by PEBComp case 'p': // ** should be handled by PEBPower ivl_assert(*this, 0); default: @@ -668,6 +670,18 @@ NetExpr* PEBComp::elaborate_expr(Design*des, NetScope*scope, return 0; } break; + case 'w': /* ==? */ + case 'W': /* !=? */ + if ((lp->expr_type() != IVL_VT_BOOL && lp->expr_type() != IVL_VT_LOGIC) || + (rp->expr_type() != IVL_VT_BOOL && rp->expr_type() != IVL_VT_LOGIC)) { + cerr << get_fileline() << ": error: " + << human_readable_op(op_) + << " operator may only have INTEGRAL operands." + << endl; + des->errors += 1; + return 0; + } + break; default: break; } @@ -1442,6 +1456,13 @@ NetExpr* PECallFunction::elaborate_sfunc_(Design*des, NetScope*scope, return 0; } + if (!type_is_vectorable(expr_type_)) { + cerr << get_fileline() << ": error: The argument to " + << name << " must be a vector type." << endl; + des->errors += 1; + return 0; + } + if (debug_elaborate) { cerr << get_fileline() << ": PECallFunction::elaborate_sfunc_: " << name << " expression is the argument cast to expr_wid=" << expr_wid << endl; @@ -2264,8 +2285,8 @@ NetExpr* PECallFunction::elaborate_base_(Design*des, NetScope*scope, NetScope*ds } cerr << get_fileline() << ": internal error: Unable to locate " - "function return value for " << path_ - << " in " << dscope->basename() << "." << endl; + "function return value for " << path_ + << " in " << dscope->basename() << "." << endl; des->errors += 1; return 0; } @@ -2536,7 +2557,13 @@ NetExpr* PECastSize::elaborate_expr(Design*des, NetScope*scope, ivl_assert(*this, size_); ivl_assert(*this, base_); - NetExpr*sub = base_->elaborate_expr(des, scope, base_->expr_width(), flags); + // When changing size, a cast behaves exactly like an assignment, + // so the result size affects the final expression width. + unsigned cast_width = base_->expr_width(); + if (cast_width < expr_width_) + cast_width = expr_width_; + + NetExpr*sub = base_->elaborate_expr(des, scope, cast_width, flags); // Perform the cast. The extension method (zero/sign), if needed, // depends on the type of the base expression. @@ -2590,7 +2617,7 @@ NetExpr* PECastType::elaborate_expr(Design*des, NetScope*scope, // Find rounded up length that can fit the whole casted array of vectors int len = base->expr_width() + vector->packed_width() - 1; - if(base->expr_width() > vector->packed_width()) { + if(base->expr_width() > (unsigned)vector->packed_width()) { len /= vector->packed_width(); } else { len /= base->expr_width(); @@ -2754,6 +2781,7 @@ NetExpr* PEConcat::elaborate_expr(Design*, NetScope*, tmp->set_line(*this); return tmp; } + // fallthrough default: cerr << get_fileline() << ": internal error: " << "I don't know how to elaborate(ivl_type_t)" @@ -3141,6 +3169,25 @@ unsigned PEIdent::test_width_method_(Design*des, NetScope*scope, width_mode_t&) } } + // Look for the enumeration attributes. + if (const netenum_t*netenum = net->enumeration()) { + if (member_name == "num") { + expr_type_ = IVL_VT_BOOL; + expr_width_ = 32; + min_width_ = 32; + signed_flag_= true; + return 32; + } + if ((member_name == "first") || (member_name == "last") || + (member_name == "next") || (member_name == "prev")) { + expr_type_ = netenum->base_type(); + expr_width_ = netenum->packed_width();; + min_width_ = expr_width_; + signed_flag_ = netenum->get_signed(); + return expr_width_; + } + } + return 0; } @@ -3448,29 +3495,41 @@ NetExpr* PEIdent::elaborate_expr(Design*des, NetScope*scope, } if (net == 0) { - cerr << get_fileline() << ": internal error: " - << "Expecting idents with ntype to be signals." << endl; + cerr << get_fileline() << ": error: Unable to bind variable `" + << path_ << "' in `" << scope_path(use_scope) << "'" << endl; des->errors += 1; return 0; } - if (! ntype->type_compatible(net->net_type())) { - cerr << get_fileline() << ": internal_error: " - << "net type doesn't match context type." << endl; + if (const netdarray_t*array_type = dynamic_cast (ntype)) { + if (array_type->type_compatible(net->net_type())) { + NetESignal*tmp = new NetESignal(net); + tmp->set_line(*this); + return tmp; + } - cerr << get_fileline() << ": : " - << "net type="; + // Icarus allows a dynamic array to be initialised with a + // single elementary value, so try that next. + ntype = array_type->element_type(); + } + + if (! ntype->type_compatible(net->net_type())) { + cerr << get_fileline() << ": error: the type of the variable '" + << path_ << "' doesn't match the context type." << endl; + + cerr << get_fileline() << ": : " << "variable type="; if (net->net_type()) net->net_type()->debug_dump(cerr); else cerr << ""; cerr << endl; - cerr << get_fileline() << ": : " - << "context type="; + cerr << get_fileline() << ": : " << "context type="; ivl_assert(*this, ntype); ntype->debug_dump(cerr); cerr << endl; + des->errors += 1; + return 0; } ivl_assert(*this, ntype->type_compatible(net->net_type())); @@ -5326,9 +5385,8 @@ NetExpr* PENewArray::elaborate_expr(Design*des, NetScope*scope, // expression. Elaborate the expression as an element // type. The run-time will assign this value to each element. const netarray_t*array_type = dynamic_cast (ntype); - ivl_type_t elem_type = array_type->element_type(); - init_val = init_->elaborate_expr(des, scope, elem_type, flags); + init_val = init_->elaborate_expr(des, scope, array_type, flags); } NetENew*tmp = new NetENew(ntype, size, init_val); @@ -5579,6 +5637,10 @@ unsigned PENumber::test_width(Design*, NetScope*, width_mode_t&mode) NetExpr* PENumber::elaborate_expr(Design*des, NetScope*, ivl_type_t ntype, unsigned) const { + // Icarus allows dynamic arrays to be initialised with a single value. + if (const netdarray_t*array_type = dynamic_cast (ntype)) + ntype = array_type->element_type(); + const netvector_t*use_type = dynamic_cast (ntype); if (use_type == 0) { cerr << get_fileline() << ": internal error: " @@ -5685,7 +5747,6 @@ unsigned PETernary::test_width(Design*des, NetScope*scope, width_mode_t&mode) } else if (tru_type == IVL_VT_LOGIC || fal_type == IVL_VT_LOGIC) { expr_type_ = IVL_VT_LOGIC; } else { - ivl_assert(*this, tru_type == fal_type); expr_type_ = tru_type; } if (expr_type_ == IVL_VT_REAL) { diff --git a/elab_lval.cc b/elab_lval.cc index d1ee58fb7..4696c9eaf 100644 --- a/elab_lval.cc +++ b/elab_lval.cc @@ -1194,7 +1194,12 @@ bool PEIdent::elaborate_lval_net_packed_member_(Design*des, NetScope*scope, if (!name_tail.index.empty()) use_sel = name_tail.index.back().sel; - ivl_assert(*this, use_sel == index_component_t::SEL_NONE || use_sel == index_component_t::SEL_BIT); + if (use_sel != index_component_t::SEL_NONE && use_sel != index_component_t::SEL_BIT) { + cerr << get_fileline() << ": sorry: Assignments to part selects of " + "a struct member are not yet supported." << endl; + des->errors += 1; + return false; + } if (! name_tail.index.empty()) { diff --git a/elab_scope.cc b/elab_scope.cc index 73834249c..cfbc2a50d 100644 --- a/elab_scope.cc +++ b/elab_scope.cc @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000-2016 Stephen Williams (steve@icarus.com) + * Copyright (c) 2000-2017 Stephen Williams (steve@icarus.com) * Copyright CERN 2013 / Stephen Williams (steve@icarus.com) * * This source code is free software; you can redistribute it @@ -59,7 +59,7 @@ void set_scope_timescale(Design*des, NetScope*scope, PScope*pscope) { scope->time_unit(pscope->time_unit); scope->time_precision(pscope->time_precision); - scope->time_from_timescale(pscope->time_from_timescale); + scope->time_from_timescale(pscope->has_explicit_timescale()); des->set_precision(pscope->time_precision); } @@ -167,8 +167,7 @@ static void collect_scope_specparams_(Design*des, NetScope*scope, } /* - * Elaborate the enumeration into the given scope. If scope==0, then - * the enumeration goes into $root instead of a scope. + * Elaborate the enumeration into the given scope. */ static void elaborate_scope_enumeration(Design*des, NetScope*scope, enum_type_t*enum_type) @@ -193,10 +192,7 @@ static void elaborate_scope_enumeration(Design*des, NetScope*scope, enum_type); use_enum->set_line(enum_type->li); - if (scope) - scope->add_enumeration_set(enum_type, use_enum); - else - des->add_enumeration_set(enum_type, use_enum); + scope->add_enumeration_set(enum_type, use_enum); size_t name_idx = 0; // Find the enumeration width. @@ -364,10 +360,7 @@ static void elaborate_scope_enumeration(Design*des, NetScope*scope, } rc_flag = use_enum->insert_name(name_idx, cur->name, cur_value); - if (scope) - rc_flag &= scope->add_enumeration_name(use_enum, cur->name); - else - rc_flag &= des->add_enumeration_name(use_enum, cur->name); + rc_flag &= scope->add_enumeration_name(use_enum, cur->name); if (! rc_flag) { cerr << use_enum->get_fileline() @@ -397,15 +390,6 @@ static void elaborate_scope_enumerations(Design*des, NetScope*scope, } } -void elaborate_rootscope_enumerations(Design*des) -{ - for (set::const_iterator cur = pform_enum_sets.begin() - ; cur != pform_enum_sets.end() ; ++ cur) { - enum_type_t*curp = *cur; - elaborate_scope_enumeration(des, 0, curp); - } -} - /* * If the pclass includes an implicit and explicit constructor, then * merge the implicit constructor into the explicit constructor as @@ -509,7 +493,6 @@ static void elaborate_scope_class(Design*des, NetScope*scope, PClass*pclass) netclass_t*use_base_class = 0; if (base_class) { - ivl_assert(*pclass, scope); use_base_class = scope->find_class(base_class->name); if (use_base_class == 0) { cerr << pclass->get_fileline() << ": error: " @@ -525,9 +508,10 @@ static void elaborate_scope_class(Design*des, NetScope*scope, PClass*pclass) use_type->save_elaborated_type = use_class; // Class scopes have no parent scope, because references are - // not allowed to escape a class method. + // not allowed to escape a class method. But they are allowed + // to reference the compilation unit scope. NetScope*class_scope = new NetScope(0, hname_t(pclass->pscope_name()), - NetScope::CLASS); + NetScope::CLASS, scope->unit()); class_scope->set_line(pclass); class_scope->set_class_def(use_class); use_class->set_class_scope(class_scope); @@ -586,12 +570,7 @@ static void elaborate_scope_class(Design*des, NetScope*scope, PClass*pclass) cur->second->elaborate_scope(des, method_scope); } - if (scope) { - scope->add_class(use_class); - - } else { - des->add_class(use_class, pclass); - } + scope->add_class(use_class); } static void elaborate_scope_classes(Design*des, NetScope*scope, @@ -603,18 +582,6 @@ static void elaborate_scope_classes(Design*des, NetScope*scope, } } -void elaborate_rootscope_classes(Design*des) -{ - if (pform_classes.empty()) - return; - - for (map::iterator cur = pform_classes.begin() - ; cur != pform_classes.end() ; ++ cur) { - blend_class_constructors(cur->second); - elaborate_scope_class(des, 0, cur->second); - } -} - static void replace_scope_parameters_(NetScope*scope, const LineInfo&loc, const Module::replace_t&replacements) { @@ -664,11 +631,6 @@ static void elaborate_scope_task(Design*des, NetScope*scope, PTask*task) task_scope->is_auto(task->is_auto()); task_scope->set_line(task); - if (scope==0) { - set_scope_timescale(des, task_scope, task); - des->add_root_task(task_scope, task); - } - if (debug_scopes) { cerr << task->get_fileline() << ": elaborate_scope_task: " << "Elaborate task scope " << scope_path(task_scope) << endl; @@ -731,11 +693,6 @@ static void elaborate_scope_func(Design*des, NetScope*scope, PFunction*task) task_scope->is_auto(task->is_auto()); task_scope->set_line(task); - if (scope==0) { - set_scope_timescale(des, task_scope, task); - des->add_root_task(task_scope, task); - } - if (debug_scopes) { cerr << task->get_fileline() << ": elaborate_scope_func: " << "Elaborate task scope " << scope_path(task_scope) << endl; @@ -791,28 +748,6 @@ static void elaborate_scope_funcs(Design*des, NetScope*scope, } -void elaborate_rootscope_tasks(Design*des) -{ - for (map::iterator cur = pform_tasks.begin() - ; cur != pform_tasks.end() ; ++ cur) { - - if (PTask*task = dynamic_cast (cur->second)) { - elaborate_scope_task(des, 0, task); - continue; - } - - if (PFunction*func = dynamic_cast(cur->second)) { - elaborate_scope_func(des, 0, func); - continue; - } - - cerr << cur->second->get_fileline() << ": internal error: " - << "elaborate_rootscope_tasks does not understand " - << "this object," << endl; - des->errors += 1; - } -} - class generate_schemes_work_item_t : public elaborator_work_item_t { public: generate_schemes_work_item_t(Design*des__, NetScope*scope, Module*mod) @@ -1169,7 +1104,7 @@ bool PGenerate::generate_scope_loop_(Design*des, NetScope*container) container->genvar_tmp_val = genvar; delete step; delete test_ex; - test_ex = elab_and_eval(des, container, loop_test, -1); + test_ex = elab_and_eval(des, container, loop_test, -1, true); test = dynamic_cast(test_ex); assert(test); } @@ -1728,6 +1663,10 @@ void PGModule::elaborate_scope_mod_instances_(Design*des, Module*mod, NetScope*s << "." << endl; } + struct attrib_list_t*attrib_list; + unsigned attrib_list_n = 0; + attrib_list = evaluate_attributes(attributes, attrib_list_n, des, sc); + // Run through the module instances, and make scopes out of // them. Also do parameter overrides that are done on the // instantiation line. @@ -1754,7 +1693,7 @@ void PGModule::elaborate_scope_mod_instances_(Design*des, Module*mod, NetScope*s // Create the new scope as a MODULE with my name. Note // that if this is a nested module, mark it thus so that // scope searches will continue into the parent scope. - NetScope*my_scope = new NetScope(sc, use_name, NetScope::MODULE, + NetScope*my_scope = new NetScope(sc, use_name, NetScope::MODULE, 0, bound_type_? true : false, mod->program_block, mod->is_interface); @@ -1762,6 +1701,9 @@ void PGModule::elaborate_scope_mod_instances_(Design*des, Module*mod, NetScope*s get_lineno(), mod->get_lineno()); my_scope->set_module_name(mod->mod_name()); + for (unsigned adx = 0 ; adx < attrib_list_n ; adx += 1) + my_scope->attribute(attrib_list[adx].key, attrib_list[adx].val); + instances[idx] = my_scope; set_scope_timescale(des, my_scope, mod); @@ -1820,6 +1762,7 @@ void PGModule::elaborate_scope_mod_instances_(Design*des, Module*mod, NetScope*s mod->elaborate_scope(des, my_scope, replace); } + delete[]attrib_list; /* Stash the instance array of scopes into the parent scope. Later elaboration passes will use this vector to diff --git a/elab_sig.cc b/elab_sig.cc index e92ad6667..efe1997a4 100644 --- a/elab_sig.cc +++ b/elab_sig.cc @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000-2016 Stephen Williams (steve@icarus.com) + * Copyright (c) 2000-2017 Stephen Williams (steve@icarus.com) * Copyright CERN 2012 / Stephen Williams (steve@icarus.com) * * This source code is free software; you can redistribute it @@ -1333,27 +1333,3 @@ NetNet* PWire::elaborate_sig(Design*des, NetScope*scope) const return sig; } - - -void Design::root_elaborate_sig(void) -{ - for (map::const_iterator cur = classes_.begin() - ; cur != classes_.end() ; ++ cur) { - - netclass_t*cur_class = cur->second; - PClass*cur_pclass = class_to_pclass_[cur_class]; - - cur_class->elaborate_sig(this, cur_pclass); - } - - for (map::iterator cur = root_tasks_.begin() - ; cur != root_tasks_.end() ; ++ cur) { - - if (debug_elaborate) { - cerr << cur->second->get_fileline() << ": root_elaborate_sig: " - << "Elaborate_sig for root task/func " << scope_path(cur->first) << endl; - } - - cur->second->elaborate_sig(this, cur->first); - } -} diff --git a/elab_type.cc b/elab_type.cc index 4c1814909..73d7842dc 100644 --- a/elab_type.cc +++ b/elab_type.cc @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012-2016 Stephen Williams (steve@icarus.com) + * Copyright (c) 2012-2017 Stephen Williams (steve@icarus.com) * * This source code is free software; you can redistribute it * and/or modify it in source code form under the terms of the GNU @@ -78,9 +78,8 @@ static void elaborate_array_ranges(Design*des, NetScope*scope, */ ivl_type_s* data_type_t::elaborate_type(Design*des, NetScope*scope) { + ivl_assert(*this, scope); Definitions*use_definitions = scope; - if (use_definitions == 0) - use_definitions = des; map::iterator pos = cache_type_elaborate_.lower_bound(use_definitions); if (pos != cache_type_elaborate_.end() && pos->first == use_definitions) @@ -147,13 +146,13 @@ ivl_type_s* class_type_t::elaborate_type_raw(Design*, NetScope*) const * available at the right time. At that time, the netenum_t* object is * stashed in the scope so that I can retrieve it here. */ -ivl_type_s* enum_type_t::elaborate_type_raw(Design*des, NetScope*scope) const +ivl_type_s* enum_type_t::elaborate_type_raw(Design*, NetScope*scope) const { ivl_assert(*this, scope); ivl_type_s*tmp = scope->enumeration_for_key(this); - if (tmp) return tmp; - - tmp = des->enumeration_for_key(this); + if (tmp == 0 && scope->unit()) { + tmp = scope->unit()->enumeration_for_key(this); +} return tmp; } diff --git a/elaborate.cc b/elaborate.cc index a4245e67b..588ccf11a 100644 --- a/elaborate.cc +++ b/elaborate.cc @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998-2016 Stephen Williams (steve@icarus.com) + * Copyright (c) 1998-2018 Stephen Williams (steve@icarus.com) * Copyright CERN 2013 / Stephen Williams (steve@icarus.com) * * This source code is free software; you can redistribute it @@ -2204,8 +2204,10 @@ void PGModule::elaborate(Design*des, NetScope*scope) const return; } - cerr << get_fileline() << ": internal error: Unknown module type: " << - type_ << endl; + if (!ignore_missing_modules) { + cerr << get_fileline() << ": internal error: Unknown module type: " << + type_ << endl; + } } void PGModule::elaborate_scope(Design*des, NetScope*sc) const @@ -2249,9 +2251,11 @@ void PGModule::elaborate_scope(Design*des, NetScope*sc) const // Not a module or primitive that I know about or can find by // any means, so give up. - cerr << get_fileline() << ": error: Unknown module type: " << type_ << endl; - missing_modules[type_] += 1; - des->errors += 1; + if (!ignore_missing_modules) { + cerr << get_fileline() << ": error: Unknown module type: " << type_ << endl; + missing_modules[type_] += 1; + des->errors += 1; + } } @@ -2351,19 +2355,7 @@ static NetExpr*elaborate_delay_expr(PExpr*expr, Design*des, NetScope*scope) { NetExpr*dex = elab_and_eval(des, scope, expr, -1); - /* Print a warning if we find default and `timescale based - * delays in the design, since this is likely an error. */ - if (scope->time_from_timescale()) dly_used_timescale = true; - else dly_used_no_timescale = true; - - if (display_ts_dly_warning && - dly_used_no_timescale && dly_used_timescale) { - cerr << "warning: Found both default and " - "`timescale based delays. Use" << endl; - cerr << " -Wtimescale to find the " - "module(s) with no `timescale." << endl; - display_ts_dly_warning = false; - } + check_for_inconsistent_delays(scope); /* If the delay expression is a real constant or vector constant, then evaluate it, scale it to the local time @@ -2914,11 +2906,12 @@ NetProc* PBlock::elaborate(Design*des, NetScope*scope) const if (nscope == 0) nscope = scope; - // Handle the special case that the block contains only one - // statement. There is no need to keep the block node. Also, - // don't elide named blocks, because they might be referenced - // elsewhere. - if ((list_.size() == 1) && (pscope_name() == 0)) { + // Handle the special case that the sequential block contains + // only one statement. There is no need to keep the block node. + // Also, don't elide named blocks, because they might be + // referenced elsewhere. + if ((type == NetBlock::SEQU) && (list_.size() == 1) && + (pscope_name() == 0)) { assert(list_[0]); NetProc*tmp = list_[0]->elaborate(des, nscope); return tmp; @@ -4198,6 +4191,7 @@ NetProc* PEventStatement::elaborate_st(Design*des, NetScope*scope, NetEvent*ev = new NetEvent(scope->local_symbol()); ev->set_line(*this); + ev->local_flag(true); unsigned expr_count = 0; NetEvWait*wa = new NetEvWait(enet); @@ -4208,14 +4202,18 @@ NetProc* PEventStatement::elaborate_st(Design*des, NetScope*scope, if (expr_.count() == 0) { assert(enet); - /* For synthesis we want just the inputs, but for the rest we - * want inputs and outputs that may cause a value to change. */ + /* For synthesis or always_comb/latch we want just the inputs, + * but for the rest we want inputs and outputs that may cause + * a value to change. */ extern bool synthesis; /* Synthesis flag from main.cc */ bool rem_out = false; - if (synthesis) { + if (synthesis || search_funcs_) { rem_out = true; } - NexusSet*nset = enet->nex_input(rem_out); + // If this is an always_comb/latch then we need an implicit T0 + // trigger of the event expression. + if (search_funcs_) wa->set_t0_trigger(); + NexusSet*nset = enet->nex_input(rem_out, search_funcs_); if (nset == 0) { cerr << get_fileline() << ": error: Unable to elaborate:" << endl; @@ -4474,6 +4472,8 @@ NetProc* PEventStatement::elaborate_wait(Design*des, NetScope*scope, /* Create an event wait and an otherwise unreferenced event variable to force a perpetual wait. */ NetEvent*wait_event = new NetEvent(scope->local_symbol()); + wait_event->set_line(*this); + wait_event->local_flag(true); scope->add_event(wait_event); NetEvWait*wait = new NetEvWait(0); @@ -4494,6 +4494,8 @@ NetProc* PEventStatement::elaborate_wait(Design*des, NetScope*scope, eval_expr(expr); NetEvent*wait_event = new NetEvent(scope->local_symbol()); + wait_event->set_line(*this); + wait_event->local_flag(true); scope->add_event(wait_event); NetEvWait*wait = new NetEvWait(0 /* noop */); @@ -5364,7 +5366,10 @@ bool PProcess::elaborate(Design*des, NetScope*scope) const gets into its wait statement before non-combinational code is executed. */ do { - if (top->type() != IVL_PR_ALWAYS) + if ((top->type() != IVL_PR_ALWAYS) && + (top->type() != IVL_PR_ALWAYS_COMB) && + (top->type() != IVL_PR_ALWAYS_FF) && + (top->type() != IVL_PR_ALWAYS_LATCH)) break; NetEvWait*st = dynamic_cast(top->statement()); @@ -5411,19 +5416,7 @@ void PSpecPath::elaborate(Design*des, NetScope*scope) const ndelays = delays.size(); if (ndelays > 12) ndelays = 12; - /* Print a warning if we find default and `timescale based - * delays in the design, since this is likely an error. */ - if (scope->time_from_timescale()) dly_used_timescale = true; - else dly_used_no_timescale = true; - - if (display_ts_dly_warning && - dly_used_no_timescale && dly_used_timescale) { - cerr << "warning: Found both default and " - "`timescale based delays. Use" << endl; - cerr << " -Wtimescale to find the " - "module(s) with no `timescale." << endl; - display_ts_dly_warning = false; - } + check_for_inconsistent_delays(scope); /* Elaborate the delay values themselves. Remember to scale them for the timescale/precision of the scope. */ @@ -5691,6 +5684,10 @@ bool PPackage::elaborate(Design*des, NetScope*scope) const // Elaborate class definitions. elaborate_classes(des, scope, classes); + // Elaborate the variable initialization statements, making a + // single initial process out of them. + result_flag &= elaborate_var_inits_(des, scope); + return result_flag; } @@ -6123,14 +6120,17 @@ class later_defparams : public elaborator_work_item_t { bool Design::check_proc_delay() const { - bool result_flag = true; + bool result = false; for (const NetProcTop*pr = procs_ ; pr ; pr = pr->next_) { - /* If this is an always block and we have no or zero delay then - * a runtime infinite loop will happen. If we possible have some + /* If this is an always process and we have no or zero delay then + * a runtime infinite loop will happen. If we possibly have some * delay then print a warning that an infinite loop is possible. */ - if (pr->type() == IVL_PR_ALWAYS) { + if ((pr->type() == IVL_PR_ALWAYS) || + (pr->type() == IVL_PR_ALWAYS_COMB) || + (pr->type() == IVL_PR_ALWAYS_FF) || + (pr->type() == IVL_PR_ALWAYS_LATCH)) { DelayType dly_type = pr->statement()->delay_type(); if (dly_type == NO_DELAY || dly_type == ZERO_DELAY) { @@ -6138,7 +6138,7 @@ bool Design::check_proc_delay() const << " statement does not have any delay." << endl; cerr << pr->get_fileline() << ": : A runtime" << " infinite loop will occur." << endl; - result_flag = false; + result = true; } else if (dly_type == POSSIBLE_DELAY && warn_inf_loop) { cerr << pr->get_fileline() << ": warning: always" @@ -6146,6 +6146,38 @@ bool Design::check_proc_delay() const cerr << pr->get_fileline() << ": : A runtime" << " infinite loop may be possible." << endl; } + + // The always_comb/ff/latch processes also have special + // delay rules that need to be checked. + if ((pr->type() == IVL_PR_ALWAYS_COMB) || + (pr->type() == IVL_PR_ALWAYS_FF) || + (pr->type() == IVL_PR_ALWAYS_LATCH)) { + const NetEvWait *wait = dynamic_cast (pr->statement()); + if (! wait) { + // The always_comb/latch processes have an event + // control added automatically by the compiler. + assert(pr->type() == IVL_PR_ALWAYS_FF); + cerr << pr->get_fileline() << ": error: the " + << "first statement of an always_ff must " + << "be an event control." << endl; + result = true; + } else if (wait->statement()->delay_type(true) != NO_DELAY) { + cerr << pr->get_fileline() << ": error: there " + << "must "; + + if (pr->type() == IVL_PR_ALWAYS_FF) { + cerr << "only be a single event control " + << "and no blocking delays in an " + << "always_ff process."; + } else { + cerr << "be no event controls or blocking " + << "delays in an always_comb/latch " + << "process."; + } + cerr << endl; + result = true; + } + } } /* If this is a final block it must not have a delay, @@ -6155,37 +6187,287 @@ bool Design::check_proc_delay() const if (pr->type() == IVL_PR_FINAL) { DelayType dly_type = pr->statement()->delay_type(); - if (dly_type != NO_DELAY && dly_type != ZERO_DELAY) { + if (dly_type != NO_DELAY) { cerr << pr->get_fileline() << ": error: final" << " statement contains a delay." << endl; - result_flag = false; + result = true; } } } - return result_flag; + return result; } -void Design::root_elaborate(void) +static void print_nexus_name(const Nexus*nex) { - for (map::const_iterator cur = classes_.begin() - ; cur != classes_.end() ; ++ cur) { - netclass_t*cur_class = cur->second; - PClass*cur_pclass = class_to_pclass_[cur_class]; - cur_class->elaborate(this, cur_pclass); - } - - for (map::iterator cur = root_tasks_.begin() - ; cur != root_tasks_.end() ; ++ cur) { - - if (debug_elaborate) { - cerr << cur->second->get_fileline() << ": Design::root_elaborate: " - << "Elaborate for root task/func " << scope_path(cur->first) << endl; + for (const Link*cur = nex->first_nlink(); cur; cur = cur->next_nlink()) { + if (cur->get_dir() != Link::OUTPUT) continue; + const NetPins*obj = cur->get_obj(); + // For a NetNet (signal) just use the name. + if (const NetNet*net = dynamic_cast(obj)) { + cerr << net->name(); + return; + // For a NetPartSelect calculate the name. + } else if (const NetPartSelect*ps = dynamic_cast(obj)) { + assert(ps->pin_count() >= 2); + assert(ps->pin(1).get_dir() == Link::INPUT); + assert(ps->pin(1).is_linked()); + print_nexus_name(ps->pin(1).nexus()); + cerr << "[]"; + return; + // For a NetUReduce calculate the name. + } else if (const NetUReduce*reduce = dynamic_cast(obj)) { + assert(reduce->pin_count() == 2); + assert(reduce->pin(1).get_dir() == Link::INPUT); + assert(reduce->pin(1).is_linked()); + switch (reduce->type()) { + case NetUReduce::AND: + cerr << "&"; + break; + case NetUReduce::OR: + cerr << "|"; + break; + case NetUReduce::XOR: + cerr << "^"; + break; + case NetUReduce::NAND: + cerr << "~&"; + break; + case NetUReduce::NOR: + cerr << "~|"; + break; + case NetUReduce::XNOR: + cerr << "~^"; + break; + case NetUReduce::NONE: + assert(0); + } + print_nexus_name(reduce->pin(1).nexus()); + return; + } else if (const NetLogic*logic = dynamic_cast(obj)) { + assert(logic->pin_count() >= 2); + assert(logic->pin(1).get_dir() == Link::INPUT); + assert(logic->pin(1).is_linked()); + switch (logic->type()) { + case NetLogic::NOT: + cerr << "~"; + break; + default: + // The other operators should never be used here, + // so just return the nexus name. + cerr << nex->name(); + return; + } + print_nexus_name(logic->pin(1).nexus()); + return; } + // Use the following to find the type of anything that may be missing: + // cerr << "(" << typeid(*obj).name() << ") "; + } + // Otherwise just use the nexus name so somthing is printed. + cerr << nex->name(); +} - cur->second->elaborate(this, cur->first); +static void print_event_probe_name(const NetEvProbe *prb) +{ + assert(prb->pin_count() == 1); + assert(prb->pin(0).get_dir() == Link::INPUT); + assert(prb->pin(0).is_linked()); + print_nexus_name(prb->pin(0).nexus()); +} + +static void check_event_probe_width(const LineInfo *info, const NetEvProbe *prb) +{ + assert(prb->pin_count() == 1); + assert(prb->pin(0).get_dir() == Link::INPUT); + assert(prb->pin(0).is_linked()); + if (prb->edge() == NetEvProbe::ANYEDGE) return; + if (prb->pin(0).nexus()->vector_width() > 1) { + cerr << info->get_fileline() << " Warning: Synthesis wants " + "the sensitivity list expressions for '"; + switch (prb->edge()) { + case NetEvProbe::POSEDGE: + cerr << "posedge "; + break; + case NetEvProbe::NEGEDGE: + cerr << "negedge "; + break; + default: + break; + } + print_nexus_name(prb->pin(0).nexus()); + cerr << "' to be a single bit." << endl; + } +} + +static void check_ff_sensitivity(const NetProc* statement) +{ + const NetEvWait *evwt = dynamic_cast (statement); + // We have already checked for and reported if the first statmemnt is + // not a wait. + if (! evwt) return; + + for (unsigned cevt = 0; cevt < evwt->nevents(); cevt += 1) { + const NetEvent *evt = evwt->event(cevt); + for (unsigned cprb = 0; cprb < evt->nprobe(); cprb += 1) { + const NetEvProbe *prb = evt->probe(cprb); + check_event_probe_width(evwt, prb); + if (prb->edge() == NetEvProbe::ANYEDGE) { + cerr << evwt->get_fileline() << " Warning: Synthesis " + "requires the sensitivity list of an " + "always_ff process to only be edge " + "sensitive. "; + print_event_probe_name(prb); + cerr << " is missing a pos/negedge." << endl; + } + } + } +} + +/* + * Check to see if the always_* processes only contain synthesizable + * constructs. + */ +bool Design::check_proc_synth() const +{ + bool result = false; + for (const NetProcTop*pr = procs_ ; pr ; pr = pr->next_) { + if ((pr->type() == IVL_PR_ALWAYS_COMB) || + (pr->type() == IVL_PR_ALWAYS_FF) || + (pr->type() == IVL_PR_ALWAYS_LATCH)) { + result |= pr->statement()->check_synth(pr->type(), + pr->scope()); + if (pr->type() == IVL_PR_ALWAYS_FF) { + check_ff_sensitivity(pr->statement()); + } + } + } + return result; +} + +/* + * Check whether all design elements have an explicit timescale or all + * design elements use the default timescale. If a mixture of explicit + * and default timescales is found, a warning message is output. Note + * that we only need to check the top level design elements - nested + * design elements will always inherit the timescale from their parent + * if they don't have any local timescale declarations. + * + * NOTE: Strictly speaking, this should be an error for SystemVerilog + * (1800-2012 section 3.14.2). + */ +static void check_timescales(bool&some_explicit, bool&some_implicit, + const PScope*scope) +{ + if (scope->time_unit_is_default) + some_implicit = true; + else + some_explicit = true; + if (scope->time_prec_is_default) + some_implicit = true; + else + some_explicit = true; +} + +static void check_timescales() +{ + bool some_explicit = false; + bool some_implicit = false; + map::iterator mod; + for (mod = pform_modules.begin(); mod != pform_modules.end(); ++mod) { + const Module*mp = (*mod).second; + check_timescales(some_explicit, some_implicit, mp); + if (some_explicit && some_implicit) + break; + } + map::iterator pkg; + if (gn_system_verilog() && !(some_explicit && some_implicit)) { + for (pkg = pform_packages.begin(); pkg != pform_packages.end(); ++pkg) { + const PPackage*pp = (*pkg).second; + check_timescales(some_explicit, some_implicit, pp); + if (some_explicit && some_implicit) + break; + } + } + if (gn_system_verilog() && !(some_explicit && some_implicit)) { + for (unsigned idx = 0; idx < pform_units.size(); idx += 1) { + const PPackage*pp = pform_units[idx]; + // We don't need a timescale if the compilation unit + // contains no items outside a design element. + if (pp->parameters.empty() && + pp->localparams.empty() && + pp->wires.empty() && + pp->tasks.empty() && + pp->funcs.empty() && + pp->classes.empty()) + continue; + + check_timescales(some_explicit, some_implicit, pp); + if (some_explicit && some_implicit) + break; + } } + if (!(some_explicit && some_implicit)) + return; + + if (gn_system_verilog()) { + cerr << "warning: " + << "Some design elements have no explicit time unit and/or" + << endl; + cerr << " : " + << "time precision. This may cause confusing timing results." + << endl; + cerr << " : " + << "Affected design elements are:" + << endl; + } else { + cerr << "warning: " + << "Some modules have no timescale. This may cause" + << endl; + cerr << " : " + << "confusing timing results. Affected modules are:" + << endl; + } + + for (mod = pform_modules.begin(); mod != pform_modules.end(); ++mod) { + Module*mp = (*mod).second; + if (mp->has_explicit_timescale()) + continue; + cerr << " : -- module " << (*mod).first + << " declared here: " << mp->get_fileline() << endl; + } + + if (!gn_system_verilog()) + return; + + for (pkg = pform_packages.begin(); pkg != pform_packages.end(); ++pkg) { + PPackage*pp = (*pkg).second; + if (pp->has_explicit_timescale()) + continue; + cerr << " : -- package " << (*pkg).first + << " declared here: " << pp->get_fileline() << endl; + } + + for (unsigned idx = 0; idx < pform_units.size(); idx += 1) { + PPackage*pp = pform_units[idx]; + if (pp->has_explicit_timescale()) + continue; + + if (pp->parameters.empty() && + pp->localparams.empty() && + pp->wires.empty() && + pp->tasks.empty() && + pp->funcs.empty() && + pp->classes.empty()) + continue; + + cerr << " : -- compilation unit"; + if (pform_units.size() > 1) { + cerr << " from: " << pp->get_file(); + } + cerr << endl; + } } /* @@ -6207,8 +6489,13 @@ struct root_elem { Design* elaborate(listroots) { + unsigned npackages = pform_packages.size(); + if (gn_system_verilog()) + npackages += pform_units.size(); + vector root_elems(roots.size()); - vector pack_elems(pform_packages.size()); + vector pack_elems(npackages); + map unit_scopes; bool rc = true; unsigned i = 0; @@ -6216,23 +6503,36 @@ Design* elaborate(listroots) // module and elaborate what I find. Design*des = new Design; - // Elaborate enum sets in $root scope. - elaborate_rootscope_enumerations(des); + // Elaborate the compilation unit scopes. From here on, these are + // treated as an additional set of packages. + if (gn_system_verilog()) { + for (i = 0; i < pform_units.size(); i += 1) { + PPackage*unit = pform_units[i]; + NetScope*scope = des->make_package_scope(unit->pscope_name(), 0, true); + scope->set_line(unit); + set_scope_timescale(des, scope, unit); - // Elaborate tasks and functions in $root scope. - elaborate_rootscope_tasks(des); + elaborator_work_item_t*es = new elaborate_package_t(des, scope, unit); + des->elaboration_work_list.push_back(es); - // Elaborate classes in $root scope. - elaborate_rootscope_classes(des); + pack_elems[i].pack = unit; + pack_elems[i].scope = scope; + + unit_scopes[unit] = scope; + } + } // Elaborate the packages. Package elaboration is simpler - // because there are fewer sub-scopes involved. - i = 0; + // because there are fewer sub-scopes involved. Note that + // in SystemVerilog, packages are not allowed to refer to + // the compilation unit scope, but the VHDL preprocessor + // assumes they can. for (map::iterator pac = pform_packages.begin() ; pac != pform_packages.end() ; ++ pac) { ivl_assert(*pac->second, pac->first == pac->second->pscope_name()); - NetScope*scope = des->make_package_scope(pac->first); + NetScope*unit_scope = unit_scopes[pac->second->parent_scope()]; + NetScope*scope = des->make_package_scope(pac->first, unit_scope, false); scope->set_line(pac->second); set_scope_timescale(des, scope, pac->second); @@ -6263,9 +6563,13 @@ Design* elaborate(listroots) // Get the module definition for this root instance. Module *rmod = (*mod).second; + // Get the compilation unit scope for this module. + NetScope*unit_scope = unit_scopes[rmod->parent_scope()]; + // Make the root scope. This makes a NetScope object and // pushes it into the list of root scopes in the Design. - NetScope*scope = des->make_root_scope(*root, rmod->program_block, + NetScope*scope = des->make_root_scope(*root, unit_scope, + rmod->program_block, rmod->is_interface); // Collect some basic properties of this scope from the @@ -6335,6 +6639,10 @@ Design* elaborate(listroots) if (des->errors > 0) return des; + // Now we have the full design, check for timescale inconsistencies. + if (warn_timescale) + check_timescales(); + if (debug_elaborate) { cerr << ": elaborate: " << "Start calling Package elaborate_sig methods." << endl; @@ -6363,8 +6671,6 @@ Design* elaborate(listroots) << "Start calling $root elaborate_sig methods." << endl; } - des->root_elaborate_sig(); - if (debug_elaborate) { cerr << ": elaborate: " << "Start calling root module elaborate_sig methods." << endl; @@ -6426,8 +6732,6 @@ Design* elaborate(listroots) rc &= pkg->elaborate(des, scope); } - des->root_elaborate(); - for (i = 0; i < root_elems.size(); i++) { Module *rmod = root_elems[i].mod; NetScope *scope = root_elems[i].scope; @@ -6442,10 +6746,11 @@ Design* elaborate(listroots) // Now that everything is fully elaborated verify that we do // not have an always block with no delay (an infinite loop), // or a final block with a delay. - if (des->check_proc_delay() == false) { - delete des; - des = 0; - } + bool has_failure = des->check_proc_delay(); + + // Check to see if the always_comb/ff/latch processes only have + // synthesizable constructs + has_failure |= des->check_proc_synth(); if (debug_elaborate) { cerr << "" << ": debug: " @@ -6453,5 +6758,10 @@ Design* elaborate(listroots) << des->find_root_scopes().size() << " root scopes " << endl; } + if (has_failure) { + delete des; + des = 0; + } + return des; } diff --git a/emit.cc b/emit.cc index eaa183454..c5c64c9d3 100644 --- a/emit.cc +++ b/emit.cc @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998-2016 Stephen Williams (steve@icarus.com) + * Copyright (c) 1998-2017 Stephen Williams (steve@icarus.com) * * This source code is free software; you can redistribute it * and/or modify it in source code form under the terms of the GNU @@ -510,24 +510,12 @@ int Design::emit(struct target_t*tgt) const if (tgt->start_design(this) == false) return -2; - for (map::const_iterator scope = root_tasks_.begin() - ; scope != root_tasks_.end() ; ++ scope) { - scope->first->emit_scope(tgt); - } - // enumerate package scopes for (map::const_iterator scope = packages_.begin() ; scope != packages_.end() ; ++ scope) { scope->second->emit_scope(tgt); } - for (map::const_iterator cur = classes_.begin() - ; cur != classes_.end() ; ++cur) { - const NetScope*use_scope = cur->second->class_scope(); - cur->second->emit_scope(tgt); - tgt->class_type(use_scope, cur->second); - } - // enumerate root scopes for (list::const_iterator scope = root_scopes_.begin() ; scope != root_scopes_.end(); ++ scope ) { @@ -552,12 +540,6 @@ int Design::emit(struct target_t*tgt) const // emit task and function definitions bool tasks_rc = true; - for (map::const_iterator scope = root_tasks_.begin() - ; scope != root_tasks_.end() ; ++ scope) - tasks_rc &= scope->first->emit_defs(tgt); - for (map::const_iterator cur = classes_.begin() - ; cur != classes_.end() ; ++cur) - tasks_rc &= cur->second->emit_defs(tgt); for (map::const_iterator scope = packages_.begin() ; scope != packages_.end() ; ++ scope ) tasks_rc &= scope->second->emit_defs(tgt); diff --git a/eval_tree.cc b/eval_tree.cc index 1c709f5f2..372a382cc 100644 --- a/eval_tree.cc +++ b/eval_tree.cc @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999-2016 Stephen Williams (steve@icarus.com) + * Copyright (c) 1999-2018 Stephen Williams (steve@icarus.com) * * This source code is free software; you can redistribute it * and/or modify it in source code form under the terms of the GNU @@ -570,11 +570,11 @@ NetEConst* NetEBComp::eval_eqeq_(bool ne_flag, const NetExpr*le, const NetExpr*r const verinum::V ne_res = ne_flag? verinum::V1 : verinum::V0; verinum::V res = eq_res; - unsigned top = lv.len(); - if (rv.len() < top) - top = rv.len(); - for (unsigned idx = 0 ; idx < top ; idx += 1) { + // The two expressions should already be padded to the same size. + ivl_assert(*this, lv.len() == rv.len()); + + for (unsigned idx = 0 ; idx < lv.len() ; idx += 1) { bool x_bit_present = false; @@ -611,60 +611,6 @@ NetEConst* NetEBComp::eval_eqeq_(bool ne_flag, const NetExpr*le, const NetExpr*r } } - if (res != verinum::Vx) { - verinum::V lpad = verinum::V0; - verinum::V rpad = verinum::V0; - - if (lv.has_sign() && lv.get(lv.len()-1) == verinum::V1) - lpad = verinum::V1; - if (rv.has_sign() && rv.get(rv.len()-1) == verinum::V1) - rpad = verinum::V1; - - for (unsigned idx = top ; idx < lv.len() ; idx += 1) - switch (lv.get(idx)) { - - case verinum::Vx: - case verinum::Vz: - res = verinum::Vx; - break; - - case verinum::V0: - if (res != verinum::Vx && rpad != verinum::V0) - res = ne_res; - break; - - case verinum::V1: - if (res != verinum::Vx && rpad != verinum::V1) - res = ne_res; - break; - - default: - break; - } - - for (unsigned idx = top ; idx < rv.len() ; idx += 1) - switch (rv.get(idx)) { - - case verinum::Vx: - case verinum::Vz: - res = verinum::Vx; - break; - - case verinum::V0: - if (res != verinum::Vx && lpad != verinum::V0) - res = ne_res; - break; - - case verinum::V1: - if (res != verinum::Vx && lpad != verinum::V1) - res = ne_res; - break; - - default: - break; - } - } - NetEConst*result = new NetEConst(verinum(res, 1)); ivl_assert(*this, result); return result; @@ -681,46 +627,15 @@ NetEConst* NetEBComp::eval_eqeqeq_(bool ne_flag, const NetExpr*le, const NetExpr verinum::V res = verinum::V1; - // Find the smallest argument length. - unsigned cnt = lv.len(); - if (cnt > rv.len()) cnt = rv.len(); + // The two expressions should already be padded to the same size. + ivl_assert(*this, lv.len() == rv.len()); - // Check the common bits. - for (unsigned idx = 0 ; idx < cnt ; idx += 1) + for (unsigned idx = 0 ; idx < lv.len() ; idx += 1) if (lv.get(idx) != rv.get(idx)) { res = verinum::V0; break; } - bool is_signed = lv.has_sign() && rv.has_sign(); - - // If the left value is longer check it against the pad bit. - if (res == verinum::V1) { - verinum::V pad = verinum::V0; - if (is_signed) - pad = rv.get(rv.len()-1); - - for (unsigned idx = cnt ; idx < lv.len() ; idx += 1) - if (lv.get(idx) != pad) { - res = verinum::V0; - break; - } - } - - // If the right value is longer check it against the pad bit. - if (res == verinum::V1) { - verinum::V pad = verinum::V0; - if (is_signed) - pad = lv.get(lv.len()-1); - - for (unsigned idx = cnt ; idx < rv.len() ; idx += 1) { - if (rv.get(idx) != pad) { - res = verinum::V0; - break; - } - } - } - if (ne_flag) { if (res == verinum::V0) res = verinum::V1; else res = verinum::V0; @@ -731,6 +646,55 @@ NetEConst* NetEBComp::eval_eqeqeq_(bool ne_flag, const NetExpr*le, const NetExpr return result; } +NetEConst* NetEBComp::eval_weqeq_(bool ne_flag, const NetExpr*le, const NetExpr*re) const +{ + const NetEConst*lc = dynamic_cast(le); + const NetEConst*rc = dynamic_cast(re); + if (lc == 0 || rc == 0) return 0; + + const verinum&lv = lc->value(); + const verinum&rv = rc->value(); + + const verinum::V eq_res = ne_flag ? verinum::V0 : verinum::V1; + const verinum::V ne_res = ne_flag ? verinum::V1 : verinum::V0; + + verinum::V res = eq_res; + + // The two expressions should already be padded to the same size. + ivl_assert(*this, lv.len() == rv.len()); + + for (unsigned idx = 0 ; idx < lv.len() ; idx += 1) { + // An X or Z in the R-value matches any L-value. + switch (rv.get(idx)) { + case verinum::Vx: + case verinum::Vz: + continue; + default: + break; + } + + // An X or Z in the L-value that is not matches by an R-value X/Z returns undefined. + switch (lv.get(idx)) { + case verinum::Vx: + case verinum::Vz: + res = verinum::Vx; + continue; + default: + break; + } + + // A hard (0/1) mismatch gives a not-equal result. + if (rv.get(idx) != lv.get(idx)) { + res = ne_res; + break; + } + } + + NetEConst*result = new NetEConst(verinum(res, 1)); + ivl_assert(*this, result); + return result; +} + NetEConst* NetEBComp::eval_arguments_(const NetExpr*l, const NetExpr*r) const { NetEConst*res = 0; @@ -744,6 +708,10 @@ NetEConst* NetEBComp::eval_arguments_(const NetExpr*l, const NetExpr*r) const res = eval_eqeq_(false, l, r); break; + case 'w': // Wild equality (==?) + res = eval_weqeq_(false, l, r); + break; + case 'G': // >= res = eval_gteq_(l, r); break; @@ -760,6 +728,10 @@ NetEConst* NetEBComp::eval_arguments_(const NetExpr*l, const NetExpr*r) const res = eval_eqeq_(true, l, r); break; + case 'W': // Wild not-equal (!=?) + res = eval_weqeq_(true, l, r); + break; + case '<': // Less than res = eval_less_(l, r); break; @@ -1102,6 +1074,7 @@ NetEConst* NetEBShift::eval_arguments_(const NetExpr*l, const NetExpr*r) const break; case 'r': lv.has_sign(false); + // fallthrough case 'R': val = cast_to_width(lv >> shift, wid); break; @@ -1553,6 +1526,7 @@ NetEConst* NetEUReduce::eval_arguments_(const NetExpr*ex) const case 'A': invert = true; + // fallthrough case '&': { res = verinum::V1; for (unsigned idx = 0 ; idx < val.len() ; idx += 1) @@ -1562,6 +1536,7 @@ NetEConst* NetEUReduce::eval_arguments_(const NetExpr*ex) const case 'N': invert = true; + // fallthrough case '|': { res = verinum::V0; for (unsigned idx = 0 ; idx < val.len() ; idx += 1) @@ -1571,6 +1546,7 @@ NetEConst* NetEUReduce::eval_arguments_(const NetExpr*ex) const case 'X': invert = true; + // fallthrough case '^': { /* Reduction XOR. */ unsigned ones = 0, unknown = 0; @@ -1622,6 +1598,7 @@ NetExpr* NetECast::eval_arguments_(const NetExpr*ex) const res_val = cast_to_width(res_val, expr_width()); res = new NetEConst(res_val); } + // fallthrough case 'v': if (const NetECReal*val = dynamic_cast(ex)) { verinum res_val(val->value().as_double(), false); @@ -1936,15 +1913,111 @@ NetExpr* NetESFunc::evaluate_min_max_(ID id, const NetExpr*arg0_, return res; } -NetEConst* NetESFunc::evaluate_countbits_(const NetExpr* /*arg0*/, - const NetExpr* /*arg1*/) const +static void no_string_arg(const NetESFunc*info, unsigned arg_num) { - return 0; + cerr << info->get_fileline() << ": error: constant function " + << info->name() << "() does not support a string argument (" + << arg_num+1 << ")." << endl; } -NetEConst* NetESFunc::evaluate_countones_(const NetExpr* /*arg*/) const +NetEConst* NetESFunc::evaluate_countbits_() const { - return 0; + const NetEConst*tmpi = dynamic_cast(parms_[0]); + + NetEConst*res = 0; + + if (tmpi) { + verinum value = tmpi->value(); + + if (value.is_string()) { + no_string_arg(this, 0); + return 0; + } + + /* Find which values need to be counted. */ + bool count_0 = false; + bool count_1 = false; + bool count_z = false; + bool count_x = false; + for (unsigned arg=1; arg < parms_.size(); ++arg) { + const NetEConst*argi = dynamic_cast(parms_[arg]); + if (! argi) return 0; + verinum check_for = argi->value(); + if (check_for.is_string()) { + no_string_arg(this, arg); + return 0; + } + switch (check_for[0]) { + case verinum::V0: + count_0 = true; + break; + case verinum::V1: + count_1 = true; + break; + case verinum::Vz: + count_z = true; + break; + case verinum::Vx: + count_x = true; + break; + } + } + + /* Search each bit of the vector looking for the values to + * be counted. */ + int count = 0; + for (unsigned bit=0; bit < value.len(); ++bit) { + switch (value[bit]) { + case verinum::V0: + if (count_0) ++count; + break; + case verinum::V1: + if (count_1) ++count; + break; + case verinum::Vz: + if (count_z) ++count; + break; + case verinum::Vx: + if (count_x) ++count; + break; + } + } + + verinum tmp (count, integer_width); + tmp.has_sign(true); + res = new NetEConst(tmp); + ivl_assert(*this, res); + } + + return res; +} + +NetEConst* NetESFunc::evaluate_countones_(const NetExpr* arg) const +{ + const NetEConst*tmpi = dynamic_cast(arg); + + NetEConst*res = 0; + + if (tmpi) { + verinum value = tmpi->value(); + int count = 0; + + if (value.is_string()) { + no_string_arg(this, 0); + return 0; + } + + for (unsigned bit=0; bit < value.len(); ++bit) { + if (value[bit] == verinum::V1) ++count; + } + + verinum tmp (count, integer_width); + tmp.has_sign(true); + res = new NetEConst(tmp); + ivl_assert(*this, res); + } + + return res; } /* Get the total number of dimensions for the given expression. */ @@ -1967,19 +2040,92 @@ NetEConst* NetESFunc::evaluate_dimensions_(const NetExpr*arg) const return new NetEConst(verinum(verinum(res), integer_width)); } -NetEConst* NetESFunc::evaluate_isunknown_(const NetExpr* /*arg*/) const +NetEConst* NetESFunc::evaluate_isunknown_(const NetExpr* arg) const { - return 0; + const NetEConst*tmpi = dynamic_cast(arg); + + NetEConst*res = 0; + + if (tmpi) { + verinum value = tmpi->value(); + unsigned is_unknown = 1; + + if (value.is_string()) { + no_string_arg(this, 0); + return 0; + } + + if (value.is_defined()) is_unknown = 0; + + verinum tmp (is_unknown, 1U); + tmp.has_sign(false); + res = new NetEConst(tmp); + ivl_assert(*this, res); + } + + return res; } -NetEConst* NetESFunc::evaluate_onehot_(const NetExpr* /*arg*/) const +static bool is_onehot(verinum&value, bool zero_is_okay) { - return 0; + bool found_a_one = false; + + for (unsigned bit=0; bit < value.len(); ++bit) { + if (value[bit] == verinum::V1) { + if (found_a_one) return false; + found_a_one = true; + } + } + + /* If no one bit was found return true if zero is okay. */ + if (zero_is_okay) found_a_one = true; + return found_a_one; } -NetEConst* NetESFunc::evaluate_onehot0_(const NetExpr* /*arg*/) const +NetEConst* NetESFunc::evaluate_onehot_(const NetExpr* arg) const { - return 0; + const NetEConst*tmpi = dynamic_cast(arg); + + NetEConst*res = 0; + + if (tmpi) { + verinum value = tmpi->value(); + + if (value.is_string()) { + no_string_arg(this, 0); + return 0; + } + + verinum tmp (is_onehot(value, false), 1U); + tmp.has_sign(false); + res = new NetEConst(tmp); + ivl_assert(*this, res); + } + + return res; +} + +NetEConst* NetESFunc::evaluate_onehot0_(const NetExpr* arg) const +{ + const NetEConst*tmpi = dynamic_cast(arg); + + NetEConst*res = 0; + + if (tmpi) { + verinum value = tmpi->value(); + + if (value.is_string()) { + no_string_arg(this, 0); + return 0; + } + + verinum tmp (is_onehot(value, true), 1U); + tmp.has_sign(false); + res = new NetEConst(tmp); + ivl_assert(*this, res); + } + + return res; } /* Get the number of unpacked dimensions for the given expression. */ @@ -2151,7 +2297,7 @@ NetExpr* NetESFunc::evaluate_two_arg_(ID id, const NetExpr*arg0, { switch (id) { case CTBITS: - return evaluate_countbits_(arg0, arg1); + return evaluate_countbits_(); /* The array functions are handled together. */ case HIGH: case INCR: @@ -2222,12 +2368,12 @@ NetESFunc::ID NetESFunc::built_in_id_() const built_in_func["$unpacked_dimensions" ] = UPDIMS; } - /* These are available in 1800-2009 and later. */ + /* This is available in 1800-2009 and later. */ if (funcs_need_init && (generation_flag >= GN_VER2009)) { built_in_func["$countones" ] = CTONES; } - /* These are available in 1800-2012 and later. */ + /* This is available in 1800-2012 and later. */ if (funcs_need_init && (generation_flag >= GN_VER2012)) { built_in_func["$countbits" ] = CTBITS; } @@ -2254,7 +2400,7 @@ NetESFunc::ID NetESFunc::built_in_id_() const NetExpr* NetESFunc::eval_tree() { - /* Get the ID for this system function if it is can be used as a + /* Get the ID for this system function if it can be used as a * constant function. */ ID id = built_in_id_(); if (id == NOT_BUILT_IN) return 0; @@ -2262,8 +2408,9 @@ NetExpr* NetESFunc::eval_tree() switch (parms_.size()) { case 1: if (! takes_nargs_(id, 1)) { - cerr << get_fileline() << ": error: " << name_ - << "() does not support a single argument." << endl; + cerr << get_fileline() << ": error: constant function " + << name_ << "() does not support a single argument." + << endl; return 0; } eval_expr(parms_[0]); @@ -2271,8 +2418,9 @@ NetExpr* NetESFunc::eval_tree() case 2: if (! takes_nargs_(id, 2)) { - cerr << get_fileline() << ": error: " << name_ - << "() does not support two arguments." << endl; + cerr << get_fileline() << ": error: constant function " + << name_ << "() does not support two arguments." + << endl; return 0; } eval_expr(parms_[0]); @@ -2282,15 +2430,21 @@ NetExpr* NetESFunc::eval_tree() default: /* Check to see if the function was called correctly. */ if (! takes_nargs_(id, parms_.size())) { - cerr << get_fileline() << ": error: " << name_ - << "() does not support " << parms_.size() + cerr << get_fileline() << ": error: constant function " + << name_ << "() does not support " << parms_.size() << " arguments." << endl; return 0; } -// HERE: Need to add support for a multi argument $countbits(). - cerr << get_fileline() << ": sorry: functions with " - << parms_.size() << " arguments are not supported: " - << name_ << "()." << endl; + if (id == CTBITS) { + for (unsigned bit = 0; bit < parms_.size(); ++bit) { + eval_expr(parms_[bit]); + } + return evaluate_countbits_(); + } else { + cerr << get_fileline() << ": sorry: constant functions with " + << parms_.size() << " arguments are not supported: " + << name_ << "()." << endl; + } return 0; } } diff --git a/expr_synth.cc b/expr_synth.cc index cb8ba87f0..86dd78dd4 100644 --- a/expr_synth.cc +++ b/expr_synth.cc @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999-2015 Stephen Williams (steve@icarus.com) + * Copyright (c) 1999-2018 Stephen Williams (steve@icarus.com) * * This source code is free software; you can redistribute it * and/or modify it in source code form under the terms of the GNU @@ -274,7 +274,18 @@ NetNet* NetEBComp::synthesize(Design*des, NetScope*scope, NetExpr*root) if (op_ == 'E' || op_ == 'N') { NetCaseCmp*gate = new NetCaseCmp(scope, scope->local_symbol(), - width, op_=='E'?NetCaseCmp::EEQ:NetCaseCmp::NEQ); + width, op_=='E' ? NetCaseCmp::EEQ : NetCaseCmp::NEQ); + gate->set_line(*this); + connect(gate->pin(0), osig->pin(0)); + connect(gate->pin(1), lsig->pin(0)); + connect(gate->pin(2), rsig->pin(0)); + des->add_node(gate); + return osig; + } + + if (op_ == 'w' || op_ == 'W') { + NetCaseCmp*gate = new NetCaseCmp(scope, scope->local_symbol(), + width, op_=='w' ? NetCaseCmp::WEQ : NetCaseCmp::WNE); gate->set_line(*this); connect(gate->pin(0), osig->pin(0)); connect(gate->pin(1), lsig->pin(0)); @@ -335,6 +346,7 @@ NetNet* NetEBComp::synthesize(Design*des, NetScope*scope, NetExpr*root) des->errors += 1; return 0; } + // fallthrough case 'e': // == connect(dev->pin_AEB(), osig->pin(0)); break; @@ -353,6 +365,7 @@ NetNet* NetEBComp::synthesize(Design*des, NetScope*scope, NetExpr*root) des->errors += 1; return 0; } + // fallthrough case 'n': // != connect(dev->pin_ANEB(), osig->pin(0)); break; @@ -1347,6 +1360,7 @@ static NetEvWait* make_func_trigger(Design*des, NetScope*scope, NetExpr*root) if (nset && (nset->size() > 0)) { NetEvent*ev = new NetEvent(scope->local_symbol()); ev->set_line(*root); + ev->local_flag(true); NetEvProbe*pr = new NetEvProbe(scope, scope->local_symbol(), ev, NetEvProbe::ANYEDGE, diff --git a/iverilog-vpi.man.in b/iverilog-vpi.man.in index 2f5f090b0..bd8f7a930 100644 --- a/iverilog-vpi.man.in +++ b/iverilog-vpi.man.in @@ -1,4 +1,4 @@ -.TH iverilog-vpi 1 "May 10th, 2015" "" "Version %M.%n%E" +.TH iverilog-vpi 1 "Jan 29th, 2017" "" "Version %M.%n%E" .SH NAME iverilog-vpi - Compile front end for VPI modules @@ -26,6 +26,11 @@ becomes \fIfoo.vpi\fP. Include the named library in the link of the VPI module. This allows VPI modules to further reference external libraries. +.TP 8 +.B -L\fIdirectory\fP +Add \fIdirectory\fP to the list of directories that will be searched +for library files. + .TP 8 .B -I\fIdirectory\fP Add \fIdirectory\fP to the list of directories that will be searched @@ -115,7 +120,7 @@ iverilog(1), vvp(1), .SH COPYRIGHT .nf -Copyright \(co 2002\-2015 Stephen Williams +Copyright \(co 2002\-2017 Stephen Williams This document can be freely redistributed according to the terms of the GNU General Public License version 2.0 diff --git a/iverilog-vpi.sh b/iverilog-vpi.sh index d1554d420..026e3e6ea 100644 --- a/iverilog-vpi.sh +++ b/iverilog-vpi.sh @@ -35,6 +35,7 @@ CCSRC= CXSRC= OBJ= LIB= +LIBDIR= OUT= INCOPT= DEFS= @@ -81,6 +82,9 @@ do -l*) LIB="$LIB $parm" ;; + -L*) LIBDIR="$LIBDIR $parm" + ;; + -I*) INCOPT="$INCOPT $parm" ;; @@ -92,6 +96,11 @@ do exit; ;; + --ccflags) + echo "$CXXFLAGS" + exit; + ;; + --ldflags) echo "$LDFLAGS" exit; @@ -148,4 +157,4 @@ then fi echo "Making $OUT from $OBJ..." -exec $LD -o $OUT $LDFLAGS $OBJ $LIB $LDLIBS +exec $LD -o $OUT $LDFLAGS $LIBDIR $OBJ $LIB $LDLIBS diff --git a/ivl.def b/ivl.def index 5fee414ef..39682eaf5 100644 --- a/ivl.def +++ b/ivl.def @@ -294,6 +294,7 @@ ivl_stmt_lval ivl_stmt_lvals ivl_stmt_lwidth ivl_stmt_name +ivl_stmt_needs_t0_trigger ivl_stmt_nevent ivl_stmt_opcode ivl_stmt_parm diff --git a/ivl_target.h b/ivl_target.h index 42dbe167b..f3fed5669 100644 --- a/ivl_target.h +++ b/ivl_target.h @@ -1,7 +1,7 @@ #ifndef IVL_ivl_target_H #define IVL_ivl_target_H /* - * Copyright (c) 2000-2016 Stephen Williams (steve@icarus.com) + * Copyright (c) 2000-2017 Stephen Williams (steve@icarus.com) * * This source code is free software; you can redistribute it * and/or modify it in source code form under the terms of the GNU @@ -306,8 +306,10 @@ typedef enum ivl_lpm_type_e { IVL_LPM_CONCAT = 16, IVL_LPM_CONCATZ = 36, /* Transparent concat */ IVL_LPM_CMP_EEQ= 18, /* Case EQ (===) */ - IVL_LPM_CMP_EQX= 37, /* Wildcard EQ (==?) */ + IVL_LPM_CMP_EQX= 37, /* Wildcard EQ (casex) */ IVL_LPM_CMP_EQZ= 38, /* casez EQ */ + IVL_LPM_CMP_WEQ= 41, + IVL_LPM_CMP_WNE= 42, IVL_LPM_CMP_EQ = 10, IVL_LPM_CMP_GE = 1, IVL_LPM_CMP_GT = 2, @@ -353,9 +355,12 @@ typedef enum ivl_path_edge_e { /* Processes are initial, always, or final blocks with a statement. This is the type of the ivl_process_t object. */ typedef enum ivl_process_type_e ENUM_UNSIGNED_INT { - IVL_PR_INITIAL = 0, - IVL_PR_ALWAYS = 1, - IVL_PR_FINAL = 2 + IVL_PR_INITIAL = 0, + IVL_PR_ALWAYS = 1, + IVL_PR_ALWAYS_COMB = 3, + IVL_PR_ALWAYS_FF = 4, + IVL_PR_ALWAYS_LATCH = 5, + IVL_PR_FINAL = 2 } ivl_process_type_t; /* These are the sorts of reasons a scope may come to be. These types @@ -2100,6 +2105,7 @@ extern unsigned ivl_stmt_lineno(ivl_statement_t net); * handle disable statements. * * ivl_stmt_events + * ivl_stmt_needs_t0_trigger * ivl_stmt_nevent * Statements that have event arguments (TRIGGER and WAIT) make * those event objects available through these methods. @@ -2227,6 +2233,7 @@ extern ivl_expr_t ivl_stmt_delay_expr(ivl_statement_t net); /* IVL_ST_DELAY */ extern uint64_t ivl_stmt_delay_val(ivl_statement_t net); /* IVL_ST_WAIT IVL_ST_TRIGGER */ +extern unsigned ivl_stmt_needs_t0_trigger(ivl_statement_t net); extern unsigned ivl_stmt_nevent(ivl_statement_t net); extern ivl_event_t ivl_stmt_events(ivl_statement_t net, unsigned idx); /* IVL_ST_CONTRIB */ diff --git a/ivl_target_priv.h b/ivl_target_priv.h index 489d801eb..3ae882b63 100644 --- a/ivl_target_priv.h +++ b/ivl_target_priv.h @@ -1,7 +1,7 @@ #ifndef IVL_ivl_target_priv_H #define IVL_ivl_target_priv_H /* - * Copyright (c) 2008-2014 Stephen Williams (steve@icarus.com) + * Copyright (c) 2008-2017 Stephen Williams (steve@icarus.com) * * This source code is free software; you can redistribute it * and/or modify it in source code form under the terms of the GNU @@ -52,7 +52,6 @@ struct ivl_design_s { // Keep arrays of root scopes. std::map classes; - std::map root_tasks; std::vector packages; std::vector roots; diff --git a/ivlpp/globals.h b/ivlpp/globals.h index 90b4632b9..a1f77e95e 100644 --- a/ivlpp/globals.h +++ b/ivlpp/globals.h @@ -1,7 +1,7 @@ #ifndef IVL_globals_H #define IVL_globals_H /* - * Copyright (c) 1999-2014 Stephen Williams (steve@icarus.com) + * Copyright (c) 1999-2017 Stephen Williams (steve@icarus.com) * * This source code is free software; you can redistribute it * and/or modify it in source code form under the terms of the GNU @@ -53,6 +53,9 @@ extern char dep_mode; extern int verbose_flag; +extern int warn_redef; +extern int warn_redef_all; + /* This is the entry to the lexer. */ extern int yylex(void); diff --git a/ivlpp/lexor.lex b/ivlpp/lexor.lex index c81af7397..8a4355264 100644 --- a/ivlpp/lexor.lex +++ b/ivlpp/lexor.lex @@ -1,7 +1,7 @@ %option prefix="yy" %{ /* - * Copyright (c) 1999-2016 Stephen Williams (steve@icarus.com) + * Copyright (c) 1999-2017 Stephen Williams (steve@icarus.com) * * This source code is free software; you can redistribute it * and/or modify it in source code form under the terms of the GNU @@ -858,6 +858,25 @@ void define_macro(const char* name, const char* value, int keyword, int argc) { int idx; struct define_t* def; + struct define_t* prev; + + /* Verilog has a very nasty system of macros jumping from + * file to file, resulting in a global macro scope. Here + * we optionally warn about any redefinitions. + * + * If istack is empty, we are processing a configuration + * or precompiled macro file, so don't want to check for + * redefinitions - when a precompiled macro file is used, + * it will contain copies of any predefined macros. + */ + if (warn_redef && istack) { + prev = def_lookup(name); + if (prev && (warn_redef_all || (strcmp(prev->value, value) != 0))) { + emit_pathline(istack); + fprintf(stderr, "warning: redefinition of macro %s from value '%s' to '%s'\n", + name, prev->value, value); + } + } def = malloc(sizeof(struct define_t)); def->name = strdup(name); @@ -2100,7 +2119,7 @@ void destroy_lexor(void) { # ifdef FLEX_SCANNER # if YY_FLEX_MAJOR_VERSION >= 2 && YY_FLEX_MINOR_VERSION >= 5 -# if defined(YY_FLEX_SUBMINOR_VERSION) && YY_FLEX_SUBMINOR_VERSION >= 9 +# if YY_FLEX_MINOR_VERSION > 5 || defined(YY_FLEX_SUBMINOR_VERSION) && YY_FLEX_SUBMINOR_VERSION >= 9 yylex_destroy(); # endif # endif diff --git a/ivlpp/main.c b/ivlpp/main.c index 7ec80cb86..19ef09bde 100644 --- a/ivlpp/main.c +++ b/ivlpp/main.c @@ -1,5 +1,5 @@ const char COPYRIGHT[] = - "Copyright (c) 1999-2015 Stephen Williams (steve@icarus.com)"; + "Copyright (c) 1999-2017 Stephen Williams (steve@icarus.com)"; /* * This source code is free software; you can redistribute it * and/or modify it in source code form under the terms of the GNU @@ -98,6 +98,10 @@ int line_direct_flag = 0; unsigned error_count = 0; FILE *depend_file = NULL; +/* Should we warn about macro redefinitions? */ +int warn_redef = 0; +int warn_redef_all = 0; + static int flist_read_flags(const char*path) { char line_buf[2048]; @@ -282,7 +286,7 @@ int main(int argc, char*argv[]) include_dir[0] = 0; /* 0 is reserved for the current files path. */ include_dir[1] = strdup("."); - while ((opt=getopt(argc, argv, "F:f:K:Lo:p:P:vV")) != EOF) switch (opt) { + while ((opt=getopt(argc, argv, "F:f:K:Lo:p:P:vVW:")) != EOF) switch (opt) { case 'F': flist_read_flags(optarg); @@ -336,6 +340,15 @@ int main(int argc, char*argv[]) break; } + case 'W': + if (strcmp(optarg, "redef-all") == 0) { + warn_redef_all = 1; + warn_redef = 1; + } else if (strcmp(optarg, "redef-chg") == 0) { + warn_redef = 1; + } + break; + case 'v': fprintf(stderr, "Icarus Verilog Preprocessor version " VERSION " (" VERSION_TAG ")\n\n"); @@ -366,7 +379,10 @@ int main(int argc, char*argv[]) " -p - Write precompiled defines to \n" " -P - Read precompiled defines from \n" " -v - Verbose\n" - " -V - Print version information and quit\n", + " -V - Print version information and quit\n" + " -W - Enable extra ivlpp warning category:\n" + " o redef-all - all macro redefinitions\n" + " o redef-chg - macro definition changes\n", argv[0]); return flag_errors; } diff --git a/lexor.lex b/lexor.lex index 06d9b1744..37c3e0207 100644 --- a/lexor.lex +++ b/lexor.lex @@ -4,7 +4,7 @@ %{ /* - * Copyright (c) 1998-2015 Stephen Williams (steve@icarus.com) + * Copyright (c) 1998-2017 Stephen Williams (steve@icarus.com) * * This source code is free software; you can redistribute it * and/or modify it in source code form under the terms of the GNU @@ -72,6 +72,7 @@ static const char* set_file_name(char*text) void reset_lexor(); static void line_directive(); static void line_directive2(); +static void reset_all(); verinum*make_unsized_binary(const char*txt); verinum*make_undef_highz_dec(const char*txt); @@ -187,6 +188,8 @@ TU [munpf] "!=" { return K_NE; } "===" { return K_CEQ; } "!==" { return K_CNE; } +"==?" { return K_WEQ; } +"!=?" { return K_WNE; } "||" { return K_LOR; } "&&" { return K_LAND; } "&&&" { return K_TAND; } @@ -310,15 +313,6 @@ TU [munpf] BEGIN(UDPTABLE); break; - /* Translate these to checks if we already have or are - * outside the declaration region. */ - case K_timeunit: - if (have_timeunit_decl) rc = K_timeunit_check; - break; - case K_timeprecision: - if (have_timeprec_decl) rc = K_timeprecision_check; - break; - default: yylval.text = 0; break; @@ -428,6 +422,12 @@ TU [munpf] if (strcmp(yytext,"$attribute") == 0) return KK_attribute; + + if (gn_system_verilog() && strcmp(yytext,"$unit") == 0) { + yylval.package = pform_units.back(); + return PACKAGE_IDENTIFIER; + } + yylval.text = strdupnew(yytext); return SYSTEM_IDENTIFIER; } @@ -566,11 +566,7 @@ TU [munpf] "definition." << endl; error_count += 1; } else { - pform_set_default_nettype(NetNet::WIRE, yylloc.text, - yylloc.first_line); - in_celldefine = false; - uc_drive = UCD_NONE; - pform_set_timescale(def_ts_units, def_ts_prec, 0, 0); + reset_all(); } } /* Notice and handle the `unconnected_drive directive. */ @@ -1597,6 +1593,18 @@ static void line_directive2() yylloc.first_line = lineno; } +/* + * Reset all compiler directives. This will be called when a `resetall + * directive is encountered or when a new compilation unit is started. + */ +static void reset_all() +{ + pform_set_default_nettype(NetNet::WIRE, yylloc.text, yylloc.first_line); + in_celldefine = false; + uc_drive = UCD_NONE; + pform_set_timescale(def_ts_units, def_ts_prec, 0, 0); +} + extern FILE*vl_input; void reset_lexor() { @@ -1605,6 +1613,14 @@ void reset_lexor() /* Announce the first file name. */ yylloc.text = set_file_name(strdupnew(vl_file.c_str())); + + if (separate_compilation) { + reset_all(); + if (!keyword_mask_stack.empty()) { + lexor_keyword_mask = keyword_mask_stack.back(); + keyword_mask_stack.clear(); + } + } } /* @@ -1614,7 +1630,7 @@ void destroy_lexor() { # ifdef FLEX_SCANNER # if YY_FLEX_MAJOR_VERSION >= 2 && YY_FLEX_MINOR_VERSION >= 5 -# if defined(YY_FLEX_SUBMINOR_VERSION) && YY_FLEX_SUBMINOR_VERSION >= 9 +# if YY_FLEX_MINOR_VERSION > 5 || defined(YY_FLEX_SUBMINOR_VERSION) && YY_FLEX_SUBMINOR_VERSION >= 9 yylex_destroy(); # endif # endif diff --git a/libmisc/StringHeap.cc b/libmisc/StringHeap.cc index f87c4fcf8..10259dc34 100644 --- a/libmisc/StringHeap.cc +++ b/libmisc/StringHeap.cc @@ -32,8 +32,8 @@ static unsigned string_pool_count = 0; StringHeap::StringHeap() { cell_base_ = 0; - cell_ptr_ = HEAPCELL; - cell_count_ = 0; + cell_size_ = 0; + cell_ptr_ = 0; } StringHeap::~StringHeap() @@ -45,20 +45,24 @@ StringHeap::~StringHeap() const char* StringHeap::add(const char*text) { unsigned len = strlen(text); - assert((len+1) <= HEAPCELL); - - unsigned rem = HEAPCELL - cell_ptr_; + unsigned rem = cell_size_ - cell_ptr_; if (rem < (len+1)) { - cell_base_ = (char*)malloc(HEAPCELL); + // release any unused memory + if (rem > 0) { + cell_base_ = (char*)realloc(cell_base_, cell_ptr_); + assert(cell_base_ != 0); + } + // start new cell + cell_size_ = (len+1) > DEFAULT_CELL_SIZE ? len+1 : DEFAULT_CELL_SIZE; + cell_base_ = (char*)malloc(cell_size_); + cell_ptr_ = 0; + assert(cell_base_ != 0); #ifdef CHECK_WITH_VALGRIND string_pool_count += 1; string_pool = (char **) realloc(string_pool, string_pool_count*sizeof(char **)); string_pool[string_pool_count-1] = cell_base_; #endif - cell_ptr_ = 0; - cell_count_ += 1; - assert(cell_base_ != 0); } char*res = cell_base_ + cell_ptr_; @@ -66,7 +70,7 @@ const char* StringHeap::add(const char*text) cell_ptr_ += len; cell_base_[cell_ptr_++] = 0; - assert(cell_ptr_ <= HEAPCELL); + assert(cell_ptr_ <= cell_size_); return res; } diff --git a/libmisc/StringHeap.h b/libmisc/StringHeap.h index 4d619accf..2d4b97d43 100644 --- a/libmisc/StringHeap.h +++ b/libmisc/StringHeap.h @@ -78,11 +78,11 @@ class StringHeap { perm_string make(const char*); private: - enum { HEAPCELL = 0x10000 }; + static const unsigned DEFAULT_CELL_SIZE = 0x10000; char*cell_base_; + unsigned cell_size_; unsigned cell_ptr_; - unsigned cell_count_; private: // not implemented StringHeap(const StringHeap&); diff --git a/libveriuser/Makefile.in b/libveriuser/Makefile.in index bdc09330f..989d7c980 100644 --- a/libveriuser/Makefile.in +++ b/libveriuser/Makefile.in @@ -47,7 +47,7 @@ LDRELOCFLAGS = @LDRELOCFLAGS@ LDTARGETFLAGS = @LDTARGETFLAGS@ -CPPFLAGS = $(INCLUDE_PATH) @CPPFLAGS@ @DEFS@ @PICFLAG@ +CPPFLAGS = $(INCLUDE_PATH) @CPPFLAGS@ @DEFS@ -DICARUS_VPI_CONST=const @PICFLAG@ CFLAGS = @WARNING_FLAGS@ @WARNING_FLAGS_CC@ @CFLAGS@ A = a_close.o a_compare_handles.o a_configure.o a_fetch_argc.o \ diff --git a/libveriuser/veriusertfs.c b/libveriuser/veriusertfs.c index 979b2b5d3..8807f6649 100644 --- a/libveriuser/veriusertfs.c +++ b/libveriuser/veriusertfs.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2002-2014 Michael Ruff (mruff at chiaro.com) + * Copyright (c) 2002-2018 Michael Ruff (mruff at chiaro.com) * Michael Runyan (mrunyan at chiaro.com) * * This source code is free software; you can redistribute it @@ -42,8 +42,9 @@ typedef struct t_pli_data { int paramvc; /* parameter number for misctf */ } s_pli_data, *p_pli_data; -static PLI_INT32 compiletf(char *); -static PLI_INT32 calltf(char *); +static PLI_INT32 compiletf(ICARUS_VPI_CONST PLI_BYTE8 *); +static PLI_INT32 calltf(ICARUS_VPI_CONST PLI_BYTE8 *); +static PLI_INT32 sizetf(ICARUS_VPI_CONST PLI_BYTE8 *); static PLI_INT32 callback(p_cb_data); /* @@ -150,7 +151,7 @@ void veriusertfs_register_table(p_tfcell vtable) tf_data.tfname = tf->tfname; tf_data.compiletf = compiletf; tf_data.calltf = calltf; - tf_data.sizetf = (PLI_INT32 (*)(PLI_BYTE8 *))tf->sizetf; + tf_data.sizetf = sizetf; tf_data.user_data = (char *)data; if (pli_trace) { @@ -180,7 +181,7 @@ void veriusertfs_register_table(p_tfcell vtable) * This function calls the veriusertfs checktf and sets up all the * callbacks misctf requires. */ -static PLI_INT32 compiletf(char *data) +static PLI_INT32 compiletf(ICARUS_VPI_CONST PLI_BYTE8*data) { p_pli_data pli; p_tfcell tf; @@ -260,7 +261,7 @@ static PLI_INT32 compiletf(char *data) /* * This function is the wrapper for the veriusertfs calltf routine. */ -static PLI_INT32 calltf(char *data) +static PLI_INT32 calltf(ICARUS_VPI_CONST PLI_BYTE8*data) { int rc = 0; p_pli_data pli; @@ -283,6 +284,32 @@ static PLI_INT32 calltf(char *data) return rc; } +/* + * This function is the wrapper for the veriusertfs sizetf routine. + */ +static PLI_INT32 sizetf(ICARUS_VPI_CONST PLI_BYTE8*data) +{ + int rc = 32; + p_pli_data pli; + p_tfcell tf; + + /* cast back from opaque */ + pli = (p_pli_data)data; + tf = pli->tf; + + /* execute sizetf */ + if (tf->sizetf) { + if (pli_trace) { + fprintf(pli_trace, "Call %s->sizetf(%d, %d)\n", + tf->tfname, tf->data, reason_sizetf); + } + + rc = tf->sizetf(tf->data, reason_sizetf); + } + + return rc; +} + /* * This function is the wrapper for all the misctf callbacks */ diff --git a/load_module.cc b/load_module.cc index 665b865e9..b285302f2 100644 --- a/load_module.cc +++ b/load_module.cc @@ -82,36 +82,10 @@ bool load_module(const char*type) fflush(depend_file); } - if (ivlpp_string) { - char*cmdline = (char*)malloc(strlen(ivlpp_string) + - strlen(path) + 4); - strcpy(cmdline, ivlpp_string); - strcat(cmdline, " \""); - strcat(cmdline, path); - strcat(cmdline, "\""); + if (verbose_flag) + cerr << "Loading library file " << path << "." << endl; - if (verbose_flag) - cerr << "Executing: " << cmdline << endl<< flush; - - FILE*file = popen(cmdline, "r"); - - if (verbose_flag) - cerr << "...parsing output from preprocessor..." << endl << flush; - - pform_parse(path, file); - pclose(file); - free(cmdline); - - } else { - if (verbose_flag) - cerr << "Loading library file " - << path << "." << endl; - - FILE*file = fopen(path, "r"); - assert(file); - pform_parse(path, file); - fclose(file); - } + pform_parse(path); if (verbose_flag) cerr << "... Load module complete." << endl << flush; @@ -119,7 +93,6 @@ bool load_module(const char*type) return true; } - return false; } diff --git a/main.cc b/main.cc index 366ca150b..290f766a7 100644 --- a/main.cc +++ b/main.cc @@ -1,5 +1,5 @@ const char COPYRIGHT[] = - "Copyright (c) 1998-2016 Stephen Williams (steve@icarus.com)"; + "Copyright (c) 1998-2017 Stephen Williams (steve@icarus.com)"; /* * This source code is free software; you can redistribute it @@ -140,6 +140,8 @@ void add_vpi_module(const char*name) map missing_modules; map library_file_map; +vector source_files; + list library_suff; list roots; @@ -164,6 +166,11 @@ bool warn_sens_entire_arr = false; bool warn_anachronisms = false; bool warn_floating_nets = false; +/* + * Ignore errors about missing modules + */ +bool ignore_missing_modules = false; + /* * Debug message class flags. */ @@ -174,6 +181,11 @@ bool debug_emit = false; bool debug_synth2 = false; bool debug_optimizer = false; +/* + * Compilation control flags. + */ +bool separate_compilation = false; + /* * Optimization control flags. */ @@ -570,6 +582,9 @@ static bool set_default_timescale(const char*ts_string) * * warnings: * Warning flag letters. + * + * ignore_missing_modules: + * true to ignore errors about missing modules */ bool had_timescale = false; static void read_iconfig_file(const char*ipath) @@ -720,6 +735,10 @@ static void read_iconfig_file(const char*ipath) break; } + } else if (strcmp(buf, "ignore_missing_modules") == 0) { + if (strcmp(cp, "true") == 0) + ignore_missing_modules = true; + } else if (strcmp(buf, "-y") == 0) { build_library_index(cp, CASE_SENSITIVE); @@ -765,6 +784,38 @@ static void read_iconfig_file(const char*ipath) fclose(ifile); } +/* + * This function reads a list of source file names. Each name starts + * with the first non-space character, and ends with the last non-space + * character. Spaces in the middle are OK. + */ +static void read_sources_file(const char*path) +{ + char line_buf[2048]; + + FILE*fd = fopen(path, "r"); + if (fd == 0) { + cerr << "ERROR: Unable to read source file list: " << path << endl; + return; + } + + while (fgets(line_buf, sizeof line_buf, fd) != 0) { + char*cp = line_buf + strspn(line_buf, " \t\r\b\f"); + char*tail = cp + strlen(cp); + while (tail > cp) { + if (! isspace((int)tail[-1])) + break; + tail -= 1; + tail[0] = 0; + } + + if (cp < tail) + source_files.push_back(filename_strings.make(cp)); + } + + fclose(fd); +} + extern Design* elaborate(list root); #if defined(HAVE_TIMES) @@ -851,12 +902,14 @@ int main(int argc, char*argv[]) min_typ_max_flag = TYP; min_typ_max_warn = 10; - while ((opt = getopt(argc, argv, "C:f:hN:P:p:Vv")) != EOF) switch (opt) { + while ((opt = getopt(argc, argv, "C:F:f:hN:P:p:Vv")) != EOF) switch (opt) { case 'C': read_iconfig_file(optarg); break; - + case 'F': + read_sources_file(optarg); + break; case 'f': parm_to_flagmap(optarg); break; @@ -909,6 +962,7 @@ int main(int argc, char*argv[]) "usage: ivl \n" "options:\n" "\t-C Config file from driver.\n" +"\t-F List of source files from driver.\n" "\t-h Print usage information, and exit.\n" "\t-N Dump the elaborated netlist to .\n" "\t-P Write the parsed input to .\n" @@ -924,11 +978,19 @@ int main(int argc, char*argv[]) return 0; } - if (optind == argc) { + int arg = optind; + while (arg < argc) { + perm_string path = filename_strings.make(argv[arg++]); + source_files.push_back(path); + } + + if (source_files.empty()) { cerr << "No input files." << endl; return 1; } + separate_compilation = source_files.size() > 1; + if( depfile_name ) { depend_file = fopen(depfile_name, "a"); if(! depend_file) { @@ -940,16 +1002,22 @@ int main(int argc, char*argv[]) switch (generation_flag) { case GN_VER2012: lexor_keyword_mask |= GN_KEYWORDS_1800_2012; + // fallthrough case GN_VER2009: lexor_keyword_mask |= GN_KEYWORDS_1800_2009; + // fallthrough case GN_VER2005_SV: lexor_keyword_mask |= GN_KEYWORDS_1800_2005; + // fallthrough case GN_VER2005: lexor_keyword_mask |= GN_KEYWORDS_1364_2005; + // fallthrough case GN_VER2001: lexor_keyword_mask |= GN_KEYWORDS_1364_2001_CONFIG; + // fallthrough case GN_VER2001_NOCONFIG: lexor_keyword_mask |= GN_KEYWORDS_1364_2001; + // fallthrough case GN_VER1995: lexor_keyword_mask |= GN_KEYWORDS_1364_1995; } @@ -1023,8 +1091,10 @@ int main(int argc, char*argv[]) if (flag_tmp) disable_concatz_generation = strcmp(flag_tmp,"true")==0; /* Parse the input. Make the pform. */ - pform_set_timescale(def_ts_units, def_ts_prec, 0, 0); - int rc = pform_parse(argv[optind]); + int rc = 0; + for (unsigned idx = 0; idx < source_files.size(); idx += 1) { + rc += pform_parse(source_files[idx]); + } if (pf_path) { ofstream out (pf_path); @@ -1038,22 +1108,16 @@ int main(int argc, char*argv[]) ; cur != disciplines.end() ; ++ cur ) { pform_dump(out, (*cur).second); } - out << "PFORM DUMP $ROOT TASKS/FUNCTIONS:" << endl; - for (map::iterator cur = pform_tasks.begin() - ; cur != pform_tasks.end() ; ++ cur) { - pform_dump(out, cur->second); - } - out << "PFORM DUMP $ROOT CLASSES:" << endl; - for (map::iterator cur = pform_classes.begin() - ; cur != pform_classes.end() ; ++ cur) { - pform_dump(out, cur->second); + out << "PFORM DUMP COMPILATION UNITS:" << endl; + for (vector::iterator pac = pform_units.begin() + ; pac != pform_units.end() ; ++ pac) { + pform_dump(out, *pac); } out << "PFORM DUMP PACKAGES:" << endl; for (map::iterator pac = pform_packages.begin() ; pac != pform_packages.end() ; ++ pac) { pform_dump(out, pac->second); } - out << "PFORM DUMP MODULES:" << endl; for (map::iterator mod = pform_modules.begin() ; mod != pform_modules.end() ; ++ mod ) { @@ -1171,12 +1235,6 @@ int main(int argc, char*argv[]) (*idx).second = 0; } - for(map::iterator it = pform_typedefs.begin() - ; it != pform_typedefs.end() ; ++it) { - delete (*it).second; - (*it).second = 0; - } - if (verbose_flag) { if (times_flag) { times(cycles+2); diff --git a/mingw-cross.txt b/mingw-cross.txt new file mode 100644 index 000000000..94ad1d1fc --- /dev/null +++ b/mingw-cross.txt @@ -0,0 +1,27 @@ + +These are instructions for building Icarus Verilog binaries for +Windows using mingw cross compiler tools on Linux. + +To start with, you need the mingw64-cross-* packages for your linux +distribution, which gives you the x86_64-w64-mingw32-* commands +installed on your system. Installing the cross environment is outside +the scope of this writeup. + +First, configure with this command: + + $ ./configure --host=x86_64-w64-mingw32 + +This generates the Makefiles needed to cross compile everything with +the mingw32 compiler. The configure script will generate the command +name paths, so long as commands line x86_64-w64-mingw32-gcc +et. al. are in your path. + +Next, compile with the command: + + $ make HOSTCC=cc HOSTCFLAGS=-O + +The configure generated the cross compiler flags, but there are a few +bits that need to be compiled with the native compiler. (version.exe +for example is used by the build process but is not installed.) The +MOSTCC= flag on the make command line makes sure the Makefile knows +about the native tool. diff --git a/net_design.cc b/net_design.cc index c0d03cf9f..b071469e2 100644 --- a/net_design.cc +++ b/net_design.cc @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000-2015 Stephen Williams (steve@icarus.com) + * Copyright (c) 2000-2017 Stephen Williams (steve@icarus.com) * * This source code is free software; you can redistribute it * and/or modify it in source code form under the terms of the GNU @@ -101,11 +101,11 @@ uint64_t Design::scale_to_precision(uint64_t val, return val; } -NetScope* Design::make_root_scope(perm_string root, bool program_block, - bool is_interface) +NetScope* Design::make_root_scope(perm_string root, NetScope*unit_scope, + bool program_block, bool is_interface) { NetScope *root_scope_; - root_scope_ = new NetScope(0, hname_t(root), NetScope::MODULE, + root_scope_ = new NetScope(0, hname_t(root), NetScope::MODULE, unit_scope, false, program_block, is_interface); /* This relies on the fact that the basename return value is permallocated. */ @@ -125,31 +125,18 @@ list Design::find_root_scopes() const return root_scopes_; } -NetScope* Design::make_package_scope(perm_string name) +NetScope* Design::make_package_scope(perm_string name, NetScope*unit_scope, + bool is_unit) { NetScope*scope; - scope = new NetScope(0, hname_t(name), NetScope::PACKAGE, false, false); + scope = new NetScope(0, hname_t(name), NetScope::PACKAGE, unit_scope, + false, false, false, is_unit); scope->set_module_name(scope->basename()); packages_[name] = scope; return scope; } -void Design::add_class(netclass_t*cl, PClass*pclass) -{ - Definitions::add_class(cl); - class_to_pclass_[cl] = pclass; -} - -netclass_t* Design::find_class(perm_string name) const -{ - map::const_iterator cur = classes_.find(name); - if (cur != classes_.end()) - return cur->second; - - return 0; -} - NetScope* Design::find_package(perm_string name) const { map::const_iterator cur = packages_.find(name); @@ -170,17 +157,6 @@ list Design::find_package_scopes() const return res; } -list Design::find_roottask_scopes() const -{ - listres; - for (map::const_iterator cur = root_tasks_.begin() - ; cur != root_tasks_.end() ; ++ cur) { - res.push_back (cur->first); - } - - return res; -} - /* * This method locates a scope in the design, given its rooted * hierarchical name. Each component of the key is used to scan one @@ -211,25 +187,6 @@ NetScope* Design::find_scope(const std::list&path) const } } - for (map::const_iterator root = root_tasks_.begin() - ; root != root_tasks_.end() ; ++ root) { - - NetScope*cur = root->first; - if (path.front() != cur->fullname()) - continue; - - std::list tmp = path; - tmp.pop_front(); - - while (cur) { - if (tmp.empty()) return cur; - - cur = cur->child( tmp.front() ); - - tmp.pop_front(); - } - } - return 0; } @@ -253,6 +210,49 @@ NetScope* Design::find_scope(const hname_t&path) const return 0; } +static bool is_design_unit(NetScope*scope) +{ + return (scope->type() == NetScope::MODULE && !scope->nested_module()) + || (scope->type() == NetScope::PACKAGE); +} + +static bool is_subroutine(NetScope::TYPE type) +{ + return type == NetScope::TASK || type == NetScope::FUNC; +} + +/* + * This method locates a scope within another scope, given its relative + * hierarchical name. Each component of the key is used to scan one + * more step down the tree until the name runs out or the search + * fails. + */ +NetScope* Design::find_scope_(NetScope*scope, const std::list&path, + NetScope::TYPE type) const +{ + std::list tmp = path; + + do { + hname_t key = tmp.front(); + /* If we are looking for a module or we are not + * looking at the last path component check for + * a name match (second line). */ + if (scope->type() == NetScope::MODULE + && (type == NetScope::MODULE || tmp.size() > 1) + && scope->module_name()==key.peek_name()) { + + /* Up references may match module name */ + + } else { + scope = scope->child( key ); + if (scope == 0) break; + } + tmp.pop_front(); + } while (! tmp.empty()); + + return scope; +} + /* * This is a relative lookup of a scope by name. The starting point is * the scope parameter within which I start looking for the scope. If @@ -266,36 +266,62 @@ NetScope* Design::find_scope(NetScope*scope, const std::list&path, if (path.empty()) return scope; - for ( ; scope ; scope = scope->parent()) { + // Record the compilation unit scope for use later. + NetScope*unit_scope = scope->unit(); - std::list tmp = path; + // First search upwards through the hierarchy. + while (scope) { + NetScope*found_scope = find_scope_(scope, path, type); + if (found_scope) + return found_scope; - NetScope*cur = scope; - do { - hname_t key = tmp.front(); - /* If we are looking for a module or we are not - * looking at the last path component check for - * a name match (second line). */ - if (cur->type() == NetScope::MODULE - && (type == NetScope::MODULE || tmp.size() > 1) - && cur->module_name()==key.peek_name()) { + // Avoid searching the unit scope twice. + if (scope == unit_scope) + unit_scope = 0; - /* Up references may match module name */ + // Special case - see IEEE 1800-2012 section 23.8.1. + if (unit_scope && is_design_unit(scope) && is_subroutine(type)) { + found_scope = find_scope_(unit_scope, path, type); + if (found_scope) + return found_scope; - } else { - cur = cur->child( key ); - if (cur == 0) break; - } - tmp.pop_front(); - } while (! tmp.empty()); + unit_scope = 0; + } - if (cur) return cur; + scope = scope->parent(); + } + + // If we haven't already done so, search the compilation unit scope. + if (unit_scope) { + NetScope*found_scope = find_scope_(unit_scope, path, type); + if (found_scope) + return found_scope; } // Last chance. Look for the name starting at the root. return find_scope(path); } +/* + * This method locates a scope within another scope, given its relative + * hierarchical name. Each component of the key is used to scan one + * more step down the tree until the name runs out or the search + * fails. + */ +NetScope* Design::find_scope_(NetScope*scope, const hname_t&path, + NetScope::TYPE type) const +{ + /* If we are looking for a module or we are not + * looking at the last path component check for + * a name match (second line). */ + if ((scope->type() == NetScope::MODULE) && (type == NetScope::MODULE) + && (scope->module_name() == path.peek_name())) { + /* Up references may match module name */ + return scope; + } + return scope->child( path ); +} + /* * This is a relative lookup of a scope by name. The starting point is * the scope parameter within which I start looking for the scope. If @@ -307,24 +333,36 @@ NetScope* Design::find_scope(NetScope*scope, const hname_t&path, { assert(scope); - for ( ; scope ; scope = scope->parent()) { + // Record the compilation unit scope for use later. + NetScope*unit_scope = scope->unit(); - NetScope*cur = scope; + // First search upwards through the hierarchy. + while (scope) { + NetScope*found_scope = find_scope_(scope, path, type); + if (found_scope) + return found_scope; - /* If we are looking for a module or we are not - * looking at the last path component check for - * a name match (second line). */ - if (cur->type() == NetScope::MODULE - && (type == NetScope::MODULE) - && cur->module_name()==path.peek_name()) { + // Avoid searching the unit scope twice. + if (scope == unit_scope) + unit_scope = 0; - /* Up references may match module name */ + // Special case - see IEEE 1800-2012 section 23.8.1. + if (unit_scope && is_design_unit(scope) && is_subroutine(type)) { + found_scope = find_scope_(unit_scope, path, type); + if (found_scope) + return found_scope; - } else { - cur = cur->child( path ); + unit_scope = 0; } - if (cur) return cur; + scope = scope->parent(); + } + + // If we haven't already done so, search the compilation unit scope. + if (unit_scope) { + NetScope*found_scope = find_scope_(unit_scope, path, type); + if (found_scope) + return found_scope; } // Last chance. Look for the name starting at the root. @@ -867,11 +905,6 @@ NetScope* Design::find_task(NetScope*scope, const pform_name_t&name) return 0; } -void Design::add_root_task(NetScope*tscope, PTaskFunc*tf) -{ - root_tasks_[tscope] = tf; -} - void Design::add_node(NetNode*net) { assert(net->design_ == 0); diff --git a/net_event.cc b/net_event.cc index 1aa967859..2b6eb8d35 100644 --- a/net_event.cc +++ b/net_event.cc @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000-2013 Stephen Williams (steve@icarus.com) + * Copyright (c) 2000-2017 Stephen Williams (steve@icarus.com) * * This source code is free software; you can redistribute it * and/or modify it in source code form under the terms of the GNU @@ -28,6 +28,7 @@ NetEvent::NetEvent(perm_string n) : name_(n) { + local_flag_ = false; scope_ = 0; snext_ = 0; probes_ = 0; @@ -345,7 +346,7 @@ void NetEvProbe::find_similar_probes(list&plist) } NetEvWait::NetEvWait(NetProc*pr) -: statement_(pr) +: statement_(pr), has_t0_trigger_(false) { } @@ -442,3 +443,8 @@ NetProc* NetEvWait::statement() { return statement_; } + +const NetProc* NetEvWait::statement() const +{ + return statement_; +} diff --git a/net_func_eval.cc b/net_func_eval.cc index 00790d692..f310af488 100644 --- a/net_func_eval.cc +++ b/net_func_eval.cc @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012-2016 Stephen Williams (steve@icarus.com) + * Copyright (c) 2012-2018 Stephen Williams (steve@icarus.com) * * This source code is free software; you can redistribute it * and/or modify it in source code form under the terms of the GNU @@ -23,6 +23,10 @@ # include # include "ivl_assert.h" +#if __cplusplus < 201103L +#define unique_ptr auto_ptr +#endif + using namespace std; /* @@ -1018,7 +1022,7 @@ NetExpr* NetESignal::evaluate_function(const LineInfo&loc, NetExpr* NetETernary::evaluate_function(const LineInfo&loc, map&context_map) const { - auto_ptr cval (cond_->evaluate_function(loc, context_map)); + unique_ptr cval (cond_->evaluate_function(loc, context_map)); switch (const_logical(cval.get())) { diff --git a/net_nex_input.cc b/net_nex_input.cc index 3e37b7b95..38e7e148a 100644 --- a/net_nex_input.cc +++ b/net_nex_input.cc @@ -1,5 +1,5 @@ /* - * Copyright (c) 2002-2016 Stephen Williams (steve@icarus.com) + * Copyright (c) 2002-2017 Stephen Williams (steve@icarus.com) * * This source code is free software; you can redistribute it * and/or modify it in source code form under the terms of the GNU @@ -27,29 +27,29 @@ # include "netlist.h" # include "netmisc.h" -NexusSet* NetExpr::nex_input(bool) +NexusSet* NetExpr::nex_input(bool, bool) const { cerr << get_fileline() << ": internal error: nex_input not implemented: " << *this << endl; - return 0; + return new NexusSet; } -NexusSet* NetProc::nex_input(bool) +NexusSet* NetProc::nex_input(bool, bool) const { cerr << get_fileline() << ": internal error: NetProc::nex_input not implemented" << endl; - return 0; + return new NexusSet; } -NexusSet* NetEArrayPattern::nex_input(bool rem_out) +NexusSet* NetEArrayPattern::nex_input(bool rem_out, bool search_funcs) const { NexusSet*result = new NexusSet; for (size_t idx = 0 ; idx < items_.size() ; idx += 1) { if (items_[idx]==0) continue; - NexusSet*tmp = items_[idx]->nex_input(rem_out); + NexusSet*tmp = items_[idx]->nex_input(rem_out, search_funcs); if (tmp == 0) continue; result->add(*tmp); @@ -58,32 +58,32 @@ NexusSet* NetEArrayPattern::nex_input(bool rem_out) return result; } -NexusSet* NetEBinary::nex_input(bool rem_out) +NexusSet* NetEBinary::nex_input(bool rem_out, bool search_funcs) const { - NexusSet*result = left_->nex_input(rem_out); - NexusSet*tmp = right_->nex_input(rem_out); + NexusSet*result = left_->nex_input(rem_out, search_funcs); + NexusSet*tmp = right_->nex_input(rem_out, search_funcs); result->add(*tmp); delete tmp; return result; } -NexusSet* NetEConcat::nex_input(bool rem_out) +NexusSet* NetEConcat::nex_input(bool rem_out, bool search_funcs) const { - if (parms_[0] == NULL) return NULL; - NexusSet*result = parms_[0]->nex_input(rem_out); + if (parms_[0] == NULL) return new NexusSet; + NexusSet*result = parms_[0]->nex_input(rem_out, search_funcs); for (unsigned idx = 1 ; idx < parms_.size() ; idx += 1) { if (parms_[idx] == NULL) { delete result; - return NULL; + return new NexusSet; } - NexusSet*tmp = parms_[idx]->nex_input(rem_out); + NexusSet*tmp = parms_[idx]->nex_input(rem_out, search_funcs); result->add(*tmp); delete tmp; } return result; } -NexusSet* NetEAccess::nex_input(bool) +NexusSet* NetEAccess::nex_input(bool, bool) const { return new NexusSet; } @@ -91,59 +91,55 @@ NexusSet* NetEAccess::nex_input(bool) /* * A constant has not inputs, so always return an empty set. */ -NexusSet* NetEConst::nex_input(bool) +NexusSet* NetEConst::nex_input(bool, bool) const { return new NexusSet; } -NexusSet* NetECReal::nex_input(bool) +NexusSet* NetECReal::nex_input(bool, bool) const { return new NexusSet; } -NexusSet* NetEEvent::nex_input(bool) +NexusSet* NetEEvent::nex_input(bool, bool) const { return new NexusSet; } -NexusSet* NetELast::nex_input(bool) +NexusSet* NetELast::nex_input(bool, bool) const { return new NexusSet; } -NexusSet* NetENetenum::nex_input(bool) +NexusSet* NetENetenum::nex_input(bool, bool) const { return new NexusSet; } -NexusSet* NetENew::nex_input(bool) +NexusSet* NetENew::nex_input(bool, bool) const { return new NexusSet; } -NexusSet* NetENull::nex_input(bool) +NexusSet* NetENull::nex_input(bool, bool) const { return new NexusSet; } -NexusSet* NetEProperty::nex_input(bool) +NexusSet* NetEProperty::nex_input(bool, bool) const { return new NexusSet; } -NexusSet* NetEScope::nex_input(bool) +NexusSet* NetEScope::nex_input(bool, bool) const { return new NexusSet; } -NexusSet* NetESelect::nex_input(bool rem_out) +NexusSet* NetESelect::nex_input(bool rem_out, bool search_funcs) const { - NexusSet*result = base_? base_->nex_input(rem_out) : new NexusSet(); - NexusSet*tmp = expr_->nex_input(rem_out); - if (tmp == NULL) { - delete result; - return NULL; - } + NexusSet*result = base_? base_->nex_input(rem_out, search_funcs) : new NexusSet(); + NexusSet*tmp = expr_->nex_input(rem_out, search_funcs); result->add(*tmp); delete tmp; /* See the comment for NetESignal below. */ @@ -157,30 +153,29 @@ NexusSet* NetESelect::nex_input(bool rem_out) /* * The $fread, etc. system functions can have NULL arguments. */ -NexusSet* NetESFunc::nex_input(bool rem_out) +NexusSet* NetESFunc::nex_input(bool rem_out, bool search_funcs) const { - if (parms_.empty()) - return new NexusSet; + NexusSet*result = new NexusSet; - NexusSet*result; - if (parms_[0]) result = parms_[0]->nex_input(rem_out); - else result = new NexusSet; - for (unsigned idx = 1 ; idx < parms_.size() ; idx += 1) { + if (parms_.empty()) return result; + + for (unsigned idx = 0 ; idx < parms_.size() ; idx += 1) { if (parms_[idx]) { - NexusSet*tmp = parms_[idx]->nex_input(rem_out); + NexusSet*tmp = parms_[idx]->nex_input(rem_out, search_funcs); result->add(*tmp); delete tmp; } } + return result; } -NexusSet* NetEShallowCopy::nex_input(bool) +NexusSet* NetEShallowCopy::nex_input(bool, bool) const { return new NexusSet; } -NexusSet* NetESignal::nex_input(bool rem_out) +NexusSet* NetESignal::nex_input(bool rem_out, bool search_funcs) const { /* * This is not what I would expect for the various selects (bit, @@ -194,7 +189,7 @@ NexusSet* NetESignal::nex_input(bool rem_out) /* If we have an array index add it to the sensitivity list. */ if (word_) { NexusSet*tmp; - tmp = word_->nex_input(rem_out); + tmp = word_->nex_input(rem_out, search_funcs); result->add(*tmp); delete tmp; if (warn_sens_entire_arr) { @@ -209,27 +204,44 @@ NexusSet* NetESignal::nex_input(bool rem_out) return result; } -NexusSet* NetETernary::nex_input(bool rem_out) +NexusSet* NetETernary::nex_input(bool rem_out, bool search_funcs) const { NexusSet*tmp; - NexusSet*result = cond_->nex_input(rem_out); + NexusSet*result = cond_->nex_input(rem_out, search_funcs); - tmp = true_val_->nex_input(rem_out); + tmp = true_val_->nex_input(rem_out, search_funcs); result->add(*tmp); delete tmp; - tmp = false_val_->nex_input(rem_out); + tmp = false_val_->nex_input(rem_out, search_funcs); result->add(*tmp); delete tmp; return result; } -NexusSet* NetEUFunc::nex_input(bool rem_out) +NexusSet* NetEUFunc::nex_input(bool rem_out, bool search_funcs) const { NexusSet*result = new NexusSet; for (unsigned idx = 0 ; idx < parms_.size() ; idx += 1) { - NexusSet*tmp = parms_[idx]->nex_input(rem_out); + NexusSet*tmp = parms_[idx]->nex_input(rem_out, search_funcs); + result->add(*tmp); + delete tmp; + } + + if (search_funcs) { + NetFuncDef*func = func_->func_def(); + NexusSet*tmp = func->proc()->nex_input(rem_out, search_funcs); + // Remove the function inputs + NexusSet*in = new NexusSet; + for (unsigned idx = 0 ; idx < func->port_count() ; idx += 1) { + NetNet*net = func->port(idx); + assert(net->pin_count() == 1); + in->add(net->pin(0).nexus(), 0, net->vector_width()); + } + tmp->rem(*in); + delete in; + result->add(*tmp); delete tmp; } @@ -237,21 +249,28 @@ NexusSet* NetEUFunc::nex_input(bool rem_out) return result; } -NexusSet* NetEUnary::nex_input(bool rem_out) +NexusSet* NetEUnary::nex_input(bool rem_out, bool search_funcs) const { - return expr_->nex_input(rem_out); + return expr_->nex_input(rem_out, search_funcs); } -NexusSet* NetAssign_::nex_input(bool rem_out) +NexusSet* NetAlloc::nex_input(bool, bool) const { + return new NexusSet; +} + +NexusSet* NetAssign_::nex_input(bool rem_out, bool search_funcs) const +{ + assert(! nest_); NexusSet*result = new NexusSet; + if (word_) { - NexusSet*tmp = word_->nex_input(rem_out); + NexusSet*tmp = word_->nex_input(rem_out, search_funcs); result->add(*tmp); delete tmp; } if (base_) { - NexusSet*tmp = base_->nex_input(rem_out); + NexusSet*tmp = base_->nex_input(rem_out, search_funcs); result->add(*tmp); delete tmp; } @@ -259,15 +278,21 @@ NexusSet* NetAssign_::nex_input(bool rem_out) return result; } -NexusSet* NetAssignBase::nex_input(bool rem_out) +NexusSet* NetAssignBase::nex_input(bool rem_out, bool search_funcs) const { - NexusSet*result = rval_->nex_input(rem_out); + NexusSet*result = new NexusSet; + // For the deassign and release statements there is no R-value. + if (rval_) { + NexusSet*tmp = rval_->nex_input(rem_out, search_funcs); + result->add(*tmp); + delete tmp; + } /* It is possible that the lval_ can have nex_input values. In particular, index expressions are statement inputs as well, so should be addressed here. */ for (NetAssign_*cur = lval_ ; cur ; cur = cur->more) { - NexusSet*tmp = cur->nex_input(rem_out); + NexusSet*tmp = cur->nex_input(rem_out, search_funcs); result->add(*tmp); delete tmp; } @@ -292,16 +317,15 @@ NexusSet* NetAssignBase::nex_input(bool rem_out) * In this example, "t" should not be in the input set because it is * used by the sequence as a temporary value. */ -NexusSet* NetBlock::nex_input(bool rem_out) +NexusSet* NetBlock::nex_input(bool rem_out, bool search_funcs) const { - if (last_ == 0) - return new NexusSet; + if (last_ == 0) return new NexusSet; - if (type_ != SEQU) { + if (! search_funcs && (type_ != SEQU)) { cerr << get_fileline() << ": internal error: Sorry, " << "I don't know how to synthesize fork/join blocks." << endl; - return 0; + return new NexusSet; } NetProc*cur = last_->next_; @@ -312,10 +336,10 @@ NexusSet* NetBlock::nex_input(bool rem_out) do { /* Get the inputs for the current statement. */ - NexusSet*tmp = cur->nex_input(rem_out); + NexusSet*tmp = cur->nex_input(rem_out, search_funcs); /* Add the current input set to the accumulated input set. */ - if (tmp != 0) result->add(*tmp); + result->add(*tmp); delete tmp; /* Add the current outputs to the accumulated output set if @@ -339,11 +363,9 @@ NexusSet* NetBlock::nex_input(bool rem_out) * the inputs to all the guards, and the inputs to all the guarded * statements. */ -NexusSet* NetCase::nex_input(bool rem_out) +NexusSet* NetCase::nex_input(bool rem_out, bool search_funcs) const { - NexusSet*result = expr_->nex_input(rem_out); - if (result == 0) - return 0; + NexusSet*result = expr_->nex_input(rem_out, search_funcs); for (size_t idx = 0 ; idx < items_.size() ; idx += 1) { @@ -351,8 +373,7 @@ NexusSet* NetCase::nex_input(bool rem_out) if (items_[idx].statement == 0) continue; - NexusSet*tmp = items_[idx].statement->nex_input(rem_out); - assert(tmp); + NexusSet*tmp = items_[idx].statement->nex_input(rem_out, search_funcs); result->add(*tmp); delete tmp; @@ -360,8 +381,7 @@ NexusSet* NetCase::nex_input(bool rem_out) case is special and is identified by a null guard. The default guard obviously has no input. */ if (items_[idx].guard) { - tmp = items_[idx].guard->nex_input(rem_out); - assert(tmp); + tmp = items_[idx].guard->nex_input(rem_out, search_funcs); result->add(*tmp); delete tmp; } @@ -370,24 +390,18 @@ NexusSet* NetCase::nex_input(bool rem_out) return result; } -NexusSet* NetCAssign::nex_input(bool) +NexusSet* NetCondit::nex_input(bool rem_out, bool search_funcs) const { - cerr << get_fileline() << ": internal warning: NetCAssign::nex_input()" - << " not implemented." << endl; - return new NexusSet; -} + NexusSet*result = expr_->nex_input(rem_out, search_funcs); -NexusSet* NetCondit::nex_input(bool rem_out) -{ - NexusSet*result = expr_->nex_input(rem_out); if (if_ != 0) { - NexusSet*tmp = if_->nex_input(rem_out); + NexusSet*tmp = if_->nex_input(rem_out, search_funcs); result->add(*tmp); delete tmp; } if (else_ != 0) { - NexusSet*tmp = else_->nex_input(rem_out); + NexusSet*tmp = else_->nex_input(rem_out, search_funcs); result->add(*tmp); delete tmp; } @@ -395,51 +409,85 @@ NexusSet* NetCondit::nex_input(bool rem_out) return result; } -NexusSet* NetDoWhile::nex_input(bool rem_out) +NexusSet* NetDisable::nex_input(bool, bool) const { - NexusSet*result = proc_->nex_input(rem_out); - NexusSet*tmp = cond_->nex_input(rem_out); - result->add(*tmp); - delete tmp; - return result; -} - -NexusSet* NetEvWait::nex_input(bool rem_out) -{ - NexusSet*result; - if (statement_) - result = statement_->nex_input(rem_out); - else - result = new NexusSet; - - return result; -} - -NexusSet* NetForce::nex_input(bool) -{ - cerr << get_fileline() << ": internal warning: NetForce::nex_input()" - << " not implemented." << endl; return new NexusSet; } -NexusSet* NetForLoop::nex_input(bool rem_out) +NexusSet* NetDoWhile::nex_input(bool rem_out, bool search_funcs) const { - NexusSet*result = init_expr_->nex_input(rem_out); + NexusSet*result = cond_->nex_input(rem_out, search_funcs); - NexusSet*tmp = condition_->nex_input(rem_out); - result->add(*tmp); - delete tmp; + if (proc_) { + NexusSet*tmp = proc_->nex_input(rem_out, search_funcs); + result->add(*tmp); + delete tmp; + } - tmp = statement_->nex_input(rem_out); - result->add(*tmp); - delete tmp; + return result; +} - tmp = step_statement_->nex_input(rem_out); - result->add(*tmp); - delete tmp; +NexusSet* NetEvTrig::nex_input(bool, bool) const +{ + return new NexusSet; +} + +NexusSet* NetEvWait::nex_input(bool rem_out, bool search_funcs) const +{ + NexusSet*result = new NexusSet; + + if (statement_) { + NexusSet*tmp = statement_->nex_input(rem_out, search_funcs); + result->add(*tmp); + delete tmp; + } + + return result; +} + +NexusSet* NetForever::nex_input(bool rem_out, bool search_funcs) const +{ + NexusSet*result = new NexusSet; + + if (statement_) { + NexusSet*tmp = statement_->nex_input(rem_out, search_funcs); + result->add(*tmp); + delete tmp; + } + + return result; +} + +NexusSet* NetForLoop::nex_input(bool rem_out, bool search_funcs) const +{ + NexusSet*result = new NexusSet; + + if (init_expr_) { + NexusSet*tmp = init_expr_->nex_input(rem_out, search_funcs); + result->add(*tmp); + delete tmp; + } + + if (condition_) { + NexusSet*tmp = condition_->nex_input(rem_out, search_funcs); + result->add(*tmp); + delete tmp; + } + + if (step_statement_) { + NexusSet*tmp = step_statement_->nex_input(rem_out, search_funcs); + result->add(*tmp); + delete tmp; + } + + if (statement_) { + NexusSet*tmp = statement_->nex_input(rem_out, search_funcs); + result->add(*tmp); + delete tmp; + } if (gn_shared_loop_index_flag) { - tmp = new NexusSet(); + NexusSet*tmp = new NexusSet(); for (unsigned idx = 0 ; idx < index_->pin_count() ; idx += 1) tmp->add(index_->pin(idx).nexus(), 0, index_->vector_width()); @@ -450,10 +498,9 @@ NexusSet* NetForLoop::nex_input(bool rem_out) return result; } -NexusSet* NetForever::nex_input(bool rem_out) +NexusSet* NetFree::nex_input(bool, bool) const { - NexusSet*result = statement_->nex_input(rem_out); - return result; + return new NexusSet; } /* @@ -465,36 +512,44 @@ NexusSet* NetForever::nex_input(bool rem_out) * include the input set of the because it does not affect the * result. The statement can be omitted. */ -NexusSet* NetPDelay::nex_input(bool rem_out) +NexusSet* NetPDelay::nex_input(bool rem_out, bool search_funcs) const { - if (statement_ == 0) return 0; - NexusSet*result = statement_->nex_input(rem_out); + NexusSet*result = new NexusSet; + + if (statement_) { + NexusSet*tmp = statement_->nex_input(rem_out, search_funcs); + result->add(*tmp); + delete tmp; + } + return result; } -NexusSet* NetRepeat::nex_input(bool rem_out) +NexusSet* NetRepeat::nex_input(bool rem_out, bool search_funcs) const { - NexusSet*result = statement_->nex_input(rem_out); - NexusSet*tmp = expr_->nex_input(rem_out); - result->add(*tmp); - delete tmp; + NexusSet*result = expr_->nex_input(rem_out, search_funcs); + + if (statement_) { + NexusSet*tmp = statement_->nex_input(rem_out, search_funcs); + result->add(*tmp); + delete tmp; + } + return result; } /* * The $display, etc. system tasks can have NULL arguments. */ -NexusSet* NetSTask::nex_input(bool rem_out) +NexusSet* NetSTask::nex_input(bool rem_out, bool search_funcs) const { - if (parms_.empty()) - return new NexusSet; + NexusSet*result = new NexusSet; - NexusSet*result; - if (parms_[0]) result = parms_[0]->nex_input(rem_out); - else result = new NexusSet; - for (unsigned idx = 1 ; idx < parms_.size() ; idx += 1) { + if (parms_.empty()) return result; + + for (unsigned idx = 0 ; idx < parms_.size() ; idx += 1) { if (parms_[idx]) { - NexusSet*tmp = parms_[idx]->nex_input(rem_out); + NexusSet*tmp = parms_[idx]->nex_input(rem_out, search_funcs); result->add(*tmp); delete tmp; } @@ -508,16 +563,20 @@ NexusSet* NetSTask::nex_input(bool rem_out) * parameters to consider, because the compiler already removed them * and converted them to blocking assignments. */ -NexusSet* NetUTask::nex_input(bool) +NexusSet* NetUTask::nex_input(bool, bool) const { return new NexusSet; } -NexusSet* NetWhile::nex_input(bool rem_out) +NexusSet* NetWhile::nex_input(bool rem_out, bool search_funcs) const { - NexusSet*result = proc_->nex_input(rem_out); - NexusSet*tmp = cond_->nex_input(rem_out); - result->add(*tmp); - delete tmp; + NexusSet*result = cond_->nex_input(rem_out, search_funcs); + + if (proc_) { + NexusSet*tmp = proc_->nex_input(rem_out, search_funcs); + result->add(*tmp); + delete tmp; + } + return result; } diff --git a/net_nex_output.cc b/net_nex_output.cc index 194947955..9c1d32e10 100644 --- a/net_nex_output.cc +++ b/net_nex_output.cc @@ -1,5 +1,5 @@ /* - * Copyright (c) 2002-2013 Stephen Williams (steve@icarus.com) + * Copyright (c) 2002-2017 Stephen Williams (steve@icarus.com) * * This source code is free software; you can redistribute it * and/or modify it in source code form under the terms of the GNU @@ -36,8 +36,13 @@ void NetProc::nex_output(NexusSet&) << endl; } +void NetAlloc::nex_output(NexusSet&) +{ +} + void NetAssign_::nex_output(NexusSet&out) { + assert(! nest_); assert(sig_); unsigned use_word = 0; unsigned use_base = 0; @@ -89,8 +94,7 @@ void NetAssignBase::nex_output(NexusSet&out) void NetBlock::nex_output(NexusSet&out) { - if (last_ == 0) - return; + if (last_ == 0) return; NetProc*cur = last_; do { @@ -104,10 +108,8 @@ void NetCase::nex_output(NexusSet&out) for (size_t idx = 0 ; idx < items_.size() ; idx += 1) { // Empty statements clearly have no output. - if (items_[idx].statement == 0) - continue; + if (items_[idx].statement == 0) continue; - assert(items_[idx].statement); items_[idx].statement->nex_output(out); } @@ -115,22 +117,31 @@ void NetCase::nex_output(NexusSet&out) void NetCondit::nex_output(NexusSet&out) { - if (if_ != 0) - if_->nex_output(out); - if (else_ != 0) - else_->nex_output(out); + if (if_) if_->nex_output(out); + if (else_) else_->nex_output(out); +} + +void NetDisable::nex_output(NexusSet&) +{ } void NetDoWhile::nex_output(NexusSet&out) { - if (proc_ != 0) - proc_->nex_output(out); + if (proc_) proc_->nex_output(out); +} + +void NetEvTrig::nex_output(NexusSet&) +{ } void NetEvWait::nex_output(NexusSet&out) { - assert(statement_); - statement_->nex_output(out); + if (statement_) statement_->nex_output(out); +} + +void NetForever::nex_output(NexusSet&out) +{ + if (statement_) statement_->nex_output(out); } void NetForLoop::nex_output(NexusSet&out) @@ -138,11 +149,20 @@ void NetForLoop::nex_output(NexusSet&out) if (statement_) statement_->nex_output(out); } +void NetFree::nex_output(NexusSet&) +{ +} + void NetPDelay::nex_output(NexusSet&out) { if (statement_) statement_->nex_output(out); } +void NetRepeat::nex_output(NexusSet&out) +{ + if (statement_) statement_->nex_output(out); +} + /* * For the purposes of synthesis, system task calls have no output at * all. This is OK because most system tasks are not synthesizable in @@ -163,6 +183,5 @@ void NetUTask::nex_output(NexusSet&) void NetWhile::nex_output(NexusSet&out) { - if (proc_ != 0) - proc_->nex_output(out); + if (proc_) proc_->nex_output(out); } diff --git a/net_scope.cc b/net_scope.cc index 42eab5a51..b9873786e 100644 --- a/net_scope.cc +++ b/net_scope.cc @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000-2016 Stephen Williams (steve@icarus.com) + * Copyright (c) 2000-2017 Stephen Williams (steve@icarus.com) * Copyright (c) 2016 CERN Michele Castellana (michele.castellana@cern.ch) * * This source code is free software; you can redistribute it @@ -112,10 +112,10 @@ void Definitions::add_class(netclass_t*net_class) * in question. */ -NetScope::NetScope(NetScope*up, const hname_t&n, NetScope::TYPE t, bool nest, - bool program, bool interface) +NetScope::NetScope(NetScope*up, const hname_t&n, NetScope::TYPE t, NetScope*in_unit, + bool nest, bool program, bool interface, bool compilation_unit) : type_(t), name_(n), nested_module_(nest), program_block_(program), - is_interface_(interface), up_(up) + is_interface_(interface), is_unit_(compilation_unit), unit_(in_unit), up_(up) { events_ = 0; lcounter_ = 0; @@ -124,6 +124,9 @@ NetScope::NetScope(NetScope*up, const hname_t&n, NetScope::TYPE t, bool nest, calls_stask_ = false; in_final_ = false; + if (compilation_unit) + unit_ = this; + if (up) { assert(t!=CLASS); need_const_func_ = up->need_const_func_; @@ -133,6 +136,8 @@ NetScope::NetScope(NetScope*up, const hname_t&n, NetScope::TYPE t, bool nest, time_from_timescale_ = up->time_from_timescale(); // Need to check for duplicate names? up_->children_[name_] = this; + if (unit_ == 0) + unit_ = up_->unit_; } else { need_const_func_ = false; is_const_func_ = false; @@ -210,6 +215,8 @@ const netenum_t*NetScope::find_enumeration_for_name(perm_string name) NetEConstEnum*tmp = cur_scope->enum_names_[name]; if (tmp) break; cur_scope = cur_scope->parent(); + if (cur_scope == 0) + cur_scope = unit_; } assert(cur_scope); @@ -304,16 +311,16 @@ bool NetScope::auto_name(const char*prefix, char pad, const char* suffix) */ bool NetScope::replace_parameter(perm_string key, PExpr*val, NetScope*scope) { - bool flag = false; + if (parameters.find(key) == parameters.end()) + return false; - if (parameters.find(key) != parameters.end()) { - param_expr_t&ref = parameters[key]; - ref.val_expr = val; - ref.val_scope = scope; - flag = true; - } + param_expr_t&ref = parameters[key]; + if (ref.local_flag) + return false; - return flag; + ref.val_expr = val; + ref.val_scope = scope; + return true; } bool NetScope::make_parameter_unannotatable(perm_string key) @@ -364,12 +371,7 @@ const NetExpr* NetScope::get_parameter(Design*des, msb = 0; lsb = 0; const NetExpr*tmp = enumeration_expr(key); - if (tmp) return tmp; - - tmp = des->enumeration_expr(key); - if (tmp) return tmp; - - return 0; + return tmp; } NetScope::param_ref_t NetScope::find_parameter(perm_string key) @@ -386,11 +388,6 @@ NetScope::param_ref_t NetScope::find_parameter(perm_string key) return idx; } -NetScope::TYPE NetScope::type() const -{ - return type_; -} - void NetScope::print_type(ostream&stream) const { switch (type_) { @@ -657,15 +654,11 @@ netclass_t*NetScope::find_class(perm_string name) if (type_==CLASS && name_==hname_t(name)) return class_def_; - // Look for the class that directly within this scope. + // Look for the class directly within this scope. map::const_iterator cur = classes_.find(name); if (cur != classes_.end()) return cur->second; - // If this is a module scope, then look no further. - if (type_==MODULE) - return 0; - if (up_==0 && type_==CLASS) { assert(class_def_); @@ -673,12 +666,16 @@ netclass_t*NetScope::find_class(perm_string name) return def_parent->find_class(name); } - // If there is no further to look, ... - if (up_ == 0) - return 0; - // Try looking up for the class. - return up_->find_class(name); + if (up_!=0 && type_!=MODULE) + return up_->find_class(name); + + // Try the compilation unit. + if (unit_ != 0) + return unit_->find_class(name); + + // Nowhere left to try... + return 0; } /* diff --git a/netclass.cc b/netclass.cc index 0ae3ba1dc..7e69a604d 100644 --- a/netclass.cc +++ b/netclass.cc @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012-2014 Stephen Williams (steve@icarus.com) + * Copyright (c) 2012-2017 Stephen Williams (steve@icarus.com) * * This source code is free software; you can redistribute it * and/or modify it in source code form under the terms of the GNU @@ -165,7 +165,8 @@ bool netclass_t::test_for_missing_initializers() const NetScope*netclass_t::method_from_name(perm_string name) const { NetScope*task = class_scope_->child( hname_t(name) ); - if (task == 0) return 0; + if ((task == 0) && super_) + task = super_->method_from_name(name); return task; } diff --git a/netlist.cc b/netlist.cc index d611f2b03..c0650959e 100644 --- a/netlist.cc +++ b/netlist.cc @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998-2016 Stephen Williams (steve@icarus.com) + * Copyright (c) 1998-2017 Stephen Williams (steve@icarus.com) * * This source code is free software; you can redistribute it * and/or modify it in source code form under the terms of the GNU @@ -24,6 +24,7 @@ # include # include # include +# include # include "compiler.h" # include "netlist.h" # include "netmisc.h" @@ -2768,7 +2769,7 @@ static DelayType delay_type_from_expr(const NetExpr*expr) * The looping structures can use the same basic code so put it here * instead of duplicating it for each one (repeat and while). */ -static DelayType get_loop_delay_type(const NetExpr*expr, const NetProc*proc) +static DelayType get_loop_delay_type(const NetExpr*expr, const NetProc*proc, bool print_delay) { DelayType result; @@ -2779,12 +2780,20 @@ static DelayType get_loop_delay_type(const NetExpr*expr, const NetProc*proc) break; /* We have a constant true expression so the body always runs. */ case DEFINITE_DELAY: - result = proc->delay_type(); + if (proc) { + result = proc->delay_type(print_delay); + } else { + result = NO_DELAY; + } break; /* We don't know if the body will run so reduce a DEFINITE_DELAY * to a POSSIBLE_DELAY. All other stay the same. */ case POSSIBLE_DELAY: - result = combine_delays(NO_DELAY, proc->delay_type()); + if (proc) { + result = combine_delays(NO_DELAY, proc->delay_type(print_delay)); + } else { + result = NO_DELAY; + } break; /* This should never happen since delay_type_from_expr() only * returns three different values. */ @@ -2797,25 +2806,40 @@ static DelayType get_loop_delay_type(const NetExpr*expr, const NetProc*proc) } /* The default object does not have any delay. */ -DelayType NetProc::delay_type() const +DelayType NetProc::delay_type(bool /* print_delay */ ) const { return NO_DELAY; } -DelayType NetBlock::delay_type() const +DelayType NetBlock::delay_type(bool print_delay) const { - DelayType result = NO_DELAY; + // A join_none has no delay. + if (type() == PARA_JOIN_NONE) return NO_DELAY; - for (const NetProc*cur = proc_first(); cur; cur = proc_next(cur)) { - DelayType dt = cur->delay_type(); - if (dt > result) result = dt; - if (dt == DEFINITE_DELAY) break; + DelayType result; + // A join_any has the minimum delay. + if (type() == PARA_JOIN_ANY) { + result = DEFINITE_DELAY; + for (const NetProc*cur = proc_first(); cur; cur = proc_next(cur)) { + DelayType dt = cur->delay_type(print_delay); + if (dt < result) result = dt; + if ((dt == NO_DELAY) && !print_delay) break; + } + + // A begin or join has the maximum delay. + } else { + result = NO_DELAY; + for (const NetProc*cur = proc_first(); cur; cur = proc_next(cur)) { + DelayType dt = cur->delay_type(print_delay); + if (dt > result) result = dt; + if ((dt == DEFINITE_DELAY) && !print_delay) break; + } } return result; } -DelayType NetCase::delay_type() const +DelayType NetCase::delay_type(bool print_delay) const { DelayType result = NO_DELAY; bool def_stmt = false; @@ -2823,7 +2847,7 @@ DelayType NetCase::delay_type() const for (unsigned idx = 0; idx < nstmts; idx += 1) { if (!expr(idx)) def_stmt = true; - DelayType dt = stat(idx) ? stat(idx)->delay_type() : NO_DELAY; + DelayType dt = stat(idx) ? stat(idx)->delay_type(print_delay) : NO_DELAY; if (idx == 0) { result = dt; } else { @@ -2831,6 +2855,7 @@ DelayType NetCase::delay_type() const } } +// FIXME: If all the cases are covered (e.g. an enum) then this is not true. /* If we don't have a default statement we don't know for sure * that we have a delay. */ if (!def_stmt) result = combine_delays(NO_DELAY, result); @@ -2838,74 +2863,636 @@ DelayType NetCase::delay_type() const return result; } -DelayType NetCondit::delay_type() const +DelayType NetCondit::delay_type(bool print_delay) const { - DelayType if_type = if_ ? if_->delay_type() : NO_DELAY; - DelayType el_type = else_? else_->delay_type() : NO_DELAY; + DelayType if_type = if_ ? if_->delay_type(print_delay) : NO_DELAY; + DelayType el_type = else_? else_->delay_type(print_delay) : NO_DELAY; return combine_delays(if_type, el_type); } /* * A do/while will execute the body at least once. */ -DelayType NetDoWhile::delay_type() const +DelayType NetDoWhile::delay_type(bool print_delay) const { - ivl_assert(*this, proc_); - return proc_->delay_type(); + if (proc_) return proc_->delay_type(print_delay); + + return ZERO_DELAY; } -DelayType NetEvWait::delay_type() const +DelayType NetEvWait::delay_type(bool print_delay) const { + if (print_delay) { + cerr << get_fileline() << ": error: an event control is not allowed " + "in an always_comb, always_ff or always_latch process." + << endl; + } + return DEFINITE_DELAY; } -DelayType NetForever::delay_type() const +DelayType NetForever::delay_type(bool print_delay) const { - ivl_assert(*this, statement_); - return statement_->delay_type(); + if (statement_) return statement_->delay_type(print_delay); + + return ZERO_DELAY; } -DelayType NetForLoop::delay_type() const +DelayType NetForLoop::delay_type(bool print_delay) const { - ivl_assert(*this, statement_); - return get_loop_delay_type(condition_, statement_); + return get_loop_delay_type(condition_, statement_, print_delay); } -DelayType NetPDelay::delay_type() const +DelayType NetPDelay::delay_type(bool print_delay) const { + if (print_delay) { + cerr << get_fileline() << ": error: a blocking delay is not allowed " + "in an always_comb, always_ff or always_latch process." + << endl; + } + if (expr_) { - return delay_type_from_expr(expr_); - } else { - if (delay() > 0) { - return DEFINITE_DELAY; + if (statement_) { + return combine_delays(delay_type_from_expr(expr_), + statement_->delay_type(print_delay)); } else { - if (statement_) { - return statement_->delay_type(); - } else { - return NO_DELAY; - } + return delay_type_from_expr(expr_); + } + } + + if (delay() > 0) return DEFINITE_DELAY; + + if (statement_) { + return combine_delays(ZERO_DELAY, + statement_->delay_type(print_delay)); + } else { + return ZERO_DELAY; + } +} + +DelayType NetRepeat::delay_type(bool print_delay) const +{ + return get_loop_delay_type(expr_, statement_, print_delay); +} + +DelayType NetTaskDef::delay_type(bool print_delay) const +{ + if (proc_) { + return proc_->delay_type(print_delay); + } else { + return NO_DELAY; + } +} + +DelayType NetUTask::delay_type(bool print_delay) const +{ + return task()->task_def()->delay_type(print_delay); +} + +static bool do_expr_event_match(const NetExpr*expr, const NetEvWait*evwt) +{ + // The event wait should only have a single event. + if (evwt->nevents() != 1) return false; + // The event should have a single probe. + const NetEvent *evt = evwt->event(0); + if (evt->nprobe() != 1) return false; + // The probe should be for any edge. + const NetEvProbe *prb = evt->probe(0); + if (prb->edge() != NetEvProbe::ANYEDGE) return false; + // Create a NexusSet from the event probe signals. + NexusSet *ns_evwt = new NexusSet; + for (unsigned idx =0; idx < prb->pin_count(); idx += 1) { + if (! prb->pin(idx).is_linked()) { + delete ns_evwt; + return false; + } + // Casting away const is safe since this nexus set is only being read. + ns_evwt->add(const_cast (prb->pin(idx).nexus()), + 0, prb->pin(idx).nexus()->vector_width()); + } + // Get the NexusSet for the expression. + NexusSet *ns_expr = expr->nex_input(); + // Make sure the event and expression NexusSets match exactly. + if (ns_evwt->size() != ns_expr->size()) { + delete ns_evwt; + delete ns_expr; + return false; + } + ns_expr->rem(*ns_evwt); + delete ns_evwt; + if (ns_expr->size() != 0) { + delete ns_expr; + return false; + } + delete ns_expr; + + return true; +} + +static bool while_is_wait(const NetExpr*expr, const NetProc*stmt) +{ + if (const NetEvWait*evwt = dynamic_cast(stmt)) { + if (evwt->statement()) return false; + const NetEBComp*cond = dynamic_cast(expr); + if (! cond) return false; + if (cond->op() != 'N') return false; + const NetEConst*cval = dynamic_cast(cond->right()); + if (! cval) return false; + const verinum val = cval->value(); + if (val.len() != 1) return false; + if (val.get(0) != verinum::V1) return false; + if (! do_expr_event_match(cond->left(), evwt)) return false; + if (evwt->get_lineno() != cond->get_lineno()) return false; + if (evwt->get_file() != cond->get_file()) return false; + return true; + } + return false; +} + +DelayType NetWhile::delay_type(bool print_delay) const +{ + // If the wait was a constant value the compiler already removed it + // so we know we can only have a possible delay. + if (while_is_wait(cond_, proc_)) { + if (print_delay) { + cerr << get_fileline() << ": error: a wait statement is " + "not allowed in an " + "always_comb, always_ff or always_latch process." + << endl; + } + return POSSIBLE_DELAY; + } + return get_loop_delay_type(cond_, proc_, print_delay); +} + +/* + * These are the check_synth() functions. They are used to print + * a warning if the item is not synthesizable. + */ +static const char * get_process_type_as_string(ivl_process_type_t pr_type) +{ + switch (pr_type) { + case IVL_PR_ALWAYS_COMB: + return "in an always_comb process."; + break; + case IVL_PR_ALWAYS_FF: + return "in an always_ff process."; + break; + case IVL_PR_ALWAYS_LATCH: + return "in an always_latch process."; + break; + default: + assert(0); + return 0; + } +} + +static void print_synth_warning(const NetProc *net_proc, const char *name, + ivl_process_type_t pr_type) +{ + cerr << net_proc->get_fileline() << ": warning: " << name + << " statement cannot be synthesized " + << get_process_type_as_string(pr_type) << endl; +} + +static void check_if_logic_l_value(const NetAssignBase *base, + ivl_process_type_t pr_type) +{ + if (base->l_val_count() != 1) return; + + const NetAssign_*lval = base->l_val(0); + if (! lval) return; + + NetNet*sig = lval->sig(); + if (! sig) return; + + if ((sig->data_type() != IVL_VT_BOOL) && + (sig->data_type() != IVL_VT_LOGIC)) { + cerr << base->get_fileline() << ": warning: Assinging to a " + "non-integral variable ("<< sig->name() + << ") cannot be synthesized " + << get_process_type_as_string(pr_type) << endl; + } +} + +/* By default elements can be synthesized or ignored. */ +bool NetProc::check_synth(ivl_process_type_t /* pr_type */, + const NetScope* /* scope */ ) const +{ + return false; +} + +// FIXME: User function calls still need to be checked (NetEUFunc). +// : Non-constant system functions need a warning (NetESFunc). +// : Constant functions should already be elaborated. + +/* By default assign elements can be synthesized. */ +bool NetAssignBase::check_synth(ivl_process_type_t /* pr_type */, + const NetScope* /* scope */ ) const +{ + return false; +} + +bool NetAssign::check_synth(ivl_process_type_t pr_type, + const NetScope* /* scope */ ) const +{ + check_if_logic_l_value(this, pr_type); + +// FIXME: Check that ff/latch only use this for internal signals. + return false; +} + +bool NetAssignNB::check_synth(ivl_process_type_t pr_type, + const NetScope* /* scope */ ) const +{ + bool result = false; + if (pr_type == IVL_PR_ALWAYS_COMB) { + cerr << get_fileline() << ": warning: A non-blocking assignment " + "should not be used in an always_comb process." << endl; + } + + if (event_) { + cerr << get_fileline() << ": error: A non-blocking assignment " + "cannot be synthesized with an event control " + << get_process_type_as_string(pr_type) << endl; + result = true; + } + + check_if_logic_l_value(this, pr_type); + + return result; +} + +bool NetBlock::check_synth(ivl_process_type_t pr_type, + const NetScope* scope) const +{ + bool result = false; + // Only a begin/end can be synthesized. + if (type() != SEQU) { + cerr << get_fileline() << ": error: A fork/"; + switch (type()) { + case PARA: + cerr << "join"; + break; + case PARA_JOIN_ANY: + cerr << "join_any"; + break; + case PARA_JOIN_NONE: + cerr << "join_none"; + break; + default: + assert(0); + } + cerr << " statement cannot be synthesized " + << get_process_type_as_string(pr_type) << endl; + result = true; + } + + const NetScope*save_scope = scope; + if (subscope()) scope = subscope(); + if (scope != save_scope) { + result |= scope->check_synth(pr_type, scope); + } + for (const NetProc*cur = proc_first(); cur; cur = proc_next(cur)) { + result |= cur->check_synth(pr_type, scope); + } + scope = save_scope; + return result; +} + +bool NetCase::check_synth(ivl_process_type_t pr_type, + const NetScope* scope) const +{ + bool result = false; + for (unsigned idx = 0; idx < nitems(); idx += 1) { + if (stat(idx)) result |= stat(idx)->check_synth(pr_type, scope); + } +// FIXME: Check for ff/latch/comb structures. + return result; +} + +bool NetCAssign::check_synth(ivl_process_type_t pr_type, + const NetScope* /* scope */ ) const +{ + print_synth_warning(this, "A procedural assign", pr_type); + return false; +} + +bool NetCondit::check_synth(ivl_process_type_t pr_type, + const NetScope* scope) const +{ + bool result = false; + if (if_) result |= if_->check_synth(pr_type, scope); + if (else_) result |= else_->check_synth(pr_type, scope); +// FIXME: Check for ff/latch/comb structures. + return result; +} + +bool NetDeassign::check_synth(ivl_process_type_t pr_type, + const NetScope* /* scope */ ) const +{ + print_synth_warning(this, "A procedural deassign", pr_type); + return false; +} + +bool NetDisable::check_synth(ivl_process_type_t pr_type, + const NetScope* scope) const +{ + while (scope) { + if (scope != target_) scope = scope->parent(); + else break; + } + + + if (! scope) { + cerr << get_fileline() << ": warning: A disable statement can " + "only be synthesized when disabling an enclosing block " + << get_process_type_as_string(pr_type) << endl; + } + return false; +} + +bool NetDoWhile::check_synth(ivl_process_type_t pr_type, + const NetScope* scope) const +{ + bool result = false; + print_synth_warning(this, "A do/while", pr_type); + if (proc_) result |= proc_->check_synth(pr_type, scope); + return result; +} + +bool NetEvTrig::check_synth(ivl_process_type_t pr_type, + const NetScope* /* scope */ ) const +{ + print_synth_warning(this, "An event trigger", pr_type); + return false; +} + +// The delay check above has already marked this as an error. +bool NetEvWait::check_synth(ivl_process_type_t pr_type, + const NetScope* scope) const +{ + bool result = false; + if (statement_) result |= statement_->check_synth(pr_type, scope); + return result; +} + +bool NetForce::check_synth(ivl_process_type_t pr_type, + const NetScope* /* scope */ ) const +{ + print_synth_warning(this, "A force", pr_type); + return false; +} + +bool NetForever::check_synth(ivl_process_type_t pr_type, + const NetScope* scope) const +{ + bool result = false; + print_synth_warning(this, "A forever", pr_type); + if (statement_) result |= statement_->check_synth(pr_type, scope); + return result; +} + +/* + * A bunch of private routines to verify that a for loop has the correct + * structure for synthesis. + */ +static void print_for_idx_warning(const NetProc*proc, const char*check, + ivl_process_type_t pr_type, NetNet*idx) +{ + cerr << proc->get_fileline() << ": warning: A for statement must use " + "the index (" << idx->name() << ") in the " << check + << " expression to be synthesized " + << get_process_type_as_string(pr_type) << endl; +} + +static void check_for_const_synth(const NetExpr*expr, const NetProc*proc, + const char*str, ivl_process_type_t pr_type) +{ + if (! dynamic_cast(expr)) { + cerr << proc-> get_fileline() << ": warning: A for " + "statement must " << str + << " value to be synthesized " + << get_process_type_as_string(pr_type) << endl; + } +} + +static void check_for_bin_synth(const NetExpr*left,const NetExpr*right, + const char*str, const char*check, + const NetProc*proc, + ivl_process_type_t pr_type, NetNet*index) +{ + const NetESignal*lsig = dynamic_cast(left); + const NetESignal*rsig = dynamic_cast(right); + + if (lsig && (lsig->sig() == index)) { + check_for_const_synth(right, proc, str, pr_type); + } else if (rsig && (rsig->sig() == index)) { + check_for_const_synth(left, proc, str, pr_type); + } else { + print_for_idx_warning(proc, check, pr_type, index); + } +} + +static void print_for_step_warning(const NetProc*proc, + ivl_process_type_t pr_type) +{ + cerr << proc->get_fileline() << ": warning: A for statement step must " + "be a simple assignment statement to be synthesized " + << get_process_type_as_string(pr_type) << endl; +} + +static void print_for_step_warning(const NetProc*proc, + ivl_process_type_t pr_type, NetNet*idx) +{ + cerr << proc->get_fileline() << ": warning: A for statement step must " + "be an assignment to the index variable (" + << idx->name() << ") to be synthesized " + << get_process_type_as_string(pr_type) << endl; +} + +static void check_for_bstep_synth(const NetExpr*expr, const NetProc*proc, + ivl_process_type_t pr_type, NetNet*index) +{ + if (const NetECast*tmp = dynamic_cast(expr)) { + expr = tmp->expr(); + } + + if (const NetEBAdd*tmp = dynamic_cast(expr)) { + check_for_bin_synth(tmp->left(), tmp->right(), + "change by a constant", "step", proc, pr_type, + index); + } else { + cerr << proc->get_fileline() << ": warning: A for statement " + "step must be a simple binary +/- " + "to be synthesized " + << get_process_type_as_string(pr_type) << endl; + } +} + +static void check_for_step_synth(const NetAssign*assign, const NetProc*proc, + ivl_process_type_t pr_type, NetNet*index) +{ + if (assign->l_val_count() != 1) { + print_for_step_warning(proc, pr_type); + } else if (assign->l_val(0)->sig() != index) { + print_for_step_warning(proc, pr_type, index); + } else { + switch (assign->assign_operator()) { + case '+': + case '-': + check_for_const_synth(assign->rval(), proc, + "have a constant step", pr_type); + break; + case 0: + check_for_bstep_synth(assign->rval(), proc, pr_type, index); + break; + default: + cerr << proc->get_fileline() << ": warning: A for statement " + "step does not support operator '" + << assign->assign_operator() + << "' it must be +/- to be synthesized " + << get_process_type_as_string(pr_type) << endl; + break; } } } -DelayType NetRepeat::delay_type() const +bool NetForLoop::check_synth(ivl_process_type_t pr_type, + const NetScope* scope) const { - ivl_assert(*this, statement_); - return get_loop_delay_type(expr_, statement_); + bool result = false; + +// FIXME: What about an enum (NetEConstEnum)? + if (! dynamic_cast(init_expr_)) { + cerr << get_fileline() << ": warning: A for statement must " + "have a constant initial value to be synthesized " + << get_process_type_as_string(pr_type) << endl; + } + +// FIXME: Do the following also need to be supported in the condition? +// It would seem like they are hard to use to find the bounds. +// From NetEBinary +// What about NetEBits sig & constant, etc. +// From NetEUnary +// What about NetEUBits ! sig or ! (sig == constat) +// What about NetEUReduce &signal + if (const NetESignal*tmp = dynamic_cast(condition_)) { + if (tmp->sig() != index_) { + print_for_idx_warning(this, "condition", pr_type, index_); + } + } else if (const NetEBComp*cmp = dynamic_cast(condition_)) { + check_for_bin_synth(cmp->left(), cmp->right(), + "compare against a constant", "condition", + this, pr_type, index_); + } else { + print_for_idx_warning(this, "condition", pr_type, index_); + } + + if (const NetAssign*tmp = dynamic_cast(step_statement_)) { + check_for_step_synth(tmp, this, pr_type, index_); + } else { + print_for_step_warning(this, pr_type); + } + + if (statement_) result |= statement_->check_synth(pr_type, scope); + return result; } -DelayType NetTaskDef::delay_type() const +// The delay check above has already marked this as an error. +bool NetPDelay::check_synth(ivl_process_type_t /* pr_type */, + const NetScope* /* scope */ ) const { - return proc_->delay_type(); + return false; } -DelayType NetUTask::delay_type() const +bool NetRelease::check_synth(ivl_process_type_t pr_type, + const NetScope* /* scope */ ) const { - return task()->task_def()->delay_type(); + print_synth_warning(this, "A release", pr_type); + return false; } -DelayType NetWhile::delay_type() const +bool NetRepeat::check_synth(ivl_process_type_t pr_type, + const NetScope* scope) const { - ivl_assert(*this, proc_); - return get_loop_delay_type(cond_, proc_); + bool result = false; + print_synth_warning(this, "A repeat", pr_type); + if (statement_) result |= statement_->check_synth(pr_type, scope); + return result; +} + +bool NetScope::check_synth(ivl_process_type_t pr_type, + const NetScope* /* scope */) const +{ + bool result = false; + // Skip local events/signals + for (NetEvent*cur = events_ ; cur ; cur = cur->snext_) { + if (cur->local_flag()) continue; + cerr << cur->get_fileline() << ": warning: An event (" + << cur->name() << ") cannot be synthesized " + << get_process_type_as_string(pr_type) << endl; + } + for (signals_map_iter_t cur = signals_map_.begin(); + cur != signals_map_.end() ; ++ cur) { + const NetNet*sig = cur->second; + if ((sig->data_type() != IVL_VT_BOOL) && + (sig->data_type() != IVL_VT_LOGIC)) { + cerr << sig->get_fileline() << ": warning: A non-integral " + "variable (" << sig->name() << ") cannot be " + "synthesized " + << get_process_type_as_string(pr_type) << endl; + } + } + return result; +} + +bool NetSTask::check_synth(ivl_process_type_t pr_type, + const NetScope* /* scope */) const +{ + if (strcmp(name(), "$ivl_darray_method$delete") == 0) { + cerr << get_fileline() << ": warning: Dynamic array " + "delete method cannot be synthesized " + << get_process_type_as_string(pr_type) << endl; + } else { + cerr << get_fileline() << ": warning: System task (" + << name() << ") cannot be synthesized " + << get_process_type_as_string(pr_type) << endl; + } + return false; +} + +bool NetTaskDef::check_synth(ivl_process_type_t pr_type, + const NetScope* /* scope */) const +{ + bool result = false; + const NetScope *tscope = this->scope(); + result |= tscope->check_synth(pr_type, tscope); + if (! tscope->is_auto()) { + cerr << tscope->get_def_file() << ":" + << tscope->get_def_lineno() + << ": warning: user task (" << tscope->basename() + << ") must be automatic to be synthesized " + << get_process_type_as_string(pr_type) << endl; + } + if (proc_) result |= proc_->check_synth(pr_type, tscope); + return result; +} + +bool NetUTask::check_synth(ivl_process_type_t pr_type, + const NetScope* scope) const +{ + return task()->task_def()->check_synth(pr_type, scope); +} + +bool NetWhile::check_synth(ivl_process_type_t pr_type, + const NetScope* scope) const +{ + bool result = false; + // A wait is already maked as an error in the delay check above. + if (! while_is_wait(cond_, proc_)) { + print_synth_warning(this, "A while", pr_type); + if (proc_) result |= proc_->check_synth(pr_type, scope); + } + return result; } diff --git a/netlist.h b/netlist.h index 57acafd64..31cfc889e 100644 --- a/netlist.h +++ b/netlist.h @@ -1,7 +1,7 @@ #ifndef IVL_netlist_H #define IVL_netlist_H /* - * Copyright (c) 1998-2016 Stephen Williams (steve@icarus.com) + * Copyright (c) 1998-2017 Stephen Williams (steve@icarus.com) * Copyright CERN 2013 / Stephen Williams (steve@icarus.com) * * This source code is free software; you can redistribute it @@ -927,10 +927,13 @@ class NetScope : public Definitions, public Attrib { public: enum TYPE { MODULE, CLASS, TASK, FUNC, BEGIN_END, FORK_JOIN, GENBLOCK, PACKAGE }; - /* Create a new scope, and attach it to the given parent. The - name is expected to have been permallocated. */ - NetScope(NetScope*up, const hname_t&name, TYPE t, bool nest=false, - bool program=false, bool interface=false); + /* Create a new scope associated with a given compilation unit, + and attach it to the given parent. If no compilation unit is + specified, the parent's compilation unit is used. The name + is expected to have been permallocated. */ + NetScope(NetScope*up, const hname_t&name, TYPE t, NetScope*in_unit=0, + bool nest=false, bool program=false, bool interface=false, + bool compilation_unit=false); ~NetScope(); /* Rename the scope using the name generated by inserting as @@ -1002,10 +1005,12 @@ class NetScope : public Definitions, public Attrib { netclass_t* find_class(perm_string name); - /* The parent and child() methods allow users of NetScope - objects to locate nearby scopes. */ + /* The unit(), parent(), and child() methods allow users of + NetScope objects to locate nearby scopes. */ + NetScope* unit() { return unit_; } NetScope* parent() { return up_; } NetScope* child(const hname_t&name); + const NetScope* unit() const { return unit_; } const NetScope* parent() const { return up_; } const NetScope* child(const hname_t&name) const; @@ -1023,7 +1028,8 @@ class NetScope : public Definitions, public Attrib { // Program blocks and interfaces have elaboration constraints. inline bool program_block() const { return program_block_; } inline bool is_interface() const { return is_interface_; } - TYPE type() const; + inline bool is_unit() const { return is_unit_; } + inline TYPE type() const { return type_; } void print_type(ostream&) const; // This provides a link to the variable initialisation process @@ -1152,6 +1158,9 @@ class NetScope : public Definitions, public Attrib { perm_string local_symbol(); void dump(ostream&) const; + // Check to see if the scope has items that are not allowed + // in an always_comb/ff/latch process. + virtual bool check_synth(ivl_process_type_t pr_type, const NetScope*scope) const; void emit_scope(struct target_t*tgt) const; bool emit_defs(struct target_t*tgt) const; @@ -1249,6 +1258,8 @@ class NetScope : public Definitions, public Attrib { bool program_block_; // True if the scope is an interface bool is_interface_; + // True if the scope is a compilation unit + bool is_unit_; perm_string file_; perm_string def_file_; @@ -1279,6 +1290,7 @@ class NetScope : public Definitions, public Attrib { const PFunction*func_pform_; unsigned elab_stage_; + NetScope*unit_; NetScope*up_; map children_; @@ -2036,7 +2048,7 @@ class NetExpr : public LineInfo { // Get the Nexus that are the input to this // expression. Normally this descends down to the reference to // a signal that reads from its input. - virtual NexusSet* nex_input(bool rem_out = true) =0; + virtual NexusSet* nex_input(bool rem_out = true, bool search_funcs = false) const =0; // Return a version of myself that is structural. This is used // for converting expressions to gates. The arguments are: @@ -2079,7 +2091,7 @@ class NetEArrayPattern : public NetExpr { void dump(ostream&) const; NetEArrayPattern* dup_expr() const; - NexusSet* nex_input(bool rem_out =true); + NexusSet* nex_input(bool rem_out = true, bool search_funcs = false) const; private: std::vector items_; @@ -2112,7 +2124,7 @@ class NetEConst : public NetExpr { virtual NetEConst* dup_expr() const; virtual NetNet*synthesize(Design*, NetScope*scope, NetExpr*); - virtual NexusSet* nex_input(bool rem_out = true); + virtual NexusSet* nex_input(bool rem_out = true, bool search_funcs = false) const; virtual NetExpr*evaluate_function(const LineInfo&loc, map&ctx) const; @@ -2184,7 +2196,7 @@ class NetECReal : public NetExpr { virtual NetECReal* dup_expr() const; virtual NetNet*synthesize(Design*, NetScope*scope, NetExpr*); - virtual NexusSet* nex_input(bool rem_out = true); + virtual NexusSet* nex_input(bool rem_out = true, bool search_funcs = false) const; virtual NetExpr*evaluate_function(const LineInfo&loc, map&ctx) const; @@ -2356,6 +2368,8 @@ class NetCaseCmp : public NetNode { enum kind_t { EEQ, // === NEQ, // !== + WEQ, // ==? + WNE, // !=? XEQ, // casex guard tests ZEQ // casez guard tests }; @@ -2626,7 +2640,7 @@ class NetProc : public virtual LineInfo { // Find the nexa that are input by the statement. This is used // for example by @* to find the inputs to the process for the // sensitivity list. - virtual NexusSet* nex_input(bool rem_out = true); + virtual NexusSet* nex_input(bool rem_out = true, bool search_funcs = false) const; // Find the nexa that are set by the statement. Add the output // values to the set passed as a parameter. @@ -2704,7 +2718,9 @@ class NetProc : public virtual LineInfo { virtual void dump(ostream&, unsigned ind) const; // Recursively checks to see if there is delay in this element. - virtual DelayType delay_type() const; + virtual DelayType delay_type(bool print_delay=false) const; + // Check to see if the item is synthesizable. + virtual bool check_synth(ivl_process_type_t pr_type, const NetScope*scope) const; protected: bool synth_async_block_substatement_(Design*des, NetScope*scope, @@ -2732,6 +2748,8 @@ class NetAlloc : public NetProc { const NetScope* scope() const; + virtual NexusSet* nex_input(bool rem_out = true, bool search_funcs = false) const; + virtual void nex_output(NexusSet&); virtual bool emit_proc(struct target_t*) const; virtual void dump(ostream&, unsigned ind) const; @@ -2839,7 +2857,7 @@ class NetAssign_ { // being outputs. For example foo[idx] = ... is the l-value // (NetAssign_ object) with a foo l-value and the input // expression idx. - NexusSet* nex_input(bool rem_out = true); + NexusSet* nex_input(bool rem_out = true, bool search_funcs = false) const; // Figuring out nex_output to process ultimately comes down to // this method. @@ -2887,7 +2905,7 @@ class NetAssignBase : public NetProc { void set_delay(NetExpr*); const NetExpr* get_delay() const; - virtual NexusSet* nex_input(bool rem_out = true); + virtual NexusSet* nex_input(bool rem_out = true, bool search_funcs = false) const; virtual void nex_output(NexusSet&o); @@ -2902,6 +2920,7 @@ class NetAssignBase : public NetProc { // This dumps all the lval structures. void dump_lval(ostream&) const; virtual void dump(ostream&, unsigned ind) const; + virtual bool check_synth(ivl_process_type_t pr_type, const NetScope*scope) const; private: NetAssign_*lval_; @@ -2923,6 +2942,7 @@ class NetAssign : public NetAssignBase { virtual bool emit_proc(struct target_t*) const; virtual int match_proc(struct proc_match_t*); virtual void dump(ostream&, unsigned ind) const; + virtual bool check_synth(ivl_process_type_t pr_type, const NetScope*scope) const; virtual bool evaluate_function(const LineInfo&loc, map&ctx) const; @@ -2945,6 +2965,7 @@ class NetAssignNB : public NetAssignBase { virtual bool emit_proc(struct target_t*) const; virtual int match_proc(struct proc_match_t*); virtual void dump(ostream&, unsigned ind) const; + virtual bool check_synth(ivl_process_type_t pr_type, const NetScope*scope) const; unsigned nevents() const; const NetEvent*event(unsigned) const; @@ -3002,12 +3023,13 @@ class NetBlock : public NetProc { // for sequential blocks. void emit_recurse(struct target_t*) const; - virtual NexusSet* nex_input(bool rem_out = true); + virtual NexusSet* nex_input(bool rem_out = true, bool search_funcs = false) const; virtual void nex_output(NexusSet&); virtual bool emit_proc(struct target_t*) const; virtual int match_proc(struct proc_match_t*); virtual void dump(ostream&, unsigned ind) const; - virtual DelayType delay_type() const; + virtual DelayType delay_type(bool print_delay=false) const; + virtual bool check_synth(ivl_process_type_t pr_type, const NetScope*scope) const; private: const Type type_; @@ -3045,7 +3067,7 @@ class NetCase : public NetProc { inline const NetExpr*expr(unsigned idx) const { return items_[idx].guard;} inline const NetProc*stat(unsigned idx) const { return items_[idx].statement; } - virtual NexusSet* nex_input(bool rem_out = true); + virtual NexusSet* nex_input(bool rem_out = true, bool search_funcs = false) const; virtual void nex_output(NexusSet&out); bool synth_async(Design*des, NetScope*scope, @@ -3054,7 +3076,8 @@ class NetCase : public NetProc { virtual bool emit_proc(struct target_t*) const; virtual void dump(ostream&, unsigned ind) const; - virtual DelayType delay_type() const; + virtual DelayType delay_type(bool print_delay=false) const; + virtual bool check_synth(ivl_process_type_t pr_type, const NetScope*scope) const; virtual bool evaluate_function(const LineInfo&loc, map&ctx) const; @@ -3091,9 +3114,9 @@ class NetCAssign : public NetAssignBase { explicit NetCAssign(NetAssign_*lv, NetExpr*rv); ~NetCAssign(); - virtual NexusSet* nex_input(bool rem_out = true); virtual void dump(ostream&, unsigned ind) const; virtual bool emit_proc(struct target_t*) const; + virtual bool check_synth(ivl_process_type_t pr_type, const NetScope*scope) const; private: // not implemented NetCAssign(const NetCAssign&); @@ -3124,7 +3147,7 @@ class NetCondit : public NetProc { bool emit_recurse_if(struct target_t*) const; bool emit_recurse_else(struct target_t*) const; - virtual NexusSet* nex_input(bool rem_out = true); + virtual NexusSet* nex_input(bool rem_out = true, bool search_funcs = false) const; virtual void nex_output(NexusSet&o); bool is_asynchronous(); @@ -3144,7 +3167,8 @@ class NetCondit : public NetProc { virtual bool emit_proc(struct target_t*) const; virtual int match_proc(struct proc_match_t*); virtual void dump(ostream&, unsigned ind) const; - virtual DelayType delay_type() const; + virtual DelayType delay_type(bool print_delay=false) const; + virtual bool check_synth(ivl_process_type_t pr_type, const NetScope*scope) const; virtual bool evaluate_function(const LineInfo&loc, map&ctx) const; @@ -3190,6 +3214,7 @@ class NetDeassign : public NetAssignBase { virtual bool emit_proc(struct target_t*) const; virtual void dump(ostream&, unsigned ind) const; + virtual bool check_synth(ivl_process_type_t pr_type, const NetScope*scope) const; private: // not implemented NetDeassign(const NetDeassign&); @@ -3213,8 +3238,11 @@ class NetDisable : public NetProc { const NetScope*target() const; + virtual NexusSet* nex_input(bool rem_out = true, bool search_funcs = false) const; + virtual void nex_output(NexusSet&); virtual bool emit_proc(struct target_t*) const; virtual void dump(ostream&, unsigned ind) const; + virtual bool check_synth(ivl_process_type_t pr_type, const NetScope*scope) const; virtual bool evaluate_function(const LineInfo&loc, map&ctx) const; @@ -3241,11 +3269,12 @@ class NetDoWhile : public NetProc { void emit_proc_recurse(struct target_t*) const; - virtual NexusSet* nex_input(bool rem_out = true); + virtual NexusSet* nex_input(bool rem_out = true, bool search_funcs = false) const; virtual void nex_output(NexusSet&); virtual bool emit_proc(struct target_t*) const; virtual void dump(ostream&, unsigned ind) const; - virtual DelayType delay_type() const; + virtual DelayType delay_type(bool print_delay=false) const; + virtual bool check_synth(ivl_process_type_t pr_type, const NetScope*scope) const; virtual bool evaluate_function(const LineInfo&loc, map&ctx) const; @@ -3302,6 +3331,9 @@ class NetEvent : public LineInfo { perm_string name() const; + bool local_flag() const { return local_flag_; } + void local_flag(bool f) { local_flag_ = f; } + // Get information about probes connected to me. unsigned nprobe() const; NetEvProbe* probe(unsigned); @@ -3333,6 +3365,7 @@ class NetEvent : public LineInfo { private: perm_string name_; + bool local_flag_; // The NetScope class uses these to list the events. NetScope*scope_; @@ -3370,8 +3403,11 @@ class NetEvTrig : public NetProc { const NetEvent*event() const; + virtual NexusSet* nex_input(bool rem_out = true, bool search_funcs = false) const; + virtual void nex_output(NexusSet&); virtual bool emit_proc(struct target_t*) const; virtual void dump(ostream&, unsigned ind) const; + virtual bool check_synth(ivl_process_type_t pr_type, const NetScope*scope) const; private: NetEvent*event_; @@ -3387,12 +3423,15 @@ class NetEvWait : public NetProc { void add_event(NetEvent*tgt); void replace_event(NetEvent*orig, NetEvent*repl); + inline void set_t0_trigger() { has_t0_trigger_ = true; }; inline unsigned nevents() const { return events_.size(); } inline const NetEvent*event(unsigned idx) const { return events_[idx]; } inline NetEvent*event(unsigned idx) { return events_[idx]; } + inline bool has_t0_trigger() const { return has_t0_trigger_; }; NetProc*statement(); + const NetProc*statement() const; virtual bool emit_proc(struct target_t*) const; bool emit_recurse(struct target_t*) const; @@ -3406,7 +3445,7 @@ class NetEvWait : public NetProc { // process? This method checks. virtual bool is_synchronous(); - virtual NexusSet* nex_input(bool rem_out = true); + virtual NexusSet* nex_input(bool rem_out = true, bool search_funcs = false) const; virtual void nex_output(NexusSet&out); virtual bool synth_async(Design*des, NetScope*scope, @@ -3425,12 +3464,14 @@ class NetEvWait : public NetProc { virtual void dump(ostream&, unsigned ind) const; // This will ignore any statement. virtual void dump_inline(ostream&) const; - virtual DelayType delay_type() const; + virtual DelayType delay_type(bool print_delay=false) const; + virtual bool check_synth(ivl_process_type_t pr_type, const NetScope*scope) const; private: NetProc*statement_; // Events that I might wait for. std::vectorevents_; + bool has_t0_trigger_; }; ostream& operator << (ostream&out, const NetEvWait&obj); @@ -3473,10 +3514,9 @@ class NetForce : public NetAssignBase { explicit NetForce(NetAssign_*l, NetExpr*r); ~NetForce(); - virtual NexusSet* nex_input(bool rem_out = true); - virtual void dump(ostream&, unsigned ind) const; virtual bool emit_proc(struct target_t*) const; + virtual bool check_synth(ivl_process_type_t pr_type, const NetScope*scope) const; }; /* @@ -3491,10 +3531,12 @@ class NetForever : public NetProc { void emit_recurse(struct target_t*) const; - virtual NexusSet* nex_input(bool rem_out = true); + virtual NexusSet* nex_input(bool rem_out = true, bool search_funcs = false) const; + virtual void nex_output(NexusSet&); virtual bool emit_proc(struct target_t*) const; virtual void dump(ostream&, unsigned ind) const; - virtual DelayType delay_type() const; + virtual DelayType delay_type(bool print_delay=false) const; + virtual bool check_synth(ivl_process_type_t pr_type, const NetScope*scope) const; virtual bool evaluate_function(const LineInfo&loc, map&ctx) const; @@ -3513,11 +3555,12 @@ class NetForLoop : public NetProc { void emit_recurse(struct target_t*) const; - virtual NexusSet* nex_input(bool rem_out = true); + virtual NexusSet* nex_input(bool rem_out = true, bool search_funcs = false) const; virtual void nex_output(NexusSet&); virtual bool emit_proc(struct target_t*) const; virtual void dump(ostream&, unsigned ind) const; - virtual DelayType delay_type() const; + virtual DelayType delay_type(bool print_delay=false) const; + virtual bool check_synth(ivl_process_type_t pr_type, const NetScope*scope) const; virtual bool evaluate_function(const LineInfo&loc, map&ctx) const; @@ -3550,6 +3593,8 @@ class NetFree : public NetProc { const NetScope* scope() const; + virtual NexusSet* nex_input(bool rem_out = true, bool search_funcs = false) const; + virtual void nex_output(NexusSet&); virtual bool emit_proc(struct target_t*) const; virtual void dump(ostream&, unsigned ind) const; @@ -3613,12 +3658,13 @@ class NetPDelay : public NetProc { uint64_t delay() const; const NetExpr*expr() const; - virtual NexusSet* nex_input(bool rem_out = true); + virtual NexusSet* nex_input(bool rem_out = true, bool search_funcs = false) const; virtual void nex_output(NexusSet&); virtual bool emit_proc(struct target_t*) const; virtual void dump(ostream&, unsigned ind) const; - virtual DelayType delay_type() const; + virtual DelayType delay_type(bool print_delay=false) const; + virtual bool check_synth(ivl_process_type_t pr_type, const NetScope*scope) const; bool emit_proc_recurse(struct target_t*) const; @@ -3640,10 +3686,12 @@ class NetRepeat : public NetProc { const NetExpr*expr() const; void emit_recurse(struct target_t*) const; - virtual NexusSet* nex_input(bool rem_out = true); + virtual NexusSet* nex_input(bool rem_out = true, bool search_funcs = false) const; + virtual void nex_output(NexusSet&); virtual bool emit_proc(struct target_t*) const; virtual void dump(ostream&, unsigned ind) const; - virtual DelayType delay_type() const; + virtual DelayType delay_type(bool print_delay=false) const; + virtual bool check_synth(ivl_process_type_t pr_type, const NetScope*scope) const; virtual bool evaluate_function(const LineInfo&loc, map&ctx) const; @@ -3666,6 +3714,7 @@ class NetRelease : public NetAssignBase { virtual bool emit_proc(struct target_t*) const; virtual void dump(ostream&, unsigned ind) const; + virtual bool check_synth(ivl_process_type_t pr_type, const NetScope*scope) const; private: }; @@ -3691,10 +3740,11 @@ class NetSTask : public NetProc { const NetExpr* parm(unsigned idx) const; - virtual NexusSet* nex_input(bool rem_out = true); + virtual NexusSet* nex_input(bool rem_out = true, bool search_funcs = false) const; virtual void nex_output(NexusSet&); virtual bool emit_proc(struct target_t*) const; virtual void dump(ostream&, unsigned ind) const; + virtual bool check_synth(ivl_process_type_t pr_type, const NetScope*scope) const; virtual bool evaluate_function(const LineInfo&loc, map&ctx) const; @@ -3724,7 +3774,8 @@ class NetTaskDef : public NetBaseDef { ~NetTaskDef(); void dump(ostream&, unsigned) const; - DelayType delay_type() const; + DelayType delay_type(bool print_delay=false) const; + virtual bool check_synth(ivl_process_type_t pr_type, const NetScope*scope) const; private: // not implemented NetTaskDef(const NetTaskDef&); @@ -3750,7 +3801,7 @@ class NetELast : public NetExpr { virtual void expr_scan(struct expr_scan_t*) const; virtual NetELast*dup_expr() const; - virtual NexusSet* nex_input(bool rem_out = true); + virtual NexusSet* nex_input(bool rem_out = true, bool search_funcs = false) const; private: NetNet*sig_; @@ -3779,7 +3830,7 @@ class NetEUFunc : public NetExpr { virtual void expr_scan(struct expr_scan_t*) const; virtual NetEUFunc*dup_expr() const; - virtual NexusSet* nex_input(bool rem_out = true); + virtual NexusSet* nex_input(bool rem_out = true, bool search_funcs = false) const; virtual NetExpr* eval_tree(); virtual NetExpr*evaluate_function(const LineInfo&loc, map&ctx) const; @@ -3815,7 +3866,7 @@ class NetEAccess : public NetExpr { virtual void expr_scan(struct expr_scan_t*) const; virtual NetEAccess*dup_expr() const; - virtual NexusSet* nex_input(bool rem_out = true); + virtual NexusSet* nex_input(bool rem_out = true, bool search_funcs = false) const; private: NetBranch*branch_; @@ -3837,11 +3888,12 @@ class NetUTask : public NetProc { const NetScope* task() const; - virtual NexusSet* nex_input(bool rem_out = true); + virtual NexusSet* nex_input(bool rem_out = true, bool search_funcs = false) const; virtual void nex_output(NexusSet&); virtual bool emit_proc(struct target_t*) const; virtual void dump(ostream&, unsigned ind) const; - virtual DelayType delay_type() const; + virtual DelayType delay_type(bool print_delay=false) const; + virtual bool check_synth(ivl_process_type_t pr_type, const NetScope*scope) const; private: NetScope*task_; @@ -3862,16 +3914,17 @@ class NetWhile : public NetProc { void emit_proc_recurse(struct target_t*) const; - virtual NexusSet* nex_input(bool rem_out = true); + virtual NexusSet* nex_input(bool rem_out = true, bool search_funcs = false) const; virtual void nex_output(NexusSet&); virtual bool emit_proc(struct target_t*) const; virtual void dump(ostream&, unsigned ind) const; - virtual DelayType delay_type() const; + virtual DelayType delay_type(bool print_delay=false) const; + virtual bool check_synth(ivl_process_type_t pr_type, const NetScope*scope) const; virtual bool evaluate_function(const LineInfo&loc, map&ctx) const; private: - NetExpr* cond_; + NetExpr*cond_; NetProc*proc_; }; @@ -4005,7 +4058,7 @@ class NetEBinary : public NetExpr { virtual NetExpr* eval_tree(); virtual NetExpr* evaluate_function(const LineInfo&loc, map&ctx) const; - virtual NexusSet* nex_input(bool rem_out = true); + virtual NexusSet* nex_input(bool rem_out = true, bool search_funcs = false) const; virtual void expr_scan(struct expr_scan_t*) const; virtual void dump(ostream&) const; @@ -4128,6 +4181,7 @@ class NetEBComp : public NetEBinary { NetEConst*eval_gt_(const NetExpr*le, const NetExpr*re) const; NetEConst*eval_gteq_(const NetExpr*le, const NetExpr*re) const; NetEConst*eval_eqeqeq_(bool ne_flag, const NetExpr*le, const NetExpr*re) const; + NetEConst*eval_weqeq_(bool ne_flag, const NetExpr*le, const NetExpr*re) const; }; /* @@ -4258,7 +4312,7 @@ class NetEConcat : public NetExpr { NetExpr* parm(unsigned idx) const { return parms_[idx]; } virtual ivl_variable_type_t expr_type() const; - virtual NexusSet* nex_input(bool rem_out = true); + virtual NexusSet* nex_input(bool rem_out = true, bool search_funcs = false) const; virtual bool has_width() const; virtual NetEConcat* dup_expr() const; virtual NetEConst* eval_tree(); @@ -4306,7 +4360,7 @@ class NetESelect : public NetExpr { // sub-expression. virtual ivl_variable_type_t expr_type() const; - virtual NexusSet* nex_input(bool rem_out = true); + virtual NexusSet* nex_input(bool rem_out = true, bool search_funcs = false) const; virtual bool has_width() const; virtual void expr_scan(struct expr_scan_t*) const; virtual NetEConst* eval_tree(); @@ -4335,7 +4389,7 @@ class NetEEvent : public NetExpr { virtual void expr_scan(struct expr_scan_t*) const; virtual NetEEvent* dup_expr() const; - virtual NexusSet* nex_input(bool rem_out = true); + virtual NexusSet* nex_input(bool rem_out = true, bool search_funcs = false) const; virtual void dump(ostream&os) const; @@ -4358,7 +4412,7 @@ class NetENetenum : public NetExpr { virtual void expr_scan(struct expr_scan_t*) const; virtual NetENetenum* dup_expr() const; - virtual NexusSet* nex_input(bool rem_out = true); + virtual NexusSet* nex_input(bool rem_out = true, bool search_funcs = false) const; virtual void dump(ostream&os) const; @@ -4382,7 +4436,7 @@ class NetENew : public NetExpr { virtual void expr_scan(struct expr_scan_t*) const; virtual NetENew* dup_expr() const; - virtual NexusSet* nex_input(bool rem_out = true); + virtual NexusSet* nex_input(bool rem_out = true, bool search_funcs = false) const; virtual void dump(ostream&os) const; @@ -4404,7 +4458,7 @@ class NetENull : public NetExpr { virtual void expr_scan(struct expr_scan_t*) const; virtual NetENull* dup_expr() const; - virtual NexusSet* nex_input(bool rem_out = true); + virtual NexusSet* nex_input(bool rem_out = true, bool search_funcs = false) const; virtual void dump(ostream&os) const; }; @@ -4430,7 +4484,7 @@ class NetEProperty : public NetExpr { ivl_variable_type_t expr_type() const; virtual void expr_scan(struct expr_scan_t*) const; virtual NetEProperty* dup_expr() const; - virtual NexusSet* nex_input(bool rem_out = true); + virtual NexusSet* nex_input(bool rem_out = true, bool search_funcs = false) const; virtual void dump(ostream&os) const; @@ -4455,7 +4509,7 @@ class NetEScope : public NetExpr { virtual void expr_scan(struct expr_scan_t*) const; virtual NetEScope* dup_expr() const; - virtual NexusSet* nex_input(bool rem_out = true); + virtual NexusSet* nex_input(bool rem_out = true, bool search_funcs = false) const; virtual void dump(ostream&os) const; @@ -4489,7 +4543,7 @@ class NetESFunc : public NetExpr { map&ctx) const; virtual ivl_variable_type_t expr_type() const; - virtual NexusSet* nex_input(bool rem_out = true); + virtual NexusSet* nex_input(bool rem_out = true, bool search_funcs = false) const; virtual const netenum_t* enumeration() const; virtual void dump(ostream&) const; @@ -4551,7 +4605,7 @@ class NetESFunc : public NetExpr { /* Added in SystemVerilog 2009 and later. */ CTONES = 0x00020024, /* $countones takes one argument. */ /* Added in SystemVerilog 2012 and later. */ - CTBITS = 0xfffe0025, /* $countbits takes one or more arguments. */ + CTBITS = 0xfffc0025, /* $countbits takes two or more arguments. */ /* Added as Icarus extensions to Verilog-A. */ ABS = 0x00020026, /* $abs takes one argument. */ MAX = 0x00040027, /* $max takes two argument. */ @@ -4561,7 +4615,7 @@ class NetESFunc : public NetExpr { bool takes_nargs_(ID func, unsigned nargs) { if (nargs > 15) nargs = 15; - return func & (1 << (nargs + 16)); + return func & (1U << (nargs + 16)); } const char* name_; @@ -4603,8 +4657,7 @@ class NetESFunc : public NetExpr { NetEConst* evaluate_array_funcs_(ID id, const NetExpr*arg0, const NetExpr*arg1) const; - NetEConst* evaluate_countbits_(const NetExpr*arg0, - const NetExpr*arg1) const; + NetEConst* evaluate_countbits_(void) const; public: bool is_built_in() const { return built_in_id_() != NOT_BUILT_IN; }; @@ -4624,7 +4677,7 @@ class NetEShallowCopy : public NetExpr { virtual void expr_scan(struct expr_scan_t*) const; virtual NetEShallowCopy* dup_expr() const; - virtual NexusSet* nex_input(bool rem_out = true); + virtual NexusSet* nex_input(bool rem_out = true, bool search_funcs = false) const; virtual void dump(ostream&os) const; @@ -4656,7 +4709,7 @@ class NetETernary : public NetExpr { virtual NetExpr*evaluate_function(const LineInfo&loc, map&ctx) const; virtual ivl_variable_type_t expr_type() const; - virtual NexusSet* nex_input(bool rem_out = true); + virtual NexusSet* nex_input(bool rem_out = true, bool search_funcs = false) const; virtual void expr_scan(struct expr_scan_t*) const; virtual void dump(ostream&) const; virtual NetNet*synthesize(Design*, NetScope*scope, NetExpr*root); @@ -4711,7 +4764,7 @@ class NetEUnary : public NetExpr { virtual NetNet* synthesize(Design*, NetScope*scope, NetExpr*root); virtual ivl_variable_type_t expr_type() const; - virtual NexusSet* nex_input(bool rem_out = true); + virtual NexusSet* nex_input(bool rem_out = true, bool search_funcs = false) const; virtual void expr_scan(struct expr_scan_t*) const; virtual void dump(ostream&) const; @@ -4787,7 +4840,7 @@ class NetESignal : public NetExpr { virtual NetESignal* dup_expr() const; NetNet* synthesize(Design*des, NetScope*scope, NetExpr*root); - NexusSet* nex_input(bool rem_out = true); + NexusSet* nex_input(bool rem_out = true, bool search_funcs = false) const; const netenum_t*enumeration() const; virtual NetExpr*evaluate_function(const LineInfo&loc, @@ -4835,7 +4888,7 @@ struct elaborator_work_item_t { * This class contains an entire design. It includes processes and a * netlist, and can be passed around from function to function. */ -class Design : public Definitions { +class Design { public: Design(); @@ -4857,12 +4910,13 @@ class Design : public Definitions { const char* get_flag(const string&key) const; - NetScope* make_root_scope(perm_string name, bool program_block, - bool is_interface); + NetScope* make_root_scope(perm_string name, NetScope*unit_scope, + bool program_block, bool is_interface); NetScope* find_root_scope(); std::list find_root_scopes() const; - NetScope* make_package_scope(perm_string name); + NetScope* make_package_scope(perm_string name, NetScope*unit_scope, + bool is_unit); std::list find_package_scopes() const; /* Attempt to set the precision to the specified value. If the @@ -4912,11 +4966,6 @@ class Design : public Definitions { // Look for defparams that never matched, and print warnings. void residual_defparams(); - // Do elaborate_sig for objects in $root scope. - void root_elaborate_sig(void); - - void root_elaborate(void); - /* This method locates a signal, starting at a given scope. The name parameter may be partially hierarchical, so this method, unlike the NetScope::find_signal method, @@ -4929,12 +4978,6 @@ class Design : public Definitions { // Tasks NetScope* find_task(NetScope*scope, const pform_name_t&name); - void add_root_task(NetScope*tscope, PTaskFunc*tf); - std::list find_roottask_scopes(void) const; - - // Find a class in the $root scope. - void add_class(netclass_t*cl, PClass*pclass); - netclass_t* find_class(perm_string name) const; // NODES void add_node(NetNode*); @@ -4948,6 +4991,7 @@ class Design : public Definitions { void add_process(NetAnalogTop*); void delete_process(NetProcTop*); bool check_proc_delay() const; + bool check_proc_synth() const; NetNet* find_discipline_reference(ivl_discipline_t dis, NetScope*scope); @@ -4962,6 +5006,12 @@ class Design : public Definitions { unsigned errors; private: + NetScope* find_scope_(NetScope*, const hname_t&name, + NetScope::TYPE type = NetScope::MODULE) const; + + NetScope* find_scope_(NetScope*, const std::list&path, + NetScope::TYPE type = NetScope::MODULE) const; + // Keep a tree of scopes. The NetScope class handles the wide // tree and per-hop searches for me. listroot_scopes_; @@ -4970,12 +5020,6 @@ class Design : public Definitions { // packages do not nest. std::mappackages_; - // Tasks in the $root scope - std::maproot_tasks_; - - // Need this for elaboration of $root scope pclass objects. - std::map class_to_pclass_; - // List the nodes in the design. NetNode*nodes_; // These are in support of the node functor iterator. diff --git a/netmisc.cc b/netmisc.cc index b0bf41b98..59da76061 100644 --- a/netmisc.cc +++ b/netmisc.cc @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001-2016 Stephen Williams (steve@icarus.com) + * Copyright (c) 2001-2017 Stephen Williams (steve@icarus.com) * * This source code is free software; you can redistribute it * and/or modify it in source code form under the terms of the GNU @@ -1260,6 +1260,8 @@ const char *human_readable_op(const char op, bool unary) if (unary) type = "~|"; // NOR else type = "!=="; // Case inequality break; + case 'w': type = "==?"; break; // Wild equality + case 'W': type = "!=?"; break; // Wild inequality case 'l': type = "<<(<)"; break; // Left shifts case 'r': type = ">>"; break; // Logical right shift @@ -1665,3 +1667,38 @@ NetScope* find_method_containing_scope(const LineInfo&, NetScope*scope) return scope; } + + +/* + * Print a warning if we find a mixture of default and explicit timescale + * based delays in the design, since this is likely an error. + */ +void check_for_inconsistent_delays(NetScope*scope) +{ + static bool used_implicit_timescale = false; + static bool used_explicit_timescale = false; + static bool display_ts_dly_warning = true; + + if (scope->time_from_timescale()) + used_explicit_timescale = true; + else + used_implicit_timescale = true; + + if (display_ts_dly_warning && + used_explicit_timescale && + used_implicit_timescale) { + if (gn_system_verilog()) { + cerr << "warning: Found both default and explicit " + "timescale based delays. Use" << endl; + cerr << " : -Wtimescale to find the design " + "element(s) with no explicit" << endl; + cerr << " : timescale." << endl; + } else { + cerr << "warning: Found both default and " + "`timescale based delays. Use" << endl; + cerr << " : -Wtimescale to find the " + "module(s) with no `timescale." << endl; + } + display_ts_dly_warning = false; + } +} diff --git a/netmisc.h b/netmisc.h index ce65701be..af639da2b 100644 --- a/netmisc.h +++ b/netmisc.h @@ -1,7 +1,7 @@ #ifndef IVL_netmisc_H #define IVL_netmisc_H /* - * Copyright (c) 1999-2016 Stephen Williams (steve@icarus.com) + * Copyright (c) 1999-2017 Stephen Williams (steve@icarus.com) * * This source code is free software; you can redistribute it * and/or modify it in source code form under the terms of the GNU @@ -378,10 +378,6 @@ const char *human_readable_op(const char op, bool unary = false); enum const_bool { C_NON, C_0, C_1, C_X }; const_bool const_logical(const NetExpr*expr); -extern bool dly_used_no_timescale; -extern bool dly_used_timescale; -extern bool display_ts_dly_warning; - /* * When scaling a real value to a time we need to do some standard * processing. @@ -409,4 +405,10 @@ extern void assign_unpacked_with_bufz(Design*des, NetScope*scope, extern NetPartSelect* detect_partselect_lval(Link&pin); +/* + * Print a warning if we find a mixture of default and explicit timescale + * based delays in the design, since this is likely an error. + */ +extern void check_for_inconsistent_delays(NetScope*scope); + #endif /* IVL_netmisc_H */ diff --git a/parse.y b/parse.y index 86e075a47..76947fd03 100644 --- a/parse.y +++ b/parse.y @@ -1,7 +1,7 @@ %{ /* - * Copyright (c) 1998-2016 Stephen Williams (steve@icarus.com) + * Copyright (c) 1998-2017 Stephen Williams (steve@icarus.com) * Copyright CERN 2012-2013 / Stephen Williams (steve@icarus.com) * * This source code is free software; you can redistribute it @@ -35,9 +35,6 @@ class PSpecPath; extern void lex_end_table(); -bool have_timeunit_decl = false; -bool have_timeprec_decl = false; - static list* param_active_range = 0; static bool param_active_signed = false; static ivl_variable_type_t param_active_type = IVL_VT_LOGIC; @@ -468,7 +465,7 @@ static void current_function_set_statement(const YYLTYPE&loc, vector %token BASED_NUMBER DEC_NUMBER UNBASED_NUMBER %token REALTIME %token K_PLUS_EQ K_MINUS_EQ K_INCR K_DECR -%token K_LE K_GE K_EG K_EQ K_NE K_CEQ K_CNE K_LP K_LS K_RS K_RSS K_SG +%token K_LE K_GE K_EG K_EQ K_NE K_CEQ K_CNE K_WEQ K_WNE K_LP K_LS K_RS K_RSS K_SG /* K_CONTRIBUTE is <+, the contribution assign. */ %token K_CONTRIBUTE %token K_PO_POS K_PO_NEG K_POW @@ -532,8 +529,6 @@ static void current_function_set_statement(const YYLTYPE&loc, vector %token K_tagged K_this K_throughout K_timeprecision K_timeunit K_type %token K_typedef K_union K_unique K_var K_virtual K_void K_wait_order %token K_wildcard K_with K_within - /* Fake tokens that are passed once we have an initial token. */ -%token K_timeprecision_check K_timeunit_check /* The new tokens from 1800-2009. */ %token K_accept_on K_checker K_endchecker K_eventually K_global K_implies @@ -598,7 +593,7 @@ static void current_function_set_statement(const YYLTYPE&loc, vector %type function_item function_item_list function_item_list_opt %type task_item task_item_list task_item_list_opt -%type tf_port_declaration tf_port_item tf_port_list tf_port_list_opt +%type tf_port_declaration tf_port_item tf_port_item_list tf_port_list tf_port_list_opt %type modport_simple_port port_name parameter_value_byname %type port_name_list parameter_value_byname_list @@ -627,6 +622,7 @@ static void current_function_set_statement(const YYLTYPE&loc, vector %type list_of_variable_decl_assignments %type data_type data_type_or_implicit data_type_or_implicit_or_void +%type simple_type_or_string %type class_identifier %type struct_union_member %type struct_union_member_list @@ -655,6 +651,7 @@ static void current_function_set_statement(const YYLTYPE&loc, vector %type statement statement_item statement_or_null %type compressed_statement %type loop_statement for_step jump_statement +%type procedural_assertion_statement %type statement_or_null_list statement_or_null_list_opt %type analog_statement @@ -682,7 +679,7 @@ static void current_function_set_statement(const YYLTYPE&loc, vector %left '|' %left '^' K_NXOR K_NOR %left '&' K_NAND -%left K_EQ K_NE K_CEQ K_CNE +%left K_EQ K_NE K_CEQ K_CNE K_WEQ K_WNE %left K_GE K_LE '<' '>' %left K_LS K_RS K_RSS %left '+' '-' @@ -691,7 +688,7 @@ static void current_function_set_statement(const YYLTYPE&loc, vector %left UNARY_PREC -/* to resolve dangling else ambiguity. */ + /* to resolve dangling else ambiguity. */ %nonassoc less_than_K_else %nonassoc K_else @@ -699,12 +696,22 @@ static void current_function_set_statement(const YYLTYPE&loc, vector %nonassoc '(' %nonassoc K_exclude + /* to resolve timeunits declaration/redeclaration ambiguity */ +%nonassoc no_timeunits_declaration +%nonassoc one_timeunits_declaration +%nonassoc K_timeunit K_timeprecision + %% /* IEEE1800-2005: A.1.2 */ /* source_text ::= [ timeunits_declaration ] { description } */ -source_text : description_list | ; +source_text + : timeunits_declaration_opt + { pform_set_scope_timescale(yyloc); } + description_list + | /* empty */ + ; assertion_item /* IEEE1800-2012: A.6.10 */ : concurrent_assertion_item @@ -1136,11 +1143,7 @@ data_type_or_implicit_or_void } ; - /* NOTE 1: We pull the "timeunits_declaration" into the description - here in order to be a little more flexible with where timeunits - statements may go. This may be a bad idea, but it is legacy now. */ - - /* NOTE 2: The "module" rule of the description combines the + /* NOTE: The "module" rule of the description combines the module_declaration, program_declaration, and interface_declaration rules from the standard description. */ @@ -1725,17 +1728,18 @@ open_range_list /* IEEE1800-2005 A.2.11 */ package_declaration /* IEEE1800-2005 A.1.2 */ : K_package lifetime_opt IDENTIFIER ';' - { pform_start_package_declaration(@1, $3, $2); - } + { pform_start_package_declaration(@1, $3, $2); } + timeunits_declaration_opt + { pform_set_scope_timescale(@1); } package_item_list_opt K_endpackage endlabel_opt { pform_end_package_declaration(@1); // If an end label is present make sure it match the package name. - if ($8) { - if (strcmp($3,$8) != 0) { - yyerror(@8, "error: End label doesn't match package name"); + if ($10) { + if (strcmp($3,$10) != 0) { + yyerror(@10, "error: End label doesn't match package name"); } - delete[]$8; + delete[]$10; } delete[]$3; } @@ -1815,6 +1819,21 @@ property_expr /* IEEE1800-2012 A.2.10 */ : expression ; +procedural_assertion_statement /* IEEE1800-2012 A.6.10 */ + : K_assert '(' expression ')' statement %prec less_than_K_else + { yyerror(@1, "sorry: Simple immediate assertion statements not implemented."); + $$ = 0; + } + | K_assert '(' expression ')' K_else statement + { yyerror(@1, "sorry: Simple immediate assertion statements not implemented."); + $$ = 0; + } + | K_assert '(' expression ')' statement K_else statement + { yyerror(@1, "sorry: Simple immediate assertion statements not implemented."); + $$ = 0; + } + ; + /* The property_qualifier rule is as literally described in the LRM, but the use is usually as { property_qualifier }, which is implemented by the property_qualifier_opt rule below. */ @@ -1865,6 +1884,60 @@ signing /* IEEE1800-2005: A.2.2.1 */ | K_unsigned { $$ = false; } ; +simple_type_or_string /* IEEE1800-2005: A.2.2.1 */ + : integer_vector_type + { ivl_variable_type_t use_vtype = $1; + bool reg_flag = false; + if (use_vtype == IVL_VT_NO_TYPE) { + use_vtype = IVL_VT_LOGIC; + reg_flag = true; + } + vector_type_t*tmp = new vector_type_t(use_vtype, false, 0); + tmp->reg_flag = reg_flag; + FILE_NAME(tmp, @1); + $$ = tmp; + } + | non_integer_type + { real_type_t*tmp = new real_type_t($1); + FILE_NAME(tmp, @1); + $$ = tmp; + } + | atom2_type + { atom2_type_t*tmp = new atom2_type_t($1, true); + FILE_NAME(tmp, @1); + $$ = tmp; + } + | K_integer + { list*pd = make_range_from_width(integer_width); + vector_type_t*tmp = new vector_type_t(IVL_VT_LOGIC, true, pd); + tmp->reg_flag = true; + tmp->integer_flag = true; + $$ = tmp; + } + | K_time + { list*pd = make_range_from_width(64); + vector_type_t*tmp = new vector_type_t(IVL_VT_LOGIC, false, pd); + tmp->reg_flag = !gn_system_verilog(); + $$ = tmp; + } + | TYPE_IDENTIFIER + { $$ = $1.type; + delete[]$1.text; + } + | PACKAGE_IDENTIFIER K_SCOPE_RES + { lex_in_package_scope($1); } + TYPE_IDENTIFIER + { lex_in_package_scope(0); + $$ = $4.type; + delete[]$4.text; + } + | K_string + { string_type_t*tmp = new string_type_t; + FILE_NAME(tmp, @1); + $$ = tmp; + } + ; + statement /* IEEE1800-2005: A.6.4 */ : attribute_list_opt statement_item { pform_bind_attributes($2->attributes, $1); @@ -2028,7 +2101,10 @@ task_declaration /* IEEE1800-2005: A.2.7 */ | K_task lifetime_opt IDENTIFIER error K_endtask { - assert(current_task == 0); + if (current_task) { + pform_pop_scope(); + current_task = 0; + } } endlabel_opt { // Last step: check any closing name. This is done late so @@ -2112,10 +2188,16 @@ tf_port_item /* IEEE1800-2005: A.2.7 */ : port_direction_opt data_type_or_implicit IDENTIFIER dimensions_opt tf_port_item_expr_opt { vector*tmp; - NetNet::PortType use_port_type = $1==NetNet::PIMPLICIT? NetNet::PINPUT : $1; + NetNet::PortType use_port_type = $1; + if ((use_port_type == NetNet::PIMPLICIT) && (gn_system_verilog() || ($2 == 0))) + use_port_type = port_declaration_context.port_type; perm_string name = lex_strings.make($3); list* ilist = list_from_identifier($3); + if (use_port_type == NetNet::PIMPLICIT) { + yyerror(@1, "error: missing task/function port direction."); + use_port_type = NetNet::PINPUT; // for error recovery + } if (($2 == 0) && ($1==NetNet::PIMPLICIT)) { // Detect special case this is an undecorated // identifier and we need to get the declaration from @@ -2127,7 +2209,6 @@ tf_port_item /* IEEE1800-2005: A.2.7 */ port_declaration_context.data_type, ilist); - } else { // Otherwise, the decorations for this identifier // indicate the type. Save the type for any right @@ -2174,8 +2255,15 @@ tf_port_item_expr_opt ; tf_port_list /* IEEE1800-2005: A.2.7 */ + : { port_declaration_context.port_type = gn_system_verilog() ? NetNet::PINPUT : NetNet::PIMPLICIT; + port_declaration_context.data_type = 0; + } + tf_port_item_list + { $$ = $2; } + ; - : tf_port_list ',' tf_port_item +tf_port_item_list + : tf_port_item_list ',' tf_port_item { vector*tmp; if ($1 && $3) { size_t s1 = $1->size(); @@ -2201,30 +2289,34 @@ tf_port_list /* IEEE1800-2005: A.2.7 */ { yyerror(@2, "error: Syntax error in task/function port declaration."); $$ = $3; } - | tf_port_list ',' + | tf_port_item_list ',' { yyerror(@2, "error: NULL port declarations are not allowed."); $$ = $1; } - | tf_port_list ';' + | tf_port_item_list ';' { yyerror(@2, "error: ';' is an invalid port declaration separator."); $$ = $1; } ; - /* NOTE: Icarus Verilog is a little more generous with the - timeunits declarations by allowing them to happen in multiple - places in the file. So the rule is adjusted to be invoked by the - "description" rule. This theoretically allows files to be - concatenated together and still compile. */ timeunits_declaration /* IEEE1800-2005: A.1.2 */ : K_timeunit TIME_LITERAL ';' - { pform_set_timeunit($2, false, false); } + { pform_set_timeunit($2, allow_timeunit_decl); } | K_timeunit TIME_LITERAL '/' TIME_LITERAL ';' - { pform_set_timeunit($2, false, false); - pform_set_timeprecision($4, false, false); + { bool initial_decl = allow_timeunit_decl && allow_timeprec_decl; + pform_set_timeunit($2, initial_decl); + pform_set_timeprec($4, initial_decl); } | K_timeprecision TIME_LITERAL ';' - { pform_set_timeprecision($2, false, false); } + { pform_set_timeprec($2, allow_timeprec_decl); } + ; + + /* Allow zero, one, or two declarations. The second declaration might + be a repeat declaration, but the pform functions take care of that. */ +timeunits_declaration_opt + : /* empty */ %prec no_timeunits_declaration + | timeunits_declaration %prec one_timeunits_declaration + | timeunits_declaration timeunits_declaration ; value_range /* IEEE1800-2005: A.8.3 */ @@ -3259,6 +3351,11 @@ expression FILE_NAME(tmp, @2); $$ = tmp; } + | expression K_WEQ attribute_list_opt expression + { PEBinary*tmp = new PEBComp('w', $1, $4); + FILE_NAME(tmp, @2); + $$ = tmp; + } | expression K_LE attribute_list_opt expression { PEBinary*tmp = new PEBComp('L', $1, $4); FILE_NAME(tmp, @2); @@ -3279,6 +3376,11 @@ expression FILE_NAME(tmp, @2); $$ = tmp; } + | expression K_WNE attribute_list_opt expression + { PEBinary*tmp = new PEBComp('W', $1, $4); + FILE_NAME(tmp, @2); + $$ = tmp; + } | expression K_LOR attribute_list_opt expression { PEBinary*tmp = new PEBLogic('o', $1, $4); FILE_NAME(tmp, @2); @@ -3751,7 +3853,7 @@ expr_primary } } - | data_type '\'' '(' expression ')' + | simple_type_or_string '\'' '(' expression ')' { PExpr*base = $4; if (gn_system_verilog()) { PECastType*tmp = new PECastType($1, base); @@ -4390,47 +4492,6 @@ cont_assign_list { $$ = $1; } ; - /* We allow zero, one or two unique declarations. */ -local_timeunit_prec_decl_opt - : /* Empty */ - | K_timeunit TIME_LITERAL '/' TIME_LITERAL ';' - { pform_set_timeunit($2, true, false); - have_timeunit_decl = true; - pform_set_timeprecision($4, true, false); - have_timeprec_decl = true; - } - | local_timeunit_prec_decl - | local_timeunit_prec_decl local_timeunit_prec_decl2 - ; - - /* By setting the appropriate have_time???_decl we allow only - one declaration of each type in this module. */ -local_timeunit_prec_decl - : K_timeunit TIME_LITERAL ';' - { pform_set_timeunit($2, true, false); - have_timeunit_decl = true; - } - | K_timeprecision TIME_LITERAL ';' - { pform_set_timeprecision($2, true, false); - have_timeprec_decl = true; - } - ; -local_timeunit_prec_decl2 - : K_timeunit TIME_LITERAL ';' - { pform_set_timeunit($2, true, false); - have_timeunit_decl = true; - } - | K_timeprecision TIME_LITERAL ';' - { pform_set_timeprecision($2, true, false); - have_timeprec_decl = true; - } - /* As the second item this form is always a check. */ - | K_timeunit TIME_LITERAL '/' TIME_LITERAL ';' - { pform_set_timeunit($2, true, true); - pform_set_timeprecision($4, true, true); - } - ; - /* This is the global structure of a module. A module is a start section, with optional ports, then an optional list of module items, and finally an end marker. */ @@ -4443,11 +4504,8 @@ module module_port_list_opt module_attribute_foreign ';' { pform_module_set_ports($8); } - local_timeunit_prec_decl_opt - { have_timeunit_decl = true; // Every thing past here is - have_timeprec_decl = true; // a check! - pform_check_timeunit_prec(); - } + timeunits_declaration_opt + { pform_set_scope_timescale(@2); } module_item_list_opt module_end { Module::UCDriveType ucd; @@ -4484,8 +4542,6 @@ module } } pform_endmodule($4, in_celldefine, ucd); - have_timeunit_decl = false; // We will allow decls again. - have_timeprec_decl = false; } endlabel_opt { // Last step: check any closing name. This is done late so @@ -4839,9 +4895,8 @@ module_item | attribute_list_opt IDENTIFIER parameter_value_opt gate_instance_list ';' { perm_string tmp1 = lex_strings.make($2); - pform_make_modgates(@2, tmp1, $3, $4); + pform_make_modgates(@2, tmp1, $3, $4, $1); delete[]$2; - if ($1) delete $1; } | attribute_list_opt @@ -4864,6 +4919,18 @@ module_item { PProcess*tmp = pform_make_behavior(IVL_PR_ALWAYS, $3, $1); FILE_NAME(tmp, @2); } + | attribute_list_opt K_always_comb statement_item + { PProcess*tmp = pform_make_behavior(IVL_PR_ALWAYS_COMB, $3, $1); + FILE_NAME(tmp, @2); + } + | attribute_list_opt K_always_ff statement_item + { PProcess*tmp = pform_make_behavior(IVL_PR_ALWAYS_FF, $3, $1); + FILE_NAME(tmp, @2); + } + | attribute_list_opt K_always_latch statement_item + { PProcess*tmp = pform_make_behavior(IVL_PR_ALWAYS_LATCH, $3, $1); + FILE_NAME(tmp, @2); + } | attribute_list_opt K_initial statement_item { PProcess*tmp = pform_make_behavior(IVL_PR_INITIAL, $3, $1); FILE_NAME(tmp, @2); @@ -4878,6 +4945,8 @@ module_item | attribute_list_opt assertion_item + | timeunits_declaration + | class_declaration | task_declaration @@ -5001,14 +5070,6 @@ module_item | KK_attribute '(' error ')' ';' { yyerror(@1, "error: Malformed $attribute parameter list."); } - | K_timeunit_check TIME_LITERAL ';' - { pform_set_timeunit($2, true, true); } - | K_timeunit_check TIME_LITERAL '/' TIME_LITERAL ';' - { pform_set_timeunit($2, true, true); - pform_set_timeprecision($4, true, true); - } - | K_timeprecision_check TIME_LITERAL ';' - { pform_set_timeprecision($2, true, true); } ; module_item_list @@ -6241,6 +6302,8 @@ statement_item /* This is roughly statement_item in the LRM */ $$ = tmp; } + | procedural_assertion_statement { $$ = $1; } + | loop_statement { $$ = $1; } | jump_statement { $$ = $1; } @@ -6417,7 +6480,7 @@ statement_item /* This is roughly statement_item in the LRM */ $$ = tmp; } | K_wait K_fork ';' - { PEventStatement*tmp = new PEventStatement(0); + { PEventStatement*tmp = new PEventStatement((PEEvent*)0); FILE_NAME(tmp,@1); $$ = tmp; } diff --git a/parse_api.h b/parse_api.h index a698c3bee..1b76b767b 100644 --- a/parse_api.h +++ b/parse_api.h @@ -1,7 +1,7 @@ #ifndef IVL_parse_api_H #define IVL_parse_api_H /* - * Copyright (c) 2001-2014 Stephen Williams (steve@icarus.com) + * Copyright (c) 2001-2017 Stephen Williams (steve@icarus.com) * * This source code is free software; you can redistribute it * and/or modify it in source code form under the terms of the GNU @@ -42,28 +42,21 @@ struct enum_type_t; */ extern std::map pform_modules; extern std::map pform_primitives; -extern std::map pform_typedefs; -extern std::set pform_enum_sets; -extern std::map pform_tasks; -extern std::map pform_classes; +extern std::vector pform_units; extern std::map pform_packages; extern void pform_dump(std::ostream&out, const PClass*pac); extern void pform_dump(std::ostream&out, const PPackage*pac); extern void pform_dump(std::ostream&out, const PTaskFunc*tf); -extern void elaborate_rootscope_enumerations(Design*des); -extern void elaborate_rootscope_classes(Design*des); -extern void elaborate_rootscope_tasks(Design*des); - /* - * This code actually invokes the parser to make modules. The first - * parameter is the name of the file that is to be parsed. The - * optional second parameter is the opened descriptor for the file. If - * the descriptor is 0 (or skipped) then the function will attempt to - * open the file on its own. + * This code actually invokes the parser to make modules. If the path + * parameter is "-", the parser reads from stdin, otherwise it attempts + * to open and read the specified file. When reading from a file, if + * the ivlpp_string variable is not set to null, the file will be piped + * through the command specified by ivlpp_string before being parsed. */ -extern int pform_parse(const char*path, FILE*file =0); +extern int pform_parse(const char*path); extern string vl_file; diff --git a/parse_misc.h b/parse_misc.h index ddee21bf7..d02902013 100644 --- a/parse_misc.h +++ b/parse_misc.h @@ -1,7 +1,7 @@ #ifndef IVL_parse_misc_H #define IVL_parse_misc_H /* - * Copyright (c) 1998-2014 Stephen Williams (steve@icarus.com) + * Copyright (c) 1998-2017 Stephen Williams (steve@icarus.com) * * This source code is free software; you can redistribute it * and/or modify it in source code form under the terms of the GNU @@ -71,12 +71,6 @@ extern unsigned long based_size; extern bool in_celldefine; enum UCDriveType { UCD_NONE, UCD_PULL0, UCD_PULL1 }; extern UCDriveType uc_drive; -/* - * Flags to control if we are declaring or checking a timeunit or - * timeprecision statement. - */ -extern bool have_timeunit_decl; -extern bool have_timeprec_decl; /* * The parser signals back to the lexor that the next identifier diff --git a/pform.cc b/pform.cc index 1cf58e4fa..d93d48659 100644 --- a/pform.cc +++ b/pform.cc @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998-2016 Stephen Williams (steve@icarus.com) + * Copyright (c) 1998-2017 Stephen Williams (steve@icarus.com) * Copyright CERN 2013 / Stephen Williams (steve@icarus.com) * * This source code is free software; you can redistribute it @@ -40,6 +40,7 @@ # include # include # include +# include # include "ivl_assert.h" # include "ivl_alloc.h" @@ -62,20 +63,19 @@ map pform_modules; map pform_primitives; /* - * typedefs in the $root scope go here. + * The pform_units is a list of the SystemVerilog compilation unit scopes. + * The current compilation unit is the last element in the list. All items + * declared or defined at the top level (outside any design element) are + * added to the current compilation unit scope. */ -mappform_typedefs; -setpform_enum_sets; +vector pform_units; -/* - * Class definitions in the $root scope go here. - */ -map pform_classes; - -/* - * Task and function definitions in the $root scope go here. - */ -map pform_tasks; +static bool is_compilation_unit(LexicalScope*scope) +{ + // A compilation unit is the only scope that doesn't have a parent. + assert(scope); + return scope->parent_scope() == 0; +} std::string vlltype::get_fileline() const { @@ -86,6 +86,42 @@ std::string vlltype::get_fileline() const } +static bool is_hex_digit_str(const char *str) +{ + while (*str) { + if (!isxdigit(*str)) return false; + str++; + } + return true; +} + +static bool is_dec_digit_str(const char *str) +{ + while (*str) { + if (!isdigit(*str)) return false; + str++; + } + return true; +} + +static bool is_oct_digit_str(const char *str) +{ + while (*str) { + if (*str < '0' || *str > '7') return false; + str++; + } + return true; +} + +static bool is_bin_digit_str(const char *str) +{ + while (*str) { + if (*str != '0' && *str != '1') return false; + str++; + } + return true; +} + /* * Parse configuration file with format =, where key * is the hierarchical name of a valid parameter name, and value @@ -152,90 +188,137 @@ void parm_to_defparam_list(const string¶m) ptr = strchr(nkey, '.'); } name.push_back(name_component_t(lex_strings.make(nkey))); + free(key); // Resolve value to PExpr class. Should support all kind of constant // format including based number, dec number, real number and string. - if (*value == '"') { // string type - char *buf = strdup (value); - char *buf_ptr = buf+1; - // Parse until another '"' or '\0' - while (*buf_ptr != '"' && *buf_ptr != '\0') { - buf_ptr++; - // Check for escape, especially '\"', which does not mean the - // end of string. - if (*buf_ptr == '\\' && *(buf_ptr+1) != '\0') - buf_ptr += 2; - } - if (*buf_ptr == '\0') // String end without '"' - cerr << ": error: missing close quote of string for defparam: " << name << endl; - else if (*(buf_ptr+1) != 0) { // '"' appears within string with no escape - cerr << buf_ptr << endl; - cerr << ": error: \'\"\' appears within string value for defparam: " << name - << ". Ignore characters after \'\"\'" << endl; - } - *buf_ptr = '\0'; - buf_ptr = buf+1; - // Remember to use 'new' to allocate string for PEString - // because 'delete' is used by its destructor. - char *nchar = strcpy(new char [strlen(buf_ptr)+1], buf_ptr); - PExpr* ndec = new PEString(nchar); + // Is it a string? + if (*value == '"') { + char *buf = strdup (value); + char *buf_ptr = buf+1; + // Parse until another '"' or '\0' + while (*buf_ptr != '"' && *buf_ptr != '\0') { + buf_ptr++; + // Check for escape, especially '\"', which does not mean the + // end of string. + if (*buf_ptr == '\\' && *(buf_ptr+1) != '\0') + buf_ptr += 2; + } + if (*buf_ptr == '\0') // String end without '"' + cerr << ": error: missing close quote of string for defparam: " << name << endl; + else if (*(buf_ptr+1) != 0) { // '"' appears within string with no escape + cerr << buf_ptr << endl; + cerr << ": error: \'\"\' appears within string value for defparam: " << name + << ". Ignore characters after \'\"\'" << endl; + } + + *buf_ptr = '\0'; + buf_ptr = buf+1; + // Remember to use 'new' to allocate string for PEString + // because 'delete' is used by its destructor. + char *nchar = strcpy(new char [strlen(buf_ptr)+1], buf_ptr); + PExpr* ndec = new PEString(nchar); Module::user_defparms.push_back( make_pair(name, ndec) ); - free(buf); + free(buf); + free(value); + return; } - else { // number type - char *num = strchr(value, '\''); - if (num != 0) { - verinum *val; - // BASED_NUMBER, something like - scope.parameter='b11 - // make sure to check 'h' first because 'b'&'d' may be included - // in hex format - if (strchr(num, 'h') || strchr(num, 'H')) - val = make_unsized_hex(num); - else if (strchr(num, 'd') || strchr(num, 'D')) - if (strchr(num, 'x') || strchr(num, 'X') || strchr(num, 'z') || strchr(num, 'Z')) - val = make_undef_highz_dec(num); - else - val = make_unsized_dec(num); - else if (strchr(num, 'b') || strchr(num, 'B')) { - val = make_unsized_binary(num); - } - else if (strchr(num, 'o') || strchr(num, 'O')) - val = make_unsized_octal(num); - else { - cerr << ": error: value specify error for defparam: " << name << endl; - free(key); - free(value); - return; - } - // BASED_NUMBER with size, something like - scope.parameter=2'b11 - if (num != value) { - *num = 0; - verinum *siz = make_unsized_dec(value); - val = pform_verinum_with_size(siz, val, "", 0); - } - - PExpr* ndec = new PENumber(val); - Module::user_defparms.push_back( make_pair(name, ndec) ); - - } - else { - // REALTIME, something like - scope.parameter=1.22 or scope.parameter=1e2 - if (strchr(value, '.') || strchr(value, 'e') || strchr(value, 'E')) { - verireal *val = new verireal(value); - PExpr* nreal = new PEFNumber(val); - Module::user_defparms.push_back( make_pair(name, nreal) ); - } - else { - // DEC_NUMBER, something like - scope.parameter=3 - verinum *val = make_unsized_dec(value); - PExpr* ndec = new PENumber(val); - Module::user_defparms.push_back( make_pair(name, ndec) ); - } - } + // Is it a based number? + char *num = strchr(value, '\''); + if (num != 0) { + verinum *val; + const char *base = num + 1; + if (*base == 's' || *base == 'S') + base++; + switch (*base) { + case 'h': + case 'H': + if (is_hex_digit_str(base+1)) { + val = make_unsized_hex(num); + } else { + cerr << ": error: invalid digit in hex value specified for defparam: " << name << endl; + free(value); + return; + } + break; + case 'd': + case 'D': + if (is_dec_digit_str(base+1)) { + val = make_unsized_dec(num); + } else { + cerr << ": error: invalid digit in decimal value specified for defparam: " << name << endl; + free(value); + return; + } + break; + case 'o': + case 'O': + if (is_oct_digit_str(base+1)) { + val = make_unsized_octal(num); + } else { + cerr << ": error: invalid digit in octal value specified for defparam: " << name << endl; + free(value); + return; + } + break; + case 'b': + case 'B': + if (is_bin_digit_str(base+1)) { + val = make_unsized_binary(num); + } else { + cerr << ": error: invalid digit in binary value specified for defparam: " << name << endl; + free(value); + return; + } + break; + default: + cerr << ": error: invalid numeric base specified for defparam: " << name << endl; + free(value); + return; + } + if (num != value) { // based number with size + *num = 0; + if (is_dec_digit_str(value)) { + verinum *siz = make_unsized_dec(value); + val = pform_verinum_with_size(siz, val, "", 0); + } else { + cerr << ": error: invalid size for value specified for defparam: " << name << endl; + free(value); + return; + } + } + PExpr* ndec = new PENumber(val); + Module::user_defparms.push_back( make_pair(name, ndec) ); + free(value); + return; } - free(key); + + // Is it a decimal number? + num = (value[0] == '-') ? value + 1 : value; + if (is_dec_digit_str(num)) { + verinum *val = make_unsized_dec(num); + if (value[0] == '-') *val = -(*val); + PExpr* ndec = new PENumber(val); + Module::user_defparms.push_back( make_pair(name, ndec) ); + free(value); + return; + } + + // Is it a real number? + char *end = 0; + double rval = strtod(value, &end); + if (end != value && *end == 0) { + verireal *val = new verireal(rval); + PExpr* nreal = new PEFNumber(val); + Module::user_defparms.push_back( make_pair(name, nreal) ); + free(value); + return; + } + + // None of the above. + cerr << ": error: invalid value specified for defparam: " << name << endl; free(value); } @@ -273,30 +356,27 @@ static PModport*pform_cur_modport = 0; static NetNet::Type pform_default_nettype = NetNet::WIRE; /* - * These variables track the current time scale, as well as where the - * timescale was set. This supports warnings about tangled timescales. + * These variables track the time scale set by the most recent `timescale + * directive. Time scales set by SystemVerilog timeunit and timeprecision + * declarations are stored directly in the current lexical scope. */ static int pform_time_unit; static int pform_time_prec; -/* These two flags check the initial timeprecision and timeunit - * declaration inside a module. - */ -static bool tp_decl_flag = false; -static bool tu_decl_flag = false; - /* - * Flags used to set time_from_timescale based on timeunit and - * timeprecision. + * These variables track where the most recent `timescale directive + * occurred. This allows us to warn about time scales that are inherited + * from another file. */ -static bool tu_global_flag = false; -static bool tp_global_flag = false; -static bool tu_local_flag = false; -static bool tp_local_flag = false; - static char*pform_timescale_file = 0; static unsigned pform_timescale_line; +/* + * These variables track whether we can accept new timeunits declarations. + */ +bool allow_timeunit_decl = true; +bool allow_timeprec_decl = true; + static inline void FILE_NAME(LineInfo*obj, const char*file, unsigned lineno) { obj->set_lineno(lineno); @@ -322,6 +402,7 @@ void pform_pop_scope() { assert(lexical_scope); lexical_scope = lexical_scope->parent_scope(); + assert(lexical_scope); } static LexicalScope::lifetime_t find_lifetime(LexicalScope::lifetime_t lifetime) @@ -329,10 +410,7 @@ static LexicalScope::lifetime_t find_lifetime(LexicalScope::lifetime_t lifetime) if (lifetime != LexicalScope::INHERITED) return lifetime; - if (lexical_scope != 0) - return lexical_scope->default_lifetime; - - return LexicalScope::STATIC; + return lexical_scope->default_lifetime; } static PScopeExtra* find_nearest_scopex(LexicalScope*scope) @@ -346,17 +424,59 @@ static PScopeExtra* find_nearest_scopex(LexicalScope*scope) } /* - * Set the local time unit/precision to the global value. + * Set the local time unit/precision. This version is used for setting + * the time scale for design elements (modules, packages, etc.) and is + * called after any initial timeunit and timeprecision declarations + * have been parsed. */ -static void pform_set_scope_timescale(PScope*scope, const struct vlltype&loc) +void pform_set_scope_timescale(const struct vlltype&loc) { - scope->time_unit = pform_time_unit; - scope->time_precision = pform_time_prec; - /* If we have a timescale file then the time information is from - * a timescale directive. */ - scope->time_from_timescale = pform_timescale_file != 0; + PScopeExtra*scope = dynamic_cast(lexical_scope); + assert(scope); - if (warn_timescale && (lexical_scope == 0) && pform_timescale_file + PScopeExtra*parent = find_nearest_scopex(scope->parent_scope()); + + bool used_global_timescale = false; + if (scope->time_unit_is_default) { + if (is_compilation_unit(scope)) { + scope->time_unit = def_ts_units; + } else if (!is_compilation_unit(parent)) { + scope->time_unit = parent->time_unit; + scope->time_unit_is_default = parent->time_unit_is_default; + } else if (pform_timescale_file != 0) { + scope->time_unit = pform_time_unit; + scope->time_unit_is_default = false; + used_global_timescale = true; + } else /* parent is compilation unit */ { + scope->time_unit = parent->time_unit; + scope->time_unit_is_default = parent->time_unit_is_default; + } + } + if (scope->time_prec_is_default) { + if (is_compilation_unit(scope)) { + scope->time_precision = def_ts_prec; + } else if (!is_compilation_unit(parent)) { + scope->time_precision = parent->time_precision; + scope->time_prec_is_default = parent->time_prec_is_default; + } else if (pform_timescale_file != 0) { + scope->time_precision = pform_time_prec; + scope->time_prec_is_default = false; + used_global_timescale = true; + } else { + scope->time_precision = parent->time_precision; + scope->time_prec_is_default = parent->time_prec_is_default; + } + } + + if (gn_system_verilog() && (scope->time_unit < scope->time_precision)) { + if (scope->time_unit_is_local || scope->time_prec_is_local) { + VLerror("error: a timeprecision is missing or is too large!"); + } + } else { + assert(scope->time_unit >= scope->time_precision); + } + + if (warn_timescale && used_global_timescale && (strcmp(pform_timescale_file, loc.text) != 0)) { cerr << loc.get_fileline() << ": warning: " @@ -365,6 +485,22 @@ static void pform_set_scope_timescale(PScope*scope, const struct vlltype&loc) cerr << pform_timescale_file << ":" << pform_timescale_line << ": ...: The inherited timescale is here." << endl; } + + allow_timeunit_decl = false; + allow_timeprec_decl = false; +} + +/* + * Set the local time unit/precision. This version is used for setting + * the time scale for subsidiary items (classes, subroutines, etc.), + * which simply inherit their time scale from their parent scope. + */ +static void pform_set_scope_timescale(PScope*scope, const PScope*parent) +{ + scope->time_unit = parent->time_unit; + scope->time_precision = parent->time_precision; + scope->time_unit_is_default = parent->time_unit_is_default; + scope->time_prec_is_default = parent->time_prec_is_default; } PClass* pform_push_class_scope(const struct vlltype&loc, perm_string name, @@ -374,19 +510,11 @@ PClass* pform_push_class_scope(const struct vlltype&loc, perm_string name, class_scope->default_lifetime = find_lifetime(lifetime); FILE_NAME(class_scope, loc); - pform_set_scope_timescale(class_scope, loc); - PScopeExtra*scopex = find_nearest_scopex(lexical_scope); - + assert(scopex); assert(!pform_cur_generate); - /* If no scope was found then this is being defined in the - * compilation unit scope. */ - if (scopex == 0) { - pform_classes[name] = class_scope; - lexical_scope = class_scope; - return class_scope; - } + pform_set_scope_timescale(class_scope, scopex); if (scopex->classes.find(name) != scopex->classes.end()) { cerr << class_scope->get_fileline() << ": error: duplicate " @@ -408,7 +536,8 @@ PPackage* pform_push_package_scope(const struct vlltype&loc, perm_string name, pkg_scope->default_lifetime = find_lifetime(lifetime); FILE_NAME(pkg_scope, loc); - pform_set_scope_timescale(pkg_scope, loc); + allow_timeunit_decl = true; + allow_timeprec_decl = true; lexical_scope = pkg_scope; return pkg_scope; @@ -426,15 +555,16 @@ PTask* pform_push_task_scope(const struct vlltype&loc, char*name, task->default_lifetime = default_lifetime; FILE_NAME(task, loc); - pform_set_scope_timescale(task, loc); - PScopeExtra*scopex = find_nearest_scopex(lexical_scope); - if ((scopex == 0) && !gn_system_verilog()) { + assert(scopex); + if (is_compilation_unit(scopex) && !gn_system_verilog()) { cerr << task->get_fileline() << ": error: task declarations " "must be contained within a module." << endl; error_count += 1; } + pform_set_scope_timescale(task, scopex); + if (pform_cur_generate) { // Check if the task is already in the dictionary. if (pform_cur_generate->tasks.find(task->pscope_name()) != @@ -446,7 +576,7 @@ PTask* pform_push_task_scope(const struct vlltype&loc, char*name, error_count += 1; } pform_cur_generate->tasks[task->pscope_name()] = task; - } else if (scopex) { + } else { // Check if the task is already in the dictionary. if (scopex->tasks.find(task->pscope_name()) != scopex->tasks.end()) { cerr << task->get_fileline() << ": error: duplicate " @@ -455,15 +585,6 @@ PTask* pform_push_task_scope(const struct vlltype&loc, char*name, error_count += 1; } scopex->tasks[task->pscope_name()] = task; - - } else { - if (pform_tasks.find(task_name) != pform_tasks.end()) { - cerr << task->get_fileline() << ": error: " - << "Duplicate definition for task '" << name - << "' in $root scope." << endl; - error_count += 1; - } - pform_tasks[task_name] = task; } lexical_scope = task; @@ -483,15 +604,16 @@ PFunction* pform_push_function_scope(const struct vlltype&loc, const char*name, func->default_lifetime = default_lifetime; FILE_NAME(func, loc); - pform_set_scope_timescale(func, loc); - PScopeExtra*scopex = find_nearest_scopex(lexical_scope); - if ((scopex == 0) && !gn_system_verilog()) { + assert(scopex); + if (is_compilation_unit(scopex) && !gn_system_verilog()) { cerr << func->get_fileline() << ": error: function declarations " "must be contained within a module." << endl; error_count += 1; } + pform_set_scope_timescale(func, scopex); + if (pform_cur_generate) { // Check if the function is already in the dictionary. if (pform_cur_generate->funcs.find(func->pscope_name()) != @@ -504,7 +626,7 @@ PFunction* pform_push_function_scope(const struct vlltype&loc, const char*name, } pform_cur_generate->funcs[func->pscope_name()] = func; - } else if (scopex != 0) { + } else { // Check if the function is already in the dictionary. if (scopex->funcs.find(func->pscope_name()) != scopex->funcs.end()) { cerr << func->get_fileline() << ": error: duplicate " @@ -513,15 +635,6 @@ PFunction* pform_push_function_scope(const struct vlltype&loc, const char*name, error_count += 1; } scopex->funcs[func->pscope_name()] = func; - - } else { - if (pform_tasks.find(func_name) != pform_tasks.end()) { - cerr << func->get_fileline() << ": error: " - << "Duplicate definition for function '" << name - << "' in $root scope." << endl; - error_count += 1; - } - pform_tasks[func_name] = func; } lexical_scope = func; @@ -621,23 +734,31 @@ static void pform_put_wire_in_scope(perm_string name, PWire*net) static void pform_put_enum_type_in_scope(enum_type_t*enum_set) { - if (lexical_scope) { - lexical_scope->enum_sets.insert(enum_set); - } else { - pform_enum_sets.insert(enum_set); - } + lexical_scope->enum_sets.insert(enum_set); } -PWire*pform_get_make_wire_in_scope(perm_string name, NetNet::Type net_type, NetNet::PortType port_type, ivl_variable_type_t vt_type) +PWire*pform_get_make_wire_in_scope(const struct vlltype&li, perm_string name, + NetNet::Type net_type, NetNet::PortType port_type, + ivl_variable_type_t vt_type) { PWire*cur = pform_get_wire_in_scope(name); + + // If the wire already exists and is fully defined, this + // must be a redeclaration. Start again with a new wire. + if (cur && cur->get_data_type() != IVL_VT_NO_TYPE) { + LineInfo tloc; + FILE_NAME(&tloc, li); + cerr << tloc.get_fileline() << ": error: duplicate declaration " + "for net or variable '" << name << "'." << endl; + error_count += 1; + delete cur; + cur = 0; + } + if (cur == 0) { cur = new PWire(name, net_type, port_type, vt_type); pform_put_wire_in_scope(name, cur); } else { - // If this is a duplicate wire, the data type has already - // been set, then return NULL. - if (cur->get_data_type() != IVL_VT_NO_TYPE) return 0; bool rc = cur->set_wire_type(net_type); assert(rc); rc = cur->set_data_type(vt_type); @@ -652,12 +773,7 @@ void pform_set_typedef(perm_string name, data_type_t*data_type, std::listtypedefs[name] - : pform_typedefs[name]; + data_type_t*&ref = lexical_scope->typedefs[name]; ivl_assert(*data_type, ref == 0); ref = data_type; @@ -667,25 +783,10 @@ void pform_set_typedef(perm_string name, data_type_t*data_type, std::list::iterator cur = pform_typedefs.find(name); - if (cur != pform_typedefs.end()) - return cur->second; - else - return 0; -} - data_type_t* pform_test_type_identifier(const char*txt) { perm_string name = lex_strings.make(txt); - // If there is no lexical_scope yet, then look only in the - // $root scope for typedefs. - if (lexical_scope == 0) { - return test_type_identifier_in_root(name); - } - LexicalScope*cur_scope = lexical_scope; do { map::iterator cur; @@ -715,10 +816,6 @@ data_type_t* pform_test_type_identifier(const char*txt) cur_scope = cur_scope->parent_scope(); } while (cur_scope); - // See if there is a typedef in the $root scope. - if (data_type_t*tmp = test_type_identifier_in_root(name)) - return tmp; - return 0; } @@ -729,13 +826,6 @@ data_type_t* pform_test_type_identifier(const char*txt) */ bool pform_test_type_identifier_local(perm_string name) { - if (lexical_scope == 0) { - if (test_type_identifier_in_root(name)) - return true; - else - return false; - } - LexicalScope*cur_scope = lexical_scope; map::iterator cur; @@ -886,64 +976,23 @@ static void pform_declare_implicit_nets(PExpr*expr) /* * The lexor calls this function to set the active timescale when it * detects a `timescale directive. The function saves the directive - * values (for use by modules) and if warnings are enabled checks to - * see if some modules have no timescale. + * values (for use by subsequent design elements) and if warnings are + * enabled checks to see if some design elements have no timescale. */ void pform_set_timescale(int unit, int prec, const char*file, unsigned lineno) { - bool first_flag = true; - assert(unit >= prec); pform_time_unit = unit; pform_time_prec = prec; - /* A `timescale clears the timeunit/timeprecision state. */ - tu_global_flag = false; - tp_global_flag = false; if (pform_timescale_file) { free(pform_timescale_file); - first_flag = false; } if (file) pform_timescale_file = strdup(file); else pform_timescale_file = 0; pform_timescale_line = lineno; - - if (!warn_timescale || !first_flag || !file) return; - - /* Look to see if we have any modules without a timescale. */ - bool have_no_ts = false; - map::iterator mod; - for (mod = pform_modules.begin(); mod != pform_modules.end(); ++ mod ) { - const Module*mp = (*mod).second; - if (mp->time_from_timescale || - mp->timescale_warn_done) continue; - have_no_ts = true; - break; - } - - /* If we do then print a message for the new ones. */ - if (have_no_ts) { - cerr << file << ":" << lineno << ": warning: " - << "Some modules have no timescale. This may cause" - << endl; - cerr << file << ":" << lineno << ": : " - << "confusing timing results. Affected modules are:" - << endl; - - for (mod = pform_modules.begin() - ; mod != pform_modules.end() ; ++ mod ) { - Module*mp = (*mod).second; - if (mp->time_from_timescale || - mp->timescale_warn_done) continue; - mp->timescale_warn_done = true; - - cerr << file << ":" << lineno << ": : " - << " -- module " << (*mod).first - << " declared here: " << mp->get_fileline() << endl; - } - } } bool get_time_unit(const char*cp, int &unit) @@ -1063,70 +1112,56 @@ static bool get_time_unit_prec(const char*cp, int &res, bool is_unit) return true; } -void pform_set_timeunit(const char*txt, bool in_module, bool only_check) +void pform_set_timeunit(const char*txt, bool initial_decl) { int val; if (get_time_unit_prec(txt, val, true)) return; - if (in_module) { - if (!only_check) { - pform_cur_module.front()->time_unit = val; - tu_decl_flag = true; - tu_local_flag = true; - } else if (!tu_decl_flag) { - VLerror(yylloc, "error: repeat timeunit found and the " - "initial module timeunit is missing."); - return; - } else if (pform_cur_module.front()->time_unit != val) { - VLerror(yylloc, "error: repeat timeunit does not match " - "the initial module timeunit " - "declaration."); - return; - } + PScopeExtra*scope = dynamic_cast(lexical_scope); + assert(scope); - } else { - /* Skip a global timeunit when `timescale is defined. */ - if (pform_timescale_file) return; - tu_global_flag = true; - pform_time_unit = val; + if (initial_decl) { + scope->time_unit = val; + scope->time_unit_is_local = true; + scope->time_unit_is_default = false; + allow_timeunit_decl = false; + } else if (!scope->time_unit_is_local) { + VLerror(yylloc, "error: repeat timeunit found and the initial " + "timeunit for this scope is missing."); + } else if (scope->time_unit != val) { + VLerror(yylloc, "error: repeat timeunit does not match the " + "initial timeunit for this scope."); } } int pform_get_timeunit() { - if (pform_cur_module.empty()) - return pform_time_unit; - else - return pform_cur_module.front()->time_unit; + PScopeExtra*scopex = find_nearest_scopex(lexical_scope); + assert(scopex); + return scopex->time_unit; } -void pform_set_timeprecision(const char*txt, bool in_module, bool only_check) +void pform_set_timeprec(const char*txt, bool initial_decl) { int val; if (get_time_unit_prec(txt, val, false)) return; - if (in_module) { - if (!only_check) { - pform_cur_module.front()->time_precision = val; - tp_decl_flag = true; - tp_local_flag = true; - } else if (!tp_decl_flag) { - VLerror(yylloc, "error: repeat timeprecision found and the " - "initial module timeprecision is missing."); - return; - } else if (pform_cur_module.front()->time_precision != val) { - VLerror(yylloc, "error: repeat timeprecision does not match " - "the initial module timeprecision " - "declaration."); - return; - } - } else { - /* Skip a global timeprecision when `timescale is defined. */ - if (pform_timescale_file) return; - pform_time_prec = val; - tp_global_flag=true; + PScopeExtra*scope = dynamic_cast(lexical_scope); + assert(scope); + + if (initial_decl) { + scope->time_precision = val; + scope->time_prec_is_local = true; + scope->time_prec_is_default = false; + allow_timeprec_decl = false; + } else if (!scope->time_prec_is_local) { + VLerror(yylloc, "error: repeat timeprecision found and the initial " + "timeprecision for this scope is missing."); + } else if (scope->time_precision != val) { + VLerror(yylloc, "error: repeat timeprecision does not match the " + "initial timeprecision for this scope."); } } @@ -1231,14 +1266,13 @@ void pform_startmodule(const struct vlltype&loc, const char*name, FILE_NAME(cur_module, loc); - pform_set_scope_timescale(cur_module, loc); - tu_local_flag = tu_global_flag; - tp_local_flag = tp_global_flag; - cur_module->library_flag = pform_library_flag; pform_cur_module.push_front(cur_module); + allow_timeunit_decl = true; + allow_timeprec_decl = true; + lexical_scope = cur_module; /* The generate scheme numbering starts with *1*, not @@ -1248,21 +1282,6 @@ void pform_startmodule(const struct vlltype&loc, const char*name, pform_bind_attributes(cur_module->attributes, attr); } -/* - * In SystemVerilog we can have separate timeunit and timeprecision - * declarations. We need to have the values worked out by time this - * task is called. - */ -void pform_check_timeunit_prec() -{ - assert(! pform_cur_module.empty()); - if (gn_system_verilog() && - (pform_cur_module.front()->time_unit < pform_cur_module.front()->time_precision)) { - VLerror("error: a timeprecision is missing or is too large!"); - } else assert(pform_cur_module.front()->time_unit >= - pform_cur_module.front()->time_precision); -} - /* * This function is called by the parser to make a simple port * reference. This is a name without a .X(...), so the internal name @@ -1306,8 +1325,6 @@ void pform_endmodule(const char*name, bool inside_celldefine, Module*cur_module = pform_cur_module.front(); pform_cur_module.pop_front(); - cur_module->time_from_timescale = (tu_local_flag && tp_local_flag) - || (pform_timescale_file != 0); perm_string mod_name = cur_module->mod_name(); assert(strcmp(name, mod_name) == 0); cur_module->is_cell = inside_celldefine; @@ -1334,16 +1351,9 @@ void pform_endmodule(const char*name, bool inside_celldefine, use_module_map[mod_name] = cur_module; } - // The current lexical scope should be this module by now, and - // this module should not have a parent lexical scope. + // The current lexical scope should be this module by now. ivl_assert(*cur_module, lexical_scope == cur_module); pform_pop_scope(); - ivl_assert(*cur_module, ! pform_cur_module.empty() || lexical_scope == 0); - - tp_decl_flag = false; - tu_decl_flag = false; - tu_local_flag = false; - tp_local_flag = false; } static void pform_add_genvar(const struct vlltype&li, const perm_string&name, @@ -2058,9 +2068,11 @@ static void pform_makegate(PGBuiltin::Type type, return; } - for (list::iterator cur = info.parms->begin() - ; cur != info.parms->end() ; ++cur) { - pform_declare_implicit_nets(*cur); + if (info.parms) { + for (list::iterator cur = info.parms->begin() + ; cur != info.parms->end() ; ++cur) { + pform_declare_implicit_nets(*cur); + } } perm_string dev_name = lex_strings.make(info.name); @@ -2129,7 +2141,8 @@ static void pform_make_modgate(perm_string type, struct parmvalue_t*overrides, list*wires, PExpr*msb, PExpr*lsb, - const char*fn, unsigned ln) + const char*fn, unsigned ln, + std::list*attr) { for (list::iterator idx = wires->begin() ; idx != wires->end() ; ++idx) { @@ -2160,6 +2173,7 @@ static void pform_make_modgate(perm_string type, pform_cur_generate->add_gate(cur); else pform_cur_module.front()->add_gate(cur); + pform_bind_attributes(cur->attributes, attr); } static void pform_make_modgate(perm_string type, @@ -2167,7 +2181,8 @@ static void pform_make_modgate(perm_string type, struct parmvalue_t*overrides, list*bind, PExpr*msb, PExpr*lsb, - const char*fn, unsigned ln) + const char*fn, unsigned ln, + std::list*attr) { unsigned npins = bind->size(); named*pins = new named[npins]; @@ -2204,12 +2219,14 @@ static void pform_make_modgate(perm_string type, pform_cur_generate->add_gate(cur); else pform_cur_module.front()->add_gate(cur); + pform_bind_attributes(cur->attributes, attr); } void pform_make_modgates(const struct vlltype&loc, perm_string type, struct parmvalue_t*overrides, - svector*gates) + svector*gates, + std::list*attr) { assert(! pform_cur_module.empty()); if (pform_cur_module.front()->program_block) { @@ -2231,7 +2248,7 @@ void pform_make_modgates(const struct vlltype&loc, pform_make_modgate(type, cur_name, overrides, cur.parms_by_name, cur.range.first, cur.range.second, - cur.file, cur.lineno); + cur.file, cur.lineno, attr); } else if (cur.parms) { @@ -2245,14 +2262,14 @@ void pform_make_modgates(const struct vlltype&loc, pform_make_modgate(type, cur_name, overrides, cur.parms, cur.range.first, cur.range.second, - cur.file, cur.lineno); + cur.file, cur.lineno, attr); } else { list*wires = new list; pform_make_modgate(type, cur_name, overrides, wires, cur.range.first, cur.range.second, - cur.file, cur.lineno); + cur.file, cur.lineno, attr); } } @@ -2677,19 +2694,16 @@ void pform_makewire(const vlltype&li, * net_decl_assign_t argument. */ void pform_makewire(const struct vlltype&li, - std::list*, str_pair_t , + std::list*delay, + str_pair_t str, std::list*assign_list, NetNet::Type type, data_type_t*data_type) { - if ((lexical_scope == 0) && !gn_system_verilog()) { + if (is_compilation_unit(lexical_scope) && !gn_system_verilog()) { VLerror(li, "error: variable declarations must be contained within a module."); return; } - if (lexical_scope == 0) { - VLerror(li, "sorry: variable declarations in the $root scope are not yet supported."); - return; - } list*names = new list; @@ -2704,8 +2718,18 @@ void pform_makewire(const struct vlltype&li, while (! assign_list->empty()) { decl_assignment_t*first = assign_list->front(); assign_list->pop_front(); - // For now, do not handle assignment expressions. - assert(! first->expr.get()); + if (PExpr*expr = first->expr.release()) { + if (type == NetNet::REG || type == NetNet::IMPLICIT_REG) { + pform_make_var_init(li, first->name, expr); + } else { + PWire*cur = pform_get_wire_in_scope(first->name); + assert(cur); + PEIdent*lval = new PEIdent(first->name); + FILE_NAME(lval, li.text, li.first_line); + PGAssign*ass = pform_make_pgassign(lval, expr, delay, str); + FILE_NAME(ass, li.text, li.first_line); + } + } delete first; } } @@ -2989,18 +3013,16 @@ void pform_set_parameter(const struct vlltype&loc, LexicalScope::range_t*value_range) { LexicalScope*scope = lexical_scope; - if ((scope == 0) && !gn_system_verilog()) { + if (is_compilation_unit(scope) && !gn_system_verilog()) { VLerror(loc, "error: parameter declarations must be contained within a module."); return; } - if (scope == 0) { - VLerror(loc, "sorry: parameter declarations in the $root scope are not yet supported."); - return; - } if (scope == pform_cur_generate) { VLerror("parameter declarations are not permitted in generate blocks"); return; } + PScopeExtra*scopex = find_nearest_scopex(lexical_scope); + assert(scopex); // Check if the parameter name is already in the dictionary. if (scope->parameters.find(name) != scope->parameters.end()) { @@ -3008,14 +3030,14 @@ void pform_set_parameter(const struct vlltype&loc, FILE_NAME(&tloc, loc); cerr << tloc.get_fileline() << ": error: duplicate definition " "for parameter '" << name << "' in '" - << pform_cur_module.front()->mod_name() << "'." << endl; + << scopex->pscope_name() << "'." << endl; error_count += 1; } if (scope->localparams.find(name) != scope->localparams.end()) { LineInfo tloc; FILE_NAME(&tloc, loc); cerr << tloc.get_fileline() << ": error: localparam and " - << "parameter in '" << pform_cur_module.front()->mod_name() + << "parameter in '" << scopex->pscope_name() << "' have the same name '" << name << "'." << endl; error_count += 1; } @@ -3027,7 +3049,7 @@ void pform_set_parameter(const struct vlltype&loc, LineInfo tloc; FILE_NAME(&tloc, loc); cerr << tloc.get_fileline() << ": error: specparam and " - "parameter in '" << pform_cur_module.front()->mod_name() + "parameter in '" << scopex->pscope_name() << "' have the same name '" << name << "'." << endl; error_count += 1; } @@ -3064,14 +3086,12 @@ void pform_set_localparam(const struct vlltype&loc, bool signed_flag, list*range, PExpr*expr) { LexicalScope*scope = lexical_scope; - if ((scope == 0) && !gn_system_verilog()) { + if (is_compilation_unit(scope) && !gn_system_verilog()) { VLerror(loc, "error: localparam declarations must be contained within a module."); return; } - if (scope == 0) { - VLerror(loc, "sorry: localparam declarations in the $root scope are not yet supported."); - return; - } + PScopeExtra*scopex = find_nearest_scopex(lexical_scope); + assert(scopex); // Check if the localparam name is already in the dictionary. if (scope->localparams.find(name) != scope->localparams.end()) { @@ -3079,14 +3099,14 @@ void pform_set_localparam(const struct vlltype&loc, FILE_NAME(&tloc, loc); cerr << tloc.get_fileline() << ": error: duplicate definition " "for localparam '" << name << "' in '" - << pform_cur_module.front()->mod_name() << "'." << endl; + << scopex->pscope_name() << "'." << endl; error_count += 1; } if (scope->parameters.find(name) != scope->parameters.end()) { LineInfo tloc; FILE_NAME(&tloc, loc); cerr << tloc.get_fileline() << ": error: parameter and " - << "localparam in '" << pform_cur_module.front()->mod_name() + << "localparam in '" << scopex->pscope_name() << "' have the same name '" << name << "'." << endl; error_count += 1; } @@ -3097,7 +3117,7 @@ void pform_set_localparam(const struct vlltype&loc, LineInfo tloc; FILE_NAME(&tloc, loc); cerr << tloc.get_fileline() << ": error: specparam and " - "localparam in '" << pform_cur_module.front()->mod_name() + "localparam in '" << scopex->pscope_name() << "' have the same name '" << name << "'." << endl; error_count += 1; } @@ -3365,9 +3385,9 @@ void pform_set_port_type(const struct vlltype&li, delete attr; } -static void pform_set_integer_2atom(uint64_t width, bool signed_flag, perm_string name, NetNet::Type net_type, list*attr) +static void pform_set_integer_2atom(const struct vlltype&li, uint64_t width, bool signed_flag, perm_string name, NetNet::Type net_type, list*attr) { - PWire*cur = pform_get_make_wire_in_scope(name, net_type, NetNet::NOT_A_PORT, IVL_VT_BOOL); + PWire*cur = pform_get_make_wire_in_scope(li, name, net_type, NetNet::NOT_A_PORT, IVL_VT_BOOL); assert(cur); cur->set_signed(signed_flag); @@ -3381,12 +3401,12 @@ static void pform_set_integer_2atom(uint64_t width, bool signed_flag, perm_strin pform_bind_attributes(cur->attributes, attr, true); } -static void pform_set_integer_2atom(uint64_t width, bool signed_flag, list*names, NetNet::Type net_type, list*attr) +static void pform_set_integer_2atom(const struct vlltype&li, uint64_t width, bool signed_flag, list*names, NetNet::Type net_type, list*attr) { for (list::iterator cur = names->begin() ; cur != names->end() ; ++ cur ) { perm_string txt = *cur; - pform_set_integer_2atom(width, signed_flag, txt, net_type, attr); + pform_set_integer_2atom(li, width, signed_flag, txt, net_type, attr); } } @@ -3397,7 +3417,7 @@ template static void pform_set2_data_type(const struct vlltype&li, T*d VLerror(li, "Compound type is not PACKED in this context."); } - PWire*net = pform_get_make_wire_in_scope(name, net_type, NetNet::NOT_A_PORT, base_type); + PWire*net = pform_get_make_wire_in_scope(li, name, net_type, NetNet::NOT_A_PORT, base_type); assert(net); net->set_data_type(data_type); pform_bind_attributes(net->attributes, attr, true); @@ -3411,11 +3431,11 @@ template static void pform_set2_data_type(const struct vlltype&li, T*d } } -static void pform_set_enum(enum_type_t*enum_type, +static void pform_set_enum(const struct vlltype&li, enum_type_t*enum_type, perm_string name, NetNet::Type net_type, std::list*attr) { - PWire*cur = pform_get_make_wire_in_scope(name, net_type, NetNet::NOT_A_PORT, enum_type->base_type); + PWire*cur = pform_get_make_wire_in_scope(li, name, net_type, NetNet::NOT_A_PORT, enum_type->base_type); assert(cur); cur->set_signed(enum_type->signed_flag); @@ -3454,7 +3474,7 @@ static void pform_set_enum(const struct vlltype&li, enum_type_t*enum_type, for (list::iterator cur = names->begin() ; cur != names->end() ; ++ cur) { perm_string txt = *cur; - pform_set_enum(enum_type, txt, net_type, attr); + pform_set_enum(li, enum_type, txt, net_type, attr); } } @@ -3478,11 +3498,11 @@ void pform_set_data_type(const struct vlltype&li, data_type_t*data_type, list (data_type)) { - pform_set_integer_2atom(atom2_type->type_code, atom2_type->signed_flag, names, net_type, attr); + pform_set_integer_2atom(li, atom2_type->type_code, atom2_type->signed_flag, names, net_type, attr); } else if (struct_type_t*struct_type = dynamic_cast (data_type)) { - pform_set_struct_type(struct_type, names, net_type, attr); + pform_set_struct_type(li, struct_type, names, net_type, attr); } else if (enum_type_t*enum_type = dynamic_cast (data_type)) { @@ -3503,7 +3523,7 @@ void pform_set_data_type(const struct vlltype&li, data_type_t*data_type, list (data_type)) { - pform_set_class_type(class_type, names, net_type, attr); + pform_set_class_type(li, class_type, names, net_type, attr); } else if (parray_type_t*array_type = dynamic_cast (data_type)) { @@ -3511,7 +3531,7 @@ void pform_set_data_type(const struct vlltype&li, data_type_t*data_type, list (data_type)) { - pform_set_string_type(string_type, names, net_type, attr); + pform_set_string_type(li, string_type, names, net_type, attr); } else { VLerror(li, "internal error: Unexpected data_type."); @@ -3552,6 +3572,16 @@ vector* pform_make_udp_input_ports(list*names) PProcess* pform_make_behavior(ivl_process_type_t type, Statement*st, list*attr) { + // Add an implicit @* around the statement for the always_comb and + // always_latch statements. + if ((type == IVL_PR_ALWAYS_COMB) || (type == IVL_PR_ALWAYS_LATCH)) { + PEventStatement *tmp = new PEventStatement(true); + tmp->set_file(st->get_file()); + tmp->set_lineno(st->get_lineno()); + tmp->set_statement(st); + st = tmp; + } + PProcess*pp = new PProcess(type, st); // If we are in a part of the code where the meta-comment @@ -3571,8 +3601,10 @@ PProcess* pform_make_behavior(ivl_process_type_t type, Statement*st, pform_put_behavior_in_scope(pp); ivl_assert(*st, ! pform_cur_module.empty()); - if (pform_cur_module.front()->program_block && type == IVL_PR_ALWAYS) { - cerr << st->get_fileline() << ": error: Always statements not allowed" + if (pform_cur_module.front()->program_block && + ((type == IVL_PR_ALWAYS) || (type == IVL_PR_ALWAYS_COMB) || + (type == IVL_PR_ALWAYS_FF) || (type == IVL_PR_ALWAYS_LATCH))) { + cerr << st->get_fileline() << ": error: Always statements are not allowed" << " in program blocks." << endl; error_count += 1; } @@ -3624,31 +3656,72 @@ void pform_add_modport_port(const struct vlltype&loc, FILE*vl_input = 0; extern void reset_lexor(); -int pform_parse(const char*path, FILE*file) +int pform_parse(const char*path) { vl_file = path; - if (file == 0) { + if (strcmp(path, "-") == 0) { + vl_input = stdin; + } else if (ivlpp_string) { + char*cmdline = (char*)malloc(strlen(ivlpp_string) + + strlen(path) + 4); + strcpy(cmdline, ivlpp_string); + strcat(cmdline, " \""); + strcat(cmdline, path); + strcat(cmdline, "\""); - if (strcmp(path, "-") == 0) - vl_input = stdin; - else - vl_input = fopen(path, "r"); + if (verbose_flag) + cerr << "Executing: " << cmdline << endl<< flush; + + vl_input = popen(cmdline, "r"); if (vl_input == 0) { - cerr << "Unable to open " <default_lifetime = LexicalScope::STATIC; + unit->set_file(filename_strings.make(path)); + unit->set_lineno(1); + pform_units.push_back(unit); + + pform_set_timescale(def_ts_units, def_ts_prec, 0, 0); + + allow_timeunit_decl = true; + allow_timeprec_decl = true; + + lexical_scope = unit; + } reset_lexor(); error_count = 0; warn_count = 0; int rc = VLparse(); - if (file == 0) - fclose(vl_input); + if (vl_input != stdin) { + if (ivlpp_string) + pclose(vl_input); + else + fclose(vl_input); + } if (rc) { cerr << "I give up." << endl; diff --git a/pform.h b/pform.h index e9d553127..2b9c04f23 100644 --- a/pform.h +++ b/pform.h @@ -1,7 +1,7 @@ #ifndef IVL_pform_H #define IVL_pform_H /* - * Copyright (c) 1998-2016 Stephen Williams (steve@icarus.com) + * Copyright (c) 1998-2017 Stephen Williams (steve@icarus.com) * * This source code is free software; you can redistribute it * and/or modify it in source code form under the terms of the GNU @@ -147,7 +147,11 @@ extern bool pform_in_interface(void); */ extern PWire* pform_get_wire_in_scope(perm_string name); -extern PWire* pform_get_make_wire_in_scope(perm_string name, NetNet::Type net_type, NetNet::PortType port_type, ivl_variable_type_t vt_type); +extern PWire* pform_get_make_wire_in_scope(const struct vlltype&li, + perm_string name, + NetNet::Type net_type, + NetNet::PortType port_type, + ivl_variable_type_t vt_type); /* * The parser uses startmodule and endmodule together to build up a @@ -165,8 +169,8 @@ extern void pform_startmodule(const struct vlltype&loc, const char*name, bool program_block, bool is_interface, LexicalScope::lifetime_t lifetime, list*attr); -extern void pform_check_timeunit_prec(); extern void pform_module_set_ports(vector*); +extern void pform_set_scope_timescale(const struct vlltype&loc); /* These functions are used when we have a complete port definition, either in an ansi style or non-ansi style declaration. In this case, we have @@ -386,11 +390,11 @@ extern void pform_set_reg_idx(perm_string name, extern void pform_set_data_type(const struct vlltype&li, data_type_t*, list*names, NetNet::Type net_type, list*attr); -extern void pform_set_struct_type(struct_type_t*struct_type, std::list*names, NetNet::Type net_type, std::list*attr); +extern void pform_set_struct_type(const struct vlltype&li, struct_type_t*struct_type, std::list*names, NetNet::Type net_type, std::list*attr); -extern void pform_set_string_type(const string_type_t*string_type, std::list*names, NetNet::Type net_type, std::list*attr); +extern void pform_set_string_type(const struct vlltype&li, const string_type_t*string_type, std::list*names, NetNet::Type net_type, std::list*attr); -extern void pform_set_class_type(class_type_t*class_type, std::list*names, NetNet::Type net_type, std::list*addr); +extern void pform_set_class_type(const struct vlltype&li, class_type_t*class_type, std::list*names, NetNet::Type net_type, std::list*addr); /* pform_set_attrib and pform_set_type_attrib exist to support the @@ -478,7 +482,8 @@ extern void pform_makegates(const struct vlltype&loc, extern void pform_make_modgates(const struct vlltype&loc, perm_string type, struct parmvalue_t*overrides, - svector*gates); + svector*gates, + list*attr); /* Make a continuous assignment node, with optional bit- or part- select. */ extern void pform_make_pgassign_list(list*alist, @@ -566,8 +571,12 @@ extern void parm_to_defparam_list(const string¶m); */ extern bool get_time_unit(const char*cp, int &unit); extern int pform_get_timeunit(); -extern void pform_set_timeunit(const char*txt, bool in_module, bool only_check); -extern void pform_set_timeprecision(const char*txt, bool in_module, - bool only_check); +extern void pform_set_timeunit(const char*txt, bool initial_decl); +extern void pform_set_timeprec(const char*txt, bool initial_decl); +/* + * Flags to determine whether this is an initial declaration. + */ +extern bool allow_timeunit_decl; +extern bool allow_timeprec_decl; #endif /* IVL_pform_H */ diff --git a/pform_class_type.cc b/pform_class_type.cc index ec2f99de4..9c1b7354e 100644 --- a/pform_class_type.cc +++ b/pform_class_type.cc @@ -22,18 +22,18 @@ # include "parse_misc.h" # include "ivl_assert.h" -static void pform_set_class_type(class_type_t*class_type, perm_string name, NetNet::Type net_type, list*attr) +static void pform_set_class_type(const struct vlltype&li, class_type_t*class_type, perm_string name, NetNet::Type net_type, list*attr) { - PWire*net = pform_get_make_wire_in_scope(name, net_type, NetNet::NOT_A_PORT, IVL_VT_CLASS); + PWire*net = pform_get_make_wire_in_scope(li, name, net_type, NetNet::NOT_A_PORT, IVL_VT_CLASS); assert(net); net->set_data_type(class_type); pform_bind_attributes(net->attributes, attr, true); } -void pform_set_class_type(class_type_t*class_type, list*names, NetNet::Type net_type, list*attr) +void pform_set_class_type(const struct vlltype&li, class_type_t*class_type, list*names, NetNet::Type net_type, list*attr) { for (list::iterator cur = names->begin() ; cur != names->end() ; ++ cur) { - pform_set_class_type(class_type, *cur, net_type, attr); + pform_set_class_type(li, class_type, *cur, net_type, attr); } } diff --git a/pform_dump.cc b/pform_dump.cc index 07b9cbf59..c0f329f86 100644 --- a/pform_dump.cc +++ b/pform_dump.cc @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998-2016 Stephen Williams (steve@icarus.com) + * Copyright (c) 1998-2017 Stephen Williams (steve@icarus.com) * * This source code is free software; you can redistribute it * and/or modify it in source code form under the terms of the GNU @@ -121,6 +121,15 @@ std::ostream& operator << (std::ostream&out, ivl_process_type_t pt) case IVL_PR_ALWAYS: out << "always"; break; + case IVL_PR_ALWAYS_COMB: + out << "always_comb"; + break; + case IVL_PR_ALWAYS_FF: + out << "always_ff"; + break; + case IVL_PR_ALWAYS_LATCH: + out << "always_latch"; + break; case IVL_PR_FINAL: out << "final"; break; @@ -627,10 +636,10 @@ void PGBuiltin::dump(ostream&out, unsigned ind) const out << "bufif1 "; break; case PGBuiltin::NOTIF0: - out << "bufif0 "; + out << "notif0 "; break; case PGBuiltin::NOTIF1: - out << "bufif1 "; + out << "notif1 "; break; case PGBuiltin::NAND: out << "nand "; @@ -729,6 +738,7 @@ void PGModule::dump(ostream&out, unsigned ind) const dump_pins(out); } out << ");" << endl; + dump_attributes_map(out, attributes, 8); } void Statement::dump(ostream&out, unsigned ind) const @@ -843,7 +853,7 @@ void PCase::dump(ostream&out, unsigned ind) const for (unsigned idx = 0 ; idx < items_->count() ; idx += 1) { PCase::Item*cur = (*items_)[idx]; - if (cur->expr.size()) { + if (! cur->expr.empty()) { out << setw(ind+2) << "" << "default:"; } else { @@ -1175,6 +1185,11 @@ void AProcess::dump(ostream&out, unsigned ind) const case IVL_PR_ALWAYS: out << setw(ind) << "" << "analog"; break; + case IVL_PR_ALWAYS_COMB: + case IVL_PR_ALWAYS_FF: + case IVL_PR_ALWAYS_LATCH: + assert(0); + break; case IVL_PR_FINAL: out << setw(ind) << "" << "analog final"; break; @@ -1705,8 +1720,10 @@ void PPackage::pform_dump(std::ostream&out) const dump_localparams_(out, 4); dump_parameters_(out, 4); dump_enumerations_(out, 4); + dump_wires_(out, 4); dump_tasks_(out, 4); dump_funcs_(out, 4); + dump_var_inits_(out, 4); out << "endpackage" << endl; } diff --git a/pform_package.cc b/pform_package.cc index 4c4b38440..6014acb7f 100644 --- a/pform_package.cc +++ b/pform_package.cc @@ -153,6 +153,11 @@ void pform_package_import(const struct vlltype&, PPackage*pkg, const char*ident) scope->imports[cur->first] = pkg; } + + for (set::const_iterator cur = pkg->enum_sets.begin() + ; cur != pkg->enum_sets.end() ; ++ cur) { + scope->enum_sets.insert(*cur); + } } } diff --git a/pform_string_type.cc b/pform_string_type.cc index 50a7f4fce..9d1ec73bc 100644 --- a/pform_string_type.cc +++ b/pform_string_type.cc @@ -21,18 +21,17 @@ # include "parse_misc.h" # include "ivl_assert.h" -static void pform_set_string_type(const string_type_t*, perm_string name, NetNet::Type net_type, list*attr) +static void pform_set_string_type(const struct vlltype&li, const string_type_t*, perm_string name, NetNet::Type net_type, list*attr) { - PWire*net = pform_get_make_wire_in_scope(name, net_type, NetNet::NOT_A_PORT, IVL_VT_STRING); + PWire*net = pform_get_make_wire_in_scope(li, name, net_type, NetNet::NOT_A_PORT, IVL_VT_STRING); assert(net); pform_bind_attributes(net->attributes, attr, true); } -void pform_set_string_type(const string_type_t*string_type, list*names, NetNet::Type net_type, list*attr) +void pform_set_string_type(const struct vlltype&li, const string_type_t*string_type, list*names, NetNet::Type net_type, list*attr) { for (list::iterator cur = names->begin() ; cur != names->end() ; ++ cur) { - pform_set_string_type(string_type, *cur, net_type, attr); + pform_set_string_type(li, string_type, *cur, net_type, attr); } } - diff --git a/pform_struct_type.cc b/pform_struct_type.cc index 433e66a91..d4ef9e7c9 100644 --- a/pform_struct_type.cc +++ b/pform_struct_type.cc @@ -62,20 +62,20 @@ ivl_variable_type_t struct_type_t::figure_packed_base_type(void) const * out the base type of the packed variable. Elaboration, later on, * well figure out the rest. */ -static void pform_set_packed_struct(struct_type_t*struct_type, perm_string name, NetNet::Type net_type, list*attr) +static void pform_set_packed_struct(const struct vlltype&li, struct_type_t*struct_type, perm_string name, NetNet::Type net_type, list*attr) { ivl_variable_type_t base_type = struct_type->figure_packed_base_type(); - PWire*net = pform_get_make_wire_in_scope(name, net_type, NetNet::NOT_A_PORT, base_type); + PWire*net = pform_get_make_wire_in_scope(li, name, net_type, NetNet::NOT_A_PORT, base_type); assert(net); net->set_data_type(struct_type); pform_bind_attributes(net->attributes, attr, true); } -static void pform_set_struct_type(struct_type_t*struct_type, perm_string name, NetNet::Type net_type, list*attr) +static void pform_set_struct_type(const struct vlltype&li, struct_type_t*struct_type, perm_string name, NetNet::Type net_type, list*attr) { if (struct_type->packed_flag) { - pform_set_packed_struct(struct_type, name, net_type, attr); + pform_set_packed_struct(li, struct_type, name, net_type, attr); return; } @@ -83,11 +83,11 @@ static void pform_set_struct_type(struct_type_t*struct_type, perm_string name, N // a "sorry" message, so no need to do anything here. } -void pform_set_struct_type(struct_type_t*struct_type, list*names, NetNet::Type net_type, list*attr) +void pform_set_struct_type(const struct vlltype&li, struct_type_t*struct_type, list*names, NetNet::Type net_type, list*attr) { for (list::iterator cur = names->begin() ; cur != names->end() ; ++ cur) { - pform_set_struct_type(struct_type, *cur, net_type, attr); + pform_set_struct_type(li, struct_type, *cur, net_type, attr); } } @@ -99,7 +99,7 @@ static void pform_makewire(const struct vlltype&li, { ivl_variable_type_t base_type = struct_type->figure_packed_base_type(); - PWire*cur = pform_get_make_wire_in_scope(name, NetNet::WIRE, ptype, base_type); + PWire*cur = pform_get_make_wire_in_scope(li, name, NetNet::WIRE, ptype, base_type); assert(cur); FILE_NAME(cur, li); cur->set_data_type(struct_type); diff --git a/pform_types.h b/pform_types.h index 22dab4b46..92061527e 100644 --- a/pform_types.h +++ b/pform_types.h @@ -1,7 +1,7 @@ #ifndef IVL_pform_types_H #define IVL_pform_types_H /* - * Copyright (c) 2007-2016 Stephen Williams (steve@icarus.com) + * Copyright (c) 2007-2018 Stephen Williams (steve@icarus.com) * * This source code is free software; you can redistribute it * and/or modify it in source code form under the terms of the GNU @@ -33,6 +33,10 @@ # include # include +#if __cplusplus < 201103L +#define unique_ptr auto_ptr +#endif + /* * parse-form types. */ @@ -117,7 +121,7 @@ struct name_component_t { struct decl_assignment_t { perm_string name; std::listindex; - std::auto_ptr expr; + std::unique_ptr expr; }; struct pform_tf_port_t { @@ -170,14 +174,14 @@ struct enum_type_t : public data_type_t { ivl_variable_type_t base_type; bool signed_flag; bool integer_flag; // True if "integer" was used - std::auto_ptr< list > range; - std::auto_ptr< list > names; + std::unique_ptr< list > range; + std::unique_ptr< list > names; LineInfo li; }; struct struct_member_t : public LineInfo { - std::auto_ptr type; - std::auto_ptr< list > names; + std::unique_ptr type; + std::unique_ptr< list > names; void pform_dump(std::ostream&out, unsigned indent) const; }; @@ -188,7 +192,7 @@ struct struct_type_t : public data_type_t { bool packed_flag; bool union_flag; - std::auto_ptr< list > members; + std::unique_ptr< list > members; }; struct atom2_type_t : public data_type_t { @@ -234,7 +238,7 @@ struct vector_type_t : public data_type_t { bool reg_flag; // True if "reg" was used bool integer_flag; // True if "integer" was used bool implicit_flag; // True if this type is implicitly logic/reg - std::auto_ptr< list > pdims; + std::unique_ptr< list > pdims; }; struct array_base_t : public data_type_t { @@ -243,7 +247,7 @@ struct array_base_t : public data_type_t { : base_type(btype), dims(pd) { } data_type_t*base_type; - std::auto_ptr< list > dims; + std::unique_ptr< list > dims; }; /* @@ -376,4 +380,8 @@ extern std::ostream& operator<< (std::ostream&out, const pform_name_t&); extern std::ostream& operator<< (std::ostream&out, const name_component_t&that); extern std::ostream& operator<< (std::ostream&out, const index_component_t&that); +#if __cplusplus < 201103L +#undef unique_ptr +#endif + #endif /* IVL_pform_types_H */ diff --git a/svector.h b/svector.h index 730428474..44864bda6 100644 --- a/svector.h +++ b/svector.h @@ -1,7 +1,7 @@ #ifndef IVL_svector_H #define IVL_svector_H /* - * Copyright (c) 1999-2014 Stephen Williams (steve@icarus.com) + * Copyright (c) 1999-2017 Stephen Williams (steve@icarus.com) * * This source code is free software; you can redistribute it * and/or modify it in source code form under the terms of the GNU @@ -57,7 +57,7 @@ template class svector { items_[l.nitems_+idx] = r[idx]; } - svector(const svector&l, TYPE r) + svector(const svector&l, TYPE&r) : nitems_(l.nitems_ + 1), items_(new TYPE[nitems_]) { for (unsigned idx = 0 ; idx < l.nitems_ ; idx += 1) items_[idx] = l[idx]; diff --git a/symbol_search.cc b/symbol_search.cc index fe24e33a0..8b8e22239 100644 --- a/symbol_search.cc +++ b/symbol_search.cc @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003-2015 Stephen Williams (steve@icarus.com) + * Copyright (c) 2003-2017 Stephen Williams (steve@icarus.com) * Copyright CERN 2012 / Stephen Williams (steve@icarus.com) * * This source code is free software; you can redistribute it @@ -143,14 +143,21 @@ static bool symbol_search(const LineInfo*li, Design*des, NetScope*scope, } } - // Don't scan up past a module boundary. - if (scope->type()==NetScope::MODULE && !scope->nested_module()) - break; // Don't scan up if we are searching within a prefixed scope. if (prefix_scope) break; - scope = scope->parent(); + // Don't scan up past a module boundary. + if (scope->type()==NetScope::MODULE && !scope->nested_module()) + scope = 0; + else + scope = scope->parent(); + + // Last chance - try the compilation unit. + if (scope == 0 && start_scope != 0) { + scope = start_scope->unit(); + start_scope = 0; + } } // Last chance: this is a single name, so it might be the name diff --git a/syn-rules.y b/syn-rules.y index ac90c186a..cb9bf50d4 100644 --- a/syn-rules.y +++ b/syn-rules.y @@ -1,7 +1,7 @@ %{ /* - * Copyright (c) 2000-2015 Stephen Williams (steve@icarus.com) + * Copyright (c) 2000-2017 Stephen Williams (steve@icarus.com) * * This source code is free software; you can redistribute it * and/or modify it in source code form under the terms of the GNU @@ -304,6 +304,15 @@ static void syn_start_process(NetProcTop*t) last_ = first_; ptr_ = first_; + // Can the following be converted into S_ALWAYS? + if ((t->type() == IVL_PR_ALWAYS_COMB) || + (t->type() == IVL_PR_ALWAYS_FF) || + (t->type() == IVL_PR_ALWAYS_LATCH)) { + cerr << t->get_fileline() << ": internal error: " + << " Need to check if this can be synthesized." << endl; + assert(0); + } + first_->token = (t->type() == IVL_PR_ALWAYS)? S_ALWAYS : S_INITIAL; first_->top = t; first_->next_ = 0; diff --git a/synth.cc b/synth.cc index 3e4c85a1d..cd7516d3d 100644 --- a/synth.cc +++ b/synth.cc @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999-2012 Stephen Williams (steve@icarus.com) + * Copyright (c) 1999-2017 Stephen Williams (steve@icarus.com) * * This source code is free software; you can redistribute it * and/or modify it in source code form under the terms of the GNU @@ -134,6 +134,9 @@ void synth_f::process(Design*des, NetProcTop*top) top_ = top; switch (top->type()) { case IVL_PR_ALWAYS: + case IVL_PR_ALWAYS_COMB: + case IVL_PR_ALWAYS_FF: + case IVL_PR_ALWAYS_LATCH: proc_always_(des); break; case IVL_PR_INITIAL: diff --git a/t-dll-api.cc b/t-dll-api.cc index 82772e67b..89b0a5aa2 100644 --- a/t-dll-api.cc +++ b/t-dll-api.cc @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000-2016 Stephen Williams (steve@icarus.com) + * Copyright (c) 2000-2018 Stephen Williams (steve@icarus.com) * Copyright CERN 2013 / Stephen Williams (steve@icarus.com) * Copyright (c) 2016 CERN Michele Castellana (michele.castellana@cern.ch) * @@ -93,10 +93,7 @@ extern "C" void ivl_design_roots(ivl_design_t des, ivl_scope_t **scopes, assert (nscopes && scopes); if (des->root_scope_list.size() == 0) { size_t fill = 0; - des->root_scope_list.resize(des->root_tasks.size() + des->packages.size() + des->roots.size() + des->classes.size()); - for (map::iterator idx = des->root_tasks.begin() - ; idx != des->root_tasks.end() ; ++ idx) - des->root_scope_list[fill++] = idx->second; + des->root_scope_list.resize(des->packages.size() + des->roots.size() + des->classes.size()); for (map::iterator idx = des->classes.begin() ; idx != des->classes.end() ; ++ idx) @@ -1238,6 +1235,8 @@ extern "C" ivl_nexus_t ivl_lpm_data(ivl_lpm_t net, unsigned idx) case IVL_LPM_CMP_GT: case IVL_LPM_CMP_NE: case IVL_LPM_CMP_NEE: + case IVL_LPM_CMP_WEQ: + case IVL_LPM_CMP_WNE: case IVL_LPM_DIVIDE: case IVL_LPM_MOD: case IVL_LPM_MULT: @@ -1393,6 +1392,8 @@ extern "C" ivl_nexus_t ivl_lpm_q(ivl_lpm_t net) case IVL_LPM_CMP_EQX: case IVL_LPM_CMP_EQZ: case IVL_LPM_CMP_NEE: + case IVL_LPM_CMP_WEQ: + case IVL_LPM_CMP_WNE: case IVL_LPM_DIVIDE: case IVL_LPM_MOD: case IVL_LPM_MULT: @@ -1519,6 +1520,7 @@ extern "C" unsigned ivl_lpm_selects(ivl_lpm_t net) case IVL_LPM_CONCATZ: cerr << "error: ivl_lpm_selects() is no longer supported for " "IVL_LPM_CONCAT, use ivl_lpm_size() instead." << endl; + // fallthrough default: assert(0); return 0; @@ -1543,6 +1545,8 @@ extern "C" int ivl_lpm_signed(ivl_lpm_t net) case IVL_LPM_CMP_GT: case IVL_LPM_CMP_NE: case IVL_LPM_CMP_NEE: + case IVL_LPM_CMP_WEQ: + case IVL_LPM_CMP_WNE: case IVL_LPM_DIVIDE: case IVL_LPM_MOD: case IVL_LPM_MULT: @@ -2134,7 +2138,7 @@ extern "C" int ivl_scope_func_signed(ivl_scope_t net) assert(net); assert(net->type_==IVL_SCT_FUNCTION); assert(net->func_type==IVL_VT_LOGIC || net->func_type==IVL_VT_BOOL); - return net->func_signed? !0 : 0; + return net->func_signed? 1 : 0; } extern "C" unsigned ivl_scope_func_width(ivl_scope_t net) @@ -2812,6 +2816,16 @@ extern "C" uint64_t ivl_stmt_delay_val(ivl_statement_t net) return net->u_.delay_.value; } +extern "C" unsigned ivl_stmt_needs_t0_trigger(ivl_statement_t net) +{ + assert(net); + if (net->type_ == IVL_ST_WAIT) { + return net->u_.wait_.needs_t0_trigger; + } else { + return 0; + } +} + extern "C" unsigned ivl_stmt_nevent(ivl_statement_t net) { assert(net); diff --git a/t-dll-proc.cc b/t-dll-proc.cc index e668919eb..ba0d4b1a0 100644 --- a/t-dll-proc.cc +++ b/t-dll-proc.cc @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000-2013 Stephen Williams (steve@icarus.com) + * Copyright (c) 2000-2017 Stephen Williams (steve@icarus.com) * * This source code is free software; you can redistribute it * and/or modify it in source code form under the terms of the GNU @@ -847,12 +847,15 @@ bool dll_target::proc_wait(const NetEvWait*net) /* This is a wait fork statement. */ if ((net->nevents() == 1) && (net->event(0) == 0)) { + stmt_cur_->u_.wait_.needs_t0_trigger = 0; stmt_cur_->u_.wait_.event = 0; stmt_cur_->type_ = IVL_ST_WAIT; stmt_cur_->u_.wait_.stmt_->type_ = IVL_ST_NOOP; return true; } + stmt_cur_->u_.wait_.needs_t0_trigger = net->has_t0_trigger(); + // This event processing code is also in the NB assign above. if (net->nevents() > 1) { stmt_cur_->u_.wait_.events = (ivl_event_t*) diff --git a/t-dll.cc b/t-dll.cc index 626f3a74f..ada97415f 100644 --- a/t-dll.cc +++ b/t-dll.cc @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000-2016 Stephen Williams (steve@icarus.com) + * Copyright (c) 2000-2018 Stephen Williams (steve@icarus.com) * Copyright CERN 2013 / Stephen Williams (steve@icarus.com) * * This source code is free software; you can redistribute it @@ -261,12 +261,6 @@ ivl_scope_t dll_target::find_scope(ivl_design_s &des, const NetScope*cur) return tmp; } - if (cur->type()==NetScope::TASK || cur->type()==NetScope::FUNC) { - map::const_iterator idx = des.root_tasks.find(cur); - if (idx != des.root_tasks.end()) - return idx->second; - } - for (unsigned idx = 0; idx < des.roots.size(); idx += 1) { assert(des.roots[idx]); ivl_scope_t scope = find_scope_from_root(des.roots[idx], cur); @@ -650,22 +644,6 @@ void dll_target::add_root(const NetScope *s) case NetScope::CLASS: root_->type_ = IVL_SCT_CLASS; break; - case NetScope::TASK: { - const NetTaskDef*def = s->task_def(); - if (def == 0) { - cerr << "?:?" << ": internal error: " - << "task " << root_->name_ - << " has no definition." << endl; - } - assert(def); - root_->type_ = IVL_SCT_TASK; - root_->tname_ = def->scope()->basename(); - break; - } - break; - case NetScope::FUNC: - fill_in_scope_function(root_, s); - break; default: assert(0); } @@ -694,11 +672,6 @@ void dll_target::add_root(const NetScope *s) des_.classes[s] = root_; break; - case NetScope::TASK: - case NetScope::FUNC: - des_.root_tasks[s] = root_; - break; - default: assert(0); break; @@ -740,11 +713,7 @@ bool dll_target::start_design(const Design*des) } assert(idx == des_.disciplines.size()); - list scope_list = des->find_roottask_scopes(); - for (list::const_iterator cur = scope_list.begin() - ; cur != scope_list.end() ; ++ cur) { - add_root(*cur); - } + list scope_list; scope_list = des->find_package_scopes(); for (list::const_iterator cur = scope_list.begin() @@ -1275,6 +1244,12 @@ void dll_target::net_case_cmp(const NetCaseCmp*net) case NetCaseCmp::NEQ: obj->type = IVL_LPM_CMP_NEE; break; + case NetCaseCmp::WEQ: + obj->type = IVL_LPM_CMP_WEQ; + break; + case NetCaseCmp::WNE: + obj->type = IVL_LPM_CMP_WNE; + break; case NetCaseCmp::XEQ: obj->type = IVL_LPM_CMP_EQX; break; @@ -2544,6 +2519,7 @@ void dll_target::scope(const NetScope*net) case NetScope::PACKAGE: cerr << "?:?" << ": internal error: " << "Package scopes should not have parents." << endl; + // fallthrough case NetScope::MODULE: scop->type_ = IVL_SCT_MODULE; scop->tname_ = net->module_name(); diff --git a/t-dll.h b/t-dll.h index b85bb2d43..879a5c966 100644 --- a/t-dll.h +++ b/t-dll.h @@ -1,7 +1,7 @@ #ifndef IVL_t_dll_H #define IVL_t_dll_H /* - * Copyright (c) 2000-2016 Stephen Williams (steve@icarus.com) + * Copyright (c) 2000-2017 Stephen Williams (steve@icarus.com) * * This source code is free software; you can redistribute it * and/or modify it in source code form under the terms of the GNU @@ -645,7 +645,7 @@ struct ivl_parameter_s { * that generally only matters for VPI calls. */ struct ivl_process_s { - ivl_process_type_t type_ : 2; + ivl_process_type_t type_ : 3; unsigned int analog_flag : 1; ivl_scope_t scope_; ivl_statement_t stmt_; @@ -862,6 +862,7 @@ struct ivl_statement_s { } utask_; struct { /* IVL_ST_TRIGGER IVL_ST_WAIT */ + unsigned needs_t0_trigger; unsigned nevent; union { ivl_event_t event; diff --git a/tgt-pcb/fp.lex b/tgt-pcb/fp.lex index af3292252..3536f51ae 100644 --- a/tgt-pcb/fp.lex +++ b/tgt-pcb/fp.lex @@ -6,7 +6,7 @@ %{ /* - * Copyright (C) 2011-2013 Stephen Williams (steve@icarus.com) + * Copyright (C) 2011-2017 Stephen Williams (steve@icarus.com) * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -79,11 +79,14 @@ void init_fp_lexor(FILE*fd) yyrestart(fd); } +/* + * Modern version of flex (>=2.5.9) can clean up the scanner data. + */ void destroy_fp_lexor() { # ifdef FLEX_SCANNER # if YY_FLEX_MAJOR_VERSION >= 2 && YY_FLEX_MINOR_VERSION >= 5 -# if defined(YY_FLEX_SUBMINOR_VERSION) && YY_FLEX_SUBMINOR_VERSION >= 9 +# if YY_FLEX_MINOR_VERSION > 5 || defined(YY_FLEX_SUBMINOR_VERSION) && YY_FLEX_SUBMINOR_VERSION >= 9 yylex_destroy(); # endif # endif diff --git a/tgt-stub/stub.c b/tgt-stub/stub.c index ea71358be..800c87f82 100644 --- a/tgt-stub/stub.c +++ b/tgt-stub/stub.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000-2016 Stephen Williams (steve@icarus.com) + * Copyright (c) 2000-2017 Stephen Williams (steve@icarus.com) * * This source code is free software; you can redistribute it * and/or modify it in source code form under the terms of the GNU @@ -394,6 +394,12 @@ static void show_lpm_cmp_eeq(ivl_lpm_t net) case IVL_LPM_CMP_NEE: str = "NEE"; break; + case IVL_LPM_CMP_WEQ: + str = "WEQ"; + break; + case IVL_LPM_CMP_WNE: + str = "WNE"; + break; default: assert(0); break; @@ -1043,6 +1049,8 @@ static void show_lpm(ivl_lpm_t net) case IVL_LPM_CMP_EQX: case IVL_LPM_CMP_EQZ: case IVL_LPM_CMP_NEE: + case IVL_LPM_CMP_WEQ: + case IVL_LPM_CMP_WNE: show_lpm_cmp_eeq(net); break; @@ -1158,6 +1166,24 @@ static int show_process(ivl_process_t net, void*x) else fprintf(out, "always\n"); break; + case IVL_PR_ALWAYS_COMB: + if (ivl_process_analog(net)) + assert(0); + else + fprintf(out, "always_comb\n"); + break; + case IVL_PR_ALWAYS_FF: + if (ivl_process_analog(net)) + assert(0); + else + fprintf(out, "always_ff\n"); + break; + case IVL_PR_ALWAYS_LATCH: + if (ivl_process_analog(net)) + assert(0); + else + fprintf(out, "always_latch\n"); + break; case IVL_PR_FINAL: if (ivl_process_analog(net)) fprintf(out, "analog final\n"); diff --git a/tgt-verilog/verilog.c b/tgt-verilog/verilog.c index 333277a59..62616dba0 100644 --- a/tgt-verilog/verilog.c +++ b/tgt-verilog/verilog.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000-2014 Stephen Williams (steve@icarus.com) + * Copyright (c) 2000-2017 Stephen Williams (steve@icarus.com) * * This source code is free software; you can redistribute it * and/or modify it in source code form under the terms of the GNU @@ -393,6 +393,9 @@ static int show_process(ivl_process_t net, void*x) fprintf(out, " initial\n"); break; case IVL_PR_ALWAYS: + case IVL_PR_ALWAYS_COMB: + case IVL_PR_ALWAYS_FF: + case IVL_PR_ALWAYS_LATCH: fprintf(out, " always\n"); break; case IVL_PR_FINAL: diff --git a/tgt-vhdl/stmt.cc b/tgt-vhdl/stmt.cc index 0da0d5e0b..6d9c7f437 100644 --- a/tgt-vhdl/stmt.cc +++ b/tgt-vhdl/stmt.cc @@ -1,7 +1,7 @@ /* * VHDL code generation for statements. * - * Copyright (C) 2008-2013 Nick Gasson (nick@nickg.me.uk) + * Copyright (C) 2008-2018 Nick Gasson (nick@nickg.me.uk) * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -683,8 +683,10 @@ static void get_nexuses_from_expr(ivl_expr_t expr, set &out) break; case IVL_EX_TERNARY: get_nexuses_from_expr(ivl_expr_oper3(expr), out); + // fallthrough case IVL_EX_BINARY: get_nexuses_from_expr(ivl_expr_oper2(expr), out); + // fallthrough case IVL_EX_UNARY: get_nexuses_from_expr(ivl_expr_oper1(expr), out); break; @@ -1248,6 +1250,7 @@ static void process_number(vhdl_binop_expr *all, vhdl_var_ref *test, switch (bits[i]) { case 'x': if (is_casez) break; + // fallthrough case '?': case 'z': continue; // Ignore these. diff --git a/tgt-vhdl/vhdl_element.cc b/tgt-vhdl/vhdl_element.cc index e7e0957b6..1b5c45191 100644 --- a/tgt-vhdl/vhdl_element.cc +++ b/tgt-vhdl/vhdl_element.cc @@ -108,7 +108,7 @@ void vhdl_element::print() const // Trap allocations of vhdl_element subclasses. // This records the pointer allocated in a static field of vhdl_element // so we can delete it just before the code generator exits. -void* vhdl_element::operator new(size_t size) throw (bad_alloc) +void* vhdl_element::operator new(size_t size) { // Let the default new handle the allocation void* ptr = ::operator new(size); @@ -171,4 +171,3 @@ int vhdl_element::free_all_objects() return freed; } - diff --git a/tgt-vhdl/vhdl_element.hh b/tgt-vhdl/vhdl_element.hh index a324e227d..8cf11d4cf 100644 --- a/tgt-vhdl/vhdl_element.hh +++ b/tgt-vhdl/vhdl_element.hh @@ -46,7 +46,7 @@ class vhdl_element { public: virtual ~vhdl_element() {} - void* operator new(size_t size) throw (std::bad_alloc); + void* operator new(size_t size); void operator delete(void* ptr); virtual void emit(std::ostream &of, int level=0) const = 0; @@ -74,4 +74,3 @@ std::string nl_string(int level); void blank_line(std::ostream &of, int level); #endif - diff --git a/tgt-vlog95/event.c b/tgt-vlog95/event.c index f4b3d370d..0a1c0b881 100644 --- a/tgt-vlog95/event.c +++ b/tgt-vlog95/event.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2013 Cary R. (cygcary@yahoo.com) + * Copyright (C) 2011-2017 Cary R. (cygcary@yahoo.com) * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -21,6 +21,24 @@ # include "config.h" # include "vlog95_priv.h" +static unsigned need_ivl_top_module = 0; + +void emit_icarus_generated_top_module() +{ + if (need_ivl_top_module) { + fprintf(vlog_out, +"\n" +"/*\n" +" * This module is used to trigger any always_comb or always_latch processes\n" +" * at time zero to make sure all the outputs have the correct values.\n" +"*/\n" +"module IVL_top_priv_module;\n" +" event IVL_T0_trigger_event;\n" +" initial #0 -> IVL_T0_trigger_event;\n" +"endmodule /* IVL_top_priv_module */\n"); + } +} + void emit_event(ivl_scope_t scope, ivl_statement_t stmt) { unsigned eidx, nevents, first = 1; @@ -68,4 +86,12 @@ void emit_event(ivl_scope_t scope, ivl_statement_t stmt) emit_id(ivl_event_basename(event)); } } + + /* If this is an always_comb/latch then we need to add a trigger to + * get the correct functionality. */ + if (ivl_stmt_needs_t0_trigger(stmt)) { + assert(first == 0); + fprintf(vlog_out, " or IVL_top_priv_module.IVL_T0_trigger_event"); + need_ivl_top_module = 1; + }; } diff --git a/tgt-vlog95/expr.c b/tgt-vlog95/expr.c index f516a7a9e..c8c16c00d 100644 --- a/tgt-vlog95/expr.c +++ b/tgt-vlog95/expr.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2014 Cary R. (cygcary@yahoo.com) + * Copyright (C) 2011-2018 Cary R. (cygcary@yahoo.com) * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -44,8 +44,10 @@ static expr_sign_t expr_get_binary_sign_type(ivl_expr_t expr) switch (ivl_expr_opcode(expr)) { case 'E': case 'e': + case 'w': case 'N': case 'n': + case 'W': case '<': case 'L': case '>': @@ -417,8 +419,10 @@ static void emit_expr_binary(ivl_scope_t scope, ivl_expr_t expr, unsigned wid, case 'p': oper = "**"; break; case 'E': oper = "==="; break; case 'e': oper = "=="; break; + case 'w': oper = "==?"; break; case 'N': oper = "!=="; break; case 'n': oper = "!="; break; + case 'W': oper = "!=?"; break; case '<': oper = "<"; break; case 'L': oper = "<="; break; case '>': oper = ">"; break; @@ -447,6 +451,7 @@ static void emit_expr_binary(ivl_scope_t scope, ivl_expr_t expr, unsigned wid, ivl_expr_file(expr), ivl_expr_lineno(expr)); vlog_errors += 1; } + //fallthrough case '+': case '-': case '*': @@ -465,6 +470,14 @@ static void emit_expr_binary(ivl_scope_t scope, ivl_expr_t expr, unsigned wid, fprintf(vlog_out, " %s ", oper); emit_expr(scope, oper2, wid, 0, can_skip_unsigned, is_full_prec); break; + case 'w': + case 'W': + fprintf(stderr, "%s:%u: vlog95 error: The wild equality operators " + "cannot be converted.\n", + ivl_expr_file(expr), + ivl_expr_lineno(expr)); + vlog_errors += 1; + // fallthrough case 'E': case 'e': case 'N': @@ -492,6 +505,7 @@ static void emit_expr_binary(ivl_scope_t scope, ivl_expr_t expr, unsigned wid, ivl_expr_file(expr), ivl_expr_lineno(expr)); vlog_errors += 1; } + // fallthrough case 'l': case 'r': emit_expr(scope, oper1, wid, 0, 0, 0); diff --git a/tgt-vlog95/logic_lpm.c b/tgt-vlog95/logic_lpm.c index 3754c82c9..202f3ec39 100644 --- a/tgt-vlog95/logic_lpm.c +++ b/tgt-vlog95/logic_lpm.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2016 Cary R. (cygcary@yahoo.com) + * Copyright (C) 2011-2018 Cary R. (cygcary@yahoo.com) * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -398,6 +398,8 @@ static ivl_nexus_t get_lpm_output(ivl_scope_t scope, ivl_lpm_t lpm) case IVL_LPM_CMP_GT: case IVL_LPM_CMP_NE: case IVL_LPM_CMP_NEE: + case IVL_LPM_CMP_WEQ: + case IVL_LPM_CMP_WNE: case IVL_LPM_CONCAT: case IVL_LPM_CONCATZ: case IVL_LPM_DIVIDE: @@ -1194,19 +1196,19 @@ static void emit_lpm_as_ca(ivl_scope_t scope, ivl_lpm_t lpm, fprintf(vlog_out, ")"); break; case IVL_LPM_CMP_EQX: -// HERE: Need to heck that this is not a real nexus. +// HERE: Need to check that this is not a real nexus. fprintf(vlog_out, "("); emit_nexus_as_ca(scope, ivl_lpm_data(lpm, 0), 0, 0); fprintf(vlog_out, " ==? "); emit_nexus_as_ca(scope, ivl_lpm_data(lpm, 1), 0, 0); fprintf(vlog_out, ")"); - fprintf(stderr, "%s:%u: vlog95 error: Compare wildcard equal " + fprintf(stderr, "%s:%u: vlog95 error: Compare wildcard equal (caseX) " "operator is not supported.\n", ivl_lpm_file(lpm), ivl_lpm_lineno(lpm)); vlog_errors += 1; break; case IVL_LPM_CMP_EQZ: -// HERE: Need to heck that this is not a real nexus. +// HERE: Need to check that this is not a real nexus. fprintf(vlog_out, "("); emit_nexus_as_ca(scope, ivl_lpm_data(lpm, 0), 0, 0); fprintf(vlog_out, " == "); @@ -1245,6 +1247,28 @@ static void emit_lpm_as_ca(ivl_scope_t scope, ivl_lpm_t lpm, emit_nexus_as_ca(scope, ivl_lpm_data(lpm, 1), 0, 0); fprintf(vlog_out, ")"); break; + case IVL_LPM_CMP_WEQ: + fprintf(vlog_out, "("); + emit_nexus_as_ca(scope, ivl_lpm_data(lpm, 0), 0, 0); + fprintf(vlog_out, " ==? "); + emit_nexus_as_ca(scope, ivl_lpm_data(lpm, 1), 0, 0); + fprintf(vlog_out, ")"); + fprintf(stderr, "%s:%u: vlog95 error: Wild equality " + "operator is not supported.\n", + ivl_lpm_file(lpm), ivl_lpm_lineno(lpm)); + vlog_errors += 1; + break; + case IVL_LPM_CMP_WNE: + fprintf(vlog_out, "("); + emit_nexus_as_ca(scope, ivl_lpm_data(lpm, 0), 0, 0); + fprintf(vlog_out, " !=? "); + emit_nexus_as_ca(scope, ivl_lpm_data(lpm, 1), 0, 0); + fprintf(vlog_out, ")"); + fprintf(stderr, "%s:%u: vlog95 error: Wild inequality " + "operator is not supported.\n", + ivl_lpm_file(lpm), ivl_lpm_lineno(lpm)); + vlog_errors += 1; + break; /* A concat-Z should never be generated, but report it as an * error if one is generated. */ case IVL_LPM_CONCATZ: @@ -1252,6 +1276,7 @@ static void emit_lpm_as_ca(ivl_scope_t scope, ivl_lpm_t lpm, "should not be generated.\n", ivl_lpm_file(lpm), ivl_lpm_lineno(lpm)); vlog_errors += 1; + // fallthrough case IVL_LPM_CONCAT: emit_lpm_concat(scope, lpm); break; @@ -2429,10 +2454,9 @@ void dump_nexus_information(ivl_scope_t scope, ivl_nexus_t nex) case IVL_VT_BOOL: fprintf(stderr, " bool"); break; case IVL_VT_LOGIC: fprintf(stderr, " logic"); break; case IVL_VT_STRING: fprintf(stderr, " string"); break; - case IVL_VT_DARRAY: fprintf(stderr, " dynamic array"); - case IVL_VT_CLASS: fprintf(stderr, " class"); - case IVL_VT_QUEUE: fprintf(stderr, " queue"); - break; + case IVL_VT_DARRAY: fprintf(stderr, " dynamic array"); break; + case IVL_VT_CLASS: fprintf(stderr, " class"); break; + case IVL_VT_QUEUE: fprintf(stderr, " queue"); break; } if (ivl_signal_signed(sig)) fprintf(stderr, " "); } else fprintf(stderr, "Error: No/missing information!"); diff --git a/tgt-vlog95/stmt.c b/tgt-vlog95/stmt.c index 4fc67135f..8d2a98d5b 100644 --- a/tgt-vlog95/stmt.c +++ b/tgt-vlog95/stmt.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2014 Cary R. (cygcary@yahoo.com) + * Copyright (C) 2011-2017 Cary R. (cygcary@yahoo.com) * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -1606,6 +1606,9 @@ void emit_process(ivl_scope_t scope, ivl_process_t proc) fprintf(vlog_out, "initial"); break; case IVL_PR_ALWAYS: + case IVL_PR_ALWAYS_COMB: + case IVL_PR_ALWAYS_FF: + case IVL_PR_ALWAYS_LATCH: fprintf(vlog_out, "always"); break; case IVL_PR_FINAL: diff --git a/tgt-vlog95/vlog95.c b/tgt-vlog95/vlog95.c index 1890d76b6..8fe45fb10 100644 --- a/tgt-vlog95/vlog95.c +++ b/tgt-vlog95/vlog95.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2010-2016 Cary R. (cygcary@yahoo.com) + * Copyright (C) 2010-2017 Cary R. (cygcary@yahoo.com) * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -30,7 +30,7 @@ static const char*version_string = "Icarus Verilog VLOG95 Code Generator " VERSION " (" VERSION_TAG ")\n\n" -"Copyright (C) 2010-2015 Cary R. (cygcary@yahoo.com)\n\n" +"Copyright (C) 2010-2017 Cary R. (cygcary@yahoo.com)\n\n" " This program is free software; you can redistribute it and/or modify\n" " it under the terms of the GNU General Public License as published by\n" " the Free Software Foundation; either version 2 of the License, or\n" @@ -219,9 +219,12 @@ int target_design(ivl_design_t des) /* Emit any UDP definitions that the design used. */ emit_udp_list(); - /* Emit any UDPs that are Icarus generated (D-FF). */ + /* Emit any UDPs that are Icarus generated (D-FF or latch). */ emit_icarus_generated_udps(); + /* Emit the Icarus top module used to trigger translated always_comb/latch processes at T0. */ + emit_icarus_generated_top_module(); + /* If there were errors then add this information to the output. */ if (vlog_errors) { fprintf(vlog_out, "\n"); diff --git a/tgt-vlog95/vlog95_priv.h b/tgt-vlog95/vlog95_priv.h index 913fd0424..36e3cf543 100644 --- a/tgt-vlog95/vlog95_priv.h +++ b/tgt-vlog95/vlog95_priv.h @@ -1,7 +1,7 @@ #ifndef IVL_vlog95_priv_H #define IVL_vlog95_priv_H /* - * Copyright (C) 2010-2016 Cary R. (cygcary@yahoo.com) + * Copyright (C) 2010-2017 Cary R. (cygcary@yahoo.com) * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -106,7 +106,6 @@ extern void emit_nexus_as_ca(ivl_scope_t scope, ivl_nexus_t nex, extern void emit_nexus_port_driver_as_ca(ivl_scope_t scope, ivl_nexus_t nex); extern void emit_const_nexus(ivl_scope_t scope, ivl_net_const_t const_net); extern void emit_signal_net_const_as_ca(ivl_scope_t scope, ivl_signal_t sig); -extern void emit_icarus_generated_udps(void); extern void add_udp_to_list(ivl_udp_t udp); extern void emit_udp_list(void); @@ -118,6 +117,9 @@ extern void emit_number(const char *bits, unsigned nbits, unsigned is_signed, const char *file, unsigned lineno); extern void emit_string(const char *string); +extern void emit_icarus_generated_udps(void); +extern void emit_icarus_generated_top_module(void); + /* * Find the enclosing module scope. */ diff --git a/tgt-vvp/draw_net_input.c b/tgt-vvp/draw_net_input.c index aa43b2203..86ec41657 100644 --- a/tgt-vvp/draw_net_input.c +++ b/tgt-vvp/draw_net_input.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001-2016 Stephen Williams (steve@icarus.com) + * Copyright (c) 2001-2017 Stephen Williams (steve@icarus.com) * * This source code is free software; you can redistribute it * and/or modify it in source code form under the terms of the GNU @@ -398,6 +398,8 @@ static char* draw_net_input_drive(ivl_nexus_t nex, ivl_nexus_ptr_t nptr) case IVL_LPM_CONCATZ: case IVL_LPM_CMP_EEQ: case IVL_LPM_CMP_EQ: + case IVL_LPM_CMP_WEQ: + case IVL_LPM_CMP_WNE: case IVL_LPM_CMP_EQX: case IVL_LPM_CMP_EQZ: case IVL_LPM_CMP_GE: diff --git a/tgt-vvp/draw_switch.c b/tgt-vvp/draw_switch.c index 01a6f30a5..fa0391810 100644 --- a/tgt-vvp/draw_switch.c +++ b/tgt-vvp/draw_switch.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008-2016 Stephen Williams (steve@icarus.com) + * Copyright (c) 2008-2018 Stephen Williams (steve@icarus.com) * * This source code is free software; you can redistribute it * and/or modify it in source code form under the terms of the GNU @@ -73,6 +73,15 @@ void draw_switch_in_scope(ivl_switch_t sw) } switch (ivl_switch_type(sw)) { + case IVL_SW_RTRAN: + fprintf(vvp_out, " .rtran"); + break; + case IVL_SW_RTRANIF0: + fprintf(vvp_out, " .rtranif0"); + break; + case IVL_SW_RTRANIF1: + fprintf(vvp_out, " .rtranif1"); + break; case IVL_SW_TRAN: fprintf(vvp_out, " .tran"); break; @@ -88,8 +97,7 @@ void draw_switch_in_scope(ivl_switch_t sw) break; default: - fprintf(stderr, "%s:%u: tgt-vvp sorry: resistive switch modeling " - "is not currently supported.\n", + fprintf(stderr, "%s:%u: tgt-vvp error: unrecognised switch type.\n", ivl_switch_file(sw), ivl_switch_lineno(sw)); vvp_errors += 1; return; diff --git a/tgt-vvp/eval_object.c b/tgt-vvp/eval_object.c index fb6240d17..7a307b150 100644 --- a/tgt-vvp/eval_object.c +++ b/tgt-vvp/eval_object.c @@ -82,6 +82,7 @@ static int eval_darray_new(ivl_expr_t ex) unsigned idx; switch (ivl_type_base(element_type)) { case IVL_VT_BOOL: + case IVL_VT_LOGIC: for (idx = 0 ; idx < ivl_expr_parms(init_expr) ; idx += 1) { draw_eval_vec4(ivl_expr_parm(init_expr,idx)); fprintf(vvp_out, " %%ix/load 3, %u, 0;\n", idx); @@ -110,6 +111,11 @@ static int eval_darray_new(ivl_expr_t ex) errors += 1; break; } + } else if (init_expr && (ivl_expr_value(init_expr) == IVL_VT_DARRAY)) { + ivl_signal_t sig = ivl_expr_signal(init_expr); + fprintf(vvp_out, " %%load/obj v%p_0;\n", sig); + fprintf(vvp_out, " %%scopy;\n"); + } else if (init_expr && number_is_immediate(size_expr,32,0)) { /* In this case, there is an init expression, the expression is NOT an array_pattern, and the size diff --git a/tgt-vvp/eval_real.c b/tgt-vvp/eval_real.c index a3c4d69c6..d7f1cfb4b 100644 --- a/tgt-vvp/eval_real.c +++ b/tgt-vvp/eval_real.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003-2013 Stephen Williams (steve@icarus.com) + * Copyright (c) 2003-2017 Stephen Williams (steve@icarus.com) * * This source code is free software; you can redistribute it * and/or modify it in source code form under the terms of the GNU @@ -57,6 +57,8 @@ static void draw_binary_real(ivl_expr_t expr) switch (ivl_expr_opcode(expr)) { case 'E': case 'N': + case 'w': + case 'W': case 'l': case 'r': case 'R': diff --git a/tgt-vvp/eval_vec4.c b/tgt-vvp/eval_vec4.c index 2afd1fbbc..c4516029e 100644 --- a/tgt-vvp/eval_vec4.c +++ b/tgt-vvp/eval_vec4.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013-2015 Stephen Williams (steve@icarus.com) + * Copyright (c) 2013-2017 Stephen Williams (steve@icarus.com) * * This source code is free software; you can redistribute it * and/or modify it in source code form under the terms of the GNU @@ -385,8 +385,7 @@ static void draw_binary_vec4_compare(ivl_expr_t expr) fprintf(vvp_out, " %%flag_get/vec4 4;\n"); break; case 'n': /* != */ - fprintf(vvp_out, " %%cmp/e;\n"); - fprintf(vvp_out, " %%flag_inv 4;\n"); + fprintf(vvp_out, " %%cmp/ne;\n"); fprintf(vvp_out, " %%flag_get/vec4 4;\n"); break; case 'E': /* === */ @@ -394,10 +393,17 @@ static void draw_binary_vec4_compare(ivl_expr_t expr) fprintf(vvp_out, " %%flag_get/vec4 6;\n"); break; case 'N': /* !== */ - fprintf(vvp_out, " %%cmp/e;\n"); - fprintf(vvp_out, " %%flag_inv 6;\n"); + fprintf(vvp_out, " %%cmp/ne;\n"); fprintf(vvp_out, " %%flag_get/vec4 6;\n"); break; + case 'w': /* ==? */ + fprintf(vvp_out, " %%cmp/we;\n"); + fprintf(vvp_out, " %%flag_get/vec4 4;\n"); + break; + case 'W': /* !=? */ + fprintf(vvp_out, " %%cmp/wne;\n"); + fprintf(vvp_out, " %%flag_get/vec4 4;\n"); + break; default: assert(0); } @@ -689,8 +695,10 @@ static void draw_binary_vec4(ivl_expr_t expr) case 'e': /* == */ case 'E': /* === */ - case 'n': /* !== */ + case 'n': /* != */ case 'N': /* !== */ + case 'w': /* ==? */ + case 'W': /* !=? */ draw_binary_vec4_compare(expr); break; diff --git a/tgt-vvp/vvp_process.c b/tgt-vvp/vvp_process.c index 4b41a4bdf..a8d2f1dfa 100644 --- a/tgt-vvp/vvp_process.c +++ b/tgt-vvp/vvp_process.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001-2016 Stephen Williams (steve@icarus.com) + * Copyright (c) 2001-2017 Stephen Williams (steve@icarus.com) * * This source code is free software; you can redistribute it * and/or modify it in source code form under the terms of the GNU @@ -1643,6 +1643,7 @@ static int show_stmt_utask(ivl_statement_t net) static int show_stmt_wait(ivl_statement_t net, ivl_scope_t sscope) { + static unsigned int cascade_counter = 0; /* Look to see if this is a SystemVerilog wait fork. */ if ((ivl_stmt_nevent(net) == 1) && (ivl_stmt_events(net, 0) == 0)) { assert(ivl_statement_type(ivl_stmt_sub_stmt(net)) == IVL_ST_NOOP); @@ -1655,11 +1656,17 @@ static int show_stmt_wait(ivl_statement_t net, ivl_scope_t sscope) if (ivl_stmt_nevent(net) == 1) { ivl_event_t ev = ivl_stmt_events(net, 0); - fprintf(vvp_out, " %%wait E_%p;\n", ev); + if (ivl_stmt_needs_t0_trigger(net)) { + fprintf(vvp_out, "Ewait_%u .event/or E_%p, E_0x0;\n", + cascade_counter, ev); + fprintf(vvp_out, " %%wait Ewait_%u;\n", cascade_counter); + cascade_counter += 1; + } else { + fprintf(vvp_out, " %%wait E_%p;\n", ev); + } } else { unsigned idx; - static unsigned int cascade_counter = 0; ivl_event_t ev = ivl_stmt_events(net, 0); fprintf(vvp_out, "Ewait_%u .event/or E_%p", cascade_counter, ev); @@ -1667,6 +1674,7 @@ static int show_stmt_wait(ivl_statement_t net, ivl_scope_t sscope) ev = ivl_stmt_events(net, idx); fprintf(vvp_out, ", E_%p", ev); } + assert(ivl_stmt_needs_t0_trigger(net) == 0); fprintf(vvp_out, ";\n %%wait Ewait_%u;\n", cascade_counter); cascade_counter += 1; } @@ -2358,6 +2366,9 @@ int draw_process(ivl_process_t net, void*x) break; case IVL_PR_ALWAYS: + case IVL_PR_ALWAYS_COMB: + case IVL_PR_ALWAYS_FF: + case IVL_PR_ALWAYS_LATCH: fprintf(vvp_out, " %%jmp T_%u;\n", thread_count); break; } @@ -2368,6 +2379,9 @@ int draw_process(ivl_process_t net, void*x) case IVL_PR_INITIAL: case IVL_PR_ALWAYS: + case IVL_PR_ALWAYS_COMB: + case IVL_PR_ALWAYS_FF: + case IVL_PR_ALWAYS_LATCH: if (init_flag) { fprintf(vvp_out, " .thread T_%u, $init;\n", thread_count); } else if (push_flag) { diff --git a/tgt-vvp/vvp_scope.c b/tgt-vvp/vvp_scope.c index 6486d72cb..3177e7976 100644 --- a/tgt-vvp/vvp_scope.c +++ b/tgt-vvp/vvp_scope.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001-2016 Stephen Williams (steve@icarus.com) + * Copyright (c) 2001-2018 Stephen Williams (steve@icarus.com) * * This source code is free software; you can redistribute it * and/or modify it in source code form under the terms of the GNU @@ -860,6 +860,7 @@ static void draw_udp_in_scope(ivl_net_logic_t lptr) * (.resolv, etc.) can be built before we build the .udp call. * This matches what is done for the other primitives. */ + assert(ivl_logic_pins(lptr) > 0); ninp = ivl_logic_pins(lptr) - 1; input_strings = calloc(ninp, sizeof(char*)); for (pdx = 0 ; pdx < ninp ; pdx += 1) { @@ -922,7 +923,7 @@ static void draw_logic_in_scope(ivl_net_logic_t lptr) ivl_drive_t str1 = ivl_logic_drive1(lptr); int level; - int ninp; + unsigned ninp; const char **input_strings; switch (ivl_logic_type(lptr)) { @@ -1055,8 +1056,8 @@ static void draw_logic_in_scope(ivl_net_logic_t lptr) /* Get all the input label that I will use for parameters to the functor that I create later. */ + assert(ivl_logic_pins(lptr) > 0); ninp = ivl_logic_pins(lptr) - 1; - assert(ninp >= 0); input_strings = calloc(ninp, sizeof(char*)); for (pdx = 0 ; pdx < (unsigned)ninp ; pdx += 1) input_strings[pdx] = draw_net_input(ivl_logic_pin(lptr, pdx+1)); @@ -1521,6 +1522,16 @@ static void draw_lpm_cmp(ivl_lpm_t net) type = "nee"; signed_string = ""; break; + case IVL_LPM_CMP_WEQ: + assert(dtc != IVL_VT_REAL); /* Should never get here! */ + type = "weq"; + signed_string = ""; + break; + case IVL_LPM_CMP_WNE: + assert(dtc != IVL_VT_REAL); /* Should never get here! */ + type = "wne"; + signed_string = ""; + break; default: assert(0); } @@ -2143,6 +2154,8 @@ static void draw_lpm_in_scope(ivl_lpm_t net) case IVL_LPM_CMP_GT: case IVL_LPM_CMP_NE: case IVL_LPM_CMP_NEE: + case IVL_LPM_CMP_WEQ: + case IVL_LPM_CMP_WNE: draw_lpm_cmp(net); return; @@ -2292,7 +2305,7 @@ int draw_scope(ivl_scope_t net, ivl_scope_t parent) unsigned width = ivl_scope_mod_module_port_width(net,idx); if( name == 0 ) name = ""; - fprintf( vvp_out, " .port_info %u %s %u \"%s\"\n", + fprintf( vvp_out, " .port_info %u %s %u \"%s\";\n", idx, vvp_port_info_type_str(ptype), width, vvp_mangle_name(name) ); } diff --git a/verinum.cc b/verinum.cc index c5f4be65e..7b466053b 100644 --- a/verinum.cc +++ b/verinum.cc @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998-2014 Stephen Williams (steve@icarus.com) + * Copyright (c) 1998-2018 Stephen Williams (steve@icarus.com) * * This source code is free software; you can redistribute it * and/or modify it in source code form under the terms of the GNU @@ -22,6 +22,7 @@ # include "verinum.h" # include # include +# include # include // Needed to get pow for as_double(). # include // Needed to get snprintf for as_string(). # include @@ -1444,7 +1445,8 @@ verinum operator / (const verinum&left, const verinum&right) if (use_len <= (8*sizeof(long) - 1)) { long l = left.as_long(); long r = right.as_long(); - long v = l / r; + bool overflow = (l == LONG_MIN) && (r == -1); + long v = overflow ? LONG_MIN : l / r; for (unsigned idx = 0 ; idx < use_len ; idx += 1) { result.set(idx, (v & 1)? verinum::V1 : verinum::V0); v >>= 1; @@ -1518,7 +1520,8 @@ verinum operator % (const verinum&left, const verinum&right) /* Use native signed modulus to do the work. */ long l = left.as_long(); long r = right.as_long(); - long v = l % r; + bool overflow = (l == LONG_MIN) && (r == -1); + long v = overflow ? 0 : l % r; for (unsigned idx = 0 ; idx < use_len ; idx += 1) { result.set(idx, (v & 1)? verinum::V1 : verinum::V0); v >>= 1; diff --git a/veriuser.h b/veriuser.h index 7e061c16f..7614673db 100644 --- a/veriuser.h +++ b/veriuser.h @@ -1,7 +1,7 @@ #ifndef VERIUSER_H #define VERIUSER_H /* - * Copyright (c) 2002-2014 Stephen Williams (steve@icarus.com) + * Copyright (c) 2002-2018 Stephen Williams (steve@icarus.com) * * This source code is free software; you can redistribute it * and/or modify it in source code form under the terms of the GNU @@ -159,6 +159,7 @@ extern void veriusertfs_register_table(p_tfcell vtable); /* callback reasons */ #define reason_checktf 1 +#define reason_sizetf 2 #define reason_calltf 3 #define reason_paramvc 7 #define reason_synch 8 diff --git a/vhdlpp/expression.h b/vhdlpp/expression.h index d31955a89..3ae6c2bb9 100644 --- a/vhdlpp/expression.h +++ b/vhdlpp/expression.h @@ -1,7 +1,7 @@ #ifndef IVL_expression_H #define IVL_expression_H /* - * Copyright (c) 2011-2014 Stephen Williams (steve@icarus.com) + * Copyright (c) 2011-2018 Stephen Williams (steve@icarus.com) * Copyright CERN 2015 / Stephen Williams (steve@icarus.com), * Copyright CERN 2016 * @author Maciej Suminski (maciej.suminski@cern.ch) @@ -39,6 +39,10 @@ class VTypeArray; class VTypePrimitive; class ExpName; +#if __cplusplus < 201103L +#define unique_ptr auto_ptr +#endif + /* * Helper class to recursively traverse an expression tree * (i.e. complex expressions). @@ -273,8 +277,8 @@ class ExpAggregate : public Expression { void dump(ostream&out, int indent) const; private: - std::auto_ptrexpr_; - std::auto_ptr range_; + std::unique_ptrexpr_; + std::unique_ptr range_; private: // not implemented choice_t& operator= (const choice_t&); }; @@ -778,7 +782,7 @@ class ExpName : public Expression { private: Expression*index(unsigned int number) const; - std::auto_ptr prefix_; + std::unique_ptr prefix_; perm_string name_; std::list*indices_; }; @@ -1093,4 +1097,8 @@ private: Expression*delay_; }; +#if __cplusplus < 201103L +#undef unique_ptr +#endif + #endif /* IVL_expression_H */ diff --git a/vhdlpp/lexor.lex b/vhdlpp/lexor.lex index 8dd8d823a..fdafcb058 100644 --- a/vhdlpp/lexor.lex +++ b/vhdlpp/lexor.lex @@ -6,7 +6,7 @@ %{ /* - * Copyright (c) 2011 Stephen Williams (steve@icarus.com) + * Copyright (c) 2011-2017 Stephen Williams (steve@icarus.com) * * This source code is free software; you can redistribute it * and/or modify it in source code form under the terms of the GNU @@ -748,7 +748,16 @@ yyscan_t prepare_lexor(FILE*fd) return scanner; } +/* + * Modern version of flex (>=2.5.9) can clean up the scanner data. + */ void destroy_lexor(yyscan_t scanner) { +# ifdef FLEX_SCANNER +# if YY_FLEX_MAJOR_VERSION >= 2 && YY_FLEX_MINOR_VERSION >= 5 +# if YY_FLEX_MINOR_VERSION > 5 || defined(YY_FLEX_SUBMINOR_VERSION) && YY_FLEX_SUBMINOR_VERSION >= 9 yylex_destroy(scanner); +# endif +# endif +# endif } diff --git a/vhdlpp/std_funcs.cc b/vhdlpp/std_funcs.cc index 4e4a992f4..2880bba98 100644 --- a/vhdlpp/std_funcs.cc +++ b/vhdlpp/std_funcs.cc @@ -1,5 +1,5 @@ /* - * Copyright CERN 2016 + * Copyright CERN 2016-2018 * @author Maciej Suminski (maciej.suminski@cern.ch) * * This source code is free software; you can redistribute it @@ -201,7 +201,7 @@ void preload_std_funcs(void) args = new list(); args->push_back(new InterfacePort(&primitive_REAL)); register_std_subprogram(new SubprogramBuiltin(perm_string::literal("integer"), - perm_string::literal("$signed"), + perm_string::literal("int'"), args, &primitive_INTEGER)); /* function std_logic_vector diff --git a/vpi/Makefile.in b/vpi/Makefile.in index aebdb70b2..a2ee88145 100644 --- a/vpi/Makefile.in +++ b/vpi/Makefile.in @@ -45,13 +45,14 @@ else INCLUDE_PATH = -I. -I.. -I$(srcdir) -I$(srcdir)/.. endif -CPPFLAGS = $(INCLUDE_PATH) @file64_support@ @CPPFLAGS@ @DEFS@ @PICFLAG@ +CPPFLAGS = $(INCLUDE_PATH) @file64_support@ @CPPFLAGS@ @DEFS@ -DICARUS_VPI_CONST=const @PICFLAG@ CFLAGS = @WARNING_FLAGS@ @WARNING_FLAGS_CC@ @CFLAGS@ CXXFLAGS = @WARNING_FLAGS@ @WARNING_FLAGS_CXX@ @CXXFLAGS@ LDFLAGS = @LDFLAGS@ # Object files for system.vpi -O = sys_table.o sys_convert.o sys_countdrivers.o sys_darray.o sys_deposit.o sys_display.o \ +O = sys_table.o sys_convert.o sys_countdrivers.o sys_darray.o sys_deposit.o \ + sys_display.o \ sys_fileio.o sys_finish.o sys_icarus.o sys_plusargs.o sys_queue.o \ sys_random.o sys_random_mti.o sys_readmem.o sys_readmem_lex.o sys_scanf.o \ sys_sdf.o sys_time.o sys_vcd.o sys_vcdoff.o vcd_priv.o mt19937int.o \ @@ -73,7 +74,8 @@ M = sys_clog2.o v2005_math.o # Object files for va_math.vpi V = va_math.o -V2009 = v2009_table.o v2009_array.o v2009_enum.o v2009_string.o +V2009 = v2009_table.o v2009_array.o v2009_bitvec.o v2009_enum.o v2009_string.o \ + sys_priv.o VHDL_SYS = vhdl_table.o sys_priv.o diff --git a/vpi/cppcheck.sup b/vpi/cppcheck.sup index 82af710f0..f0fd8584d 100644 --- a/vpi/cppcheck.sup +++ b/vpi/cppcheck.sup @@ -45,83 +45,83 @@ variableScope:fstapi.c:6238 variableScope:fstapi.c:6466 // These functions are not used by Icarus // fstReaderClrFacProcessMask() -unusedFunction:fstapi.c:3344 +unusedFunction:fstapi.c:3345 // fstReaderClrFacProcessMaskAll() -unusedFunction:fstapi.c:3373 +unusedFunction:fstapi.c:3374 // fstReaderGetAliasCount() -unusedFunction:fstapi.c:3436 +unusedFunction:fstapi.c:3437 // fstReaderGetCurrentFlatScope() -unusedFunction:fstapi.c:3182 +unusedFunction:fstapi.c:3183 // fstReaderGetAliasCount() -unusedFunction:fstapi.c:3279 +unusedFunction:fstapi.c:3280 // fstReaderGetCurrentScopeUserInfo() -unusedFunction:fstapi.c:3196 +unusedFunction:fstapi.c:3197 // fstReaderGetDateString() -unusedFunction:fstapi.c:3464 +unusedFunction:fstapi.c:3465 // fstReaderGetDoubleEndianMatchState() -unusedFunction:fstapi.c:3450 +unusedFunction:fstapi.c:3451 // fstReaderGetDumpActivityChangeTime() -unusedFunction:fstapi.c:3492 +unusedFunction:fstapi.c:3493 // fstReaderGetDumpActivityChangeValue() -unusedFunction:fstapi.c:3507 +unusedFunction:fstapi.c:3508 // fstReaderGetEndTime() -unusedFunction:fstapi.c:3401 +unusedFunction:fstapi.c:3402 // fstReaderGetFacProcessMask() -unusedFunction:fstapi.c:3307 +unusedFunction:fstapi.c:3308 // fstReaderGetFileType() -unusedFunction:fstapi.c:3471 +unusedFunction:fstapi.c:3472 // fstReaderGetFseekFailed() -unusedFunction:fstapi.c:3292 +unusedFunction:fstapi.c:3293 // fstReaderGetMaxHandle() -unusedFunction:fstapi.c:3429 +unusedFunction:fstapi.c:3430 // fstReaderGetMemoryUsedByWriter() -unusedFunction:fstapi.c:3408 +unusedFunction:fstapi.c:3409 // fstReaderGetNumberDumpActivityChanges() -unusedFunction:fstapi.c:3485 +unusedFunction:fstapi.c:3486 // fstReaderGetScopeCount() -unusedFunction:fstapi.c:3415 +unusedFunction:fstapi.c:3416 // fstReaderGetStartTime() -unusedFunction:fstapi.c:3394 +unusedFunction:fstapi.c:3395 // fstReaderGetTimescale() -unusedFunction:fstapi.c:3387 +unusedFunction:fstapi.c:3388 // fstReaderGetTimezero() -unusedFunction:fstapi.c:3478 +unusedFunction:fstapi.c:3479 // fstReaderGetValueChangeSectionCount() -unusedFunction:fstapi.c:3443 +unusedFunction:fstapi.c:3444 // fstReaderGetValueFromHandleAtTime() -unusedFunction:fstapi.c:5685 +unusedFunction:fstapi.c:5686 // fstReaderGetVarCount() -unusedFunction:fstapi.c:3422 +unusedFunction:fstapi.c:3423 // fstReaderGetVersionString() -unusedFunction:fstapi.c:3457 +unusedFunction:fstapi.c:3458 // fstReaderIterBlocks() -unusedFunction:fstapi.c:4652 +unusedFunction:fstapi.c:4653 // fstReaderIterBlocksSetNativeDoublesOnCallback() -unusedFunction:fstapi.c:3557 +unusedFunction:fstapi.c:3558 // fstReaderIterateHier() -unusedFunction:fstapi.c:3782 +unusedFunction:fstapi.c:3783 // fstReaderIterateHierRewind() -unusedFunction:fstapi.c:3762 +unusedFunction:fstapi.c:3763 // fstReaderOpen() -unusedFunction:fstapi.c:4550 +unusedFunction:fstapi.c:4551 // fstReaderOpenForUtilitiesOnly() -unusedFunction:fstapi.c:4542 +unusedFunction:fstapi.c:4543 // fstReaderPushScope() -unusedFunction:fstapi.c:3244 +unusedFunction:fstapi.c:3245 // fstReaderResetScope() -unusedFunction:fstapi.c:3233 +unusedFunction:fstapi.c:3234 // fstReaderSetFacProcessMask() -unusedFunction:fstapi.c:3326 +unusedFunction:fstapi.c:3327 // fstReaderSetFacProcessMaskAll() -unusedFunction:fstapi.c:3362 +unusedFunction:fstapi.c:3363 // fstReaderSetLimitTimeRange() -unusedFunction:fstapi.c:3522 +unusedFunction:fstapi.c:3523 // fstReaderSetUnlimitedTimeRange() -unusedFunction:fstapi.c:3535 +unusedFunction:fstapi.c:3536 // fstReaderSetVcdExtensions() -unusedFunction:fstapi.c:3546 +unusedFunction:fstapi.c:3547 // fstUtilityEscToBin() -unusedFunction:fstapi.c:6485 +unusedFunction:fstapi.c:6544 // fstWriterCreateVar2() unusedFunction:fstapi.c:2528 // fstWriterEmitVariableLengthValueChange() @@ -232,6 +232,10 @@ unusedLabel:fastlz.c:545 // These functions are not used by Icarus // fastlz_compress_level() unusedFunction:fastlz.c:150 +// FASTLZ_COMPRESSOR() +unusedFunction:fastlz.c:162 +// FASTLZ_DECOMPRESSOR() +unusedFunction:fastlz.c:416 // lz4.c from GTKWave // These functions are not used by Icarus diff --git a/vpi/fstapi.c b/vpi/fstapi.c index 18d38ec99..35f601191 100644 --- a/vpi/fstapi.c +++ b/vpi/fstapi.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2009-2015 Tony Bybell. + * Copyright (c) 2009-2018 Tony Bybell. * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), @@ -128,6 +128,7 @@ void **JenkinsIns(void *base_i, const unsigned char *mem, uint32_t length, uint3 #include #endif +#define FST_APIMESS "FSTAPI | " /***********************/ /*** ***/ @@ -193,7 +194,7 @@ if(nam) /* cppcheck warning fix: nam is always defined, so this is not needed */ dwRetVal = GetTempPath(MAX_PATH, lpTempPathBuffer); if((dwRetVal > MAX_PATH) || (dwRetVal == 0)) { - fprintf(stderr, "GetTempPath() failed in "__FILE__" line %d, exiting.\n", __LINE__); + fprintf(stderr, FST_APIMESS"GetTempPath() failed in "__FILE__" line %d, exiting.\n", __LINE__); exit(255); } else @@ -201,7 +202,7 @@ if(nam) /* cppcheck warning fix: nam is always defined, so this is not needed */ uRetVal = GetTempFileName(lpTempPathBuffer, TEXT("FSTW"), 0, szTempFileName); if (uRetVal == 0) { - fprintf(stderr, "GetTempFileName() failed in "__FILE__" line %d, exiting.\n", __LINE__); + fprintf(stderr, FST_APIMESS"GetTempFileName() failed in "__FILE__" line %d, exiting.\n", __LINE__); exit(255); } else @@ -282,7 +283,7 @@ static char *fstRealpath(const char *path, char *resolved_path) #if (defined(__MACH__) && defined(__APPLE__)) if(!resolved_path) { - resolved_path = malloc(PATH_MAX+1); /* fixes bug on Leopard when resolved_path == NULL */ + resolved_path = (char *)malloc(PATH_MAX+1); /* fixes bug on Leopard when resolved_path == NULL */ } #endif @@ -292,7 +293,7 @@ return(realpath(path, resolved_path)); #ifdef __MINGW32__ if(!resolved_path) { - resolved_path = malloc(PATH_MAX+1); + resolved_path = (char *)malloc(PATH_MAX+1); } return(_fullpath(resolved_path, path, PATH_MAX)); #else @@ -316,7 +317,7 @@ static void *fstMmap2(size_t __len, int __fd, off_t __off) { (void)__off; -unsigned char *pnt = malloc(__len); +unsigned char *pnt = (unsigned char *)malloc(__len); off_t cur_offs = lseek(__fd, 0, SEEK_CUR); size_t i; @@ -792,6 +793,8 @@ char *geom_handle_nam; char *valpos_handle_nam; char *curval_handle_nam; char *tchn_handle_nam; + +fstEnumHandle max_enumhandle; }; @@ -803,7 +806,7 @@ if(rc<0) { xc->fseek_failed = 1; #ifdef FST_DEBUG - fprintf(stderr, "Seek to #%"PRId64" (whence = %d) failed!\n", offset, whence); + fprintf(stderr, FST_APIMESS"Seek to #%" PRId64 " (whence = %d) failed!\n", offset, whence); perror("Why"); #endif } @@ -969,12 +972,12 @@ fflush(xc->handle); if(!xc->valpos_mem) { fflush(xc->valpos_handle); - xc->valpos_mem = fstMmap(NULL, xc->maxhandle * 4 * sizeof(uint32_t), PROT_READ|PROT_WRITE, MAP_SHARED, fileno(xc->valpos_handle), 0); + xc->valpos_mem = (uint32_t *)fstMmap(NULL, xc->maxhandle * 4 * sizeof(uint32_t), PROT_READ|PROT_WRITE, MAP_SHARED, fileno(xc->valpos_handle), 0); } if(!xc->curval_mem) { fflush(xc->curval_handle); - xc->curval_mem = fstMmap(NULL, xc->maxvalpos, PROT_READ|PROT_WRITE, MAP_SHARED, fileno(xc->curval_handle), 0); + xc->curval_mem = (unsigned char *)fstMmap(NULL, xc->maxvalpos, PROT_READ|PROT_WRITE, MAP_SHARED, fileno(xc->curval_handle), 0); } } @@ -1105,7 +1108,7 @@ xc->next_huge_break = FST_ACTIVATE_HUGE_BREAK; */ void *fstWriterCreate(const char *nam, int use_compressed_hier) { -struct fstWriterContext *xc = calloc(1, sizeof(struct fstWriterContext)); +struct fstWriterContext *xc = (struct fstWriterContext *)calloc(1, sizeof(struct fstWriterContext)); xc->compress_hier = use_compressed_hier; fstDetermineBreakSize(xc); @@ -1119,7 +1122,7 @@ if((!nam)|| else { int flen = strlen(nam); - char *hf = calloc(1, flen + 6); + char *hf = (char *)calloc(1, flen + 6); memcpy(hf, nam, flen); strcpy(hf + flen, ".hier"); @@ -1130,7 +1133,7 @@ if((!nam)|| xc->curval_handle = tmpfile_open(&xc->curval_handle_nam); /* .bits */ xc->tchn_handle = tmpfile_open(&xc->tchn_handle_nam); /* .tchn */ xc->vchg_alloc_siz = xc->fst_break_size + xc->fst_break_add_size; - xc->vchg_mem = malloc(xc->vchg_alloc_siz); + xc->vchg_mem = (unsigned char *)malloc(xc->vchg_alloc_siz); if(xc->hier_handle && xc->geom_handle && xc->valpos_handle && xc->curval_handle && xc->vchg_mem && xc->tchn_handle) { @@ -1179,7 +1182,7 @@ if(xc) int rc; destlen = xc->maxvalpos; - dmem = malloc(compressBound(destlen)); + dmem = (unsigned char *)malloc(compressBound(destlen)); rc = compress2(dmem, &destlen, xc->curval_mem, xc->maxvalpos, 4); /* was 9...which caused performance drag on traces with many signals */ fputc(FST_BL_SKIP, xc->handle); /* temporarily tag the section, use FST_BL_VCDATA on finalize */ @@ -1268,7 +1271,7 @@ if((xc->vchg_siz <= 1)||(xc->already_in_flush)) return; xc->already_in_flush = 1; /* should really do this with a semaphore */ xc->section_header_only = 0; -scratchpad = malloc(xc->vchg_siz); +scratchpad = (unsigned char *)malloc(xc->vchg_siz); vchg_mem = xc->vchg_mem; @@ -1278,7 +1281,7 @@ fputc(xc->fourpack ? '4' : (xc->fastpack ? 'F' : 'Z'), f); fpos = 1; packmemlen = 1024; /* maintain a running "longest" allocation to */ -packmem = malloc(packmemlen); /* prevent continual malloc...free every loop iter */ +packmem = (unsigned char *)malloc(packmemlen); /* prevent continual malloc...free every loop iter */ for(i=0;imaxhandle;i++) { @@ -1398,13 +1401,13 @@ for(i=0;imaxhandle;i++) idx = ((vm4ip[1]+7) & ~7); switch(vm4ip[1] & 7) { - case 0: do { acc = (pnt[idx+7-8] & 1) << 0; - case 7: acc |= (pnt[idx+6-8] & 1) << 1; - case 6: acc |= (pnt[idx+5-8] & 1) << 2; - case 5: acc |= (pnt[idx+4-8] & 1) << 3; - case 4: acc |= (pnt[idx+3-8] & 1) << 4; - case 3: acc |= (pnt[idx+2-8] & 1) << 5; - case 2: acc |= (pnt[idx+1-8] & 1) << 6; + case 0: do { acc = (pnt[idx+7-8] & 1) << 0; /* fallthrough */ + case 7: acc |= (pnt[idx+6-8] & 1) << 1; /* fallthrough */ + case 6: acc |= (pnt[idx+5-8] & 1) << 2; /* fallthrough */ + case 5: acc |= (pnt[idx+4-8] & 1) << 3; /* fallthrough */ + case 4: acc |= (pnt[idx+3-8] & 1) << 4; /* fallthrough */ + case 3: acc |= (pnt[idx+2-8] & 1) << 5; /* fallthrough */ + case 2: acc |= (pnt[idx+1-8] & 1) << 6; /* fallthrough */ case 1: acc |= (pnt[idx+0-8] & 1) << 7; *(--scratchpnt) = acc; idx -= 8; @@ -1440,7 +1443,7 @@ for(i=0;imaxhandle;i++) else { free(packmem); - dmem = packmem = malloc(compressBound(packmemlen = wrlen)); + dmem = packmem = (unsigned char *)malloc(compressBound(packmemlen = wrlen)); } rc = compress2(dmem, &destlen, scratchpnt, wrlen, 4); @@ -1495,7 +1498,7 @@ for(i=0;imaxhandle;i++) else { free(packmem); - dmem = packmem = malloc(packmemlen = (wrlen * 2) + 2); + dmem = packmem = (unsigned char *)malloc(packmemlen = (wrlen * 2) + 2); } rc = (xc->fourpack) ? LZ4_compress((char *)scratchpnt, (char *)dmem, wrlen) : fastlz_compress(scratchpnt, wrlen, dmem); @@ -1663,7 +1666,7 @@ if(zerocnt) /* fpos += */ fstWriterVarint(f, (zerocnt << 1)); /* scan-build */ } #ifdef FST_DEBUG -fprintf(stderr, "value chains: %d\n", cnt); +fprintf(stderr, FST_APIMESS"value chains: %d\n", cnt); #endif xc->vchg_mem[0] = '!'; @@ -1677,11 +1680,11 @@ fflush(xc->tchn_handle); tlen = ftello(xc->tchn_handle); fstWriterFseeko(xc, xc->tchn_handle, 0, SEEK_SET); -tmem = fstMmap(NULL, tlen, PROT_READ|PROT_WRITE, MAP_SHARED, fileno(xc->tchn_handle), 0); +tmem = (unsigned char *)fstMmap(NULL, tlen, PROT_READ|PROT_WRITE, MAP_SHARED, fileno(xc->tchn_handle), 0); if(tmem) { unsigned long destlen = tlen; - unsigned char *dmem = malloc(compressBound(destlen)); + unsigned char *dmem = (unsigned char *)malloc(compressBound(destlen)); int rc = compress2(dmem, &destlen, tmem, tlen, 9); if((rc == Z_OK) && (((off_t)destlen) < tlen)) @@ -1738,7 +1741,7 @@ if(xc->dump_size_limit) xc2->size_limit_locked = 1; xc2->is_initial_time = 1; /* to trick emit value and emit time change */ #ifdef FST_DEBUG - fprintf(stderr, "<< dump file size limit reached, stopping dumping >>\n"); + fprintf(stderr, FST_APIMESS"<< dump file size limit reached, stopping dumping >>\n"); #endif } } @@ -1780,7 +1783,7 @@ struct fstWriterContext *xc = (struct fstWriterContext *)ctx; if(xc->parallel_enabled) { - struct fstWriterContext *xc2 = malloc(sizeof(struct fstWriterContext)); + struct fstWriterContext *xc2 = (struct fstWriterContext *)malloc(sizeof(struct fstWriterContext)); unsigned int i; pthread_mutex_lock(&xc->mutex); @@ -1789,16 +1792,16 @@ if(xc->parallel_enabled) xc->xc_parent = xc; memcpy(xc2, xc, sizeof(struct fstWriterContext)); - xc2->valpos_mem = malloc(xc->maxhandle * 4 * sizeof(uint32_t)); + xc2->valpos_mem = (uint32_t *)malloc(xc->maxhandle * 4 * sizeof(uint32_t)); memcpy(xc2->valpos_mem, xc->valpos_mem, xc->maxhandle * 4 * sizeof(uint32_t)); /* curval mem is updated in the thread */ #ifdef FST_REMOVE_DUPLICATE_VC - xc2->curval_mem = malloc(xc->maxvalpos); + xc2->curval_mem = (unsigned char *)malloc(xc->maxvalpos); memcpy(xc2->curval_mem, xc->curval_mem, xc->maxvalpos); #endif - xc->vchg_mem = malloc(xc->vchg_alloc_siz); + xc->vchg_mem = (unsigned char *)malloc(xc->vchg_alloc_siz); xc->vchg_mem[0] = '!'; xc->vchg_siz = 1; @@ -1907,11 +1910,11 @@ if(xc && !xc->already_in_close && !xc->already_in_flush) /* write out geom section */ fflush(xc->geom_handle); tlen = ftello(xc->geom_handle); - tmem = fstMmap(NULL, tlen, PROT_READ|PROT_WRITE, MAP_SHARED, fileno(xc->geom_handle), 0); + tmem = (unsigned char *)fstMmap(NULL, tlen, PROT_READ|PROT_WRITE, MAP_SHARED, fileno(xc->geom_handle), 0); if(tmem) { unsigned long destlen = tlen; - unsigned char *dmem = malloc(compressBound(destlen)); + unsigned char *dmem = (unsigned char *)malloc(compressBound(destlen)); int rc = compress2(dmem, &destlen, tmem, tlen, 9); if((rc != Z_OK) || (((off_t)destlen) > tlen)) @@ -1979,7 +1982,7 @@ if(xc && !xc->already_in_close && !xc->already_in_flush) int zfd; int fourpack_duo = 0; #ifndef __MINGW32__ - char *fnam = malloc(strlen(xc->filename) + 5 + 1); + char *fnam = (char *)malloc(strlen(xc->filename) + 5 + 1); #endif fixup_offs = ftello(xc->handle); @@ -1990,7 +1993,7 @@ if(xc && !xc->already_in_close && !xc->already_in_flush) if(!xc->fourpack) { - unsigned char *mem = malloc(FST_GZIO_LEN); + unsigned char *mem = (unsigned char *)malloc(FST_GZIO_LEN); zfd = dup(fileno(xc->handle)); fflush(xc->handle); zhandle = gzdopen(zfd, "wb4"); @@ -2021,8 +2024,8 @@ if(xc && !xc->already_in_close && !xc->already_in_flush) fflush(xc->handle); lz4_maxlen = LZ4_compressBound(xc->hier_file_len); - mem = malloc(lz4_maxlen); - hmem = fstMmap(NULL, xc->hier_file_len, PROT_READ|PROT_WRITE, MAP_SHARED, fileno(xc->hier_handle), 0); + mem = (unsigned char *)malloc(lz4_maxlen); + hmem = (unsigned char *)fstMmap(NULL, xc->hier_file_len, PROT_READ|PROT_WRITE, MAP_SHARED, fileno(xc->hier_handle), 0); packed_len = LZ4_compress((char *)hmem, (char *)mem, xc->hier_file_len); fstMunmap(hmem, xc->hier_file_len); @@ -2035,7 +2038,7 @@ if(xc && !xc->already_in_close && !xc->already_in_flush) int packed_len_duo; lz4_maxlen_duo = LZ4_compressBound(packed_len); - mem_duo = malloc(lz4_maxlen_duo); + mem_duo = (unsigned char *)malloc(lz4_maxlen_duo); packed_len_duo = LZ4_compress((char *)mem, (char *)mem_duo, packed_len); fstWriterVarint(xc->handle, packed_len); /* 1st round compressed length */ @@ -2095,7 +2098,7 @@ if(xc && !xc->already_in_close && !xc->already_in_flush) FILE *fp; off_t offpnt, uclen; int flen = strlen(xc->filename); - char *hf = calloc(1, flen + 5); + char *hf = (char *)calloc(1, flen + 5); strcpy(hf, xc->filename); strcpy(hf+flen, ".pak"); @@ -2103,7 +2106,7 @@ if(xc && !xc->already_in_close && !xc->already_in_flush) if(fp) { - void *dsth; + gzFile dsth; int zfd; char gz_membuf[FST_GZIO_LEN]; @@ -2159,7 +2162,7 @@ if(xc && !xc->already_in_close && !xc->already_in_flush) #ifdef __MINGW32__ { int flen = strlen(xc->filename); - char *hf = calloc(1, flen + 6); + char *hf = (char *)calloc(1, flen + 6); strcpy(hf, xc->filename); if(xc->compress_hier) @@ -2302,7 +2305,7 @@ if(xc && path && path[0]) const unsigned char *path2 = (const unsigned char *)path; PPvoid_t pv; #else - char *path2 = alloca(slen + 1); /* judy lacks const qualifier in its JudyHSIns definition */ + char *path2 = (char *)alloca(slen + 1); /* judy lacks const qualifier in its JudyHSIns definition */ PPvoid_t pv; strcpy(path2, path); #endif @@ -2478,7 +2481,7 @@ if(xc) #ifndef FST_WRITER_PARALLEL if(xc->parallel_enabled) { - fprintf(stderr, "ERROR: fstWriterSetParallelMode(), FST_WRITER_PARALLEL not enabled during compile, exiting.\n"); + fprintf(stderr, FST_APIMESS"fstWriterSetParallelMode(), FST_WRITER_PARALLEL not enabled during compile, exiting.\n"); exit(255); } #endif @@ -2585,7 +2588,7 @@ if(xc && nam) xc->vchg_alloc_siz = xc->fst_break_size + xc->fst_break_add_size; if(xc->vchg_mem) { - xc->vchg_mem = realloc(xc->vchg_mem, xc->vchg_alloc_siz); + xc->vchg_mem = (unsigned char *)realloc(xc->vchg_mem, xc->vchg_alloc_siz); } } } @@ -2723,6 +2726,111 @@ if(xc) } +fstEnumHandle fstWriterCreateEnumTable(void *ctx, const char *name, uint32_t elem_count, unsigned int min_valbits, const char **literal_arr, const char **val_arr) +{ +fstEnumHandle handle = 0; +unsigned int *literal_lens = NULL; +unsigned int *val_lens = NULL; +int lit_len_tot = 0; +int val_len_tot = 0; +int name_len; +char elem_count_buf[16]; +int elem_count_len; +int total_len; +int pos = 0; +char *attr_str = NULL; + +if(ctx && name && literal_arr && val_arr && (elem_count != 0)) + { + struct fstWriterContext *xc = (struct fstWriterContext *)ctx; + + uint32_t i; + + name_len = strlen(name); + elem_count_len = sprintf(elem_count_buf, "%" PRIu32, elem_count); + + literal_lens = (unsigned int *)calloc(elem_count, sizeof(unsigned int)); + val_lens = (unsigned int *)calloc(elem_count, sizeof(unsigned int)); + + for(i=0;i 0) + { + if(val_lens[i] < min_valbits) + { + val_len_tot += (min_valbits - val_lens[i]); /* additional converted len is same for '0' character */ + } + } + } + + total_len = name_len + 1 + elem_count_len + 1 + lit_len_tot + elem_count + val_len_tot + elem_count; + + attr_str = (char*)malloc(total_len); + pos = 0; + + memcpy(attr_str+pos, name, name_len); + pos += name_len; + attr_str[pos++] = ' '; + + memcpy(attr_str+pos, elem_count_buf, elem_count_len); + pos += elem_count_len; + attr_str[pos++] = ' '; + + for(i=0;i 0) + { + if(val_lens[i] < min_valbits) + { + memset(attr_str+pos, '0', min_valbits - val_lens[i]); + pos += (min_valbits - val_lens[i]); + } + } + + pos += fstUtilityBinToEsc((unsigned char*)attr_str+pos, (unsigned char*)val_arr[i], val_lens[i]); + attr_str[pos++] = ' '; + } + + attr_str[pos-1] = 0; + +#ifdef FST_DEBUG + fprintf(stderr, FST_APIMESS"fstWriterCreateEnumTable() total_len: %d, pos: %d\n", total_len, pos); + fprintf(stderr, FST_APIMESS"*%s*\n", attr_str); +#endif + + fstWriterSetAttrBegin(xc, FST_AT_MISC, FST_MT_ENUMTABLE, attr_str, handle = ++xc->max_enumhandle); + + free(attr_str); + free(val_lens); + free(literal_lens); + } + +return(handle); +} + + +void fstWriterEmitEnumTableRef(void *ctx, fstEnumHandle handle) +{ +struct fstWriterContext *xc = (struct fstWriterContext *)ctx; +if(xc && handle) + { + fstWriterSetAttrBegin(xc, FST_AT_MISC, FST_MT_ENUMTABLE, NULL, handle); + } +} + + /* * value and time change emission */ @@ -2757,10 +2865,10 @@ if((xc) && (handle <= xc->maxhandle)) if((fpos + len + 10) > xc->vchg_alloc_siz) { xc->vchg_alloc_siz += (xc->fst_break_add_size + len); /* +len added in the case of extremely long vectors and small break add sizes */ - xc->vchg_mem = realloc(xc->vchg_mem, xc->vchg_alloc_siz); + xc->vchg_mem = (unsigned char *)realloc(xc->vchg_mem, xc->vchg_alloc_siz); if(!xc->vchg_mem) { - fprintf(stderr, "FATAL ERROR, could not realloc() in fstWriterEmitValueChange, exiting.\n"); + fprintf(stderr, FST_APIMESS"Could not realloc() in fstWriterEmitValueChange, exiting.\n"); exit(255); } } @@ -2871,10 +2979,10 @@ if((xc) && (handle <= xc->maxhandle)) if((fpos + len + 10 + 5) > xc->vchg_alloc_siz) { xc->vchg_alloc_siz += (xc->fst_break_add_size + len + 5); /* +len added in the case of extremely long vectors and small break add sizes */ - xc->vchg_mem = realloc(xc->vchg_mem, xc->vchg_alloc_siz); + xc->vchg_mem = (unsigned char *)realloc(xc->vchg_mem, xc->vchg_alloc_siz); if(!xc->vchg_mem) { - fprintf(stderr, "FATAL ERROR, could not realloc() in fstWriterEmitVariableLengthValueChange, exiting.\n"); + fprintf(stderr, FST_APIMESS"Could not realloc() in fstWriterEmitVariableLengthValueChange, exiting.\n"); exit(255); } } @@ -2948,7 +3056,7 @@ struct fstWriterContext *xc = (struct fstWriterContext *)ctx; if(xc) { - struct fstBlackoutChain *b = calloc(1, sizeof(struct fstBlackoutChain)); + struct fstBlackoutChain *b = (struct fstBlackoutChain *)calloc(1, sizeof(struct fstBlackoutChain)); b->tim = xc->curtime; b->active = (enable != 0); @@ -3119,7 +3227,7 @@ if(rc<0) { xc->fseek_failed = 1; #ifdef FST_DEBUG - fprintf(stderr, "Seek to #%"PRId64" (whence = %d) failed!\n", offset, whence); + fprintf(stderr, FST_APIMESS"Seek to #%" PRId64 " (whence = %d) failed!\n", offset, whence); perror("Why"); #endif } @@ -3247,12 +3355,12 @@ const char *fstReaderPushScope(void *ctx, const char *nam, void *user_info) struct fstReaderContext *xc = (struct fstReaderContext *)ctx; if(xc) { - struct fstCurrHier *ch = malloc(sizeof(struct fstCurrHier)); + struct fstCurrHier *ch = (struct fstCurrHier *)malloc(sizeof(struct fstCurrHier)); int chl = xc->curr_hier ? xc->curr_hier->len : 0; int len = chl + 1 + strlen(nam); if(len >= xc->flat_hier_alloc_len) { - xc->curr_flat_hier_nam = xc->curr_flat_hier_nam ? realloc(xc->curr_flat_hier_nam, len+1) : malloc(len+1); + xc->curr_flat_hier_nam = xc->curr_flat_hier_nam ? (char *)realloc(xc->curr_flat_hier_nam, len+1) : (char *)malloc(len+1); } if(chl) @@ -3472,7 +3580,7 @@ return(xc ? xc->date : NULL); int fstReaderGetFileType(void *ctx) { struct fstReaderContext *xc = (struct fstReaderContext *)ctx; -return(xc ? xc->filetype : FST_FT_VERILOG); +return(xc ? (int)xc->filetype : (int)FST_FT_VERILOG); } @@ -3605,8 +3713,8 @@ int pass_status = 1; if(!xc->fh) { off_t offs_cache = ftello(xc->f); - char *fnam = malloc(strlen(xc->filename) + 6 + 16 + 32 + 1); - unsigned char *mem = malloc(FST_GZIO_LEN); + char *fnam = (char *)malloc(strlen(xc->filename) + 6 + 16 + 32 + 1); + unsigned char *mem = (unsigned char *)malloc(FST_GZIO_LEN); off_t hl, uclen; off_t clen = 0; gzFile zhandle = NULL; @@ -3703,8 +3811,8 @@ if(!xc->fh) else if(htyp == FST_BL_HIER_LZ4DUO) { - unsigned char *lz4_cmem = malloc(clen); - unsigned char *lz4_ucmem = malloc(uclen); + unsigned char *lz4_cmem = (unsigned char *)malloc(clen); + unsigned char *lz4_ucmem = (unsigned char *)malloc(uclen); unsigned char *lz4_ucmem2; uint64_t uclen2; int skiplen2 = 0; @@ -3712,7 +3820,7 @@ if(!xc->fh) fstFread(lz4_cmem, clen, 1, xc->f); uclen2 = fstGetVarint64(lz4_cmem, &skiplen2); - lz4_ucmem2 = malloc(uclen2); + lz4_ucmem2 = (unsigned char *)malloc(uclen2); pass_status = (uclen2 == (uint64_t)LZ4_decompress_safe_partial ((char *)lz4_cmem + skiplen2, (char *)lz4_ucmem2, clen - skiplen2, uclen2, uclen2)); if(pass_status) { @@ -3731,8 +3839,8 @@ if(!xc->fh) else if(htyp == FST_BL_HIER_LZ4) { - unsigned char *lz4_cmem = malloc(clen); - unsigned char *lz4_ucmem = malloc(uclen); + unsigned char *lz4_cmem = (unsigned char *)malloc(clen); + unsigned char *lz4_ucmem = (unsigned char *)malloc(uclen); fstFread(lz4_cmem, clen, 1, xc->f); pass_status = (uclen == LZ4_decompress_safe_partial ((char *)lz4_cmem, (char *)lz4_ucmem, clen, uclen, uclen)); @@ -3748,6 +3856,10 @@ if(!xc->fh) else /* FST_BL_SKIP */ { pass_status = 0; + if(xc->fh) + { + fclose(xc->fh); xc->fh = NULL; /* needed in case .hier file is missing and there are no hier sections */ + } } free(mem); @@ -3965,7 +4077,7 @@ if(!xc->fh) } } -str = malloc(FST_ID_NAM_ATTR_SIZ+1); +str = (char *)malloc(FST_ID_NAM_ATTR_SIZ+1); if(fv) { @@ -3974,40 +4086,40 @@ if(fv) fprintf(fv, "$date\n\t%s\n$end\n", xc->date); fprintf(fv, "$version\n\t%s\n$end\n", xc->version); - if(xc->timezero) fprintf(fv, "$timezero\n\t%"PRId64"\n$end\n", xc->timezero); + if(xc->timezero) fprintf(fv, "$timezero\n\t%" PRId64 "\n$end\n", xc->timezero); switch(xc->timescale) { case 2: time_scale = 100; time_dimension[0] = 0; break; - case 1: time_scale = 10; + case 1: time_scale = 10; /* fallthrough */ case 0: time_dimension[0] = 0; break; case -1: time_scale = 100; time_dimension[0] = 'm'; break; - case -2: time_scale = 10; + case -2: time_scale = 10; /* fallthrough */ case -3: time_dimension[0] = 'm'; break; case -4: time_scale = 100; time_dimension[0] = 'u'; break; - case -5: time_scale = 10; + case -5: time_scale = 10; /* fallthrough */ case -6: time_dimension[0] = 'u'; break; case -10: time_scale = 100; time_dimension[0] = 'p'; break; - case -11: time_scale = 10; + case -11: time_scale = 10; /* fallthrough */ case -12: time_dimension[0] = 'p'; break; case -13: time_scale = 100; time_dimension[0] = 'f'; break; - case -14: time_scale = 10; + case -14: time_scale = 10; /* fallthrough */ case -15: time_dimension[0] = 'f'; break; case -16: time_scale = 100; time_dimension[0] = 'a'; break; - case -17: time_scale = 10; + case -17: time_scale = 10; /* fallthrough */ case -18: time_dimension[0] = 'a'; break; case -19: time_scale = 100; time_dimension[0] = 'z'; break; - case -20: time_scale = 10; + case -20: time_scale = 10; /* fallthrough */ case -21: time_dimension[0] = 'z'; break; case -7: time_scale = 100; time_dimension[0] = 'n'; break; - case -8: time_scale = 10; + case -8: time_scale = 10; /* fallthrough */ case -9: default: time_dimension[0] = 'n'; break; } @@ -4019,10 +4131,10 @@ xc->maxhandle = 0; xc->num_alias = 0; free(xc->signal_lens); -xc->signal_lens = malloc(num_signal_dyn*sizeof(uint32_t)); +xc->signal_lens = (uint32_t *)malloc(num_signal_dyn*sizeof(uint32_t)); free(xc->signal_typs); -xc->signal_typs = malloc(num_signal_dyn*sizeof(unsigned char)); +xc->signal_typs = (unsigned char *)malloc(num_signal_dyn*sizeof(unsigned char)); fstReaderFseeko(xc, xc->fh, 0, SEEK_SET); while(!feof(xc->fh)) @@ -4067,13 +4179,13 @@ while(!feof(xc->fh)) switch(attrtype) { case FST_AT_ARRAY: if((subtype < FST_AR_NONE) || (subtype > FST_AR_MAX)) subtype = FST_AR_NONE; - fprintf(fv, "$attrbegin %s %s %s %"PRId64" $end\n", attrtypes[attrtype], arraytypes[subtype], str, attrarg); + fprintf(fv, "$attrbegin %s %s %s %" PRId64 " $end\n", attrtypes[attrtype], arraytypes[subtype], str, attrarg); break; case FST_AT_ENUM: if((subtype < FST_EV_SV_INTEGER) || (subtype > FST_EV_MAX)) subtype = FST_EV_SV_INTEGER; - fprintf(fv, "$attrbegin %s %s %s %"PRId64" $end\n", attrtypes[attrtype], enumvaluetypes[subtype], str, attrarg); + fprintf(fv, "$attrbegin %s %s %s %" PRId64 " $end\n", attrtypes[attrtype], enumvaluetypes[subtype], str, attrarg); break; case FST_AT_PACK: if((subtype < FST_PT_NONE) || (subtype > FST_PT_MAX)) subtype = FST_PT_NONE; - fprintf(fv, "$attrbegin %s %s %s %"PRId64" $end\n", attrtypes[attrtype], packtypes[subtype], str, attrarg); + fprintf(fv, "$attrbegin %s %s %s %" PRId64 " $end\n", attrtypes[attrtype], packtypes[subtype], str, attrarg); break; case FST_AT_MISC: default: attrtype = FST_AT_MISC; @@ -4088,11 +4200,11 @@ while(!feof(xc->fh)) int sidx_skiplen_dummy = 0; uint64_t sidx = fstGetVarint64((unsigned char *)str, &sidx_skiplen_dummy); - fprintf(fv, "$attrbegin %s %02x %"PRId64" %"PRId64" $end\n", attrtypes[attrtype], subtype, sidx, attrarg); + fprintf(fv, "$attrbegin %s %02x %" PRId64 " %" PRId64 " $end\n", attrtypes[attrtype], subtype, sidx, attrarg); } else { - fprintf(fv, "$attrbegin %s %02x %s %"PRId64" $end\n", attrtypes[attrtype], subtype, str, attrarg); + fprintf(fv, "$attrbegin %s %02x %s %" PRId64 " $end\n", attrtypes[attrtype], subtype, str, attrarg); } } break; @@ -4150,8 +4262,8 @@ while(!feof(xc->fh)) if(xc->maxhandle == num_signal_dyn) { num_signal_dyn *= 2; - xc->signal_lens = realloc(xc->signal_lens, num_signal_dyn*sizeof(uint32_t)); - xc->signal_typs = realloc(xc->signal_typs, num_signal_dyn*sizeof(unsigned char)); + xc->signal_lens = (uint32_t *)realloc(xc->signal_lens, num_signal_dyn*sizeof(uint32_t)); + xc->signal_typs = (unsigned char *)realloc(xc->signal_typs, num_signal_dyn*sizeof(unsigned char)); } xc->signal_lens[xc->maxhandle] = len; xc->signal_typs[xc->maxhandle] = vartype; @@ -4172,7 +4284,7 @@ while(!feof(xc->fh)) char vcdid_buf[16]; uint32_t modlen = (vartype != FST_VT_VCD_PORT) ? len : ((len - 2) / 3); fstVcdID(vcdid_buf, xc->maxhandle+1); - fprintf(fv, "$var %s %"PRIu32" %s %s $end\n", vartypes[vartype], modlen, vcdid_buf, str); + fprintf(fv, "$var %s %" PRIu32 " %s %s $end\n", vartypes[vartype], modlen, vcdid_buf, str); } xc->maxhandle++; } @@ -4188,7 +4300,7 @@ while(!feof(xc->fh)) char vcdid_buf[16]; uint32_t modlen = (vartype != FST_VT_VCD_PORT) ? len : ((len - 2) / 3); fstVcdID(vcdid_buf, alias); - fprintf(fv, "$var %s %"PRIu32" %s %s $end\n", vartypes[vartype], modlen, vcdid_buf, str); + fprintf(fv, "$var %s %" PRIu32 " %s %s $end\n", vartypes[vartype], modlen, vcdid_buf, str); } xc->num_alias++; } @@ -4203,14 +4315,14 @@ if(fv) fprintf(fv, "$enddefinitions $end\n"); maxhandle_scanbuild = xc->maxhandle ? xc->maxhandle : 1; /*scan-build warning suppression, in reality we have at least one signal */ -xc->signal_lens = realloc(xc->signal_lens, maxhandle_scanbuild*sizeof(uint32_t)); -xc->signal_typs = realloc(xc->signal_typs, maxhandle_scanbuild*sizeof(unsigned char)); +xc->signal_lens = (uint32_t *)realloc(xc->signal_lens, maxhandle_scanbuild*sizeof(uint32_t)); +xc->signal_typs = (unsigned char *)realloc(xc->signal_typs, maxhandle_scanbuild*sizeof(unsigned char)); free(xc->process_mask); -xc->process_mask = calloc(1, (maxhandle_scanbuild+7)/8); +xc->process_mask = (unsigned char *)calloc(1, (maxhandle_scanbuild+7)/8); free(xc->temp_signal_value_buf); -xc->temp_signal_value_buf = malloc(xc->longest_signal_value_len + 1); +xc->temp_signal_value_buf = (unsigned char *)malloc(xc->longest_signal_value_len + 1); xc->var_count = xc->maxhandle + xc->num_alias; @@ -4239,7 +4351,7 @@ if(sectype == FST_BL_ZWRAPPER) FILE *fcomp; off_t offpnt, uclen; char gz_membuf[FST_GZIO_LEN]; - void *zhandle; + gzFile zhandle; int zfd; int flen = strlen(xc->filename); char *hf; @@ -4249,7 +4361,7 @@ if(sectype == FST_BL_ZWRAPPER) if(!seclen) return(0); /* not finished compressing, this is a failed read */ - hf = calloc(1, flen + 16 + 32 + 1); + hf = (char *)calloc(1, flen + 16 + 32 + 1); sprintf(hf, "%s.upk_%d_%p", xc->filename, getpid(), (void *)xc); fcomp = fopen(hf, "w+b"); @@ -4412,7 +4524,7 @@ if(gzread_pass_status) { uint64_t clen = seclen - 24; uint64_t uclen = fstReaderUint64(xc->f); - unsigned char *ucdata = malloc(uclen); + unsigned char *ucdata = (unsigned char *)malloc(uclen); unsigned char *pnt = ucdata; unsigned int i; @@ -4421,11 +4533,11 @@ if(gzread_pass_status) xc->longest_signal_value_len = 32; /* arbitrarily set at 32...this is much longer than an expanded double */ free(xc->process_mask); - xc->process_mask = calloc(1, (xc->maxhandle+7)/8); + xc->process_mask = (unsigned char *)calloc(1, (xc->maxhandle+7)/8); if(clen != uclen) { - unsigned char *cdata = malloc(clen); + unsigned char *cdata = (unsigned char *)malloc(clen); unsigned long destlen = uclen; unsigned long sourcelen = clen; int rc; @@ -4435,7 +4547,7 @@ if(gzread_pass_status) if(rc != Z_OK) { - printf("geom uncompress rc = %d\n", rc); + fprintf(stderr, FST_APIMESS"fstReaderInit(), geom uncompress rc = %d, exiting.\n", rc); exit(255); } @@ -4447,9 +4559,9 @@ if(gzread_pass_status) } free(xc->signal_lens); - xc->signal_lens = malloc(sizeof(uint32_t) * xc->maxhandle); + xc->signal_lens = (uint32_t *)malloc(sizeof(uint32_t) * xc->maxhandle); free(xc->signal_typs); - xc->signal_typs = malloc(sizeof(unsigned char) * xc->maxhandle); + xc->signal_typs = (unsigned char *)malloc(sizeof(unsigned char) * xc->maxhandle); for(i=0;imaxhandle;i++) { @@ -4476,7 +4588,7 @@ if(gzread_pass_status) } free(xc->temp_signal_value_buf); - xc->temp_signal_value_buf = malloc(xc->longest_signal_value_len + 1); + xc->temp_signal_value_buf = (unsigned char *)malloc(xc->longest_signal_value_len + 1); free(ucdata); } @@ -4505,9 +4617,9 @@ if(gzread_pass_status) xc->num_blackouts = fstReaderVarint32(xc->f); free(xc->blackout_times); - xc->blackout_times = calloc(xc->num_blackouts, sizeof(uint64_t)); + xc->blackout_times = (uint64_t *)calloc(xc->num_blackouts, sizeof(uint64_t)); free(xc->blackout_activity); - xc->blackout_activity = calloc(xc->num_blackouts, sizeof(unsigned char)); + xc->blackout_activity = (unsigned char *)calloc(xc->num_blackouts, sizeof(unsigned char)); for(i=0;inum_blackouts;i++) { @@ -4542,7 +4654,7 @@ return(hdr_seen); void *fstReaderOpenForUtilitiesOnly(void) { -struct fstReaderContext *xc = calloc(1, sizeof(struct fstReaderContext)); +struct fstReaderContext *xc = (struct fstReaderContext *)calloc(1, sizeof(struct fstReaderContext)); return(xc); } @@ -4550,7 +4662,7 @@ return(xc); void *fstReaderOpen(const char *nam) { -struct fstReaderContext *xc = calloc(1, sizeof(struct fstReaderContext)); +struct fstReaderContext *xc = (struct fstReaderContext *)calloc(1, sizeof(struct fstReaderContext)); if((!nam)||(!(xc->f=fopen(nam, "rb")))) { @@ -4560,7 +4672,7 @@ if((!nam)||(!(xc->f=fopen(nam, "rb")))) else { int flen = strlen(nam); - char *hf = calloc(1, flen + 6); + char *hf = (char *)calloc(1, flen + 6); int rc; #if defined(__MINGW32__) || defined(FST_MACOSX) @@ -4699,9 +4811,9 @@ uint32_t mc_mem_len; /* corresponds to largest value encountered in chain_table_ if(!xc) return(0); -scatterptr = calloc(xc->maxhandle, sizeof(uint32_t)); -headptr = calloc(xc->maxhandle, sizeof(uint32_t)); -length_remaining = calloc(xc->maxhandle, sizeof(uint32_t)); +scatterptr = (uint32_t *)calloc(xc->maxhandle, sizeof(uint32_t)); +headptr = (uint32_t *)calloc(xc->maxhandle, sizeof(uint32_t)); +length_remaining = (uint32_t *)calloc(xc->maxhandle, sizeof(uint32_t)); if(fv) { @@ -4726,7 +4838,7 @@ for(;;) if((sectype == EOF) || (sectype == FST_BL_SKIP)) { #ifdef FST_DEBUG - fprintf(stderr, "<< EOF >>\n"); + fprintf(stderr, FST_APIMESS"<< EOF >>\n"); #endif break; } @@ -4763,11 +4875,11 @@ for(;;) mem_required_for_traversal = fstReaderUint64(xc->f); - mem_for_traversal = malloc(mem_required_for_traversal + 66); /* add in potential fastlz overhead */ + mem_for_traversal = (unsigned char *)malloc(mem_required_for_traversal + 66); /* add in potential fastlz overhead */ #ifdef FST_DEBUG - fprintf(stderr, "sec: %u seclen: %d begtim: %d endtim: %d\n", + fprintf(stderr, FST_APIMESS"sec: %u seclen: %d begtim: %d endtim: %d\n", secnum, (int)seclen, (int)beg_tim, (int)end_tim); - fprintf(stderr, "\tmem_required_for_traversal: %d\n", (int)mem_required_for_traversal); + fprintf(stderr, FST_APIMESS"mem_required_for_traversal: %d\n", (int)mem_required_for_traversal); #endif /* process time block */ { @@ -4785,11 +4897,11 @@ for(;;) tsec_clen = fstReaderUint64(xc->f); tsec_nitems = fstReaderUint64(xc->f); #ifdef FST_DEBUG - fprintf(stderr, "\ttime section unc: %d, com: %d (%d items)\n", + fprintf(stderr, FST_APIMESS"time section unc: %d, com: %d (%d items)\n", (int)tsec_uclen, (int)tsec_clen, (int)tsec_nitems); #endif if(tsec_clen > seclen) break; /* corrupted tsec_clen: by definition it can't be larger than size of section */ - ucdata = malloc(tsec_uclen); + ucdata = (unsigned char *)malloc(tsec_uclen); if(!ucdata) break; /* malloc fail as tsec_uclen out of range from corrupted file */ destlen = tsec_uclen; sourcelen = tsec_clen; @@ -4798,14 +4910,14 @@ for(;;) if(tsec_uclen != tsec_clen) { - cdata = malloc(tsec_clen); + cdata = (unsigned char *)malloc(tsec_clen); fstFread(cdata, tsec_clen, 1, xc->f); rc = uncompress(ucdata, &destlen, cdata, sourcelen); if(rc != Z_OK) { - printf("tsec uncompress rc = %d\n", rc); + fprintf(stderr, FST_APIMESS"fstReaderIterBlocks2(), tsec uncompress rc = %d, exiting.\n", rc); exit(255); } @@ -4817,7 +4929,7 @@ for(;;) } free(time_table); - time_table = calloc(tsec_nitems, sizeof(uint64_t)); + time_table = (uint64_t *)calloc(tsec_nitems, sizeof(uint64_t)); tpnt = ucdata; tpval = 0; for(ti=0;tinum_blackouts)&&(cur_blackout != xc->num_blackouts)) @@ -4871,7 +4983,7 @@ for(;;) } else { - unsigned char *mc = malloc(frame_clen); + unsigned char *mc = (unsigned char *)malloc(frame_clen); int rc; unsigned long destlen = frame_uclen; @@ -4881,7 +4993,7 @@ for(;;) rc = uncompress(mu, &destlen, mc, sourcelen); if(rc != Z_OK) { - printf("rc: %d\n", rc); + fprintf(stderr, FST_APIMESS"fstReaderIterBlocks2(), frame uncompress rc: %d, exiting.\n", rc); exit(255); } free(mc); @@ -5044,9 +5156,9 @@ for(;;) packtype = fgetc(xc->f); #ifdef FST_DEBUG - fprintf(stderr, "\tframe_uclen: %d, frame_clen: %d, frame_maxhandle: %d\n", + fprintf(stderr, FST_APIMESS"frame_uclen: %d, frame_clen: %d, frame_maxhandle: %d\n", (int)frame_uclen, (int)frame_clen, (int)frame_maxhandle); - fprintf(stderr, "\tvc_maxhandle: %d, packtype: %c\n", (int)vc_maxhandle, packtype); + fprintf(stderr, FST_APIMESS"vc_maxhandle: %d, packtype: %c\n", (int)vc_maxhandle, packtype); #endif indx_pntr = blkpos + seclen - 24 -tsec_clen -8; @@ -5054,9 +5166,9 @@ for(;;) chain_clen = fstReaderUint64(xc->f); indx_pos = indx_pntr - chain_clen; #ifdef FST_DEBUG - fprintf(stderr, "\tindx_pos: %d (%d bytes)\n", (int)indx_pos, (int)chain_clen); + fprintf(stderr, FST_APIMESS"indx_pos: %d (%d bytes)\n", (int)indx_pos, (int)chain_clen); #endif - chain_cmem = malloc(chain_clen); + chain_cmem = (unsigned char *)malloc(chain_clen); if(!chain_cmem) goto block_err; fstReaderFseeko(xc, xc->f, indx_pos, SEEK_SET); fstFread(chain_cmem, chain_clen, 1, xc->f); @@ -5067,8 +5179,8 @@ for(;;) free(chain_table_lengths); vc_maxhandle_largest = vc_maxhandle; - chain_table = calloc((vc_maxhandle+1), sizeof(off_t)); - chain_table_lengths = calloc((vc_maxhandle+1), sizeof(uint32_t)); + chain_table = (off_t *)calloc((vc_maxhandle+1), sizeof(off_t)); + chain_table_lengths = (uint32_t *)calloc((vc_maxhandle+1), sizeof(uint32_t)); } if(!chain_table || !chain_table_lengths) goto block_err; @@ -5173,11 +5285,11 @@ for(;;) } #ifdef FST_DEBUG - fprintf(stderr, "\tdecompressed chain idx len: %"PRIu32"\n", idx); + fprintf(stderr, FST_APIMESS"decompressed chain idx len: %" PRIu32 "\n", idx); #endif mc_mem_len = 16384; - mc_mem = malloc(mc_mem_len); /* buffer for compressed reads */ + mc_mem = (unsigned char *)malloc(mc_mem_len); /* buffer for compressed reads */ /* check compressed VC data */ if(idx > xc->maxhandle) idx = xc->maxhandle; @@ -5207,7 +5319,7 @@ for(;;) if(mc_mem_len < chain_table_lengths[i]) { free(mc_mem); - mc_mem = malloc(mc_mem_len = chain_table_lengths[i]); + mc_mem = (unsigned char *)malloc(mc_mem_len = chain_table_lengths[i]); } mc = mc_mem; @@ -5241,7 +5353,7 @@ for(;;) if(rc != Z_OK) { - printf("\tfac: %d clen: %d (rc=%d)\n", (int)i, (int)val, rc); + fprintf(stderr, FST_APIMESS"fstReaderIterBlocks2(), fac: %d clen: %d (rc=%d), exiting.\n", (int)i, (int)val, rc); exit(255); } @@ -5286,7 +5398,7 @@ for(;;) } } - wx_len = sprintf(wx_buf, "#%"PRIu64"\n", time_table[i]); + wx_len = sprintf(wx_buf, "#%" PRIu64 "\n", time_table[i]); fstWritex(xc, wx_buf, wx_len); if((xc->num_blackouts)&&(cur_blackout != xc->num_blackouts)) @@ -5386,7 +5498,7 @@ for(;;) vcdid_len = fstVcdIDForFwrite(vcd_id+1, idx+1); { - unsigned char *vesc = malloc(len*4 + 1); + unsigned char *vesc = (unsigned char *)malloc(len*4 + 1); int vlen = fstUtilityBinToEsc(vesc, vdata, len); fstWritex(xc, vesc, vlen); free(vesc); @@ -5713,7 +5825,7 @@ if(!xc->rvat_sig_offs) { uint32_t cur_offs = 0; - xc->rvat_sig_offs = calloc(xc->maxhandle, sizeof(uint32_t)); + xc->rvat_sig_offs = (uint32_t *)calloc(xc->maxhandle, sizeof(uint32_t)); for(i=0;imaxhandle;i++) { xc->rvat_sig_offs[i] = cur_offs; @@ -5793,9 +5905,9 @@ mem_required_for_traversal = fstReaderUint64(xc->f); #ifdef FST_DEBUG -fprintf(stderr, "rvat sec: %u seclen: %d begtim: %d endtim: %d\n", +fprintf(stderr, FST_APIMESS"rvat sec: %u seclen: %d begtim: %d endtim: %d\n", secnum, (int)seclen, (int)beg_tim, (int)end_tim); -fprintf(stderr, "\tmem_required_for_traversal: %d\n", (int)mem_required_for_traversal); +fprintf(stderr, FST_APIMESS"mem_required_for_traversal: %d\n", (int)mem_required_for_traversal); #endif /* process time block */ @@ -5814,24 +5926,24 @@ tsec_uclen = fstReaderUint64(xc->f); tsec_clen = fstReaderUint64(xc->f); tsec_nitems = fstReaderUint64(xc->f); #ifdef FST_DEBUG -fprintf(stderr, "\ttime section unc: %d, com: %d (%d items)\n", +fprintf(stderr, FST_APIMESS"time section unc: %d, com: %d (%d items)\n", (int)tsec_uclen, (int)tsec_clen, (int)tsec_nitems); #endif -ucdata = malloc(tsec_uclen); +ucdata = (unsigned char *)malloc(tsec_uclen); destlen = tsec_uclen; sourcelen = tsec_clen; fstReaderFseeko(xc, xc->f, -24 - ((off_t)tsec_clen), SEEK_CUR); if(tsec_uclen != tsec_clen) { - cdata = malloc(tsec_clen); + cdata = (unsigned char *)malloc(tsec_clen); fstFread(cdata, tsec_clen, 1, xc->f); rc = uncompress(ucdata, &destlen, cdata, sourcelen); if(rc != Z_OK) { - printf("tsec uncompress rc = %d\n", rc); + fprintf(stderr, FST_APIMESS"fstReaderGetValueFromHandleAtTime(), tsec uncompress rc = %d, exiting.\n", rc); exit(255); } @@ -5842,7 +5954,7 @@ if(tsec_uclen != tsec_clen) fstFread(ucdata, tsec_uclen, 1, xc->f); } -xc->rvat_time_table = calloc(tsec_nitems, sizeof(uint64_t)); +xc->rvat_time_table = (uint64_t *)calloc(tsec_nitems, sizeof(uint64_t)); tpnt = ucdata; tpval = 0; for(ti=0;tif, blkpos+32, SEEK_SET); frame_uclen = fstReaderVarint64(xc->f); frame_clen = fstReaderVarint64(xc->f); xc->rvat_frame_maxhandle = fstReaderVarint64(xc->f); -xc->rvat_frame_data = malloc(frame_uclen); +xc->rvat_frame_data = (unsigned char *)malloc(frame_uclen); if(frame_uclen == frame_clen) { @@ -5869,7 +5981,7 @@ if(frame_uclen == frame_clen) } else { - unsigned char *mc = malloc(frame_clen); + unsigned char *mc = (unsigned char *)malloc(frame_clen); int rc; unsigned long destlen = frame_uclen; @@ -5879,7 +5991,7 @@ if(frame_uclen == frame_clen) rc = uncompress(xc->rvat_frame_data, &destlen, mc, sourcelen); if(rc != Z_OK) { - printf("decompress rc: %d\n", rc); + fprintf(stderr, FST_APIMESS"fstReaderGetValueFromHandleAtTime(), frame decompress rc: %d, exiting.\n", rc); exit(255); } free(mc); @@ -5890,9 +6002,9 @@ xc->rvat_vc_start = ftello(xc->f); /* points to '!' character */ xc->rvat_packtype = fgetc(xc->f); #ifdef FST_DEBUG -fprintf(stderr, "\tframe_uclen: %d, frame_clen: %d, frame_maxhandle: %d\n", +fprintf(stderr, FST_APIMESS"frame_uclen: %d, frame_clen: %d, frame_maxhandle: %d\n", (int)frame_uclen, (int)frame_clen, (int)xc->rvat_frame_maxhandle); -fprintf(stderr, "\tvc_maxhandle: %d\n", (int)xc->rvat_vc_maxhandle); +fprintf(stderr, FST_APIMESS"vc_maxhandle: %d\n", (int)xc->rvat_vc_maxhandle); #endif indx_pntr = blkpos + seclen - 24 -tsec_clen -8; @@ -5900,14 +6012,14 @@ fstReaderFseeko(xc, xc->f, indx_pntr, SEEK_SET); chain_clen = fstReaderUint64(xc->f); indx_pos = indx_pntr - chain_clen; #ifdef FST_DEBUG -fprintf(stderr, "\tindx_pos: %d (%d bytes)\n", (int)indx_pos, (int)chain_clen); +fprintf(stderr, FST_APIMESS"indx_pos: %d (%d bytes)\n", (int)indx_pos, (int)chain_clen); #endif -chain_cmem = malloc(chain_clen); +chain_cmem = (unsigned char *)malloc(chain_clen); fstReaderFseeko(xc, xc->f, indx_pos, SEEK_SET); fstFread(chain_cmem, chain_clen, 1, xc->f); -xc->rvat_chain_table = calloc((xc->rvat_vc_maxhandle+1), sizeof(off_t)); -xc->rvat_chain_table_lengths = calloc((xc->rvat_vc_maxhandle+1), sizeof(uint32_t)); +xc->rvat_chain_table = (off_t *)calloc((xc->rvat_vc_maxhandle+1), sizeof(off_t)); +xc->rvat_chain_table_lengths = (uint32_t *)calloc((xc->rvat_vc_maxhandle+1), sizeof(uint32_t)); pnt = chain_cmem; idx = 0; @@ -5916,10 +6028,10 @@ pval = 0; if(sectype == FST_BL_VCDATA_DYN_ALIAS2) { uint32_t prev_alias = 0; - + do { int skiplen; - + if(*pnt & 0x01) { int64_t shval = fstGetSVarint64(pnt, &skiplen) >> 1; @@ -5934,7 +6046,7 @@ if(sectype == FST_BL_VCDATA_DYN_ALIAS2) xc->rvat_chain_table[idx] = 0; /* need to explicitly zero as calloc above might not run */ xc->rvat_chain_table_lengths[idx] = prev_alias = shval; /* because during this loop iter would give stale data! */ idx++; - } + } else { xc->rvat_chain_table[idx] = 0; /* need to explicitly zero as calloc above might not run */ @@ -5945,14 +6057,14 @@ if(sectype == FST_BL_VCDATA_DYN_ALIAS2) else { uint64_t val = fstGetVarint32(pnt, &skiplen); - + fstHandle loopcnt = val >> 1; for(i=0;irvat_chain_table[idx++] = 0; } } - + pnt += skiplen; } while (pnt != (chain_cmem + chain_clen)); } @@ -5962,7 +6074,7 @@ if(sectype == FST_BL_VCDATA_DYN_ALIAS2) { int skiplen; uint64_t val = fstGetVarint32(pnt, &skiplen); - + if(!val) { pnt += skiplen; @@ -5986,7 +6098,7 @@ if(sectype == FST_BL_VCDATA_DYN_ALIAS2) xc->rvat_chain_table[idx++] = 0; } } - + pnt += skiplen; } while (pnt != (chain_cmem + chain_clen)); } @@ -6011,7 +6123,7 @@ for(i=0;irvat_data_valid = 1; @@ -6049,8 +6161,8 @@ if(!xc->rvat_chain_mem) xc->rvat_chain_len = fstReaderVarint32WithSkip(xc->f, &skiplen); if(xc->rvat_chain_len) { - unsigned char *mu = malloc(xc->rvat_chain_len); - unsigned char *mc = malloc(xc->rvat_chain_table_lengths[facidx]); + unsigned char *mu = (unsigned char *)malloc(xc->rvat_chain_len); + unsigned char *mc = (unsigned char *)malloc(xc->rvat_chain_table_lengths[facidx]); unsigned long destlen = xc->rvat_chain_len; unsigned long sourcelen = xc->rvat_chain_table_lengths[facidx]; int rc = Z_OK; @@ -6071,7 +6183,7 @@ if(!xc->rvat_chain_mem) if(rc != Z_OK) { - printf("\tclen: %d (rc=%d)\n", (int)xc->rvat_chain_len, rc); + fprintf(stderr, FST_APIMESS"fstReaderGetValueFromHandleAtTime(), rvat decompress clen: %d (rc=%d), exiting.\n", (int)xc->rvat_chain_len, rc); exit(255); } @@ -6081,7 +6193,7 @@ if(!xc->rvat_chain_mem) else { int destlen = xc->rvat_chain_table_lengths[facidx] - skiplen; - unsigned char *mu = malloc(xc->rvat_chain_len = destlen); + unsigned char *mu = (unsigned char *)malloc(xc->rvat_chain_len = destlen); fstFread(mu, destlen, 1, xc->f); /* data to process is for(j=0;jrvat_chain_mem = mu; @@ -6382,17 +6494,17 @@ static uint32_t j_hash(const uint8_t *k, uint32_t length, uint32_t initval) c += length; switch(len) /* all the case statements fall through */ { - case 11: c+=((uint32_t)k[10]<<24); - case 10: c+=((uint32_t)k[9]<<16); - case 9 : c+=((uint32_t)k[8]<<8); + case 11: c+=((uint32_t)k[10]<<24); /* fallthrough */ + case 10: c+=((uint32_t)k[9]<<16); /* fallthrough */ + case 9 : c+=((uint32_t)k[8]<<8); /* fallthrough */ /* the first byte of c is reserved for the length */ - case 8 : b+=((uint32_t)k[7]<<24); - case 7 : b+=((uint32_t)k[6]<<16); - case 6 : b+=((uint32_t)k[5]<<8); - case 5 : b+=k[4]; - case 4 : a+=((uint32_t)k[3]<<24); - case 3 : a+=((uint32_t)k[2]<<16); - case 2 : a+=((uint32_t)k[1]<<8); + case 8 : b+=((uint32_t)k[7]<<24); /* fallthrough */ + case 7 : b+=((uint32_t)k[6]<<16); /* fallthrough */ + case 6 : b+=((uint32_t)k[5]<<8); /* fallthrough */ + case 5 : b+=k[4]; /* fallthrough */ + case 4 : a+=((uint32_t)k[3]<<24); /* fallthrough */ + case 3 : a+=((uint32_t)k[2]<<16); /* fallthrough */ + case 2 : a+=((uint32_t)k[1]<<8); /* fallthrough */ case 1 : a+=k[0]; /* case 0: nothing left to add */ } @@ -6427,7 +6539,7 @@ struct collchain_t *chain, *pchain; if(!*base) { - *base = calloc(1, (hashmask + 1) * sizeof(void *)); + *base = (struct collchain_t **)calloc(1, (hashmask + 1) * sizeof(void *)); } ar = *base; @@ -6450,7 +6562,7 @@ while(chain) chain = chain->next; } -chain = calloc(1, sizeof(struct collchain_t) + length - 1); +chain = (struct collchain_t *)calloc(1, sizeof(struct collchain_t) + length - 1); memcpy(chain->mem, mem, length); chain->fullhash = hf; chain->length = length; @@ -6496,9 +6608,46 @@ if(base && *base) /*** ***/ /************************/ -int fstUtilityBinToEsc(unsigned char *d, unsigned char *s, int len) +int fstUtilityBinToEscConvertedLen(const unsigned char *s, int len) { -unsigned char *src = s; +const unsigned char *src = s; +int dlen = 0; +int i; + +for(i=0;i ' ') && (src[i] <= '~')) /* no white spaces in output */ + { + dlen++; + } + else + { + dlen += 4; + } + break; + } + } + +return(dlen); +} + + +int fstUtilityBinToEsc(unsigned char *d, const unsigned char *s, int len) +{ +const unsigned char *src = s; unsigned char *dst = d; unsigned char val; int i; @@ -6597,3 +6746,76 @@ for(i=0;ielem_count = cnt; + et->name = strdup(s); + et->literal_arr = (char**)calloc(cnt, sizeof(char *)); + et->val_arr = (char**)calloc(cnt, sizeof(char *)); + + sp = strchr(et->name, ' '); + *sp = 0; + + sp = strchr(sp+1, ' '); + + for(i=0;iliteral_arr[i] = sp+1; + sp = sp2; + + newlen = fstUtilityEscToBin(NULL, (unsigned char*)et->literal_arr[i], strlen(et->literal_arr[i])); + et->literal_arr[i][newlen] = 0; + } + + for(i=0;ival_arr[i] = sp+1; + sp = sp2; + + newlen = fstUtilityEscToBin(NULL, (unsigned char*)et->val_arr[i], strlen(et->val_arr[i])); + et->val_arr[i][newlen] = 0; + } + } + } + +return(et); +} + + +void fstUtilityFreeEnumTable(struct fstETab *etab) +{ +if(etab) + { + free(etab->literal_arr); + free(etab->val_arr); + free(etab->name); + free(etab); + } +} diff --git a/vpi/fstapi.h b/vpi/fstapi.h index df86ef079..aef6de23b 100644 --- a/vpi/fstapi.h +++ b/vpi/fstapi.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2009-2015 Tony Bybell. + * Copyright (c) 2009-2018 Tony Bybell. * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), @@ -39,6 +39,7 @@ extern "C" { #define FST_RDLOAD "FSTLOAD | " typedef uint32_t fstHandle; +typedef uint32_t fstEnumHandle; enum fstWriterPackType { FST_WR_PT_ZLIB = 0, @@ -168,7 +169,11 @@ enum fstHierType { FST_HT_ATTRBEGIN = 3, FST_HT_ATTREND = 4, - FST_HT_MAX = 4 + /* FST_HT_TREEBEGIN and FST_HT_TREEEND are not yet used by FST but are currently used when fstHier bridges other formats */ + FST_HT_TREEBEGIN = 5, + FST_HT_TREEEND = 6, + + FST_HT_MAX = 6 }; enum fstAttrType { @@ -192,9 +197,10 @@ enum fstMiscType { FST_MT_SOURCESTEM = 4, /* use fstWriterSetSourceStem() to emit */ FST_MT_SOURCEISTEM = 5, /* use fstWriterSetSourceInstantiationStem() to emit */ FST_MT_VALUELIST = 6, /* use fstWriterSetValueList() to emit, followed by fstWriterCreateVar*() */ - FST_MT_UNKNOWN = 7, + FST_MT_ENUMTABLE = 7, /* use fstWriterCreateEnumTable() and fstWriterEmitEnumTableRef() to emit */ + FST_MT_UNKNOWN = 8, - FST_MT_MAX = 7 + FST_MT_MAX = 8 }; enum fstArrayType { @@ -224,7 +230,10 @@ enum fstEnumValueType { FST_EV_SV_UNSIGNED_LONGINT = 12, FST_EV_SV_UNSIGNED_BYTE = 13, - FST_EV_MAX = 13 + FST_EV_REG = 14, + FST_EV_TIME = 15, + + FST_EV_MAX = 15 }; enum fstPackType { @@ -320,11 +329,21 @@ union { }; +struct fstETab +{ +char *name; +uint32_t elem_count; +char **literal_arr; +char **val_arr; +}; + + /* * writer functions */ void fstWriterClose(void *ctx); void * fstWriterCreate(const char *nam, int use_compressed_hier); +fstEnumHandle fstWriterCreateEnumTable(void *ctx, const char *name, uint32_t elem_count, unsigned int min_valbits, const char **literal_arr, const char **val_arr); /* used for Verilog/SV */ fstHandle fstWriterCreateVar(void *ctx, enum fstVarType vt, enum fstVarDir vd, uint32_t len, const char *nam, fstHandle aliasHandle); @@ -333,9 +352,10 @@ fstHandle fstWriterCreateVar(void *ctx, enum fstVarType vt, enum fstVarDir fstHandle fstWriterCreateVar2(void *ctx, enum fstVarType vt, enum fstVarDir vd, uint32_t len, const char *nam, fstHandle aliasHandle, const char *type, enum fstSupplementalVarType svt, enum fstSupplementalDataType sdt); +void fstWriterEmitDumpActive(void *ctx, int enable); +void fstWriterEmitEnumTableRef(void *ctx, fstEnumHandle handle); void fstWriterEmitValueChange(void *ctx, fstHandle handle, const void *val); void fstWriterEmitVariableLengthValueChange(void *ctx, fstHandle handle, const void *val, uint32_t len); -void fstWriterEmitDumpActive(void *ctx, int enable); void fstWriterEmitTimeChange(void *ctx, uint64_t tim); void fstWriterFlushContext(void *ctx); int fstWriterGetDumpSizeLimitReached(void *ctx); @@ -418,8 +438,12 @@ void fstReaderSetVcdExtensions(void *ctx, int enable); /* * utility functions */ -int fstUtilityBinToEsc(unsigned char *d, unsigned char *s, int len); +int fstUtilityBinToEscConvertedLen(const unsigned char *s, int len); /* used for mallocs for fstUtilityBinToEsc() */ +int fstUtilityBinToEsc(unsigned char *d, const unsigned char *s, int len); int fstUtilityEscToBin(unsigned char *d, unsigned char *s, int len); +struct fstETab *fstUtilityExtractEnumTableFromString(const char *s); +void fstUtilityFreeEnumTable(struct fstETab *etab); /* must use to free fstETab properly */ + #ifdef __cplusplus } diff --git a/vpi/lxt2_write.c b/vpi/lxt2_write.c index 1ebf3e179..d51ad73a2 100644 --- a/vpi/lxt2_write.c +++ b/vpi/lxt2_write.c @@ -97,7 +97,7 @@ if (lonumfacs)) { struct lxt2_wr_symbol *s = lt->symchain; - struct lxt2_wr_symbol **aliascache = calloc(lt->numalias ? lt->numalias : 1, sizeof(struct lxt2_wr_symbol *)); + struct lxt2_wr_symbol **aliascache = (struct lxt2_wr_symbol**)calloc(lt->numalias ? lt->numalias : 1, sizeof(struct lxt2_wr_symbol *)); unsigned int aliases_encountered, facs_encountered; lt->sorted_facs = (struct lxt2_wr_symbol **)calloc(lt->numfacs, sizeof(struct lxt2_wr_symbol *)); @@ -920,7 +920,7 @@ if(flags&LXT2_WR_SYM_F_DOUBLE) s->len = 32; } - s->value = malloc(s->len + 1); + s->value = (char*)malloc(s->len + 1); memset(s->value, lt->initial_value, s->len); s->value[s->len]=0; @@ -1017,7 +1017,7 @@ static void lxt2_wr_emit_do_breakfile(struct lxt2_wr_trace *lt) { unsigned int len = strlen(lt->lxtname); int i; -char *tname = malloc(len + 30); +char *tname = (char*)malloc(len + 30); FILE *f2, *clone; off_t cnt, seg; char buf[32768]; @@ -1810,13 +1810,13 @@ while(s->aliased_to) /* find root alias if exists */ valuelen = strlen(value); /* ensure string is proper length */ if(valuelen == s->len) { - vfix = wave_alloca(s->len+1); + vfix = (char*)wave_alloca(s->len+1); strcpy(vfix, value); value = vfix; } else { - vfix = wave_alloca(s->len+1); + vfix = (char*)wave_alloca(s->len+1); if(valuelen < s->len) { @@ -2088,7 +2088,7 @@ if((lt)&&(lt->blackout)) else { free(s->value); - s->value = calloc(1, 1*sizeof(char)); + s->value = (char*)calloc(1, 1*sizeof(char)); } } } @@ -2101,9 +2101,11 @@ if((lt)&&(lt->blackout)) { if((!(s->flags&LXT2_WR_SYM_F_ALIAS))&&(s->rows<2)) { + char tmp[16]; /* To get rid of the warning */ if(!(s->flags&(LXT2_WR_SYM_F_DOUBLE|LXT2_WR_SYM_F_STRING))) { - lxt2_wr_emit_value_bit_string(lt, s, 0, "x"); + strcpy(tmp, "x"); + lxt2_wr_emit_value_bit_string(lt, s, 0, tmp); } else if (s->flags&LXT2_WR_SYM_F_DOUBLE) { @@ -2113,7 +2115,8 @@ if((lt)&&(lt->blackout)) } else if (s->flags&LXT2_WR_SYM_F_STRING) { - lxt2_wr_emit_value_string(lt, s, 0, "UNDEF"); + strcpy(tmp, "UNDEF"); + lxt2_wr_emit_value_string(lt, s, 0, tmp); } } s=s->symchain; @@ -2202,4 +2205,3 @@ if(lt) lt->timezero = timeval; } } - diff --git a/vpi/lxt2_write.h b/vpi/lxt2_write.h index 7f2c6d134..1a8a1adbb 100644 --- a/vpi/lxt2_write.h +++ b/vpi/lxt2_write.h @@ -43,7 +43,7 @@ extern "C" { #define ftello ftell #endif -#include +#include "wavealloca.h" #define LXT2_WR_HDRID (0x1380) #define LXT2_WR_VERSION (0x0001) @@ -314,4 +314,3 @@ int lxt2_wr_emit_value_bit_string(struct lxt2_wr_trace *lt, struct lxt2_wr_sy #endif #endif - diff --git a/vpi/lz4.c b/vpi/lz4.c index 08cf6b5cd..5ee034eea 100644 --- a/vpi/lz4.c +++ b/vpi/lz4.c @@ -228,6 +228,9 @@ static const int LZ4_minLength = (MFLIMIT+1); #define GB *(1U<<30) #define MAXD_LOG 16 +#ifdef MAX_DISTANCE +#undef MAX_DISTANCE +#endif #define MAX_DISTANCE ((1 << MAXD_LOG) - 1) #define ML_BITS 4 @@ -825,7 +828,7 @@ _next_match: /* Match description too long : reduce it */ matchLength = (15-1) + (oMaxMatch-op) * 255; } - //printf("offset %5i, matchLength%5i \n", (int)(ip-match), matchLength + MINMATCH); + /*printf("offset %5i, matchLength%5i \n", (int)(ip-match), matchLength + MINMATCH);*/ ip += MINMATCH + matchLength; if (matchLength>=ML_MASK) diff --git a/vpi/sdf_lexor.lex b/vpi/sdf_lexor.lex index 0b8c7767e..9f05dd230 100644 --- a/vpi/sdf_lexor.lex +++ b/vpi/sdf_lexor.lex @@ -5,7 +5,7 @@ %{ /* - * Copyright (c) 2007-2014 Stephen Williams (steve@icarus.com) + * Copyright (c) 2007-2017 Stephen Williams (steve@icarus.com) * * This source code is free software; you can redistribute it * and/or modify it in source code form under the terms of the GNU @@ -217,7 +217,7 @@ static void destroy_sdf_lexor(void) { # ifdef FLEX_SCANNER # if YY_FLEX_MAJOR_VERSION >= 2 && YY_FLEX_MINOR_VERSION >= 5 -# if defined(YY_FLEX_SUBMINOR_VERSION) && YY_FLEX_SUBMINOR_VERSION >= 9 +# if YY_FLEX_MINOR_VERSION > 5 || defined(YY_FLEX_SUBMINOR_VERSION) && YY_FLEX_SUBMINOR_VERSION >= 9 yylex_destroy(); # endif # endif diff --git a/vpi/sys_convert.c b/vpi/sys_convert.c index 389e3c764..8f78fec5a 100644 --- a/vpi/sys_convert.c +++ b/vpi/sys_convert.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003-2014 Michael Ruff (mruff at chiaro.com) + * Copyright (c) 2003-2018 Michael Ruff (mruff at chiaro.com) * * This source code is free software; you can redistribute it * and/or modify it in source code form under the terms of the GNU @@ -90,12 +90,12 @@ static void error_message(vpiHandle callh, const char* msg) vpi_control(vpiFinish, 1); } -static PLI_INT32 sizetf_32 (PLI_BYTE8*name) +static PLI_INT32 sizetf_32 (ICARUS_VPI_CONST PLI_BYTE8*name) { (void)name; /* Parameter is not used. */ return 32; } -static PLI_INT32 sizetf_64 (PLI_BYTE8*name) +static PLI_INT32 sizetf_64 (ICARUS_VPI_CONST PLI_BYTE8*name) { (void)name; /* Parameter is not used. */ return 64; @@ -288,4 +288,3 @@ void sys_convert_register(void) res = vpi_register_systf(&tf_data); vpip_make_systf_system_defined(res); } - diff --git a/vpi/sys_countdrivers.c b/vpi/sys_countdrivers.c index 3eedc431e..d4fbb8ea4 100644 --- a/vpi/sys_countdrivers.c +++ b/vpi/sys_countdrivers.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2012-2014 Martin Whitaker. (icarus@martin-whitaker.me.uk) + * Copyright (C) 2012-2018 Martin Whitaker. (icarus@martin-whitaker.me.uk) * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -33,6 +33,7 @@ static void check_net_arg(vpiHandle arg, vpiHandle callh, const char *name) case vpiPartSelect: if (vpi_get(vpiType, vpi_handle(vpiParent, arg)) != vpiNet) break; + // fallthrough case vpiNet: if (vpi_get(vpiSize, arg) != 1) break; diff --git a/vpi/sys_display.c b/vpi/sys_display.c index dc04182fd..04cd66799 100644 --- a/vpi/sys_display.c +++ b/vpi/sys_display.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999-2016 Stephen Williams (steve@icarus.com) + * Copyright (c) 1999-2018 Stephen Williams (steve@icarus.com) * * This source code is free software; you can redistribute it * and/or modify it in source code form under the terms of the GNU @@ -407,31 +407,31 @@ static unsigned int get_format_char(char **rtn, int ljust, int plus, vpi_printf("WARNING: %s:%d: missing argument for %s%s.\n", info->filename, info->lineno, info->name, fmtb); } else { - value.format = vpiStringVal; + value.format = vpiIntVal; vpi_get_value(info->items[*idx], &value); if (value.format == vpiSuppressVal) { vpi_printf("WARNING: %s:%d: incompatible value for %s%s.\n", info->filename, info->lineno, info->name, fmtb); } else { - char ch = value.value.str[strlen(value.value.str)-1]; - - /* If the default buffer is too small, make it big enough. */ - size = width + 1; - if (size > ini_size) result = realloc(result, size*sizeof(char)); + char ch = value.value.integer; /* If the width is less than one then use a width of one. */ if (width < 1) width = 1; + size = width + 1; + assert(size <= ini_size); + if (ljust == 0) { if (width > 1) { - char *cp = malloc((width+1)*sizeof(char)); - memset(cp, (ld_zero == 1 ? '0': ' '), width-1); - cp[width-1] = ch; - cp[width] = '\0'; - sprintf(result, "%*s", width, cp); - free(cp); - } else sprintf(result, "%c", ch); - } else sprintf(result, "%-*c", width, ch); - size = strlen(result) + 1; + memset(result, (ld_zero == 1 ? '0': ' '), width-1); + } + result[width-1] = ch; + } else { + result[0] = ch; + if (width > 1) { + memset(result+1, ' ', width-1); + } + } + result[width] = '\0'; } } break; @@ -1169,7 +1169,7 @@ static int sys_check_args(vpiHandle callh, vpiHandle argv, const PLI_BYTE8*name, name, vpi_get_str(vpiType, arg)); ret = 1; } - + // fallthrough case vpiConstant: case vpiParameter: case vpiNet: @@ -1971,6 +1971,8 @@ static const char *pts_convert(int value) { const char *string; switch (value) { + case 2: string = "100s"; break; + case 1: string = "10s"; break; case 0: string = "1s"; break; case -1: string = "100ms"; break; case -2: string = "10ms"; break; diff --git a/vpi/sys_fileio.c b/vpi/sys_fileio.c index f63fd64e0..dbdecf5dc 100644 --- a/vpi/sys_fileio.c +++ b/vpi/sys_fileio.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003-2013 Stephen Williams (steve@icarus.com) + * Copyright (c) 2003-2018 Stephen Williams (steve@icarus.com) * * This source code is free software; you can redistribute it * and/or modify it in source code form under the terms of the GNU @@ -132,7 +132,7 @@ static PLI_INT32 sys_fopen_calltf(ICARUS_VPI_CONST PLI_BYTE8*name) } } if (! fail) break; - + // fallthrough default: vpi_printf("WARNING: %s:%d: ", vpi_get_str(vpiFile, callh), diff --git a/vpi/sys_lxt.c b/vpi/sys_lxt.c index b05c3dbfa..d0de6765d 100644 --- a/vpi/sys_lxt.c +++ b/vpi/sys_lxt.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2002-2016 Stephen Williams (steve@icarus.com) + * Copyright (c) 2002-2018 Stephen Williams (steve@icarus.com) * * This source code is free software; you can redistribute it * and/or modify it in source code form under the terms of the GNU @@ -550,6 +550,7 @@ static void scan_item(unsigned depth, vpiHandle item, int skip) PLI_INT32 idx = vpi_get(vpiIndex, item); item = vpi_handle_by_index(array, idx); } + // fallthrough case vpiIntegerVar: case vpiBitVar: case vpiByteVar: diff --git a/vpi/sys_lxt2.c b/vpi/sys_lxt2.c index 1527efa09..3327264d1 100644 --- a/vpi/sys_lxt2.c +++ b/vpi/sys_lxt2.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003-2016 Stephen Williams (steve@icarus.com) + * Copyright (c) 2003-2018 Stephen Williams (steve@icarus.com) * * This source code is free software; you can redistribute it * and/or modify it in source code form under the terms of the GNU @@ -610,6 +610,7 @@ static void scan_item(unsigned depth, vpiHandle item, int skip) PLI_INT32 idx = vpi_get(vpiIndex, item); item = vpi_handle_by_index(array, idx); } + // fallthrough case vpiIntegerVar: case vpiBitVar: case vpiByteVar: diff --git a/vpi/sys_priv.c b/vpi/sys_priv.c index 1d5e977bb..dd9714325 100644 --- a/vpi/sys_priv.c +++ b/vpi/sys_priv.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003-2016 Stephen Williams (steve@icarus.com) + * Copyright (c) 2003-2018 Stephen Williams (steve@icarus.com) * * This source code is free software; you can redistribute it * and/or modify it in source code form under the terms of the GNU @@ -37,17 +37,17 @@ PLI_UINT64 timerec_to_time64(const struct t_vpi_time*timerec) char *as_escaped(char *arg) { - unsigned idx, cur, cnt, len = strlen(arg); - char *res = (char *) malloc(sizeof(char *) * len); + unsigned idx, cur, cnt, len = strlen(arg) + 1; + char *res = (char *) malloc(sizeof(char) * len); cur = 0; - cnt = len; + cnt = len - 1; for (idx = 0; idx < cnt; idx++) { if (isprint((int)arg[idx])) { res[cur] = arg[idx]; cur += 1; } else { len += 3; - res = (char *) realloc(res, sizeof(char *) * len); + res = (char *) realloc(res, sizeof(char) * len); sprintf(&(res[cur]), "\\%03o", arg[idx]); cur += 4; } @@ -399,3 +399,23 @@ PLI_INT32 sys_one_string_arg_compiletf(ICARUS_VPI_CONST PLI_BYTE8 *name) return 0; } + +/* Return an integer value to the caller. */ +void put_integer_value(vpiHandle callh, PLI_INT32 result) +{ + s_vpi_value val; + + val.format = vpiIntVal; + val.value.integer = result; + vpi_put_value(callh, &val, 0, vpiNoDelay); +} + +/* Return a scalar value to the caller. */ +void put_scalar_value(vpiHandle callh, PLI_INT32 result) +{ + s_vpi_value val; + + val.format = vpiScalarVal; + val.value.scalar = result; + vpi_put_value(callh, &val, 0, vpiNoDelay); +} diff --git a/vpi/sys_priv.h b/vpi/sys_priv.h index 36553b250..d9052d51d 100644 --- a/vpi/sys_priv.h +++ b/vpi/sys_priv.h @@ -1,7 +1,7 @@ #ifndef IVL_sys_priv_H #define IVL_sys_priv_H /* - * Copyright (c) 2002-2014 Stephen Williams (steve@icarus.com) + * Copyright (c) 2002-2018 Stephen Williams (steve@icarus.com) * * This source code is free software; you can redistribute it * and/or modify it in source code form under the terms of the GNU @@ -65,4 +65,10 @@ extern PLI_INT32 sys_one_opt_numeric_arg_compiletf(ICARUS_VPI_CONST PLI_BYTE8 *n extern PLI_INT32 sys_two_numeric_args_compiletf(ICARUS_VPI_CONST PLI_BYTE8 *name); extern PLI_INT32 sys_one_string_arg_compiletf(ICARUS_VPI_CONST PLI_BYTE8 *name); +/* + * The standard put/return a value to the caller routines. + */ +extern void put_integer_value(vpiHandle callh, PLI_INT32 result); +extern void put_scalar_value(vpiHandle callh, PLI_INT32 result); + #endif /* IVL_sys_priv_H */ diff --git a/vpi/sys_queue.c b/vpi/sys_queue.c index 3d34c7b4a..7eb7525c2 100644 --- a/vpi/sys_queue.c +++ b/vpi/sys_queue.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2014 Cary R. (cygcary@yahoo.com) + * Copyright (C) 2011-2018 Cary R. (cygcary@yahoo.com) * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -781,6 +781,7 @@ static PLI_INT32 fill_variable_with_scaled_time(vpiHandle var, uint64_t c_time) switch (words) { default: val_ptr[1].aval = (c_time >> 32) & 0xffffffff; + // fallthrough case 1: val_ptr[0].aval = c_time & 0xffffffff; } diff --git a/vpi/sys_random.c b/vpi/sys_random.c index f774764a6..72bb1c66f 100644 --- a/vpi/sys_random.c +++ b/vpi/sys_random.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000-2014 Stephen Williams (steve@icarus.com) + * Copyright (c) 2000-2018 Stephen Williams (steve@icarus.com) * * This source code is free software; you can redistribute it * and/or modify it in source code form under the terms of the GNU @@ -924,7 +924,7 @@ static PLI_INT32 sys_dist_erlang_calltf(ICARUS_VPI_CONST PLI_BYTE8 *name) return 0; } -static PLI_INT32 sys_rand_func_sizetf(PLI_BYTE8 *name) +static PLI_INT32 sys_rand_func_sizetf(ICARUS_VPI_CONST PLI_BYTE8 *name) { (void)name; /* Parameter is not used. */ return 32; diff --git a/vpi/sys_readmem.c b/vpi/sys_readmem.c index a670a6317..0922214cf 100644 --- a/vpi/sys_readmem.c +++ b/vpi/sys_readmem.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999-2014 Stephen Williams (steve@icarus.com) + * Copyright (c) 1999-2018 Stephen Williams (steve@icarus.com) * * This source code is free software; you can redistribute it * and/or modify it in source code form under the terms of the GNU @@ -49,6 +49,7 @@ static void get_mem_params(vpiHandle argv, vpiHandle callh, const char *name, case vpiConstant: case vpiParameter: if (vpi_get(vpiConstType, *start_item) != vpiRealConst) break; + // fallthrough case vpiRealVar: vpi_printf("WARNING: %s:%d: ", vpi_get_str(vpiFile, callh), (int)vpi_get(vpiLineNo, callh)); @@ -67,6 +68,7 @@ static void get_mem_params(vpiHandle argv, vpiHandle callh, const char *name, if (vpi_get(vpiConstType, *stop_item) != vpiRealConst) { break; } + // fallthrough case vpiRealVar: vpi_printf("WARNING: %s:%d: ", vpi_get_str(vpiFile, callh), diff --git a/vpi/sys_readmem_lex.lex b/vpi/sys_readmem_lex.lex index 22e5b0e80..c7f4c53ef 100644 --- a/vpi/sys_readmem_lex.lex +++ b/vpi/sys_readmem_lex.lex @@ -4,7 +4,7 @@ %{ /* - * Copyright (c) 1999-2009 Stephen Williams (steve@icarus.com) + * Copyright (c) 1999-2017 Stephen Williams (steve@icarus.com) * * This source code is free software; you can redistribute it * and/or modify it in source code form under the terms of the GNU @@ -199,7 +199,7 @@ void destroy_readmem_lexor(void) { # ifdef FLEX_SCANNER # if YY_FLEX_MAJOR_VERSION >= 2 && YY_FLEX_MINOR_VERSION >= 5 -# if defined(YY_FLEX_SUBMINOR_VERSION) && YY_FLEX_SUBMINOR_VERSION >= 9 +# if YY_FLEX_MINOR_VERSION > 5 || defined(YY_FLEX_SUBMINOR_VERSION) && YY_FLEX_SUBMINOR_VERSION >= 9 yylex_destroy(); # endif # endif diff --git a/vpi/sys_scanf.c b/vpi/sys_scanf.c index 2e86cae2d..4768a72e8 100644 --- a/vpi/sys_scanf.c +++ b/vpi/sys_scanf.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2006-2015 Stephen Williams (steve@icarus.com) + * Copyright (c) 2006-2018 Stephen Williams (steve@icarus.com) * * This source code is free software; you can redistribute it * and/or modify it in source code form under the terms of the GNU @@ -219,7 +219,7 @@ static double get_float(struct byte_source *src, unsigned width, int *match) */ static int scan_format_float(vpiHandle callh, vpiHandle argv, struct byte_source *src, unsigned width, - unsigned suppress_flag, PLI_BYTE8 *name, + unsigned suppress_flag, ICARUS_VPI_CONST PLI_BYTE8 *name, char code) { vpiHandle arg; @@ -266,7 +266,7 @@ static int scan_format_float(vpiHandle callh, vpiHandle argv, */ static int scan_format_float_time(vpiHandle callh, vpiHandle argv, struct byte_source*src, unsigned width, - unsigned suppress_flag, PLI_BYTE8 *name) + unsigned suppress_flag, ICARUS_VPI_CONST PLI_BYTE8 *name) { vpiHandle scope = vpi_handle(vpiScope, callh); int time_units = vpi_get(vpiTimeUnit, scope); @@ -330,7 +330,7 @@ static int scan_format_float_time(vpiHandle callh, vpiHandle argv, */ static int scan_format_base(vpiHandle callh, vpiHandle argv, struct byte_source *src, unsigned width, - unsigned suppress_flag, PLI_BYTE8 *name, + unsigned suppress_flag, ICARUS_VPI_CONST PLI_BYTE8 *name, const char *match, char code, PLI_INT32 type) { @@ -406,7 +406,7 @@ static int scan_format_base(vpiHandle callh, vpiHandle argv, */ static int scan_format_binary(vpiHandle callh, vpiHandle argv, struct byte_source *src, int width, - unsigned suppress_flag, PLI_BYTE8 *name) + unsigned suppress_flag, ICARUS_VPI_CONST PLI_BYTE8 *name) { return scan_format_base(callh, argv, src, width, suppress_flag, name, "01xzXZ?_", 'b', vpiBinStrVal); @@ -420,7 +420,7 @@ static int scan_format_binary(vpiHandle callh, vpiHandle argv, */ static int scan_format_char(vpiHandle callh, vpiHandle argv, struct byte_source *src, unsigned width, - unsigned suppress_flag, PLI_BYTE8 *name) + unsigned suppress_flag, ICARUS_VPI_CONST PLI_BYTE8 *name) { vpiHandle arg; s_vpi_value val; @@ -466,7 +466,7 @@ static int scan_format_char(vpiHandle callh, vpiHandle argv, */ static int scan_format_decimal(vpiHandle callh, vpiHandle argv, struct byte_source *src, unsigned width, - unsigned suppress_flag, PLI_BYTE8 *name) + unsigned suppress_flag, ICARUS_VPI_CONST PLI_BYTE8 *name) { vpiHandle arg; char *strval = malloc(1); @@ -585,7 +585,7 @@ static int scan_format_decimal(vpiHandle callh, vpiHandle argv, */ static int scan_format_hex(vpiHandle callh, vpiHandle argv, struct byte_source *src, unsigned width, - unsigned suppress_flag, PLI_BYTE8 *name) + unsigned suppress_flag, ICARUS_VPI_CONST PLI_BYTE8 *name) { return scan_format_base(callh, argv, src, width, suppress_flag, name, "0123456789abcdefxzABCDEFXZ?_", 'h', @@ -597,7 +597,7 @@ static int scan_format_hex(vpiHandle callh, vpiHandle argv, */ static int scan_format_octal(vpiHandle callh, vpiHandle argv, struct byte_source *src, unsigned width, - unsigned suppress_flag, PLI_BYTE8 *name) + unsigned suppress_flag, ICARUS_VPI_CONST PLI_BYTE8 *name) { return scan_format_base(callh, argv, src, width, suppress_flag, name, "01234567xzXZ?_", 'o', vpiOctStrVal); @@ -608,7 +608,7 @@ static int scan_format_octal(vpiHandle callh, vpiHandle argv, * Routine to return the current hierarchical path (implements %m). */ static int scan_format_module_path(vpiHandle callh, vpiHandle argv, - unsigned suppress_flag, PLI_BYTE8 *name) + unsigned suppress_flag, ICARUS_VPI_CONST PLI_BYTE8 *name) { vpiHandle scope, arg; char *module_path; @@ -650,7 +650,7 @@ static int scan_format_module_path(vpiHandle callh, vpiHandle argv, */ static int scan_format_string(vpiHandle callh, vpiHandle argv, struct byte_source *src, unsigned width, - unsigned suppress_flag, PLI_BYTE8 *name) + unsigned suppress_flag, ICARUS_VPI_CONST PLI_BYTE8 *name) { vpiHandle arg; char *strval = malloc(1); @@ -729,7 +729,7 @@ static int scan_format_string(vpiHandle callh, vpiHandle argv, */ static int scan_format_two_state(vpiHandle callh, vpiHandle argv, struct byte_source *src, unsigned width, - unsigned suppress_flag, PLI_BYTE8 *name) + unsigned suppress_flag, ICARUS_VPI_CONST PLI_BYTE8 *name) { vpiHandle arg; p_vpi_vecval val_ptr; @@ -868,7 +868,7 @@ static int scan_format_two_state(vpiHandle callh, vpiHandle argv, */ static int scan_format_four_state(vpiHandle callh, vpiHandle argv, struct byte_source *src, unsigned width, - unsigned suppress_flag, PLI_BYTE8 *name) + unsigned suppress_flag, ICARUS_VPI_CONST PLI_BYTE8 *name) { vpiHandle arg; p_vpi_vecval val_ptr; @@ -1006,7 +1006,7 @@ static int scan_format_four_state(vpiHandle callh, vpiHandle argv, * passed to this function, which processes the rest of the function. */ static int scan_format(vpiHandle callh, struct byte_source*src, vpiHandle argv, - PLI_BYTE8 *name) + ICARUS_VPI_CONST PLI_BYTE8 *name) { s_vpi_value val; vpiHandle item; @@ -1258,6 +1258,7 @@ static int is_assignable_obj(vpiHandle obj) break; case vpiPartSelect: if (! is_assignable_obj(vpi_handle(vpiParent, obj))) break; + // fallthrough case vpiIntegerVar: case vpiBitVar: case vpiByteVar: @@ -1403,7 +1404,7 @@ static PLI_INT32 sys_sscanf_compiletf(ICARUS_VPI_CONST PLI_BYTE8 *name) case vpiConstant: case vpiParameter: if (vpi_get(vpiConstType, reg) == vpiStringConst) break; - + // fallthrough default: vpi_printf("ERROR: %s:%d: ", vpi_get_str(vpiFile, callh), (int)vpi_get(vpiLineNo, callh)); diff --git a/vpi/sys_sdf.c b/vpi/sys_sdf.c index 5d69ff623..9d3cd2b7b 100644 --- a/vpi/sys_sdf.c +++ b/vpi/sys_sdf.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007-2014 Stephen Williams (steve@icarus.com) + * Copyright (c) 2007-2017 Stephen Williams (steve@icarus.com) * * This source code is free software; you can redistribute it * and/or modify it in source code form under the terms of the GNU @@ -289,7 +289,10 @@ static PLI_INT32 sys_sdf_annotate_calltf(ICARUS_VPI_CONST PLI_BYTE8*name) FILE *sdf_fd; char *fname = get_filename(callh, name, vpi_scan(argv)); - if (fname == 0) return 0; + if (fname == 0) { + vpi_free_object(argv); + return 0; + } sdf_fd = fopen(fname, "r"); if (sdf_fd == 0) { @@ -297,6 +300,8 @@ static PLI_INT32 sys_sdf_annotate_calltf(ICARUS_VPI_CONST PLI_BYTE8*name) (int)vpi_get(vpiLineNo, callh)); vpi_printf("Unable to open SDF file \"%s\"." " Skipping this annotation.\n", fname); + vpi_free_object(argv); + free(fname); return 0; } diff --git a/vpi/sys_table.c b/vpi/sys_table.c index bb5e3ad7e..23b2c9142 100644 --- a/vpi/sys_table.c +++ b/vpi/sys_table.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999-2010,2012 Stephen Williams (steve@icarus.com) + * Copyright (c) 1999-2018 Stephen Williams (steve@icarus.com) * * This source code is free software; you can redistribute it * and/or modify it in source code form under the terms of the GNU diff --git a/vpi/table_mod_lexor.lex b/vpi/table_mod_lexor.lex index bd518ee7e..36031821b 100644 --- a/vpi/table_mod_lexor.lex +++ b/vpi/table_mod_lexor.lex @@ -6,7 +6,7 @@ %{ /* - * Copyright (C) 2011-2013 Cary R. (cygcary@yahoo.com) + * Copyright (C) 2011-2017 Cary R. (cygcary@yahoo.com) * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -154,7 +154,7 @@ void destroy_tblmod_lexor(void) { # ifdef FLEX_SCANNER # if YY_FLEX_MAJOR_VERSION >= 2 && YY_FLEX_MINOR_VERSION >= 5 -# if defined(YY_FLEX_SUBMINOR_VERSION) && YY_FLEX_SUBMINOR_VERSION >= 9 +# if YY_FLEX_MINOR_VERSION > 5 || defined(YY_FLEX_SUBMINOR_VERSION) && YY_FLEX_SUBMINOR_VERSION >= 9 yylex_destroy(); # endif # endif diff --git a/vpi/v2009.sft b/vpi/v2009.sft index e2a84620b..e60c8cfdd 100644 --- a/vpi/v2009.sft +++ b/vpi/v2009.sft @@ -12,5 +12,11 @@ $high vpiSysFuncInt $increment vpiSysFuncInt $size vpiSysFuncInt +$countbits vpiSysFuncInt +$countones vpiSysFuncInt +$onehot vpiSysFuncSized 1 unsigned +$onehot0 vpiSysFuncSized 1 unsigned +$isunknown vpiSysFuncSized 1 unsigned + $ivl_array_method$to_vec vpiSysFuncVoid $ivl_array_method$from_vec vpiSysFuncVoid diff --git a/vpi/v2009_bitvec.c b/vpi/v2009_bitvec.c new file mode 100644 index 000000000..cc824b9bb --- /dev/null +++ b/vpi/v2009_bitvec.c @@ -0,0 +1,340 @@ +/* + * Copyright (C) 2018 Cary R. (cygcary@yahoo.com) + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#include +#include "vpi_user.h" +#include "sys_priv.h" + +/* + * Check that $couintbits() is called with the correct arguments. + */ +static PLI_INT32 countbits_compiletf(ICARUS_VPI_CONST PLI_BYTE8 *name) +{ + vpiHandle callh = vpi_handle(vpiSysTfCall, 0); + vpiHandle argv, arg; + int cb_count = 1; + + assert(callh != 0); + argv = vpi_iterate(vpiArgument, callh); + (void)name; /* Parameter is not used. */ + + /* $countbits() must have arguments. */ + if (argv == 0) { + vpi_printf("ERROR: %s:%d: ", vpi_get_str(vpiFile, callh), + (int)vpi_get(vpiLineNo, callh)); + vpi_printf("$countbits() requires at least two arguments.\n"); + vpi_control(vpiFinish, 1); + return 0; + } + + /* The 1st argument must be numeric. */ + arg = vpi_scan(argv); + if (! is_numeric_obj(arg)) { + vpi_printf("ERROR: %s:%d: ", vpi_get_str(vpiFile, callh), + (int)vpi_get(vpiLineNo, callh)); + vpi_printf("The first argument to $countbits() must be numeric.\n"); + vpi_control(vpiFinish, 1); + } + + /* We need one or more numeric control bit arguments. */ + arg = vpi_scan(argv); + if (! arg) { + vpi_printf("ERROR: %s:%d: ", vpi_get_str(vpiFile, callh), + (int)vpi_get(vpiLineNo, callh)); + vpi_printf("$countbits() requires at least one control bit " + "argument.\n"); + vpi_control(vpiFinish, 1); + } + + do { + if (arg && ! is_numeric_obj(arg)) { + vpi_printf("ERROR: %s:%d: ", vpi_get_str(vpiFile, callh), + (int)vpi_get(vpiLineNo, callh)); + vpi_printf("Control bit argument %d to $countbits() must " + "be numeric.\n", cb_count); + vpi_control(vpiFinish, 1); + } + ++cb_count; + if (arg) arg = vpi_scan(argv); + } while (arg); + + return 0; +} + +/* Count the number of bits in the expression that match the search bits. */ +static PLI_INT32 count_bits_in_expr(vpiHandle expr_arg, char search[4]) +{ + s_vpi_value val; + PLI_INT32 result; + PLI_INT32 size = vpi_get(vpiSize, expr_arg); + assert(size > 0); + + val.format = vpiVectorVal; + vpi_get_value(expr_arg, &val); + + result = 0; + for (unsigned lp = 0; lp < (unsigned)size; ++lp) { + unsigned offset = lp / 32; + unsigned bit = lp % 32; + unsigned abit, bbit; + abit = (val.value.vector[offset].aval >> bit) & 0x1; + bbit = (val.value.vector[offset].bval >> bit) & 0x1; + if (search[(bbit<<1)|abit]) ++result; + } + + return result; +} + +static PLI_INT32 countbits_calltf(ICARUS_VPI_CONST PLI_BYTE8 *name) +{ + vpiHandle callh = vpi_handle(vpiSysTfCall, 0); + vpiHandle argv = vpi_iterate(vpiArgument, callh); + vpiHandle expr_arg = vpi_scan(argv); + vpiHandle arg; + char search[4]; + (void)name; /* Parameter is not used. */ + + /* Scan the control bit arguments and mark which control bits to + * include in the count. */ + for (unsigned lp = 0; lp < 4 ; ++lp) search[lp] = 0; + while ((arg = vpi_scan(argv))) { + s_vpi_value val; + val.format = vpiScalarVal; + vpi_get_value(arg, &val); + switch (val.value.scalar) { + case vpi0: + search[0] = 1; + break; + case vpi1: + search[1] = 1; + break; + case vpiZ: + search[2] = 1; + break; + case vpiX: + search[3] = 1; + break; + default: + vpi_printf("WARNING: %s:%d: ", vpi_get_str(vpiFile, callh), + (int)vpi_get(vpiLineNo, callh)); + vpi_printf("Unknown scalar control bit argument %d passed " + "to $countbits() will be ignored.\n", + val.value.scalar); + break; + } + } + + put_integer_value(callh, count_bits_in_expr(expr_arg, search)); + + return 0; +} + +/* Count the number of ones in the expression. */ +static PLI_INT32 count_ones_in_expr(vpiHandle expr_arg) +{ + s_vpi_value val; + PLI_INT32 result; + PLI_INT32 size = vpi_get(vpiSize, expr_arg); + assert(size > 0); + + val.format = vpiVectorVal; + vpi_get_value(expr_arg, &val); + + result = 0; + size = (size + 31) / 32; + for (unsigned lp = 0; lp < (unsigned)size; ++lp) { + PLI_UINT32 ones = ~val.value.vector[lp].bval & + val.value.vector[lp].aval; + while (ones) { + if (ones & 0x1) ++result; + ones >>= 1; + } + } + + return result; +} + +static PLI_INT32 countones_calltf(ICARUS_VPI_CONST PLI_BYTE8 *name) +{ + vpiHandle callh = vpi_handle(vpiSysTfCall, 0); + vpiHandle argv = vpi_iterate(vpiArgument, callh); + vpiHandle expr_arg = vpi_scan(argv); + (void)name; /* Parameter is not used. */ + + vpi_free_object(argv); + + put_integer_value(callh, count_ones_in_expr(expr_arg)); + + return 0; +} + +/* Check to see if the expression is onehot. */ +static PLI_INT32 is_onehot(vpiHandle expr_arg, unsigned zero_is_okay) +{ + s_vpi_value val; + unsigned found_a_one; + PLI_INT32 size = vpi_get(vpiSize, expr_arg); + assert(size > 0); + + val.format = vpiVectorVal; + vpi_get_value(expr_arg, &val); + + found_a_one = 0; + size = (size + 31) / 32; + for (unsigned lp = 0; lp < (unsigned)size; ++lp) { + PLI_UINT32 ones = ~val.value.vector[lp].bval & + val.value.vector[lp].aval; + while (ones) { + if (ones & 0x1) { + if (found_a_one) return vpi0; + found_a_one = 1; + } + ones >>= 1; + } + } + + if (found_a_one) return vpi1; + else if (zero_is_okay) return vpi1; + return vpi0; +} + +static PLI_INT32 onehot_calltf(ICARUS_VPI_CONST PLI_BYTE8 *name) +{ + vpiHandle callh = vpi_handle(vpiSysTfCall, 0); + vpiHandle argv = vpi_iterate(vpiArgument, callh); + vpiHandle expr_arg = vpi_scan(argv); + (void)name; /* Parameter is not used. */ + + vpi_free_object(argv); + + put_scalar_value(callh, is_onehot(expr_arg, 0)); + + return 0; +} + +static PLI_INT32 onehot0_calltf(ICARUS_VPI_CONST PLI_BYTE8 *name) +{ + vpiHandle callh = vpi_handle(vpiSysTfCall, 0); + vpiHandle argv = vpi_iterate(vpiArgument, callh); + vpiHandle expr_arg = vpi_scan(argv); + (void)name; /* Parameter is not used. */ + + vpi_free_object(argv); + + put_scalar_value(callh, is_onehot(expr_arg, 1)); + + return 0; +} + +/* Check to see if the expression has an undefined value. */ +static PLI_INT32 is_unknown(vpiHandle expr_arg) +{ + s_vpi_value val; + PLI_INT32 size = vpi_get(vpiSize, expr_arg); + assert(size > 0); + + val.format = vpiVectorVal; + vpi_get_value(expr_arg, &val); + + size = (size + 31) / 32; + for (unsigned lp = 0; lp < (unsigned)size; ++lp) { + if (val.value.vector[lp].bval) return vpi1; + } + + return vpi0; +} + +static PLI_INT32 isunknown_calltf(ICARUS_VPI_CONST PLI_BYTE8 *name) +{ + vpiHandle callh = vpi_handle(vpiSysTfCall, 0); + vpiHandle argv = vpi_iterate(vpiArgument, callh); + vpiHandle expr_arg = vpi_scan(argv); + (void)name; /* Parameter is not used. */ + + vpi_free_object(argv); + + put_scalar_value(callh, is_unknown(expr_arg)); + + return 0; +} + +static PLI_INT32 bit_vec_sizetf(ICARUS_VPI_CONST PLI_BYTE8 *name) +{ + (void)name; /* Parameter is not used. */ + + return 1; +} + +/* + * Register the functions with Verilog. + */ +void v2009_bitvec_register(void) +{ + s_vpi_systf_data tf_data; + vpiHandle res; + + tf_data.type = vpiSysFunc; + tf_data.sysfunctype = vpiIntFunc; + tf_data.calltf = countbits_calltf; + tf_data.compiletf = countbits_compiletf; + tf_data.sizetf = 0; + tf_data.tfname = "$countbits"; + tf_data.user_data = 0; + res = vpi_register_systf(&tf_data); + vpip_make_systf_system_defined(res); + + tf_data.type = vpiSysFunc; + tf_data.sysfunctype = vpiIntFunc; + tf_data.calltf = countones_calltf; + tf_data.compiletf = sys_one_numeric_arg_compiletf; + tf_data.sizetf = 0; + tf_data.tfname = "$countones"; + tf_data.user_data = "$countones"; + res = vpi_register_systf(&tf_data); + vpip_make_systf_system_defined(res); + + tf_data.type = vpiSysFunc; + tf_data.sysfunctype = vpiSizedFunc; + tf_data.calltf = onehot_calltf; + tf_data.compiletf = sys_one_numeric_arg_compiletf; + tf_data.sizetf = bit_vec_sizetf; + tf_data.tfname = "$onehot"; + tf_data.user_data = "$onehot"; + res = vpi_register_systf(&tf_data); + vpip_make_systf_system_defined(res); + + tf_data.type = vpiSysFunc; + tf_data.sysfunctype = vpiSizedFunc; + tf_data.calltf = onehot0_calltf; + tf_data.compiletf = sys_one_numeric_arg_compiletf; + tf_data.sizetf = bit_vec_sizetf; + tf_data.tfname = "$onehot0"; + tf_data.user_data = "$onehot0"; + res = vpi_register_systf(&tf_data); + vpip_make_systf_system_defined(res); + + tf_data.type = vpiSysFunc; + tf_data.sysfunctype = vpiSizedFunc; + tf_data.calltf = isunknown_calltf; + tf_data.compiletf = sys_one_numeric_arg_compiletf; + tf_data.sizetf = bit_vec_sizetf; + tf_data.tfname = "$isunknown"; + tf_data.user_data = "$isunknown"; + res = vpi_register_systf(&tf_data); + vpip_make_systf_system_defined(res); +} diff --git a/vpi/v2009_enum.c b/vpi/v2009_enum.c index be9aaa9fa..8c638ff22 100644 --- a/vpi/v2009_enum.c +++ b/vpi/v2009_enum.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010-2014 Stephen Williams (steve@icarus.com) + * Copyright (c) 2010-2018 Stephen Williams (steve@icarus.com) * * This source code is free software; you can redistribute it * and/or modify it in source code form under the terms of the GNU @@ -108,6 +108,7 @@ static PLI_INT32 ivl_enum_method_next_prev_compiletf(ICARUS_VPI_CONST PLI_BYTE8* case vpiConstant: case vpiParameter: if (vpi_get(vpiConstType, arg_count) != vpiStringConst) break; + // fallthrough default: vpi_printf("%s:%d: compiler error: ", vpi_get_str(vpiFile, sys), @@ -226,7 +227,7 @@ static void fill_handle_with_init(vpiHandle arg, int is_two_state) /* * Implement the next()/prev() enumeration methods. */ -static PLI_INT32 ivl_enum_method_next_prev_calltf(PLI_BYTE8*name) +static PLI_INT32 ivl_enum_method_next_prev_calltf(ICARUS_VPI_CONST PLI_BYTE8*name) { vpiHandle sys = vpi_handle(vpiSysTfCall, 0); vpiHandle argv = vpi_iterate(vpiArgument, sys); @@ -431,7 +432,7 @@ static PLI_INT32 ivl_enum_method_name_compiletf(ICARUS_VPI_CONST PLI_BYTE8*name) /* * Implement the name() enumeration method. */ -static PLI_INT32 ivl_enum_method_name_calltf(PLI_BYTE8*name) +static PLI_INT32 ivl_enum_method_name_calltf(ICARUS_VPI_CONST PLI_BYTE8*name) { vpiHandle sys = vpi_handle(vpiSysTfCall, 0); vpiHandle argv = vpi_iterate(vpiArgument, sys); diff --git a/vpi/v2009_table.c b/vpi/v2009_table.c index 4e3328779..1a3f8ee2b 100644 --- a/vpi/v2009_table.c +++ b/vpi/v2009_table.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010-2013 Stephen Williams (steve@icarus.com) + * Copyright (c) 2010-2018 Stephen Williams (steve@icarus.com) * * This source code is free software; you can redistribute it * and/or modify it in source code form under the terms of the GNU @@ -18,11 +18,13 @@ */ extern void v2009_array_register(void); +extern void v2009_bitvec_register(void); extern void v2009_enum_register(void); extern void v2009_string_register(void); void (*vlog_startup_routines[])(void) = { v2009_array_register, + v2009_bitvec_register, v2009_enum_register, v2009_string_register, 0 diff --git a/vpi/vams_simparam.c b/vpi/vams_simparam.c index 6d5e8b30d..2de9818a9 100644 --- a/vpi/vams_simparam.c +++ b/vpi/vams_simparam.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2008-2014 Cary R. (cygcary@yahoo.com) + * Copyright (C) 2008-2018 Cary R. (cygcary@yahoo.com) * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -247,7 +247,7 @@ static PLI_INT32 simparam_str_calltf(ICARUS_VPI_CONST PLI_BYTE8 *name_ext) return 0; } -static PLI_INT32 simparam_str_sizetf(PLI_BYTE8 *name_ext) +static PLI_INT32 simparam_str_sizetf(ICARUS_VPI_CONST PLI_BYTE8 *name_ext) { (void) name_ext; /* Parameter is not used. */ return MAX_STRING_RESULT; /* 128 characters max! */ diff --git a/vpi/wavealloca.h b/vpi/wavealloca.h index 4be2e4937..86276648f 100644 --- a/vpi/wavealloca.h +++ b/vpi/wavealloca.h @@ -1,10 +1,23 @@ /* - * Copyright (c) Tony Bybell 1999. + * Copyright (c) 1999 Tony Bybell. * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. */ #ifndef WAVE_ALLOCA_H diff --git a/vpi_user.h b/vpi_user.h index 8fb8b12d8..db0a9bd5f 100644 --- a/vpi_user.h +++ b/vpi_user.h @@ -1,7 +1,7 @@ #ifndef VPI_USER_H #define VPI_USER_H /* - * Copyright (c) 1999-2014 Stephen Williams (steve@icarus.com) + * Copyright (c) 1999-2018 Stephen Williams (steve@icarus.com) * * This source code is free software; you can redistribute it * and/or modify it in source code form under the terms of the GNU @@ -46,7 +46,9 @@ EXTERN_C_START # include # include "_pli_types.h" +#ifndef ICARUS_VPI_CONST #define ICARUS_VPI_CONST +#endif #ifdef __cplusplus typedef class __vpiHandle *vpiHandle; #else @@ -63,7 +65,7 @@ typedef struct t_vpi_systf_data { const char *tfname; PLI_INT32 (*calltf) (ICARUS_VPI_CONST PLI_BYTE8*); PLI_INT32 (*compiletf)(ICARUS_VPI_CONST PLI_BYTE8*); - PLI_INT32 (*sizetf) (PLI_BYTE8*); + PLI_INT32 (*sizetf) (ICARUS_VPI_CONST PLI_BYTE8*); ICARUS_VPI_CONST PLI_BYTE8 *user_data; } s_vpi_systf_data, *p_vpi_systf_data; @@ -466,7 +468,7 @@ typedef struct t_cb_data { p_vpi_time time; p_vpi_value value; PLI_INT32 index; - char *user_data; + ICARUS_VPI_CONST PLI_BYTE8 *user_data; } s_cb_data, *p_cb_data; #define cbValueChange 1 diff --git a/vvp/Makefile.in b/vvp/Makefile.in index 1e19c14e8..998e38969 100644 --- a/vvp/Makefile.in +++ b/vvp/Makefile.in @@ -56,7 +56,7 @@ else INCLUDE_PATH = -I. -I.. -I$(srcdir) -I$(srcdir)/.. endif -CPPFLAGS = $(INCLUDE_PATH) @CPPFLAGS@ @DEFS@ +CPPFLAGS = $(INCLUDE_PATH) @CPPFLAGS@ @DEFS@ -DICARUS_VPI_CONST=const CFLAGS = @WARNING_FLAGS@ @WARNING_FLAGS_CC@ @CFLAGS@ CXXFLAGS = @WARNING_FLAGS@ @WARNING_FLAGS_CXX@ @CXXFLAGS@ LDFLAGS = @rdynamic@ @LDFLAGS@ diff --git a/vvp/README.txt b/vvp/README.txt index a6bfe2c01..dea23ae1a 100644 --- a/vvp/README.txt +++ b/vvp/README.txt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001-2015 Stephen Williams (steve@icarus.com) + * Copyright (c) 2001-2017 Stephen Williams (steve@icarus.com) * */ @@ -684,6 +684,8 @@ similar: