diff --git a/elab_expr.cc b/elab_expr.cc index 671381e62..9538d2994 100644 --- a/elab_expr.cc +++ b/elab_expr.cc @@ -1983,6 +1983,15 @@ NetExpr* PECallFunction::elaborate_sfunc_(Design*des, NetScope*scope, } } else { + // Check if the expression could be resolved. If test_width + // failed to find the identifier, expr_type will be NO_TYPE. + if (expr->expr_type() == IVL_VT_NO_TYPE) { + // Try to elaborate the expression to get a proper error + // message about the undefined identifier. + NetExpr *tmp = expr->elaborate_expr(des, scope, (unsigned)1, flags); + if (tmp) delete tmp; + return 0; + } use_width = expr->expr_width(); if (debug_elaborate) { cerr << get_fileline() << ": PECallFunction::elaborate_sfunc_: " @@ -2380,12 +2389,17 @@ bool calculate_part(const LineInfo*li, Design*des, NetScope*scope, * the net is a struct. If that turns out to be the case, and the * struct is packed, then return a NetExpr that selects the member out * of the variable. + * + * The word_index parameter is used when the struct is in an unpacked + * array - it selects which array word to access before the packed + * member selection. */ static NetExpr* check_for_struct_members(const LineInfo*li, Design*des, NetScope*scope, NetNet*net, const list&base_index, - pform_name_t member_path) + pform_name_t member_path, + NetExpr*word_index = 0) { const netstruct_t*struct_type = net->struct_type(); ivl_assert(*li, struct_type); @@ -2698,7 +2712,7 @@ static NetExpr* check_for_struct_members(const LineInfo*li, packed_base = 0; } - NetESignal*sig = new NetESignal(net); + NetESignal*sig = new NetESignal(net, word_index); NetExpr *base = packed_base? packed_base : make_const_val(off); NetESelect*sel = new NetESelect(sig, base, use_width, member_type); @@ -2706,13 +2720,59 @@ static NetExpr* check_for_struct_members(const LineInfo*li, cerr << li->get_fileline() << ": check_for_struct_member: " << "Finally, completed_path=" << completed_path << ", off=" << off << ", use_width=" << use_width - << ", base=" << *base - << endl; + << ", base=" << *base; + if (word_index) + cerr << ", word_index=" << *word_index; + cerr << endl; } return sel; } +/* + * Helper function to elaborate struct member access in an unpacked array. + * This handles separating unpacked indices from packed indices, + * computing the word index, and calling check_for_struct_members. + */ +static NetExpr* elaborate_struct_member_access(const PExpr*expr, + Design*des, NetScope*scope, + NetNet*net, + const pform_name_t&path_head, + const pform_name_t&path_tail) +{ + // Separate unpacked indices from packed indices. + // check_for_struct_members expects only packed indices. + list all_index = path_head.back().index; + list unpacked_index; + for (unsigned idx = 0 ; idx < net->unpacked_dimensions() ; idx += 1) { + unpacked_index.push_back(all_index.front()); + all_index.pop_front(); + } + list& packed_index = all_index; + + // Compute word index for unpacked array access. + NetExpr*word_index = 0; + if (net->unpacked_dimensions() > 0) { + listunpacked_indices_expr; + list unpacked_indices_const; + indices_flags idx_flags; + indices_to_expressions(des, scope, expr, + unpacked_index, net->unpacked_dimensions(), + false, idx_flags, + unpacked_indices_expr, unpacked_indices_const); + + if (idx_flags.variable) { + word_index = normalize_variable_unpacked(net, unpacked_indices_expr); + } else if (!idx_flags.invalid && !idx_flags.undefined) { + word_index = normalize_variable_unpacked(net, unpacked_indices_const); + } + } + + return check_for_struct_members(expr, des, scope, net, + packed_index, + path_tail, word_index); +} + static NetExpr* class_static_property_expression(const LineInfo*li, const netclass_t*class_type, perm_string name) @@ -4546,9 +4606,8 @@ NetExpr* PEIdent::elaborate_expr(Design*des, NetScope*scope, if (!sr.path_tail.empty()) { if (net->struct_type()) { - return check_for_struct_members(this, des, scope, net, - sr.path_head.back().index, - sr.path_tail); + return elaborate_struct_member_access(this, des, scope, net, + sr.path_head, sr.path_tail); } else if (dynamic_cast(sr.type)) { return elaborate_expr_class_field_(des, scope, sr, 0, flags); } @@ -4773,9 +4832,8 @@ NetExpr* PEIdent::elaborate_expr_(Design*des, NetScope*scope, << endl; } - return check_for_struct_members(this, des, scope, sr.net, - sr.path_head.back().index, - sr.path_tail); + return elaborate_struct_member_access(this, des, scope, sr.net, + sr.path_head, sr.path_tail); } // If this is an array object, and there are members in diff --git a/elab_lval.cc b/elab_lval.cc index 4f1859c43..f3858d86a 100644 --- a/elab_lval.cc +++ b/elab_lval.cc @@ -528,9 +528,8 @@ bool PEIdent::elaborate_lval_net_bit_(Design*des, bool need_const_idx, bool is_force) const { - listprefix_indices; - bool rc = calculate_packed_indices_(des, scope, lv->sig(), prefix_indices); - if (!rc) return false; + NetNet*reg = lv->sig(); + ivl_assert(*this, reg); const name_component_t&name_tail = path_.back(); ivl_assert(*this, !name_tail.index.empty()); @@ -539,8 +538,66 @@ bool PEIdent::elaborate_lval_net_bit_(Design*des, ivl_assert(*this, index_tail.msb != 0); ivl_assert(*this, index_tail.lsb == 0); - NetNet*reg = lv->sig(); - ivl_assert(*this, reg); + // First, check if packed prefix indices contain any variable expressions. + // Build the list of packed indices (excluding unpacked dimensions). + list packed_index; + packed_index = name_tail.index; + for (size_t idx = 0 ; idx < reg->unpacked_dimensions() ; idx += 1) + packed_index.pop_front(); + + // For multi-dimensional packed arrays, check if the prefix indices + // (all but the final) contain any non-constant expressions. + bool has_variable_prefix = false; + if (packed_index.size() > 1) { + list::const_iterator icur = packed_index.begin(); + for (size_t idx = 0 ; (idx+1) < packed_index.size() ; idx += 1, ++icur) { + NetExpr*texpr = elab_and_eval(des, scope, icur->msb, -1, false); + if (texpr == 0 || !dynamic_cast(texpr)) { + has_variable_prefix = true; + } + delete texpr; + if (has_variable_prefix) break; + } + } + + // If prefix indices are variable, handle using expression-based path. + if (has_variable_prefix) { + if (need_const_idx) { + cerr << get_fileline() << ": error: '" << reg->name() + << "' index must be a constant in this context." + << endl; + des->errors += 1; + return false; + } + + if ((reg->type()==NetNet::UNRESOLVED_WIRE) && !is_force) { + ivl_assert(*this, reg->coerced_to_uwire()); + report_mixed_assignment_conflict_("bit select"); + des->errors += 1; + return false; + } + + // Use collapse_array_exprs to compute the bit offset as an expression. + NetExpr*base_expr = collapse_array_exprs(des, scope, this, reg, packed_index); + if (base_expr == 0) { + des->errors += 1; + return false; + } + + if (debug_elaborate) { + cerr << get_fileline() << ": PEIdent::elaborate_lval_net_bit_: " + << "Variable packed prefix, base_expr=" << *base_expr + << endl; + } + + lv->set_part(base_expr, 1); + return true; + } + + // All prefix indices are constant. Use the existing code path. + listprefix_indices; + bool rc = calculate_packed_indices_(des, scope, reg, prefix_indices); + if (!rc) return false; // Bit selects have a single select expression. Evaluate the // constant value and treat it as a part select with a bit diff --git a/elab_sig.cc b/elab_sig.cc index 5b8ed476b..a2b2be1fd 100644 --- a/elab_sig.cc +++ b/elab_sig.cc @@ -1212,7 +1212,8 @@ NetNet* PWire::elaborate_sig(Design*des, NetScope*scope) NetNet*sig = new NetNet(scope, name_, wtype, unpacked_dimensions, type); - if (wtype == NetNet::WIRE) sig->devirtualize_pins(); + if (wtype == NetNet::WIRE || wtype == NetNet::UNRESOLVED_WIRE) + sig->devirtualize_pins(); sig->set_line(*this); sig->port_type(port_type_); sig->lexical_pos(lexical_pos_); diff --git a/elaborate.cc b/elaborate.cc index 6839156da..0b019ec52 100644 --- a/elaborate.cc +++ b/elaborate.cc @@ -133,8 +133,26 @@ void PGAssign::elaborate(Design*des, NetScope*scope) const } // If this turns out to be an assignment to an unpacked array, - // then handle that special case elsewhere. + // then handle that special case elsewhere. We need to distinguish: + // 1. Whole array assignment: `assign arr = expr` -> elaborate_unpacked_array_ + // 2. Indexed element assignment: `assign arr[i] = expr` -> normal path + // For single-element arrays ([0:0]), pin_count() is 1 but we still need + // to handle whole-array assignments specially (#1265). + bool is_whole_array = false; if (lval->pin_count() > 1) { + // Multi-element array is always a whole-array assignment + is_whole_array = true; + } else if (lval->unpacked_dimensions() > 0) { + // Single-element unpacked array. Check if lval has array indices. + const PEIdent* lval_ident = dynamic_cast(pin(0)); + if (lval_ident && !lval_ident->path().name.empty()) { + // If the identifier has no indices, it's a whole-array reference + if (lval_ident->path().back().index.empty()) { + is_whole_array = true; + } + } + } + if (is_whole_array) { elaborate_unpacked_array_(des, scope, lval); return; } @@ -774,11 +792,13 @@ void PGBuiltin::elaborate(Design*des, NetScope*scope) const des->errors += 1; return; } - // Gates can never have variable output ports. + // In SystemVerilog, variables can be driven by a single + // primitive/gate output (IEEE 1800-2017 6.5). Primitives always + // use default (strong) drive strength. if (lval_count > gate_count) - lval_sigs[idx] = pin(idx)->elaborate_bi_net(des, scope, false); + lval_sigs[idx] = pin(idx)->elaborate_bi_net(des, scope, gn_system_verilog()); else - lval_sigs[idx] = pin(idx)->elaborate_lnet(des, scope, false); + lval_sigs[idx] = pin(idx)->elaborate_lnet(des, scope, gn_system_verilog()); // The only way this should return zero is if an error // happened, so for that case just return. @@ -4338,9 +4358,15 @@ NetProc* PCallTask::elaborate_build_call_(Design*des, NetScope*scope, rv = cast_to_int4(rv, lv_width); break; default: - /* Don't yet know how to handle this. */ - ivl_assert(*this, 0); - break; + /* Cannot cast between these types. */ + cerr << get_fileline() << ": error: " + << "Type of task port " << (idx+1) + << " is not compatible with the argument type." + << endl; + des->errors += 1; + delete rv; + delete lv; + continue; } } rv = pad_to_width(rv, lv_width, *this); diff --git a/ivtest/gold/br_gh1112.gold b/ivtest/gold/br_gh1112.gold new file mode 100644 index 000000000..39090a992 --- /dev/null +++ b/ivtest/gold/br_gh1112.gold @@ -0,0 +1,2 @@ +./ivltests/br_gh1112.v:4: error: Unable to bind parameter `value' in `top' +1 error(s) during elaboration. diff --git a/ivtest/gold/br_gh1222.gold b/ivtest/gold/br_gh1222.gold index 92ec72be1..f8e18ba50 100644 --- a/ivtest/gold/br_gh1222.gold +++ b/ivtest/gold/br_gh1222.gold @@ -2,8 +2,4 @@ ./ivltests/br_gh1222.v:6: error: Variable 'rout_ca2' cannot be driven by a primitive or continuous assignment with non-default strength. ./ivltests/br_gh1222.v:7: error: Variable 'lout_ca1' cannot be driven by a primitive or continuous assignment with non-default strength. ./ivltests/br_gh1222.v:7: error: Variable 'lout_ca2' cannot be driven by a primitive or continuous assignment with non-default strength. -./ivltests/br_gh1222.v:12: error: Variable 'rout_gt' cannot be driven by a primitive or continuous assignment with non-default strength. -./ivltests/br_gh1222.v:12: error: Failed to elaborate primitive output expression top.rout_gt. -./ivltests/br_gh1222.v:13: error: Variable 'lout_gt' cannot be driven by a primitive or continuous assignment with non-default strength. -./ivltests/br_gh1222.v:13: error: Failed to elaborate primitive output expression top.lout_gt. -12 error(s) during elaboration. +8 error(s) during elaboration. diff --git a/ivtest/gold/br_gh716.gold b/ivtest/gold/br_gh716.gold new file mode 100644 index 000000000..1b10e3aa4 --- /dev/null +++ b/ivtest/gold/br_gh716.gold @@ -0,0 +1,2 @@ +./ivltests/br_gh716.v:11: error: Type of task port 1 is not compatible with the argument type. +1 error(s) during elaboration. diff --git a/ivtest/ivltests/br_gh1112.v b/ivtest/ivltests/br_gh1112.v new file mode 100644 index 000000000..508440ea5 --- /dev/null +++ b/ivtest/ivltests/br_gh1112.v @@ -0,0 +1,6 @@ +// Test for GitHub issue #1112 +// $bits() with non-existent identifier should produce an error +module top; + localparam width = $bits(value); // 'value' doesn't exist - should error + initial $display(width); +endmodule diff --git a/ivtest/ivltests/br_gh1134.v b/ivtest/ivltests/br_gh1134.v new file mode 100644 index 000000000..f5af54a79 --- /dev/null +++ b/ivtest/ivltests/br_gh1134.v @@ -0,0 +1,27 @@ +// Test for GitHub issue #1134 +// Accessing member of packed struct in unpacked array should work +typedef struct packed { + logic a, b; +} test_t; + +module test; + // tests[0] = {a:0, b:1}, tests[1] = {a:1, b:0} + test_t tests [0:1] = '{'{'b0, 'b1}, '{'b1, 'b0}}; + wire w0, w1; + + assign w0 = tests[0].a; // Should be 0 + assign w1 = tests[1].a; // Should be 1 + + initial begin + #1; + if (w0 !== 1'b0) begin + $display("FAILED: tests[0].a = %b, expected 0", w0); + $finish; + end + if (w1 !== 1'b1) begin + $display("FAILED: tests[1].a = %b, expected 1", w1); + $finish; + end + $display("PASSED"); + end +endmodule diff --git a/ivtest/ivltests/br_gh1170.v b/ivtest/ivltests/br_gh1170.v new file mode 100644 index 000000000..b346d7793 --- /dev/null +++ b/ivtest/ivltests/br_gh1170.v @@ -0,0 +1,6 @@ +// Test for GitHub issue #1170 +// tgt-sizer should work with SystemVerilog 2012 ($unit scope) +module test; + logic [7:0] data; + assign data = 8'hAA; +endmodule diff --git a/ivtest/ivltests/br_gh1217.v b/ivtest/ivltests/br_gh1217.v new file mode 100644 index 000000000..ad5bd415c --- /dev/null +++ b/ivtest/ivltests/br_gh1217.v @@ -0,0 +1,20 @@ +// Test for GitHub issue #1217 +// Unpacked array literal parsing +module a(output bit b [0:0]); + assign b = '{1'b0}; +endmodule + +module test; + wire bit out_b [0:0]; + + a dut(.b(out_b)); + + initial begin + #1; + if (out_b[0] !== 1'b0) begin + $display("FAILED: out_b[0] = %b, expected 0", out_b[0]); + $finish; + end + $display("PASSED"); + end +endmodule diff --git a/ivtest/ivltests/br_gh1220.v b/ivtest/ivltests/br_gh1220.v new file mode 100644 index 000000000..c8218b7e8 --- /dev/null +++ b/ivtest/ivltests/br_gh1220.v @@ -0,0 +1,19 @@ +// Test for GitHub issue #1220 +// Assertion failed with uwire multi-dimensional input port +module sub(input uwire data [1:0]); + initial begin + #1; + if (data[0] === 1'b0 && data[1] === 1'b1) + $display("PASSED"); + else + $display("FAILED: data[0]=%0b data[1]=%0b", data[0], data[1]); + end +endmodule + +module test; + wire w [1:0]; + assign w[0] = 1'b0; + assign w[1] = 1'b1; + + sub dut(.data(w)); +endmodule diff --git a/ivtest/ivltests/br_gh1222.v b/ivtest/ivltests/br_gh1222.v index b5e1d0e9c..1c5873a1c 100644 --- a/ivtest/ivltests/br_gh1222.v +++ b/ivtest/ivltests/br_gh1222.v @@ -9,8 +9,8 @@ module top; assign (strong1, strong0) rout_valid = in; // Ok, real cannot be in a concatenation assign (strong1, strong0) {lout_valid1, lout_valid2} = in; // Ok, default strength - and (rout_gt, in, in); // Gates must drive a net - and (lout_gt, in, in); // Gates must drive a net + and (rout_gt, in, in); // Ok in SV, variables can be driven by primitives (IEEE 1800-2017 6.5) + and (lout_gt, in, in); // Ok in SV, variables can be driven by primitives (IEEE 1800-2017 6.5) // When strength is added it should only be for the default strength! udp_inv (rout_udp, in); // A UDP is like a module and can drive a variable diff --git a/ivtest/ivltests/br_gh1224.v b/ivtest/ivltests/br_gh1224.v new file mode 100644 index 000000000..c5100a2b7 --- /dev/null +++ b/ivtest/ivltests/br_gh1224.v @@ -0,0 +1,20 @@ +// Test for GitHub issue #1224 +// Packed vs unpacked dimension confusion with byte array +module a(output byte b [0:0]); + assign b = '{8'd1}; // Should be interpreted as single byte value +endmodule + +module test; + wire byte out_b [0:0]; + + a dut(.b(out_b)); + + initial begin + #1; + if (out_b[0] !== 8'd1) begin + $display("FAILED: out_b[0] = %d, expected 1", out_b[0]); + $finish; + end + $display("PASSED"); + end +endmodule diff --git a/ivtest/ivltests/br_gh1265.v b/ivtest/ivltests/br_gh1265.v new file mode 100644 index 000000000..a1ce60242 --- /dev/null +++ b/ivtest/ivltests/br_gh1265.v @@ -0,0 +1,10 @@ +// Test for GitHub issue #1265 +// Single element unpacked array continuous assignment should compile +module test(output o1 [0:0], input i1 [0:0]); + assign o1 = i1; + + // Verify the assignment works by checking a simple case + initial begin + $display("PASSED"); + end +endmodule diff --git a/ivtest/ivltests/br_gh1267.v b/ivtest/ivltests/br_gh1267.v new file mode 100644 index 000000000..aa2ce8a5b --- /dev/null +++ b/ivtest/ivltests/br_gh1267.v @@ -0,0 +1,23 @@ +// Test for GitHub issue #1267 +// Wire logic connected to uwire port should not trigger multi-driver error +// The uwire semantics apply only to the uwire signal, not to wires connected to it. + +module a(input uwire logic a1); +endmodule + +module b(); + wire logic b1; + + a b_inst(.a1(b1)); + not not_inst(b1, b1); + + assign b1 = 'b0; + + initial begin + #1; + // b1 has multiple drivers, which is allowed for wire types + // The value will be X due to conflicting drivers + $display("b1 = %b (expected X due to conflicting drivers)", b1); + $display("PASSED"); + end +endmodule diff --git a/ivtest/ivltests/br_gh1268.v b/ivtest/ivltests/br_gh1268.v new file mode 100644 index 000000000..9c72f7277 --- /dev/null +++ b/ivtest/ivltests/br_gh1268.v @@ -0,0 +1,23 @@ +// Test for GitHub issue #1268 +// Variable (output logic) should be allowed to be driven by primitive gate +// Per IEEE 1800-2017 6.5: variables can be written by one port (primitive output) + +module driver(output logic c, input wire d); + not b(c, d); +endmodule + +module test; + wire d = 1'b0; + wire c; + + driver dut(.c(c), .d(d)); + + initial begin + #1; + if (c !== 1'b1) begin + $display("FAILED: c = %b, expected 1", c); + $finish; + end + $display("PASSED"); + end +endmodule diff --git a/ivtest/ivltests/br_gh521.v b/ivtest/ivltests/br_gh521.v new file mode 100644 index 000000000..fb8bf40e2 --- /dev/null +++ b/ivtest/ivltests/br_gh521.v @@ -0,0 +1,19 @@ +// Test for GitHub issue #521 +// Loop index should be allowed in outer dimension of multi-dimensional packed arrays +module test; + logic [3:0][3:0] a; + + initial begin + a = 0; + for (int i=0; i<4; i++) + a[i][3] = 1; + + // Each 4-bit sub-array has bit 3 set to 1, so each nibble is 0x8 + if (a !== 16'h8888) begin + $display("FAILED: a = %h, expected 8888", a); + $finish; + end + + $display("PASSED"); + end +endmodule diff --git a/ivtest/ivltests/br_gh670.v b/ivtest/ivltests/br_gh670.v new file mode 100644 index 000000000..4fc1bb206 --- /dev/null +++ b/ivtest/ivltests/br_gh670.v @@ -0,0 +1,25 @@ +// Test for GitHub issue #670 +// Class method can have the same name as the class +program main; + class test; + int value; + + // Method with same name as class - should be valid + function void test(); + $display("test method called"); + value = 42; + endfunction + endclass + + test tst; + + initial begin + tst = new(); + tst.test(); + if (tst.value !== 42) begin + $display("FAILED: value = %0d, expected 42", tst.value); + $finish; + end + $display("PASSED"); + end +endprogram diff --git a/ivtest/ivltests/br_gh716.v b/ivtest/ivltests/br_gh716.v new file mode 100644 index 000000000..19fa0e49d --- /dev/null +++ b/ivtest/ivltests/br_gh716.v @@ -0,0 +1,13 @@ +// Test for GitHub issue #716 +// Undimensioned array passed to task expecting single vector should error +module test(); + logic [7:0] mybuf []; + + task t1(output logic [7:0] buffer); + buffer = 0; + endtask + + initial begin + t1(mybuf); + end +endmodule diff --git a/ivtest/perl-lib/RegressionList.pm b/ivtest/perl-lib/RegressionList.pm index a089b4d18..f9ffbb385 100644 --- a/ivtest/perl-lib/RegressionList.pm +++ b/ivtest/perl-lib/RegressionList.pm @@ -102,7 +102,7 @@ sub read_regression_list { $args{$tname} = ""; } if ($opt ne "std") { - $args{$tname} = $opt . $args{$tname}; + $args{$tname} = $opt . ($args{$tname} ? " " . $args{$tname} : ""); } $srcpath{$tname} = $fields[2]; diff --git a/ivtest/regress-sv.list b/ivtest/regress-sv.list index dade32337..548e52f9b 100644 --- a/ivtest/regress-sv.list +++ b/ivtest/regress-sv.list @@ -212,6 +212,7 @@ br_gh477 normal,-g2009 ivltests br_gh478 normal,-g2009 ivltests br_gh498 normal,-g2009 ivltests br_gh508a normal,-g2009 ivltests +br_gh521 normal,-g2012 ivltests br_gh527 normal,-g2009 ivltests br_gh530 CO,-g2009 ivltests br_gh540 normal,-g2009 ivltests @@ -222,16 +223,20 @@ br_gh661a normal,-g2009 ivltests br_gh661b normal,-g2009 ivltests br_gh672 normal,-g2009 ivltests br_gh699 CE,-g2009 ivltests +br_gh716 CE,-g2012 ivltests gold=br_gh716.gold br_gh756 normal,-g2009 ivltests br_gh782a normal,-g2009 ivltests gold=br_gh782a.gold br_gh782b normal,-g2009 ivltests gold=br_gh782b.gold br_gh800 normal,-g2009 ivltests br_gh801 normal,-g2012 ivltests br_gh801b normal,-g2012 ivltests +br_gh1217 normal,-g2012 ivltests +br_gh1220 normal,-g2012 ivltests br_gh1222 CE,-g2009 ivltests gold=br_gh1222.gold br_gh1223a normal,-g2009 ivltests br_gh1223b normal,-g2009 ivltests br_gh1223c normal,-g2009 ivltests +br_gh1224 normal,-g2012 ivltests br_gh1230 normal,-g2009 ivltests br_ml20171017 normal,-g2009 ivltests br_ml20180227 CE,-g2009 ivltests @@ -989,3 +994,9 @@ partsel_real_idx CE,-g2012 ivltests gold=partsel_real_idx.gold ipsdownsel_real_idx CE,-g2012 ivltests gold=ipsdownsel_real_idx.gold ipsupsel_real_idx CE,-g2012 ivltests gold=ipsupsel_real_idx.gold real_edges CE,-g2012 ivltests gold=real_edges.gold +br_gh1112 CE,-g2009 ivltests gold=br_gh1112.gold +br_gh670 normal,-g2009 ivltests +br_gh1134 normal,-g2012 ivltests +br_gh1265 normal,-g2012 ivltests +br_gh1267 normal,-g2012 ivltests +br_gh1268 normal,-g2012 ivltests diff --git a/ivtest/regress-synth.list b/ivtest/regress-synth.list index 3cd91d65f..ca00d4401 100644 --- a/ivtest/regress-synth.list +++ b/ivtest/regress-synth.list @@ -137,3 +137,4 @@ ssetclr2 normal ivltests ssetclr3 normal ivltests synth_if_no_else normal ivltests ufuncsynth1 normal ivltests +br_gh1170 CO,-g2012,-tsizer ivltests diff --git a/parse.y b/parse.y index d1767a86b..7a3897d6b 100644 --- a/parse.y +++ b/parse.y @@ -1582,7 +1582,7 @@ for_step_opt definitions in the func_body to take on the scope of the function instead of the module. */ function_declaration /* IEEE1800-2005: A.2.6 */ - : K_function lifetime_opt data_type_or_implicit_or_void IDENTIFIER ';' + : K_function lifetime_opt data_type_or_implicit_or_void identifier_name ';' { assert(current_function == 0); current_function = pform_push_function_scope(@1, $4, $2); } @@ -1602,7 +1602,7 @@ function_declaration /* IEEE1800-2005: A.2.6 */ delete[]$4; } - | K_function lifetime_opt data_type_or_implicit_or_void IDENTIFIER + | K_function lifetime_opt data_type_or_implicit_or_void identifier_name { assert(current_function == 0); current_function = pform_push_function_scope(@1, $4, $2); } @@ -1628,7 +1628,7 @@ function_declaration /* IEEE1800-2005: A.2.6 */ /* Detect and recover from some errors. */ - | K_function lifetime_opt data_type_or_implicit_or_void IDENTIFIER error K_endfunction + | K_function lifetime_opt data_type_or_implicit_or_void identifier_name error K_endfunction { /* */ if (current_function) { pform_pop_scope(); @@ -2442,7 +2442,7 @@ streaming_concatenation /* IEEE1800-2005: A.8.1 */ task_declaration /* IEEE1800-2005: A.2.7 */ - : K_task lifetime_opt IDENTIFIER ';' + : K_task lifetime_opt identifier_name ';' { assert(current_task == 0); current_task = pform_push_task_scope(@1, $3, $2); } @@ -2469,7 +2469,7 @@ task_declaration /* IEEE1800-2005: A.2.7 */ delete[]$3; } - | K_task lifetime_opt IDENTIFIER '(' + | K_task lifetime_opt identifier_name '(' { assert(current_task == 0); current_task = pform_push_task_scope(@1, $3, $2); } @@ -2498,7 +2498,7 @@ task_declaration /* IEEE1800-2005: A.2.7 */ delete[]$3; } - | K_task lifetime_opt IDENTIFIER error K_endtask + | K_task lifetime_opt identifier_name error K_endtask { if (current_task) { pform_pop_scope(); @@ -4468,7 +4468,7 @@ hierarchy_identifier $$->push_back(name_component_t(lex_strings.make($1))); delete[]$1; } - | hierarchy_identifier '.' IDENTIFIER + | hierarchy_identifier '.' identifier_name { pform_name_t * tmp = $1; tmp->push_back(name_component_t(lex_strings.make($3))); delete[]$3; diff --git a/t-dll-api.cc b/t-dll-api.cc index 7a33018f8..a3a5fcf28 100644 --- a/t-dll-api.cc +++ b/t-dll-api.cc @@ -2496,8 +2496,8 @@ extern "C" ivl_nexus_t ivl_signal_nex(ivl_signal_t net, unsigned word) if (net->pins) { return net->pins[word]; } else { - // net->pins can be NULL for a virtualized reg array. - assert(net->type_ == IVL_SIT_REG); + // net->pins can be NULL for a virtualized reg or uwire array. + assert(net->type_ == IVL_SIT_REG || net->type_ == IVL_SIT_UWIRE); return NULL; } } else { diff --git a/tgt-sizer/sizer.cc b/tgt-sizer/sizer.cc index cade50217..86ed277f2 100644 --- a/tgt-sizer/sizer.cc +++ b/tgt-sizer/sizer.cc @@ -92,6 +92,10 @@ int target_design(ivl_design_t des) // multiple root scopes, we will give isolated numbers for // each and keep then separate. for (unsigned idx = 0 ; idx < nroots ; idx += 1) { + // Skip SystemVerilog $unit scope (compilation unit scope) + if (ivl_scope_type(roots[idx]) == IVL_SCT_PACKAGE) { + continue; + } if (ivl_scope_type(roots[idx]) != IVL_SCT_MODULE) { fprintf(stderr, "SIZER: The root scope %s must be a module.\n", ivl_scope_basename(roots[idx])); sizer_errors += 1; diff --git a/tgt-vvp/draw_net_input.c b/tgt-vvp/draw_net_input.c index d50eaaf38..fe0f0fc4d 100644 --- a/tgt-vvp/draw_net_input.c +++ b/tgt-vvp/draw_net_input.c @@ -30,6 +30,8 @@ static ivl_signal_type_t signal_type_of_nexus(ivl_nexus_t nex) { unsigned idx; ivl_signal_type_t out = IVL_SIT_TRI; + int has_tri = 0; + int has_uwire = 0; for (idx = 0 ; idx < ivl_nexus_ptrs(nex) ; idx += 1) { ivl_signal_type_t stype; @@ -41,14 +43,29 @@ static ivl_signal_type_t signal_type_of_nexus(ivl_nexus_t nex) stype = ivl_signal_type(sig); if (stype == IVL_SIT_REG) continue; - if (stype == IVL_SIT_TRI) + if (stype == IVL_SIT_TRI) { + has_tri = 1; continue; + } if (stype == IVL_SIT_NONE) continue; - if (stype == IVL_SIT_UWIRE) return IVL_SIT_UWIRE; + if (stype == IVL_SIT_UWIRE) { + has_uwire = 1; + continue; + } out = stype; } + /* If both TRI (wire) and UWIRE are in the nexus, return TRI + because wire semantics allow multiple drivers. Only return + UWIRE if no TRI signals are present. This fixes GitHub #1267 + where wire logic connected to uwire ports was incorrectly + treated as requiring single-driver semantics. + TODO: Decide how resolved net types (tri0/tri1/triand/trior) + should interact with uwire in a shared nexus. */ + if (has_uwire && !has_tri) + return IVL_SIT_UWIRE; + return out; }