From 39ee49b2524e495e4a7f1b20a178459f6c4b52ce Mon Sep 17 00:00:00 2001 From: Martin Whitaker Date: Wed, 14 Mar 2012 19:49:37 +0000 Subject: [PATCH 01/10] Improved behaviour of tranif when control is 'x' or 'z'. The IEEE standard does not specify the behaviour of a tranif primitive when its control input is an 'x' or 'z'. vvp currently treats these as if the tran was turned off, but it would be better to propagate the uncertainty to the tran bi-directional ports. For compatibility with other simulators, we adopt the behaviour specified for MOS primitives. --- tgt-vvp/draw_net_input.c | 10 +++--- vvp/island_tran.cc | 69 +++++++++++++++++++++++++++++++--------- 2 files changed, 60 insertions(+), 19 deletions(-) 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/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) From ae901f328542ca906056591bcbcaefdb0caeaff8 Mon Sep 17 00:00:00 2001 From: Gordon McGregor Date: Sun, 8 Apr 2012 00:05:50 -0500 Subject: [PATCH 02/10] adding vpi_mode_flag controls around callbacks in vpiNextSimTime --- vvp/vpi_callback.cc | 4 ++++ 1 file changed, 4 insertions(+) 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) From abf8274e4b42e76ec436ca497845bf188ccc64f9 Mon Sep 17 00:00:00 2001 From: Stephen Williams Date: Fri, 27 Apr 2012 18:22:25 -0700 Subject: [PATCH 03/10] Fixup parse of attributes attached to statements. --- parse.y | 94 ++++++++++++++++++++++++++++----------------------------- 1 file changed, 46 insertions(+), 48 deletions(-) diff --git a/parse.y b/parse.y index cce1cffca..a67ca88d5 100644 --- a/parse.y +++ b/parse.y @@ -574,7 +574,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 +750,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 +1317,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 +1805,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); + } - | 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); + } /* variable declarations. Note that data_type can be 0 if we are recovering from an error. */ - | attribute_list_opt data_type register_variable_list ';' + | data_type register_variable_list ';' + { if ($1) pform_set_data_type(@1, $1, $2); + } + + | K_reg data_type register_variable_list ';' { if ($2) pform_set_data_type(@2, $2, $3); - if ($1) delete $1; } - | attribute_list_opt K_reg data_type register_variable_list ';' - { if ($3) pform_set_data_type(@3, $3, $4); - if ($1) delete $1; + | 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 +1837,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."); @@ -4199,15 +4204,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); } @@ -5445,7 +5450,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 +5518,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 +5552,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 +5631,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; } From 8ea1e497680c955784d4a488577b8077ccdc41be Mon Sep 17 00:00:00 2001 From: Stephen Williams Date: Mon, 30 Apr 2012 11:48:33 -0700 Subject: [PATCH 04/10] Improve net bit select calculations. --- PExpr.h | 2 ++ elab_expr.cc | 37 +++++++++++++++++++++++++++++++++++++ elab_net.cc | 22 ++++++---------------- 3 files changed, 45 insertions(+), 16 deletions(-) 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/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..163e543cc 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; From 69c10c47221b445fa1f2b1562dda192e76515da0 Mon Sep 17 00:00:00 2001 From: Stephen Williams Date: Mon, 30 Apr 2012 16:00:25 -0700 Subject: [PATCH 05/10] Handle case generate under a conditional generate that is unnamed. When a conditional statement is unnamed, it doesn't create a scope and we get into "direct" generate scheme elaboration. This direct elaboration needs to handle case generate schemes. --- elab_scope.cc | 16 ++++++++++++++-- elab_sig.cc | 17 ++++++++++++++--- elaborate.cc | 50 ++++++++++++++++++++++++++++++++++++++++---------- 3 files changed, 68 insertions(+), 15 deletions(-) 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; From fb3969b5b851eb0013e71beb34dedf7ac7b3187b Mon Sep 17 00:00:00 2001 From: Stephen Williams Date: Mon, 30 Apr 2012 16:30:24 -0700 Subject: [PATCH 06/10] Add command line control over anachronism warnings. --- compiler.h | 3 +++ driver/main.c | 12 +++++++++++- main.cc | 4 ++++ parse.y | 4 ++-- scripts/devel-stub.conf | 2 +- scripts/devel-stub.sh | 2 +- 6 files changed, 22 insertions(+), 5 deletions(-) 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/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/parse.y b/parse.y index a67ca88d5..c6a5017a5 100644 --- a/parse.y +++ b/parse.y @@ -4272,7 +4272,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; } @@ -4281,7 +4281,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; } 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=$?" From 75b12151a437e16e3cf913846c30cdce01ecf9a1 Mon Sep 17 00:00:00 2001 From: Martin Whitaker Date: Mon, 30 Apr 2012 23:05:42 +0100 Subject: [PATCH 07/10] Disable width minimisation of literal numbers passed to system tasks. The final step of expression elaboration is to reduce the width of lossless/unsized constant expressions to the minimum needed to hold the resulting constant value. This leads to unexpected results if the user supplies a literal number with redundant digits that gets passed to a system task that is sensitive to the width (e.g. $display). This patch prevents width reduction occurring in this case. --- netmisc.cc | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) 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(); } From 2013addd22a3b9cc05bb30a3367830671e1aadf9 Mon Sep 17 00:00:00 2001 From: Stephen Williams Date: Sun, 15 Apr 2012 18:04:09 -0700 Subject: [PATCH 08/10] Fix check for SV continuous assign to variable. SystemVerilog allows a variable to be used as a variable OR as an unresolved wire. The detection of this case was checking the references to the affected value, instead of the l-value references. (cherry picked from commit cceeaa30f27260cd444015cb39b04353cb858768) --- elab_net.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/elab_net.cc b/elab_net.cc index 163e543cc..db70c4069 100644 --- a/elab_net.cc +++ b/elab_net.cc @@ -443,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); } From c3f25c3c6c60d5c215c798b98f6a08665bf2b026 Mon Sep 17 00:00:00 2001 From: Stephen Williams Date: Tue, 1 May 2012 08:50:07 -0700 Subject: [PATCH 09/10] Prepare for 2012-05-01 snapshot --- verilog.spec | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 From 5d05d97eb0c9a6852a4901be2ef6aae3a8129d03 Mon Sep 17 00:00:00 2001 From: Stephen Williams Date: Wed, 9 May 2012 10:56:52 -0700 Subject: [PATCH 10/10] Repair handling of attributes attached to variables. --- parse.y | 22 +++++++++++------ pform.cc | 58 ++++++++++++++++++++++++++------------------ pform.h | 15 ++++++------ pform_struct_type.cc | 11 +++++---- 4 files changed, 63 insertions(+), 43 deletions(-) diff --git a/parse.y b/parse.y index c6a5017a5..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 @@ -1806,22 +1811,22 @@ block_item_decl is implicit in the "integer" of the declaration. */ : K_integer signed_unsigned_opt register_variable_list ';' - { pform_set_reg_integer($3); + { pform_set_reg_integer($3, attributes_in_context); } | K_time register_variable_list ';' - { pform_set_reg_time($2); + { pform_set_reg_time($2, attributes_in_context); } /* variable declarations. Note that data_type can be 0 if we are recovering from an error. */ | data_type register_variable_list ';' - { if ($1) pform_set_data_type(@1, $1, $2); + { if ($1) pform_set_data_type(@1, $1, $2, attributes_in_context); } | K_reg data_type register_variable_list ';' - { if ($2) pform_set_data_type(@2, $2, $3); + { if ($2) pform_set_data_type(@2, $2, $3, attributes_in_context); } | K_event list_of_identifiers ';' @@ -4100,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; + } /* */ 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); } }