diff --git a/PExpr.h b/PExpr.h index 1355b67d0..2583ec05e 100644 --- a/PExpr.h +++ b/PExpr.h @@ -682,6 +682,8 @@ class PECallFunction : public PExpr { bool check_call_matches_definition_(Design*des, NetScope*dscope) const; + NetExpr* cast_to_width_(NetExpr*expr, int wid, bool signed_flag) const; + NetExpr* elaborate_sfunc_(Design*des, NetScope*scope, int expr_wid) const; NetExpr* elaborate_access_func_(Design*des, NetScope*scope, ivl_nature_t) const; unsigned test_width_sfunc_(Design*des, NetScope*scope, diff --git a/elab_expr.cc b/elab_expr.cc index fa165569a..eee54849a 100644 --- a/elab_expr.cc +++ b/elab_expr.cc @@ -1087,14 +1087,20 @@ unsigned PECallFunction::test_width_sfunc_(Design*des, NetScope*scope, if (expr == 0) return 0; - expr_width_ = expr->test_width(des, scope, min, lval, expr_type__, unsized_flag); + // The argument width is self-determined. + expr_width_ = expr->test_width(des, scope, 0, 0, expr_type__, unsized_flag); expr_type_ = expr_type__; + // The result width is context dependent. + if (expr_width_ > min) + min = expr_width_; + if (debug_elaborate) - cerr << get_fileline() << ": debug: test_width" - << " of $signed/$unsigned returns test_width" - << " of subexpression." << endl; - return expr_width_; + cerr << get_fileline() << ": debug: $signed/$unsigned" + << " argument width = " << expr_width_ + << ", result width = " << min << "." << endl; + + return min; } // Run through the arguments of the system function and make @@ -1208,6 +1214,34 @@ unsigned PECallFunction::test_width(Design*des, NetScope*scope, return 0; } +NetExpr*PECallFunction::cast_to_width_(NetExpr*expr, int wid, bool signed_flag) const +{ + /* 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 > (int)(tmp->expr_width())) { + verinum oval = pad_to_width(tmp->value(), wid); + tmp = new NetEConst(oval); + tmp->set_line(*this); + delete expr; + } + return tmp; + } + + if (wid < 0) + wid = expr->expr_width(); + + if (debug_elaborate) + cerr << get_fileline() << ": debug: cast to " << wid + << " bits" << endl; + + NetESelect*tmp = new NetESelect(expr, 0, wid); + tmp->set_line(*this); + tmp->cast_signed(signed_flag); + return tmp; +} + /* * Given a call to a system function, generate the proper expression * nodes to represent the call in the netlist. Since we don't support @@ -1217,11 +1251,9 @@ unsigned PECallFunction::test_width(Design*des, NetScope*scope, NetExpr* PECallFunction::elaborate_sfunc_(Design*des, NetScope*scope, int expr_wid) const { - /* Catch the special case that the system function is the - $signed function. This function is special, in that it does - not lead to executable code but takes the single parameter - and makes it into a signed expression. No bits are changed, - it just changes the interpretation. */ + /* Catch the special case that the system function is the $signed + function. Its argument will be evaluated as a self-determined + expression. */ if (strcmp(peek_tail_name(path_), "$signed") == 0) { if ((parms_.size() != 1) || (parms_[0] == 0)) { cerr << get_fileline() << ": error: The $signed() function " @@ -1231,11 +1263,11 @@ NetExpr* PECallFunction::elaborate_sfunc_(Design*des, NetScope*scope, int expr_w } PExpr*expr = parms_[0]; - NetExpr*sub = expr->elaborate_expr(des, scope, -1, true); - sub->cast_signed(true); - return sub; + NetExpr*sub = expr->elaborate_expr(des, scope, expr_width_, true); + + return cast_to_width_(sub, expr_wid, true); } - /* add $unsigned to match $signed */ + /* As above, for the $unsigned function. */ if (strcmp(peek_tail_name(path_), "$unsigned") == 0) { if ((parms_.size() != 1) || (parms_[0] == 0)) { cerr << get_fileline() << ": error: The $unsigned() function " @@ -1245,13 +1277,9 @@ NetExpr* PECallFunction::elaborate_sfunc_(Design*des, NetScope*scope, int expr_w } PExpr*expr = parms_[0]; - NetExpr*sub = expr->elaborate_expr(des, scope, -1, true); - sub->cast_signed(false); + NetExpr*sub = expr->elaborate_expr(des, scope, expr_width_, true); - if (expr_wid > 0 && (unsigned)expr_wid > sub->expr_width()) - sub = pad_to_width(sub, expr_wid, *this); - - return sub; + return cast_to_width_(sub, expr_wid, false); } /* Interpret the internal $sizeof system function to return diff --git a/tgt-vvp/draw_vpi.c b/tgt-vvp/draw_vpi.c index 02159e839..a19a1257e 100644 --- a/tgt-vvp/draw_vpi.c +++ b/tgt-vvp/draw_vpi.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003-2009 Stephen Williams (steve@icarus.com) + * Copyright (c) 2003-2010 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 @@ -184,7 +184,9 @@ static int get_vpi_taskfunc_signal_arg(struct args_info *result, if (ivl_expr_oper1(vexpr)) return 0; bexpr = ivl_expr_oper2(expr); - assert(bexpr); + + /* This is a pad operation. */ + if (!bexpr) return 0; /* This is a constant bit/part select. */ if (number_is_immediate(bexpr, 64, 1)) {