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/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 f47d03f5f..3ba1503db 100644 --- a/README.txt +++ b/README.txt @@ -77,10 +77,16 @@ the configure scripts. Unpack the tar-ball and cd into the verilog-######### directory (presumably that is how you got to this README) and compile the source 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 eae1ec460..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 @@ -120,6 +120,10 @@ 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..56ba6d201 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 @@ -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 03054ef8f..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 [-EiSvV] [-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,9 @@ 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; @@ -344,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) @@ -410,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); @@ -421,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); @@ -450,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); @@ -501,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"); @@ -517,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"); @@ -561,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) { @@ -990,7 +1028,7 @@ int main(int argc, char **argv) } } - while ((opt = getopt(argc, argv, "B:c:D:d:Ef:g:hl:I:iM: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': @@ -1046,8 +1084,8 @@ int main(int argc, char **argv) break; case 'i': - ignore_missing_modules = 1; - break; + ignore_missing_modules = 1; + break; case 'l': process_file_name(optarg, 1); @@ -1093,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; @@ -1135,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); } @@ -1288,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 b15d1aecf..8722039c1 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-2017 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; } @@ -2264,8 +2278,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; } @@ -3141,6 +3155,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 +3481,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 +5371,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 +5623,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: " diff --git a/elab_scope.cc b/elab_scope.cc index 9796ce7fc..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) @@ -1758,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); 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 82b90fc7d..ffd9b2d34 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 @@ -2355,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 @@ -2918,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; @@ -4202,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); @@ -4212,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; @@ -4478,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); @@ -4498,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 */); @@ -5368,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()); @@ -5415,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. */ @@ -5695,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; } @@ -6127,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) { @@ -6142,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" @@ -6150,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, @@ -6159,37 +6187,158 @@ 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) +/* + * Check to see if the always_* processes only contain synthesizable + * constructs. + */ +bool Design::check_proc_synth() const { - 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; + 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()); } + } + return result; +} - cur->second->elaborate(this, cur->first); +/* + * 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; + } } /* @@ -6211,8 +6360,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; @@ -6220,23 +6374,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); @@ -6267,9 +6434,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 @@ -6339,6 +6510,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; @@ -6367,8 +6542,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; @@ -6430,8 +6603,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; @@ -6446,10 +6617,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: " @@ -6457,5 +6629,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..7536bd56b 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-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 @@ -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; diff --git a/expr_synth.cc b/expr_synth.cc index cb8ba87f0..5c28e1adb 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-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 @@ -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)); @@ -1347,6 +1358,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/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/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 e814b7466..975e5abf9 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; @@ -179,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. */ @@ -777,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) @@ -863,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; @@ -921,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" @@ -936,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) { @@ -1035,8 +1085,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); @@ -1050,22 +1102,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 ) { @@ -1183,12 +1229,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/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_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 f3f5a4518..b9873786e 100644 --- a/net_scope.cc +++ b/net_scope.cc @@ -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); @@ -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..803316a2a 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..4ef652339 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; @@ -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_; @@ -4624,7 +4678,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 +4710,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 +4765,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 +4841,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 +4889,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 +4911,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 +4967,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 +4979,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 +4992,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 +5007,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 +5021,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 882509da8..c55dac843 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 @@ -683,7 +678,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 '+' '-' @@ -692,7 +687,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 @@ -700,12 +695,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 @@ -1137,11 +1142,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. */ @@ -1726,17 +1727,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; } @@ -2044,7 +2046,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 @@ -2128,10 +2133,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 @@ -2143,7 +2154,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 @@ -2190,8 +2200,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(); @@ -2217,30 +2234,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 */ @@ -3275,6 +3296,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); @@ -3295,6 +3321,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); @@ -4406,47 +4437,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. */ @@ -4459,11 +4449,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; @@ -4500,8 +4487,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 @@ -4879,6 +4864,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); @@ -4893,6 +4890,8 @@ module_item | attribute_list_opt assertion_item + | timeunits_declaration + | class_declaration | task_declaration @@ -5016,14 +5015,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 @@ -6434,7 +6425,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 b9e36042e..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 @@ -63,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 { @@ -357,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); @@ -406,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) @@ -413,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) @@ -430,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: " @@ -449,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, @@ -458,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 " @@ -492,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; @@ -510,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()) != @@ -530,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 " @@ -539,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; @@ -567,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()) != @@ -588,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 " @@ -597,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; @@ -705,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); @@ -736,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; @@ -751,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; @@ -799,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; } @@ -813,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; @@ -970,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) @@ -1147,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."); } } @@ -1315,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 @@ -1332,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 @@ -1390,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; @@ -1418,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, @@ -2768,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; @@ -2795,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; } } @@ -3080,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()) { @@ -3099,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; } @@ -3118,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; } @@ -3155,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()) { @@ -3170,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; } @@ -3188,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; } @@ -3456,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); @@ -3472,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); } } @@ -3488,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); @@ -3502,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); @@ -3545,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); } } @@ -3569,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)) { @@ -3594,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)) { @@ -3602,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."); @@ -3643,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 @@ -3662,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; } @@ -3715,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 8666386eb..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 @@ -567,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 de03de673..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; @@ -844,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 { @@ -1176,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; @@ -1706,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_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/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..a32950437 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-2017 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: @@ -1543,6 +1544,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 +2137,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 +2815,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..29e874154 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-2017 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; 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-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..b47f6f4d4 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-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 @@ -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; @@ -465,6 +469,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; + case 'E': case 'e': case 'N': diff --git a/tgt-vlog95/logic_lpm.c b/tgt-vlog95/logic_lpm.c index 3754c82c9..024325090 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-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 @@ -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: 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..4c3194d98 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-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 @@ -1521,6 +1521,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 +2153,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 +2304,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/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/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.h b/vpi/fstapi.h index df86ef079..e66c20467 100644 --- a/vpi/fstapi.h +++ b/vpi/fstapi.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2009-2015 Tony Bybell. + * Copyright (c) 2009-2017 Tony Bybell. * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), @@ -168,7 +168,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 { diff --git a/vpi/lz4.c b/vpi/lz4.c index 08cf6b5cd..c050cf1e0 100644 --- a/vpi/lz4.c +++ b/vpi/lz4.c @@ -825,7 +825,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_display.c b/vpi/sys_display.c index dc04182fd..5ecc8c5b4 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-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 @@ -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_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_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/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/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: