From 6f41576930f026d1e7080912c76b4fdf1c64ac3e Mon Sep 17 00:00:00 2001 From: Martin Whitaker Date: Mon, 22 Feb 2016 22:22:22 +0000 Subject: [PATCH 01/51] Add support for SystemVerilog assignment operators in constant functions. (cherry-picked from master branch) --- net_func_eval.cc | 96 +++++++++++++++++++++++++++++++++++++++++++++--- netlist.h | 1 + 2 files changed, 92 insertions(+), 5 deletions(-) diff --git a/net_func_eval.cc b/net_func_eval.cc index ecbe55780..783b1ead7 100644 --- a/net_func_eval.cc +++ b/net_func_eval.cc @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012-2013 Stephen Williams (steve@icarus.com) + * Copyright (c) 2012-2016 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 @@ -209,6 +209,71 @@ bool NetProc::evaluate_function(const LineInfo&, return false; } +void NetAssign::eval_func_lval_op_(const LineInfo&loc, + verinum&lv, verinum&rv) const +{ + unsigned lv_width = lv.len(); + bool lv_sign = lv.has_sign(); + switch (op_) { + case 'l': + case 'R': + // The left operand is self-determined. + break; + case 'r': + // The left operand is self-determined, but we need to + // cast it to unsigned to get a logical shift. + lv.has_sign(false); + break; + default: + // The left operand must be cast to the expression type/size + lv = cast_to_width(lv, rv.len()); + lv.has_sign(rv.has_sign()); + } + switch (op_) { + case '+': + lv = lv + rv; + break; + case '-': + lv = lv - rv; + break; + case '*': + lv = lv * rv; + break; + case '/': + lv = lv / rv; + break; + case '%': + lv = lv % rv; + break; + case '&': + for (unsigned idx = 0 ; idx < lv.len() ; idx += 1) + lv.set(idx, lv[idx] & rv[idx]); + break; + case '|': + for (unsigned idx = 0 ; idx < lv.len() ; idx += 1) + lv.set(idx, lv[idx] | rv[idx]); + break; + case '^': + for (unsigned idx = 0 ; idx < lv.len() ; idx += 1) + lv.set(idx, lv[idx] ^ rv[idx]); + break; + case 'l': + lv = lv << rv.as_unsigned(); + break; + case 'r': + lv = lv >> rv.as_unsigned(); + break; + case 'R': + lv = lv >> rv.as_unsigned(); + break; + default: + // illegal assignment operator + ivl_assert(loc, 0); + } + lv = cast_to_width(lv, lv_width); + lv.has_sign(lv_sign); +} + bool NetAssign::eval_func_lval_(const LineInfo&loc, map&context_map, const NetAssign_*lval, NetExpr*rval_result) const @@ -271,16 +336,37 @@ bool NetAssign::eval_func_lval_(const LineInfo&loc, NetEConst*lval_const = dynamic_cast(old_lval); verinum lval_v = lval_const->value(); NetEConst*rval_const = dynamic_cast(rval_result); - verinum rval_v = cast_to_width(rval_const->value(), lval->lwidth()); + verinum rval_v = rval_const->value(); - for (unsigned idx = 0 ; idx < rval_v.len() ; idx += 1) - lval_v.set(idx+base, rval_v[idx]); + verinum lpart(verinum::Vx, lval->lwidth()); + if (op_) { + for (unsigned idx = 0 ; idx < lpart.len() ; idx += 1) + lpart.set(idx, lval_v[base+idx]); + + eval_func_lval_op_(loc, lpart, rval_v); + } else { + lpart = cast_to_width(rval_v, lval->lwidth()); + } + for (unsigned idx = 0 ; idx < lpart.len() ; idx += 1) + lval_v.set(idx+base, lpart[idx]); delete base_result; delete rval_result; rval_result = new NetEConst(lval_v); } else { - rval_result = fix_assign_value(lval->sig(), rval_result); + if (op_) { + NetEConst*lval_const = dynamic_cast(old_lval); + verinum lval_v = lval_const->value(); + NetEConst*rval_const = dynamic_cast(rval_result); + verinum rval_v = rval_const->value(); + + eval_func_lval_op_(loc, lval_v, rval_v); + + delete rval_result; + rval_result = new NetEConst(lval_v); + } else { + rval_result = fix_assign_value(lval->sig(), rval_result); + } } if (old_lval) diff --git a/netlist.h b/netlist.h index a3e601165..47848e993 100644 --- a/netlist.h +++ b/netlist.h @@ -2849,6 +2849,7 @@ class NetAssign : public NetAssignBase { map&ctx) const; private: + void eval_func_lval_op_(const LineInfo&loc, verinum&lv, verinum&rv) const; bool eval_func_lval_(const LineInfo&loc, map&ctx, const NetAssign_*lval, NetExpr*rval_result) const; From b0461787c879bcd5a12c6c248af36ed8e9c285fc Mon Sep 17 00:00:00 2001 From: Martin Whitaker Date: Mon, 22 Feb 2016 23:31:35 +0000 Subject: [PATCH 02/51] Extended constant function assignment operator support to real values. (cherry-picked from master branch) Also output a "sorry" message if the LHS is a concatenation. --- net_func_eval.cc | 58 ++++++++++++++++++++++++++++++++++++++++++++---- netlist.h | 1 + 2 files changed, 55 insertions(+), 4 deletions(-) diff --git a/net_func_eval.cc b/net_func_eval.cc index 783b1ead7..d53471f3b 100644 --- a/net_func_eval.cc +++ b/net_func_eval.cc @@ -209,6 +209,32 @@ bool NetProc::evaluate_function(const LineInfo&, return false; } +void NetAssign::eval_func_lval_op_real_(const LineInfo&loc, + verireal&lv, verireal&rv) const +{ + switch (op_) { + case '+': + lv = lv + rv; + break; + case '-': + lv = lv - rv; + break; + case '*': + lv = lv * rv; + break; + case '/': + lv = lv / rv; + break; + case '%': + lv = lv % rv; + break; + default: + cerr << "Illegal assignment operator: " + << human_readable_op(op_) << endl; + ivl_assert(loc, 0); + } +} + void NetAssign::eval_func_lval_op_(const LineInfo&loc, verinum&lv, verinum&rv) const { @@ -267,7 +293,8 @@ void NetAssign::eval_func_lval_op_(const LineInfo&loc, lv = lv >> rv.as_unsigned(); break; default: - // illegal assignment operator + cerr << "Illegal assignment operator: " + << human_readable_op(op_) << endl; ivl_assert(loc, 0); } lv = cast_to_width(lv, lv_width); @@ -334,8 +361,10 @@ bool NetAssign::eval_func_lval_(const LineInfo&loc, ivl_assert(loc, base + lval->lwidth() <= old_lval->expr_width()); NetEConst*lval_const = dynamic_cast(old_lval); + ivl_assert(loc, lval_const); verinum lval_v = lval_const->value(); NetEConst*rval_const = dynamic_cast(rval_result); + ivl_assert(loc, rval_const); verinum rval_v = rval_const->value(); verinum lpart(verinum::Vx, lval->lwidth()); @@ -354,18 +383,32 @@ bool NetAssign::eval_func_lval_(const LineInfo&loc, delete rval_result; rval_result = new NetEConst(lval_v); } else { - if (op_) { + if (op_ == 0) { + rval_result = fix_assign_value(lval->sig(), rval_result); + } else if (dynamic_cast(rval_result)) { + NetECReal*lval_const = dynamic_cast(old_lval); + ivl_assert(loc, lval_const); + verireal lval_r = lval_const->value(); + NetECReal*rval_const = dynamic_cast(rval_result); + ivl_assert(loc, rval_const); + verireal rval_r = rval_const->value(); + + eval_func_lval_op_real_(loc, lval_r, rval_r); + + delete rval_result; + rval_result = new NetECReal(lval_r); + } else { NetEConst*lval_const = dynamic_cast(old_lval); + ivl_assert(loc, lval_const); verinum lval_v = lval_const->value(); NetEConst*rval_const = dynamic_cast(rval_result); + ivl_assert(loc, rval_const); verinum rval_v = rval_const->value(); eval_func_lval_op_(loc, lval_v, rval_v); delete rval_result; rval_result = new NetEConst(lval_v); - } else { - rval_result = fix_assign_value(lval->sig(), rval_result); } } @@ -404,6 +447,13 @@ bool NetAssign::evaluate_function(const LineInfo&loc, NetEConst*rval_const = dynamic_cast(rval_result); ivl_assert(*this, rval_const); + if (op_) { + cerr << get_fileline() << ": sorry: Assignment operators " + "inside a constant function are not currently " + "supported if the LHS is a concatenation." << endl; + return false; + } + verinum rval_full = rval_const->value(); delete rval_result; diff --git a/netlist.h b/netlist.h index 47848e993..01c09a709 100644 --- a/netlist.h +++ b/netlist.h @@ -2849,6 +2849,7 @@ class NetAssign : public NetAssignBase { map&ctx) const; private: + void eval_func_lval_op_real_(const LineInfo&loc, verireal&lv, verireal&rv) const; void eval_func_lval_op_(const LineInfo&loc, verinum&lv, verinum&rv) const; bool eval_func_lval_(const LineInfo&loc, map&ctx, const NetAssign_*lval, NetExpr*rval_result) const; From 2771abf86a8f6011f686733ba84a28118774d40e Mon Sep 17 00:00:00 2001 From: Martin Whitaker Date: Tue, 23 Feb 2016 16:44:03 +0000 Subject: [PATCH 03/51] Fix compressed assignments to concatenations. When loading a lval concatenation, tgt-vvp was loading the elements in the wrong order for the %concat instruction. (cherry picked from commit b77d758f193f83999a3bbd751da0797bace7c7a3) --- tgt-vvp/stmt_assign.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/tgt-vvp/stmt_assign.c b/tgt-vvp/stmt_assign.c index 7a788e807..777781747 100644 --- a/tgt-vvp/stmt_assign.c +++ b/tgt-vvp/stmt_assign.c @@ -183,17 +183,17 @@ static void get_vec_from_lval(ivl_statement_t net, struct vec_slice_info*slices) unsigned wid = ivl_stmt_lwidth(net); cur_bit = 0; - for (lidx = 0 ; lidx < ivl_stmt_lvals(net) ; lidx += 1) { + for (lidx = ivl_stmt_lvals(net) ; lidx > 0 ; lidx -= 1) { ivl_lval_t lval; unsigned bit_limit = wid - cur_bit; - lval = ivl_stmt_lval(net, lidx); + lval = ivl_stmt_lval(net, lidx-1); if (bit_limit > ivl_lval_width(lval)) bit_limit = ivl_lval_width(lval); - get_vec_from_lval_slice(lval, slices+lidx, bit_limit); - if (lidx > 0) { + get_vec_from_lval_slice(lval, slices+lidx-1, bit_limit); + if (cur_bit > 0) { fprintf(vvp_out, " %%concat/vec4;\n"); } From ec9897af5aa94d67c01ebac061357cdf65d1f304 Mon Sep 17 00:00:00 2001 From: Martin Whitaker Date: Tue, 23 Feb 2016 16:46:26 +0000 Subject: [PATCH 04/51] Fix lval extension for compressed assignment in constant function. The type of extension (zero/sign) is determined by the expression type, not the operand type, so we need to cast to the expression type before extending the value. (cherry picked from commit 241b6723e530d204619b0b73f78a4038af3667f3) --- net_func_eval.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/net_func_eval.cc b/net_func_eval.cc index d53471f3b..9e045c63c 100644 --- a/net_func_eval.cc +++ b/net_func_eval.cc @@ -252,8 +252,8 @@ void NetAssign::eval_func_lval_op_(const LineInfo&loc, break; default: // The left operand must be cast to the expression type/size - lv = cast_to_width(lv, rv.len()); lv.has_sign(rv.has_sign()); + lv = cast_to_width(lv, rv.len()); } switch (op_) { case '+': From e2aae72880b981d09300c84546234780780537a1 Mon Sep 17 00:00:00 2001 From: Martin Whitaker Date: Tue, 23 Feb 2016 16:53:01 +0000 Subject: [PATCH 05/51] Fix expression type for compressed assignment statements. A compressed assignment statement should give exactly the same result as the equivalent uncompressed statement. This means that the type (signed/unsigned) of the LHS affects the type of the RHS expression (unlike in normal assignments). We need to take care that bit/part selects and concatenations are correctly identified as unsigned values, even in the cases where they reduce to a single whole signal. (cherry picked from commit 0199ad129de6b628561b714e259948c25d2bdc7b) --- Statement.h | 3 ++- elab_expr.cc | 4 ++-- elab_lval.cc | 4 ++++ elaborate.cc | 12 +++++++++--- net_assign.cc | 3 +++ netlist.h | 7 +++++++ netmisc.cc | 20 ++++++++++++++------ netmisc.h | 6 ++++-- 8 files changed, 45 insertions(+), 14 deletions(-) diff --git a/Statement.h b/Statement.h index b650a03f9..cc7214194 100644 --- a/Statement.h +++ b/Statement.h @@ -108,7 +108,8 @@ class PAssign_ : public Statement { NetAssign_* elaborate_lval(Design*, NetScope*scope) const; NetExpr* elaborate_rval_(Design*, NetScope*, ivl_type_t lv_net_type, ivl_variable_type_t lv_type, - unsigned lv_width) const; + unsigned lv_width, + bool force_unsigned =false) const; NetExpr* elaborate_rval_(Design*, NetScope*, ivl_type_t ntype) const; NetExpr* elaborate_rval_obj_(Design*, NetScope*, diff --git a/elab_expr.cc b/elab_expr.cc index fbaa0246b..9e38a134c 100644 --- a/elab_expr.cc +++ b/elab_expr.cc @@ -90,7 +90,7 @@ static NetBranch* find_existing_implicit_branch(NetNet*sig, NetNet*gnd) NetExpr* elaborate_rval_expr(Design*des, NetScope*scope, ivl_type_t lv_net_type, ivl_variable_type_t lv_type, unsigned lv_width, - PExpr*expr, bool need_const) + PExpr*expr, bool need_const, bool force_unsigned) { if (debug_elaborate) { cerr << expr->get_fileline() << ": elaborate_rval_expr: " @@ -135,7 +135,7 @@ NetExpr* elaborate_rval_expr(Design*des, NetScope*scope, ivl_type_t lv_net_type, } return elab_and_eval(des, scope, expr, context_wid, need_const, - false, lv_type); + false, lv_type, force_unsigned); } /* diff --git a/elab_lval.cc b/elab_lval.cc index ab277685f..718d80e76 100644 --- a/elab_lval.cc +++ b/elab_lval.cc @@ -138,6 +138,9 @@ NetAssign_* PEConcat::elaborate_lval(Design*des, continue; } + /* A concatenation is always unsigned. */ + tmp->set_signed(false); + /* Link the new l-value to the previous one. */ NetAssign_*last = tmp; while (last->more) @@ -399,6 +402,7 @@ NetAssign_* PEIdent::elaborate_lval(Design*des, /* No select expressions. */ NetAssign_*lv = new NetAssign_(reg); + lv->set_signed(reg->get_signed()); return lv; } diff --git a/elaborate.cc b/elaborate.cc index 376c099d1..1f2214929 100644 --- a/elaborate.cc +++ b/elaborate.cc @@ -2325,7 +2325,8 @@ NetExpr* PAssign_::elaborate_rval_(Design*des, NetScope*scope, NetExpr* PAssign_::elaborate_rval_(Design*des, NetScope*scope, ivl_type_t lv_net_type, ivl_variable_type_t lv_type, - unsigned lv_width) const + unsigned lv_width, + bool force_unsigned) const { ivl_assert(*this, rval_); @@ -2334,7 +2335,7 @@ NetExpr* PAssign_::elaborate_rval_(Design*des, NetScope*scope, // should look into fixing calls to this method to pass a // net_type instead of the separate lv_width/lv_type values. NetExpr*rv = elaborate_rval_expr(des, scope, lv_net_type, lv_type, lv_width, - rval(), is_constant_); + rval(), is_constant_, force_unsigned); if (!is_constant_ || !rv) return rv; @@ -2452,7 +2453,12 @@ NetProc* PAssign::elaborate_compressed_(Design*des, NetScope*scope) const NetAssign_*lv = elaborate_lval(des, scope); if (lv == 0) return 0; - NetExpr*rv = elaborate_rval_(des, scope, 0, lv->expr_type(), count_lval_width(lv)); + // Compressed assignments should behave identically to the + // equivalent uncompressed assignments. This means we need + // to take the type of the LHS into account when determining + // the type of the RHS expression. + NetExpr*rv = elaborate_rval_(des, scope, 0, lv->expr_type(), + count_lval_width(lv), !lv->get_signed()); if (rv == 0) return 0; NetAssign*cur = new NetAssign(lv, op_, rv); diff --git a/net_assign.cc b/net_assign.cc index 1467ee961..fa5c1cce7 100644 --- a/net_assign.cc +++ b/net_assign.cc @@ -43,6 +43,8 @@ NetAssign_::NetAssign_(NetAssign_*n) : nest_(n), sig_(0), word_(0), base_(0), sel_type_(IVL_SEL_OTHER) { more = 0; + signed_ = false; + turn_sig_to_wire_on_release_ = false; } NetAssign_::NetAssign_(NetNet*s) @@ -51,6 +53,7 @@ NetAssign_::NetAssign_(NetNet*s) lwid_ = sig_->vector_width(); sig_->incr_lref(); more = 0; + signed_ = false; turn_sig_to_wire_on_release_ = false; } diff --git a/netlist.h b/netlist.h index 01c09a709..19d671b72 100644 --- a/netlist.h +++ b/netlist.h @@ -2732,6 +2732,12 @@ class NetAssign_ { void set_property(const perm_string&name); inline perm_string get_property(void) const { return member_; } + // Determine if the assigned object is signed or unsigned. + // This is used when determining the expression type for + // a compressed assignment statement. + bool get_signed() const { return signed_; } + void set_signed(bool flag) { signed_ = flag; } + // Get the width of the r-value that this node expects. This // method accounts for the presence of the mux, so it is not // necessarily the same as the pin_count(). @@ -2782,6 +2788,7 @@ class NetAssign_ { // member/property if signal is a class. perm_string member_; + bool signed_; bool turn_sig_to_wire_on_release_; // indexed part select base NetExpr*base_; diff --git a/netmisc.cc b/netmisc.cc index 50a48a2c3..2ced04acb 100644 --- a/netmisc.cc +++ b/netmisc.cc @@ -802,9 +802,10 @@ NetExpr* condition_reduce(NetExpr*expr) } static NetExpr* do_elab_and_eval(Design*des, NetScope*scope, PExpr*pe, - int context_width, bool need_const, bool annotatable, - bool force_expand, - ivl_variable_type_t cast_type) + int context_width, bool need_const, + bool annotatable, bool force_expand, + ivl_variable_type_t cast_type, + bool force_unsigned) { PExpr::width_mode_t mode = PExpr::SIZED; if ((context_width == -2) && !gn_strict_expr_width_flag) @@ -824,6 +825,11 @@ static NetExpr* do_elab_and_eval(Design*des, NetScope*scope, PExpr*pe, if ((pe->expr_type() != IVL_VT_REAL) && (expr_width < pos_context_width)) expr_width = pos_context_width; + // If this is the RHS of a compressed assignment, the LHS also + // affects the expression type (signed/unsigned). + if (force_unsigned) + pe->cast_signed(false); + if (debug_elaborate) { cerr << pe->get_fileline() << ": elab_and_eval: test_width of " << *pe << endl; @@ -910,10 +916,11 @@ static NetExpr* do_elab_and_eval(Design*des, NetScope*scope, PExpr*pe, NetExpr* elab_and_eval(Design*des, NetScope*scope, PExpr*pe, int context_width, bool need_const, bool annotatable, - ivl_variable_type_t cast_type) + ivl_variable_type_t cast_type, bool force_unsigned) { return do_elab_and_eval(des, scope, pe, context_width, - need_const, annotatable, false, cast_type); + need_const, annotatable, false, + cast_type, force_unsigned); } /* @@ -926,7 +933,8 @@ NetExpr* elab_and_eval_lossless(Design*des, NetScope*scope, PExpr*pe, ivl_variable_type_t cast_type) { return do_elab_and_eval(des, scope, pe, context_width, - need_const, annotatable, true, cast_type); + need_const, annotatable, true, + cast_type, false); } NetExpr* elab_and_eval(Design*des, NetScope*scope, PExpr*pe, diff --git a/netmisc.h b/netmisc.h index 2b67403f2..4123d4f61 100644 --- a/netmisc.h +++ b/netmisc.h @@ -258,7 +258,8 @@ extern NetExpr* elab_and_eval(Design*des, NetScope*scope, PExpr*pe, int context_width, bool need_const =false, bool annotatable =false, - ivl_variable_type_t cast_type =IVL_VT_NO_TYPE); + ivl_variable_type_t cast_type =IVL_VT_NO_TYPE, + bool force_unsigned =false); extern NetExpr* elab_and_eval_lossless(Design*des, NetScope*scope, PExpr*pe, int context_width, @@ -297,7 +298,8 @@ extern NetExpr* elaborate_rval_expr(Design*des, NetScope*scope, ivl_type_t lv_net_type, ivl_variable_type_t lv_type, unsigned lv_width, PExpr*expr, - bool need_const =false); + bool need_const =false, + bool force_unsigned =false); extern bool evaluate_ranges(Design*des, NetScope*scope, std::vector&llist, From 33db07ab8d3dfcb719b0a94ad2fc0670319d565c Mon Sep 17 00:00:00 2001 From: Martin Whitaker Date: Tue, 23 Feb 2016 20:57:30 +0000 Subject: [PATCH 06/51] Fix expression/operator type for compressed assignment/shift. (cherry picked from commit a7066e3686456fdcdd552269b3d15d55df86e7fe) --- elaborate.cc | 26 +++++++++++++++++++++++--- 1 file changed, 23 insertions(+), 3 deletions(-) diff --git a/elaborate.cc b/elaborate.cc index 1f2214929..eeb8cc27c 100644 --- a/elaborate.cc +++ b/elaborate.cc @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998-2015 Stephen Williams (steve@icarus.com) + * Copyright (c) 1998-2016 Stephen Williams (steve@icarus.com) * Copyright CERN 2013 / Stephen Williams (steve@icarus.com) * * This source code is free software; you can redistribute it @@ -2457,11 +2457,31 @@ NetProc* PAssign::elaborate_compressed_(Design*des, NetScope*scope) const // equivalent uncompressed assignments. This means we need // to take the type of the LHS into account when determining // the type of the RHS expression. + bool force_unsigned; + switch (op_) { + case 'l': + case 'r': + case 'R': + // The right-hand operand of shift operations is + // self-determined. + force_unsigned = false; + break; + default: + force_unsigned = !lv->get_signed(); + break; + } NetExpr*rv = elaborate_rval_(des, scope, 0, lv->expr_type(), - count_lval_width(lv), !lv->get_signed()); + count_lval_width(lv), force_unsigned); if (rv == 0) return 0; - NetAssign*cur = new NetAssign(lv, op_, rv); + // The ivl_target API doesn't support signalling the type + // of a lval, so convert arithmetic shifts into logical + // shifts now if the lval is unsigned. + char op = op_; + if ((op == 'R') && !lv->get_signed()) + op = 'r'; + + NetAssign*cur = new NetAssign(lv, op, rv); cur->set_line(*this); return cur; From b551a783e8f880e99a51a0838d29c95622fae8ad Mon Sep 17 00:00:00 2001 From: Martin Whitaker Date: Tue, 23 Feb 2016 22:02:03 +0000 Subject: [PATCH 07/51] Add support for real valued compressed assignment statements in tgt-vvp. (cherry picked from commit a0bee0a76f9a8d7d465662e7b0dd7332ba1cc975) --- tgt-vvp/stmt_assign.c | 191 ++++++++++++++++++++++++++++++++++++++---- 1 file changed, 176 insertions(+), 15 deletions(-) diff --git a/tgt-vvp/stmt_assign.c b/tgt-vvp/stmt_assign.c index 777781747..94503fe41 100644 --- a/tgt-vvp/stmt_assign.c +++ b/tgt-vvp/stmt_assign.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011-2015 Stephen Williams (steve@icarus.com) + * Copyright (c) 2011-2016 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 @@ -555,28 +555,130 @@ static int show_stmt_assign_vector(ivl_statement_t net) return 0; } -/* - * This function assigns a value to a real variable. This is destined - * for /dev/null when typed ivl_signal_t takes over all the real - * variable support. - */ -static int show_stmt_assign_sig_real(ivl_statement_t net) +enum real_lval_type_e { + REAL_NO_TYPE = 0, + REAL_SIMPLE_WORD, + REAL_MEMORY_WORD_STATIC, + REAL_MEMORY_WORD_DYNAMIC +}; + +struct real_lval_info { + enum real_lval_type_e type; + + union { + struct { + unsigned long use_word; + } simple_word; + + struct { + unsigned long use_word; + } memory_word_static; + + struct { + /* Index reg that holds the memory word index */ + int word_idx_reg; + /* Stored x/non-x flag */ + unsigned x_flag; + } memory_word_dynamic; + } u_; +}; + +static void get_real_from_lval(ivl_lval_t lval, struct real_lval_info*slice) +{ + ivl_signal_t sig = ivl_lval_sig(lval); + ivl_expr_t word_ix = ivl_lval_idx(lval); + unsigned long use_word = 0; + + /* If the word index is a constant expression, then evaluate + it to select the word, and pay no further heed to the + expression itself. */ + if (word_ix && number_is_immediate(word_ix, IMM_WID, 0)) { + assert(! number_is_unknown(word_ix)); + use_word = get_number_immediate(word_ix); + word_ix = 0; + } + + if (ivl_signal_dimensions(sig)==0 && word_ix==0) { + + slice->type = REAL_SIMPLE_WORD; + slice->u_.simple_word.use_word = use_word; + fprintf(vvp_out, " %%load/real v%p_%lu;\n", sig, use_word); + + } else if (ivl_signal_dimensions(sig) > 0 && word_ix == 0) { + + slice->type = REAL_MEMORY_WORD_STATIC; + slice->u_.memory_word_static.use_word = use_word; + if (use_word < ivl_signal_array_count(sig)) { + fprintf(vvp_out, " %%ix/load 3, %lu, 0;\n", + use_word); + fprintf(vvp_out, " %%load/reala v%p, 3;\n", sig); + } else { + fprintf(vvp_out, " %%pushi/real 0, 0;\n"); + } + + } else if (ivl_signal_dimensions(sig) > 0 && word_ix != 0) { + + slice->type = REAL_MEMORY_WORD_DYNAMIC; + + slice->u_.memory_word_dynamic.word_idx_reg = allocate_word(); + slice->u_.memory_word_dynamic.x_flag = allocate_flag(); + + draw_eval_expr_into_integer(word_ix, slice->u_.memory_word_dynamic.word_idx_reg); + fprintf(vvp_out, " %%flag_mov %u, 4;\n", slice->u_.memory_word_dynamic.x_flag); + fprintf(vvp_out, " %%load/reala v%p, %d;\n", sig, slice->u_.memory_word_dynamic.word_idx_reg); + + } else { + assert(0); + } +} + +static void put_real_to_lval(ivl_lval_t lval, struct real_lval_info*slice) +{ + ivl_signal_t sig = ivl_lval_sig(lval); + + switch (slice->type) { + default: + fprintf(vvp_out, " ; XXXX slice->type=%d\n", slice->type); + assert(0); + break; + + case REAL_SIMPLE_WORD: + fprintf(vvp_out, " %%store/real v%p_%lu;\n", + sig, slice->u_.simple_word.use_word); + break; + + case REAL_MEMORY_WORD_STATIC: + if (slice->u_.memory_word_static.use_word < ivl_signal_array_count(sig)) { + int word_idx = allocate_word(); + fprintf(vvp_out," %%flag_set/imm 4, 0;\n"); + fprintf(vvp_out," %%ix/load %d, %lu, 0;\n", word_idx, slice->u_.memory_word_static.use_word); + fprintf(vvp_out," %%store/reala v%p, %d;\n", sig, word_idx); + clr_word(word_idx); + } else { + fprintf(vvp_out," ; Skip this slice write to v%p [%lu]\n", sig, slice->u_.memory_word_static.use_word); + } + break; + + case REAL_MEMORY_WORD_DYNAMIC: + fprintf(vvp_out, " %%flag_mov 4, %u;\n", slice->u_.memory_word_dynamic.x_flag); + fprintf(vvp_out, " %%store/reala v%p, %d;\n", sig, slice->u_.memory_word_dynamic.word_idx_reg); + clr_word(slice->u_.memory_word_dynamic.word_idx_reg); + clr_flag(slice->u_.memory_word_dynamic.x_flag); + break; + + } +} + +static void store_real_to_lval(ivl_lval_t lval) { - ivl_lval_t lval; ivl_signal_t var; - assert(ivl_stmt_opcode(net) == 0); - - draw_eval_real(ivl_stmt_rval(net)); - - assert(ivl_stmt_lvals(net) == 1); - lval = ivl_stmt_lval(net, 0); var = ivl_lval_sig(lval); assert(var != 0); if (ivl_signal_dimensions(var) == 0) { fprintf(vvp_out, " %%store/real v%p_0;\n", var); - return 0; + return; } // For now, only support 1-dimensional arrays. @@ -612,7 +714,66 @@ static int show_stmt_assign_sig_real(ivl_statement_t net) } clr_word(word_ix); +} +/* + * This function assigns a value to a real variable. This is destined + * for /dev/null when typed ivl_signal_t takes over all the real + * variable support. + */ +static int show_stmt_assign_sig_real(ivl_statement_t net) +{ + struct real_lval_info*slice = 0; + ivl_lval_t lval; + + assert(ivl_stmt_lvals(net) == 1); + lval = ivl_stmt_lval(net, 0); + + /* If this is a compressed assignment, then get the contents + of the l-value. We need this value as part of the r-value + calculation. */ + if (ivl_stmt_opcode(net) != 0) { + fprintf(vvp_out, " ; show_stmt_assign_real: Get l-value for compressed %c= operand\n", ivl_stmt_opcode(net)); + slice = calloc(1, sizeof(struct real_lval_info)); + get_real_from_lval(lval, slice); + } + + draw_eval_real(ivl_stmt_rval(net)); + + switch (ivl_stmt_opcode(net)) { + case 0: + store_real_to_lval(lval); + if (slice) free(slice); + return 0; + + case '+': + fprintf(vvp_out, " %%add/wr;\n"); + break; + + case '-': + fprintf(vvp_out, " %%sub/wr;\n"); + break; + + case '*': + fprintf(vvp_out, " %%mul/wr;\n"); + break; + + case '/': + fprintf(vvp_out, " %%div/wr;\n"); + break; + + case '%': + fprintf(vvp_out, " %%mod/wr;\n"); + break; + + default: + fprintf(vvp_out, "; UNSUPPORTED ASSIGNMENT OPCODE: %c\n", ivl_stmt_opcode(net)); + assert(0); + break; + } + + put_real_to_lval(lval, slice); + free(slice); return 0; } From a391c3ae281f053910777749aacb6646b54dcb9b Mon Sep 17 00:00:00 2001 From: Martin Whitaker Date: Sat, 5 Mar 2016 17:43:25 +0000 Subject: [PATCH 08/51] Fix for br1000 - avoid infinite loop when processes share a for-loop index. (cherry picked from commit b4d5248c67ec83cbcf9b936b9f49711dc94f7c75) --- compiler.h | 7 ++++++- driver/iverilog.man.in | 15 +++++++++++++-- driver/main.c | 13 +++++++++++-- main.cc | 7 +++++++ net_nex_input.cc | 11 ++++++++++- 5 files changed, 47 insertions(+), 6 deletions(-) diff --git a/compiler.h b/compiler.h index 7c545bed8..ca1e36732 100644 --- a/compiler.h +++ b/compiler.h @@ -1,7 +1,7 @@ #ifndef IVL_compiler_H #define IVL_compiler_H /* - * Copyright (c) 1999-2014 Stephen Williams (steve@icarus.com) + * Copyright (c) 1999-2016 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 @@ -186,6 +186,11 @@ extern bool gn_strict_ca_eval_flag; standard expression width rules. */ extern bool gn_strict_expr_width_flag; +/* If this flag is true, then don't add a for-loop control variable + to an implicit event_expression list if it is only used inside the + loop. */ +extern bool gn_shared_loop_index_flag; + /* If variables can be converted to uwires by a continuous assignment (assuming no procedural assign, then return true. This will be true for SystemVerilog */ diff --git a/driver/iverilog.man.in b/driver/iverilog.man.in index bf7d986be..2157df516 100644 --- a/driver/iverilog.man.in +++ b/driver/iverilog.man.in @@ -1,4 +1,4 @@ -.TH iverilog 1 "Aug 7th, 2015" "" "Version %M.%n%E" +.TH iverilog 1 "Mar 5th, 2016" "" "Version %M.%n%E" .SH NAME iverilog - Icarus Verilog compiler @@ -133,6 +133,17 @@ parameter assignment is evaluated as a lossless expression, as is any expression containing an unsized constant number, and unsized constant numbers are not truncated to integer width. .TP 8 +.B -gshared-loop-index\fI|\fP-gno-shared-loop-index +Enable (default) or disable the exclusion of for-loop control variables +from implicit event_expression lists. When enabled, if a for-loop control +variable (loop index) is only used inside the for-loop statement, the +compiler will not include it in an implicit event_expression list it +calculates for that statement or any enclosing statement. This allows +the same control variable to be used in multiple processes without risk +of entering an infinite loop caused by each process triggering all other +processes that use the same varaible. For strict compliance with the +standards, this behaviour should be disabled. +.TP 8 .B -I\fIincludedir\fP Append directory \fIincludedir\fP to list of directories searched for Verilog include files. The \fB\-I\fP switch may be used many times @@ -532,7 +543,7 @@ Tips on using, debugging, and developing the compiler can be found at .SH COPYRIGHT .nf -Copyright \(co 2002\-2015 Stephen Williams +Copyright \(co 2002\-2016 Stephen Williams This document can be freely redistributed according to the terms of the GNU General Public License version 2.0 diff --git a/driver/main.c b/driver/main.c index 7144aad5a..1cc3c7b5b 100644 --- a/driver/main.c +++ b/driver/main.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000-2015 Stephen Williams (steve@icarus.com) + * Copyright (c) 2000-2016 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 @@ -128,6 +128,7 @@ const char*gen_icarus = "icarus-misc"; const char*gen_io_range_error = "io-range-error"; const char*gen_strict_ca_eval = "no-strict-ca-eval"; const char*gen_strict_expr_width = "no-strict-expr-width"; +const char*gen_shared_loop_index = "shared-loop-index"; const char*gen_verilog_ams = "no-verilog-ams"; /* Boolean: true means use a default include dir, false means don't */ @@ -730,6 +731,12 @@ static int process_generation(const char*name) else if (strcmp(name,"no-strict-expr-width") == 0) gen_strict_expr_width = "no-strict-expr-width"; + else if (strcmp(name,"shared-loop-index") == 0) + gen_shared_loop_index = "shared-loop-index"; + + else if (strcmp(name,"no-shared-loop-index") == 0) + gen_shared_loop_index = "no-shared-loop-index"; + else if (strcmp(name,"verilog-ams") == 0) gen_verilog_ams = "verilog-ams"; @@ -755,7 +762,8 @@ static int process_generation(const char*name) " icarus-misc | no-icarus-misc\n" " io-range-error | no-io-range-error\n" " strict-ca-eval | no-strict-ca-eval\n" - " strict-expr-width | no-strict-expr-width\n"); + " strict-expr-width | no-strict-expr-width\n" + " shared-loop-index | no-shared-loop-index\n"); return 1; } @@ -1108,6 +1116,7 @@ int main(int argc, char **argv) fprintf(iconfig_file, "generation:%s\n", gen_io_range_error); fprintf(iconfig_file, "generation:%s\n", gen_strict_ca_eval); fprintf(iconfig_file, "generation:%s\n", gen_strict_expr_width); + fprintf(iconfig_file, "generation:%s\n", gen_shared_loop_index); fprintf(iconfig_file, "generation:%s\n", gen_verilog_ams); fprintf(iconfig_file, "generation:%s\n", gen_icarus); fprintf(iconfig_file, "warnings:%s\n", warning_flags); diff --git a/main.cc b/main.cc index f0a8dbf17..7ab9510c1 100644 --- a/main.cc +++ b/main.cc @@ -108,6 +108,7 @@ bool gn_assertions_flag = true; bool gn_io_range_error_flag = true; bool gn_strict_ca_eval_flag = false; bool gn_strict_expr_width_flag = false; +bool gn_shared_loop_index_flag = true; bool gn_verilog_ams_flag = false; /* @@ -344,6 +345,12 @@ static void process_generation_flag(const char*gen) } else if (strcmp(gen,"no-strict-expr-width") == 0) { gn_strict_expr_width_flag = false; + } else if (strcmp(gen,"shared-loop-index") == 0) { + gn_shared_loop_index_flag = true; + + } else if (strcmp(gen,"no-shared-loop-index") == 0) { + gn_shared_loop_index_flag = false; + } else { } } diff --git a/net_nex_input.cc b/net_nex_input.cc index aff41f281..4cb91fc24 100644 --- a/net_nex_input.cc +++ b/net_nex_input.cc @@ -1,5 +1,5 @@ /* - * Copyright (c) 2002-2013 Stephen Williams (steve@icarus.com) + * Copyright (c) 2002-2016 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 @@ -427,6 +427,15 @@ NexusSet* NetForLoop::nex_input(bool rem_out) result->add(*tmp); delete tmp; + if (gn_shared_loop_index_flag) { + tmp = new NexusSet(); + for (unsigned idx = 0 ; idx < index_->pin_count() ; idx += 1) + tmp->add(index_->pin(idx).nexus(), 0, index_->vector_width()); + + result->rem(*tmp); + delete tmp; + } + return result; } From 583a31c1212481b2081aaebf171fbdb98d6e0648 Mon Sep 17 00:00:00 2001 From: Martin Whitaker Date: Sat, 5 Mar 2016 17:52:58 +0000 Subject: [PATCH 09/51] Changed default for -gshared-loop-index to false. --- driver/iverilog.man.in | 2 +- driver/main.c | 2 +- main.cc | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/driver/iverilog.man.in b/driver/iverilog.man.in index 2157df516..2d3a62344 100644 --- a/driver/iverilog.man.in +++ b/driver/iverilog.man.in @@ -134,7 +134,7 @@ expression containing an unsized constant number, and unsized constant numbers are not truncated to integer width. .TP 8 .B -gshared-loop-index\fI|\fP-gno-shared-loop-index -Enable (default) or disable the exclusion of for-loop control variables +Enable or disable (default) the exclusion of for-loop control variables from implicit event_expression lists. When enabled, if a for-loop control variable (loop index) is only used inside the for-loop statement, the compiler will not include it in an implicit event_expression list it diff --git a/driver/main.c b/driver/main.c index 1cc3c7b5b..c370ac844 100644 --- a/driver/main.c +++ b/driver/main.c @@ -128,7 +128,7 @@ const char*gen_icarus = "icarus-misc"; const char*gen_io_range_error = "io-range-error"; const char*gen_strict_ca_eval = "no-strict-ca-eval"; const char*gen_strict_expr_width = "no-strict-expr-width"; -const char*gen_shared_loop_index = "shared-loop-index"; +const char*gen_shared_loop_index = "no-shared-loop-index"; const char*gen_verilog_ams = "no-verilog-ams"; /* Boolean: true means use a default include dir, false means don't */ diff --git a/main.cc b/main.cc index 7ab9510c1..b3bd130f2 100644 --- a/main.cc +++ b/main.cc @@ -108,7 +108,7 @@ bool gn_assertions_flag = true; bool gn_io_range_error_flag = true; bool gn_strict_ca_eval_flag = false; bool gn_strict_expr_width_flag = false; -bool gn_shared_loop_index_flag = true; +bool gn_shared_loop_index_flag = false; bool gn_verilog_ams_flag = false; /* From 3b577340ad1880ab98ef92606334e078cb7c30fb Mon Sep 17 00:00:00 2001 From: Martin Whitaker Date: Sun, 13 Mar 2016 16:38:55 +0000 Subject: [PATCH 10/51] Fix for br1001 - connect undriven wand/wor to 'bz in tgt-vvp. (cherry picked from commit dbaf2471f2d1713e48f887610ba27bedcc18e733) --- tgt-vvp/draw_net_input.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/tgt-vvp/draw_net_input.c b/tgt-vvp/draw_net_input.c index e2f94fb20..f95eee330 100644 --- a/tgt-vvp/draw_net_input.c +++ b/tgt-vvp/draw_net_input.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001-2015 Stephen Williams (steve@icarus.com) + * Copyright (c) 2001-2016 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 @@ -711,6 +711,8 @@ static void draw_net_input_x(ivl_nexus_t nex, tmp += strlen(tmp); switch (res) { case IVL_SIT_TRI: + case IVL_SIT_TRIAND: + case IVL_SIT_TRIOR: case IVL_SIT_UWIRE: for (jdx = 0 ; jdx < wid ; jdx += 1) *tmp++ = 'z'; From 88cd5534c4e33ad5d981236f111fd1478c820680 Mon Sep 17 00:00:00 2001 From: Cary R Date: Tue, 15 Mar 2016 03:48:12 -0700 Subject: [PATCH 11/51] Use correct type when printing supply pull message --- elab_sig.cc | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/elab_sig.cc b/elab_sig.cc index a643a1d9c..4429c0e45 100644 --- a/elab_sig.cc +++ b/elab_sig.cc @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000-2015 Stephen Williams (steve@icarus.com) + * Copyright (c) 2000-2016 Stephen Williams (steve@icarus.com) * Copyright CERN 2012 / Stephen Williams (steve@icarus.com) * * This source code is free software; you can redistribute it @@ -1185,6 +1185,14 @@ NetNet* PWire::elaborate_sig(Design*des, NetScope*scope) const NetLogic*pull = 0; if (wtype == NetNet::SUPPLY0 || wtype == NetNet::SUPPLY1) { + if (debug_elaborate) { + cerr << get_fileline() << ": debug: " + << "Generate a SUPPLY pull for the "; + if (wtype == NetNet::SUPPLY0) cerr << "supply0"; + else cerr << "supply1"; + cerr << " net." << endl; + } + NetLogic::TYPE pull_type = (wtype==NetNet::SUPPLY1) ? NetLogic::PULLUP : NetLogic::PULLDOWN; @@ -1195,14 +1203,6 @@ NetNet* PWire::elaborate_sig(Design*des, NetScope*scope) const pull->pin(0).drive1(IVL_DR_SUPPLY); des->add_node(pull); wtype = NetNet::WIRE; - - if (debug_elaborate) { - cerr << get_fileline() << ": debug: " - << "Generate a SUPPLY pull for the "; - if (wtype == NetNet::SUPPLY0) cerr << "supply0"; - else cerr << "supply1"; - cerr << " net." << endl; - } } From d9be5318f935f2fd62b3473296e831e3ea30c8f0 Mon Sep 17 00:00:00 2001 From: Cary R Date: Thu, 24 Mar 2016 20:23:02 -0700 Subject: [PATCH 12/51] Fix a cppcheck warning --- vpi/lxt2_write.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/vpi/lxt2_write.c b/vpi/lxt2_write.c index b50aa2359..1ebf3e179 100644 --- a/vpi/lxt2_write.c +++ b/vpi/lxt2_write.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003-2012 Tony Bybell. + * Copyright (c) 2003-2016 Tony Bybell. * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), @@ -1029,12 +1029,12 @@ for(i=len;i>0;i--) if(!i) { - sprintf(tname, "%s_%03d.lxt", lt->lxtname, ++lt->break_number); + sprintf(tname, "%s_%03u.lxt", lt->lxtname, ++lt->break_number); } else { memcpy(tname, lt->lxtname, i); - sprintf(tname+i, "_%03d.lxt", ++lt->break_number); + sprintf(tname+i, "_%03u.lxt", ++lt->break_number); } f2 = fopen(tname, "wb"); From 04ae07f03c0a89d94f9a358bbce135c4dd7636be Mon Sep 17 00:00:00 2001 From: Martin Whitaker Date: Fri, 25 Mar 2016 21:46:04 +0000 Subject: [PATCH 13/51] Fix for GitHub issue #94 - enhance support for SystemVerilog size casting. Allow the size expression to be any constant expression. Also ensure that the expression width and type are correctly calculated and applied. (cherry picked from commit dc1c3a4043f222250ce49b47d6d90072737749fb) --- PExpr.cc | 4 ++-- PExpr.h | 6 +++--- elab_expr.cc | 48 +++++++++++++++++++++++++++++++++++++++-------- netmisc.h | 23 ++++++++++++++++++++++- pad_to_width.cc | 50 ++++++++++++++++++++++++++++++++++++++++++++++++- parse.y | 33 ++++++++++++++++++-------------- pform_dump.cc | 4 ++-- 7 files changed, 137 insertions(+), 31 deletions(-) diff --git a/PExpr.cc b/PExpr.cc index 7e0e3693f..bce998419 100644 --- a/PExpr.cc +++ b/PExpr.cc @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998-2012 Stephen Williams + * Copyright (c) 1998-2016 Stephen Williams * Copyright CERN 2013 / Stephen Williams (steve@icarus.com) * * This source code is free software; you can redistribute it @@ -137,7 +137,7 @@ bool PEBinary::has_aa_term(Design*des, NetScope*scope) const return left_->has_aa_term(des, scope) || right_->has_aa_term(des, scope); } -PECastSize::PECastSize(unsigned si, PExpr*b) +PECastSize::PECastSize(PExpr*si, PExpr*b) : size_(si), base_(b) { } diff --git a/PExpr.h b/PExpr.h index 55f0fb237..adf17a137 100644 --- a/PExpr.h +++ b/PExpr.h @@ -1,7 +1,7 @@ #ifndef IVL_PExpr_H #define IVL_PExpr_H /* - * Copyright (c) 1998-2014 Stephen Williams + * Copyright (c) 1998-2016 Stephen Williams * Copyright CERN 2013 / Stephen Williams (steve@icarus.com) * * This source code is free software; you can redistribute it @@ -971,7 +971,7 @@ class PECallFunction : public PExpr { class PECastSize : public PExpr { public: - explicit PECastSize(unsigned expr_wid, PExpr*base); + explicit PECastSize(PExpr*size, PExpr*base); ~PECastSize(); void dump(ostream &out) const; @@ -984,7 +984,7 @@ class PECastSize : public PExpr { width_mode_t&mode); private: - unsigned size_; + PExpr* size_; PExpr* base_; }; diff --git a/elab_expr.cc b/elab_expr.cc index 9e38a134c..2f92afa27 100644 --- a/elab_expr.cc +++ b/elab_expr.cc @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999-2015 Stephen Williams (steve@icarus.com) + * Copyright (c) 1999-2016 Stephen Williams (steve@icarus.com) * Copyright CERN 2013 / Stephen Williams (steve@icarus.com) * * This source code is free software; you can redistribute it @@ -2521,22 +2521,54 @@ NetExpr* PECallFunction::elaborate_expr_method_(Design*des, NetScope*scope, unsigned PECastSize::test_width(Design*des, NetScope*scope, width_mode_t&) { - expr_width_ = size_; + ivl_assert(*this, size_); + ivl_assert(*this, base_); + + NetExpr*size_ex = elab_and_eval(des, scope, size_, -1, true); + NetEConst*size_ce = dynamic_cast(size_ex); + expr_width_ = size_ce ? size_ce->value().as_ulong() : 0; + delete size_ex; + if (expr_width_ == 0) { + cerr << get_fileline() << ": error: Cast size expression " + "must be constant and greater than zero." << endl; + des->errors += 1; + return 0; + } width_mode_t tmp_mode = PExpr::SIZED; base_->test_width(des, scope, tmp_mode); - return size_; + if (!type_is_vectorable(base_->expr_type())) { + cerr << get_fileline() << ": error: Cast base expression " + "must be a vector type." << endl; + des->errors += 1; + return 0; + } + + expr_type_ = base_->expr_type(); + min_width_ = expr_width_; + signed_flag_ = base_->has_sign(); + + return expr_width_; } NetExpr* PECastSize::elaborate_expr(Design*des, NetScope*scope, - unsigned, unsigned) const + unsigned expr_wid, unsigned flags) const { - NetExpr*sub = base_->elaborate_expr(des, scope, base_->expr_width(), NO_FLAGS); - NetESelect*sel = new NetESelect(sub, 0, size_); - sel->set_line(*this); + flags &= ~SYS_TASK_ARG; // don't propagate the SYS_TASK_ARG flag - return sel; + ivl_assert(*this, size_); + ivl_assert(*this, base_); + + NetExpr*sub = base_->elaborate_expr(des, scope, base_->expr_width(), flags); + + // Perform the cast. The extension method (zero/sign), if needed, + // depends on the type of the base expression. + NetExpr*tmp = cast_to_width(sub, expr_width_, base_->has_sign(), *this); + + // Pad up to the expression width. The extension method (zero/sign) + // depends on the type of enclosing expression. + return pad_to_width(tmp, expr_wid, signed_flag_, *this); } unsigned PECastType::test_width(Design*des, NetScope*scope, width_mode_t&wid) diff --git a/netmisc.h b/netmisc.h index 4123d4f61..2e2297b15 100644 --- a/netmisc.h +++ b/netmisc.h @@ -1,7 +1,7 @@ #ifndef IVL_netmisc_H #define IVL_netmisc_H /* - * Copyright (c) 1999-2014 Stephen Williams (steve@icarus.com) + * Copyright (c) 1999-2016 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 @@ -66,6 +66,27 @@ inline NetScope* symbol_search(const LineInfo*li, * enough. */ extern NetExpr*pad_to_width(NetExpr*expr, unsigned wid, const LineInfo&info); + +/* + * This function transforms an expression by either zero or sign extending + * the high bits until the expression has the desired width. This may mean + * not transforming the expression at all, if it is already wide enough. + * The extension method and the returned expression type is determined by + * signed_flag. + */ +extern NetExpr*pad_to_width(NetExpr*expr, unsigned wid, bool signed_flag, + const LineInfo&info); + +/* + * This function transforms an expression by either zero or sign extending + * or discarding the high bits until the expression has the desired width. + * This may mean not transforming the expression at all, if it is already + * the correct width. The extension method (if needed) and the returned + * expression type is determined by signed_flag. + */ +extern NetExpr*cast_to_width(NetExpr*expr, unsigned wid, bool signed_flag, + const LineInfo&info); + extern NetNet*pad_to_width(Design*des, NetNet*n, unsigned w, const LineInfo&info); diff --git a/pad_to_width.cc b/pad_to_width.cc index 32ba6c61d..85f8d74e4 100644 --- a/pad_to_width.cc +++ b/pad_to_width.cc @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999-2011 Stephen Williams (steve@icarus.com) + * Copyright (c) 1999-2016 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 @@ -51,6 +51,54 @@ NetExpr*pad_to_width(NetExpr*expr, unsigned wid, const LineInfo&info) return tmp; } +NetExpr*pad_to_width(NetExpr*expr, unsigned wid, bool signed_flag, + const LineInfo&info) +{ + if (wid <= expr->expr_width()) { + expr->cast_signed(signed_flag); + return expr; + } + + /* If the expression is a const, then replace it with a wider + const. This is a more efficient result. */ + if (NetEConst*tmp = dynamic_cast(expr)) { + verinum oval = tmp->value(); + oval.has_sign(signed_flag); + oval = pad_to_width(oval, wid); + tmp = new NetEConst(oval); + tmp->set_line(info); + delete expr; + return tmp; + } + + NetESelect*tmp = new NetESelect(expr, 0, wid); + tmp->cast_signed(signed_flag); + tmp->set_line(info); + return tmp; +} + +NetExpr*cast_to_width(NetExpr*expr, unsigned wid, bool signed_flag, + const LineInfo&info) +{ + /* If the expression is a const, then replace it with a new + const. This is a more efficient result. */ + if (NetEConst*tmp = dynamic_cast(expr)) { + tmp->cast_signed(signed_flag); + if (wid != tmp->expr_width()) { + tmp = new NetEConst(verinum(tmp->value(), wid)); + tmp->set_line(info); + delete expr; + } + return tmp; + } + + NetESelect*tmp = new NetESelect(expr, 0, wid); + tmp->cast_signed(signed_flag); + tmp->set_line(info); + + return tmp; +} + /* * Pad a NetNet to the desired vector width by concatenating a * NetConst of constant zeros. Use a NetConcat node to do the diff --git a/parse.y b/parse.y index 806b58713..739bf9b73 100644 --- a/parse.y +++ b/parse.y @@ -607,7 +607,8 @@ static void current_function_set_statement(const YYLTYPE&loc, vector %type gate_instance_list %type hierarchy_identifier implicit_class_handle -%type assignment_pattern expression expr_primary expr_mintypmax +%type assignment_pattern expression expr_mintypmax +%type expr_primary_or_typename expr_primary %type class_new dynamic_array_new %type inc_or_dec_expression inside_expression lpvalue %type branch_probe_expression streaming_concatenation @@ -3033,7 +3034,7 @@ branch_probe_expression ; expression - : expr_primary + : expr_primary_or_typename { $$ = $1; } | inc_or_dec_expression { $$ = $1; } @@ -3328,6 +3329,20 @@ expression_list_proper } ; +expr_primary_or_typename + : expr_primary + + /* There are a few special cases (notably $bits argument) where the + expression may be a type name. Let the elaborator sort this out. */ + | TYPE_IDENTIFIER + { PETypename*tmp = new PETypename($1.type); + FILE_NAME(tmp,@1); + $$ = tmp; + delete[]$1.text; + } + + ; + expr_primary : number { assert($1); @@ -3369,15 +3384,6 @@ expr_primary delete[]$1; } - /* There are a few special cases (notably $bits argument) where the - expression may be a type name. Let the elaborator sort this out. */ - | TYPE_IDENTIFIER - { PETypename*tmp = new PETypename($1.type); - FILE_NAME(tmp,@1); - $$ = tmp; - delete[]$1.text; - } - /* The hierarchy_identifier rule matches simple identifiers as well as indexed arrays and part selects */ @@ -3681,12 +3687,11 @@ expr_primary /* Cast expressions are primaries */ - | DEC_NUMBER '\'' '(' expression ')' + | expr_primary '\'' '(' expression ')' { PExpr*base = $4; if (gn_system_verilog()) { - PECastSize*tmp = new PECastSize($1->as_ulong(), base); + PECastSize*tmp = new PECastSize($1, base); FILE_NAME(tmp, @1); - delete $1; $$ = tmp; } else { yyerror(@1, "error: Size cast requires SystemVerilog."); diff --git a/pform_dump.cc b/pform_dump.cc index 4cbd994ec..afd2ddc27 100644 --- a/pform_dump.cc +++ b/pform_dump.cc @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998-2014 Stephen Williams (steve@icarus.com) + * Copyright (c) 1998-2016 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 @@ -318,7 +318,7 @@ void PECallFunction::dump(ostream &out) const void PECastSize::dump(ostream &out) const { - out << size_ << "'("; + out << *size_ << "'("; base_->dump(out); out << ")"; } From 8bd4e9d481e258d922db026f13f0ffb37571ff76 Mon Sep 17 00:00:00 2001 From: Martin Whitaker Date: Fri, 25 Mar 2016 22:23:45 +0000 Subject: [PATCH 14/51] Refactor to use new pad_to_width/cast_to_width functions. (cherry picked from commit 7f475d4210aab7af478d047476361c86797d6285) --- elab_expr.cc | 69 ++++++++++--------------------------------------- netmisc.h | 15 +++++------ pad_to_width.cc | 27 ------------------- 3 files changed, 21 insertions(+), 90 deletions(-) diff --git a/elab_expr.cc b/elab_expr.cc index 2f92afa27..c1923b83c 100644 --- a/elab_expr.cc +++ b/elab_expr.cc @@ -675,10 +675,7 @@ NetExpr* PEBComp::elaborate_expr(Design*des, NetScope*scope, NetExpr*tmp = new NetEBComp(op_, lp, rp); tmp->set_line(*this); - tmp = pad_to_width(tmp, expr_wid, *this); - tmp->cast_signed(signed_flag_); - - return tmp; + return pad_to_width(tmp, expr_wid, signed_flag_, *this); } unsigned PEBLogic::test_width(Design*, NetScope*, width_mode_t&) @@ -716,10 +713,7 @@ NetExpr*PEBLogic::elaborate_expr(Design*des, NetScope*scope, NetExpr*tmp = new NetEBLogic(op_, lp, rp); tmp->set_line(*this); - tmp = pad_to_width(tmp, expr_wid, *this); - tmp->cast_signed(signed_flag_); - - return tmp; + return pad_to_width(tmp, expr_wid, signed_flag_, *this); } unsigned PEBLeftWidth::test_width(Design*des, NetScope*scope, width_mode_t&mode) @@ -1035,8 +1029,7 @@ NetExpr*PEBShift::elaborate_expr_leaf(Design*des, NetExpr*lp, NetExpr*rp, tmp->set_line(*this); tmp = new NetESelect(lp, tmp, 1); tmp->set_line(*this); - tmp = pad_to_width(tmp, expr_wid, *this); - tmp->cast_signed(true); + tmp = pad_to_width(tmp, expr_wid, true, *this); delete rp; return tmp; @@ -1414,23 +1407,7 @@ NetExpr*PECallFunction::cast_to_width_(NetExpr*expr, unsigned wid) const << " from expr_width()=" << expr->expr_width() << endl; } - /* If the expression is a const, then replace it with a new - const. This is a more efficient result. */ - if (NetEConst*tmp = dynamic_cast(expr)) { - tmp->cast_signed(signed_flag_); - if (wid != tmp->expr_width()) { - tmp = new NetEConst(verinum(tmp->value(), wid)); - tmp->set_line(*this); - delete expr; - } - return tmp; - } - - NetESelect*tmp = new NetESelect(expr, 0, wid); - tmp->cast_signed(signed_flag_); - tmp->set_line(*this); - - return tmp; + return cast_to_width(expr, wid, signed_flag_, *this); } /* @@ -1606,10 +1583,7 @@ NetExpr* PECallFunction::elaborate_sfunc_(Design*des, NetScope*scope, if (missing_parms || parm_errors) return 0; - NetExpr*tmp = pad_to_width(fun, expr_wid, *this); - tmp->cast_signed(signed_flag_); - - return tmp; + return pad_to_width(fun, expr_wid, signed_flag_, *this); } NetExpr* PECallFunction::elaborate_access_func_(Design*des, NetScope*scope, @@ -1666,10 +1640,7 @@ NetExpr* PECallFunction::elaborate_access_func_(Design*des, NetScope*scope, NetExpr*tmp = new NetEAccess(branch, nature); tmp->set_line(*this); - tmp = pad_to_width(tmp, expr_wid, *this); - tmp->cast_signed(signed_flag_); - - return tmp; + return pad_to_width(tmp, expr_wid, signed_flag_, *this); } /* @@ -2281,10 +2252,7 @@ NetExpr* PECallFunction::elaborate_base_(Design*des, NetScope*scope, NetScope*ds if(res->darray_type()) return func; - NetExpr*tmp = pad_to_width(func, expr_wid, *this); - tmp->cast_signed(signed_flag_); - - return tmp; + return pad_to_width(func, expr_wid, signed_flag_, *this); } cerr << get_fileline() << ": internal error: Unable to locate " @@ -2883,8 +2851,7 @@ NetExpr* PEConcat::elaborate_expr(Design*des, NetScope*scope, return 0; } - NetExpr*tmp = pad_to_width(concat, expr_wid, *this); - tmp->cast_signed(signed_flag_); + NetExpr*tmp = pad_to_width(concat, expr_wid, signed_flag_, *this); concat_depth -= 1; return tmp; @@ -3801,10 +3768,7 @@ NetExpr* PEIdent::elaborate_expr(Design*des, NetScope*scope, if (!tmp) return 0; - tmp = pad_to_width(tmp, expr_wid, *this); - tmp->cast_signed(signed_flag_); - - return tmp; + return pad_to_width(tmp, expr_wid, signed_flag_, *this); } // If the identifier names a signal (a register or wire) @@ -3840,10 +3804,7 @@ NetExpr* PEIdent::elaborate_expr(Design*des, NetScope*scope, << ", tmp=" << *tmp << endl; } - tmp = pad_to_width(tmp, expr_wid, *this); - tmp->cast_signed(signed_flag_); - - return tmp; + return pad_to_width(tmp, expr_wid, signed_flag_, *this); } // If the identifier is a named event @@ -3943,9 +3904,7 @@ NetExpr* PEIdent::elaborate_expr(Design*des, NetScope*scope, member_comp); if (!tmp) return 0; - tmp = pad_to_width(tmp, expr_wid, *this); - tmp->cast_signed(signed_flag_); - return tmp; + return pad_to_width(tmp, expr_wid, signed_flag_, *this); } if (net->class_type() != 0) { @@ -4524,7 +4483,7 @@ NetExpr* PEIdent::elaborate_expr_param_(Design*des, << "Elaborate parameter <" << path_ << "> as enumeration constant." << *etmp << endl; tmp = etmp->dup_expr(); - tmp = pad_to_width(tmp, expr_wid, *this); + tmp = pad_to_width(tmp, expr_wid, signed_flag_, *this); } else { perm_string name = peek_tail_name(path_); @@ -6114,7 +6073,7 @@ NetExpr* PEUnary::elaborate_expr(Design*des, NetScope*scope, } tmp->set_line(*this); } - tmp = pad_to_width(tmp, expr_wid, *this); + tmp = pad_to_width(tmp, expr_wid, signed_flag_, *this); break; case '&': // Reduction AND @@ -6132,7 +6091,7 @@ NetExpr* PEUnary::elaborate_expr(Design*des, NetScope*scope, } tmp = new NetEUReduce(op_, ip); tmp->set_line(*this); - tmp = pad_to_width(tmp, expr_wid, *this); + tmp = pad_to_width(tmp, expr_wid, signed_flag_, *this); break; case '~': diff --git a/netmisc.h b/netmisc.h index 2e2297b15..e0569bce0 100644 --- a/netmisc.h +++ b/netmisc.h @@ -59,14 +59,6 @@ inline NetScope* symbol_search(const LineInfo*li, return symbol_search(li, des, start, path, net, par, eve, ex1, ex2); } -/* - * This function transforms an expression by padding the high bits - * with V0 until the expression has the desired width. This may mean - * not transforming the expression at all, if it is already wide - * enough. - */ -extern NetExpr*pad_to_width(NetExpr*expr, unsigned wid, const LineInfo&info); - /* * This function transforms an expression by either zero or sign extending * the high bits until the expression has the desired width. This may mean @@ -76,6 +68,13 @@ extern NetExpr*pad_to_width(NetExpr*expr, unsigned wid, const LineInfo&info); */ extern NetExpr*pad_to_width(NetExpr*expr, unsigned wid, bool signed_flag, const LineInfo&info); +/* + * This version determines the extension method from the base expression type. + */ +inline NetExpr*pad_to_width(NetExpr*expr, unsigned wid, const LineInfo&info) +{ + return pad_to_width(expr, wid, expr->has_sign(), info); +} /* * This function transforms an expression by either zero or sign extending diff --git a/pad_to_width.cc b/pad_to_width.cc index 85f8d74e4..32db9e6c4 100644 --- a/pad_to_width.cc +++ b/pad_to_width.cc @@ -24,33 +24,6 @@ # include "netmisc.h" -/* - * This function transforms an expression by padding the high bits - * with V0 until the expression has the desired width. This may mean - * not transforming the expression at all, if it is already wide - * enough. - */ -NetExpr*pad_to_width(NetExpr*expr, unsigned wid, const LineInfo&info) -{ - if (wid <= expr->expr_width()) - return expr; - - /* If the expression is a const, then replace it with a wider - const. This is a more efficient result. */ - if (NetEConst*tmp = dynamic_cast(expr)) { - verinum oval = pad_to_width(tmp->value(), wid); - tmp = new NetEConst(oval); - tmp->set_line(info); - delete expr; - return tmp; - } - - NetESelect*tmp = new NetESelect(expr, 0, wid); - tmp->set_line(info); - tmp->cast_signed(expr->has_sign()); - return tmp; -} - NetExpr*pad_to_width(NetExpr*expr, unsigned wid, bool signed_flag, const LineInfo&info) { From 6974613bffc36e13722d104faa7007db32bcd677 Mon Sep 17 00:00:00 2001 From: Martin Whitaker Date: Sat, 2 Apr 2016 19:49:38 +0100 Subject: [PATCH 15/51] Fix for GitHub issue #96 - support mixed constant/variable delays in vvp. If all three rise/fall/decay delay values are constant, we can use the vvp .delay statement variant that takes three literal numbers. If not, we have to use the variant that takes three net inputs. If some of the delay values are constant, we need to create constant drivers for those delay inputs. (cherry picked from commit 20104c92c8c515aa5e7364753832055131d6c6f6) --- elaborate.cc | 4 +- tgt-vvp/Makefile.in | 4 +- tgt-vvp/draw_delay.c | 127 +++++++++++++++++++++++++++++++++++++++ tgt-vvp/draw_mux.c | 40 +----------- tgt-vvp/draw_net_input.c | 69 +++------------------ tgt-vvp/draw_switch.c | 26 ++------ tgt-vvp/vvp_priv.h | 7 +++ tgt-vvp/vvp_scope.c | 66 ++------------------ 8 files changed, 160 insertions(+), 183 deletions(-) create mode 100644 tgt-vvp/draw_delay.c diff --git a/elaborate.cc b/elaborate.cc index eeb8cc27c..26acf0933 100644 --- a/elaborate.cc +++ b/elaborate.cc @@ -787,7 +787,7 @@ void PGBuiltin::elaborate(Design*des, NetScope*scope) const if (check_delay_count(des)) return; NetExpr* rise_time, *fall_time, *decay_time; - eval_delays(des, scope, rise_time, fall_time, decay_time); + eval_delays(des, scope, rise_time, fall_time, decay_time, true); struct attrib_list_t*attrib_list; unsigned attrib_list_n = 0; @@ -2000,7 +2000,7 @@ void PGModule::elaborate_udp_(Design*des, PUdp*udp, NetScope*scope) const PDelays tmp_del; tmp_del.set_delays(overrides_, false); tmp_del.eval_delays(des, scope, rise_expr, fall_expr, - decay_expr); + decay_expr, true); } } diff --git a/tgt-vvp/Makefile.in b/tgt-vvp/Makefile.in index 82a4a78e2..d09c9e709 100644 --- a/tgt-vvp/Makefile.in +++ b/tgt-vvp/Makefile.in @@ -47,8 +47,8 @@ CPPFLAGS = $(INCLUDE_PATH) @CPPFLAGS@ @DEFS@ @PICFLAG@ CFLAGS = @WARNING_FLAGS@ @WARNING_FLAGS_CC@ @CFLAGS@ LDFLAGS = @LDFLAGS@ -O = vvp.o draw_class.o draw_enum.o draw_mux.o draw_substitute.o draw_net_input.o \ - draw_switch.o draw_ufunc.o draw_vpi.o \ +O = vvp.o draw_class.o draw_delay.o draw_enum.o draw_mux.o draw_net_input.o \ + draw_substitute.o draw_switch.o draw_ufunc.o draw_vpi.o \ eval_bool.o \ eval_condit.o \ eval_expr.o eval_object.o eval_real.o eval_string.o \ diff --git a/tgt-vvp/draw_delay.c b/tgt-vvp/draw_delay.c new file mode 100644 index 000000000..1fcc92a21 --- /dev/null +++ b/tgt-vvp/draw_delay.c @@ -0,0 +1,127 @@ +/* + * Copyright (c) 2016 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 + * General Public License as published by the Free Software + * Foundation; either version 2 of the License, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +# include "vvp_priv.h" +# include +# include +# include + + +/* + * This function draws a BUFT to drive a constant delay value. + */ +static char* draw_const_net(void*ptr, char*suffix, uint64_t value) +{ + char tmp[64]; + char c4_value[69]; + unsigned idx; + c4_value[0] = 'C'; + c4_value[1] = '4'; + c4_value[2] = '<'; + for (idx = 0; idx < 64; idx += 1) { + c4_value[66-idx] = (value & 1) ? '1' : '0'; + value >>= 1; + } + c4_value[67] = '>'; + c4_value[68] = 0; + + /* Make the constant an argument to a BUFT, which is + what we use to drive the value. */ + fprintf(vvp_out, "L_%p/%s .functor BUFT 1, %s, C4<0>, C4<0>, C4<0>;\n", + ptr, suffix, c4_value); + snprintf(tmp, sizeof tmp, "L_%p/%s", ptr, suffix); + return strdup(tmp); +} + +/* + * Draw the appropriate delay statement. + */ +void draw_delay(void*ptr, unsigned wid, const char*input, ivl_expr_t rise_exp, + ivl_expr_t fall_exp, ivl_expr_t decay_exp) +{ + char tmp[64]; + if (input == 0) { + snprintf(tmp, sizeof tmp, "L_%p/d", ptr); + input = tmp; + } + + /* If the delays are all constants then process them here. */ + if (number_is_immediate(rise_exp, 64, 0) && + number_is_immediate(fall_exp, 64, 0) && + number_is_immediate(decay_exp, 64, 0)) { + + assert(! number_is_unknown(rise_exp)); + assert(! number_is_unknown(fall_exp)); + assert(! number_is_unknown(decay_exp)); + + fprintf(vvp_out, "L_%p .delay %u " + "(%" PRIu64 ",%" PRIu64 ",%" PRIu64 ") %s;\n", + ptr, wid, + get_number_immediate64(rise_exp), + get_number_immediate64(fall_exp), + get_number_immediate64(decay_exp), + input); + + /* For a variable delay we indicate only two delays by setting the + * decay time to zero. */ + } else { + char*rise_const = 0; + char*fall_const = 0; + char*decay_const = 0; + const char*rise_str; + const char*fall_str; + const char*decay_str; + + if (number_is_immediate(rise_exp, 64, 0)) { + uint64_t value = get_number_immediate64(rise_exp); + rise_str = rise_const = draw_const_net(ptr, "tr", value); + } else { + ivl_signal_t sig = ivl_expr_signal(rise_exp); + assert(sig && ivl_signal_dimensions(sig) == 0); + rise_str = draw_net_input(ivl_signal_nex(sig,0)); + } + + if (number_is_immediate(fall_exp, 64, 0)) { + uint64_t value = get_number_immediate64(fall_exp); + fall_str = fall_const = draw_const_net(ptr, "tf", value); + } else { + ivl_signal_t sig = ivl_expr_signal(fall_exp); + assert(sig && ivl_signal_dimensions(sig) == 0); + fall_str = draw_net_input(ivl_signal_nex(sig,0)); + } + + if (decay_exp == 0) { + decay_str = "0"; + } else if (number_is_immediate(decay_exp, 64, 0)) { + uint64_t value = get_number_immediate64(decay_exp); + decay_str = decay_const = draw_const_net(ptr, "td", value); + } else { + ivl_signal_t sig = ivl_expr_signal(decay_exp); + assert(sig && ivl_signal_dimensions(sig) == 0); + decay_str = draw_net_input(ivl_signal_nex(sig,0)); + } + + fprintf(vvp_out, "L_%p .delay %u %s, %s, %s, %s;\n", + ptr, wid, input, rise_str, fall_str, decay_str); + + free(rise_const); + free(fall_const); + free(decay_const); + } +} diff --git a/tgt-vvp/draw_mux.c b/tgt-vvp/draw_mux.c index 4fb27270f..41b952267 100644 --- a/tgt-vvp/draw_mux.c +++ b/tgt-vvp/draw_mux.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2002-2012 Stephen Williams (steve@icarus.com) + * Copyright (c) 2002-2016 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 @@ -51,44 +51,8 @@ static void draw_lpm_mux_ab(ivl_lpm_t net, const char*muxz) if (data_type_of_nexus(ivl_lpm_q(net)) == IVL_VT_REAL) dly_width = 0; + draw_delay(net, dly_width, 0, d_rise, d_fall, d_decay); dly = "/d"; - if (number_is_immediate(d_rise, 64, 0) && - number_is_immediate(d_fall, 64, 0) && - number_is_immediate(d_decay, 64, 0)) { - - assert( ! number_is_unknown(d_rise)); - assert( ! number_is_unknown(d_fall)); - assert( ! number_is_unknown(d_decay)); - - fprintf(vvp_out, "L_%p .delay %u (%" PRIu64 ",%" PRIu64 ",%" PRIu64 ") L_%p/d;\n", - net, dly_width, - get_number_immediate64(d_rise), - get_number_immediate64(d_fall), - get_number_immediate64(d_decay), net); - } else { - ivl_signal_t sig; - // We do not currently support calculating the decay from - // the rise and fall variable delays. - assert(d_decay != 0); - assert(ivl_expr_type(d_rise) == IVL_EX_SIGNAL); - assert(ivl_expr_type(d_fall) == IVL_EX_SIGNAL); - assert(ivl_expr_type(d_decay) == IVL_EX_SIGNAL); - - fprintf(vvp_out, "L_%p .delay %u L_%p/d", - net, dly_width, net); - - sig = ivl_expr_signal(d_rise); - assert(ivl_signal_dimensions(sig) == 0); - fprintf(vvp_out, ", v%p_0", sig); - - sig = ivl_expr_signal(d_fall); - assert(ivl_signal_dimensions(sig) == 0); - fprintf(vvp_out, ", v%p_0", sig); - - sig = ivl_expr_signal(d_decay); - assert(ivl_signal_dimensions(sig) == 0); - fprintf(vvp_out, ", v%p_0;\n", sig); - } } input[0] = draw_net_input(ivl_lpm_data(net,0)); diff --git a/tgt-vvp/draw_net_input.c b/tgt-vvp/draw_net_input.c index f95eee330..e98d394e3 100644 --- a/tgt-vvp/draw_net_input.c +++ b/tgt-vvp/draw_net_input.c @@ -330,9 +330,11 @@ static char* draw_net_input_drive(ivl_nexus_t nex, ivl_nexus_ptr_t nptr) cptr = ivl_nexus_ptr_con(nptr); if (cptr) { + char tmp[64]; char *result = 0; ivl_expr_t d_rise, d_fall, d_decay; unsigned dly_width = 0; + char *dly; /* Constants should have exactly 1 pin, with a literal value. */ assert(nptr_pin == 0); @@ -368,68 +370,17 @@ static char* draw_net_input_drive(ivl_nexus_t nex, ivl_nexus_ptr_t nptr) d_fall = ivl_const_delay(cptr, 1); d_decay = ivl_const_delay(cptr, 2); - /* We have a delayed constant, so we need to build some code. */ + dly = ""; if (d_rise != 0) { - char tmp[128]; - fprintf(vvp_out, "L_%p/d .functor BUFT 1, %s, " - "C4<0>, C4<0>, C4<0>;\n", cptr, result); - free(result); - - /* Is this a fixed or variable delay? */ - if (number_is_immediate(d_rise, 64, 0) && - number_is_immediate(d_fall, 64, 0) && - number_is_immediate(d_decay, 64, 0)) { - - assert(! number_is_unknown(d_rise)); - assert(! number_is_unknown(d_fall)); - assert(! number_is_unknown(d_decay)); - - fprintf(vvp_out, "L_%p .delay %u " - "(%" PRIu64 ",%" PRIu64 ",%" PRIu64 ") L_%p/d;\n", - cptr, dly_width, - get_number_immediate64(d_rise), - get_number_immediate64(d_fall), - get_number_immediate64(d_decay), cptr); - - } else { - ivl_signal_t sig; - // We do not currently support calculating the decay - // from the rise and fall variable delays. - assert(d_decay != 0); - assert(ivl_expr_type(d_rise) == IVL_EX_SIGNAL); - assert(ivl_expr_type(d_fall) == IVL_EX_SIGNAL); - assert(ivl_expr_type(d_decay) == IVL_EX_SIGNAL); - - fprintf(vvp_out, "L_%p .delay %u L_%p/d", - cptr, dly_width, cptr); - - sig = ivl_expr_signal(d_rise); - assert(ivl_signal_dimensions(sig) == 0); - fprintf(vvp_out, ", v%p_0", sig); - - sig = ivl_expr_signal(d_fall); - assert(ivl_signal_dimensions(sig) == 0); - fprintf(vvp_out, ", v%p_0", sig); - - sig = ivl_expr_signal(d_decay); - assert(ivl_signal_dimensions(sig) == 0); - fprintf(vvp_out, ", v%p_0;\n", sig); - } - - snprintf(tmp, sizeof tmp, "L_%p", cptr); - result = strdup(tmp); - - } else { - char tmp[64]; - fprintf(vvp_out, "L_%p .functor BUFT 1, %s, " - "C4<0>, C4<0>, C4<0>;\n", cptr, result); - free(result); - - snprintf(tmp, sizeof tmp, "L_%p", cptr); - result = strdup(tmp); + draw_delay(cptr, dly_width, 0, d_rise, d_fall, d_decay); + dly = "/d"; } + fprintf(vvp_out, "L_%p%s .functor BUFT 1, %s, C4<0>, C4<0>, C4<0>;\n", + cptr, dly, result); + free(result); - return result; + snprintf(tmp, sizeof tmp, "L_%p", cptr); + return strdup(tmp); } lpm = ivl_nexus_ptr_lpm(nptr); diff --git a/tgt-vvp/draw_switch.c b/tgt-vvp/draw_switch.c index b53d214b0..01a6f30a5 100644 --- a/tgt-vvp/draw_switch.c +++ b/tgt-vvp/draw_switch.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008-2010,2012 Stephen Williams (steve@icarus.com) + * Copyright (c) 2008-2016 Stephen Williams (steve@icarus.com) * * This source code is free software; you can redistribute it * and/or modify it in source code form under the terms of the GNU @@ -38,18 +38,6 @@ void draw_switch_in_scope(ivl_switch_t sw) ivl_expr_t fall_exp = ivl_switch_delay(sw, 1); ivl_expr_t decay_exp= ivl_switch_delay(sw, 2); - if ((rise_exp || fall_exp || decay_exp) && - (!number_is_immediate(rise_exp, 64, 0) || - number_is_unknown(rise_exp) || - !number_is_immediate(fall_exp, 64, 0) || - number_is_unknown(fall_exp) || - !number_is_immediate(decay_exp, 64, 0) || - number_is_unknown(decay_exp))) { - fprintf(stderr, "%s:%u: error: Invalid tranif delay expression.\n", - ivl_switch_file(sw), ivl_switch_lineno(sw)); - vvp_errors += 1; - } - island = ivl_switch_island(sw); if (ivl_island_flag_test(island, 0) == 0) draw_tran_island(island); @@ -67,24 +55,18 @@ void draw_switch_in_scope(ivl_switch_t sw) char str_e_buf[4 + 2*sizeof(void*)]; if (enable && rise_exp) { - assert(fall_exp && decay_exp); - /* If the enable has a delay, then generate a .delay node to delay the input by the specified amount. Do the delay outside of the island so that the island processing doesn't have to deal with it. */ const char*raw = draw_net_input(enable); + draw_delay(sw, 1, raw, rise_exp, fall_exp, decay_exp); + snprintf(str_e_buf, sizeof str_e_buf, "p%p", sw); str_e = str_e_buf; - fprintf(vvp_out, "%s/d .delay 1 " - "(%" PRIu64 ",%" PRIu64 ",%" PRIu64 ") %s;\n", - str_e, get_number_immediate64(rise_exp), - get_number_immediate64(fall_exp), - get_number_immediate64(decay_exp), raw); - - fprintf(vvp_out, "%s .import I%p, %s/d;\n", str_e, island, str_e); + fprintf(vvp_out, "%s .import I%p, L_%p;\n", str_e, island, sw); } else if (enable) { str_e = draw_island_net_input(island, enable); diff --git a/tgt-vvp/vvp_priv.h b/tgt-vvp/vvp_priv.h index 5255058cc..85a26021d 100644 --- a/tgt-vvp/vvp_priv.h +++ b/tgt-vvp/vvp_priv.h @@ -256,6 +256,13 @@ extern void show_stmt_file_line(ivl_statement_t net, const char*desc); extern int test_immediate_vec4_ok(ivl_expr_t expr); extern void draw_immediate_vec4(ivl_expr_t expr, const char*opcode); +/* + * Draw a delay statement. + */ +extern void draw_delay(void*ptr, unsigned wid, const char*input, + ivl_expr_t rise_exp, ivl_expr_t fall_exp, + ivl_expr_t decay_exp); + /* * These functions manage word register allocation. */ diff --git a/tgt-vvp/vvp_scope.c b/tgt-vvp/vvp_scope.c index 6a333d926..2919c3337 100644 --- a/tgt-vvp/vvp_scope.c +++ b/tgt-vvp/vvp_scope.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001-2015 Stephen Williams (steve@icarus.com) + * Copyright (c) 2001-2016 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 @@ -717,7 +717,7 @@ static unsigned need_delay(ivl_net_logic_t lptr) /* * Draw the appropriate delay statement. Returns zero if there is not a delay. */ -static void draw_delay(ivl_net_logic_t lptr) +static void draw_logic_delay(ivl_net_logic_t lptr) { ivl_expr_t rise_exp = ivl_logic_delay(lptr, 0); ivl_expr_t fall_exp = ivl_logic_delay(lptr, 1); @@ -730,49 +730,7 @@ static void draw_delay(ivl_net_logic_t lptr) delay_wid = 0; } - /* If the delays are all constants then process them here. */ - if (number_is_immediate(rise_exp, 64, 0) && - number_is_immediate(fall_exp, 64, 0) && - number_is_immediate(decay_exp, 64, 0)) { - - assert(! number_is_unknown(rise_exp)); - assert(! number_is_unknown(fall_exp)); - assert(! number_is_unknown(decay_exp)); - - fprintf(vvp_out, "L_%p .delay %u " - "(%" PRIu64 ",%" PRIu64 ",%" PRIu64 ") L_%p/d;\n", - lptr, delay_wid, - get_number_immediate64(rise_exp), - get_number_immediate64(fall_exp), - get_number_immediate64(decay_exp), lptr); - /* For a variable delay we indicate only two delays by setting the - * decay time to zero. */ - } else { - ivl_signal_t sig; - assert(ivl_expr_type(rise_exp) == IVL_EX_SIGNAL); - assert(ivl_expr_type(fall_exp) == IVL_EX_SIGNAL); - assert((decay_exp == 0) || - (ivl_expr_type(decay_exp) == IVL_EX_SIGNAL)); - - fprintf(vvp_out, "L_%p .delay %u L_%p/d", lptr, delay_wid, lptr); - - sig = ivl_expr_signal(rise_exp); - assert(ivl_signal_dimensions(sig) == 0); - fprintf(vvp_out, ", %s", draw_net_input(ivl_signal_nex(sig,0))); - - sig = ivl_expr_signal(fall_exp); - assert(ivl_signal_dimensions(sig) == 0); - fprintf(vvp_out, ", %s", draw_net_input(ivl_signal_nex(sig,0))); - - if (decay_exp) { - sig = ivl_expr_signal(decay_exp); - assert(ivl_signal_dimensions(sig) == 0); - fprintf(vvp_out, ", %s;\n", - draw_net_input(ivl_signal_nex(sig,0))); - } else { - fprintf(vvp_out, ", 0;\n"); - } - } + draw_delay(lptr, delay_wid, 0, rise_exp, fall_exp, decay_exp); } static void draw_udp_def(ivl_udp_t udp) @@ -908,7 +866,7 @@ static void draw_udp_in_scope(ivl_net_logic_t lptr) fprintf(vvp_out, ";\n"); /* Generate a delay when needed. */ - if (need_delay_flag) draw_delay(lptr); + if (need_delay_flag) draw_logic_delay(lptr); } static void draw_logic_in_scope(ivl_net_logic_t lptr) @@ -1112,7 +1070,7 @@ static void draw_logic_in_scope(ivl_net_logic_t lptr) free(input_strings); /* Generate a delay when needed. */ - if (need_delay_flag) draw_delay(lptr); + if (need_delay_flag) draw_logic_delay(lptr); } static void draw_event_in_scope(ivl_event_t obj) @@ -1312,20 +1270,8 @@ static const char* draw_lpm_output_delay(ivl_lpm_t net, ivl_variable_type_t dt) const char*dly = ""; if (d_rise != 0) { - assert(number_is_immediate(d_rise, 64, 0)); - assert(number_is_immediate(d_fall, 64, 0)); - assert(number_is_immediate(d_decay, 64, 0)); - - assert(! number_is_unknown(d_rise)); - assert(! number_is_unknown(d_fall)); - assert(! number_is_unknown(d_decay)); - + draw_delay(net, width, 0, d_rise, d_fall, d_decay); dly = "/d"; - fprintf(vvp_out, "L_%p .delay %u (%" PRIu64 ",%" PRIu64 ",%" PRIu64 ")" - " L_%p/d;\n", net, width, - get_number_immediate64(d_rise), - get_number_immediate64(d_fall), - get_number_immediate64(d_decay), net); } return dly; From aa2260f4fabdd4cc4e5bf24d57d6c8c637e188fb Mon Sep 17 00:00:00 2001 From: Larry Doolittle Date: Tue, 15 Mar 2016 22:16:40 -0700 Subject: [PATCH 16/51] Capitalize Verilog in a few places (cherry picked from commit 89edf62206c69cfcf6a33ac0b91766338f048fb5) --- elab_lval.cc | 4 ++-- netlist.h | 2 +- netmisc.cc | 2 +- vpi/sys_icarus.c | 2 +- vvp/vvp_net_sig.h | 2 +- 5 files changed, 6 insertions(+), 6 deletions(-) diff --git a/elab_lval.cc b/elab_lval.cc index 718d80e76..047d611ab 100644 --- a/elab_lval.cc +++ b/elab_lval.cc @@ -290,13 +290,13 @@ NetAssign_* PEIdent::elaborate_lval(Design*des, } // We are processing the tail of a string of names. For - // example, the verilog may be "a.b.c", so we are processing + // example, the Verilog may be "a.b.c", so we are processing // "c" at this point. (Note that if method_name is not nil, // then this is "a.b.c.method" and "a.b.c" is a struct or class.) const name_component_t&name_tail = path_.back(); // Use the last index to determine what kind of select - // (bit/part/etc) we are processing. For example, the verilog + // (bit/part/etc) we are processing. For example, the Verilog // may be "a.b.c[1][2][]". All but the last index must // be simple expressions, only the may be a part // select etc., so look at it to determine how we will be diff --git a/netlist.h b/netlist.h index 19d671b72..de561e706 100644 --- a/netlist.h +++ b/netlist.h @@ -713,7 +713,7 @@ class NetNet : public NetObj, public PortType { /* This method returns a reference to the packed dimensions for the vector. These are arranged as a list where the first range in the list (front) is the left-most range in - the verilog declaration. These packed dims are compressed + the Verilog declaration. These packed dims are compressed to represent the dimensions of all the subtypes. */ const std::vector& packed_dims() const { return slice_dims_; } diff --git a/netmisc.cc b/netmisc.cc index 2ced04acb..6a68a9918 100644 --- a/netmisc.cc +++ b/netmisc.cc @@ -925,7 +925,7 @@ NetExpr* elab_and_eval(Design*des, NetScope*scope, PExpr*pe, /* * This variant of elab_and_eval does the expression losslessly, no - * matter what the generation of verilog. This is in support of + * matter what the generation of Verilog. This is in support of * certain special contexts, notably index expressions. */ NetExpr* elab_and_eval_lossless(Design*des, NetScope*scope, PExpr*pe, diff --git a/vpi/sys_icarus.c b/vpi/sys_icarus.c index 40d8c52e3..7a1037572 100644 --- a/vpi/sys_icarus.c +++ b/vpi/sys_icarus.c @@ -60,7 +60,7 @@ static PLI_INT32 missing_optional_compiletf(ICARUS_VPI_CONST PLI_BYTE8* name) { vpiHandle callh = vpi_handle(vpiSysTfCall, 0); - vpi_printf("SORRY: %s:%d: %s() is not available in Icarus verilog.\n", + vpi_printf("SORRY: %s:%d: %s() is not available in Icarus Verilog.\n", vpi_get_str(vpiFile, callh), (int)vpi_get(vpiLineNo, callh), name); vpi_control(vpiFinish, 1); diff --git a/vvp/vvp_net_sig.h b/vvp/vvp_net_sig.h index d9ac0c3ae..893b28b39 100644 --- a/vvp/vvp_net_sig.h +++ b/vvp/vvp_net_sig.h @@ -393,7 +393,7 @@ class vvp_fun_signal_object_aa : public vvp_fun_signal_object, public automatic_ /* vvp_wire * The vvp_wire is different from vvp_variable objects in that it * exists only as a filter. The vvp_wire class tree is for - * implementing verilog wires/nets (as opposed to regs/variables). + * implementing Verilog wires/nets (as opposed to regs/variables). * * vvp_vpi_callback * | From 9be3fc3a56b85f6648171ceecc106170fd7d3600 Mon Sep 17 00:00:00 2001 From: Martin Whitaker Date: Mon, 4 Apr 2016 22:29:54 +0100 Subject: [PATCH 17/51] Fix GitHub issue #99 - recv_vec4_pv not implemented for arithmetic functors. Also initialise the stored operand values to 'bz instead of 'bx to get the correct results when bits are not driven. (cherry picked from commit b2f7d09f0de1696dc078e172cc0af65e11deb4a4) --- vvp/arith.cc | 42 ++++++++++++++++++++++++++++++++++++------ vvp/arith.h | 6 +++++- 2 files changed, 41 insertions(+), 7 deletions(-) diff --git a/vvp/arith.cc b/vvp/arith.cc index 7fe9ebcef..1377d1623 100644 --- a/vvp/arith.cc +++ b/vvp/arith.cc @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001-2013 Stephen Williams (steve@icarus.com) + * Copyright (c) 2001-2016 Stephen Williams (steve@icarus.com) * * This source code is free software; you can redistribute it * and/or modify it in source code form under the terms of the GNU @@ -26,13 +26,13 @@ # include vvp_arith_::vvp_arith_(unsigned wid) -: wid_(wid), x_val_(wid) +: wid_(wid), op_a_(wid), op_b_(wid), x_val_(wid) { - for (unsigned idx = 0 ; idx < wid ; idx += 1) + for (unsigned idx = 0 ; idx < wid ; idx += 1) { + op_a_ .set_bit(idx, BIT4_Z); + op_b_ .set_bit(idx, BIT4_Z); x_val_.set_bit(idx, BIT4_X); - - op_a_ = x_val_; - op_b_ = x_val_; + } } void vvp_arith_::dispatch_operand_(vvp_net_ptr_t ptr, vvp_vector4_t bit) @@ -51,6 +51,36 @@ void vvp_arith_::dispatch_operand_(vvp_net_ptr_t ptr, vvp_vector4_t bit) } } +void vvp_arith_::recv_vec4_pv(vvp_net_ptr_t ptr, const vvp_vector4_t&bit, + unsigned base, unsigned wid, unsigned vwid, + vvp_context_t) +{ + unsigned port = ptr.port(); + + assert(bit.size() == wid); + assert(base + wid <= vwid); + + vvp_vector4_t tmp; + switch (port) { + case 0: + tmp = op_a_; + break; + case 1: + tmp = op_b_; + break; + default: + fprintf(stderr, "Unsupported port type %u.\n", port); + assert(0); + } + + // Set the part for the input. If nothing changes, then break. + bool flag = tmp.set_vec(base, bit); + if (flag == false) + return; + + recv_vec4(ptr, tmp, 0); +} + vvp_arith_abs::vvp_arith_abs() { diff --git a/vvp/arith.h b/vvp/arith.h index 612f060b9..097434206 100644 --- a/vvp/arith.h +++ b/vvp/arith.h @@ -1,7 +1,7 @@ #ifndef IVL_arith_H #define IVL_arith_H /* - * Copyright (c) 2001-2014 Stephen Williams (steve@icarus.com) + * Copyright (c) 2001-2016 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 @@ -37,6 +37,10 @@ class vvp_arith_ : public vvp_net_fun_t { public: explicit vvp_arith_(unsigned wid); + void recv_vec4_pv(vvp_net_ptr_t p, const vvp_vector4_t&bit, + unsigned base, unsigned wid, unsigned vwid, + vvp_context_t); + protected: void dispatch_operand_(vvp_net_ptr_t ptr, vvp_vector4_t bit); From 3f75f6b155ce0ba1cad4d64377bb0a7064c9ee06 Mon Sep 17 00:00:00 2001 From: Martin Whitaker Date: Sat, 19 Mar 2016 13:04:38 +0000 Subject: [PATCH 18/51] Fully support variable initialization in tasks/functions/named blocks. (cherry picked from commit 635adfc01eb3844deeefcf86d1a9a9b7c284369f) --- PScope.h | 10 ++++- elaborate.cc | 112 +++++++++++++++++++++++++++++++++++++++++++---- net_func_eval.cc | 8 ++++ net_proc.cc | 11 +++++ net_scope.cc | 1 + netlist.h | 10 +++++ parse.y | 6 +-- pform.cc | 31 +++++++------ pform.h | 4 +- pform_dump.cc | 17 +++++++ 10 files changed, 182 insertions(+), 28 deletions(-) diff --git a/PScope.h b/PScope.h index 30e1fea7e..f7eb73f96 100644 --- a/PScope.h +++ b/PScope.h @@ -1,7 +1,7 @@ #ifndef IVL_PScope_H #define IVL_PScope_H /* - * Copyright (c) 2008-2014 Stephen Williams (steve@icarus.com) + * Copyright (c) 2008-2016 Stephen Williams (steve@icarus.com) * * This source code is free software; you can redistribute it * and/or modify it in source code form under the terms of the GNU @@ -36,6 +36,7 @@ class PProcess; class PClass; class PTask; class PWire; +class Statement; class Design; class NetScope; @@ -108,6 +109,9 @@ class LexicalScope { // creating implicit nets. map genvars; + // Variable initializations in this scope + vector var_inits; + // Behaviors (processes) in this scope list behaviors; list analog_behaviors; @@ -130,6 +134,10 @@ class LexicalScope { void dump_wires_(ostream&out, unsigned indent) const; + void dump_var_inits_(ostream&out, unsigned indent) const; + + bool elaborate_var_inits_(Design*des, NetScope*scope) const; + private: LexicalScope*parent_; }; diff --git a/elaborate.cc b/elaborate.cc index 26acf0933..d22d35735 100644 --- a/elaborate.cc +++ b/elaborate.cc @@ -2894,14 +2894,27 @@ NetProc* PBlock::elaborate(Design*des, NetScope*scope) const des->errors += 1; return 0; } - assert(nscope); - - elaborate_behaviors_(des, nscope); } NetBlock*cur = new NetBlock(type, nscope); + if (nscope) { + // Handle any variable initialization statements in this scope. + // For automatic scopes these statements need to be executed + // each time the block is entered, so add them to the main + // block. For static scopes, put them in a separate process + // that will be executed at the start of simulation. + if (nscope->is_auto()) { + for (unsigned idx = 0; idx < var_inits.size(); idx += 1) { + NetProc*tmp = var_inits[idx]->elaborate(des, nscope); + if (tmp) cur->append(tmp); + } + } else { + elaborate_var_inits_(des, nscope); + } + } + if (nscope == 0) nscope = scope; @@ -5023,7 +5036,6 @@ void PFunction::elaborate(Design*des, NetScope*scope) const des->errors += 1; return; } - assert(def); ivl_assert(*this, statement_); @@ -5036,6 +5048,31 @@ void PFunction::elaborate(Design*des, NetScope*scope) const return; } + // Handle any variable initialization statements in this scope. + // For automatic functions, these statements need to be executed + // each time the function is called, so insert them at the start + // of the elaborated definition. For static functions, put them + // in a separate process that will be executed before the start + // of simulation. + if (is_auto_) { + // Get the NetBlock of the statement. If it is not a + // NetBlock then create one to wrap the initialization + // statements and the original statement. + NetBlock*blk = dynamic_cast (st); + if ((blk == 0) && (var_inits.size() > 0)) { + blk = new NetBlock(NetBlock::SEQU, scope); + blk->set_line(*this); + blk->append(st); + st = blk; + } + for (unsigned idx = var_inits.size(); idx > 0; idx -= 1) { + NetProc*tmp = var_inits[idx-1]->elaborate(des, scope); + if (tmp) blk->prepend(tmp); + } + } else { + elaborate_var_inits_(des, scope); + } + def->set_proc(st); } @@ -5198,11 +5235,6 @@ NetProc* PReturn::elaborate(Design*des, NetScope*scope) const void PTask::elaborate(Design*des, NetScope*task) const { - // Elaborate any processes that are part of this scope that - // aren't the definition itself. This can happen, for example, - // with variable initialization statements in this scope. - elaborate_behaviors_(des, task); - NetTaskDef*def = task->task_def(); assert(def); @@ -5221,6 +5253,31 @@ void PTask::elaborate(Design*des, NetScope*task) const } } + // Handle any variable initialization statements in this scope. + // For automatic tasks , these statements need to be executed + // each time the task is called, so insert them at the start + // of the elaborated definition. For static tasks, put them + // in a separate process that will be executed before the start + // of simulation. + if (is_auto_) { + // Get the NetBlock of the statement. If it is not a + // NetBlock then create one to wrap the initialization + // statements and the original statement. + NetBlock*blk = dynamic_cast (st); + if ((blk == 0) && (var_inits.size() > 0)) { + blk = new NetBlock(NetBlock::SEQU, task); + blk->set_line(*this); + blk->append(st); + st = blk; + } + for (unsigned idx = var_inits.size(); idx > 0; idx -= 1) { + NetProc*tmp = var_inits[idx-1]->elaborate(des, task); + if (tmp) blk->prepend(tmp); + } + } else { + elaborate_var_inits_(des, task); + } + def->set_proc(st); } @@ -5677,6 +5734,10 @@ bool Module::elaborate(Design*des, NetScope*scope) const (*gt)->elaborate(des, scope); } + // Elaborate the variable initialization statements, making a + // single initial process out of them. + result_flag &= elaborate_var_inits_(des, scope); + // Elaborate the behaviors, making processes out of them. This // involves scanning the PProcess* list, creating a NetProcTop // for each process. @@ -5867,6 +5928,8 @@ bool PGenerate::elaborate_(Design*des, NetScope*scope) const for (gates_it_t cur = gates.begin() ; cur != gates.end() ; ++ cur ) (*cur)->elaborate(des, scope); + elaborate_var_inits_(des, scope); + typedef list::const_iterator proc_it_t; for (proc_it_t cur = behaviors.begin(); cur != behaviors.end(); ++ cur ) (*cur)->elaborate(des, scope); @@ -5902,6 +5965,37 @@ bool PScope::elaborate_behaviors_(Design*des, NetScope*scope) const return result_flag; } +bool LexicalScope::elaborate_var_inits_(Design*des, NetScope*scope) const +{ + if (var_inits.size() == 0) + return true; + + NetProc*proc = 0; + if (var_inits.size() == 1) { + proc = var_inits[0]->elaborate(des, scope); + } else { + NetBlock*blk = new NetBlock(NetBlock::SEQU, scope); + bool flag = true; + for (unsigned idx = 0; idx < var_inits.size(); idx += 1) { + NetProc*tmp = var_inits[idx]->elaborate(des, scope); + if (tmp) + blk->append(tmp); + else + flag = false; + } + if (flag) proc = blk; + } + if (proc == 0) + return false; + + NetProcTop*top = new NetProcTop(scope, IVL_PR_INITIAL, proc); + des->add_process(top); + + scope->set_var_init(proc); + + return true; +} + class elaborate_package_t : public elaborator_work_item_t { public: elaborate_package_t(Design*d, NetScope*scope, PPackage*p) diff --git a/net_func_eval.cc b/net_func_eval.cc index 9e045c63c..00790d692 100644 --- a/net_func_eval.cc +++ b/net_func_eval.cc @@ -88,6 +88,10 @@ NetExpr* NetFuncDef::evaluate_function(const LineInfo&loc, const std::vectorevaluate_function_find_locals(loc, context_map); + // Execute any variable initialization statements. + if (const NetProc*init_proc = scope()->var_init()) + init_proc->evaluate_function(loc, context_map); + if (debug_eval_tree && proc_==0) { cerr << loc.get_fileline() << ": NetFuncDef::evaluate_function: " << "Function " << scope_path(scope()) @@ -505,6 +509,10 @@ bool NetBlock::evaluate_function(const LineInfo&loc, // Now collect the new locals. subscope_->evaluate_function_find_locals(loc, local_context_map); use_local_context_map = true; + + // Execute any variable initialization statements. + if (const NetProc*init_proc = subscope_->var_init()) + init_proc->evaluate_function(loc, local_context_map); } // Now use the local context map if there is any local diff --git a/net_proc.cc b/net_proc.cc index 2aedec7c2..8b6902b68 100644 --- a/net_proc.cc +++ b/net_proc.cc @@ -56,6 +56,17 @@ void NetBlock::append(NetProc*cur) } } +void NetBlock::prepend(NetProc*cur) +{ + if (last_ == 0) { + last_ = cur; + cur->next_ = cur; + } else { + cur->next_ = last_->next_; + last_->next_ = cur; + } +} + const NetProc* NetBlock::proc_first() const { if (last_ == 0) diff --git a/net_scope.cc b/net_scope.cc index 688266aff..438ccd729 100644 --- a/net_scope.cc +++ b/net_scope.cc @@ -139,6 +139,7 @@ NetScope::NetScope(NetScope*up, const hname_t&n, NetScope::TYPE t, bool nest, time_from_timescale_ = false; } + var_init_ = 0; switch (t) { case NetScope::TASK: task_ = 0; diff --git a/netlist.h b/netlist.h index de561e706..68bc27319 100644 --- a/netlist.h +++ b/netlist.h @@ -1020,6 +1020,13 @@ class NetScope : public Definitions, public Attrib { TYPE type() const; void print_type(ostream&) const; + // This provides a link to the variable initialisation process + // for use when evaluating a constant function. Note this is + // only used for static functions - the variable initialization + // for automatic functions is included in the function definition. + void set_var_init(const NetProc*proc) { var_init_ = proc; } + const NetProc* var_init() const { return var_init_; } + void set_task_def(NetTaskDef*); void set_func_def(NetFuncDef*); void set_class_def(netclass_t*); @@ -1250,6 +1257,8 @@ class NetScope : public Definitions, public Attrib { vector ports_; + const NetProc*var_init_; + union { NetTaskDef*task_; NetFuncDef*func_; @@ -2904,6 +2913,7 @@ class NetBlock : public NetProc { NetScope* subscope() const { return subscope_; } void append(NetProc*); + void prepend(NetProc*); const NetProc*proc_first() const; const NetProc*proc_next(const NetProc*cur) const; diff --git a/parse.y b/parse.y index 739bf9b73..a901a63de 100644 --- a/parse.y +++ b/parse.y @@ -4223,7 +4223,7 @@ port_declaration port_declaration_context.port_net_type = use_type; port_declaration_context.data_type = $4; - pform_make_reginit(@5, name, $7); + pform_make_var_init(@5, name, $7); delete[]$5; $$ = ptmp; @@ -4622,7 +4622,7 @@ module_item IVL_VT_NO_TYPE, $1, SR_BOTH); for (pp = $6->begin(); pp != $6->end(); ++ pp ) { if ((*pp).second) { - pform_make_reginit(@2, (*pp).first, (*pp).second); + pform_make_var_init(@2, (*pp).first, (*pp).second); } } delete $6; @@ -5486,7 +5486,7 @@ register_variable pform_makewire(@1, name, NetNet::REG, NetNet::NOT_A_PORT, IVL_VT_NO_TYPE, 0); pform_set_reg_idx(name, $2); - pform_make_reginit(@1, name, $4); + pform_make_var_init(@1, name, $4); $$ = $1; } ; diff --git a/pform.cc b/pform.cc index 594026993..bc1211907 100644 --- a/pform.cc +++ b/pform.cc @@ -2248,23 +2248,30 @@ void pform_make_pgassign_list(list*alist, } /* - * this function makes the initial assignment to a register as given - * in the source. It handles the case where a reg variable is assigned - * where it it declared: + * This function makes the initial assignment to a variable as given + * in the source. It handles the case where a variable is assigned + * where it is declared, e.g. * * reg foo = ; * - * This is equivalent to the combination of statements: + * In Verilog-2001 this is only supported at the module level, and is + * equivalent to the combination of statements: * * reg foo; * initial foo = ; * - * and that is how it is parsed. This syntax is not part of the - * IEEE1364-1995 standard, but is approved by OVI as enhancement - * BTF-B14. + * In SystemVerilog, variable initializations are allowed in any scope. + * For static variables, initializations are performed before the start + * of simulation. For automatic variables, initializations are performed + * each time the enclosing block is entered. Here we store the variable + * assignments in the current scope, and later elaboration creates an + * initialization block that will be executed at the appropriate time. + * + * This syntax is not part of the IEEE1364-1995 standard, but is + * approved by OVI as enhancement BTF-B14. */ -void pform_make_reginit(const struct vlltype&li, - perm_string name, PExpr*expr) +void pform_make_var_init(const struct vlltype&li, + perm_string name, PExpr*expr) { if (! pform_at_module_level() && !gn_system_verilog()) { VLerror(li, "error: variable declaration assignments are only " @@ -2275,7 +2282,7 @@ void pform_make_reginit(const struct vlltype&li, PWire*cur = pform_get_wire_in_scope(name); if (cur == 0) { - VLerror(li, "internal error: reginit to non-register?"); + VLerror(li, "internal error: var_init to non-register?"); delete expr; return; } @@ -2284,10 +2291,8 @@ void pform_make_reginit(const struct vlltype&li, FILE_NAME(lval, li); PAssign*ass = new PAssign(lval, expr, true); FILE_NAME(ass, li); - PProcess*top = new PProcess(IVL_PR_INITIAL, ass); - FILE_NAME(top, li); - pform_put_behavior_in_scope(top); + lexical_scope->var_inits.push_back(ass); } /* diff --git a/pform.h b/pform.h index 2e7f8ea5e..e1ce49065 100644 --- a/pform.h +++ b/pform.h @@ -351,8 +351,8 @@ extern void pform_makewire(const struct vlltype&li, list*names, list*attr); -extern void pform_make_reginit(const struct vlltype&li, - perm_string name, PExpr*expr); +extern void pform_make_var_init(const struct vlltype&li, + perm_string name, PExpr*expr); /* Look up the names of the wires, and set the port type, i.e. input, output or inout. If the wire does not exist, create diff --git a/pform_dump.cc b/pform_dump.cc index afd2ddc27..bc44c0519 100644 --- a/pform_dump.cc +++ b/pform_dump.cc @@ -789,6 +789,8 @@ void PBlock::dump(ostream&out, unsigned ind) const dump_events_(out, ind+2); dump_wires_(out, ind+2); + + dump_var_inits_(out, ind+2); } for (unsigned idx = 0 ; idx < list_.size() ; idx += 1) { @@ -1030,6 +1032,8 @@ void PFunction::dump(ostream&out, unsigned ind) const dump_wires_(out, ind+2); + dump_var_inits_(out, ind+2); + if (statement_) statement_->dump(out, ind+2); else @@ -1072,6 +1076,8 @@ void PTask::dump(ostream&out, unsigned ind) const dump_wires_(out, ind+2); + dump_var_inits_(out, ind+2); + if (statement_) statement_->dump(out, ind+2); else @@ -1269,6 +1275,8 @@ void PGenerate::dump(ostream&out, unsigned indent) const (*idx)->dump(out, indent+2); } + dump_var_inits_(out, indent+2); + for (list::const_iterator idx = behaviors.begin() ; idx != behaviors.end() ; ++ idx ) { (*idx)->dump(out, indent+2); @@ -1408,6 +1416,14 @@ void LexicalScope::dump_wires_(ostream&out, unsigned indent) const } } +void LexicalScope::dump_var_inits_(ostream&out, unsigned indent) const +{ + // Iterate through and display all the register initializations. + for (unsigned idx = 0; idx < var_inits.size(); idx += 1) { + var_inits[idx]->dump(out, indent); + } +} + void PScopeExtra::dump_classes_(ostream&out, unsigned indent) const { // Dump the task definitions. @@ -1564,6 +1580,7 @@ void Module::dump(ostream&out) const (*gate)->dump(out); } + dump_var_inits_(out, 4); for (list::const_iterator behav = behaviors.begin() ; behav != behaviors.end() ; ++ behav ) { From 72fc3d712deafcdb6f67fabf4bae4d9b6aebc386 Mon Sep 17 00:00:00 2001 From: Martin Whitaker Date: Sat, 19 Mar 2016 13:46:09 +0000 Subject: [PATCH 19/51] For SystemVerilog, run variable initialization before main simulation starts. (cherry picked from commit 54feb89bf540fb75abc31ede03cc9be444015e94) --- elaborate.cc | 4 ++++ tgt-vvp/vvp_process.c | 13 +++++++++++-- vvp/compile.cc | 6 ++++-- vvp/schedule.cc | 12 +++++++++++- vvp/schedule.h | 4 +++- 5 files changed, 33 insertions(+), 6 deletions(-) diff --git a/elaborate.cc b/elaborate.cc index d22d35735..77692372a 100644 --- a/elaborate.cc +++ b/elaborate.cc @@ -5989,6 +5989,10 @@ bool LexicalScope::elaborate_var_inits_(Design*des, NetScope*scope) const return false; NetProcTop*top = new NetProcTop(scope, IVL_PR_INITIAL, proc); + if (gn_system_verilog()) { + top->attribute(perm_string::literal("_ivl_schedule_init"), + verinum(1)); + } des->add_process(top); scope->set_var_init(proc); diff --git a/tgt-vvp/vvp_process.c b/tgt-vvp/vvp_process.c index 571c8b100..98ca72cff 100644 --- a/tgt-vvp/vvp_process.c +++ b/tgt-vvp/vvp_process.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001-2015 Stephen Williams (steve@icarus.com) + * Copyright (c) 2001-2016 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 @@ -2298,6 +2298,7 @@ int draw_process(ivl_process_t net, void*x) ivl_scope_t scope = ivl_process_scope(net); ivl_statement_t stmt = ivl_process_stmt(net); + int init_flag = 0; int push_flag = 0; (void)x; /* Parameter is not used. */ @@ -2306,6 +2307,12 @@ int draw_process(ivl_process_t net, void*x) ivl_attribute_t attr = ivl_process_attr_val(net, idx); + if (strcmp(attr->key, "_ivl_schedule_init") == 0) { + + init_flag = 1; + + } + if (strcmp(attr->key, "_ivl_schedule_push") == 0) { push_flag = 1; @@ -2349,7 +2356,9 @@ int draw_process(ivl_process_t net, void*x) case IVL_PR_INITIAL: case IVL_PR_ALWAYS: - if (push_flag) { + if (init_flag) { + fprintf(vvp_out, " .thread T_%u, $init;\n", thread_count); + } else if (push_flag) { fprintf(vvp_out, " .thread T_%u, $push;\n", thread_count); } else { fprintf(vvp_out, " .thread T_%u;\n", thread_count); diff --git a/vvp/compile.cc b/vvp/compile.cc index 3bf1d7474..ef1e49bf9 100644 --- a/vvp/compile.cc +++ b/vvp/compile.cc @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001-2014 Stephen Williams (steve@icarus.com) + * Copyright (c) 2001-2016 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 @@ -1935,7 +1935,9 @@ void compile_thread(char*start_sym, char*flag) vthread_t thr = vthread_new(pc, vpip_peek_current_scope()); - if (flag && (strcmp(flag,"$final") == 0)) + if (flag && (strcmp(flag,"$init") == 0)) + schedule_init_vthread(thr); + else if (flag && (strcmp(flag,"$final") == 0)) schedule_final_vthread(thr); else schedule_vthread(thr, 0, push_flag); diff --git a/vvp/schedule.cc b/vvp/schedule.cc index 9ed169fab..79c68b024 100644 --- a/vvp/schedule.cc +++ b/vvp/schedule.cc @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001-2013 Stephen Williams (steve@icarus.com) + * Copyright (c) 2001-2016 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 @@ -760,6 +760,16 @@ void schedule_vthread(vthread_t thr, vvp_time64_t delay, bool push_flag) } } +void schedule_init_vthread(vthread_t thr) +{ + struct vthread_event_s*cur = new vthread_event_s; + + cur->thr = thr; + vthread_mark_scheduled(thr); + + schedule_init_event(cur); +} + void schedule_final_vthread(vthread_t thr) { struct vthread_event_s*cur = new vthread_event_s; diff --git a/vvp/schedule.h b/vvp/schedule.h index 49db903e9..4dace3d04 100644 --- a/vvp/schedule.h +++ b/vvp/schedule.h @@ -1,7 +1,7 @@ #ifndef IVL_schedule_H #define IVL_schedule_H /* - * Copyright (c) 2001-2014 Stephen Williams (steve@icarus.com) + * Copyright (c) 2001-2016 Stephen Williams (steve@icarus.com) * * This source code is free software; you can redistribute it * and/or modify it in source code form under the terms of the GNU @@ -35,6 +35,8 @@ extern void schedule_vthread(vthread_t thr, vvp_time64_t delay, bool push_flag =false); +extern void schedule_init_vthread(vthread_t thr); + extern void schedule_final_vthread(vthread_t thr); /* From 4aef636559f1b021f784d5a987d88bd5a7c1a83b Mon Sep 17 00:00:00 2001 From: Martin Whitaker Date: Sat, 19 Mar 2016 14:21:10 +0000 Subject: [PATCH 20/51] Variable initialization blocks should be unamed. Also add file/line info to initial process. (cherry picked from commit 72bb63cf42811ff7dbbf36c975e4359954e65e8f) --- elaborate.cc | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/elaborate.cc b/elaborate.cc index 77692372a..e8ac6a7fd 100644 --- a/elaborate.cc +++ b/elaborate.cc @@ -5974,7 +5974,7 @@ bool LexicalScope::elaborate_var_inits_(Design*des, NetScope*scope) const if (var_inits.size() == 1) { proc = var_inits[0]->elaborate(des, scope); } else { - NetBlock*blk = new NetBlock(NetBlock::SEQU, scope); + NetBlock*blk = new NetBlock(NetBlock::SEQU, 0); bool flag = true; for (unsigned idx = 0; idx < var_inits.size(); idx += 1) { NetProc*tmp = var_inits[idx]->elaborate(des, scope); @@ -5989,6 +5989,9 @@ bool LexicalScope::elaborate_var_inits_(Design*des, NetScope*scope) const return false; NetProcTop*top = new NetProcTop(scope, IVL_PR_INITIAL, proc); + if (const LineInfo*li = dynamic_cast(this)) { + top->set_line(*li); + } if (gn_system_verilog()) { top->attribute(perm_string::literal("_ivl_schedule_init"), verinum(1)); From 7d2eeb01372d2f4d49e727f9bb1f0d5e009471d3 Mon Sep 17 00:00:00 2001 From: Martin Whitaker Date: Sat, 19 Mar 2016 17:27:27 +0000 Subject: [PATCH 21/51] Added support for default subroutine lifetimes (SystemVerilog). (cherry picked from commit 6e718c2e0c1463fce997860e4ab02cef0363db8a) --- PScope.h | 3 ++ parse.y | 91 ++++++++++++++++++++++++++---------------------- pform.cc | 55 +++++++++++++++++++++++------ pform.h | 24 +++++++++---- pform_package.cc | 7 ++-- pform_pclass.cc | 14 +++++--- 6 files changed, 127 insertions(+), 67 deletions(-) diff --git a/PScope.h b/PScope.h index f7eb73f96..081d9fb58 100644 --- a/PScope.h +++ b/PScope.h @@ -57,6 +57,9 @@ class LexicalScope { // A virtual destructor is so that dynamic_cast can work. virtual ~LexicalScope() { } + enum lifetime_t { INHERITED, STATIC, AUTOMATIC }; + lifetime_t default_lifetime; + struct range_t { // True if this is an exclude bool exclude_flag; diff --git a/parse.y b/parse.y index a901a63de..1b0fec636 100644 --- a/parse.y +++ b/parse.y @@ -1,7 +1,7 @@ %{ /* - * Copyright (c) 1998-2015 Stephen Williams (steve@icarus.com) + * Copyright (c) 1998-2016 Stephen Williams (steve@icarus.com) * Copyright CERN 2012-2013 / Stephen Williams (steve@icarus.com) * * This source code is free software; you can redistribute it @@ -452,6 +452,8 @@ static void current_function_set_statement(const YYLTYPE&loc, vector PSpecPath* specpath; list *dimensions; + + LexicalScope::lifetime_t lifetime; }; %token IDENTIFIER SYSTEM_IDENTIFIER STRING TIME_LITERAL @@ -560,7 +562,7 @@ static void current_function_set_statement(const YYLTYPE&loc, vector %type number pos_neg_number %type signing unsigned_signed_opt signed_unsigned_opt %type import_export -%type K_automatic_opt K_packed_opt K_reg_opt K_static_opt K_virtual_opt +%type K_packed_opt K_reg_opt K_static_opt K_virtual_opt %type udp_reg_opt edge_operator %type drive_strength drive_strength_opt dr_strength0 dr_strength1 %type udp_input_sym udp_output_sym @@ -665,6 +667,8 @@ static void current_function_set_statement(const YYLTYPE&loc, vector %type atom2_type %type module_start module_end +%type lifetime_opt + %token K_TAND %right K_PLUS_EQ K_MINUS_EQ K_MUL_EQ K_DIV_EQ K_MOD_EQ K_AND_EQ K_OR_EQ %right K_XOR_EQ K_LS_EQ K_RS_EQ K_RSS_EQ @@ -724,17 +728,17 @@ block_identifier_opt /* */ ; class_declaration /* IEEE1800-2005: A.1.2 */ - : K_virtual_opt K_class class_identifier class_declaration_extends_opt ';' - { pform_start_class_declaration(@2, $3, $4.type, $4.exprs); } + : K_virtual_opt K_class lifetime_opt class_identifier class_declaration_extends_opt ';' + { pform_start_class_declaration(@2, $4, $5.type, $5.exprs, $3); } class_items_opt K_endclass { // Process a class. - pform_end_class_declaration(@8); + pform_end_class_declaration(@9); } class_declaration_endlabel_opt { // Wrap up the class. - if ($10 && $3 && $3->name != $10) { - yyerror(@10, "error: Class end label doesn't match class name."); - delete[]$10; + if ($11 && $4 && $4->name != $11) { + yyerror(@11, "error: Class end label doesn't match class name."); + delete[]$11; } } ; @@ -1194,7 +1198,7 @@ for_step /* IEEE1800-2005: A.6.8 */ 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 K_automatic_opt data_type_or_implicit_or_void IDENTIFIER ';' + : K_function lifetime_opt data_type_or_implicit_or_void IDENTIFIER ';' { assert(current_function == 0); current_function = pform_push_function_scope(@1, $4, $2); } @@ -1215,7 +1219,7 @@ function_declaration /* IEEE1800-2005: A.2.6 */ "function name"); } if (! gn_system_verilog()) { - yyerror(@11, "error: Function end label require " + yyerror(@11, "error: Function end labels require " "SystemVerilog."); } delete[]$11; @@ -1223,7 +1227,7 @@ function_declaration /* IEEE1800-2005: A.2.6 */ delete[]$4; } - | K_function K_automatic_opt data_type_or_implicit_or_void IDENTIFIER + | K_function lifetime_opt data_type_or_implicit_or_void IDENTIFIER { assert(current_function == 0); current_function = pform_push_function_scope(@1, $4, $2); } @@ -1259,7 +1263,7 @@ function_declaration /* IEEE1800-2005: A.2.6 */ /* Detect and recover from some errors. */ - | K_function K_automatic_opt data_type_or_implicit_or_void IDENTIFIER error K_endfunction + | K_function lifetime_opt data_type_or_implicit_or_void IDENTIFIER error K_endfunction { /* */ if (current_function) { pform_pop_scope(); @@ -1365,6 +1369,12 @@ jump_statement /* IEEE1800-2005: A.6.5 */ } ; +lifetime_opt /* IEEE1800-2005: A.2.1.3 */ + : K_automatic { $$ = LexicalScope::AUTOMATIC; } + | K_static { $$ = LexicalScope::STATIC; } + | { $$ = LexicalScope::INHERITED; } + ; + /* Loop statements are kinds of statements. */ loop_statement /* IEEE1800-2005: A.6.8 */ @@ -1704,20 +1714,20 @@ open_range_list /* IEEE1800-2005 A.2.11 */ ; package_declaration /* IEEE1800-2005 A.1.2 */ - : K_package IDENTIFIER ';' - { pform_start_package_declaration(@1, $2); + : K_package lifetime_opt IDENTIFIER ';' + { pform_start_package_declaration(@1, $3, $2); } package_item_list_opt K_endpackage endlabel_opt { pform_end_package_declaration(@1); // If an end label is present make sure it match the package name. - if ($7) { - if (strcmp($2,$7) != 0) { - yyerror(@7, "error: End label doesn't match package name"); + if ($8) { + if (strcmp($3,$8) != 0) { + yyerror(@8, "error: End label doesn't match package name"); } - delete[]$7; + delete[]$8; } - delete[]$2; + delete[]$3; } ; @@ -1896,7 +1906,7 @@ streaming_concatenation /* IEEE1800-2005: A.8.1 */ task_declaration /* IEEE1800-2005: A.2.7 */ - : K_task K_automatic_opt IDENTIFIER ';' + : K_task lifetime_opt IDENTIFIER ';' { assert(current_task == 0); current_task = pform_push_task_scope(@1, $3, $2); } @@ -1909,7 +1919,7 @@ task_declaration /* IEEE1800-2005: A.2.7 */ pform_pop_scope(); current_task = 0; if ($7 && $7->size() > 1 && !gn_system_verilog()) { - yyerror(@7, "error: Task body with multiple statements requres SystemVerilog."); + yyerror(@7, "error: Task body with multiple statements requires SystemVerilog."); } delete $7; } @@ -1932,7 +1942,7 @@ task_declaration /* IEEE1800-2005: A.2.7 */ delete[]$3; } - | K_task K_automatic_opt IDENTIFIER '(' + | K_task lifetime_opt IDENTIFIER '(' { assert(current_task == 0); current_task = pform_push_task_scope(@1, $3, $2); } @@ -1966,7 +1976,7 @@ task_declaration /* IEEE1800-2005: A.2.7 */ delete[]$3; } - | K_task K_automatic_opt IDENTIFIER '(' ')' ';' + | K_task lifetime_opt IDENTIFIER '(' ')' ';' { assert(current_task == 0); current_task = pform_push_task_scope(@1, $3, $2); } @@ -1983,7 +1993,7 @@ task_declaration /* IEEE1800-2005: A.2.7 */ pform_pop_scope(); current_task = 0; if ($9->size() > 1 && !gn_system_verilog()) { - yyerror(@9, "error: Task body with multiple statements requres SystemVerilog."); + yyerror(@9, "error: Task body with multiple statements requires SystemVerilog."); } delete $9; } @@ -2006,7 +2016,7 @@ task_declaration /* IEEE1800-2005: A.2.7 */ delete[]$3; } - | K_task K_automatic_opt IDENTIFIER error K_endtask + | K_task lifetime_opt IDENTIFIER error K_endtask { assert(current_task == 0); } @@ -4377,13 +4387,13 @@ local_timeunit_prec_decl2 items, and finally an end marker. */ module - : attribute_list_opt module_start IDENTIFIER - { pform_startmodule(@2, $3, $2==K_program, $2==K_interface, $1); } + : attribute_list_opt module_start lifetime_opt IDENTIFIER + { pform_startmodule(@2, $4, $2==K_program, $2==K_interface, $3, $1); } module_package_import_list_opt module_parameter_port_list_opt module_port_list_opt module_attribute_foreign ';' - { pform_module_set_ports($7); } + { pform_module_set_ports($8); } local_timeunit_prec_decl_opt { have_timeunit_decl = true; // Every thing past here is have_timeprec_decl = true; // a check! @@ -4409,22 +4419,22 @@ module } // Check that program/endprogram and module/endmodule // keywords match. - if ($2 != $14) { + if ($2 != $15) { switch ($2) { case K_module: - yyerror(@14, "error: module not closed by endmodule."); + yyerror(@15, "error: module not closed by endmodule."); break; case K_program: - yyerror(@14, "error: program not closed by endprogram."); + yyerror(@15, "error: program not closed by endprogram."); break; case K_interface: - yyerror(@14, "error: interface not closed by endinterface."); + yyerror(@15, "error: interface not closed by endinterface."); break; default: break; } } - pform_endmodule($3, in_celldefine, ucd); + pform_endmodule($4, in_celldefine, ucd); have_timeunit_decl = false; // We will allow decls again. have_timeprec_decl = false; } @@ -4434,19 +4444,19 @@ module // endlabel_opt but still have the pform_endmodule() called // early enough that the lexor can know we are outside the // module. - if ($16) { - if (strcmp($3,$16) != 0) { + if ($17) { + if (strcmp($4,$17) != 0) { switch ($2) { case K_module: - yyerror(@16, "error: End label doesn't match " + yyerror(@17, "error: End label doesn't match " "module name."); break; case K_program: - yyerror(@16, "error: End label doesn't match " + yyerror(@17, "error: End label doesn't match " "program name."); break; case K_interface: - yyerror(@16, "error: End label doesn't match " + yyerror(@17, "error: End label doesn't match " "interface name."); break; default: @@ -4457,9 +4467,9 @@ module yyerror(@8, "error: Module end labels require " "SystemVerilog."); } - delete[]$16; + delete[]$17; } - delete[]$3; + delete[]$4; } ; @@ -6782,7 +6792,6 @@ udp_primitive presence is significant. This is a fairly common pattern so collect those rules here. */ -K_automatic_opt: K_automatic { $$ = true; } | { $$ = false; } ; K_packed_opt : K_packed { $$ = true; } | { $$ = false; } ; K_reg_opt : K_reg { $$ = true; } | { $$ = false; } ; K_static_opt : K_static { $$ = true; } | { $$ = false; } ; diff --git a/pform.cc b/pform.cc index bc1211907..34a5eb638 100644 --- a/pform.cc +++ b/pform.cc @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998-2015 Stephen Williams (steve@icarus.com) + * Copyright (c) 1998-2016 Stephen Williams (steve@icarus.com) * Copyright CERN 2013 / Stephen Williams (steve@icarus.com) * * This source code is free software; you can redistribute it @@ -312,12 +312,29 @@ static inline void FILE_NAME(LineInfo*obj, const char*file, unsigned lineno) */ static LexicalScope* lexical_scope = 0; +LexicalScope* pform_peek_scope(void) +{ + assert(lexical_scope); + return lexical_scope; +} + void pform_pop_scope() { assert(lexical_scope); lexical_scope = lexical_scope->parent_scope(); } +static LexicalScope::lifetime_t find_lifetime(LexicalScope::lifetime_t lifetime) +{ + if (lifetime != LexicalScope::INHERITED) + return lifetime; + + if (lexical_scope != 0) + return lexical_scope->default_lifetime; + + return LexicalScope::STATIC; +} + static PScopeExtra* find_nearest_scopex(LexicalScope*scope) { PScopeExtra*scopex = dynamic_cast (scope); @@ -328,15 +345,11 @@ static PScopeExtra* find_nearest_scopex(LexicalScope*scope) return scopex; } -LexicalScope* pform_peek_scope(void) -{ - assert(lexical_scope); - return lexical_scope; -} - -PClass* pform_push_class_scope(const struct vlltype&loc, perm_string name) +PClass* pform_push_class_scope(const struct vlltype&loc, perm_string name, + LexicalScope::lifetime_t lifetime) { PClass*class_scope = new PClass(name, lexical_scope); + class_scope->default_lifetime = find_lifetime(lifetime); FILE_NAME(class_scope, loc); PScopeExtra*scopex = find_nearest_scopex(lexical_scope); @@ -364,20 +377,27 @@ PClass* pform_push_class_scope(const struct vlltype&loc, perm_string name) return class_scope; } -PPackage* pform_push_package_scope(const struct vlltype&loc, perm_string name) +PPackage* pform_push_package_scope(const struct vlltype&loc, perm_string name, + LexicalScope::lifetime_t lifetime) { PPackage*pkg_scope = new PPackage(name, lexical_scope); + pkg_scope->default_lifetime = find_lifetime(lifetime); FILE_NAME(pkg_scope, loc); lexical_scope = pkg_scope; return pkg_scope; } -PTask* pform_push_task_scope(const struct vlltype&loc, char*name, bool is_auto) +PTask* pform_push_task_scope(const struct vlltype&loc, char*name, + LexicalScope::lifetime_t lifetime) { perm_string task_name = lex_strings.make(name); + LexicalScope::lifetime_t default_lifetime = find_lifetime(lifetime); + bool is_auto = default_lifetime == LexicalScope::AUTOMATIC; + PTask*task = new PTask(task_name, lexical_scope, is_auto); + task->default_lifetime = default_lifetime; FILE_NAME(task, loc); PScopeExtra*scopex = find_nearest_scopex(lexical_scope); @@ -424,11 +444,15 @@ PTask* pform_push_task_scope(const struct vlltype&loc, char*name, bool is_auto) } PFunction* pform_push_function_scope(const struct vlltype&loc, const char*name, - bool is_auto) + LexicalScope::lifetime_t lifetime) { perm_string func_name = lex_strings.make(name); + LexicalScope::lifetime_t default_lifetime = find_lifetime(lifetime); + bool is_auto = default_lifetime == LexicalScope::AUTOMATIC; + PFunction*func = new PFunction(func_name, lexical_scope, is_auto); + func->default_lifetime = default_lifetime; FILE_NAME(func, loc); PScopeExtra*scopex = find_nearest_scopex(lexical_scope); @@ -1131,6 +1155,7 @@ verinum* pform_verinum_with_size(verinum*siz, verinum*val, void pform_startmodule(const struct vlltype&loc, const char*name, bool program_block, bool is_interface, + LexicalScope::lifetime_t lifetime, list*attr) { if (! pform_cur_module.empty() && !gn_system_verilog()) { @@ -1139,6 +1164,12 @@ void pform_startmodule(const struct vlltype&loc, const char*name, error_count += 1; } + if (lifetime != LexicalScope::INHERITED && !gn_system_verilog()) { + cerr << loc << ": error: Default subroutine lifetimes " + "require SystemVerilog." << endl; + error_count += 1; + } + if (gn_system_verilog() && ! pform_cur_module.empty()) { if (pform_cur_module.front()->program_block) { cerr << loc << ": error: module, program, or interface " @@ -1158,6 +1189,8 @@ void pform_startmodule(const struct vlltype&loc, const char*name, Module*cur_module = new Module(lexical_scope, lex_name); cur_module->program_block = program_block; cur_module->is_interface = is_interface; + cur_module->default_lifetime = find_lifetime(lifetime); + /* Set the local time unit/precision to the global value. */ cur_module->time_unit = pform_time_unit; cur_module->time_precision = pform_time_prec; diff --git a/pform.h b/pform.h index e1ce49065..21d5c3e75 100644 --- a/pform.h +++ b/pform.h @@ -1,7 +1,7 @@ #ifndef IVL_pform_H #define IVL_pform_H /* - * Copyright (c) 1998-2015 Stephen Williams (steve@icarus.com) + * Copyright (c) 1998-2016 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 @@ -163,6 +163,7 @@ extern PWire* pform_get_make_wire_in_scope(perm_string name, NetNet::Type net_ty */ extern void pform_startmodule(const struct vlltype&loc, const char*name, bool program_block, bool is_interface, + LexicalScope::lifetime_t lifetime, list*attr); extern void pform_check_timeunit_prec(); extern void pform_module_set_ports(vector*); @@ -186,7 +187,8 @@ extern void pform_endmodule(const char*, bool inside_celldefine, extern void pform_start_class_declaration(const struct vlltype&loc, class_type_t*type, data_type_t*base_type, - std::list*base_exprs); + std::list*base_exprs, + LexicalScope::lifetime_t lifetime); extern void pform_class_property(const struct vlltype&loc, property_qualifier_t pq, data_type_t*data_type, @@ -211,7 +213,8 @@ extern void pform_make_udp(perm_string name, * Package related functions. */ extern void pform_start_package_declaration(const struct vlltype&loc, - const char*type); + const char*type, + LexicalScope::lifetime_t lifetime); extern void pform_end_package_declaration(const struct vlltype&loc); extern void pform_package_import(const struct vlltype&loc, PPackage*pkg, const char*ident); @@ -246,13 +249,20 @@ extern void pform_pop_scope(); */ extern LexicalScope* pform_peek_scope(); -extern PClass* pform_push_class_scope(const struct vlltype&loc, perm_string name); +extern PClass* pform_push_class_scope(const struct vlltype&loc, perm_string name, + LexicalScope::lifetime_t lifetime); + extern PFunction*pform_push_constructor_scope(const struct vlltype&loc); -extern PPackage* pform_push_package_scope(const struct vlltype&loc, perm_string name); + +extern PPackage* pform_push_package_scope(const struct vlltype&loc, perm_string name, + LexicalScope::lifetime_t lifetime); + extern PTask*pform_push_task_scope(const struct vlltype&loc, char*name, - bool is_auto); + LexicalScope::lifetime_t lifetime); + extern PFunction*pform_push_function_scope(const struct vlltype&loc, const char*name, - bool is_auto); + LexicalScope::lifetime_t lifetime); + extern PBlock*pform_push_block_scope(char*name, PBlock::BL_TYPE tt); extern void pform_put_behavior_in_scope(AProcess*proc); diff --git a/pform_package.cc b/pform_package.cc index a4ed9c832..4c4b38440 100644 --- a/pform_package.cc +++ b/pform_package.cc @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012 Stephen Williams (steve@icarus.com) + * Copyright (c) 2012-2016 Stephen Williams (steve@icarus.com) * Copyright CERN 2013 Stephen Williams (steve@icarus.com) * * This source code is free software; you can redistribute it @@ -35,12 +35,13 @@ map pform_packages; static PPackage*pform_cur_package = 0; -void pform_start_package_declaration(const struct vlltype&loc, const char*name) +void pform_start_package_declaration(const struct vlltype&loc, const char*name, + LexicalScope::lifetime_t lifetime) { ivl_assert(loc, pform_cur_package == 0); perm_string use_name = lex_strings.make(name); - PPackage*pkg_scope = pform_push_package_scope(loc, use_name); + PPackage*pkg_scope = pform_push_package_scope(loc, use_name, lifetime); FILE_NAME(pkg_scope, loc); pform_cur_package = pkg_scope; } diff --git a/pform_pclass.cc b/pform_pclass.cc index 0636126f4..bd2a7a21a 100644 --- a/pform_pclass.cc +++ b/pform_pclass.cc @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012-2014 Stephen Williams (steve@icarus.com) + * Copyright (c) 2012-2016 Stephen Williams (steve@icarus.com) * * This source code is free software; you can redistribute it * and/or modify it in source code form under the terms of the GNU @@ -36,9 +36,13 @@ static PClass*pform_cur_class = 0; * if present, are the "exprs" that would be passed to a chained * constructor. */ -void pform_start_class_declaration(const struct vlltype&loc, class_type_t*type, data_type_t*base_type, list*base_exprs) +void pform_start_class_declaration(const struct vlltype&loc, + class_type_t*type, + data_type_t*base_type, + list*base_exprs, + LexicalScope::lifetime_t lifetime) { - PClass*class_scope = pform_push_class_scope(loc, type->name); + PClass*class_scope = pform_push_class_scope(loc, type->name, lifetime); class_scope->type = type; assert(pform_cur_class == 0); pform_cur_class = class_scope; @@ -127,7 +131,7 @@ void pform_set_constructor_return(PFunction*net) PFunction*pform_push_constructor_scope(const struct vlltype&loc) { assert(pform_cur_class); - PFunction*func = pform_push_function_scope(loc, "new", true); + PFunction*func = pform_push_function_scope(loc, "new", LexicalScope::AUTOMATIC); return func; } @@ -138,7 +142,7 @@ void pform_end_class_declaration(const struct vlltype&loc) // If there were initializer statements, then collect them // into an implicit constructor function. if (! pform_cur_class->type->initialize.empty()) { - PFunction*func = pform_push_function_scope(loc, "new@", true); + PFunction*func = pform_push_function_scope(loc, "new@", LexicalScope::AUTOMATIC); func->set_ports(0); pform_set_constructor_return(func); pform_set_this_class(loc, func); From 5bbb054173dec1300add7090a143e7da7d9192da Mon Sep 17 00:00:00 2001 From: Martin Whitaker Date: Sat, 19 Mar 2016 20:39:54 +0000 Subject: [PATCH 22/51] Add check for explicit lifetime when initialising static variables. If a static variable declared in a task, function, or block has an initialisation expression, SystemVerilog requires the declaration to have an explicit static lifetime. This is supposed to be a compile error, but for now just output a warning. Implementing this required adding support in the parser for explicit lifetimes in variable declarations. For now, just output an error if the user asks for a lifetime that isn't the default for that scope. (cherry picked from commit 9538c81d342c7bdf2ad81ad22966f179dd290bfd) --- PScope.cc | 6 +++++- PScope.h | 7 +++++-- PTask.cc | 5 +++++ PTask.h | 2 ++ Statement.cc | 5 +++++ Statement.h | 2 ++ parse.y | 45 +++++++++++++++++++++++++++++++++++++++++---- pform.cc | 1 + 8 files changed, 66 insertions(+), 7 deletions(-) diff --git a/PScope.cc b/PScope.cc index 377142bf9..9add20a1b 100644 --- a/PScope.cc +++ b/PScope.cc @@ -19,6 +19,11 @@ # include "PScope.h" +bool LexicalScope::var_init_needs_explicit_lifetime() const +{ + return false; +} + PScope::PScope(perm_string n, LexicalScope*parent) : LexicalScope(parent), name_(n) { @@ -58,4 +63,3 @@ PScopeExtra::PScopeExtra(perm_string n) PScopeExtra::~PScopeExtra() { } - diff --git a/PScope.h b/PScope.h index 081d9fb58..ce6f94afb 100644 --- a/PScope.h +++ b/PScope.h @@ -53,11 +53,12 @@ class NetScope; class LexicalScope { public: - explicit LexicalScope(LexicalScope*parent) : parent_(parent) { } + enum lifetime_t { INHERITED, STATIC, AUTOMATIC }; + + explicit LexicalScope(LexicalScope*parent) : default_lifetime(INHERITED), parent_(parent) { } // A virtual destructor is so that dynamic_cast can work. virtual ~LexicalScope() { } - enum lifetime_t { INHERITED, STATIC, AUTOMATIC }; lifetime_t default_lifetime; struct range_t { @@ -124,6 +125,8 @@ class LexicalScope { LexicalScope* parent_scope() const { return parent_; } + virtual bool var_init_needs_explicit_lifetime() const; + protected: void dump_typedefs_(ostream&out, unsigned indent) const; diff --git a/PTask.cc b/PTask.cc index 034f38da6..93f8ba10f 100644 --- a/PTask.cc +++ b/PTask.cc @@ -30,6 +30,11 @@ PTaskFunc::~PTaskFunc() { } +bool PTaskFunc::var_init_needs_explicit_lifetime() const +{ + return default_lifetime == STATIC; +} + void PTaskFunc::set_ports(vector*p) { assert(ports_ == 0); diff --git a/PTask.h b/PTask.h index 1b636d05a..4c1899d04 100644 --- a/PTask.h +++ b/PTask.h @@ -41,6 +41,8 @@ class PTaskFunc : public PScope, public LineInfo { PTaskFunc(perm_string name, LexicalScope*parent); ~PTaskFunc(); + bool var_init_needs_explicit_lifetime() const; + void set_ports(std::vector*p); void set_this(class_type_t*use_type, PWire*this_wire); diff --git a/Statement.cc b/Statement.cc index e0ed46d24..942558107 100644 --- a/Statement.cc +++ b/Statement.cc @@ -115,6 +115,11 @@ PBlock::~PBlock() delete list_[idx]; } +bool PBlock::var_init_needs_explicit_lifetime() const +{ + return default_lifetime == STATIC; +} + PChainConstructor* PBlock::extract_chain_constructor() { if (list_.empty()) diff --git a/Statement.h b/Statement.h index cc7214194..18e4c0f9a 100644 --- a/Statement.h +++ b/Statement.h @@ -183,6 +183,8 @@ class PBlock : public PScope, public Statement { BL_TYPE bl_type() const { return bl_type_; } + bool var_init_needs_explicit_lifetime() const; + // This is only used if this block is the statement list for a // constructor. We look for a PChainConstructor as the first // statement, and if it is there, extract it. diff --git a/parse.y b/parse.y index 1b0fec636..b9f90933e 100644 --- a/parse.y +++ b/parse.y @@ -65,6 +65,10 @@ static PTask* current_task = 0; static PFunction* current_function = 0; static stack current_block_stack; +/* The variable declaration rules need to know if a lifetime has been + specified. */ +static LexicalScope::lifetime_t var_lifetime; + static pform_name_t* pform_create_this(void) { name_component_t name (perm_string::literal("@")); @@ -667,7 +671,7 @@ static void current_function_set_statement(const YYLTYPE&loc, vector %type atom2_type %type module_start module_end -%type lifetime_opt +%type lifetime lifetime_opt %token K_TAND %right K_PLUS_EQ K_MINUS_EQ K_MUL_EQ K_DIV_EQ K_MOD_EQ K_AND_EQ K_OR_EQ @@ -1369,10 +1373,14 @@ jump_statement /* IEEE1800-2005: A.6.5 */ } ; -lifetime_opt /* IEEE1800-2005: A.2.1.3 */ +lifetime /* IEEE1800-2005: A.2.1.3 */ : K_automatic { $$ = LexicalScope::AUTOMATIC; } | K_static { $$ = LexicalScope::STATIC; } - | { $$ = LexicalScope::INHERITED; } + ; + +lifetime_opt /* IEEE1800-2005: A.2.1.3 */ + : lifetime { $$ = $1; } + | { $$ = LexicalScope::INHERITED; } ; /* Loop statements are kinds of statements. */ @@ -2254,6 +2262,19 @@ variable_dimension /* IEEE1800-2005: A.2.5 */ } ; +variable_lifetime + : lifetime + { if (!gn_system_verilog()) { + yyerror(@1, "error: overriding the default variable lifetime " + "requires SystemVerilog."); + } else if ($1 != pform_peek_scope()->default_lifetime) { + yyerror(@1, "sorry: overriding the default variable lifetime " + "is not yet supported."); + } + var_lifetime = $1; + } + ; + /* 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. */ @@ -2328,10 +2349,20 @@ block_item_decl { if ($1) pform_set_data_type(@1, $1, $2, NetNet::REG, attributes_in_context); } + | variable_lifetime data_type register_variable_list ';' + { if ($2) pform_set_data_type(@2, $2, $3, NetNet::REG, attributes_in_context); + var_lifetime = LexicalScope::INHERITED; + } + | K_reg data_type register_variable_list ';' { if ($2) pform_set_data_type(@2, $2, $3, NetNet::REG, attributes_in_context); } + | variable_lifetime K_reg data_type register_variable_list ';' + { if ($3) pform_set_data_type(@3, $3, $4, NetNet::REG, attributes_in_context); + var_lifetime = LexicalScope::INHERITED; + } + | K_event event_variable_list ';' { if ($2) pform_make_events($2, @1.text, @1.first_line); } @@ -5492,7 +5523,13 @@ register_variable $$ = $1; } | IDENTIFIER dimensions_opt '=' expression - { perm_string name = lex_strings.make($1); + { if (pform_peek_scope()->var_init_needs_explicit_lifetime() + && (var_lifetime == LexicalScope::INHERITED)) { + cerr << @3 << ": warning: Static variable initialization requires " + "explicit lifetime in this context." << endl; + warn_count += 1; + } + perm_string name = lex_strings.make($1); pform_makewire(@1, name, NetNet::REG, NetNet::NOT_A_PORT, IVL_VT_NO_TYPE, 0); pform_set_reg_idx(name, $2); diff --git a/pform.cc b/pform.cc index 34a5eb638..95f0d5191 100644 --- a/pform.cc +++ b/pform.cc @@ -513,6 +513,7 @@ PBlock* pform_push_block_scope(char*name, PBlock::BL_TYPE bt) } PBlock*block = new PBlock(block_name, lexical_scope, bt); + block->default_lifetime = find_lifetime(LexicalScope::INHERITED); lexical_scope = block; return block; From 2689ebacfecdc86e0aa4ba2341f60cb700d15aaf Mon Sep 17 00:00:00 2001 From: Martin Whitaker Date: Mon, 18 Apr 2016 23:47:43 +0100 Subject: [PATCH 23/51] Extended fix for GitHub issue #99. Most vvp functors need to support recv_vec4_pv. Any that are strength-aware also need to support recv_vec8_pv. Note the simplifying assumption that is documented in the base class recv_vec4_pv_ implementation. (cherry picked from commit 6e5ed73b09fcfa60a010ca572a4ed75caf9e5b51) --- vvp/arith.cc | 49 +++++++++++++++++++++------------------------ vvp/arith.h | 16 +++++++++++++-- vvp/bufif.cc | 9 ++++++++- vvp/bufif.h | 6 +++++- vvp/delay.cc | 15 +++++++++++++- vvp/delay.h | 8 +++++++- vvp/dff.cc | 9 ++++++++- vvp/dff.h | 6 +++++- vvp/extend.cc | 9 ++++++++- vvp/npmos.cc | 28 ++++++++++++++++++++++++-- vvp/npmos.h | 14 ++++++++++++- vvp/substitute.cc | 13 +++++++++++- vvp/vvp_net.cc | 51 +++++++++++++++++++++++++++++++++++++++++++++++ vvp/vvp_net.h | 19 +++++++++++++++++- 14 files changed, 212 insertions(+), 40 deletions(-) diff --git a/vvp/arith.cc b/vvp/arith.cc index 1377d1623..c67846d9f 100644 --- a/vvp/arith.cc +++ b/vvp/arith.cc @@ -53,35 +53,11 @@ void vvp_arith_::dispatch_operand_(vvp_net_ptr_t ptr, vvp_vector4_t bit) void vvp_arith_::recv_vec4_pv(vvp_net_ptr_t ptr, const vvp_vector4_t&bit, unsigned base, unsigned wid, unsigned vwid, - vvp_context_t) + vvp_context_t ctx) { - unsigned port = ptr.port(); - - assert(bit.size() == wid); - assert(base + wid <= vwid); - - vvp_vector4_t tmp; - switch (port) { - case 0: - tmp = op_a_; - break; - case 1: - tmp = op_b_; - break; - default: - fprintf(stderr, "Unsupported port type %u.\n", port); - assert(0); - } - - // Set the part for the input. If nothing changes, then break. - bool flag = tmp.set_vec(base, bit); - if (flag == false) - return; - - recv_vec4(ptr, tmp, 0); + recv_vec4_pv_(ptr, bit, base, wid, vwid, ctx); } - vvp_arith_abs::vvp_arith_abs() { } @@ -112,6 +88,13 @@ void vvp_arith_abs::recv_vec4(vvp_net_ptr_t ptr, const vvp_vector4_t&bit, ptr.ptr()->send_vec4(out, 0); } +void vvp_arith_abs::recv_vec4_pv(vvp_net_ptr_t ptr, const vvp_vector4_t&bit, + unsigned base, unsigned wid, unsigned vwid, + vvp_context_t ctx) +{ + recv_vec4_pv_(ptr, bit, base, wid, vwid, ctx); +} + void vvp_arith_abs::recv_real(vvp_net_ptr_t ptr, double bit, vvp_context_t) { @@ -151,6 +134,13 @@ void vvp_arith_cast_real::recv_vec4(vvp_net_ptr_t ptr, const vvp_vector4_t&bit, ptr.ptr()->send_real(val, 0); } +void vvp_arith_cast_real::recv_vec4_pv(vvp_net_ptr_t ptr, const vvp_vector4_t&bit, + unsigned base, unsigned wid, unsigned vwid, + vvp_context_t ctx) +{ + recv_vec4_pv_(ptr, bit, base, wid, vwid, ctx); +} + vvp_arith_cast_vec2::vvp_arith_cast_vec2(unsigned wid) : wid_(wid) { @@ -173,6 +163,13 @@ void vvp_arith_cast_vec2::recv_vec4(vvp_net_ptr_t ptr, const vvp_vector4_t&bit, ptr.ptr()->send_vec4(vector2_to_vector4(tmp,wid_), 0); } +void vvp_arith_cast_vec2::recv_vec4_pv(vvp_net_ptr_t ptr, const vvp_vector4_t&bit, + unsigned base, unsigned wid, unsigned vwid, + vvp_context_t ctx) +{ + recv_vec4_pv_(ptr, bit, base, wid, vwid, ctx); +} + // Division vvp_arith_div::vvp_arith_div(unsigned wid, bool signed_flag) diff --git a/vvp/arith.h b/vvp/arith.h index 097434206..5c6945526 100644 --- a/vvp/arith.h +++ b/vvp/arith.h @@ -37,9 +37,9 @@ class vvp_arith_ : public vvp_net_fun_t { public: explicit vvp_arith_(unsigned wid); - void recv_vec4_pv(vvp_net_ptr_t p, const vvp_vector4_t&bit, + void recv_vec4_pv(vvp_net_ptr_t ptr, const vvp_vector4_t&bit, unsigned base, unsigned wid, unsigned vwid, - vvp_context_t); + vvp_context_t ctx); protected: void dispatch_operand_(vvp_net_ptr_t ptr, vvp_vector4_t bit); @@ -63,6 +63,10 @@ class vvp_arith_abs : public vvp_net_fun_t { void recv_real(vvp_net_ptr_t ptr, double bit, vvp_context_t); + void recv_vec4_pv(vvp_net_ptr_t ptr, const vvp_vector4_t&bit, + unsigned base, unsigned wid, unsigned vwid, + vvp_context_t ctx); + private: }; @@ -86,6 +90,10 @@ class vvp_arith_cast_real : public vvp_net_fun_t { void recv_vec4(vvp_net_ptr_t ptr, const vvp_vector4_t&bit, vvp_context_t); + void recv_vec4_pv(vvp_net_ptr_t ptr, const vvp_vector4_t&bit, + unsigned base, unsigned wid, unsigned vwid, + vvp_context_t ctx); + private: bool signed_; }; @@ -100,6 +108,10 @@ class vvp_arith_cast_vec2 : public vvp_net_fun_t { void recv_vec4(vvp_net_ptr_t ptr, const vvp_vector4_t&bit, vvp_context_t); + void recv_vec4_pv(vvp_net_ptr_t ptr, const vvp_vector4_t&bit, + unsigned base, unsigned wid, unsigned vwid, + vvp_context_t ctx); + private: unsigned wid_; }; diff --git a/vvp/bufif.cc b/vvp/bufif.cc index 9a1bc8df0..25469936e 100644 --- a/vvp/bufif.cc +++ b/vvp/bufif.cc @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001-2010 Stephen Williams (steve@icarus.com) + * Copyright (c) 2001-2016 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 @@ -81,3 +81,10 @@ void vvp_fun_bufif::recv_vec4(vvp_net_ptr_t ptr, const vvp_vector4_t&bit, ptr.ptr()->send_vec8(out); } + +void vvp_fun_bufif::recv_vec4_pv(vvp_net_ptr_t ptr, const vvp_vector4_t&bit, + unsigned base, unsigned wid, unsigned vwid, + vvp_context_t ctx) +{ + recv_vec4_pv_(ptr, bit, base, wid, vwid, ctx); +} diff --git a/vvp/bufif.h b/vvp/bufif.h index 8cb3bc57e..1bbf79544 100644 --- a/vvp/bufif.h +++ b/vvp/bufif.h @@ -1,7 +1,7 @@ #ifndef IVL_bufif_H #define IVL_bufif_H /* - * Copyright (c) 2001-2014 Stephen Williams (steve@icarus.com) + * Copyright (c) 2001-2016 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 @@ -40,6 +40,10 @@ class vvp_fun_bufif : public vvp_net_fun_t { void recv_vec4(vvp_net_ptr_t port, const vvp_vector4_t&bit, vvp_context_t); + void recv_vec4_pv(vvp_net_ptr_t ptr, const vvp_vector4_t&bit, + unsigned base, unsigned wid, unsigned vwid, + vvp_context_t ctx); + private: vvp_vector4_t bit_; vvp_vector4_t en_; diff --git a/vvp/delay.cc b/vvp/delay.cc index 5bda67ad8..fbb83236d 100644 --- a/vvp/delay.cc +++ b/vvp/delay.cc @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005-2014 Stephen Williams + * Copyright (c) 2005-2016 Stephen Williams * * This source code is free software; you can redistribute it * and/or modify it in source code form under the terms of the GNU @@ -332,6 +332,13 @@ void vvp_fun_delay::recv_vec4(vvp_net_ptr_t port, const vvp_vector4_t&bit, } } +void vvp_fun_delay::recv_vec4_pv(vvp_net_ptr_t ptr, const vvp_vector4_t&bit, + unsigned base, unsigned wid, unsigned vwid, + vvp_context_t ctx) +{ + recv_vec4_pv_(ptr, bit, base, wid, vwid, ctx); +} + /* See the recv_vec4 comment above. */ void vvp_fun_delay::recv_vec8(vvp_net_ptr_t port, const vvp_vector8_t&bit) { @@ -397,6 +404,12 @@ void vvp_fun_delay::recv_vec8(vvp_net_ptr_t port, const vvp_vector8_t&bit) } } +void vvp_fun_delay::recv_vec8_pv(vvp_net_ptr_t ptr, const vvp_vector8_t&bit, + unsigned base, unsigned wid, unsigned vwid) +{ + recv_vec8_pv_(ptr, bit, base, wid, vwid); +} + void vvp_fun_delay::recv_real(vvp_net_ptr_t port, double bit, vvp_context_t) { diff --git a/vvp/delay.h b/vvp/delay.h index 6a3815ce3..b565a434f 100644 --- a/vvp/delay.h +++ b/vvp/delay.h @@ -1,7 +1,7 @@ #ifndef IVL_delay_H #define IVL_delay_H /* - * Copyright 2005-2014 Stephen Williams + * Copyright 2005-2016 Stephen Williams * * This source code is free software; you can redistribute it * and/or modify it in source code form under the terms of the GNU @@ -99,6 +99,12 @@ class vvp_fun_delay : public vvp_net_fun_t, private vvp_gen_event_s { vvp_context_t); //void recv_long(vvp_net_ptr_t port, long bit); + void recv_vec4_pv(vvp_net_ptr_t ptr, const vvp_vector4_t&bit, + unsigned base, unsigned wid, unsigned vwid, + vvp_context_t ctx); + void recv_vec8_pv(vvp_net_ptr_t ptr, const vvp_vector8_t&bit, + unsigned base, unsigned wid, unsigned vwid); + private: virtual void run_run(); diff --git a/vvp/dff.cc b/vvp/dff.cc index 2df5d0878..b77cbf547 100644 --- a/vvp/dff.cc +++ b/vvp/dff.cc @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005-2015 Stephen Williams (steve@icarus.com) + * Copyright (c) 2005-2016 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 @@ -103,6 +103,13 @@ void vvp_dff::recv_vec4(vvp_net_ptr_t port, const vvp_vector4_t&bit, } } +void vvp_dff::recv_vec4_pv(vvp_net_ptr_t ptr, const vvp_vector4_t&bit, + unsigned base, unsigned wid, unsigned vwid, + vvp_context_t ctx) +{ + recv_vec4_pv_(ptr, bit, base, wid, vwid, ctx); +} + /* * The recv_async functions respond to the asynchronous * set/clear input by propagating the desired output. diff --git a/vvp/dff.h b/vvp/dff.h index d069a68ba..17924af08 100644 --- a/vvp/dff.h +++ b/vvp/dff.h @@ -1,7 +1,7 @@ #ifndef IVL_dff_H #define IVL_dff_H /* - * Copyright (c) 2005-2015 Stephen Williams (steve@icarus.com) + * Copyright (c) 2005-2016 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 @@ -44,6 +44,10 @@ class vvp_dff : public vvp_net_fun_t { void recv_vec4(vvp_net_ptr_t port, const vvp_vector4_t&bit, vvp_context_t); + void recv_vec4_pv(vvp_net_ptr_t ptr, const vvp_vector4_t&bit, + unsigned base, unsigned wid, unsigned vwid, + vvp_context_t ctx); + private: virtual void recv_async(vvp_net_ptr_t port); diff --git a/vvp/extend.cc b/vvp/extend.cc index cb484ea83..ea7c8419b 100644 --- a/vvp/extend.cc +++ b/vvp/extend.cc @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005-2010 Stephen Williams + * Copyright (c) 2005-2016 Stephen Williams * * This source code is free software; you can redistribute it * and/or modify it in source code form under the terms of the GNU @@ -51,3 +51,10 @@ void vvp_fun_extend_signed::recv_vec4(vvp_net_ptr_t port, const vvp_vector4_t&bi port.ptr()->send_vec4(res, 0); } + +void vvp_fun_extend_signed::recv_vec4_pv(vvp_net_ptr_t ptr, const vvp_vector4_t&bit, + unsigned base, unsigned wid, unsigned vwid, + vvp_context_t ctx) +{ + recv_vec4_pv_(ptr, bit, base, wid, vwid, ctx); +} diff --git a/vvp/npmos.cc b/vvp/npmos.cc index 11b633916..1359c9691 100644 --- a/vvp/npmos.cc +++ b/vvp/npmos.cc @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005 Stephen Williams (steve@icarus.com) + * Copyright (c) 2005-2016 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 @@ -43,6 +43,19 @@ void vvp_fun_pmos_::recv_vec4(vvp_net_ptr_t ptr, const vvp_vector4_t&bit, generate_output_(ptr); } +void vvp_fun_pmos_::recv_vec4_pv(vvp_net_ptr_t ptr, const vvp_vector4_t&bit, + unsigned base, unsigned wid, unsigned vwid, + vvp_context_t ctx) +{ + recv_vec4_pv_(ptr, bit, base, wid, vwid, ctx); +} + +void vvp_fun_pmos_::recv_vec8_pv(vvp_net_ptr_t ptr, const vvp_vector8_t&bit, + unsigned base, unsigned wid, unsigned vwid) +{ + recv_vec8_pv_(ptr, bit, base, wid, vwid); +} + void vvp_fun_pmos_::generate_output_(vvp_net_ptr_t ptr) { vvp_vector8_t out (bit_.size()); @@ -147,7 +160,18 @@ void vvp_fun_cmos_::recv_vec4(vvp_net_ptr_t ptr, const vvp_vector4_t &bit, generate_output_(ptr); } -#include +void vvp_fun_cmos_::recv_vec4_pv(vvp_net_ptr_t ptr, const vvp_vector4_t&bit, + unsigned base, unsigned wid, unsigned vwid, + vvp_context_t ctx) +{ + recv_vec4_pv_(ptr, bit, base, wid, vwid, ctx); +} + +void vvp_fun_cmos_::recv_vec8_pv(vvp_net_ptr_t ptr, const vvp_vector8_t&bit, + unsigned base, unsigned wid, unsigned vwid) +{ + recv_vec8_pv_(ptr, bit, base, wid, vwid); +} void vvp_fun_cmos_::generate_output_(vvp_net_ptr_t ptr) { diff --git a/vvp/npmos.h b/vvp/npmos.h index 4bbcc199e..cb6950685 100644 --- a/vvp/npmos.h +++ b/vvp/npmos.h @@ -1,7 +1,7 @@ #ifndef IVL_npmos_H #define IVL_npmos_H /* - * Copyright (c) 2005-2014 Stephen Williams (steve@icarus.com) + * Copyright (c) 2005-2016 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 @@ -51,6 +51,12 @@ class vvp_fun_pmos_ : public vvp_net_fun_t { void recv_vec4(vvp_net_ptr_t port, const vvp_vector4_t&bit, vvp_context_t); + void recv_vec4_pv(vvp_net_ptr_t ptr, const vvp_vector4_t&bit, + unsigned base, unsigned wid, unsigned vwid, + vvp_context_t ctx); + void recv_vec8_pv(vvp_net_ptr_t ptr, const vvp_vector8_t&bit, + unsigned base, unsigned wid, unsigned vwid); + protected: void generate_output_(vvp_net_ptr_t port); @@ -108,6 +114,12 @@ class vvp_fun_cmos_ : public vvp_net_fun_t { void recv_vec4(vvp_net_ptr_t port, const vvp_vector4_t &bit, vvp_context_t); + void recv_vec4_pv(vvp_net_ptr_t ptr, const vvp_vector4_t&bit, + unsigned base, unsigned wid, unsigned vwid, + vvp_context_t ctx); + void recv_vec8_pv(vvp_net_ptr_t ptr, const vvp_vector8_t&bit, + unsigned base, unsigned wid, unsigned vwid); + protected: void generate_output_(vvp_net_ptr_t port); diff --git a/vvp/substitute.cc b/vvp/substitute.cc index 04e83d460..09d516733 100644 --- a/vvp/substitute.cc +++ b/vvp/substitute.cc @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014 Stephen Williams (steve@icarus.com) + * Copyright (c) 2016 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 @@ -32,6 +32,10 @@ class vvp_fun_substitute : public vvp_net_fun_t { void recv_vec4(vvp_net_ptr_t port, const vvp_vector4_t&bit, vvp_context_t); + void recv_vec4_pv(vvp_net_ptr_t ptr, const vvp_vector4_t&bit, + unsigned base, unsigned wid, unsigned vwid, + vvp_context_t ctx); + private: unsigned wid_; unsigned soff_; @@ -77,6 +81,13 @@ void vvp_fun_substitute::recv_vec4(vvp_net_ptr_t port, const vvp_vector4_t&bit, port.ptr()->send_vec4(val_, 0); } +void vvp_fun_substitute::recv_vec4_pv(vvp_net_ptr_t ptr, const vvp_vector4_t&bit, + unsigned base, unsigned wid, unsigned vwid, + vvp_context_t ctx) +{ + recv_vec4_pv_(ptr, bit, base, wid, vwid, ctx); +} + void compile_substitute(char*label, unsigned width, unsigned soff, unsigned swidth, unsigned argc, struct symb_s*argv) diff --git a/vvp/vvp_net.cc b/vvp/vvp_net.cc index bf8edffff..864f72bbd 100644 --- a/vvp/vvp_net.cc +++ b/vvp/vvp_net.cc @@ -3249,6 +3249,31 @@ void vvp_net_fun_t::recv_vec4(vvp_net_ptr_t, const vvp_vector4_t&, assert(0); } +void vvp_net_fun_t::recv_vec4_pv_(vvp_net_ptr_t p, const vvp_vector4_t&bit, + unsigned base, unsigned wid, unsigned vwid, + vvp_context_t) +{ + // The majority of functors don't normally expect to receive part + // values, because the primary operands of an expression will be + // extended to the expression width. But in the case that a primary + // operand is a wire that is only partly driven by a single driver, + // the part value driven onto the wire propagates directly to the + // inputs of any functors connected to that wire. In this case we + // know that the remaining bits are undriven, so can simply build + // the full width value from the part we have received. + // + // Note that this case is almost certainly a bug in the user's + // code, but we still need to handle it correctly. See GitHub + // issue #99 and br_gh99*.v in the test suite for examples. + + assert(bit.size() == wid); + assert(base + wid <= vwid); + + vvp_vector4_t tmp(vwid, BIT4_Z); + tmp.set_vec(base, bit); + recv_vec4(p, tmp, 0); +} + void vvp_net_fun_t::recv_vec4_pv(vvp_net_ptr_t, const vvp_vector4_t&bit, unsigned base, unsigned wid, unsigned vwid, vvp_context_t) @@ -3264,6 +3289,19 @@ void vvp_net_fun_t::recv_vec8(vvp_net_ptr_t port, const vvp_vector8_t&bit) recv_vec4(port, reduce4(bit), 0); } +void vvp_net_fun_t::recv_vec8_pv_(vvp_net_ptr_t p, const vvp_vector8_t&bit, + unsigned base, unsigned wid, unsigned vwid) +{ + // This is the strength-aware version of recv_vec4_pv_. + + assert(bit.size() == wid); + assert(base + wid <= vwid); + + vvp_vector8_t tmp(vwid); + tmp.set_vec(base, bit); + recv_vec8(p, tmp); +} + void vvp_net_fun_t::recv_vec8_pv(vvp_net_ptr_t port, const vvp_vector8_t&bit, unsigned base, unsigned wid, unsigned vwid) { @@ -3331,6 +3369,12 @@ void vvp_fun_drive::recv_vec4(vvp_net_ptr_t port, const vvp_vector4_t&bit, port.ptr()->send_vec8(vvp_vector8_t(bit, drive0_, drive1_)); } +void vvp_fun_drive::recv_vec4_pv(vvp_net_ptr_t ptr, const vvp_vector4_t&bit, + unsigned base, unsigned wid, unsigned vwid, + vvp_context_t ctx) +{ + recv_vec4_pv_(ptr, bit, base, wid, vwid, ctx); +} /* **** vvp_wide_fun_* methods **** */ @@ -3426,6 +3470,13 @@ void vvp_wide_fun_t::recv_vec4(vvp_net_ptr_t port, const vvp_vector4_t&bit, core_->dispatch_vec4_from_input_(pidx, bit); } +void vvp_wide_fun_t::recv_vec4_pv(vvp_net_ptr_t ptr, const vvp_vector4_t&bit, + unsigned base, unsigned wid, unsigned vwid, + vvp_context_t ctx) +{ + recv_vec4_pv_(ptr, bit, base, wid, vwid, ctx); +} + void vvp_wide_fun_t::recv_real(vvp_net_ptr_t port, double bit, vvp_context_t) { diff --git a/vvp/vvp_net.h b/vvp/vvp_net.h index ab90e4221..a59045780 100644 --- a/vvp/vvp_net.h +++ b/vvp/vvp_net.h @@ -1,7 +1,7 @@ #ifndef IVL_vvp_net_H #define IVL_vvp_net_H /* - * Copyright (c) 2004-2015 Stephen Williams (steve@icarus.com) + * Copyright (c) 2004-2016 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 @@ -1230,6 +1230,13 @@ class vvp_net_fun_t { // do something about it. virtual void force_flag(bool run_now); + protected: + void recv_vec4_pv_(vvp_net_ptr_t p, const vvp_vector4_t&bit, + unsigned base, unsigned wid, unsigned vwid, + vvp_context_t context); + void recv_vec8_pv_(vvp_net_ptr_t p, const vvp_vector8_t&bit, + unsigned base, unsigned wid, unsigned vwid); + public: // These objects are only permallocated. static void* operator new(std::size_t size) { return heap_.alloc(size); } static void operator delete(void*); // not implemented @@ -1470,6 +1477,9 @@ class vvp_fun_drive : public vvp_net_fun_t { vvp_context_t context); //void recv_long(vvp_net_ptr_t port, long bit); + void recv_vec4_pv(vvp_net_ptr_t port, const vvp_vector4_t&bit, + unsigned base, unsigned wid, unsigned vwid, + vvp_context_t); private: unsigned char drive0_; unsigned char drive1_; @@ -1490,6 +1500,9 @@ class vvp_fun_extend_signed : public vvp_net_fun_t { void recv_vec4(vvp_net_ptr_t port, const vvp_vector4_t&bit, vvp_context_t context); + void recv_vec4_pv(vvp_net_ptr_t port, const vvp_vector4_t&bit, + unsigned base, unsigned wid, unsigned vwid, + vvp_context_t); private: unsigned width_; }; @@ -1571,6 +1584,10 @@ class vvp_wide_fun_t : public vvp_net_fun_t { void recv_real(vvp_net_ptr_t port, double bit, vvp_context_t context); + void recv_vec4_pv(vvp_net_ptr_t p, const vvp_vector4_t&bit, + unsigned base, unsigned wid, unsigned vwid, + vvp_context_t context); + private: vvp_wide_fun_core*core_; unsigned port_base_; From b46d8b8389d01357e8631c4c689dd0b6055b6be2 Mon Sep 17 00:00:00 2001 From: Martin Whitaker Date: Mon, 4 Apr 2016 20:40:30 +0100 Subject: [PATCH 24/51] Fix for br974 - support SV types in non-ansi port declarations. (cherry picked from commit 6ba2bee977e17c9c4cfe8c4ea8a1545394c1ccc4) --- parse.y | 165 ++++++++++++++++++++++++++++++++------------------ pform.cc | 84 +++++++++++++++++++++---- pform.h | 25 +++++--- pform_types.h | 17 +++++- 4 files changed, 209 insertions(+), 82 deletions(-) diff --git a/parse.y b/parse.y index b9f90933e..b030fdbed 100644 --- a/parse.y +++ b/parse.y @@ -135,17 +135,17 @@ static list*attributes_in_context = 0; static const struct str_pair_t pull_strength = { IVL_DR_PULL, IVL_DR_PULL }; static const struct str_pair_t str_strength = { IVL_DR_STRONG, IVL_DR_STRONG }; -static list >* make_port_list(char*id, PExpr*expr) +static list* make_port_list(char*id, list*udims, PExpr*expr) { - list >*tmp = new list >; - tmp->push_back(make_pair(lex_strings.make(id), expr)); + list*tmp = new list; + tmp->push_back(pform_port_t(lex_strings.make(id), udims, expr)); delete[]id; return tmp; } -static list >* make_port_list(list >*tmp, - char*id, PExpr*expr) +static list* make_port_list(list*tmp, + char*id, list*udims, PExpr*expr) { - tmp->push_back(make_pair(lex_strings.make(id), expr)); + tmp->push_back(pform_port_t(lex_strings.make(id), udims, expr)); delete[]id; return tmp; } @@ -374,7 +374,7 @@ static void current_function_set_statement(const YYLTYPE&loc, vector char*text; list*perm_strings; - list >*port_list; + list*port_list; vector* tf_ports; @@ -582,7 +582,7 @@ static void current_function_set_statement(const YYLTYPE&loc, vector %type register_variable net_variable event_variable endlabel_opt class_declaration_endlabel_opt %type register_variable_list net_variable_list event_variable_list %type list_of_identifiers loop_variables -%type list_of_port_identifiers +%type list_of_port_identifiers list_of_variable_port_identifiers %type net_decl_assign net_decl_assigns @@ -642,7 +642,7 @@ static void current_function_set_statement(const YYLTYPE&loc, vector %type variable_dimension %type dimensions_opt dimensions -%type net_type var_type net_type_opt +%type net_type net_type_opt %type gatetype switchtype %type port_direction port_direction_opt %type bit_logic bit_logic_opt @@ -4048,14 +4048,21 @@ list_of_identifiers ; list_of_port_identifiers - : IDENTIFIER - { $$ = make_port_list($1, 0); } - | IDENTIFIER '=' expression - { $$ = make_port_list($1, $3); } - | list_of_port_identifiers ',' IDENTIFIER - { $$ = make_port_list($1, $3, 0); } - | list_of_port_identifiers ',' IDENTIFIER '=' expression - { $$ = make_port_list($1, $3, $5); } + : IDENTIFIER dimensions_opt + { $$ = make_port_list($1, $2, 0); } + | list_of_port_identifiers ',' IDENTIFIER dimensions_opt + { $$ = make_port_list($1, $3, $4, 0); } + ; + +list_of_variable_port_identifiers + : IDENTIFIER dimensions_opt + { $$ = make_port_list($1, $2, 0); } + | IDENTIFIER dimensions_opt '=' expression + { $$ = make_port_list($1, $2, $4); } + | list_of_variable_port_identifiers ',' IDENTIFIER dimensions_opt + { $$ = make_port_list($1, $3, $4, 0); } + | list_of_variable_port_identifiers ',' IDENTIFIER dimensions_opt '=' expression + { $$ = make_port_list($1, $3, $4, $6); } ; @@ -4643,58 +4650,102 @@ module_item delete $4; } - | attribute_list_opt port_direction unsigned_signed_opt dimensions_opt delay3_opt list_of_identifiers ';' - { pform_set_port_type(@2, $6, $4, $3, $2, $1); } - /* The next two rules handle Verilog 2001 statements of the form: + /* The next two rules handle port declarations that include a net type, e.g. input wire signed [h:l] ; This creates the wire and sets the port type all at once. */ - | attribute_list_opt port_direction net_type unsigned_signed_opt dimensions_opt list_of_identifiers ';' - { pform_makewire(@2, $5, $4, $6, $3, $2, IVL_VT_NO_TYPE, $1, SR_BOTH); } + | attribute_list_opt port_direction net_type data_type_or_implicit list_of_port_identifiers ';' + { pform_module_define_port(@2, $5, $2, $3, $4, $1); } - | attribute_list_opt K_output var_type unsigned_signed_opt dimensions_opt list_of_port_identifiers ';' - { list >::const_iterator pp; - list*tmp = new list; - for (pp = $6->begin(); pp != $6->end(); ++ pp ) { - tmp->push_back((*pp).first); + | attribute_list_opt port_direction K_wreal list_of_port_identifiers ';' + { real_type_t*real_type = new real_type_t(real_type_t::REAL); + pform_module_define_port(@2, $4, $2, NetNet::WIRE, real_type, $1); + } + + /* The next three rules handle port declarations that include a variable + type, e.g. + output reg signed [h:l] ; + and also handle incomplete port declarations, e.g. + input signed [h:l] ; + */ + | attribute_list_opt K_inout data_type_or_implicit list_of_port_identifiers ';' + { NetNet::Type use_type = $3 ? NetNet::IMPLICIT : NetNet::NONE; + if (vector_type_t*dtype = dynamic_cast ($3)) { + if (dtype->implicit_flag) + use_type = NetNet::NONE; } - pform_makewire(@2, $5, $4, tmp, $3, NetNet::POUTPUT, - IVL_VT_NO_TYPE, $1, SR_BOTH); - for (pp = $6->begin(); pp != $6->end(); ++ pp ) { - if ((*pp).second) { - pform_make_var_init(@2, (*pp).first, (*pp).second); - } + if (use_type == NetNet::NONE) + pform_set_port_type(@2, $4, NetNet::PINOUT, $3, $1); + else + pform_module_define_port(@2, $4, NetNet::PINOUT, use_type, $3, $1); + } + + | attribute_list_opt K_input data_type_or_implicit list_of_port_identifiers ';' + { NetNet::Type use_type = $3 ? NetNet::IMPLICIT : NetNet::NONE; + if (vector_type_t*dtype = dynamic_cast ($3)) { + if (dtype->implicit_flag) + use_type = NetNet::NONE; } - delete $6; + if (use_type == NetNet::NONE) + pform_set_port_type(@2, $4, NetNet::PINPUT, $3, $1); + else + pform_module_define_port(@2, $4, NetNet::PINPUT, use_type, $3, $1); } - | attribute_list_opt port_direction K_wreal list_of_identifiers ';' - { pform_makewire(@2, 0, true, $4, NetNet::WIRE, $2, - IVL_VT_REAL, $1, SR_BOTH); + | attribute_list_opt K_output data_type_or_implicit list_of_variable_port_identifiers ';' + { NetNet::Type use_type = $3 ? NetNet::IMPLICIT : NetNet::NONE; + if (vector_type_t*dtype = dynamic_cast ($3)) { + if (dtype->implicit_flag) + use_type = NetNet::NONE; + else if (dtype->reg_flag) + use_type = NetNet::REG; + else + use_type = NetNet::IMPLICIT_REG; + + // The SystemVerilog types that can show up as + // output ports are implicitly (on the inside) + // variables because "reg" is not valid syntax + // here. + } else if (dynamic_cast ($3)) { + use_type = NetNet::IMPLICIT_REG; + } else if (dynamic_cast ($3)) { + use_type = NetNet::IMPLICIT_REG; + } else if (enum_type_t*etype = dynamic_cast ($3)) { + if(etype->base_type == IVL_VT_LOGIC) + use_type = NetNet::IMPLICIT_REG; + } + if (use_type == NetNet::NONE) + pform_set_port_type(@2, $4, NetNet::POUTPUT, $3, $1); + else + pform_module_define_port(@2, $4, NetNet::POUTPUT, use_type, $3, $1); } - /* var_type declaration (reg variables) cannot be input or output, - because the port declaration implies an external driver, which - cannot be attached to a reg. These rules catch that error early. */ - - | attribute_list_opt K_input var_type unsigned_signed_opt dimensions_opt list_of_identifiers ';' - { pform_makewire(@2, $5, $4, $6, $3, NetNet::PINPUT, - IVL_VT_NO_TYPE, $1); - yyerror(@3, "error: reg variables cannot be inputs."); - } - - | attribute_list_opt K_inout var_type unsigned_signed_opt dimensions_opt list_of_identifiers ';' - { pform_makewire(@2, $5, $4, $6, $3, NetNet::PINOUT, - IVL_VT_NO_TYPE, $1); - yyerror(@3, "error: reg variables cannot be inouts."); - } - - | attribute_list_opt port_direction unsigned_signed_opt dimensions_opt delay3_opt error ';' + | attribute_list_opt port_direction net_type data_type_or_implicit error ';' { yyerror(@2, "error: Invalid variable list in port declaration."); if ($1) delete $1; if ($4) delete $4; - if ($5) delete $5; + yyerrok; + } + + | attribute_list_opt K_inout data_type_or_implicit error ';' + { yyerror(@2, "error: Invalid variable list in port declaration."); + if ($1) delete $1; + if ($3) delete $3; + yyerrok; + } + + | attribute_list_opt K_input data_type_or_implicit error ';' + { yyerror(@2, "error: Invalid variable list in port declaration."); + if ($1) delete $1; + if ($3) delete $3; + yyerrok; + } + + | attribute_list_opt K_output data_type_or_implicit error ';' + { yyerror(@2, "error: Invalid variable list in port declaration."); + if ($1) delete $1; + if ($3) delete $3; yyerrok; } @@ -5094,10 +5145,6 @@ net_type | K_uwire { $$ = NetNet::UNRESOLVED_WIRE; } ; -var_type - : K_reg { $$ = NetNet::REG; } - ; - param_type : bit_logic_opt unsigned_signed_opt dimensions_opt { param_active_range = $3; diff --git a/pform.cc b/pform.cc index 95f0d5191..059a9d32e 100644 --- a/pform.cc +++ b/pform.cc @@ -1939,6 +1939,7 @@ static void pform_set_net_range(perm_string name, VLerror("error: name is not a valid net."); return; } + // If this is not implicit ("implicit" meaning we don't // know what the type is yet) then set the type now. if (net_type != NetNet::IMPLICIT && net_type != NetNet::NONE) { @@ -2344,7 +2345,8 @@ void pform_module_define_port(const struct vlltype&li, NetNet::PortType port_kind, NetNet::Type type, data_type_t*vtype, - list*attr) + list*attr, + bool keep_attr) { struct_type_t*struct_type = 0; ivl_variable_type_t data_type = IVL_VT_NO_TYPE; @@ -2433,10 +2435,37 @@ void pform_module_define_port(const struct vlltype&li, cur->set_unpacked_idx(*urange); } - pform_bind_attributes(cur->attributes, attr); + pform_bind_attributes(cur->attributes, attr, keep_attr); pform_put_wire_in_scope(name, cur); } +void pform_module_define_port(const struct vlltype&li, + list*ports, + NetNet::PortType port_kind, + NetNet::Type type, + data_type_t*vtype, + list*attr) +{ + for (list::iterator cur = ports->begin() + ; cur != ports->end() ; ++ cur ) { + + data_type_t*use_type = vtype; + if (cur->udims) + use_type = new uarray_type_t(vtype, cur->udims); + + pform_module_define_port(li, cur->name, port_kind, type, use_type, + attr, true); + if (cur->udims) + delete use_type; + + if (cur->expr) + pform_make_var_init(li, cur->name, cur->expr); + } + + delete ports; + delete attr; +} + /* * This function makes a single signal (a wire, a reg, etc) as * requested by the parser. The name is unscoped, so I attach the @@ -3239,24 +3268,53 @@ static void pform_set_port_type(perm_string name, NetNet::PortType pt, } void pform_set_port_type(const struct vlltype&li, - list*names, - list*range, - bool signed_flag, + list*ports, NetNet::PortType pt, + data_type_t*dt, list*attr) { assert(pt != NetNet::PIMPLICIT && pt != NetNet::NOT_A_PORT); - for (list::iterator cur = names->begin() - ; cur != names->end() ; ++ cur ) { - perm_string txt = *cur; - pform_set_port_type(txt, pt, li.text, li.first_line); - pform_set_net_range(txt, NetNet::NONE, range, signed_flag, IVL_VT_NO_TYPE, - SR_PORT, attr); + list*range = 0; + bool signed_flag = false; + if (vector_type_t*vt = dynamic_cast (dt)) { + assert(vt->implicit_flag); + range = vt->pdims.get(); + signed_flag = vt->signed_flag; + } else { + assert(dt == 0); } - delete names; - delete range; + bool have_init_expr = false; + for (list::iterator cur = ports->begin() + ; cur != ports->end() ; ++ cur ) { + + pform_set_port_type(cur->name, pt, li.text, li.first_line); + pform_set_net_range(cur->name, NetNet::NONE, range, signed_flag, + IVL_VT_NO_TYPE, SR_PORT, attr); + if (cur->udims) { + cerr << li.text << ":" << li.first_line << ": warning: " + << "Array dimensions in incomplete port declarations " + << "are currently ignored." << endl; + cerr << li.text << ":" << li.first_line << ": : " + << "The dimensions specified in the net or variable " + << "declaration will be used." << endl; + delete cur->udims; + } + if (cur->expr) { + have_init_expr = true; + delete cur->expr; + } + } + if (have_init_expr) { + cerr << li.text << ":" << li.first_line << ": error: " + << "Incomplete port declarations cannot be initialized." + << endl; + error_count += 1; + } + + delete ports; + delete dt; delete attr; } diff --git a/pform.h b/pform.h index 21d5c3e75..b3544f9e9 100644 --- a/pform.h +++ b/pform.h @@ -168,14 +168,21 @@ extern void pform_startmodule(const struct vlltype&loc, const char*name, extern void pform_check_timeunit_prec(); extern void pform_module_set_ports(vector*); -/* This function is used to support the port definition in a - port_definition_list. In this case, we have everything needed to - define the port, all in one place. */ +/* These functions are used when we have a complete port definition, either + in an ansi style or non-ansi style declaration. In this case, we have + everything needed to define the port, all in one place. */ extern void pform_module_define_port(const struct vlltype&li, perm_string name, NetNet::PortType, NetNet::Type type, data_type_t*vtype, + list*attr, + bool keep_attr =false); +extern void pform_module_define_port(const struct vlltype&li, + list*ports, + NetNet::PortType, + NetNet::Type type, + data_type_t*vtype, list*attr); extern Module::port_t* pform_module_port_reference(perm_string name, @@ -364,14 +371,14 @@ extern void pform_makewire(const struct vlltype&li, extern void pform_make_var_init(const struct vlltype&li, perm_string name, PExpr*expr); - /* Look up the names of the wires, and set the port type, - i.e. input, output or inout. If the wire does not exist, create - it. The second form takes a single name. */ +/* This function is used when we have an incomplete port definition in + a non-ansi style declaration. Look up the names of the wires, and set + the port type, i.e. input, output or inout, and, if specified, the + range and signedness. If the wire does not exist, create it. */ extern void pform_set_port_type(const struct vlltype&li, - list*names, - list*range, - bool signed_flag, + list*ports, NetNet::PortType, + data_type_t*dt, list*attr); extern void pform_set_reg_idx(perm_string name, diff --git a/pform_types.h b/pform_types.h index 149ae9f27..22dab4b46 100644 --- a/pform_types.h +++ b/pform_types.h @@ -1,7 +1,7 @@ #ifndef IVL_pform_types_H #define IVL_pform_types_H /* - * Copyright (c) 2007-2014 Stephen Williams (steve@icarus.com) + * Copyright (c) 2007-2016 Stephen Williams (steve@icarus.com) * * This source code is free software; you can redistribute it * and/or modify it in source code form under the terms of the GNU @@ -72,6 +72,21 @@ typedef named named_pexpr_t; */ typedef std::pair pform_range_t; +/* + * The pform_port_t holds the name and optional unpacked dimensions + * and initialization expression for a single port in a list of port + * declarations. + */ +struct pform_port_t { + pform_port_t(perm_string n, list*ud, PExpr*e) + : name(n), udims(ud), expr(e) { } + ~pform_port_t() { } + + perm_string name; + list*udims; + PExpr*expr; +}; + /* * Semantic NOTES: * - The SEL_BIT is a single expression. This might me a bit select From 161cebb17883825ae02b857b5fc789398aeca498 Mon Sep 17 00:00:00 2001 From: Maciej Suminski Date: Wed, 24 Feb 2016 16:34:18 +0100 Subject: [PATCH 25/51] vvp: Corrected vvp_net_fun_t::recv_vec4_pv() (commit de968e18) (cherry picked from commit 9cf1dcbae205dc251b1fbd11acc5eb8f38550f21) --- vvp/part.cc | 9 +++++++++ vvp/part.h | 4 ++++ 2 files changed, 13 insertions(+) diff --git a/vvp/part.cc b/vvp/part.cc index 6ba40927a..d96f04405 100644 --- a/vvp/part.cc +++ b/vvp/part.cc @@ -208,6 +208,15 @@ void vvp_fun_part_pv::recv_vec4(vvp_net_ptr_t port, const vvp_vector4_t&bit, port.ptr()->send_vec4_pv(bit, base_, wid_, vwid_, context); } +void vvp_fun_part_pv::recv_vec4_pv(vvp_net_ptr_t port, const vvp_vector4_t&bit, + unsigned base, unsigned wid, unsigned vwid, + vvp_context_t ctx) +{ + assert(port.port() == 0); + + port.ptr()->send_vec4_pv(bit, base, wid, vwid, ctx); +} + void vvp_fun_part_pv::recv_vec8(vvp_net_ptr_t port, const vvp_vector8_t&bit) { assert(port.port() == 0); diff --git a/vvp/part.h b/vvp/part.h index 90a59a225..89d0018c6 100644 --- a/vvp/part.h +++ b/vvp/part.h @@ -109,6 +109,10 @@ class vvp_fun_part_pv : public vvp_net_fun_t { void recv_vec4(vvp_net_ptr_t port, const vvp_vector4_t&bit, vvp_context_t context); + void recv_vec4_pv(vvp_net_ptr_t port, const vvp_vector4_t&bit, + unsigned, unsigned, unsigned, + vvp_context_t); + void recv_vec8(vvp_net_ptr_t port, const vvp_vector8_t&bit); private: From b2281b0e655e8f0a3cf64c1769b301bcd18dcfbd Mon Sep 17 00:00:00 2001 From: Maciej Suminski Date: Tue, 1 Mar 2016 16:17:07 +0100 Subject: [PATCH 26/51] ivl: Fixed slice base calculation when range is rising (e.g. logic [0:3] arr) or when it starts with a non-zero integer (e.g. logic [4:1] arr). (cherry picked from commit de775975e8d846c2a591a7889dd26c96b76acbc3) --- netmisc.cc | 42 +++++++++++++++++++++++++++++++++++------- 1 file changed, 35 insertions(+), 7 deletions(-) diff --git a/netmisc.cc b/netmisc.cc index 6a68a9918..7f5de1761 100644 --- a/netmisc.cc +++ b/netmisc.cc @@ -248,6 +248,25 @@ static NetExpr* make_sub_expr(long val, NetExpr*expr) return res; } +/* + * Subtract a signed constant from an existing expression. + */ +static NetExpr* make_sub_expr(NetExpr*expr, long val) +{ + verinum val_v (val, expr->expr_width()); + val_v.has_sign(true); + + NetEConst*val_c = new NetEConst(val_v); + val_c->set_line(*expr); + + NetEBAdd*res = new NetEBAdd('-', expr, val_c, expr->expr_width(), + expr->has_sign()); + res->set_line(*expr); + + return res; +} + + /* * Multiple an existing expression by a signed positive number. * This does a lossless multiply, so the arguments will need to be @@ -434,17 +453,26 @@ NetExpr *normalize_variable_slice_base(const list&indices, NetExpr*base, -- pcur; } - long sb; - if (pcur->get_msb() >= pcur->get_lsb()) - sb = pcur->get_lsb(); - else - sb = pcur->get_msb(); - + long sb = min(pcur->get_lsb(), pcur->get_msb()); long loff; reg->sb_to_slice(indices, sb, loff, lwid); + bool idx_incr = pcur->get_msb() < pcur->get_lsb(); + + if(pcur->get_lsb() != 0) { + // Adjust the base for the case when the array range does not start from 0 + if(idx_incr) + base = make_sub_expr(pcur->get_lsb(), base); + else + base = make_sub_expr(base, pcur->get_lsb()); + } + base = make_mult_expr(base, lwid); - base = make_add_expr(base, loff); + + // TODO I do not see any influence of the lines below to the test suite + if(!idx_incr) + base = make_add_expr(base, loff); + return base; } From 30257e09147c025adf457ae299d85e096e801225 Mon Sep 17 00:00:00 2001 From: Maciej Suminski Date: Mon, 15 Feb 2016 15:12:40 +0100 Subject: [PATCH 27/51] ivl: Support for part selection in multidimensional packed ports assignment. (cherry picked from commit b4baace4b1bb89dbf16e31445b5c0b0d2cbdc1c3) --- elab_net.cc | 87 +++++++++++++++++++++++++++++++++++------------------ netmisc.cc | 2 +- 2 files changed, 58 insertions(+), 31 deletions(-) diff --git a/elab_net.cc b/elab_net.cc index 09a38f454..55bdbce9c 100644 --- a/elab_net.cc +++ b/elab_net.cc @@ -328,39 +328,66 @@ bool PEIdent::eval_part_select_(Design*des, NetScope*scope, NetNet*sig, return false; } - long lidx_tmp = sig->sb_to_idx(prefix_indices, lsb); - long midx_tmp = sig->sb_to_idx(prefix_indices, msb); - /* Detect reversed indices of a part select. */ - if (lidx_tmp > midx_tmp) { - cerr << get_fileline() << ": error: Part select " - << sig->name() << "[" << msb << ":" - << lsb << "] indices reversed." << endl; - cerr << get_fileline() << ": : Did you mean " - << sig->name() << "[" << lsb << ":" - << msb << "]?" << endl; - long tmp = midx_tmp; - midx_tmp = lidx_tmp; - lidx_tmp = tmp; - des->errors += 1; - } + if (prefix_indices.size()+1 < sig->packed_dims().size()) { + // Here we have a slice that doesn't have enough indices + // to get to a single slice. For example: + // wire [9:0][5:1] foo + // ... foo[4:3] ... + // Make this work by finding the indexed slices and + // creating a generated slice that spans the whole + // range. + long loff, moff; + unsigned long lwid, mwid; + bool lrc; + lrc = sig->sb_to_slice(prefix_indices, lsb, loff, lwid); + ivl_assert(*this, lrc); + lrc = sig->sb_to_slice(prefix_indices, msb, moff, mwid); + ivl_assert(*this, lrc); + ivl_assert(*this, lwid == mwid); - /* Warn about a part select that is out of range. */ - if (midx_tmp >= (long)sig->vector_width() || lidx_tmp < 0) { - cerr << get_fileline() << ": warning: Part select " - << sig->name(); - if (sig->unpacked_dimensions() > 0) { - cerr << "[]"; + if (moff > loff) { + lidx = loff; + midx = moff + mwid - 1; + } else { + lidx = moff; + midx = loff + lwid - 1; } - cerr << "[" << msb << ":" << lsb - << "] is out of range." << endl; - } - /* This is completely out side the signal so just skip it. */ - if (lidx_tmp >= (long)sig->vector_width() || midx_tmp < 0) { - return false; - } + } else { + long lidx_tmp = sig->sb_to_idx(prefix_indices, lsb); + long midx_tmp = sig->sb_to_idx(prefix_indices, msb); - midx = midx_tmp; - lidx = lidx_tmp; + /* Detect reversed indices of a part select. */ + if (lidx_tmp > midx_tmp) { + cerr << get_fileline() << ": error: Part select " + << sig->name() << "[" << msb << ":" + << lsb << "] indices reversed." << endl; + cerr << get_fileline() << ": : Did you mean " + << sig->name() << "[" << lsb << ":" + << msb << "]?" << endl; + long tmp = midx_tmp; + midx_tmp = lidx_tmp; + lidx_tmp = tmp; + des->errors += 1; + } + + /* Warn about a part select that is out of range. */ + if (midx_tmp >= (long)sig->vector_width() || lidx_tmp < 0) { + cerr << get_fileline() << ": warning: Part select " + << sig->name(); + if (sig->unpacked_dimensions() > 0) { + cerr << "[]"; + } + cerr << "[" << msb << ":" << lsb + << "] is out of range." << endl; + } + /* This is completely out side the signal so just skip it. */ + if (lidx_tmp >= (long)sig->vector_width() || midx_tmp < 0) { + return false; + } + + midx = midx_tmp; + lidx = lidx_tmp; + } break; } diff --git a/netmisc.cc b/netmisc.cc index 7f5de1761..8c6e240c5 100644 --- a/netmisc.cc +++ b/netmisc.cc @@ -1440,7 +1440,7 @@ bool evaluate_index_prefix(Design*des, NetScope*scope, return false; } - prefix_indices .push_back(tmp); + prefix_indices.push_back(tmp); delete texpr; } From 06f6a7277096699419d4f9b31b3bbdc8c66e2e97 Mon Sep 17 00:00:00 2001 From: Martin Whitaker Date: Tue, 10 May 2016 21:59:21 +0100 Subject: [PATCH 28/51] Fix for GitHub issue #103 - vvp assertion failure on part select propagation. The implementation of vvp_fun_part_pv::recv_vec4_pv was incorrect, and propagated the incoming widths rather than the stored widths. (cherry picked from commit 0c66116f51ac6c6cf7aa42b37ac13f6116cee085) --- vvp/part.cc | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/vvp/part.cc b/vvp/part.cc index d96f04405..a999f5a97 100644 --- a/vvp/part.cc +++ b/vvp/part.cc @@ -1,5 +1,5 @@ /* - * Copyright (c) 2004-2014 Stephen Williams (steve@icarus.com) + * Copyright (c) 2004-2016 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 @@ -213,8 +213,14 @@ void vvp_fun_part_pv::recv_vec4_pv(vvp_net_ptr_t port, const vvp_vector4_t&bit, vvp_context_t ctx) { assert(port.port() == 0); + assert(bit.size() == wid); + assert(base + wid <= vwid); + assert(vwid == wid_); - port.ptr()->send_vec4_pv(bit, base, wid, vwid, ctx); + vvp_vector4_t tmp(wid_, BIT4_Z); + tmp.set_vec(base, bit); + + port.ptr()->send_vec4_pv(tmp, base_, wid_, vwid_, ctx); } void vvp_fun_part_pv::recv_vec8(vvp_net_ptr_t port, const vvp_vector8_t&bit) From d77019955051d2f51047171cf8251f9972b57800 Mon Sep 17 00:00:00 2001 From: Martin Whitaker Date: Tue, 10 May 2016 23:02:04 +0100 Subject: [PATCH 29/51] Add tgt-vvp sorry message for unsupported mixed NB/CA to vector. --- tgt-vvp/vvp_process.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/tgt-vvp/vvp_process.c b/tgt-vvp/vvp_process.c index 98ca72cff..435184b7f 100644 --- a/tgt-vvp/vvp_process.c +++ b/tgt-vvp/vvp_process.c @@ -225,6 +225,15 @@ static void assign_to_lvector(ivl_lval_t lval, const unsigned long use_word = 0; + if (ivl_signal_type(sig) == IVL_SIT_UWIRE) { + fprintf(stderr, "%s:%u: tgt-vvp sorry: V10 does not support " + "mixed continuous and non-blocking assignments to " + "different parts of the same vector (%s).\n", + ivl_signal_file(sig), ivl_signal_lineno(sig), + ivl_signal_basename(sig)); + vvp_errors += 1; + } + // Detect the case that this is actually a non-blocking assign // to an array word. In that case, run off somewhere else to // deal with it. From 27a46f4afe929b889f198182a1fd7addcae584d7 Mon Sep 17 00:00:00 2001 From: Martin Whitaker Date: Mon, 6 Jun 2016 20:12:04 +0100 Subject: [PATCH 30/51] Fix for GitHub issue #105 - fully support SV macro escape sequences. The existing support for ``, `", and `\`" did not work in nested macro definitions. Note that the new implementation only detects and replaces these sequences inside the macro text (as required by the IEEE standard), whereas the old implementation would detect and replace them anywhere in the source files. (cherry picked from commit 332170d36b404a1e4ea5016a1c32e2a12e786a44) --- ivlpp/lexor.lex | 82 ++++++++++++++++++++++++++----------------------- 1 file changed, 43 insertions(+), 39 deletions(-) diff --git a/ivlpp/lexor.lex b/ivlpp/lexor.lex index b22fac4cb..c81af7397 100644 --- a/ivlpp/lexor.lex +++ b/ivlpp/lexor.lex @@ -1,7 +1,7 @@ %option prefix="yy" %{ /* - * Copyright (c) 1999-2015 Stephen Williams (steve@icarus.com) + * Copyright (c) 1999-2016 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 @@ -148,18 +148,38 @@ static void ifdef_leave(void) free(cur); } -#define YY_INPUT(buf,result,max_size) do { \ - if (istack->file) { \ - size_t rc = fread(buf, 1, max_size, istack->file); \ - result = (rc == 0) ? YY_NULL : rc; \ - } else { \ - if (*istack->str == 0) \ - result = YY_NULL; \ - else { \ - buf[0] = *istack->str++; \ - result = 1; \ - } \ - } \ +#define YY_INPUT(buf,result,max_size) do { \ + if (istack->file) { \ + size_t rc = fread(buf, 1, max_size, istack->file); \ + result = (rc == 0) ? YY_NULL : rc; \ + } else { \ + /* We are expanding a macro. Handle the SV macro escape \ + sequences. There doesn't seem to be any good reason \ + not to allow them in traditional Verilog as well. */ \ + while ((istack->str[0] == '`') && \ + (istack->str[1] == '`')) { \ + istack->str += 2; \ + } \ + if (*istack->str == 0) { \ + result = YY_NULL; \ + } else if ((istack->str[0] == '`') && \ + (istack->str[1] == '"')) { \ + istack->str += 2; \ + buf[0] = '"'; \ + result = 1; \ + } else if ((istack->str[0] == '`') && \ + (istack->str[1] == '\\')&& \ + (istack->str[2] == '`') && \ + (istack->str[3] == '"')) { \ + istack->str += 4; \ + buf[0] = '\\'; \ + buf[1] = '"'; \ + result = 2; \ + } else { \ + buf[0] = *istack->str++; \ + result = 1; \ + } \ + } \ } while (0) static int comment_enter = 0; @@ -242,12 +262,6 @@ keywords (include|define|undef|ifdef|ifndef|else|elseif|endif) if (macro_needs_args(yytext+1)) yy_push_state(MA_START); else do_expand(0); } - /* `" overrides the usual lexical meaning of " and `\`" indicates - that the expansion should include the escape sequence \". - */ -`\" { fputc('"', yyout); } -`\\`\" { fprintf(yyout, "\\\""); } - /* Strings do not contain preprocessor directives, but can expand * macros. If that happens, they get expanded in the context of the * string. @@ -514,29 +528,19 @@ keywords (include|define|undef|ifdef|ifndef|else|elseif|endif) do_expand(0); } - /* Stringified version of macro expansion. If the sequence `` is - * encountered inside a macro definition, we use the SystemVerilog - * handling of ignoring it so that identifiers can be constructed - * from arguments. If istack->file is NULL, we are reading text - * produced from a macro, so use SystemVerilog's handling; - * otherwise, use the special Icarus handling. - */ + /* Stringified version of macro expansion. This is an Icarus extension. + When expanding macro text, the SV usage of `` takes precedence. */ ``[a-zA-Z_][a-zA-Z0-9_$]* { - if (istack->file == NULL) - fprintf(yyout, "%s", yytext+2); - else { - assert(do_expand_stringify_flag == 0); - do_expand_stringify_flag = 1; - fputc('"', yyout); - if (macro_needs_args(yytext+2)) - yy_push_state(MA_START); - else - do_expand(0); - } + assert(istack->file); + assert(do_expand_stringify_flag == 0); + do_expand_stringify_flag = 1; + fputc('"', yyout); + if (macro_needs_args(yytext+2)) + yy_push_state(MA_START); + else + do_expand(0); } -`` { if (istack->file != NULL) ECHO; } - \( { BEGIN(MA_ADD); macro_start_args(); } {W} {} From 86968e3752244266b1c158a745fc2be35a166684 Mon Sep 17 00:00:00 2001 From: Martin Whitaker Date: Thu, 9 Jun 2016 21:27:20 +0100 Subject: [PATCH 31/51] Fix for GitHub issue #106 - prevent VPI writes during read-only synch. (cherry picked from commit 8234f1845d25fba9b041828858b4328af1dc6ea7) --- vvp/schedule.cc | 6 ++++++ vvp/schedule.h | 7 +++++++ vvp/vpi_priv.cc | 30 ++++++++++++++++++++++-------- 3 files changed, 35 insertions(+), 8 deletions(-) diff --git a/vvp/schedule.cc b/vvp/schedule.cc index 79c68b024..e6d06604b 100644 --- a/vvp/schedule.cc +++ b/vvp/schedule.cc @@ -949,6 +949,10 @@ extern void vpiStartOfSim(); extern void vpiPostsim(); extern void vpiNextSimTime(void); +static bool sim_at_rosync = false; +bool schedule_at_rosync(void) +{ return sim_at_rosync; } + /* * The scheduler uses this function to drain the rosync events of the * current time. The ctim object is still in the event queue, because @@ -961,6 +965,7 @@ extern void vpiNextSimTime(void); */ static void run_rosync(struct event_time_s*ctim) { + sim_at_rosync = true; while (ctim->rosync) { struct event_s*cur = ctim->rosync->next; if (cur->next == cur) { @@ -972,6 +977,7 @@ static void run_rosync(struct event_time_s*ctim) cur->run_run(); delete cur; } + sim_at_rosync = false; while (ctim->del_thr) { struct event_s*cur = ctim->del_thr->next; diff --git a/vvp/schedule.h b/vvp/schedule.h index 4dace3d04..e1a465364 100644 --- a/vvp/schedule.h +++ b/vvp/schedule.h @@ -155,6 +155,13 @@ extern void schedule_simulate(void); */ extern vvp_time64_t schedule_simtime(void); +/* + * Indicate that the simulator is running the rosync callbacks. This is + * used to prevent the callbacks from performing any write operations + * in the current simulation time slot. + */ +extern bool schedule_at_rosync(void); + /* * This function is the equivalent of the $finish system task. It * tells the simulator that simulation is done, the current thread diff --git a/vvp/vpi_priv.cc b/vvp/vpi_priv.cc index 858286b9e..01fae5621 100644 --- a/vvp/vpi_priv.cc +++ b/vvp/vpi_priv.cc @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008-2015 Stephen Williams (steve@icarus.com) + * Copyright (c) 2008-2016 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 @@ -1067,13 +1067,13 @@ vpiHandle vpi_put_value(vpiHandle obj, s_vpi_value*vp, vvp_time64_t dly; int scale; - if (vpi_get(vpiAutomatic, obj)) { - fprintf(stderr, "vpi error: cannot put a value with " - "a delay on automatically allocated " - "variable '%s'\n", - vpi_get_str(vpiName, obj)); - return 0; - } + if (vpi_get(vpiAutomatic, obj)) { + fprintf(stderr, "VPI error: cannot put a value with " + "a delay on automatically allocated " + "variable '%s'.\n", + vpi_get_str(vpiName, obj)); + return 0; + } assert(when != 0); @@ -1095,6 +1095,13 @@ vpiHandle vpi_put_value(vpiHandle obj, s_vpi_value*vp, break; } + if ((dly == 0) && schedule_at_rosync()) { + fprintf(stderr, "VPI error: attempted to put a value to " + "variable '%s' during a read-only synch " + "callback.\n", vpi_get_str(vpiName, obj)); + return 0; + } + vpip_put_value_event*put = new vpip_put_value_event; put->handle = obj; put->value = *vp; @@ -1132,6 +1139,13 @@ vpiHandle vpi_put_value(vpiHandle obj, s_vpi_value*vp, return 0; } + if (schedule_at_rosync()) { + fprintf(stderr, "VPI error: attempted to put a value to " + "variable '%s' during a read-only synch " + "callback.\n", vpi_get_str(vpiName, obj)); + return 0; + } + obj->vpi_put_value(vp, flags); return 0; From 99138eafb1140df7e84292c2b91f69ef5a189f03 Mon Sep 17 00:00:00 2001 From: Martin Whitaker Date: Sat, 9 Jul 2016 17:10:22 +0100 Subject: [PATCH 32/51] Fix vector width calculation for multi-dimensional packed arrays. (cherry picked from commit d496b095fff7e4d41a9f16062501c1e900252ed8) --- netlist.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/netlist.cc b/netlist.cc index 838e82ceb..bb162a021 100644 --- a/netlist.cc +++ b/netlist.cc @@ -557,7 +557,7 @@ void NetNet::calculate_slice_widths_from_packed_dims_(void) ivl_assert(*this, ! slice_wids_.empty()); slice_wids_[0] = netrange_width(slice_dims_); vector::const_iterator cur = slice_dims_.begin(); - for (size_t idx = 1 ; idx < slice_wids_.size() ; idx += 1) { + for (size_t idx = 1 ; idx < slice_wids_.size() ; idx += 1, cur++) { slice_wids_[idx] = slice_wids_[idx-1] / cur->width(); } } From 3e13594816116f547170a6c7021e8fabf464c886 Mon Sep 17 00:00:00 2001 From: Martin Whitaker Date: Sat, 9 Jul 2016 23:33:33 +0100 Subject: [PATCH 33/51] Fix for GitHub issue 112 - index calculation for >2D packed arrays. (cherry picked from commit 1448210f282437a0d08110ad8d961cd0de46e434) --- netmisc.cc | 33 ++++++++++++++++++--------------- nettypes.cc | 5 ++--- 2 files changed, 20 insertions(+), 18 deletions(-) diff --git a/netmisc.cc b/netmisc.cc index 8c6e240c5..78ef08c85 100644 --- a/netmisc.cc +++ b/netmisc.cc @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001-2014 Stephen Williams (steve@icarus.com) + * Copyright (c) 2001-2016 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 @@ -457,22 +457,25 @@ NetExpr *normalize_variable_slice_base(const list&indices, NetExpr*base, long loff; reg->sb_to_slice(indices, sb, loff, lwid); - bool idx_incr = pcur->get_msb() < pcur->get_lsb(); + /* Calculate the space needed for the offset. */ + unsigned min_wid = num_bits(-loff); + /* We need enough space for the larger of the offset or the + * base expression. */ + if (min_wid < base->expr_width()) min_wid = base->expr_width(); + /* Pad the base expression to the correct width. */ + base = pad_to_width(base, min_wid, *base); - if(pcur->get_lsb() != 0) { - // Adjust the base for the case when the array range does not start from 0 - if(idx_incr) - base = make_sub_expr(pcur->get_lsb(), base); - else - base = make_sub_expr(base, pcur->get_lsb()); + if (pcur->get_msb() >= pcur->get_lsb()) { + if (pcur->get_lsb() != 0) + base = make_sub_expr(base, pcur->get_lsb()); + base = make_mult_expr(base, lwid); + base = make_add_expr(base, loff); + } else { + if (pcur->get_msb() != 0) + base = make_sub_expr(base, pcur->get_msb()); + base = make_mult_expr(base, lwid); + base = make_sub_expr(loff, base); } - - base = make_mult_expr(base, lwid); - - // TODO I do not see any influence of the lines below to the test suite - if(!idx_incr) - base = make_add_expr(base, loff); - return base; } diff --git a/nettypes.cc b/nettypes.cc index 2f2e3988f..807956b4b 100644 --- a/nettypes.cc +++ b/nettypes.cc @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012-2013 Stephen Williams (steve@icarus.com) + * Copyright (c) 2012-2016 Stephen Williams (steve@icarus.com) * * This source code is free software; you can redistribute it * and/or modify it in source code form under the terms of the GNU @@ -147,13 +147,12 @@ bool prefix_to_slice(const std::vector&dims, do { -- icur; acc_wid *= pcur->width(); + -- pcur; if (pcur->get_msb() >= pcur->get_lsb()) acc_off += (*icur - pcur->get_lsb()) * acc_wid; else acc_off += (pcur->get_lsb() - *icur) * acc_wid; - -- pcur; - } while (icur != prefix.begin()); // Got our final offset. From a5f6329500918e08c20e113e75580fe08e344310 Mon Sep 17 00:00:00 2001 From: Martin Whitaker Date: Sun, 10 Jul 2016 13:30:58 +0100 Subject: [PATCH 34/51] Improved fix for GitHub issue #112. This does a better job of setting the intermediate expression types and widths when calculating the canonical index into a packed array. It still doesn't properly handle out-of-bound indices (br953). (cherry picked from commit 7f612270b3e8e07b8077534ddb6c553b67c16659) --- netmisc.cc | 34 +++++++++++++++++++++++----------- 1 file changed, 23 insertions(+), 11 deletions(-) diff --git a/netmisc.cc b/netmisc.cc index 78ef08c85..b0bf41b98 100644 --- a/netmisc.cc +++ b/netmisc.cc @@ -203,7 +203,7 @@ static NetExpr* make_add_expr(NetExpr*expr, long val) } verinum val_v (val, expr->expr_width()); - val_v.has_sign(true); + val_v.has_sign(expr->has_sign()); NetEConst*val_c = new NetEConst(val_v); val_c->set_line(*expr); @@ -236,7 +236,7 @@ static NetExpr* make_add_expr(const LineInfo*loc, NetExpr*expr1, NetExpr*expr2) static NetExpr* make_sub_expr(long val, NetExpr*expr) { verinum val_v (val, expr->expr_width()); - val_v.has_sign(true); + val_v.has_sign(expr->has_sign()); NetEConst*val_c = new NetEConst(val_v); val_c->set_line(*expr); @@ -254,7 +254,7 @@ static NetExpr* make_sub_expr(long val, NetExpr*expr) static NetExpr* make_sub_expr(NetExpr*expr, long val) { verinum val_v (val, expr->expr_width()); - val_v.has_sign(true); + val_v.has_sign(expr->has_sign()); NetEConst*val_c = new NetEConst(val_v); val_c->set_line(*expr); @@ -268,7 +268,7 @@ static NetExpr* make_sub_expr(NetExpr*expr, long val) /* - * Multiple an existing expression by a signed positive number. + * Multiply an existing expression by a signed positive number. * This does a lossless multiply, so the arguments will need to be * sized to match the output size. */ @@ -277,7 +277,7 @@ static NetExpr* make_mult_expr(NetExpr*expr, unsigned long val) const unsigned val_wid = ceil(log2((double)val)) ; unsigned use_wid = expr->expr_width() + val_wid; verinum val_v (val, use_wid); - val_v.has_sign(true); + val_v.has_sign(expr->has_sign()); NetEConst*val_c = new NetEConst(val_v); val_c->set_line(*expr); @@ -457,23 +457,35 @@ NetExpr *normalize_variable_slice_base(const list&indices, NetExpr*base, long loff; reg->sb_to_slice(indices, sb, loff, lwid); - /* Calculate the space needed for the offset. */ - unsigned min_wid = num_bits(-loff); - /* We need enough space for the larger of the offset or the - * base expression. */ - if (min_wid < base->expr_width()) min_wid = base->expr_width(); - /* Pad the base expression to the correct width. */ + unsigned min_wid = base->expr_width(); + if ((sb < 0) && !base->has_sign()) min_wid += 1; + if (min_wid < num_bits(pcur->get_lsb())) min_wid = pcur->get_lsb(); + if (min_wid < num_bits(pcur->get_msb())) min_wid = pcur->get_msb(); base = pad_to_width(base, min_wid, *base); + if ((sb < 0) && !base->has_sign()) { + NetESelect *tmp = new NetESelect(base, 0 , min_wid); + tmp->set_line(*base); + tmp->cast_signed(true); + base = tmp; + } if (pcur->get_msb() >= pcur->get_lsb()) { if (pcur->get_lsb() != 0) base = make_sub_expr(base, pcur->get_lsb()); base = make_mult_expr(base, lwid); + min_wid = base->expr_width(); + if (min_wid < num_bits(loff)) min_wid = num_bits(loff); + if (loff != 0) min_wid += 1; + base = pad_to_width(base, min_wid, *base); base = make_add_expr(base, loff); } else { if (pcur->get_msb() != 0) base = make_sub_expr(base, pcur->get_msb()); base = make_mult_expr(base, lwid); + min_wid = base->expr_width(); + if (min_wid < num_bits(loff)) min_wid = num_bits(loff); + if (loff != 0) min_wid += 1; + base = pad_to_width(base, min_wid, *base); base = make_sub_expr(loff, base); } return base; From face462cc2b555cc6b1890592d932ce183972728 Mon Sep 17 00:00:00 2001 From: Martin Whitaker Date: Sun, 10 Jul 2016 20:00:39 +0100 Subject: [PATCH 35/51] Partial fix for br1006 - allow part selects in path declarations. This just enables the compiler to parse path declarations that contain part selects. As for bit selects, the part select is discarded, and if elaboration of specify blocks is enabled, the path declaration will be applied to the entire vector. If elaboration is enabled, a warning message will now be output when a bit or part select is discarded. (cherry picked from commit ad877048096a00d5c7eb191f1149fde11428e930) --- parse.y | 36 ++++++++++++++++++++++++++++++++++-- 1 file changed, 34 insertions(+), 2 deletions(-) diff --git a/parse.y b/parse.y index b030fdbed..897479f09 100644 --- a/parse.y +++ b/parse.y @@ -5833,7 +5833,23 @@ specify_path_identifiers delete[]$1; } | IDENTIFIER '[' expr_primary ']' - { list*tmp = new list; + { if (gn_specify_blocks_flag) { + yywarn(@4, "Bit selects are not currently supported " + "in path declarations. The declaration " + "will be applied to the whole vector."); + } + list*tmp = new list; + tmp->push_back(lex_strings.make($1)); + $$ = tmp; + delete[]$1; + } + | IDENTIFIER '[' expr_primary polarity_operator expr_primary ']' + { if (gn_specify_blocks_flag) { + yywarn(@4, "Part selects are not currently supported " + "in path declarations. The declaration " + "will be applied to the whole vector."); + } + list*tmp = new list; tmp->push_back(lex_strings.make($1)); $$ = tmp; delete[]$1; @@ -5845,7 +5861,23 @@ specify_path_identifiers delete[]$3; } | specify_path_identifiers ',' IDENTIFIER '[' expr_primary ']' - { list*tmp = $1; + { if (gn_specify_blocks_flag) { + yywarn(@4, "Bit selects are not currently supported " + "in path declarations. The declaration " + "will be applied to the whole vector."); + } + list*tmp = $1; + tmp->push_back(lex_strings.make($3)); + $$ = tmp; + delete[]$3; + } + | specify_path_identifiers ',' IDENTIFIER '[' expr_primary polarity_operator expr_primary ']' + { if (gn_specify_blocks_flag) { + yywarn(@4, "Part selects are not currently supported " + "in path declarations. The declaration " + "will be applied to the whole vector."); + } + list*tmp = $1; tmp->push_back(lex_strings.make($3)); $$ = tmp; delete[]$3; From 6155986d1c7905ce3f7cdae7169aed0932b97933 Mon Sep 17 00:00:00 2001 From: Martin Whitaker Date: Mon, 11 Jul 2016 20:04:24 +0100 Subject: [PATCH 36/51] Fix for br1005 - segfault when SV queue is declared inside a class. For now, output a "sorry" message to indicate this is not yet supported. (cherry picked from commit ad1101cc806a94d1a871c9fdbd15f667cff43dea) --- elab_type.cc | 14 +++++++++++++- pform_pclass.cc | 1 + 2 files changed, 14 insertions(+), 1 deletion(-) diff --git a/elab_type.cc b/elab_type.cc index eb2803cbf..4c1814909 100644 --- a/elab_type.cc +++ b/elab_type.cc @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012-2014 Stephen Williams (steve@icarus.com) + * Copyright (c) 2012-2016 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 @@ -17,11 +17,13 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ +# include "PExpr.h" # include "pform_types.h" # include "netlist.h" # include "netclass.h" # include "netdarray.h" # include "netenum.h" +# include "netqueue.h" # include "netparray.h" # include "netscalar.h" # include "netstruct.h" @@ -245,6 +247,16 @@ ivl_type_s* uarray_type_t::elaborate_type_raw(Design*des, NetScope*scope) const return res; } + // Special case: if the dimension is null:nil. this is a queue. + if (cur->second==0 && dynamic_cast(cur->first)) { + cerr << get_fileline() << ": sorry: " + << "SV queues inside classes are not yet supported." << endl; + des->errors += 1; + + ivl_type_s*res = new netqueue_t(btype); + return res; + } + vector dimensions; bool bad_range = evaluate_ranges(des, scope, dimensions, *dims); diff --git a/pform_pclass.cc b/pform_pclass.cc index bd2a7a21a..a3b7df4f0 100644 --- a/pform_pclass.cc +++ b/pform_pclass.cc @@ -79,6 +79,7 @@ void pform_class_property(const struct vlltype&loc, if (! curp->index.empty()) { list*pd = new list (curp->index); use_type = new uarray_type_t(use_type, pd); + FILE_NAME(use_type, loc); } pform_cur_class->type->properties[curp->name] From 73d688c3134403511d9616fd875b78410ed5d0ee Mon Sep 17 00:00:00 2001 From: Martin Whitaker Date: Tue, 12 Jul 2016 20:59:50 +0100 Subject: [PATCH 37/51] Fix for br1003 - prevent segfault when delays are used outside a module. (cherry picked from commit b8f9ed27c5f91496693260563adae142eaa3abc5) --- pform.cc | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/pform.cc b/pform.cc index 059a9d32e..5a8299468 100644 --- a/pform.cc +++ b/pform.cc @@ -1066,7 +1066,10 @@ void pform_set_timeunit(const char*txt, bool in_module, bool only_check) int pform_get_timeunit() { - return pform_cur_module.front()->time_unit; + if (pform_cur_module.front()) + return pform_cur_module.front()->time_unit; + else + return pform_time_unit; } void pform_set_timeprecision(const char*txt, bool in_module, bool only_check) From 07623bef2e5ed158b1a49d5769acd52a498ccdcf Mon Sep 17 00:00:00 2001 From: Martin Whitaker Date: Thu, 21 Jul 2016 19:06:21 +0100 Subject: [PATCH 38/51] Fix assignment of outputs from class methods. As for inputs, skip over the implicit 'this' parameter. (cherry picked from commit e316cc708b265f401477b7b7eb667725f47aafca) --- elaborate.cc | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/elaborate.cc b/elaborate.cc index e8ac6a7fd..8afdeb8b7 100644 --- a/elaborate.cc +++ b/elaborate.cc @@ -3817,7 +3817,9 @@ NetProc* PCallTask::elaborate_build_call_(Design*des, NetScope*scope, expression that can be a target to a procedural assignment, including a memory word. */ - for (unsigned idx = 0 ; idx < parm_count ; idx += 1) { + for (unsigned idx = use_this?1:0 ; idx < parm_count ; idx += 1) { + + size_t parms_idx = use_this? idx-1 : idx; NetNet*port = def->port(idx); @@ -3833,12 +3835,12 @@ NetProc* PCallTask::elaborate_build_call_(Design*des, NetScope*scope, message. Note that the elaborate_lval method already printed a detailed message for the latter case. */ NetAssign_*lv = 0; - if (idx < parms_.size() && parms_[idx]) { - lv = parms_[idx]->elaborate_lval(des, scope, false, false); + if (parms_idx < parms_.size() && parms_[parms_idx]) { + lv = parms_[parms_idx]->elaborate_lval(des, scope, false, false); if (lv == 0) { - cerr << parms_[idx]->get_fileline() << ": error: " + cerr << parms_[parms_idx]->get_fileline() << ": error: " << "I give up on task port " << (idx+1) - << " expression: " << *parms_[idx] << endl; + << " expression: " << *parms_[parms_idx] << endl; } } else if (port->port_type() == NetNet::POUTPUT) { // Output ports were skipped earlier, so From 9b55a3d67f35166d04ef0544248ef9c52b44c92d Mon Sep 17 00:00:00 2001 From: Martin Whitaker Date: Fri, 22 Jul 2016 22:48:20 +0100 Subject: [PATCH 39/51] Support timescales in design units that aren't inside a module. SystemVerilog allows tasks, functions, and classes to be defined at the root level or inside packages, so we can't rely on an enclosing module being present to provide the timescale. (cherry picked from commit 7bed181f680f4598db2a084980d7b889c588dcbf) --- Module.cc | 5 +---- Module.h | 6 +----- PScope.cc | 37 ++++++++++++++--------------------- PScope.h | 14 ++++++++----- elab_scope.cc | 26 ++++++++++++++++-------- elaborate.cc | 11 ++++++----- pform.cc | 50 +++++++++++++++++++++++++++++++---------------- vpi/sys_display.c | 7 +------ vpi/sys_priv.c | 11 +++++++---- vvp/vpi_signal.cc | 5 ++++- 10 files changed, 95 insertions(+), 77 deletions(-) diff --git a/Module.cc b/Module.cc index b69a3a950..80e1200e2 100644 --- a/Module.cc +++ b/Module.cc @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998-2010 Stephen Williams (steve@icarus.com) + * Copyright (c) 1998-2016 Stephen Williams (steve@icarus.com) * * This source code is free software; you can redistribute it * and/or modify it in source code form under the terms of the GNU @@ -35,9 +35,6 @@ Module::Module(LexicalScope*parent, perm_string n) program_block = false; uc_drive = UCD_NONE; timescale_warn_done = false; - time_unit = 0; - time_precision = 0; - time_from_timescale = false; } Module::~Module() diff --git a/Module.h b/Module.h index f142a761d..66c60af4f 100644 --- a/Module.h +++ b/Module.h @@ -1,7 +1,7 @@ #ifndef IVL_Module_H #define IVL_Module_H /* - * Copyright (c) 1998-2015 Stephen Williams (steve@icarus.com) + * Copyright (c) 1998-2016 Stephen Williams (steve@icarus.com) * * This source code is free software; you can redistribute it * and/or modify it in source code form under the terms of the GNU @@ -121,10 +121,6 @@ class Module : public PScopeExtra, public LineInfo { map attributes; - /* These are the timescale for this module. The default is - set by the `timescale directive. */ - int time_unit, time_precision; - bool time_from_timescale; bool timescale_warn_done; /* The module has a list of generate schemes that appear in diff --git a/PScope.cc b/PScope.cc index 9add20a1b..0b6a132d3 100644 --- a/PScope.cc +++ b/PScope.cc @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008,2010 Stephen Williams (steve@icarus.com) + * Copyright (c) 2008,2016 Stephen Williams (steve@icarus.com) * * This source code is free software; you can redistribute it * and/or modify it in source code form under the terms of the GNU @@ -24,23 +24,6 @@ bool LexicalScope::var_init_needs_explicit_lifetime() const return false; } -PScope::PScope(perm_string n, LexicalScope*parent) -: LexicalScope(parent), name_(n) -{ -} - -PScope::PScope(perm_string n) -: LexicalScope(0), name_(n) -{ -} - -PScope::~PScope() -{ - for(map::iterator it = typedefs.begin(); - it != typedefs.end(); ++it) - delete it->second; -} - PWire* LexicalScope::wires_find(perm_string name) { map::const_iterator cur = wires.find(name); @@ -50,13 +33,23 @@ PWire* LexicalScope::wires_find(perm_string name) return (*cur).second; } -PScopeExtra::PScopeExtra(perm_string n, LexicalScope*parent) -: PScope(n, parent) +PScope::PScope(perm_string n, LexicalScope*parent) +: LexicalScope(parent), name_(n) { + time_unit = 0; + time_precision = 0; + time_from_timescale = false; } -PScopeExtra::PScopeExtra(perm_string n) -: PScope(n) +PScope::~PScope() +{ + for(map::iterator it = typedefs.begin(); + it != typedefs.end(); ++it) + delete it->second; +} + +PScopeExtra::PScopeExtra(perm_string n, LexicalScope*parent) +: PScope(n, parent) { } diff --git a/PScope.h b/PScope.h index ce6f94afb..7e4fd6fa3 100644 --- a/PScope.h +++ b/PScope.h @@ -159,12 +159,17 @@ class PScope : public LexicalScope { // modules do not nest in Verilog, the parent must be nil for // modules. Scopes for tasks and functions point to their // containing module. - PScope(perm_string name, LexicalScope*parent); - PScope(perm_string name); + explicit PScope(perm_string name, LexicalScope*parent =0); virtual ~PScope(); perm_string pscope_name() const { return name_; } + /* These are the timescale for this scope. The default is + set by the `timescale directive or, in SystemVerilog, + by timeunit and timeprecision statements. */ + int time_unit, time_precision; + bool time_from_timescale; + protected: bool elaborate_sig_wires_(Design*des, NetScope*scope) const; @@ -182,14 +187,13 @@ class PScope : public LexicalScope { class PScopeExtra : public PScope { public: - PScopeExtra(perm_string, LexicalScope*parent); - PScopeExtra(perm_string); + explicit PScopeExtra(perm_string, LexicalScope*parent =0); ~PScopeExtra(); /* Task definitions within this module */ std::map tasks; std::map funcs; - /* class definitions within this module. */ + /* Class definitions within this module. */ std::map classes; /* This is the lexical order of the classes, and is used by elaboration to choose an elaboration order. */ diff --git a/elab_scope.cc b/elab_scope.cc index 6f37e63d7..73834249c 100644 --- a/elab_scope.cc +++ b/elab_scope.cc @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000-2015 Stephen Williams (steve@icarus.com) + * Copyright (c) 2000-2016 Stephen Williams (steve@icarus.com) * Copyright CERN 2013 / Stephen Williams (steve@icarus.com) * * This source code is free software; you can redistribute it @@ -54,6 +54,15 @@ # include # include "ivl_assert.h" + +void set_scope_timescale(Design*des, NetScope*scope, PScope*pscope) +{ + scope->time_unit(pscope->time_unit); + scope->time_precision(pscope->time_precision); + scope->time_from_timescale(pscope->time_from_timescale); + des->set_precision(pscope->time_precision); +} + typedef map::const_iterator mparm_it_t; static void collect_parm_item_(Design*des, NetScope*scope, perm_string name, @@ -523,6 +532,7 @@ static void elaborate_scope_class(Design*des, NetScope*scope, PClass*pclass) class_scope->set_class_def(use_class); use_class->set_class_scope(class_scope); use_class->set_definition_scope(scope); + set_scope_timescale(des, class_scope, pclass); // Collect the properties, elaborate them, and add them to the // elaborated class definition. @@ -654,8 +664,10 @@ static void elaborate_scope_task(Design*des, NetScope*scope, PTask*task) task_scope->is_auto(task->is_auto()); task_scope->set_line(task); - if (scope==0) + if (scope==0) { + set_scope_timescale(des, task_scope, task); des->add_root_task(task_scope, task); + } if (debug_scopes) { cerr << task->get_fileline() << ": elaborate_scope_task: " @@ -719,8 +731,10 @@ static void elaborate_scope_func(Design*des, NetScope*scope, PFunction*task) task_scope->is_auto(task->is_auto()); task_scope->set_line(task); - if (scope==0) + if (scope==0) { + set_scope_timescale(des, task_scope, task); des->add_root_task(task_scope, task); + } if (debug_scopes) { cerr << task->get_fileline() << ": elaborate_scope_func: " @@ -1750,11 +1764,7 @@ void PGModule::elaborate_scope_mod_instances_(Design*des, Module*mod, NetScope*s instances[idx] = my_scope; - // Set time units and precision. - my_scope->time_unit(mod->time_unit); - my_scope->time_precision(mod->time_precision); - my_scope->time_from_timescale(mod->time_from_timescale); - des->set_precision(mod->time_precision); + set_scope_timescale(des, my_scope, mod); // Look for module parameter replacements. The "replace" map // maps parameter name to replacement expression that is diff --git a/elaborate.cc b/elaborate.cc index 8afdeb8b7..0faa7ed2a 100644 --- a/elaborate.cc +++ b/elaborate.cc @@ -36,6 +36,7 @@ # include "PEvent.h" # include "PGenerate.h" # include "PPackage.h" +# include "PScope.h" # include "PSpec.h" # include "netlist.h" # include "netenum.h" @@ -50,6 +51,9 @@ # include "ivl_assert.h" +// Implemented in elab_scope.cc +extern void set_scope_timescale(Design*des, NetScope*scope, PScope*pscope); + void PGate::elaborate(Design*, NetScope*) const { cerr << "internal error: what kind of gate? " << @@ -6238,6 +6242,7 @@ Design* elaborate(listroots) ivl_assert(*pac->second, pac->first == pac->second->pscope_name()); NetScope*scope = des->make_package_scope(pac->first); scope->set_line(pac->second); + set_scope_timescale(des, scope, pac->second); elaborator_work_item_t*es = new elaborate_package_t(des, scope, pac->second); des->elaboration_work_list.push_back(es); @@ -6274,11 +6279,7 @@ Design* elaborate(listroots) // Collect some basic properties of this scope from the // Module definition. scope->set_line(rmod); - scope->time_unit(rmod->time_unit); - scope->time_precision(rmod->time_precision); - scope->time_from_timescale(rmod->time_from_timescale); - des->set_precision(rmod->time_precision); - + set_scope_timescale(des, scope, rmod); // Save this scope, along with its definition, in the // "root_elems" list for later passes. diff --git a/pform.cc b/pform.cc index 5a8299468..be8972afb 100644 --- a/pform.cc +++ b/pform.cc @@ -345,6 +345,28 @@ static PScopeExtra* find_nearest_scopex(LexicalScope*scope) return scopex; } +/* + * Set the local time unit/precision to the global value. + */ +static void pform_set_scope_timescale(PScope*scope, const struct vlltype&loc) +{ + scope->time_unit = pform_time_unit; + scope->time_precision = pform_time_prec; + /* If we have a timescale file then the time information is from + * a timescale directive. */ + scope->time_from_timescale = pform_timescale_file != 0; + + if (warn_timescale && (lexical_scope == 0) && pform_timescale_file + && (strcmp(pform_timescale_file, loc.text) != 0)) { + + cerr << loc.get_fileline() << ": warning: " + << "timescale for " << scope->pscope_name() + << " inherited from another file." << endl; + cerr << pform_timescale_file << ":" << pform_timescale_line + << ": ...: The inherited timescale is here." << endl; + } +} + PClass* pform_push_class_scope(const struct vlltype&loc, perm_string name, LexicalScope::lifetime_t lifetime) { @@ -352,6 +374,8 @@ PClass* pform_push_class_scope(const struct vlltype&loc, perm_string name, class_scope->default_lifetime = find_lifetime(lifetime); FILE_NAME(class_scope, loc); + pform_set_scope_timescale(class_scope, loc); + PScopeExtra*scopex = find_nearest_scopex(lexical_scope); assert(!pform_cur_generate); @@ -384,6 +408,8 @@ PPackage* pform_push_package_scope(const struct vlltype&loc, perm_string name, pkg_scope->default_lifetime = find_lifetime(lifetime); FILE_NAME(pkg_scope, loc); + pform_set_scope_timescale(pkg_scope, loc); + lexical_scope = pkg_scope; return pkg_scope; } @@ -400,6 +426,8 @@ PTask* pform_push_task_scope(const struct vlltype&loc, char*name, task->default_lifetime = default_lifetime; FILE_NAME(task, loc); + pform_set_scope_timescale(task, loc); + PScopeExtra*scopex = find_nearest_scopex(lexical_scope); if ((scopex == 0) && !gn_system_verilog()) { cerr << task->get_fileline() << ": error: task declarations " @@ -455,6 +483,8 @@ PFunction* pform_push_function_scope(const struct vlltype&loc, const char*name, func->default_lifetime = default_lifetime; FILE_NAME(func, loc); + pform_set_scope_timescale(func, loc); + PScopeExtra*scopex = find_nearest_scopex(lexical_scope); if ((scopex == 0) && (generation_flag < GN_VER2005_SV)) { cerr << func->get_fileline() << ": error: function declarations " @@ -1195,17 +1225,12 @@ void pform_startmodule(const struct vlltype&loc, const char*name, cur_module->is_interface = is_interface; cur_module->default_lifetime = find_lifetime(lifetime); - /* Set the local time unit/precision to the global value. */ - cur_module->time_unit = pform_time_unit; - cur_module->time_precision = pform_time_prec; + FILE_NAME(cur_module, loc); + + pform_set_scope_timescale(cur_module, loc); tu_local_flag = tu_global_flag; tp_local_flag = tp_global_flag; - /* If we have a timescale file then the time information is from - * a timescale directive. */ - cur_module->time_from_timescale = pform_timescale_file != 0; - - FILE_NAME(cur_module, loc); cur_module->library_flag = pform_library_flag; pform_cur_module.push_front(cur_module); @@ -1216,15 +1241,6 @@ void pform_startmodule(const struct vlltype&loc, const char*name, zero. That's just the way it is, thanks to the standard. */ scope_generate_counter = 1; - if (warn_timescale && pform_timescale_file - && (strcmp(pform_timescale_file,loc.text) != 0)) { - - cerr << cur_module->get_fileline() << ": warning: " - << "timescale for " << name - << " inherited from another file." << endl; - cerr << pform_timescale_file << ":" << pform_timescale_line - << ": ...: The inherited timescale is here." << endl; - } pform_bind_attributes(cur_module->attributes, attr); } diff --git a/vpi/sys_display.c b/vpi/sys_display.c index a7a34dfa7..b5e0737c8 100644 --- a/vpi/sys_display.c +++ b/vpi/sys_display.c @@ -1971,12 +1971,7 @@ static PLI_INT32 sys_printtimescale_calltf(ICARUS_VPI_CONST PLI_BYTE8*name) item = vpi_scan(argv); vpi_free_object(argv); } - - if (vpi_get(vpiType, item) != vpiModule) { - scope = vpi_handle(vpiModule, item); - } else { - scope = item; - } + scope = sys_func_module(item); vpi_printf("Time scale of (%s) is ", vpi_get_str(vpiFullName, item)); vpi_printf("%s / ", pts_convert(vpi_get(vpiTimeUnit, scope))); diff --git a/vpi/sys_priv.c b/vpi/sys_priv.c index 08529cced..1d5e977bb 100644 --- a/vpi/sys_priv.c +++ b/vpi/sys_priv.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003-2011 Stephen Williams (steve@icarus.com) + * Copyright (c) 2003-2016 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 @@ -229,15 +229,18 @@ unsigned is_string_obj(vpiHandle obj) /* - * Find the enclosing module. + * Find the enclosing module. If there is no enclosing module (which can be + * the case in SystemVerilog), return the highest enclosing scope. */ vpiHandle sys_func_module(vpiHandle obj) { assert(obj); while (vpi_get(vpiType, obj) != vpiModule) { - obj = vpi_handle(vpiScope, obj); - assert(obj); + vpiHandle scope = vpi_handle(vpiScope, obj); + if (scope == 0) + break; + obj = scope; } return obj; diff --git a/vvp/vpi_signal.cc b/vvp/vpi_signal.cc index 608e41cee..243254853 100644 --- a/vvp/vpi_signal.cc +++ b/vvp/vpi_signal.cc @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001-2015 Stephen Williams (steve@icarus.com) + * Copyright (c) 2001-2016 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 @@ -1409,6 +1409,9 @@ static vpiHandle PV_get_handle(int code, vpiHandle ref) case vpiParent: return rfp->parent; + case vpiScope: + return vpi_handle(vpiScope, rfp->parent); + case vpiModule: return vpi_handle(vpiModule, rfp->parent); } From 0ffbb2b1dec85b7681033c4c488ddd58ce87585f Mon Sep 17 00:00:00 2001 From: Martin Whitaker Date: Fri, 22 Jul 2016 23:09:36 +0100 Subject: [PATCH 40/51] Fix for GitHub issue #115 - synthesis aborts on case with max guard of 0. The calculation of the required multiplexer width was incorrect for the corner case of a single guard value of zero. (cherry picked from commit 27213f2af8c914995db2f6375710ebc258534f3a) --- synth2.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/synth2.cc b/synth2.cc index 3d3805891..da173a1c6 100644 --- a/synth2.cc +++ b/synth2.cc @@ -565,7 +565,7 @@ bool NetCase::synth_async(Design*des, NetScope*scope, // The minimum selector width is the number of inputs that // are selected, rounded up to the nearest power of 2. - unsigned sel_need = ceil(log2(max_guard_value + 1)); + unsigned sel_need = max(ceil(log2(max_guard_value + 1)), 1.0); // If the sel_width can select more than just the explicit // guard values, and there is a default statement, then adjust From d6d50e9b68aafe56db54731a202d6ce34f106ae2 Mon Sep 17 00:00:00 2001 From: Martin Whitaker Date: Sat, 23 Jul 2016 00:10:01 +0100 Subject: [PATCH 41/51] Update vlog95 target to handle timescales for root scope tasks/functions. (cherry picked from commit b1b91f49c85dfe13e021af5cf56422a87d148b40) --- tgt-vlog95/misc.c | 32 ++++++++++++++++++++++++++++++-- tgt-vlog95/scope.c | 29 +---------------------------- tgt-vlog95/vlog95.c | 27 +++++++++++++++------------ tgt-vlog95/vlog95_priv.h | 7 ++++++- 4 files changed, 52 insertions(+), 43 deletions(-) diff --git a/tgt-vlog95/misc.c b/tgt-vlog95/misc.c index 8787c0302..5076bd4c6 100644 --- a/tgt-vlog95/misc.c +++ b/tgt-vlog95/misc.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2014 Cary R. (cygcary@yahoo.com) + * Copyright (C) 2011-2016 Cary R. (cygcary@yahoo.com) * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -872,7 +872,8 @@ void emit_scope_path(ivl_scope_t scope, ivl_scope_t call_scope) /* Check to see if this is a root scope task or function. */ if (ivl_scope_parent(call_scope) == 0) { - fprintf(vlog_out, "ivl_root_scope."); + fprintf(vlog_out, "ivl_root_scope_%s.", + ivl_scope_basename(call_scope)); mod_scope = 0; call_mod_scope = 0; } else { @@ -938,3 +939,30 @@ void get_sig_msb_lsb(ivl_signal_t sig, int *msb, int *lsb) break; } } + +const char*get_time_const(int time_value) +{ + switch (time_value) { + case 2: return "100s"; + case 1: return "10s"; + case 0: return "1s"; + case -1: return "100ms"; + case -2: return "10ms"; + case -3: return "1ms"; + case -4: return "100us"; + case -5: return "10us"; + case -6: return "1us"; + case -7: return "100ns"; + case -8: return "10ns"; + case -9: return "1ns"; + case -10: return "100ps"; + case -11: return "10ps"; + case -12: return "1ps"; + case -13: return "100fs"; + case -14: return "10fs"; + case -15: return "1fs"; + default: + fprintf(stderr, "Invalid time constant value %d.\n", time_value); + return "N/A"; + } +} diff --git a/tgt-vlog95/scope.c b/tgt-vlog95/scope.c index 1f939d8d2..116d696f7 100644 --- a/tgt-vlog95/scope.c +++ b/tgt-vlog95/scope.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2010-2015 Cary R. (cygcary@yahoo.com) + * Copyright (C) 2010-2016 Cary R. (cygcary@yahoo.com) * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -24,33 +24,6 @@ const char *func_rtn_name = 0; -static const char*get_time_const(int time_value) -{ - switch (time_value) { - case 2: return "100s"; - case 1: return "10s"; - case 0: return "1s"; - case -1: return "100ms"; - case -2: return "10ms"; - case -3: return "1ms"; - case -4: return "100us"; - case -5: return "10us"; - case -6: return "1us"; - case -7: return "100ns"; - case -8: return "10ns"; - case -9: return "1ns"; - case -10: return "100ps"; - case -11: return "10ps"; - case -12: return "1ps"; - case -13: return "100fs"; - case -14: return "10fs"; - case -15: return "1fs"; - default: - fprintf(stderr, "Invalid time constant value %d.\n", time_value); - return "N/A"; - } -} - static void emit_func_return(ivl_signal_t sig) { if (ivl_signal_dimensions(sig) > 0) { diff --git a/tgt-vlog95/vlog95.c b/tgt-vlog95/vlog95.c index 4841cb522..1890d76b6 100644 --- a/tgt-vlog95/vlog95.c +++ b/tgt-vlog95/vlog95.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2010-2013 Cary R. (cygcary@yahoo.com) + * Copyright (C) 2010-2016 Cary R. (cygcary@yahoo.com) * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -60,7 +60,6 @@ int target_design(ivl_design_t des) { ivl_scope_t *roots; unsigned nroots, idx; - unsigned has_root_scope = 0; const char*path = ivl_design_flag(des, "-o"); /* Set the indent spacing with the -pspacing flag passed to iverilog * (e.g. -pspacing=4). The default is 2 spaces. */ @@ -190,23 +189,27 @@ int target_design(ivl_design_t des) switch(ivl_scope_type(roots[idx])) { case IVL_SCT_FUNCTION: case IVL_SCT_TASK: - if (! has_root_scope) { - fprintf(vlog_out, "module ivl_root_scope;\n"); - indent += indent_incr; - has_root_scope = 1; - } + /* Create a separate module for each task/function. + This allows us to handle different timescales. */ + fprintf(vlog_out, "\n`timescale %s/%s\n", + get_time_const(ivl_scope_time_units(roots[idx])), + get_time_const(ivl_scope_time_precision(roots[idx]))); + fprintf(vlog_out, "module ivl_root_scope_%s;\n", + ivl_scope_basename(roots[idx])); + indent += indent_incr; + /* Say this task/function has a parent so the * definition is emitted correctly. */ emit_scope(roots[idx], roots[idx]); + + indent -= indent_incr; + assert(indent == 0); + fprintf(vlog_out, "endmodule /* ivl_root_scope_%p */\n", + roots[idx]); break; default: break; } - } - if (has_root_scope) { - indent -= indent_incr; - assert(indent == 0); - fprintf(vlog_out, "endmodule /* ivl_root_scope */\n"); } /* Emit the rest of the scope objects. */ for (idx = 0; idx < nroots; idx += 1) emit_scope(roots[idx], 0); diff --git a/tgt-vlog95/vlog95_priv.h b/tgt-vlog95/vlog95_priv.h index fb632d95e..913fd0424 100644 --- a/tgt-vlog95/vlog95_priv.h +++ b/tgt-vlog95/vlog95_priv.h @@ -1,7 +1,7 @@ #ifndef IVL_vlog95_priv_H #define IVL_vlog95_priv_H /* - * Copyright (C) 2010-2014 Cary R. (cygcary@yahoo.com) + * Copyright (C) 2010-2016 Cary R. (cygcary@yahoo.com) * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -145,6 +145,11 @@ extern char * get_package_name(ivl_scope_t scope); */ extern void get_sig_msb_lsb(ivl_signal_t sig, int *msb, int *lsb); +/* + * Convert a timescale value to a string. + */ +extern const char*get_time_const(int time_value); + /* * Cleanup functions. */ From 4066031addc98a0bfab4df030ac76da068f95db9 Mon Sep 17 00:00:00 2001 From: Martin Whitaker Date: Tue, 26 Jul 2016 21:40:27 +0100 Subject: [PATCH 42/51] Fix for GitHub issue #104 - assigning hierarchical signal from top level task. When emitting a design, all scopes must be emitted before emitting any top level task/function/method definitions, otherwise hierarchical references can't always be resolved. (cherry picked from commit 2bc42fc6e2c9ab5e6e59e86dcabdf22401bc0690) --- emit.cc | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/emit.cc b/emit.cc index bd46fc5c4..7f86b6f9b 100644 --- a/emit.cc +++ b/emit.cc @@ -507,7 +507,6 @@ int Design::emit(struct target_t*tgt) const for (map::const_iterator scope = root_tasks_.begin() ; scope != root_tasks_.end() ; ++ scope) { scope->first->emit_scope(tgt); - scope->first->emit_defs(tgt); } // enumerate package scopes @@ -521,7 +520,6 @@ int Design::emit(struct target_t*tgt) const const NetScope*use_scope = cur->second->class_scope(); cur->second->emit_scope(tgt); tgt->class_type(use_scope, cur->second); - cur->second->emit_defs(tgt); } // enumerate root scopes @@ -548,6 +546,12 @@ int Design::emit(struct target_t*tgt) const // emit task and function definitions bool tasks_rc = true; + for (map::const_iterator scope = root_tasks_.begin() + ; scope != root_tasks_.end() ; ++ scope) + tasks_rc &= scope->first->emit_defs(tgt); + for (map::const_iterator cur = classes_.begin() + ; cur != classes_.end() ; ++cur) + tasks_rc &= cur->second->emit_defs(tgt); for (map::const_iterator scope = packages_.begin() ; scope != packages_.end() ; ++ scope ) tasks_rc &= scope->second->emit_defs(tgt); From cda95c15543aa73ee379f6d5bb383905fd619340 Mon Sep 17 00:00:00 2001 From: Martin Whitaker Date: Tue, 26 Jul 2016 21:59:54 +0100 Subject: [PATCH 43/51] Fix vlog95 target to handle hierarchical references in root-level tasks. (cherry picked from commit 8461e1d9c415f8152c98c58728656c82f88cd84a) --- tgt-vlog95/misc.c | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/tgt-vlog95/misc.c b/tgt-vlog95/misc.c index 5076bd4c6..7c8d32987 100644 --- a/tgt-vlog95/misc.c +++ b/tgt-vlog95/misc.c @@ -747,7 +747,9 @@ void emit_name_of_nexus(ivl_scope_t scope, ivl_nexus_t nex, unsigned allow_UD) * This function traverses the scope tree looking for the enclosing module * scope. When it is found the module scope is returned. As far as this * translation is concerned a package is a special form of a module - * definition and a class is also a top level scope. + * definition and a class is also a top level scope. In SystemVerilog, + * tasks and functions can also be top level scopes - we create a wrapper + * module for these later. */ ivl_scope_t get_module_scope(ivl_scope_t scope) { @@ -756,6 +758,12 @@ ivl_scope_t get_module_scope(ivl_scope_t scope) (ivl_scope_type(scope) != IVL_SCT_PACKAGE) && (ivl_scope_type(scope) != IVL_SCT_CLASS)) { ivl_scope_t pscope = ivl_scope_parent(scope); + if (pscope == 0) { + if (ivl_scope_type(scope) == IVL_SCT_TASK) + break; + if (ivl_scope_type(scope) == IVL_SCT_FUNCTION) + break; + } assert(pscope); scope = pscope; } From f9559853f1ae60c9de7073b45f75801c8893b104 Mon Sep 17 00:00:00 2001 From: Martin Whitaker Date: Mon, 8 Aug 2016 22:10:16 +0100 Subject: [PATCH 44/51] Fix for br1007 - out-of-range constant bit select should be a warning. An out-of-range constant bit select on the LHS of an assignment was being treated as an error, whereas an out-of range constant part select would only result in a warning. In any other context, either case would result in a warning, so convert the error to a warning. In addition, all warnings for out-of-range or undefined constant bit/part selects should be controlled by -Wselect-range. (cherry picked from commit b51e58fa9db937561697b75086f865001b2b2ac4) --- elab_lval.cc | 47 ++++++++++++++++++++++++++--------------------- 1 file changed, 26 insertions(+), 21 deletions(-) diff --git a/elab_lval.cc b/elab_lval.cc index 047d611ab..eec2aabd1 100644 --- a/elab_lval.cc +++ b/elab_lval.cc @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000-2014 Stephen Williams (steve@icarus.com) + * Copyright (c) 2000-2016 Stephen Williams (steve@icarus.com) * Copyright CERN 2012-2013 / Stephen Williams (steve@icarus.com) * * This source code is free software; you can redistribute it @@ -691,20 +691,24 @@ bool PEIdent::elaborate_lval_net_bit_(Design*des, unsigned long lwid; bool rcl = reg->sb_to_slice(prefix_indices, lsb, loff, lwid); ivl_assert(*this, rcl); - cerr << get_fileline() << ": warning: L-value packed array " - << "select of " << reg->name(); - if (reg->unpacked_dimensions() > 0) cerr << "[]"; - cerr << " has an undefined index." << endl; - + if (warn_ob_select) { + cerr << get_fileline() + << ": warning: L-value packed array select of " + << reg->name(); + if (reg->unpacked_dimensions() > 0) cerr << "[]"; + cerr << " has an undefined index." << endl; + } lv->set_part(new NetEConst(verinum(verinum::Vx)), lwid); return true; // The index is undefined and this is a bit select. } else { - cerr << get_fileline() << ": warning: L-value bit select of " - << reg->name(); - if (reg->unpacked_dimensions() > 0) cerr << "[]"; - cerr << " has an undefined index." << endl; - + if (warn_ob_select) { + cerr << get_fileline() + << ": warning: L-value bit select of " + << reg->name(); + if (reg->unpacked_dimensions() > 0) cerr << "[]"; + cerr << " has an undefined index." << endl; + } lv->set_part(new NetEConst(verinum(verinum::Vx)), 1); return true; } @@ -801,12 +805,10 @@ bool PEIdent::elaborate_lval_net_bit_(Design*des, // Constant bit select that does something useful. long loff = reg->sb_to_idx(prefix_indices,lsb); - if (loff < 0 || loff >= (long)reg->vector_width()) { - cerr << get_fileline() << ": error: bit select " + if (warn_ob_select && (loff < 0 || loff >= (long)reg->vector_width())) { + cerr << get_fileline() << ": warning: bit select " << reg->name() << "[" <errors += 1; - return 0; } if (reg->type()==NetNet::UNRESOLVED_WIRE) { @@ -872,10 +874,13 @@ bool PEIdent::elaborate_lval_net_part_(Design*des, ivl_assert(*this, reg); if (! parts_defined_flag) { - cerr << get_fileline() << ": warning: L-value part select of " - << reg->name(); - if (reg->unpacked_dimensions() > 0) cerr << "[]"; - cerr << " has an undefined index." << endl; + if (warn_ob_select) { + cerr << get_fileline() + << ": warning: L-value part select of " + << reg->name(); + if (reg->unpacked_dimensions() > 0) cerr << "[]"; + cerr << " has an undefined index." << endl; + } // Use a width of two here so we can distinguish between an // undefined bit or part select. lv->set_part(new NetEConst(verinum(verinum::Vx)), 2); @@ -938,11 +943,11 @@ bool PEIdent::elaborate_lval_net_part_(Design*des, } /* If the part select extends beyond the extremes of the - variable, then report an error. Note that loff is + variable, then output a warning. Note that loff is converted to normalized form so is relative the variable pins. */ - if (loff < 0 || moff >= (long)reg->vector_width()) { + if (warn_ob_select && (loff < 0 || moff >= (long)reg->vector_width())) { cerr << get_fileline() << ": warning: Part select " << reg->name() << "[" << msb<<":"< Date: Sun, 14 Aug 2016 12:45:28 -0700 Subject: [PATCH 45/51] Update fstapi.c to latest from GTKWave --- vpi/fstapi.c | 119 ++++++++++++++++++++++++++++++++++++++------------- 1 file changed, 89 insertions(+), 30 deletions(-) diff --git a/vpi/fstapi.c b/vpi/fstapi.c index 18e06735c..18d38ec99 100644 --- a/vpi/fstapi.c +++ b/vpi/fstapi.c @@ -3074,6 +3074,7 @@ uint32_t *rvat_chain_table_lengths; uint64_t rvat_vc_maxhandle; off_t rvat_vc_start; uint32_t *rvat_sig_offs; +int rvat_packtype; uint32_t rvat_chain_len; unsigned char *rvat_chain_mem; @@ -5886,6 +5887,7 @@ if(frame_uclen == frame_clen) xc->rvat_vc_maxhandle = fstReaderVarint64(xc->f); xc->rvat_vc_start = ftello(xc->f); /* points to '!' character */ +xc->rvat_packtype = fgetc(xc->f); #ifdef FST_DEBUG fprintf(stderr, "\tframe_uclen: %d, frame_clen: %d, frame_maxhandle: %d\n", @@ -5910,37 +5912,84 @@ xc->rvat_chain_table_lengths = calloc((xc->rvat_vc_maxhandle+1), sizeof(uint32_t pnt = chain_cmem; idx = 0; pval = 0; -do + +if(sectype == FST_BL_VCDATA_DYN_ALIAS2) { - int skiplen; - uint64_t val = fstGetVarint32(pnt, &skiplen); - - if(!val) - { - pnt += skiplen; - val = fstGetVarint32(pnt, &skiplen); - xc->rvat_chain_table[idx] = 0; - xc->rvat_chain_table_lengths[idx] = -val; - idx++; - } - else - if(val&1) - { - pval = xc->rvat_chain_table[idx] = pval + (val >> 1); - if(idx) { xc->rvat_chain_table_lengths[pidx] = pval - xc->rvat_chain_table[pidx]; } - pidx = idx++; - } - else - { - fstHandle loopcnt = val >> 1; - for(i=0;irvat_chain_table[idx++] = 0; + int64_t shval = fstGetSVarint64(pnt, &skiplen) >> 1; + if(shval > 0) + { + pval = xc->rvat_chain_table[idx] = pval + shval; + if(idx) { xc->rvat_chain_table_lengths[pidx] = pval - xc->rvat_chain_table[pidx]; } + pidx = idx++; + } + else if(shval < 0) + { + xc->rvat_chain_table[idx] = 0; /* need to explicitly zero as calloc above might not run */ + xc->rvat_chain_table_lengths[idx] = prev_alias = shval; /* because during this loop iter would give stale data! */ + idx++; + } + else + { + xc->rvat_chain_table[idx] = 0; /* need to explicitly zero as calloc above might not run */ + xc->rvat_chain_table_lengths[idx] = prev_alias; /* because during this loop iter would give stale data! */ + idx++; + } } - } - - pnt += skiplen; - } while (pnt != (chain_cmem + chain_clen)); + else + { + uint64_t val = fstGetVarint32(pnt, &skiplen); + + fstHandle loopcnt = val >> 1; + for(i=0;irvat_chain_table[idx++] = 0; + } + } + + pnt += skiplen; + } while (pnt != (chain_cmem + chain_clen)); + } + else + { + do + { + int skiplen; + uint64_t val = fstGetVarint32(pnt, &skiplen); + + if(!val) + { + pnt += skiplen; + val = fstGetVarint32(pnt, &skiplen); + xc->rvat_chain_table[idx] = 0; + xc->rvat_chain_table_lengths[idx] = -val; + idx++; + } + else + if(val&1) + { + pval = xc->rvat_chain_table[idx] = pval + (val >> 1); + if(idx) { xc->rvat_chain_table_lengths[pidx] = pval - xc->rvat_chain_table[pidx]; } + pidx = idx++; + } + else + { + fstHandle loopcnt = val >> 1; + for(i=0;irvat_chain_table[idx++] = 0; + } + } + + pnt += skiplen; + } while (pnt != (chain_cmem + chain_clen)); + } free(chain_cmem); xc->rvat_chain_table[idx] = indx_pos - xc->rvat_vc_start; @@ -6004,10 +6053,20 @@ if(!xc->rvat_chain_mem) unsigned char *mc = malloc(xc->rvat_chain_table_lengths[facidx]); unsigned long destlen = xc->rvat_chain_len; unsigned long sourcelen = xc->rvat_chain_table_lengths[facidx]; - int rc; + int rc = Z_OK; fstFread(mc, xc->rvat_chain_table_lengths[facidx], 1, xc->f); - rc = uncompress(mu, &destlen, mc, sourcelen); + + switch(xc->rvat_packtype) + { + case '4': rc = (destlen == (unsigned long)LZ4_decompress_safe_partial((char *)mc, (char *)mu, sourcelen, destlen, destlen)) ? Z_OK : Z_DATA_ERROR; + break; + case 'F': fastlz_decompress(mc, sourcelen, mu, destlen); /* rc appears unreliable */ + break; + default: rc = uncompress(mu, &destlen, mc, sourcelen); + break; + } + free(mc); if(rc != Z_OK) From 8bb4777789dca4935d5cf044dca36678d4a880d1 Mon Sep 17 00:00:00 2001 From: Cary R Date: Sun, 14 Aug 2016 17:25:12 -0700 Subject: [PATCH 46/51] Fix getting timeunit outside of module to use a defined check value --- pform.cc | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/pform.cc b/pform.cc index be8972afb..e1ce254c0 100644 --- a/pform.cc +++ b/pform.cc @@ -1096,10 +1096,10 @@ void pform_set_timeunit(const char*txt, bool in_module, bool only_check) int pform_get_timeunit() { - if (pform_cur_module.front()) - return pform_cur_module.front()->time_unit; - else + if (pform_cur_module.empty()) return pform_time_unit; + else + return pform_cur_module.front()->time_unit; } void pform_set_timeprecision(const char*txt, bool in_module, bool only_check) From 9449c468655faed73a19bd19e4028d503ff6659b Mon Sep 17 00:00:00 2001 From: Martin Whitaker Date: Thu, 8 Sep 2016 23:00:48 +0100 Subject: [PATCH 47/51] Use gn_system_verilog() where appropriate. Replace explicit comparisons against generation_flag with calls to the gn_system_verilog helper function, both for code clarity and to fix a couple of bugs. Also simplify the implementation of the function, as we already rely on the generation_flag enumeration being an ordered list. (cherry picked from commit 3c9b39846c1f4cee84c73ee14ac33687fdcc6f04) --- compiler.h | 23 +++++++++-------------- lexor.lex | 6 +++--- main.cc | 2 +- parse.y | 2 +- pform.cc | 10 +++++----- 5 files changed, 19 insertions(+), 24 deletions(-) diff --git a/compiler.h b/compiler.h index ca1e36732..bd6ca25f5 100644 --- a/compiler.h +++ b/compiler.h @@ -142,7 +142,8 @@ extern int build_library_index(const char*path, bool key_case_sensitive); /* This is the generation of Verilog that the compiler is asked to support. Then there are also more detailed controls for more - specific language features. */ + specific language features. Note that the compiler often assumes + this is an ordered list. */ enum generation_t { GN_VER1995 = 1, GN_VER2001_NOCONFIG = 2, @@ -191,25 +192,19 @@ extern bool gn_strict_expr_width_flag; loop. */ extern bool gn_shared_loop_index_flag; -/* If variables can be converted to uwires by a continuous assignment - (assuming no procedural assign, then return true. This will be true - for SystemVerilog */ -static inline bool gn_var_can_be_uwire(void) +static inline bool gn_system_verilog(void) { - if (generation_flag == GN_VER2005_SV || - generation_flag == GN_VER2009 || - generation_flag == GN_VER2012) + if (generation_flag >= GN_VER2005_SV) return true; return false; } -static inline bool gn_system_verilog(void) +/* If variables can be converted to uwires by a continuous assignment + (assuming no procedural assign), then return true. This will be true + for SystemVerilog */ +static inline bool gn_var_can_be_uwire(void) { - if (generation_flag == GN_VER2005_SV || - generation_flag == GN_VER2009 || - generation_flag == GN_VER2012) - return true; - return false; + return gn_system_verilog(); } static inline bool gn_modules_nest(void) diff --git a/lexor.lex b/lexor.lex index a153000ad..15591d402 100644 --- a/lexor.lex +++ b/lexor.lex @@ -453,7 +453,7 @@ TU [munpf] return BASED_NUMBER; } \'[01xzXZ] { - if (generation_flag < GN_VER2005_SV) { + if (!gn_system_verilog()) { cerr << yylloc.text << ":" << yylloc.first_line << ": warning: " << "Using SystemVerilog 'N bit vector. Use at least " << "-g2005-sv to remove this warning." << endl; @@ -479,7 +479,7 @@ TU [munpf] /* This rule handles scaled time values for SystemVerilog. */ [0-9][0-9_]*(\.[0-9][0-9_]*)?{TU}?s { - if(generation_flag & (GN_VER2005_SV | GN_VER2009 | GN_VER2012)) { + if (gn_system_verilog()) { yylval.text = strdupnew(yytext); return TIME_LITERAL; } else REJECT; } @@ -857,7 +857,7 @@ verinum*make_unsized_binary(const char*txt) ptr += 1; } - assert((tolower(*ptr) == 'b') || (generation_flag >= GN_VER2005_SV)); + assert((tolower(*ptr) == 'b') || gn_system_verilog()); if (tolower(*ptr) == 'b') { ptr += 1; } else { diff --git a/main.cc b/main.cc index b3bd130f2..9e54f5c50 100644 --- a/main.cc +++ b/main.cc @@ -1118,7 +1118,7 @@ int main(int argc, char*argv[]) /* Decide if we are going to allow system functions to be called * as tasks. */ - if (generation_flag >= GN_VER2005_SV) { + if (gn_system_verilog()) { def_sfunc_as_task = IVL_SFUNC_AS_TASK_WARNING; } diff --git a/parse.y b/parse.y index 897479f09..a4bd0623e 100644 --- a/parse.y +++ b/parse.y @@ -2232,7 +2232,7 @@ variable_dimension /* IEEE1800-2005: A.2.5 */ } | '[' expression ']' { // SystemVerilog canonical range - if (generation_flag < GN_VER2005_SV) { + if (!gn_system_verilog()) { warn_count += 1; cerr << @2 << ": warning: Use of SystemVerilog [size] dimension. " << "Use at least -g2005-sv to remove this warning." << endl; diff --git a/pform.cc b/pform.cc index e1ce254c0..fed8aefbf 100644 --- a/pform.cc +++ b/pform.cc @@ -486,7 +486,7 @@ PFunction* pform_push_function_scope(const struct vlltype&loc, const char*name, pform_set_scope_timescale(func, loc); PScopeExtra*scopex = find_nearest_scopex(lexical_scope); - if ((scopex == 0) && (generation_flag < GN_VER2005_SV)) { + if ((scopex == 0) && !gn_system_verilog()) { cerr << func->get_fileline() << ": error: function declarations " "must be contained within a module." << endl; error_count += 1; @@ -1252,7 +1252,7 @@ void pform_startmodule(const struct vlltype&loc, const char*name, void pform_check_timeunit_prec() { assert(! pform_cur_module.empty()); - if ((generation_flag & (GN_VER2005_SV | GN_VER2009 | GN_VER2012)) && + if (gn_system_verilog() && (pform_cur_module.front()->time_unit < pform_cur_module.front()->time_precision)) { VLerror("error: a timeprecision is missing or is too large!"); } else assert(pform_cur_module.front()->time_unit >= @@ -2678,7 +2678,7 @@ void pform_makewire(const struct vlltype&li, NetNet::Type type, data_type_t*data_type) { - if ((lexical_scope == 0) && (generation_flag < GN_VER2005_SV)) { + if ((lexical_scope == 0) && !gn_system_verilog()) { VLerror(li, "error: variable declarations must be contained within a module."); return; } @@ -2983,7 +2983,7 @@ void pform_set_parameter(const struct vlltype&loc, LexicalScope::range_t*value_range) { LexicalScope*scope = lexical_scope; - if ((scope == 0) && (generation_flag < GN_VER2005_SV)) { + if ((scope == 0) && !gn_system_verilog()) { VLerror(loc, "error: parameter declarations must be contained within a module."); return; } @@ -3058,7 +3058,7 @@ void pform_set_localparam(const struct vlltype&loc, bool signed_flag, list*range, PExpr*expr) { LexicalScope*scope = lexical_scope; - if ((scope == 0) && (generation_flag < GN_VER2005_SV)) { + if ((scope == 0) && !gn_system_verilog()) { VLerror(loc, "error: localparam declarations must be contained within a module."); return; } From e7852f8f9c2b3dec52f098f726b971e2008dfa79 Mon Sep 17 00:00:00 2001 From: Martin Whitaker Date: Sat, 17 Sep 2016 19:20:48 +0100 Subject: [PATCH 48/51] Fix for GitHub issue #127 - coerce output ports to inout when necessary. (cherry picked from commit 080dd0323dae72f5448e6f4053ce315ddb844d13) --- elaborate.cc | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/elaborate.cc b/elaborate.cc index 0faa7ed2a..f4f99f85f 100644 --- a/elaborate.cc +++ b/elaborate.cc @@ -1425,6 +1425,16 @@ void PGModule::elaborate_mod_(Design*des, Module*rmod, NetScope*scope) const << prts[0]->name() << " is coerced to inout." << endl; } + if (!prts.empty() && (prts[0]->port_type() == NetNet::POUTPUT) + && (prts[0]->type() != NetNet::REG) + && prts[0]->pin(0).nexus()->has_floating_input() + && pins[idx]->is_collapsible_net(des, scope)) { + prts[0]->port_type(NetNet::PINOUT); + + cerr << pins[idx]->get_fileline() << ": warning: output port " + << prts[0]->name() << " is coerced to inout." << endl; + } + // Elaborate the expression that connects to the // module[s] port. sig is the thing outside the module // that connects to the port. From a11dc8b472d2a128f02e029114160cc8271a1d30 Mon Sep 17 00:00:00 2001 From: Martin Whitaker Date: Sat, 17 Sep 2016 19:40:05 +0100 Subject: [PATCH 49/51] Backport Nexus::has_floating_input() from master branch. Needed to support check for output port coercion. --- net_link.cc | 14 ++++++++++++++ netlist.h | 4 ++++ 2 files changed, 18 insertions(+) diff --git a/net_link.cc b/net_link.cc index 15c67e046..fcd202f10 100644 --- a/net_link.cc +++ b/net_link.cc @@ -311,6 +311,20 @@ void Nexus::count_io(unsigned&inp, unsigned&out) const } } +bool Nexus::has_floating_input() const +{ + bool found_input = false; + for (const Link*cur = first_nlink() ; cur ; cur = cur->next_nlink()) { + if (cur->get_dir() == Link::OUTPUT) + return false; + + if (cur->get_dir() == Link::INPUT) + found_input = true; + } + + return found_input; +} + bool Nexus::drivers_present() const { for (const Link*cur = first_nlink() ; cur ; cur = cur->next_nlink()) { diff --git a/netlist.h b/netlist.h index 68bc27319..054b87b66 100644 --- a/netlist.h +++ b/netlist.h @@ -388,6 +388,10 @@ class Nexus { is a variable, but also if this is a net with a force. */ bool assign_lval() const; + /* This method returns true if there are any inputs + attached to this nexus but no drivers. */ + bool has_floating_input() const; + /* This method returns true if there are any drivers (including variables) attached to this nexus. */ bool drivers_present() const; From 37ecdb4cfbcf0ff9fc070895ac7067a75ba3e92f Mon Sep 17 00:00:00 2001 From: Martin Whitaker Date: Sat, 17 Sep 2016 19:49:26 +0100 Subject: [PATCH 50/51] Stop tgt-vvp from generating .alias records. (partial backport of commit d44c814bab0c26347d821708fb671b691fdb4242) Net arrays can be handled by nets directly, instead of creating .alias records. But keep support for .alias records in vvp. to maintain backwards compatibility. --- tgt-vvp/vvp_scope.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tgt-vvp/vvp_scope.c b/tgt-vvp/vvp_scope.c index 2919c3337..80534c429 100644 --- a/tgt-vvp/vvp_scope.c +++ b/tgt-vvp/vvp_scope.c @@ -669,7 +669,7 @@ static void draw_net_in_scope(ivl_signal_t sig) swapped ? last : first ); } - fprintf(vvp_out, "v%p_%u .alias%s v%p %u, %d %d, " + fprintf(vvp_out, "v%p_%u .net%s v%p %u, %d %d, " "v%p_%u; Alias to %s\n", sig, iword, datatype_flag, sig, iword, msb, lsb, nex_data->net, nex_data->net_word, From 572124e1e975d26b8bc3df86d25a65c79b678410 Mon Sep 17 00:00:00 2001 From: Martin Whitaker Date: Sun, 2 Oct 2016 18:57:32 +0100 Subject: [PATCH 51/51] Allow library files to be specified on the iverilog command line. This was already supported in command files, using the '-v' flag. '-v' is already in use on the command line, so use '-l' instead, and make that an alias for '-v' in command files. (cherry picked from commit 7ddc514518a535ef0a63674bfe03f0223bb5e55b) --- driver/cflexor.lex | 5 +++-- driver/iverilog.man.in | 24 ++++++++++++++++++++---- driver/main.c | 8 ++++++-- 3 files changed, 29 insertions(+), 8 deletions(-) diff --git a/driver/cflexor.lex b/driver/cflexor.lex index b0ba1a40b..3f3e46e80 100644 --- a/driver/cflexor.lex +++ b/driver/cflexor.lex @@ -4,7 +4,7 @@ %{ /* - * Copyright (c) 2001-2014 Stephen Williams (steve@icarus.com) + * Copyright (c) 2001-2016 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 @@ -124,7 +124,8 @@ int cmdfile_stack_ptr = 0; "-c" { return TOK_Dc; } "-f" { return TOK_Dc; } - /* Notice the -v flag. */ + /* Notice the -l or -v flag. */ +"-l" { return TOK_Dv; } "-v" { return TOK_Dv; } /* Notice the -y flag. */ diff --git a/driver/iverilog.man.in b/driver/iverilog.man.in index 2d3a62344..fbbaa14a5 100644 --- a/driver/iverilog.man.in +++ b/driver/iverilog.man.in @@ -1,14 +1,15 @@ -.TH iverilog 1 "Mar 5th, 2016" "" "Version %M.%n%E" +.TH iverilog 1 "Oct 2nd, 2016" "" "Version %M.%n%E" .SH NAME iverilog - Icarus Verilog compiler .SH SYNOPSIS .B iverilog [\-ESVv] [\-Bpath] [\-ccmdfile|\-fcmdfile] [\-Dmacro[=defn]] -[\-Pparameter=value] [\-pflag=value] -[\-dname] [\-g1995|\-g2001|\-g2005|\-g2005-sv|\-g2009|\-g2012|\-g] +[\-Pparameter=value] [\-pflag=value] [\-dname] +[\-g1995\:|\-g2001\:|\-g2005\:|\-g2005-sv\:|\-g2009\:|\-g2012\:|\-g] [\-Iincludedir] [\-mmodule] [\-M[mode=]file] [\-Nfile] [\-ooutputfilename] -[\-stopmodule] [\-ttype] [\-Tmin/typ/max] [\-Wclass] [\-ypath] sourcefile +[\-stopmodule] [\-ttype] [\-Tmin/typ/max] [\-Wclass] [\-ypath] [\-lfile] +sourcefile .SH DESCRIPTION .PP @@ -150,6 +151,12 @@ for Verilog include files. The \fB\-I\fP switch may be used many times to specify several directories to search, the directories are searched in the order they appear on the command line. .TP 8 +.B -l\fIfile\fP +Add the specified file to the list of source files to be compiled, +but mark it as a library file. All modules contained within that +file will be treated as library modules, and only elaborated if +they are instantiated by other modules in the design. +.TP 8 .B -M\fIpath\fP This is equivalent to \fB\-Mall=path\fP. Preserved for backwards compatibility. @@ -413,6 +420,15 @@ A \fB\-c\fP or \fB\-f\fP token prefixes a command file, exactly like it does on the command line. The cmdfile may be on the same line or the next non-comment line. +.TP 8 +.B -l\ \fIfile\fP -v\ \fIfile\fP +A \fB\-l\fP token prefixes a library file in the command file, +exactly like it does on the command line. The parameter to the \fB\-l\fP +flag may be on the same line or the next non-comment line. \fB\-v\fP is +an alias for \fB\-l\fP, provided for compatibility with other simulators. + +Variables in the \fIfile\fP are substituted. + .TP 8 .B -y\ \fIlibdir\fP A \fB\-y\fP token prefixes a library directory in the command file, diff --git a/driver/main.c b/driver/main.c index c370ac844..93de379c1 100644 --- a/driver/main.c +++ b/driver/main.c @@ -44,7 +44,7 @@ const char HELP[] = " [-M [mode=]depfile] [-m module]\n" " [-N file] [-o filename] [-p flag=value]\n" " [-s topmodule] [-t target] [-T min|typ|max]\n" -" [-W class] [-y dir] [-Y suf] source_file(s)\n" +" [-W class] [-y dir] [-Y suf] [-l file] source_file(s)\n" "\n" "See the man page for details."; @@ -928,7 +928,7 @@ int main(int argc, char **argv) } } - while ((opt = getopt(argc, argv, "B:c:D:d:Ef:g:hI:M:m:N:o:P:p:Ss:T:t:vVW:y:Y:")) != EOF) { + while ((opt = getopt(argc, argv, "B:c:D:d:Ef:g:hl:I:M:m:N:o:P:p:Ss:T:t:vVW:y:Y:")) != EOF) { switch (opt) { case 'B': @@ -983,6 +983,10 @@ int main(int argc, char **argv) process_include_dir(optarg); break; + case 'l': + process_file_name(optarg, 1); + break; + case 'M': if (process_depfile(optarg) != 0) return -1;