diff --git a/PExpr.h b/PExpr.h index 03c9e3284..257f3e977 100644 --- a/PExpr.h +++ b/PExpr.h @@ -328,6 +328,8 @@ class PEIdent : public PExpr { // elaborate/calculate, or false if there is some sort of // source error. + bool calculate_bits_(Design*, NetScope*, long&msb, bool&defined) const; + // The calculate_parts_ method calculates the range // expressions of a part select for the current object. The // part select expressions are elaborated and evaluated, and diff --git a/compiler.h b/compiler.h index 68dafe5d9..976cbc831 100644 --- a/compiler.h +++ b/compiler.h @@ -92,6 +92,9 @@ extern bool warn_inf_loop; extern bool warn_sens_entire_vec; extern bool warn_sens_entire_arr; +/* Warn about level-appropriate anochronisms. */ +extern bool warn_anachronisms; + /* This is true if verbose output is requested. */ extern bool verbose_flag; diff --git a/driver/main.c b/driver/main.c index 0409166d3..923dbc5fd 100644 --- a/driver/main.c +++ b/driver/main.c @@ -136,7 +136,7 @@ int gen_std_include = 1; of the include list. */ int gen_relative_include = 0; -char warning_flags[16] = ""; +char warning_flags[16] = "n"; unsigned integer_width = 32; @@ -491,11 +491,15 @@ static int t_compile() static void process_warning_switch(const char*name) { if (strcmp(name,"all") == 0) { + process_warning_switch("anachronisms"); process_warning_switch("implicit"); process_warning_switch("portbind"); process_warning_switch("select-range"); process_warning_switch("timescale"); process_warning_switch("sensitivity-entire-array"); + } else if (strcmp(name,"anachronisms") == 0) { + if (! strchr(warning_flags, 'n')) + strcat(warning_flags, "n"); } else if (strcmp(name,"implicit") == 0) { if (! strchr(warning_flags, 'i')) strcat(warning_flags, "i"); @@ -519,6 +523,12 @@ static void process_warning_switch(const char*name) } else if (strcmp(name,"sensitivity-entire-array") == 0) { if (! strchr(warning_flags, 'a')) strcat(warning_flags, "a"); + } else if (strcmp(name,"no-anachronisms") == 0) { + char*cp = strchr(warning_flags, 'n'); + if (cp) while (*cp) { + cp[0] = cp[1]; + cp += 1; + } } else if (strcmp(name,"no-implicit") == 0) { char*cp = strchr(warning_flags, 'i'); if (cp) while (*cp) { diff --git a/elab_expr.cc b/elab_expr.cc index 992fc5d0e..2e51f4f3d 100644 --- a/elab_expr.cc +++ b/elab_expr.cc @@ -1879,6 +1879,43 @@ bool PEIdent::calculate_packed_indices_(Design*des, NetScope*scope, NetNet*net, return evaluate_index_prefix(des, scope, prefix_indices, index); } + +bool PEIdent::calculate_bits_(Design*des, NetScope*scope, + long&msb, bool&defined) const +{ + defined = true; + const name_component_t&name_tail = path_.back(); + ivl_assert(*this, !name_tail.index.empty()); + + const index_component_t&index_tail = name_tail.index.back(); + ivl_assert(*this, index_tail.sel == index_component_t::SEL_BIT); + ivl_assert(*this, index_tail.msb && !index_tail.lsb); + + /* This handles bit selects. In this case, there in one + bit select expressions which must be constant. */ + + NetExpr*msb_ex = elab_and_eval(des, scope, index_tail.msb, -1, true); + NetEConst*msb_c = dynamic_cast(msb_ex); + if (msb_c == 0) { + cerr << index_tail.msb->get_fileline() << ": error: " + "Bit select expressionsmust be constant." + << endl; + cerr << index_tail.msb->get_fileline() << ": : " + "This msb expression violates the rule: " + << *index_tail.msb << endl; + des->errors += 1; + /* Attempt to recover from error. */ + msb = 0; + } else { + if (! msb_c->value().is_defined()) + defined = false; + msb = msb_c->value().as_long(); + } + + delete msb_ex; + return true; +} + /* * Given that the msb_ and lsb_ are part select expressions, this * function calculates their values. Note that this method does *not* diff --git a/elab_net.cc b/elab_net.cc index a39ccfe74..db70c4069 100644 --- a/elab_net.cc +++ b/elab_net.cc @@ -360,24 +360,14 @@ bool PEIdent::eval_part_select_(Design*des, NetScope*scope, NetNet*sig, case index_component_t::SEL_BIT: if (name_tail.index.size() > sig->array_dimensions()) { - verinum*mval = index_tail.msb->eval_const(des, scope); - if (mval == 0) { - cerr << get_fileline() << ": error: Index of " << path_ << - " needs to be constant in this context." << - endl; - cerr << get_fileline() << ": : Index expression is: " - << *index_tail.msb << endl; - cerr << get_fileline() << ": : Context scope is: " - << scope_path(scope) << endl; - des->errors += 1; - return false; - } - assert(mval); - - midx = sig->sb_to_idx(prefix_indices, mval->as_long()); + long msb; + bool bit_defined_flag; + /* bool flag = */ calculate_bits_(des, scope, msb, bit_defined_flag); + ivl_assert(*this, bit_defined_flag); + midx = sig->sb_to_idx(prefix_indices, msb); if (midx >= (long)sig->vector_width()) { cerr << get_fileline() << ": error: Index " << sig->name() - << "[" << mval->as_long() << "] is out of range." + << "[" << msb << "] is out of range." << endl; des->errors += 1; midx = 0; @@ -453,7 +443,7 @@ NetNet* PEIdent::elaborate_lnet_common_(Design*des, NetScope*scope, wire. */ if (gn_var_can_be_uwire() && (sig->type() == NetNet::REG) - && (sig->peek_eref() == 0) ) { + && (sig->peek_lref() == 0) ) { sig->type(NetNet::UNRESOLVED_WIRE); } diff --git a/elab_scope.cc b/elab_scope.cc index 02d46659f..5d8af02dc 100644 --- a/elab_scope.cc +++ b/elab_scope.cc @@ -961,6 +961,12 @@ bool PGenerate::generate_scope_case_(Design*des, NetScope*container) return true; } + if (debug_scopes) { + cerr << get_fileline() << ": PGenerate::generate_scope_case_: " + << "Generate subscope " << use_name + << " and elaborate." << endl; + } + NetScope*scope = new NetScope(container, use_name, NetScope::GENBLOCK); scope->set_line(get_file(), get_lineno()); @@ -1030,7 +1036,13 @@ void PGenerate::elaborate_subscope_direct_(Design*des, NetScope*scope) typedef list::const_iterator generate_it_t; for (generate_it_t cur = generate_schemes.begin() ; cur != generate_schemes.end() ; ++ cur ) { - (*cur) -> generate_scope(des, scope); + PGenerate*curp = *cur; + if (debug_scopes) { + cerr << get_fileline() << ": elaborate_subscope_direct_: " + << "Elaborate direct subscope " << curp->scope_name + << " within scope " << scope_name << endl; + } + curp -> generate_scope(des, scope); } } @@ -1082,7 +1094,7 @@ void PGenerate::elaborate_subscope_(Design*des, NetScope*scope) if (debug_scopes) cerr << get_fileline() << ": debug: Generated scope " << scope_path(scope) - << " by generate block " << scope_name << endl; + << " for generate block " << scope_name << endl; // Save the scope that we created, for future use. scope_list_.push_back(scope); diff --git a/elab_sig.cc b/elab_sig.cc index ca7a1ac73..f5ba9d4ca 100644 --- a/elab_sig.cc +++ b/elab_sig.cc @@ -387,9 +387,20 @@ bool PGenerate::elaborate_sig_direct_(Design*des, NetScope*container) const for (generate_it_t cur = generate_schemes.begin() ; cur != generate_schemes.end() ; ++ cur ) { PGenerate*item = *cur; - if (item->direct_nested_ || !item->scope_list_.empty()) { - // Found the item, and it is direct nested. - flag &= item->elaborate_sig(des, container); + if (item->scheme_type == PGenerate::GS_CASE) { + typedef list::const_iterator generate_it_t; + for (generate_it_t icur = item->generate_schemes.begin() + ; icur != item->generate_schemes.end() ; ++ icur ) { + PGenerate*case_item = *icur; + if (case_item->direct_nested_ || !case_item->scope_list_.empty()) { + flag &= case_item->elaborate_sig(des, container); + } + } + } else { + if (item->direct_nested_ || !item->scope_list_.empty()) { + // Found the item, and it is direct nested. + flag &= item->elaborate_sig(des, container); + } } } return flag; diff --git a/elaborate.cc b/elaborate.cc index cd3ef2d73..77a82f745 100644 --- a/elaborate.cc +++ b/elaborate.cc @@ -4539,15 +4539,18 @@ bool PGenerate::elaborate(Design*des, NetScope*container) const bool flag = true; + if (debug_elaborate) { + cerr << get_fileline() << ": PGenerate::elaborate: " + "generate " << scheme_type + << " elaborating in scope " << scope_path(container) + << "." << endl; + } + // Handle the special case that this is a CASE scheme. In this // case the PGenerate itself does not have the generated // item. Look instead for the case ITEM that has a scope // generated for it. if (scheme_type == PGenerate::GS_CASE) { - if (debug_elaborate) - cerr << get_fileline() << ": debug: generate case" - << " elaborating in scope " - << scope_path(container) << "." << endl; typedef list::const_iterator generate_it_t; for (generate_it_t cur = generate_schemes.begin() @@ -4593,23 +4596,50 @@ bool PGenerate::elaborate(Design*des, NetScope*container) const bool PGenerate::elaborate_direct_(Design*des, NetScope*container) const { - if (debug_elaborate) + bool flag = true; + + if (debug_elaborate) { cerr << get_fileline() << ": debug: " << "Direct nesting elaborate in scope " - << scope_path(container) << "." << endl; + << scope_path(container) + << ", scheme_type=" << scheme_type << endl; + } // Elaborate for a direct nested generated scheme knows // that there are only sub_schemes to be elaborated. There // should be exactly 1 active generate scheme, search for it // using this loop. - bool flag = true; typedef list::const_iterator generate_it_t; for (generate_it_t cur = generate_schemes.begin() ; cur != generate_schemes.end() ; ++ cur ) { PGenerate*item = *cur; - if (item->direct_nested_ || !item->scope_list_.empty()) { - // Found the item, and it is direct nested. - flag &= item->elaborate(des, container); + if (debug_elaborate) { + cerr << get_fileline() << ": PGenerate::elaborate_direct_: " + << "item->scope_name=" << item->scope_name + << ", item->scheme_type=" << item->scheme_type + << ", item->direct_nested_=" << item->direct_nested_ + << ", item->scope_list_.size()=" << item->scope_list_.size() + << "." << endl; + } + + // Special case: If this is a case generate scheme, then + // the PGenerate object (item) does not acctually + // contain anything. Instead scan the case items, which + // are listed as sub-schemes of the item. + if (item->scheme_type == PGenerate::GS_CASE) { + typedef list::const_iterator generate_it_t; + for (generate_it_t icur = item->generate_schemes.begin() + ; icur != item->generate_schemes.end() ; ++ icur ) { + PGenerate*case_item = *icur; + if (case_item->direct_nested_ || !case_item->scope_list_.empty()) { + flag &= case_item->elaborate(des, container); + } + } + } else { + if (item->direct_nested_ || !item->scope_list_.empty()) { + // Found the item, and it is direct nested. + flag &= item->elaborate(des, container); + } } } return flag; diff --git a/main.cc b/main.cc index bac6e326c..2b8066576 100644 --- a/main.cc +++ b/main.cc @@ -158,6 +158,7 @@ bool warn_inf_loop = false; bool warn_ob_select = false; bool warn_sens_entire_vec = false; bool warn_sens_entire_arr = false; +bool warn_anachronisms = false; /* * Debug message class flags. @@ -667,6 +668,9 @@ static void read_iconfig_file(const char*ipath) case 'a': warn_sens_entire_arr = true; break; + case 'n': + warn_anachronisms = true; + break; default: break; } diff --git a/netmisc.cc b/netmisc.cc index 504b58dcb..d6b5e6b98 100644 --- a/netmisc.cc +++ b/netmisc.cc @@ -602,7 +602,11 @@ NetExpr* elab_sys_task_arg(Design*des, NetScope*scope, perm_string name, eval_expr(tmp, -1); if (NetEConst*ce = dynamic_cast(tmp)) { - if (mode != PExpr::SIZED) + // For lossless/unsized constant expressions, we can now + // determine the exact width required to hold the result. + // But leave literal numbers exactly as the user supplied + // them. + if ((mode != PExpr::SIZED) && !dynamic_cast(pe)) ce->trim(); } diff --git a/parse.y b/parse.y index cce1cffca..5d67e237b 100644 --- a/parse.y +++ b/parse.y @@ -66,6 +66,11 @@ static stack current_block_stack; * simulation issues. */ static unsigned args_after_notifier; +/* The rules sometimes push attributes into a global context where + sub-rules may grab them. This makes parser rules a little easier to + write in some cases. */ +static list*attributes_in_context = 0; + /* Later version of bison (including 1.35) will not compile in stack extension if the output is compiled with C++ and either the YYSTYPE or YYLTYPE are provided by the source code. However, I can get the @@ -574,7 +579,8 @@ static void current_function_set_statement(const YYLTYPE&loc, vector %type event_expression_list %type event_expression %type event_control -%type statement statement_or_null compressed_statement +%type statement statement_item statement_or_null +%type compressed_statement %type loop_statement for_step jump_statement %type statement_or_null_list statement_or_null_list_opt @@ -749,7 +755,7 @@ class_item /* IEEE1800-2005: A.1.8 */ cause a conflict. */ | method_qualifier_opt K_function K_new '(' tf_port_list_opt ')' ';' function_item_list_opt - implicit_class_handle '.' K_new '(' expression_list_with_nuls ')' + attribute_list_opt implicit_class_handle '.' K_new '(' expression_list_with_nuls ')' statement_or_null_list_opt K_endfunction endnew_opt { yyerror(@3, "sorry: Class constructors not supported yet."); @@ -1316,13 +1322,20 @@ signing /* IEEE1800-2005: A.2.2.1 */ | K_unsigned { $$ = false; } ; +statement /* IEEE1800-2005: A.6.4 */ + : attribute_list_opt statement_item + { pform_bind_attributes($2->attributes, $1); + $$ = $2; + } + ; + /* Many places where statements are allowed can actually take a statement or a null statement marked with a naked semi-colon. */ statement_or_null /* IEEE1800-2005: A.6.4 */ : statement { $$ = $1; } - | ';' + | attribute_list_opt ';' { $$ = 0; } ; @@ -1797,35 +1810,31 @@ block_item_decl all the trappings of a general variable declaration. All of that is implicit in the "integer" of the declaration. */ - : attribute_list_opt K_integer signed_unsigned_opt register_variable_list ';' - { pform_set_reg_integer($4); - if ($1) delete $1; - } + : K_integer signed_unsigned_opt register_variable_list ';' + { pform_set_reg_integer($3, attributes_in_context); + } - | attribute_list_opt K_time register_variable_list ';' - { pform_set_reg_time($3); - if ($1) delete $1; - } + | K_time register_variable_list ';' + { pform_set_reg_time($2, attributes_in_context); + } /* variable declarations. Note that data_type can be 0 if we are recovering from an error. */ - | attribute_list_opt data_type register_variable_list ';' - { if ($2) pform_set_data_type(@2, $2, $3); - if ($1) delete $1; + | data_type register_variable_list ';' + { if ($1) pform_set_data_type(@1, $1, $2, attributes_in_context); } - | attribute_list_opt K_reg data_type register_variable_list ';' - { if ($3) pform_set_data_type(@3, $3, $4); - if ($1) delete $1; + | K_reg data_type register_variable_list ';' + { if ($2) pform_set_data_type(@2, $2, $3, attributes_in_context); } - | K_event list_of_identifiers ';' - { pform_make_events($2, @1.text, @1.first_line); - } + | K_event list_of_identifiers ';' + { pform_make_events($2, @1.text, @1.first_line); + } - | K_parameter parameter_assign_decl ';' - | K_localparam localparam_assign_decl ';' + | K_parameter parameter_assign_decl ';' + | K_localparam localparam_assign_decl ';' /* Blocks can have type declarations. */ @@ -1833,15 +1842,16 @@ block_item_decl /* Recover from errors that happen within variable lists. Use the trailing semi-colon to resync the parser. */ - | attribute_list_opt K_integer error ';' - { yyerror(@2, "error: syntax error in integer variable list."); - yyerrok; - if ($1) delete $1; - } - | attribute_list_opt K_time error ';' - { yyerror(@2, "error: syntax error in time variable list."); - yyerrok; - } + + | K_integer error ';' + { yyerror(@1, "error: syntax error in integer variable list."); + yyerrok; + } + + | K_time error ';' + { yyerror(@1, "error: syntax error in time variable list."); + yyerrok; + } | K_parameter error ';' { yyerror(@1, "error: syntax error in parameter list."); @@ -4095,12 +4105,15 @@ module_item will see the discipline name as an identifier. We match it to the discipline or type name semantically. */ | DISCIPLINE_IDENTIFIER list_of_identifiers ';' - { pform_attach_discipline(@1, $1, $2); } + { pform_attach_discipline(@1, $1, $2); } /* block_item_decl rule is shared with task blocks and named - begin/end. */ + begin/end. Careful to pass attributes to the block_item_decl. */ - | block_item_decl + | attribute_list_opt { attributes_in_context = $1; } block_item_decl + { delete attributes_in_context; + attributes_in_context = 0; + } /* */ @@ -4199,15 +4212,15 @@ module_item /* Always and initial items are behavioral processes. */ - | attribute_list_opt K_always statement + | attribute_list_opt K_always statement_item { PProcess*tmp = pform_make_behavior(IVL_PR_ALWAYS, $3, $1); FILE_NAME(tmp, @2); } - | attribute_list_opt K_initial statement + | attribute_list_opt K_initial statement_item { PProcess*tmp = pform_make_behavior(IVL_PR_INITIAL, $3, $1); FILE_NAME(tmp, @2); } - | attribute_list_opt K_final statement + | attribute_list_opt K_final statement_item { PProcess*tmp = pform_make_behavior(IVL_PR_FINAL, $3, $1); FILE_NAME(tmp, @2); } @@ -4267,7 +4280,7 @@ module_item /* Handle some anachronistic syntax cases. */ | K_generate K_begin module_item_list_opt K_end K_endgenerate { /* Detect and warn about anachronistic begin/end use */ - if (generation_flag > GN_VER2001) { + if (generation_flag > GN_VER2001 && warn_anachronisms) { warn_count += 1; cerr << @2 << ": warning: Anachronistic use of begin/end to surround generate schemes." << endl; } @@ -4276,7 +4289,7 @@ module_item pform_start_generate_nblock(@2, $4); } module_item_list_opt K_end K_endgenerate { /* Detect and warn about anachronistic named begin/end use */ - if (generation_flag > GN_VER2001) { + if (generation_flag > GN_VER2001 && warn_anachronisms) { warn_count += 1; cerr << @2 << ": warning: Anachronistic use of named begin/end to surround generate schemes." << endl; } @@ -5445,7 +5458,7 @@ spec_notifier ; -statement /* This is roughly statement_item in the LRM */ +statement_item /* This is roughly statement_item in the LRM */ /* assign and deassign statements are procedural code to do structural assignments, and to turn that structural assignment @@ -5513,8 +5526,6 @@ statement /* This is roughly statement_item in the LRM */ delete $6; $$ = tmp; } - | K_begin error K_end - { yyerrok; } /* fork-join blocks are very similar to begin-end blocks. In fact, from the parser's perspective there is no real difference. All we @@ -5549,8 +5560,6 @@ statement /* This is roughly statement_item in the LRM */ delete $6; $$ = tmp; } - | K_fork error K_join - { yyerrok; } | K_disable hierarchy_identifier ';' { PDisable*tmp = new PDisable(*$2); @@ -5630,29 +5639,26 @@ statement /* This is roughly statement_item in the LRM */ $$ = tmp; } - | event_control attribute_list_opt statement_or_null + | event_control statement_or_null { PEventStatement*tmp = $1; if (tmp == 0) { yyerror(@1, "error: Invalid event control."); $$ = 0; } else { - if ($3) pform_bind_attributes($3->attributes,$2); - tmp->set_statement($3); + tmp->set_statement($2); $$ = tmp; } } - | '@' '*' attribute_list_opt statement_or_null + | '@' '*' statement_or_null { PEventStatement*tmp = new PEventStatement; FILE_NAME(tmp, @1); - if ($4) pform_bind_attributes($4->attributes,$3); - tmp->set_statement($4); + tmp->set_statement($3); $$ = tmp; } - | '@' '(' '*' ')' attribute_list_opt statement_or_null + | '@' '(' '*' ')' statement_or_null { PEventStatement*tmp = new PEventStatement; FILE_NAME(tmp, @1); - if ($6) pform_bind_attributes($6->attributes,$5); - tmp->set_statement($6); + tmp->set_statement($5); $$ = tmp; } diff --git a/pform.cc b/pform.cc index 7fb93e9c2..ac8cb2a9b 100644 --- a/pform.cc +++ b/pform.cc @@ -1521,7 +1521,8 @@ static void pform_set_net_range(perm_string name, const list*range, bool signed_flag, ivl_variable_type_t dt, - PWSRType rt) + PWSRType rt, + std::list*attr) { PWire*cur = pform_get_wire_in_scope(name); if (cur == 0) { @@ -1541,17 +1542,20 @@ static void pform_set_net_range(perm_string name, if (dt != IVL_VT_NO_TYPE) cur->set_data_type(dt); + + pform_bind_attributes(cur->attributes, attr, true); } void pform_set_net_range(list*names, list*range, bool signed_flag, - ivl_variable_type_t dt) + ivl_variable_type_t dt, + std::list*attr) { for (list::iterator cur = names->begin() ; cur != names->end() ; ++ cur ) { perm_string txt = *cur; - pform_set_net_range(txt, range, signed_flag, dt, SR_NET); + pform_set_net_range(txt, range, signed_flag, dt, SR_NET, attr); } delete names; @@ -2036,7 +2040,7 @@ void pform_makewire(const vlltype&li, pform_makewire(li, txt, type, pt, dt, attr); /* This has already been done for real variables. */ if (dt != IVL_VT_REAL) { - pform_set_net_range(txt, range, signed_flag, dt, rt); + pform_set_net_range(txt, range, signed_flag, dt, rt, 0); } } @@ -2066,7 +2070,7 @@ void pform_makewire(const vlltype&li, /* This has already been done for real variables. */ if (dt != IVL_VT_REAL) { pform_set_net_range(first->name, range, signed_flag, dt, - SR_NET); + SR_NET, 0); } PWire*cur = pform_get_wire_in_scope(first->name); @@ -2534,14 +2538,14 @@ void pform_set_port_type(const struct vlltype&li, perm_string txt = *cur; pform_set_port_type(txt, pt, li.text, li.first_line); pform_set_net_range(txt, range, signed_flag, IVL_VT_NO_TYPE, - SR_PORT); + SR_PORT, 0); } delete names; delete range; } -static void pform_set_reg_integer(perm_string name) +static void pform_set_reg_integer(perm_string name, list*attr) { PWire*cur = pform_get_make_wire_in_scope(name, NetNet::INTEGER, NetNet::NOT_A_PORT, IVL_VT_LOGIC); assert(cur); @@ -2553,19 +2557,21 @@ static void pform_set_reg_integer(perm_string name) rlist.push_back(rng); cur->set_range(rlist, SR_NET); cur->set_signed(true); + + pform_bind_attributes(cur->attributes, attr, true); } -void pform_set_reg_integer(list*names) +void pform_set_reg_integer(list*names, list*attr) { for (list::iterator cur = names->begin() ; cur != names->end() ; ++ cur ) { perm_string txt = *cur; - pform_set_reg_integer(txt); + pform_set_reg_integer(txt, attr); } delete names; } -static void pform_set_reg_time(perm_string name) +static void pform_set_reg_time(perm_string name, list*attr) { PWire*cur = pform_get_make_wire_in_scope(name, NetNet::REG, NetNet::NOT_A_PORT, IVL_VT_LOGIC); assert(cur); @@ -2576,19 +2582,21 @@ static void pform_set_reg_time(perm_string name) listrlist; rlist.push_back(rng); cur->set_range(rlist, SR_NET); + + pform_bind_attributes(cur->attributes, attr, true); } -void pform_set_reg_time(list*names) +void pform_set_reg_time(list*names, list*attr) { for (list::iterator cur = names->begin() ; cur != names->end() ; ++ cur ) { perm_string txt = *cur; - pform_set_reg_time(txt); + pform_set_reg_time(txt, attr); } delete names; } -static void pform_set_integer_2atom(uint64_t width, bool signed_flag, perm_string name) +static void pform_set_integer_2atom(uint64_t width, bool signed_flag, perm_string name, list*attr) { PWire*cur = pform_get_make_wire_in_scope(name, NetNet::REG, NetNet::NOT_A_PORT, IVL_VT_BOOL); assert(cur); @@ -2601,14 +2609,15 @@ static void pform_set_integer_2atom(uint64_t width, bool signed_flag, perm_strin listrlist; rlist.push_back(rng); cur->set_range(rlist, SR_NET); + pform_bind_attributes(cur->attributes, attr, true); } -void pform_set_integer_2atom(uint64_t width, bool signed_flag, list*names) +static void pform_set_integer_2atom(uint64_t width, bool signed_flag, list*names, list*attr) { for (list::iterator cur = names->begin() ; cur != names->end() ; ++ cur ) { perm_string txt = *cur; - pform_set_integer_2atom(width, signed_flag, txt); + pform_set_integer_2atom(width, signed_flag, txt, attr); } delete names; } @@ -2617,32 +2626,32 @@ void pform_set_integer_2atom(uint64_t width, bool signed_flag, list * This function detects the derived class for the given type and * dispatches the type to the proper subtype function. */ -void pform_set_data_type(const struct vlltype&li, data_type_t*data_type, list*names) +void pform_set_data_type(const struct vlltype&li, data_type_t*data_type, list*names, list*attr) { if (atom2_type_t*atom2_type = dynamic_cast (data_type)) { - pform_set_integer_2atom(atom2_type->type_code, atom2_type->signed_flag, names); + pform_set_integer_2atom(atom2_type->type_code, atom2_type->signed_flag, names, attr); return; } if (struct_type_t*struct_type = dynamic_cast (data_type)) { - pform_set_struct_type(struct_type, names); + pform_set_struct_type(struct_type, names, attr); return; } if (enum_type_t*enum_type = dynamic_cast (data_type)) { - pform_set_enum(li, enum_type, names); + pform_set_enum(li, enum_type, names, attr); return; } if (vector_type_t*vec_type = dynamic_cast (data_type)) { pform_set_net_range(names, vec_type->pdims.get(), vec_type->signed_flag, - vec_type->base_type); + vec_type->base_type, attr); return; } if (/*real_type_t*real_type =*/ dynamic_cast (data_type)) { - pform_set_net_range(names, 0, true, IVL_VT_REAL); + pform_set_net_range(names, 0, true, IVL_VT_REAL, attr); return; } @@ -2655,7 +2664,7 @@ void pform_set_data_type(const struct vlltype&li, data_type_t*data_type, list*attr) { (void) li; // The line information is not currently needed. PWire*cur = pform_get_make_wire_in_scope(name, NetNet::REG, NetNet::NOT_A_PORT, enum_type->base_type); @@ -2667,9 +2676,10 @@ static void pform_set_enum(const struct vlltype&li, enum_type_t*enum_type, assert(enum_type->range->size() == 1); cur->set_range(*enum_type->range, SR_NET); cur->set_enumeration(enum_type); + pform_bind_attributes(cur->attributes, attr, true); } -void pform_set_enum(const struct vlltype&li, enum_type_t*enum_type, list*names) +void pform_set_enum(const struct vlltype&li, enum_type_t*enum_type, list*names, std::list*attr) { // By definition, the base type can only be IVL_VT_LOGIC or // IVL_VT_BOOL. @@ -2689,7 +2699,7 @@ void pform_set_enum(const struct vlltype&li, enum_type_t*enum_type, list::iterator cur = names->begin() ; cur != names->end() ; ++ cur) { perm_string txt = *cur; - pform_set_enum(li, enum_type, txt); + pform_set_enum(li, enum_type, txt, attr); } delete names; diff --git a/pform.h b/pform.h index be4d744d8..c907c6b95 100644 --- a/pform.h +++ b/pform.h @@ -292,18 +292,19 @@ extern void pform_set_port_type(const struct vlltype&li, extern void pform_set_net_range(list*names, list*, bool signed_flag, - ivl_variable_type_t); + ivl_variable_type_t, + std::list*attr); extern void pform_set_reg_idx(perm_string name, PExpr*l, PExpr*r); -extern void pform_set_reg_integer(list*names); -extern void pform_set_reg_time(list*names); +extern void pform_set_reg_integer(list*names, list*attr); +extern void pform_set_reg_time(list*names, list*attr); -extern void pform_set_integer_2atom(uint64_t width, bool signed_flag, list*names); +//XXXXextern void pform_set_integer_2atom(uint64_t width, bool signed_flag, list*names); -extern void pform_set_data_type(const struct vlltype&li, data_type_t*, list*names); +extern void pform_set_data_type(const struct vlltype&li, data_type_t*, list*names, list*attr); -extern void pform_set_enum(const struct vlltype&li, enum_type_t*enum_type, list*names); +extern void pform_set_enum(const struct vlltype&li, enum_type_t*enum_type, list*names, std::list*attr); -extern void pform_set_struct_type(struct_type_t*struct_type, list*names); +extern void pform_set_struct_type(struct_type_t*struct_type, std::list*names, std::list*attr); /* pform_set_attrib and pform_set_type_attrib exist to support the $attribute syntax, which can only set string values to diff --git a/pform_struct_type.cc b/pform_struct_type.cc index 1fe44bbe8..16ef1debd 100644 --- a/pform_struct_type.cc +++ b/pform_struct_type.cc @@ -48,18 +48,19 @@ static ivl_variable_type_t figure_struct_base_type(struct_type_t*struct_type) * 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) +static void pform_set_packed_struct(struct_type_t*struct_type, perm_string name, list*attr) { ivl_variable_type_t base_type = figure_struct_base_type(struct_type); PWire*net = pform_get_make_wire_in_scope(name, NetNet::REG, NetNet::NOT_A_PORT, base_type); net->set_struct_type(struct_type); + pform_bind_attributes(net->attributes, attr, true); } -static void pform_set_struct_type(struct_type_t*struct_type, perm_string name) +static void pform_set_struct_type(struct_type_t*struct_type, perm_string name, list*attr) { if (struct_type->packed_flag) { - pform_set_packed_struct(struct_type, name); + pform_set_packed_struct(struct_type, name, attr); return; } @@ -67,11 +68,11 @@ static void pform_set_struct_type(struct_type_t*struct_type, perm_string name) ivl_assert(*struct_type, 0); } -void pform_set_struct_type(struct_type_t*struct_type, list*names) +void pform_set_struct_type(struct_type_t*struct_type, list*names, list*attr) { for (list::iterator cur = names->begin() ; cur != names->end() ; ++ cur) { - pform_set_struct_type(struct_type, *cur); + pform_set_struct_type(struct_type, *cur, attr); } } diff --git a/scripts/devel-stub.conf b/scripts/devel-stub.conf index 5982f4988..0764294d5 100644 --- a/scripts/devel-stub.conf +++ b/scripts/devel-stub.conf @@ -14,7 +14,7 @@ iwidth:32 sys_func:vpi/system.sft sys_func:vpi/v2005_math.sft sys_func:vpi/va_math.sft -warnings:implicit +warnings:ailnpstv debug:eval_tree debug:elaborate debug:elab_pexpr diff --git a/scripts/devel-stub.sh b/scripts/devel-stub.sh index 10fe34f6d..e39315b3b 100644 --- a/scripts/devel-stub.sh +++ b/scripts/devel-stub.sh @@ -9,6 +9,6 @@ # # NOTE: DO NOT INSTALL THIS FILE. -./ivl -v -Ctgt-stub/stub.conf -C./scripts/devel-stub.conf -Pa.pf -Na.net -fDLL=tgt-stub/stub.tgt foo.vl +./ivl -v -Ctgt-stub/stub.conf -C./scripts/devel-stub.conf -Pa.pf -Na.net -fDLL=tgt-stub/stub.tgt foo.vl |& tee foo.log echo "*** ivl command completed, rc=$?" diff --git a/tgt-vvp/draw_net_input.c b/tgt-vvp/draw_net_input.c index ffc835518..5b7de3472 100644 --- a/tgt-vvp/draw_net_input.c +++ b/tgt-vvp/draw_net_input.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001-2011 Stephen Williams (steve@icarus.com) + * Copyright (c) 2001-2012 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 @@ -703,11 +703,13 @@ static void draw_net_input_x(ivl_nexus_t nex, if ( (sw = ivl_nexus_ptr_switch(nptr)) ) { assert(island == 0 || island == ivl_switch_island(sw)); island = ivl_switch_island(sw); - if (nex == ivl_switch_a(sw)) + if (nex == ivl_switch_a(sw)) { + nex_flags |= VVP_NEXUS_DATA_STR; island_input_flag = 0; - else if (nex == ivl_switch_b(sw)) + } else if (nex == ivl_switch_b(sw)) { + nex_flags |= VVP_NEXUS_DATA_STR; island_input_flag = 0; - else if (island_input_flag == -1) { + } else if (island_input_flag == -1) { assert(nex == ivl_switch_enable(sw)); island_input_flag = 1; } diff --git a/verilog.spec b/verilog.spec index a3cb4be06..9f6cbe645 100644 --- a/verilog.spec +++ b/verilog.spec @@ -1,6 +1,6 @@ #norootforbuild # -%define rev_date 20111127 +%define rev_date 20120501 # Normally, the suff-ix is %nil, meaning the suffix is to not be used. # But if the builder wants to make a suffixed package, he may set this # to a value (i.e. -test) to cause suffixes to be put in all the right diff --git a/vvp/island_tran.cc b/vvp/island_tran.cc index 4cd0989b8..5462f02a4 100644 --- a/vvp/island_tran.cc +++ b/vvp/island_tran.cc @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008-2011 Stephen Williams (steve@icarus.com) + * Copyright (c) 2008-2012 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 @@ -31,6 +31,12 @@ class vvp_island_tran : public vvp_island { void run_island(); }; +enum tran_state_t { + tran_disabled, + tran_enabled, + tran_unknown +}; + struct vvp_island_branch_tran : public vvp_island_branch { vvp_island_branch_tran(vvp_net_t*en__, bool active_high__, @@ -43,7 +49,7 @@ struct vvp_island_branch_tran : public vvp_island_branch { vvp_net_t*en; unsigned width, part, offset; bool active_high; - bool enabled_flag; + tran_state_t state; }; vvp_island_branch_tran::vvp_island_branch_tran(vvp_net_t*en__, @@ -54,7 +60,7 @@ vvp_island_branch_tran::vvp_island_branch_tran(vvp_net_t*en__, : en(en__), width(width__), part(part__), offset(offset__), active_high(active_high__) { - enabled_flag = en__ ? false : true; + state = en__ ? tran_disabled : tran_enabled; } static inline vvp_island_branch_tran* BRANCH_TRAN(vvp_island_branch*tmp) @@ -73,7 +79,7 @@ void vvp_island_tran::run_island() { // Test to see if any of the branches are enabled. This loop // tests the enabled inputs for all the branches and caches - // the results in the enabled_flag for each branch. + // the results in the state for each branch. bool runnable = false; for (vvp_island_branch*cur = branches_ ; cur ; cur = cur->next_branch) { vvp_island_branch_tran*tmp = dynamic_cast(cur); @@ -103,7 +109,7 @@ bool vvp_island_branch_tran::run_test_enabled() // If there is no ep port (no "enabled" input) then this is a // tran branch. Assume it is always enabled. if (ep == 0) { - enabled_flag = true; + state = tran_enabled; return true; } @@ -122,7 +128,6 @@ bool vvp_island_branch_tran::run_test_enabled() // // If the outvalue is nil, then we know that this port is a // .import after all, so just read the invalue. - enabled_flag = false; vvp_bit4_t enable_val; if (ep->outvalue.size() != 0) enable_val = ep->outvalue.value(0).value(); @@ -131,14 +136,47 @@ bool vvp_island_branch_tran::run_test_enabled() else enable_val = ep->invalue.value(0).value(); - if (active_high==true && enable_val != BIT4_1) - return false; + switch (enable_val) { + case BIT4_0: + state = active_high ? tran_disabled : tran_enabled; + break; + case BIT4_1: + state = active_high ? tran_enabled : tran_disabled; + break; + default: + state = tran_unknown; + break; + } + return (state != tran_disabled); +} - if (active_high==false && enable_val != BIT4_0) - return false; +// The IEEE standard does not specify the behaviour when a tranif control +// input is 'x' or 'z'. We use the rules that are given for MOS switches. +inline vvp_vector8_t resolve_ambiguous(const vvp_vector8_t&a, + const vvp_vector8_t&b, + tran_state_t state) +{ + assert(a.size() == b.size()); + vvp_vector8_t out (a.size()); - enabled_flag = true; - return true; + for (unsigned idx = 0 ; idx < out.size() ; idx += 1) { + vvp_scalar_t a_bit = a.value(idx); + vvp_scalar_t b_bit = b.value(idx); + if (state == tran_unknown) { + switch (b_bit.value()) { + case BIT4_0: + b_bit = vvp_scalar_t(BIT4_X, b_bit.strength0(), 0); + break; + case BIT4_1: + b_bit = vvp_scalar_t(BIT4_X, 0, b_bit.strength1()); + break; + default: + break; + } + } + out.set_bit(idx, resolve(a_bit, b_bit)); + } + return out; } static void push_value_through_branches(const vvp_vector8_t&val, @@ -149,8 +187,8 @@ static void push_value_through_branch(const vvp_vector8_t&val, { vvp_island_branch_tran*branch = BRANCH_TRAN(cur.ptr()); - // If the branch is not enabled, skip. - if (! branch->enabled_flag) + // If the branch is disabled, skip. + if (branch->state == tran_disabled) return; unsigned src_ab = cur.port(); @@ -174,7 +212,8 @@ static void push_value_through_branch(const vvp_vector8_t&val, // previously collected (and resolved) for the port. if (branch->width == 0) { // There are no part selects. - dst_port->value = resolve(dst_port->value, val); + dst_port->value = resolve_ambiguous(dst_port->value, val, + branch->state); } else if (dst_ab == 1) { // The other side is a strict subset (part select) diff --git a/vvp/vpi_callback.cc b/vvp/vpi_callback.cc index 3dd441caf..5c9268e2a 100644 --- a/vvp/vpi_callback.cc +++ b/vvp/vpi_callback.cc @@ -482,6 +482,9 @@ void vpiNextSimTime(void) { simulator_callback* cur; + assert(vpi_mode_flag == VPI_MODE_NONE); + vpi_mode_flag = VPI_MODE_RWSYNC; + while (NextSimTime) { cur = NextSimTime; NextSimTime = dynamic_cast(cur->next); @@ -489,6 +492,7 @@ void vpiNextSimTime(void) delete cur; } + vpi_mode_flag = VPI_MODE_NONE; } static simulator_callback* make_prepost(p_cb_data data)