From e719dc250a01c68415017b666b970b5262ef55d8 Mon Sep 17 00:00:00 2001 From: Cary R Date: Wed, 6 Aug 2008 11:46:43 -0700 Subject: [PATCH 01/11] %load/av now matches %load/v for truncating/extension. This patch adds code to make %load/av extend or truncate a value like %load/v. --- vvp/opcodes.txt | 5 +++-- vvp/vthread.cc | 14 ++++++++------ 2 files changed, 11 insertions(+), 8 deletions(-) diff --git a/vvp/opcodes.txt b/vvp/opcodes.txt index ef5c909b1..f3a266569 100644 --- a/vvp/opcodes.txt +++ b/vvp/opcodes.txt @@ -414,8 +414,9 @@ ended, then the %join does not block or yield the thread. * %load/av , , This instruction loads a word from the specified array. The word -address is in index register 3. The width should match the width of -the array word. +address is in index register 3. Like %load/v below the width does +not have to match the width of the array word. See the %load/v +description for more information. * %load/avp0 , , * %load/avp0/s , , diff --git a/vvp/vthread.cc b/vvp/vthread.cc index 31d1c8602..b83cfc397 100644 --- a/vvp/vthread.cc +++ b/vvp/vthread.cc @@ -2363,19 +2363,21 @@ bool of_LOAD_AV(vthread_t thr, vvp_code_t cp) vvp_vector4_t word = array_get_word(cp->array, adr); - if (word.size() != wid) { - fprintf(stderr, "internal error: array width=%u, word.size()=%u, wid=%u\n", - 0, word.size(), wid); - assert(word.size() == wid); - } - /* Check the address once, before we scan the vector. */ thr_check_addr(thr, bit+wid-1); + if (word.size() > wid) + word.resize(wid); + /* Copy the vector bits into the bits4 vector. Do the copy directly to skip the excess calls to thr_check_addr. */ thr->bits4.set_vec(bit, word); + /* If the source is shorter then the desired width, then pad + with BIT4_X values. */ + for (unsigned idx = word.size() ; idx < wid ; idx += 1) + thr->bits4.set_bit(bit+idx, BIT4_X); + return true; } From d43452f88d98b7aab9e7d37a44f1dc3605af6809 Mon Sep 17 00:00:00 2001 From: Cary R Date: Wed, 6 Aug 2008 15:46:43 -0700 Subject: [PATCH 02/11] Check all generate expressions for failure. This patch adds code to check that the various generate expressions evaluate correctly. --- elab_scope.cc | 28 ++++++++++++++++++++++++---- 1 file changed, 24 insertions(+), 4 deletions(-) diff --git a/elab_scope.cc b/elab_scope.cc index 37f186e93..36cf94a96 100644 --- a/elab_scope.cc +++ b/elab_scope.cc @@ -475,7 +475,12 @@ bool PGenerate::generate_scope_loop_(Design*des, NetScope*container) container->genvar_tmp_val = genvar; NetExpr*test_ex = elab_and_eval(des, container, loop_test, -1); NetEConst*test = dynamic_cast(test_ex); - assert(test); + if (test == 0) { + cerr << get_fileline() << ": error: Cannot evaluate genvar" + << " conditional expression: " << *loop_test << endl; + des->errors += 1; + return false; + } while (test->value().as_long()) { // The actual name of the scope includes the genvar so @@ -522,7 +527,12 @@ bool PGenerate::generate_scope_loop_(Design*des, NetScope*container) // Calculate the step for the loop variable. NetExpr*step_ex = elab_and_eval(des, container, loop_step, -1); NetEConst*step = dynamic_cast(step_ex); - assert(step); + if (step == 0) { + cerr << get_fileline() << ": error: Cannot evaluate genvar" + << " step expression: " << *loop_step << endl; + des->errors += 1; + return false; + } if (debug_scopes) cerr << get_fileline() << ": debug: genvar step from " << genvar << " to " << step->value().as_long() << endl; @@ -547,7 +557,12 @@ bool PGenerate::generate_scope_condit_(Design*des, NetScope*container, bool else { NetExpr*test_ex = elab_and_eval(des, container, loop_test, -1); NetEConst*test = dynamic_cast (test_ex); - assert(test); + if (test == 0) { + cerr << get_fileline() << ": error: Cannot evaluate genvar" + << " conditional expression: " << *loop_test << endl; + des->errors += 1; + return false; + } // If the condition evaluates as false, then do not create the // scope. @@ -589,7 +604,12 @@ bool PGenerate::generate_scope_case_(Design*des, NetScope*container) { NetExpr*case_value_ex = elab_and_eval(des, container, loop_test, -1); NetEConst*case_value_co = dynamic_cast(case_value_ex); - assert(case_value_co); + if (case_value_co == 0) { + cerr << get_fileline() << ": error: Cannot evaluate genvar case" + << " expression: " << *loop_test << endl; + des->errors += 1; + return false; + } // The name of the scope to generate, whatever that item is. hname_t use_name (scope_name); From ef66ca649878f14342cf1bc17f64f7bd8daa8cc7 Mon Sep 17 00:00:00 2001 From: Cary R Date: Wed, 6 Aug 2008 20:09:52 -0700 Subject: [PATCH 03/11] Do a part select of the array selection result not the base array. When doing the part select of an array selection you need to use the result from the array selection to do the part select not the base array signal. --- elab_net.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/elab_net.cc b/elab_net.cc index f00936882..6cd63c12d 100644 --- a/elab_net.cc +++ b/elab_net.cc @@ -2327,7 +2327,7 @@ NetNet* PEIdent::elaborate_net_array_(Design*des, NetScope*scope, } while (0); #else if (name_tail.index.size() > sig->array_dimensions()) - tmp = process_select_(des, scope, sig); + tmp = process_select_(des, scope, tmp); #endif return tmp; From 79e1273814b76ff679f0eecab2eb160fb13ee498 Mon Sep 17 00:00:00 2001 From: Stephen Williams Date: Sat, 9 Aug 2008 16:45:20 -0700 Subject: [PATCH 04/11] Do not consome pform defparams in module definition. The list of defparams in the pform module definitions (in class Module) should not be consumed when they are used. The module may be instantiated moltiple times, so consuming the defparams during elaboration will cause subsequent instantiations to not have the defparams. That's wrong. --- elab_scope.cc | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/elab_scope.cc b/elab_scope.cc index 36cf94a96..fd1228d44 100644 --- a/elab_scope.cc +++ b/elab_scope.cc @@ -316,17 +316,17 @@ bool Module::elaborate_scope(Design*des, NetScope*scope, // here because the parameter receiving the assignment may be // in a scope not discovered by this pass. - while (! defparms.empty()) { - Module::named_expr_t cur = defparms.front(); - defparms.pop_front(); + typedef list::const_iterator defparms_iter_t; + for (defparms_iter_t cur = defparms.begin() + ; cur != defparms.end() ; cur ++) { - PExpr*ex = cur.second; + PExpr*ex = cur->second; assert(ex); NetExpr*val = ex->elaborate_pexpr(des, scope); - delete ex; if (val == 0) continue; - scope->defparams.push_back(make_pair(cur.first, val)); + + scope->defparams.push_back(make_pair(cur->first, val)); } // Evaluate the attributes. Evaluate them in the scope of the From 65272623486c259632d90e8310aa3f61edc199cf Mon Sep 17 00:00:00 2001 From: Nick Gasson Date: Fri, 8 Aug 2008 20:35:27 +0100 Subject: [PATCH 05/11] Add correct file/line information to signals This patch adds a FILE_NAME function for signals to extract the file/line information from the net's LineInfo, replacing the dummy values. --- t-dll.cc | 3 +-- t-dll.h | 6 ++++++ 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/t-dll.cc b/t-dll.cc index 06cd40220..e11692145 100644 --- a/t-dll.cc +++ b/t-dll.cc @@ -2374,8 +2374,7 @@ void dll_target::signal(const NetNet*net) object, or creating the sigs_ array if this is the first signal. */ obj->scope_ = find_scope(des_, net->scope()); - obj->file = perm_string::literal("N/A"); - obj->lineno = 0; + FILE_NAME(obj, net); assert(obj->scope_); if (obj->scope_->nsigs_ == 0) { diff --git a/t-dll.h b/t-dll.h index 3bb1b9279..c409a6ce9 100644 --- a/t-dll.h +++ b/t-dll.h @@ -771,4 +771,10 @@ static inline void FILE_NAME(ivl_process_t net, const LineInfo*info) net->lineno = info->get_lineno(); } +static inline void FILE_NAME(ivl_signal_t net, const LineInfo*info) +{ + net->file = info->get_file(); + net->lineno = info->get_lineno(); +} + #endif From 2a389a9abe0c7ec7370c81a1ef5a8975163c0b9f Mon Sep 17 00:00:00 2001 From: Cary R Date: Fri, 8 Aug 2008 13:57:26 -0700 Subject: [PATCH 06/11] Display signal array size when using -delaborate. This patch modifies one of the debug_elaborate messages to display the array information when needed. --- elab_sig.cc | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/elab_sig.cc b/elab_sig.cc index 8faa7f2c9..cccac8ba7 100644 --- a/elab_sig.cc +++ b/elab_sig.cc @@ -1003,8 +1003,11 @@ NetNet* PWire::elaborate_sig(Design*des, NetScope*scope) const if (debug_elaborate) { cerr << get_fileline() << ": debug: Create signal " - << wtype << " ["< 0) { + cerr << " [" << array_s0 << ":" << array_e0 << "]" << endl; + } + cerr << " in scope " << scope_path(scope) << endl; } From 5aecd044c5201bfddbad51d03372a79c1df918fa Mon Sep 17 00:00:00 2001 From: Martin Whitaker Date: Fri, 8 Aug 2008 23:05:15 +0100 Subject: [PATCH 07/11] Patch to fix pr2043585. This patch fixes a bug in the VVP code generator that causes syntactically incorrect code to be generated if an event expression contains a memory or array port. --- tgt-vvp/vvp_scope.c | 66 ++++++++++++++++++++++++++------------------- 1 file changed, 38 insertions(+), 28 deletions(-) diff --git a/tgt-vvp/vvp_scope.c b/tgt-vvp/vvp_scope.c index 3be138c7e..42f378711 100644 --- a/tgt-vvp/vvp_scope.c +++ b/tgt-vvp/vvp_scope.c @@ -895,6 +895,10 @@ static void draw_logic_in_scope(ivl_net_logic_t lptr) static void draw_event_in_scope(ivl_event_t obj) { + char tmp[4][32]; + + const unsigned ntmp = sizeof(tmp) / sizeof(tmp[0]); + unsigned nany = ivl_event_nany(obj); unsigned nneg = ivl_event_nneg(obj); unsigned npos = ivl_event_npos(obj); @@ -903,13 +907,13 @@ static void draw_event_in_scope(ivl_event_t obj) /* Figure out how many probe functors are needed. */ if (nany > 0) - cnt += (nany+3) / 4; + cnt += (nany+ntmp-1) / ntmp; if (nneg > 0) - cnt += (nneg+3) / 4; + cnt += (nneg+ntmp-1) / ntmp; if (npos > 0) - cnt += (npos+3) / 4; + cnt += (npos+ntmp-1) / ntmp; if (cnt == 0) { /* If none are needed, then this is a named event. The @@ -923,48 +927,57 @@ static void draw_event_in_scope(ivl_event_t obj) unsigned idx; unsigned ecnt = 0; - for (idx = 0 ; idx < nany ; idx += 4, ecnt += 1) { + for (idx = 0 ; idx < nany ; idx += ntmp, ecnt += 1) { unsigned sub, top; - fprintf(vvp_out, "E_%p/%u .event edge", obj, ecnt); - - top = idx + 4; + top = idx + ntmp; if (nany < top) top = nany; for (sub = idx ; sub < top ; sub += 1) { ivl_nexus_t nex = ivl_event_any(obj, sub); - fprintf(vvp_out, ", %s", draw_input_from_net(nex)); + strncpy(tmp[sub-idx], draw_input_from_net(nex), sizeof(tmp[0])); } + + fprintf(vvp_out, "E_%p/%u .event edge", obj, ecnt); + for (sub = idx ; sub < top ; sub += 1) + fprintf(vvp_out, ", %s", tmp[sub-idx]); + fprintf(vvp_out, ";\n"); } - for (idx = 0 ; idx < nneg ; idx += 4, ecnt += 1) { + for (idx = 0 ; idx < nneg ; idx += ntmp, ecnt += 1) { unsigned sub, top; - fprintf(vvp_out, "E_%p/%u .event negedge", obj, ecnt); - - top = idx + 4; + top = idx + ntmp; if (nneg < top) top = nneg; for (sub = idx ; sub < top ; sub += 1) { ivl_nexus_t nex = ivl_event_neg(obj, sub); - fprintf(vvp_out, ", %s", draw_input_from_net(nex)); + strncpy(tmp[sub-idx], draw_input_from_net(nex), sizeof(tmp[0])); } + + fprintf(vvp_out, "E_%p/%u .event negedge", obj, ecnt); + for (sub = idx ; sub < top ; sub += 1) + fprintf(vvp_out, ", %s", tmp[sub-idx]); + fprintf(vvp_out, ";\n"); } - for (idx = 0 ; idx < npos ; idx += 4, ecnt += 1) { + for (idx = 0 ; idx < npos ; idx += ntmp, ecnt += 1) { unsigned sub, top; - fprintf(vvp_out, "E_%p/%u .event posedge", obj, ecnt); - - top = idx + 4; + top = idx + ntmp; if (npos < top) top = npos; for (sub = idx ; sub < top ; sub += 1) { ivl_nexus_t nex = ivl_event_pos(obj, sub); - fprintf(vvp_out, ", %s", draw_input_from_net(nex)); + strncpy(tmp[sub-idx], draw_input_from_net(nex), sizeof(tmp[0])); } + + fprintf(vvp_out, "E_%p/%u .event posedge", obj, ecnt); + for (sub = idx ; sub < top ; sub += 1) + fprintf(vvp_out, ", %s", tmp[sub-idx]); + fprintf(vvp_out, ";\n"); } @@ -981,20 +994,17 @@ static void draw_event_in_scope(ivl_event_t obj) } else { unsigned num_input_strings = nany + nneg + npos; unsigned idx; - ivl_nexus_t input_nexa[4]; const char*edge = 0; - assert(num_input_strings <= 4); + assert(num_input_strings <= ntmp); if (nany > 0) { assert((nneg + npos) == 0); - assert(nany <= 4); - edge = "edge"; for (idx = 0 ; idx < nany ; idx += 1) { ivl_nexus_t nex = ivl_event_any(obj, idx); - input_nexa[idx] = nex; + strncpy(tmp[idx], draw_input_from_net(nex), sizeof(tmp[0])); } } else if (nneg > 0) { @@ -1003,7 +1013,7 @@ static void draw_event_in_scope(ivl_event_t obj) for (idx = 0 ; idx < nneg ; idx += 1) { ivl_nexus_t nex = ivl_event_neg(obj, idx); - input_nexa[idx] = nex; + strncpy(tmp[idx], draw_input_from_net(nex), sizeof(tmp[0])); } } else { @@ -1012,14 +1022,14 @@ static void draw_event_in_scope(ivl_event_t obj) for (idx = 0 ; idx < npos ; idx += 1) { ivl_nexus_t nex = ivl_event_pos(obj, idx); - input_nexa[idx] = nex; + strncpy(tmp[idx], draw_input_from_net(nex), sizeof(tmp[0])); } } fprintf(vvp_out, "E_%p .event %s", obj, edge); - for (idx = 0 ; idx < num_input_strings ; idx += 1) - fprintf(vvp_out, ", %s", draw_input_from_net(input_nexa[idx])); - + for (idx = 0 ; idx < num_input_strings ; idx += 1) { + fprintf(vvp_out, ", %s", tmp[idx]); + } fprintf(vvp_out, ";\n"); } } From f835c7569e9ae910e4780b3c5c00a6cb1bd07369 Mon Sep 17 00:00:00 2001 From: Cary R Date: Fri, 8 Aug 2008 16:34:24 -0700 Subject: [PATCH 08/11] Check for a possible corrupt function definition and return. If a function definition has no ports and no return type it is assumed to be a bad definition so we don't check it further. --- elab_sig.cc | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/elab_sig.cc b/elab_sig.cc index cccac8ba7..ae2221d1c 100644 --- a/elab_sig.cc +++ b/elab_sig.cc @@ -589,9 +589,17 @@ void PFunction::elaborate_sig(Design*des, NetScope*scope) const break; default: - cerr << get_fileline() << ": internal error: I don't know how " - << "to deal with return type of function " - << scope->basename() << "." << endl; + if (ports_) { + cerr << get_fileline() << ": internal error: I don't know " + << "how to deal with return type of function " + << scope->basename() << "." << endl; + } else { + /* If we do not have any ports or a return type this + * is probably a bad function definition. */ + cerr << get_fileline() << ": error: Bad definition for " + << "function " << scope->basename() << "?" << endl; + return; + } } svectorports (ports_? ports_->count() : 0); From c918cf4a469efa7f3b93e315173ba814d48e363f Mon Sep 17 00:00:00 2001 From: Cary R Date: Fri, 8 Aug 2008 17:22:54 -0700 Subject: [PATCH 09/11] User task and function arguments can take an optional reg. User task and function arguments can take an optional reg property. This property is completely ignored by Icarus. --- parse.y | 54 ++++++++++++++++++++++++++++++------------------------ 1 file changed, 30 insertions(+), 24 deletions(-) diff --git a/parse.y b/parse.y index c97dae85b..7a4485c75 100644 --- a/parse.y +++ b/parse.y @@ -3734,29 +3734,34 @@ task_item | task_port_item { $$ = $1; } ; +reg_opt + : K_reg + | + ; + task_port_item - : K_input signed_opt range_opt list_of_identifiers ';' + : K_input reg_opt signed_opt range_opt list_of_identifiers ';' { svector*tmp = pform_make_task_ports(NetNet::PINPUT, - IVL_VT_NO_TYPE, $2, - $3, $4, + IVL_VT_NO_TYPE, $3, + $4, $5, @1.text, @1.first_line); $$ = tmp; } - | K_output signed_opt range_opt list_of_identifiers ';' + | K_output reg_opt signed_opt range_opt list_of_identifiers ';' { svector*tmp = pform_make_task_ports(NetNet::POUTPUT, - IVL_VT_LOGIC, $2, - $3, $4, + IVL_VT_LOGIC, $3, + $4, $5, @1.text, @1.first_line); $$ = tmp; } - | K_inout signed_opt range_opt list_of_identifiers ';' + | K_inout reg_opt signed_opt range_opt list_of_identifiers ';' { svector*tmp = pform_make_task_ports(NetNet::PINOUT, - IVL_VT_LOGIC, $2, - $3, $4, + IVL_VT_LOGIC, $3, + $4, $5, @1.text, @1.first_line); $$ = tmp; } @@ -3861,47 +3866,48 @@ task_item_list_opt task_port_decl - : K_input signed_opt range_opt IDENTIFIER + : K_input reg_opt signed_opt range_opt IDENTIFIER { port_declaration_context.port_type = NetNet::PINPUT; port_declaration_context.var_type = IVL_VT_LOGIC; - port_declaration_context.sign_flag = $2; + port_declaration_context.sign_flag = $3; delete port_declaration_context.range; - port_declaration_context.range = copy_range($3); + port_declaration_context.range = copy_range($4); svector*tmp = pform_make_task_ports(NetNet::PINPUT, - IVL_VT_LOGIC, $2, - $3, list_from_identifier($4), + IVL_VT_LOGIC, $3, + $4, list_from_identifier($5), @1.text, @1.first_line); $$ = tmp; } - | K_output signed_opt range_opt IDENTIFIER + | K_output reg_opt signed_opt range_opt IDENTIFIER { port_declaration_context.port_type = NetNet::POUTPUT; port_declaration_context.var_type = IVL_VT_LOGIC; - port_declaration_context.sign_flag = $2; + port_declaration_context.sign_flag = $3; delete port_declaration_context.range; - port_declaration_context.range = copy_range($3); + port_declaration_context.range = copy_range($4); svector*tmp = pform_make_task_ports(NetNet::POUTPUT, - IVL_VT_LOGIC, $2, - $3, list_from_identifier($4), + IVL_VT_LOGIC, $3, + $4, list_from_identifier($5), @1.text, @1.first_line); $$ = tmp; } - | K_inout signed_opt range_opt IDENTIFIER + | K_inout reg_opt signed_opt range_opt IDENTIFIER { port_declaration_context.port_type = NetNet::PINOUT; port_declaration_context.var_type = IVL_VT_LOGIC; - port_declaration_context.sign_flag = $2; + port_declaration_context.sign_flag = $3; delete port_declaration_context.range; - port_declaration_context.range = copy_range($3); + port_declaration_context.range = copy_range($4); svector*tmp = pform_make_task_ports(NetNet::PINOUT, - IVL_VT_LOGIC, $2, - $3, list_from_identifier($4), + IVL_VT_LOGIC, $3, + $4, list_from_identifier($5), @1.text, @1.first_line); $$ = tmp; } +// Need to add time and realtime! | K_input K_integer IDENTIFIER { svector*range_stub = new svector(2); From b1f1c11441e1a0497f1cab7046da6b1c42311afe Mon Sep 17 00:00:00 2001 From: Cary R Date: Fri, 8 Aug 2008 18:12:52 -0700 Subject: [PATCH 10/11] User task and function arguments can be time or realtime This patch adds the time and realtime properties for user task and function arguments. It also make a common rule for real and realtime since they are the same. --- parse.y | 178 ++++++++++++++++++++++++++++++++++++++++++-------------- 1 file changed, 134 insertions(+), 44 deletions(-) diff --git a/parse.y b/parse.y index 7a4485c75..7382eae6b 100644 --- a/parse.y +++ b/parse.y @@ -351,6 +351,13 @@ number : BASED_NUMBER based_size = 0; } ; + /* real and realtime are exactly the same so save some code + * with a common matching rule. */ +real_or_realtime + : K_real + | K_realtime + ; + /* Verilog-2001 supports attribute lists, which can be attached to a variety of different objects. The syntax inside the (* *) is a comma separated list of names or names with assigned values. */ @@ -2426,17 +2433,7 @@ parameter_assign_decl param_active_signed = false; param_active_type = IVL_VT_LOGIC; } - | K_real - { param_active_range = 0; - param_active_signed = true; - param_active_type = IVL_VT_REAL; - } - parameter_assign_list - { param_active_range = 0; - param_active_signed = false; - param_active_type = IVL_VT_LOGIC; - } - | K_realtime + | real_or_realtime { param_active_range = 0; param_active_signed = true; param_active_type = IVL_VT_REAL; @@ -2565,17 +2562,7 @@ localparam_assign_decl param_active_signed = false; param_active_type = IVL_VT_LOGIC; } - | K_real - { param_active_range = 0; - param_active_signed = true; - param_active_type = IVL_VT_REAL; - } - localparam_assign_list - { param_active_range = 0; - param_active_signed = false; - param_active_type = IVL_VT_LOGIC; - } - | K_realtime + | real_or_realtime { param_active_range = 0; param_active_signed = true; param_active_type = IVL_VT_REAL; @@ -3767,11 +3754,10 @@ task_port_item } /* When the port is an integer, infer a signed vector of the integer - shape. Generate a range to make it work. */ + shape. Generate a range ([31:0]) to make it work. */ | K_input K_integer list_of_identifiers ';' - { svector*range_stub - = new svector(2); + { svector*range_stub = new svector(2); PExpr*re; re = new PENumber(new verinum(integer_width-1, integer_width)); @@ -3786,8 +3772,7 @@ task_port_item $$ = tmp; } | K_output K_integer list_of_identifiers ';' - { svector*range_stub - = new svector(2); + { svector*range_stub = new svector(2); PExpr*re; re = new PENumber(new verinum(integer_width-1, integer_width)); @@ -3802,8 +3787,7 @@ task_port_item $$ = tmp; } | K_inout K_integer list_of_identifiers ';' - { svector*range_stub - = new svector(2); + { svector*range_stub = new svector(2); PExpr*re; re = new PENumber(new verinum(integer_width-1, integer_width)); @@ -3818,9 +3802,54 @@ task_port_item $$ = tmp; } - /* Ports can be real. */ + /* Ports can be time with a width of [63:0] (unsigned). */ - | K_input K_real list_of_identifiers ';' + | K_input K_time list_of_identifiers ';' + { svector*range_stub = new svector(2); + PExpr*re; + re = new PENumber(new verinum((uint64_t)63, integer_width)); + (*range_stub)[0] = re; + re = new PENumber(new verinum((uint64_t)0, integer_width)); + (*range_stub)[1] = re; + svector*tmp + = pform_make_task_ports(NetNet::PINPUT, + IVL_VT_LOGIC, false, + range_stub, $3, + @1.text, @1.first_line); + $$ = tmp; + } + | K_output K_time list_of_identifiers ';' + { svector*range_stub = new svector(2); + PExpr*re; + re = new PENumber(new verinum((uint64_t)63, integer_width)); + (*range_stub)[0] = re; + re = new PENumber(new verinum((uint64_t)0, integer_width)); + (*range_stub)[1] = re; + svector*tmp + = pform_make_task_ports(NetNet::POUTPUT, + IVL_VT_LOGIC, false, + range_stub, $3, + @1.text, @1.first_line); + $$ = tmp; + } + | K_inout K_time list_of_identifiers ';' + { svector*range_stub = new svector(2); + PExpr*re; + re = new PENumber(new verinum((uint64_t)63, integer_width)); + (*range_stub)[0] = re; + re = new PENumber(new verinum((uint64_t)0, integer_width)); + (*range_stub)[1] = re; + svector*tmp + = pform_make_task_ports(NetNet::PINOUT, + IVL_VT_LOGIC, false, + range_stub, $3, + @1.text, @1.first_line); + $$ = tmp; + } + + /* Ports can be real or realtime. */ + + | K_input real_or_realtime list_of_identifiers ';' { svector*tmp = pform_make_task_ports(NetNet::PINPUT, IVL_VT_REAL, false, @@ -3828,7 +3857,7 @@ task_port_item @1.text, @1.first_line); $$ = tmp; } - | K_output K_real list_of_identifiers ';' + | K_output real_or_realtime list_of_identifiers ';' { svector*tmp = pform_make_task_ports(NetNet::POUTPUT, IVL_VT_REAL, true, @@ -3836,7 +3865,7 @@ task_port_item @1.text, @1.first_line); $$ = tmp; } - | K_inout K_real list_of_identifiers ';' + | K_inout real_or_realtime list_of_identifiers ';' { svector*tmp = pform_make_task_ports(NetNet::PINOUT, IVL_VT_REAL, true, @@ -3907,10 +3936,10 @@ task_port_decl $$ = tmp; } -// Need to add time and realtime! + /* Ports can be integer with a width of [31:0]. */ + | K_input K_integer IDENTIFIER - { svector*range_stub - = new svector(2); + { svector*range_stub = new svector(2); PExpr*re; re = new PENumber(new verinum(integer_width-1, integer_width)); @@ -3931,8 +3960,7 @@ task_port_decl $$ = tmp; } | K_output K_integer IDENTIFIER - { svector*range_stub - = new svector(2); + { svector*range_stub = new svector(2); PExpr*re; re = new PENumber(new verinum(integer_width-1, integer_width)); @@ -3953,8 +3981,7 @@ task_port_decl $$ = tmp; } | K_inout K_integer IDENTIFIER - { svector*range_stub - = new svector(2); + { svector*range_stub = new svector(2); PExpr*re; re = new PENumber(new verinum(integer_width-1, integer_width)); @@ -3975,9 +4002,72 @@ task_port_decl $$ = tmp; } - /* Ports can be real. */ + /* Ports can be time with a width of [63:0] (unsigned). */ + + | K_input K_time IDENTIFIER + { svector*range_stub = new svector(2); + PExpr*re; + re = new PENumber(new verinum((uint64_t)63, integer_width)); + (*range_stub)[0] = re; + re = new PENumber(new verinum((uint64_t)0, integer_width)); + (*range_stub)[1] = re; + port_declaration_context.port_type = NetNet::PINPUT; + port_declaration_context.var_type = IVL_VT_LOGIC; + port_declaration_context.sign_flag = false; + delete port_declaration_context.range; + port_declaration_context.range = copy_range(range_stub); + svector*tmp + = pform_make_task_ports(NetNet::PINPUT, + IVL_VT_LOGIC, false, + range_stub, + list_from_identifier($3), + @1.text, @1.first_line); + $$ = tmp; + } + | K_output K_time IDENTIFIER + { svector*range_stub = new svector(2); + PExpr*re; + re = new PENumber(new verinum((uint64_t)63, integer_width)); + (*range_stub)[0] = re; + re = new PENumber(new verinum((uint64_t)0, integer_width)); + (*range_stub)[1] = re; + port_declaration_context.port_type = NetNet::POUTPUT; + port_declaration_context.var_type = IVL_VT_LOGIC; + port_declaration_context.sign_flag = false; + delete port_declaration_context.range; + port_declaration_context.range = copy_range(range_stub); + svector*tmp + = pform_make_task_ports(NetNet::POUTPUT, + IVL_VT_LOGIC, false, + range_stub, + list_from_identifier($3), + @1.text, @1.first_line); + $$ = tmp; + } + | K_inout K_time IDENTIFIER + { svector*range_stub = new svector(2); + PExpr*re; + re = new PENumber(new verinum((uint64_t)63, integer_width)); + (*range_stub)[0] = re; + re = new PENumber(new verinum((uint64_t)0, integer_width)); + (*range_stub)[1] = re; + port_declaration_context.port_type = NetNet::PINOUT; + port_declaration_context.var_type = IVL_VT_LOGIC; + port_declaration_context.sign_flag = false; + delete port_declaration_context.range; + port_declaration_context.range = copy_range(range_stub); + svector*tmp + = pform_make_task_ports(NetNet::PINOUT, + IVL_VT_LOGIC, false, + range_stub, + list_from_identifier($3), + @1.text, @1.first_line); + $$ = tmp; + } - | K_input K_real IDENTIFIER + /* Ports can be real or realtime. */ + + | K_input real_or_realtime IDENTIFIER { port_declaration_context.port_type = NetNet::PINPUT; port_declaration_context.var_type = IVL_VT_REAL; port_declaration_context.sign_flag = false; @@ -3990,7 +4080,7 @@ task_port_decl @1.text, @1.first_line); $$ = tmp; } - | K_output K_real IDENTIFIER + | K_output real_or_realtime IDENTIFIER { port_declaration_context.port_type = NetNet::POUTPUT; port_declaration_context.var_type = IVL_VT_REAL; port_declaration_context.sign_flag = false; @@ -4003,7 +4093,7 @@ task_port_decl @1.text, @1.first_line); $$ = tmp; } - | K_inout K_real IDENTIFIER + | K_inout real_or_realtime IDENTIFIER { port_declaration_context.port_type = NetNet::PINOUT; port_declaration_context.var_type = IVL_VT_REAL; port_declaration_context.sign_flag = false; From 1f8ff7ff8d7a7b98ba643886d576c7c02c59b615 Mon Sep 17 00:00:00 2001 From: Cary R Date: Fri, 8 Aug 2008 19:15:05 -0700 Subject: [PATCH 11/11] Pass a NULL expression when parameter expression elaboration fails When elaborating a parameter expression fails we need to set the expression to 0 since it has already been partially allocated. Doing this allows us to not evaluate the dummy expression later. --- elab_scope.cc | 40 ++++++++++++++++++++++++---------------- net_design.cc | 4 ++-- 2 files changed, 26 insertions(+), 18 deletions(-) diff --git a/elab_scope.cc b/elab_scope.cc index fd1228d44..b77292dea 100644 --- a/elab_scope.cc +++ b/elab_scope.cc @@ -53,7 +53,7 @@ void Module::elaborate_parm_item_(perm_string name, const param_expr_t&cur, assert(ex); NetExpr*val = ex->elaborate_pexpr(des, scope); - if (val == 0) return; + NetExpr*msb = 0; NetExpr*lsb = 0; bool signed_flag = cur.signed_flag; @@ -71,19 +71,6 @@ void Module::elaborate_parm_item_(perm_string name, const param_expr_t&cur, assert(lsb); } - if (signed_flag) { - /* If explicitly signed, then say so. */ - val->cast_signed(true); - } else if (cur.msb) { - /* If there is a range, then the signedness comes - from the type and not the expression. */ - val->cast_signed(signed_flag); - } else { - /* otherwise, let the expression describe - itself. */ - signed_flag = val->has_sign(); - } - NetScope::range_t*range_list = 0; for (Module::range_t*range = cur.range ; range ; range = range->next) { NetScope::range_t*tmp = new NetScope::range_t; @@ -118,8 +105,29 @@ void Module::elaborate_parm_item_(perm_string name, const param_expr_t&cur, range_list = tmp; } - val = scope->set_parameter(name, val, cur.type, msb, lsb, signed_flag, range_list, cur); - assert(val); + /* Set the parameter expression to 0 if the evaluation failed. */ + if (val == 0) { + val = scope->set_parameter(name, val, cur.type, msb, lsb, + signed_flag, range_list, cur); + delete val; + return; + } + + if (signed_flag) { + /* If explicitly signed, then say so. */ + val->cast_signed(true); + } else if (cur.msb) { + /* If there is a range, then the signedness comes + from the type and not the expression. */ + val->cast_signed(signed_flag); + } else { + /* otherwise, let the expression describe + itself. */ + signed_flag = val->has_sign(); + } + + val = scope->set_parameter(name, val, cur.type, msb, lsb, signed_flag, + range_list, cur); delete val; } diff --git a/net_design.cc b/net_design.cc index 595c1a44a..9a290cb8e 100644 --- a/net_design.cc +++ b/net_design.cc @@ -357,11 +357,11 @@ void NetScope::evaluate_parameter_logic_(Design*des, param_ref_t cur) /* Evaluate the parameter expression, if necessary. */ NetExpr*expr = (*cur).second.expr; - assert(expr); + if (expr == NULL) return; // This is an invalid parameter so return. eval_expr(expr); - /* The eval_expr may delete any replace the expr pointer, so the + /* The eval_expr may delete and replace the expr pointer, so the second.expr value cannot be relied on. Might as well replace it now with the expression that we evaluated. */ (*cur).second.expr = expr;