diff --git a/PExpr.h b/PExpr.h index ba4ec4d24..1beb01f6b 100644 --- a/PExpr.h +++ b/PExpr.h @@ -666,7 +666,7 @@ class PECallFunction : public PExpr { bool check_call_matches_definition_(Design*des, NetScope*dscope) const; - NetExpr* elaborate_sfunc_(Design*des, NetScope*scope) const; + NetExpr* elaborate_sfunc_(Design*des, NetScope*scope, int expr_wid) const; NetNet* elaborate_net_sfunc_(Design*des, NetScope*scope, unsigned width, const NetExpr* rise, diff --git a/elab_expr.cc b/elab_expr.cc index df84cbcd4..cf4470b93 100644 --- a/elab_expr.cc +++ b/elab_expr.cc @@ -372,7 +372,7 @@ unsigned PECallFunction::test_width(Design*des, NetScope*scope, * size_tf functions, make assumptions about widths based on some * known function names. */ -NetExpr* PECallFunction::elaborate_sfunc_(Design*des, NetScope*scope) const +NetExpr* PECallFunction::elaborate_sfunc_(Design*des, NetScope*scope, int expr_wid) const { /* Catch the special case that the system function is the @@ -405,6 +405,10 @@ NetExpr* PECallFunction::elaborate_sfunc_(Design*des, NetScope*scope) const PExpr*expr = parms_[0]; NetExpr*sub = expr->elaborate_expr(des, scope, -1, true); sub->cast_signed(false); + + if (expr_wid > 0 && (unsigned)expr_wid > sub->expr_width()) + sub = pad_to_width(sub, expr_wid); + return sub; } @@ -536,7 +540,7 @@ NetExpr* PECallFunction::elaborate_expr(Design*des, NetScope*scope, int expr_wid, bool) const { if (peek_tail_name(path_)[0] == '$') - return elaborate_sfunc_(des, scope); + return elaborate_sfunc_(des, scope, expr_wid); NetFuncDef*def = des->find_function(scope, path_); if (def == 0) { @@ -570,7 +574,14 @@ NetExpr* PECallFunction::elaborate_expr(Design*des, NetScope*scope, for (unsigned idx = 0 ; idx < parms.count() ; idx += 1) { PExpr*tmp = parms_[idx]; if (tmp) { - parms[idx] = elab_and_eval(des, scope, tmp, -1); + int argwid = def->port(idx)->vector_width(); + parms[idx] = elab_and_eval(des, scope, tmp, argwid); + if (debug_elaborate) + cerr << get_line() << ": debug:" + << " function " << path_ + << " arg " << (idx+1) + << " argwid=" << argwid + << ": " << *parms[idx] << endl; } else { missing_parms += 1; @@ -1253,7 +1264,7 @@ NetExpr* PEIdent::elaborate_expr_net_word_(Design*des, NetScope*scope, // Recalculate the constant address with the adjusted base. unsigned use_addr = net->array_index_to_address(addr); - if (use_addr != addr) { + if (addr < 0 || use_addr != (unsigned long)addr) { verinum val (use_addr, 8*sizeof(use_addr)); NetEConst*tmp = new NetEConst(val); tmp->set_line(*this); diff --git a/set_width.cc b/set_width.cc index 1c1bdae8b..c47a2dad8 100644 --- a/set_width.cc +++ b/set_width.cc @@ -250,6 +250,11 @@ bool NetEConcat::set_width(unsigned w, bool) bool NetEConst::set_width(unsigned w, bool last_chance) { + /* Make the value signed if the NetEConst is signed. + * This happens when $signed() is called, so this + * sign information needs to be propagated. */ + value_.has_sign(has_sign()); + if (w == value_.len()) { expr_width(w); return true; @@ -438,153 +443,3 @@ bool NetEUReduce::set_width(unsigned w, bool) return w == 1; } - -/* - * $Log: set_width.cc,v $ - * Revision 1.42 2007/01/16 05:44:15 steve - * Major rework of array handling. Memories are replaced with the - * more general concept of arrays. The NetMemory and NetEMemory - * classes are removed from the ivl core program, and the IVL_LPM_RAM - * lpm type is removed from the ivl_target API. - * - * Revision 1.41 2006/11/04 06:19:25 steve - * Remove last bits of relax_width methods, and use test_width - * to calculate the width of an r-value expression that may - * contain unsized numbers. - * - * Revision 1.40 2006/10/30 05:44:49 steve - * Expression widths with unsized literals are pseudo-infinite width. - * - * Revision 1.39 2006/07/31 03:50:17 steve - * Add support for power in constant expressions. - * - * Revision 1.38 2006/05/02 04:29:42 steve - * Be more stubborn about widths. - * - * Revision 1.37 2005/11/26 00:35:44 steve - * More precise about r-value width of constants. - * - * Revision 1.36 2005/05/17 20:56:55 steve - * Parameters cannot have their width changed. - * - * Revision 1.35 2005/01/24 05:28:31 steve - * Remove the NetEBitSel and combine all bit/part select - * behavior into the NetESelect node and IVL_EX_SELECT - * ivl_target expression type. - * - * Revision 1.34 2003/08/28 04:11:19 steve - * Spelling patch. - * - * Revision 1.33 2003/07/26 03:34:42 steve - * Start handling pad of expressions in code generators. - * - * Revision 1.32 2003/06/21 01:21:43 steve - * Harmless fixup of warnings. - * - * Revision 1.31 2003/06/18 03:55:19 steve - * Add arithmetic shift operators. - * - * Revision 1.30 2003/05/20 15:05:33 steve - * Do not try to set constants to width 0. - * - * Revision 1.29 2003/05/04 20:04:09 steve - * Fix truncation of signed constant in constant addition. - * - * Revision 1.28 2003/04/02 04:25:26 steve - * Fix xz extension of constants. - * - * Revision 1.27 2003/02/06 17:50:23 steve - * Real constants have no defined vector width - * - * Revision 1.26 2003/01/26 21:02:21 steve - * Remember to save signedness of number. - * - * Revision 1.25 2002/11/13 03:03:08 steve - * Do not truncate high bits of right shift. - * - * Revision 1.24 2002/11/06 02:25:13 steve - * No need to keep excess width from an - * unsigned constant value, if it can - * be trimmed safely. - * - * Revision 1.23 2002/08/12 01:35:00 steve - * conditional ident string using autoconfig. - * - * Revision 1.22 2002/05/05 21:11:50 steve - * Put off evaluation of concatenation repeat expresions - * until after parameters are defined. This allows parms - * to be used in repeat expresions. - * - * Add the builtin $signed system function. - * - * Revision 1.21 2002/04/27 04:49:27 steve - * If the verinum is already right, no need to reset it. - * - * Revision 1.20 2001/11/19 04:26:46 steve - * Unary reduction operators are all 1-bit results. - * - * Revision 1.19 2001/07/27 04:51:44 steve - * Handle part select expressions as variants of - * NetESignal/IVL_EX_SIGNAL objects, instead of - * creating new and useless temporary signals. - * - * Revision 1.18 2001/07/25 03:10:49 steve - * Create a config.h.in file to hold all the config - * junk, and support gcc 3.0. (Stephan Boettcher) - * - * Revision 1.17 2001/02/08 01:10:30 steve - * Remove dead code. - * - * Revision 1.16 2001/02/07 21:47:13 steve - * Fix expression widths for rvalues and parameters (PR#131,132) - * - * Revision 1.15 2001/01/27 05:41:48 steve - * Fix sign extension of evaluated constants. (PR#91) - * - * Revision 1.14 2000/06/18 03:29:52 steve - * Handle width expansion of shift operators. - * - * Revision 1.13 2000/05/04 03:37:59 steve - * Add infrastructure for system functions, move - * $time to that structure and add $random. - * - * Revision 1.12 2000/04/28 18:43:23 steve - * integer division in expressions properly get width. - * - * Revision 1.11 2000/04/26 03:33:32 steve - * Do not set width too small to hold significant bits. - * - * Revision 1.10 2000/04/21 02:46:42 steve - * Many Unary operators have known widths. - * - * Revision 1.9 2000/02/23 02:56:55 steve - * Macintosh compilers do not support ident. - * - * Revision 1.8 2000/01/13 03:35:35 steve - * Multiplication all the way to simulation. - * - * Revision 1.7 2000/01/01 19:56:51 steve - * Properly expand/shrink constants in expressions. - * - * Revision 1.6 1999/10/05 06:19:46 steve - * Add support for reduction NOR. - * - * Revision 1.5 1999/10/05 04:02:10 steve - * Relaxed width handling for <= assignment. - * - * Revision 1.4 1999/09/29 00:42:51 steve - * Allow expanding of additive operators. - * - * Revision 1.3 1999/09/23 03:56:57 steve - * Support shift operators. - * - * Revision 1.2 1999/09/23 02:27:50 steve - * comparison parameter width is self determined. - * - * Revision 1.1 1999/09/23 00:21:55 steve - * Move set_width methods into a single file, - * Add the NetEBLogic class for logic expressions, - * Fix error setting with of && in if statements. - * - */ - diff --git a/verinum.cc b/verinum.cc index d651aaf1d..7b26a3322 100644 --- a/verinum.cc +++ b/verinum.cc @@ -912,6 +912,36 @@ static verinum unsigned_divide(verinum num, verinum den) return result; } +static verinum unsigned_modulus(verinum num, verinum den) +{ + unsigned nwid = num.len(); + while (nwid > 0 && (num.get(nwid-1) == verinum::V0)) + nwid -= 1; + + unsigned dwid = den.len(); + while (dwid > 0 && (den.get(dwid-1) == verinum::V0)) + dwid -= 1; + + if (dwid > nwid) + return num; + + den = den << (nwid-dwid); + + unsigned idx = nwid - dwid + 1; + verinum result (verinum::V0, idx); + while (idx > 0) { + if (den <= num) { + verinum dif = num - den; + num = dif; + result.set(idx-1, verinum::V1); + } + den = den >> 1; + idx -= 1; + } + + return num; +} + /* * This operator divides the left number by the right number. If * either value is signed, the result is signed. If both values have a @@ -1039,20 +1069,25 @@ verinum operator % (const verinum&left, const verinum&right) } else { - /* XXXX FIXME XXXX Use native unsigned division to do + /* Use native unsigned division, if possible, to do the work. This does not work if the result is too - large for the native integer. */ - assert(use_len <= 8*sizeof(unsigned long)); - unsigned long l = left.as_ulong(); - unsigned long r = right.as_ulong(); - unsigned long v = l % r; - for (unsigned idx = 0 ; idx < use_len ; idx += 1) { - result.set(idx, (v & 1)? verinum::V1 : verinum::V0); - v >>= 1; + large for the native integer, so resort to a modulus + function in that case. */ + if (use_len <= 8*sizeof(unsigned long)) { + assert(use_len <= 8*sizeof(unsigned long)); + unsigned long l = left.as_ulong(); + unsigned long r = right.as_ulong(); + unsigned long v = l % r; + for (unsigned idx = 0 ; idx < use_len ; idx += 1) { + result.set(idx, (v & 1)? verinum::V1 : verinum::V0); + v >>= 1; + } + } else { + result = unsigned_modulus(left, right); } } - return result; + return trim_vnum(result); } verinum concat(const verinum&left, const verinum&right)