From d5874992761a4b1d985ec484dba7cd55c7562999 Mon Sep 17 00:00:00 2001 From: Stephen Williams Date: Mon, 1 Oct 2007 20:38:20 -0700 Subject: [PATCH 1/5] test_width method for functions in expressions In expressions, user defined functions have a clearly defined width and the test_width expression needs to express that. Note that the $signed/$unsigned functions are special and magical. Signed-off-by: Stephen Williams --- PExpr.h | 164 ++---------------------------------------- elab_expr.cc | 63 ++++++++++++++-- tgt-stub/expression.c | 8 ++- 3 files changed, 71 insertions(+), 164 deletions(-) diff --git a/PExpr.h b/PExpr.h index a3d9288f3..ba4ec4d24 100644 --- a/PExpr.h +++ b/PExpr.h @@ -18,9 +18,6 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ -#ifdef HAVE_CVS_IDENT -#ident "$Id: PExpr.h,v 1.90 2007/06/04 19:14:06 steve Exp $" -#endif # include # include @@ -659,6 +656,10 @@ class PECallFunction : public PExpr { virtual NetExpr*elaborate_expr(Design*des, NetScope*scope, int expr_wid, bool sys_task_arg) const; + virtual unsigned test_width(Design*des, NetScope*scope, + unsigned min, unsigned lval, + bool&unsized_flag) const; + private: pform_name_t path_; svector parms_; @@ -673,160 +674,9 @@ class PECallFunction : public PExpr { const NetExpr* decay, Link::strength_t drive0, Link::strength_t drive1) const; + unsigned test_width_sfunc_(Design*des, NetScope*scope, + unsigned min, unsigned lval, + bool&unsized_flag) const; }; -/* - * $Log: PExpr.h,v $ - * Revision 1.90 2007/06/04 19:14:06 steve - * Build errors in picky GCC compilers. - * - * Revision 1.89 2007/06/04 02:19:07 steve - * Handle bit/part select of array words in nets. - * - * Revision 1.88 2007/05/24 04:07:11 steve - * Rework the heirarchical identifier parse syntax and pform - * to handle more general combinations of heirarch and bit selects. - * - * Revision 1.87 2007/01/16 05:44:14 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.86 2006/11/10 04:54:26 steve - * Add test_width methods for PETernary and PEString. - * - * Revision 1.85 2006/11/04 06:19:24 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.84 2006/10/30 05:44:49 steve - * Expression widths with unsized literals are pseudo-infinite width. - * - * Revision 1.83 2006/06/18 04:15:50 steve - * Add support for system functions in continuous assignments. - * - * Revision 1.82 2006/06/02 04:48:49 steve - * Make elaborate_expr methods aware of the width that the context - * requires of it. In the process, fix sizing of the width of unary - * minus is context determined sizes. - * - * Revision 1.81 2006/04/28 04:28:35 steve - * Allow concatenations as arguments to inout ports. - * - * Revision 1.80 2006/04/16 00:54:04 steve - * Cleanup lval part select handling. - * - * Revision 1.79 2006/04/16 00:15:43 steve - * Fix part selects in l-values. - * - * Revision 1.78 2006/03/25 02:36:26 steve - * Get rid of excess PESTring:: prefix within class declaration. - * - * Revision 1.77 2006/02/02 02:43:57 steve - * Allow part selects of memory words in l-values. - * - * Revision 1.76 2006/01/02 05:33:19 steve - * Node delays can be more general expressions in structural contexts. - * - * Revision 1.75 2005/12/07 04:04:23 steve - * Allow constant concat expressions. - * - * Revision 1.74 2005/11/27 17:01:56 steve - * Fix for stubborn compiler. - * - * Revision 1.73 2005/11/27 05:56:20 steve - * Handle bit select of parameter with ranges. - * - * Revision 1.72 2005/11/10 13:28:11 steve - * Reorganize signal part select handling, and add support for - * indexed part selects. - * - * Expand expression constant propagation to eliminate extra - * sums in certain cases. - * - * Revision 1.71 2005/10/04 04:09:25 steve - * Add support for indexed select attached to parameters. - * - * Revision 1.70 2005/08/06 17:58:16 steve - * Implement bi-directional part selects. - * - * Revision 1.69 2005/07/07 16:22:49 steve - * Generalize signals to carry types. - * - * Revision 1.68 2005/01/09 20:16:00 steve - * Use PartSelect/PV and VP to handle part selects through ports. - * - * Revision 1.67 2004/12/29 23:55:43 steve - * Unify elaboration of l-values for all proceedural assignments, - * including assing, cassign and force. - * - * Generate NetConcat devices for gate outputs that feed into a - * vector results. Use this to hande gate arrays. Also let gate - * arrays handle vectors of gates when the outputs allow for it. - * - * Revision 1.66 2004/10/04 01:10:51 steve - * Clean up spurious trailing white space. - * - * Revision 1.65 2003/02/08 19:49:21 steve - * Calculate delay statement delays using elaborated - * expressions instead of pre-elaborated expression - * trees. - * - * Remove the eval_pexpr methods from PExpr. - * - * Revision 1.64 2003/01/30 16:23:07 steve - * Spelling fixes. - * - * Revision 1.63 2002/11/09 19:20:48 steve - * Port expressions for output ports are lnets, not nets. - * - * Revision 1.62 2002/08/12 01:34:58 steve - * conditional ident string using autoconfig. - * - * Revision 1.61 2002/06/04 05:38:43 steve - * Add support for memory words in l-value of - * blocking assignments, and remove the special - * NetAssignMem class. - * - * Revision 1.60 2002/05/23 03:08:51 steve - * Add language support for Verilog-2001 attribute - * syntax. Hook this support into existing $attribute - * handling, and add number and void value types. - * - * Add to the ivl_target API new functions for access - * of complex attributes attached to gates. - * - * Revision 1.59 2002/04/23 03:53:59 steve - * Add support for non-constant bit select. - * - * Revision 1.58 2002/04/14 03:55:25 steve - * Precalculate unary - if possible. - * - * Revision 1.57 2002/04/13 02:33:17 steve - * Detect missing indices to memories (PR#421) - * - * Revision 1.56 2002/03/09 04:02:26 steve - * Constant expressions are not l-values for task ports. - * - * Revision 1.55 2002/03/09 02:10:22 steve - * Add the NetUserFunc netlist node. - * - * Revision 1.54 2001/12/30 21:32:03 steve - * Support elaborate_net for PEString objects. - * - * Revision 1.53 2001/12/03 04:47:14 steve - * Parser and pform use hierarchical names as hname_t - * objects instead of encoded strings. - * - * Revision 1.52 2001/11/08 05:15:50 steve - * Remove string paths from PExpr elaboration. - * - * Revision 1.51 2001/11/07 04:26:46 steve - * elaborate_lnet uses scope instead of string path. - * - * Revision 1.50 2001/11/07 04:01:59 steve - * eval_const uses scope instead of a string path. - */ #endif diff --git a/elab_expr.cc b/elab_expr.cc index b2e50bfc4..5a9e8f295 100644 --- a/elab_expr.cc +++ b/elab_expr.cc @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999-2006 Stephen Williams (steve@icarus.com) + * Copyright (c) 1999-2007 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 @@ -16,9 +16,6 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ -#ifdef HAVE_CVS_IDENT -#ident "$Id: elab_expr.cc,v 1.126 2007/06/02 03:42:12 steve Exp $" -#endif # include "config.h" # include "compiler.h" @@ -38,7 +35,8 @@ unsigned PExpr::test_width(Design*des, NetScope*scope, { if (debug_elaborate) { cerr << get_line() << ": debug: test_width defaults to " - << min << ", ignoring unsized_flag" << endl; + << min << ", ignoring unsized_flag. typeid=" + << typeid(*this).name() << endl; } return min; } @@ -307,6 +305,61 @@ unsigned PEBShift::test_width(Design*des, NetScope*scope, return wid_left; } +unsigned PECallFunction::test_width_sfunc_(Design*des, NetScope*scope, + unsigned min, unsigned lval, + bool&unsized_flag) const +{ + perm_string name = peek_tail_name(path_); + + if (name=="$signed"|| name=="$unsigned") { + PExpr*expr = parms_[0]; + if (expr == 0) + return 0; + unsigned wid = expr->test_width(des, scope, min, lval, unsized_flag); + if (debug_elaborate) + cerr << get_line() << ": debug: test_width" + << " of $signed/$unsigned returns test_width" + << " of subexpression." << endl; + return wid; + } + + if (debug_elaborate) + cerr << get_line() << ": debug: test_width " + << "of system function " << name + << " returns 32 always?" << endl; + return 32; +} + +unsigned PECallFunction::test_width(Design*des, NetScope*scope, + unsigned min, unsigned lval, + bool&unsized_flag) const +{ + if (peek_tail_name(path_)[0] == '$') + return test_width_sfunc_(des, scope, min, lval, unsized_flag); + + NetFuncDef*def = des->find_function(scope, path_); + if (def == 0) { + if (debug_elaborate) + cerr << get_line() << ": debug: test_width " + << "cannot find definition of " << path_ + << " in " << scope_path(scope) << "." << endl; + return 0; + } + + NetScope*dscope = def->scope(); + assert(dscope); + + if (NetNet*res = dscope->find_signal(dscope->basename())) { + if (debug_elaborate) + cerr << get_line() << ": debug: test_width " + << "of function returns width " << res->vector_width() + << "." << endl; + return res->vector_width(); + } + + ivl_assert(*this, 0); + return 0; +} /* * Given a call to a system function, generate the proper expression diff --git a/tgt-stub/expression.c b/tgt-stub/expression.c index 6d4b1c3d4..b992d15f5 100644 --- a/tgt-stub/expression.c +++ b/tgt-stub/expression.c @@ -80,9 +80,13 @@ static void show_function_call(ivl_expr_t net, unsigned ind) ivl_scope_t def = ivl_expr_def(net); const char*sign = ivl_expr_signed(net)? "signed" : "unsigned"; const char*vt = vt_type_string(net); + unsigned idx; - fprintf(out, "%*s<%s %s function %s>\n", ind, "", - vt, sign, ivl_scope_name(def)); + fprintf(out, "%*s<%s %s function %s with %u arguments>\n", ind, "", + vt, sign, ivl_scope_name(def), ivl_expr_parms(net)); + + for (idx = 0 ; idx < ivl_expr_parms(net) ; idx += 1) + show_expression(ivl_expr_parm(net,idx), ind+4); } static void show_memory_expression(ivl_expr_t net, unsigned ind) From 5d750b7779555aa4e643e0d9c0a498d075f0fff9 Mon Sep 17 00:00:00 2001 From: Stephen Williams Date: Wed, 3 Oct 2007 20:58:40 -0700 Subject: [PATCH 2/5] Optomize runtime using immediate compare Implement compare-immediate instructions and generate code to use these new instructions to improve runtime performance. Signed-off-by: Stephen Williams --- tgt-vvp/eval_expr.c | 89 +++++++++++++++++++++++++++++++++------------ vvp/codes.h | 2 + vvp/compile.cc | 2 + vvp/opcodes.txt | 6 +++ vvp/vthread.cc | 63 ++++++++++++++++++++++++++++++++ 5 files changed, 139 insertions(+), 23 deletions(-) diff --git a/tgt-vvp/eval_expr.c b/tgt-vvp/eval_expr.c index 46447f1ac..4627ecf77 100644 --- a/tgt-vvp/eval_expr.c +++ b/tgt-vvp/eval_expr.c @@ -36,6 +36,9 @@ int number_is_unknown(ivl_expr_t ex) const char*bits; unsigned idx; + if (ivl_expr_type(ex) == IVL_EX_ULONG) + return 0; + assert(ivl_expr_type(ex) == IVL_EX_NUMBER); bits = ivl_expr_bits(ex); @@ -66,6 +69,10 @@ int number_is_immediate(ivl_expr_t ex, unsigned lim_wid) if (bits[idx] != '0') return 0; + /* Negative numbers are not "immediate". */ + if (ivl_expr_signed(ex) && bits[ivl_expr_width(ex)-1]=='1') + return 0; + return 1; } @@ -290,13 +297,7 @@ static struct vector_info draw_binary_expr_eq(ivl_expr_t exp, return draw_binary_expr_eq_real(exp); } - if ((ivl_expr_type(re) == IVL_EX_ULONG) - && (0 == (ivl_expr_uvalue(re) & ~0xffff))) - return draw_eq_immediate(exp, ewid, le, re, stuff_ok_flag); - - if ((ivl_expr_type(re) == IVL_EX_NUMBER) - && (! number_is_unknown(re)) - && number_is_immediate(re, 16)) + if (number_is_immediate(re,16) && !number_is_unknown(re)) return draw_eq_immediate(exp, ewid, le, re, stuff_ok_flag); assert(ivl_expr_value(le) == IVL_VT_LOGIC @@ -683,42 +684,78 @@ static struct vector_info draw_binary_expr_le(ivl_expr_t exp, assert(ivl_expr_value(re) == IVL_VT_LOGIC || ivl_expr_value(re) == IVL_VT_BOOL); - lv = draw_eval_expr_wid(le, owid, STUFF_OK_XZ); - rv = draw_eval_expr_wid(re, owid, STUFF_OK_XZ); + lv.wid = 0; + rv.wid = 0; switch (ivl_expr_opcode(exp)) { case 'G': - assert(lv.wid == rv.wid); - fprintf(vvp_out, " %%cmp/%c %u, %u, %u;\n", s_flag, - rv.base, lv.base, lv.wid); + rv = draw_eval_expr_wid(re, owid, STUFF_OK_XZ); + if (number_is_immediate(le,16) && !number_is_unknown(le)) { + unsigned imm = get_number_immediate(le); + assert(imm >= 0); + fprintf(vvp_out, " %%cmpi/%c %u, %u, %u;\n", s_flag, + rv.base, imm, rv.wid); + } else { + lv = draw_eval_expr_wid(le, owid, STUFF_OK_XZ); + assert(lv.wid == rv.wid); + fprintf(vvp_out, " %%cmp/%c %u, %u, %u;\n", s_flag, + rv.base, lv.base, lv.wid); + } fprintf(vvp_out, " %%or 5, 4, 1;\n"); break; case 'L': - assert(lv.wid == rv.wid); - fprintf(vvp_out, " %%cmp/%c %u, %u, %u;\n", s_flag, - lv.base, rv.base, lv.wid); + lv = draw_eval_expr_wid(le, owid, STUFF_OK_XZ); + if (number_is_immediate(re,16) && !number_is_unknown(re)) { + unsigned imm = get_number_immediate(re); + assert(imm >= 0); + fprintf(vvp_out, " %%cmpi/%c %u, %u, %u;\n", s_flag, + lv.base, imm, lv.wid); + } else { + rv = draw_eval_expr_wid(re, owid, STUFF_OK_XZ); + assert(lv.wid == rv.wid); + fprintf(vvp_out, " %%cmp/%c %u, %u, %u;\n", s_flag, + lv.base, rv.base, lv.wid); + } fprintf(vvp_out, " %%or 5, 4, 1;\n"); break; case '<': - assert(lv.wid == rv.wid); - fprintf(vvp_out, " %%cmp/%c %u, %u, %u;\n", s_flag, - lv.base, rv.base, lv.wid); + lv = draw_eval_expr_wid(le, owid, STUFF_OK_XZ); + if (number_is_immediate(re,16) && !number_is_unknown(re)) { + unsigned imm = get_number_immediate(re); + assert(imm >= 0); + fprintf(vvp_out, " %%cmpi/%c %u, %u, %u;\n", s_flag, + lv.base, imm, lv.wid); + } else { + rv = draw_eval_expr_wid(re, owid, STUFF_OK_XZ); + assert(lv.wid == rv.wid); + fprintf(vvp_out, " %%cmp/%c %u, %u, %u;\n", s_flag, + lv.base, rv.base, lv.wid); + } break; case '>': - assert(lv.wid == rv.wid); - fprintf(vvp_out, " %%cmp/%c %u, %u, %u;\n", s_flag, - rv.base, lv.base, lv.wid); + rv = draw_eval_expr_wid(re, owid, STUFF_OK_XZ); + if (number_is_immediate(le,16) && !number_is_unknown(le)) { + unsigned imm = get_number_immediate(le); + assert(imm >= 0); + fprintf(vvp_out, " %%cmpi/%c %u, %u, %u;\n", s_flag, + rv.base, imm, rv.wid); + } else { + lv = draw_eval_expr_wid(le, owid, STUFF_OK_XZ); + assert(lv.wid == rv.wid); + fprintf(vvp_out, " %%cmp/%c %u, %u, %u;\n", s_flag, + rv.base, lv.base, lv.wid); + } break; default: assert(0); } - clr_vector(lv); - clr_vector(rv); + if (lv.wid > 0) clr_vector(lv); + if (rv.wid > 0) clr_vector(rv); if ((stuff_ok_flag&STUFF_OK_47) && (wid == 1)) { lv.base = 5; @@ -1365,6 +1402,12 @@ static struct vector_info draw_number_expr(ivl_expr_t exp, unsigned wid) load the constant bit values. */ res.base = allocate_vector(wid); + if ((!number_is_unknown(exp)) && number_is_immediate(exp, 16)) { + int val = get_number_immediate(exp); + fprintf(vvp_out, " %%movi %u, %d, %u;\n", res.base, val, wid); + return res; + } + idx = 0; while (idx < nwid) { unsigned cnt; diff --git a/vvp/codes.h b/vvp/codes.h index 7243202dc..c70093494 100644 --- a/vvp/codes.h +++ b/vvp/codes.h @@ -54,6 +54,7 @@ extern bool of_BLEND(vthread_t thr, vvp_code_t code); extern bool of_BREAKPOINT(vthread_t thr, vvp_code_t code); extern bool of_CASSIGN_LINK(vthread_t thr, vvp_code_t code); extern bool of_CASSIGN_V(vthread_t thr, vvp_code_t code); +extern bool of_CMPIS(vthread_t thr, vvp_code_t code); extern bool of_CMPIU(vthread_t thr, vvp_code_t code); extern bool of_CMPS(vthread_t thr, vvp_code_t code); extern bool of_CMPU(vthread_t thr, vvp_code_t code); @@ -103,6 +104,7 @@ extern bool of_MOD_S(vthread_t thr, vvp_code_t code); extern bool of_MOD_WR(vthread_t thr, vvp_code_t code); extern bool of_MOV(vthread_t thr, vvp_code_t code); extern bool of_MOV_WR(vthread_t thr, vvp_code_t code); +extern bool of_MOVI(vthread_t thr, vvp_code_t code); extern bool of_MUL(vthread_t thr, vvp_code_t code); extern bool of_MUL_WR(vthread_t thr, vvp_code_t code); extern bool of_MULI(vthread_t thr, vvp_code_t code); diff --git a/vvp/compile.cc b/vvp/compile.cc index 9a4dcb9fa..505c41d37 100644 --- a/vvp/compile.cc +++ b/vvp/compile.cc @@ -124,6 +124,7 @@ const static struct opcode_table_s opcode_table[] = { { "%cmp/wu", of_CMPWU, 2, {OA_BIT1, OA_BIT2, OA_NONE} }, { "%cmp/x", of_CMPX, 3, {OA_BIT1, OA_BIT2, OA_NUMBER} }, { "%cmp/z", of_CMPZ, 3, {OA_BIT1, OA_BIT2, OA_NUMBER} }, + { "%cmpi/s", of_CMPIS, 3, {OA_BIT1, OA_BIT2, OA_NUMBER} }, { "%cmpi/u", of_CMPIU, 3, {OA_BIT1, OA_BIT2, OA_NUMBER} }, { "%cvt/ir", of_CVT_IR, 2, {OA_BIT1, OA_BIT2, OA_NONE} }, { "%cvt/ri", of_CVT_RI, 2, {OA_BIT1, OA_BIT2, OA_NONE} }, @@ -164,6 +165,7 @@ const static struct opcode_table_s opcode_table[] = { { "%mod/wr", of_MOD_WR, 2, {OA_BIT1, OA_BIT2, OA_NONE} }, { "%mov", of_MOV, 3, {OA_BIT1, OA_BIT2, OA_NUMBER} }, { "%mov/wr", of_MOV_WR, 2, {OA_BIT1, OA_BIT2, OA_NONE} }, + { "%movi", of_MOVI, 3, {OA_BIT1, OA_BIT2, OA_NUMBER} }, { "%mul", of_MUL, 3, {OA_BIT1, OA_BIT2, OA_NUMBER} }, { "%mul/wr", of_MUL_WR, 2, {OA_BIT1, OA_BIT2, OA_NONE} }, { "%muli", of_MULI, 3, {OA_BIT1, OA_BIT2, OA_NUMBER} }, diff --git a/vvp/opcodes.txt b/vvp/opcodes.txt index bb2d5d91d..74a64f21b 100644 --- a/vvp/opcodes.txt +++ b/vvp/opcodes.txt @@ -189,6 +189,12 @@ The %cmp/u and %cmp/s differ only in the handling of the lt bit. The compare. In either case, if either operand contains x or z, then lt bit gets the x value. +* %cmpi/s , , +* %cmpi/u , , + +These instructions are similar to the %cmp instructions above, except +that the right hand operand is an immediate value. This is a positive +number that the vector is compared with. * %cmp/wr , diff --git a/vvp/vthread.cc b/vvp/vthread.cc index a7fddbc43..1e8707684 100644 --- a/vvp/vthread.cc +++ b/vvp/vthread.cc @@ -891,6 +891,55 @@ bool of_CMPS(vthread_t thr, vvp_code_t cp) return true; } +bool of_CMPIS(vthread_t thr, vvp_code_t cp) +{ + vvp_bit4_t eq = BIT4_1; + vvp_bit4_t eeq = BIT4_1; + vvp_bit4_t lt = BIT4_0; + + unsigned idx1 = cp->bit_idx[0]; + unsigned imm = cp->bit_idx[1]; + + const unsigned end1 = (idx1 < 4)? idx1 : idx1 + cp->number - 1; + thr_check_addr(thr, end1); + const vvp_bit4_t sig1 = thr_get_bit(thr, end1); + + for (unsigned idx = 0 ; idx < cp->number ; idx += 1) { + vvp_bit4_t lv = thr_get_bit(thr, idx1); + vvp_bit4_t rv = (imm & 1)? BIT4_1 : BIT4_0; + imm >>= 1; + + if (lv > rv) { + lt = BIT4_0; + eeq = BIT4_0; + } else if (lv < rv) { + lt = BIT4_1; + eeq = BIT4_0; + } + if (eq != BIT4_X) { + if ((lv == BIT4_0) && (rv != BIT4_0)) + eq = BIT4_0; + if ((lv == BIT4_1) && (rv != BIT4_1)) + eq = BIT4_0; + if (bit4_is_xz(lv) || bit4_is_xz(rv)) + eq = BIT4_X; + } + + if (idx1 >= 4) idx1 += 1; + } + + if (eq == BIT4_X) + lt = BIT4_X; + else if (sig1 == BIT4_1) + lt = BIT4_1; + + thr_put_bit(thr, 4, eq); + thr_put_bit(thr, 5, lt); + thr_put_bit(thr, 6, eeq); + + return true; +} + bool of_CMPIU(vthread_t thr, vvp_code_t cp) { vvp_bit4_t eq = BIT4_1; @@ -2531,6 +2580,20 @@ bool of_MOV_WR(vthread_t thr, vvp_code_t cp) return true; } +bool of_MOVI(vthread_t thr, vvp_code_t cp) +{ + unsigned dst = cp->bit_idx[0]; + unsigned val = cp->bit_idx[1]; + unsigned wid = cp->number; + + thr_check_addr(thr, dst+wid); + + for (unsigned idx = 0 ; idx < wid ; idx += 1, val >>= 1) + thr->bits4.set_bit(dst+idx, (val&1)? BIT4_1 : BIT4_0); + + return true; +} + bool of_MUL(vthread_t thr, vvp_code_t cp) { assert(cp->bit_idx[0] >= 4); From acdbe274f994d32ab26e4b94f14aaae748c8ae65 Mon Sep 17 00:00:00 2001 From: Stephen Williams Date: Wed, 3 Oct 2007 22:26:42 -0700 Subject: [PATCH 3/5] Fix signed ocmpare of negative numbers. signed compare in proceedural code was comparing the absolute value if both operands were negative. Wrong! Signed-off-by: Stephen Williams --- vvp/vthread.cc | 6 ------ 1 file changed, 6 deletions(-) diff --git a/vvp/vthread.cc b/vvp/vthread.cc index 1e8707684..d7aa74cd6 100644 --- a/vvp/vthread.cc +++ b/vvp/vthread.cc @@ -867,12 +867,6 @@ bool of_CMPS(vthread_t thr, vvp_code_t cp) /* Correct the lt bit to account for the sign of the parameters. */ if (lt != BIT4_X) { - - /* If both numbers are negative (and not equal) then - switch the direction of the lt. */ - if ((sig1 == BIT4_1) && (sig2 == BIT4_1) && (eq != BIT4_1)) - lt = ~lt; - /* If the first is negative and the last positive, then a < b for certain. */ if ((sig1 == BIT4_1) && (sig2 == BIT4_0)) From 08028177fece574438a89c80a827402bb3216842 Mon Sep 17 00:00:00 2001 From: Stephen Williams Date: Fri, 5 Oct 2007 20:31:51 -0700 Subject: [PATCH 4/5] Correct elaboration of network constants. Constant propagation incorrectly elided an entire constant net node if only the LSB of the driven vector was HiZ. This caused the entire vector to look like HiZ. Also, the code generator for writing the constant values missed bits. Signed-off-by: Stephen Williams --- cprop.cc | 93 ++++----------------------------------------- tgt-vvp/vvp_scope.c | 13 +------ 2 files changed, 9 insertions(+), 97 deletions(-) diff --git a/cprop.cc b/cprop.cc index cd29a1b4e..07677be17 100644 --- a/cprop.cc +++ b/cprop.cc @@ -16,16 +16,13 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ -#ifdef HAVE_CVS_IDENT -#ident "$Id: cprop.cc,v 1.56 2007/03/07 00:38:15 steve Exp $" -#endif # include "config.h" # include "netlist.h" # include "netmisc.h" # include "functor.h" -# include +# include "ivl_assert.h" @@ -846,15 +843,17 @@ struct cprop_dc_functor : public functor_t { void cprop_dc_functor::lpm_const(Design*des, NetConst*obj) { // 'bz constant values drive high impedance to whatever is - // connected to it. In other words, it is a noop. + // connected to it. In other words, it is a noop. But that is + // only true if *all* the bits of the vectors. { unsigned tmp = 0; - for (unsigned idx = 0 ; idx < obj->pin_count() ; idx += 1) + ivl_assert(*obj, obj->pin_count()==1); + for (unsigned idx = 0 ; idx < obj->width() ; idx += 1) { if (obj->value(idx) == verinum::Vz) { - obj->pin(idx).unlink(); tmp += 1; } + } - if (tmp == obj->pin_count()) { + if (tmp == obj->width()) { delete obj; return; } @@ -948,81 +947,3 @@ void cprop(Design*des) des->functor(&dc); } -/* - * $Log: cprop.cc,v $ - * Revision 1.56 2007/03/07 00:38:15 steve - * Lint fixes. - * - * Revision 1.55 2006/05/24 04:32:57 steve - * Fix handling of ternary-to-bufif0 constant propagation. - * - * Revision 1.54 2005/07/15 19:22:52 steve - * bufif enable is LOGIC. - * - * Revision 1.53 2005/05/15 04:44:30 steve - * Disable obsolete logic constant fixup code. - * - * Revision 1.52 2005/04/24 23:44:01 steve - * Update DFF support to new data flow. - * - * Revision 1.51 2005/02/12 22:52:45 steve - * Fix copyright notice. - * - * Revision 1.50 2005/02/12 06:25:40 steve - * Restructure NetMux devices to pass vectors. - * Generate NetMux devices from ternary expressions, - * Reduce NetMux devices to bufif when appropriate. - * - * Revision 1.49 2005/01/16 04:20:32 steve - * Implement LPM_COMPARE nodes as two-input vector functors. - * - * Revision 1.48 2004/12/11 02:31:25 steve - * Rework of internals to carry vectors through nexus instead - * of single bits. Make the ivl, tgt-vvp and vvp initial changes - * down this path. - * - * Revision 1.47 2004/02/20 18:53:34 steve - * Addtrbute keys are perm_strings. - * - * Revision 1.46 2003/11/08 17:53:34 steve - * Do not remove constants accessible to VPI. - * - * Revision 1.45 2003/10/31 02:40:06 steve - * Donot elide FF that has set or clr connections. - * - * Revision 1.44 2003/04/25 05:06:32 steve - * Handle X values in constant == nets. - * - * Revision 1.43 2003/03/06 00:28:41 steve - * All NetObj objects have lex_string base names. - * - * Revision 1.42 2003/02/26 01:29:24 steve - * LPM objects store only their base names. - * - * Revision 1.41 2003/01/30 16:23:07 steve - * Spelling fixes. - * - * Revision 1.40 2003/01/27 05:09:17 steve - * Spelling fixes. - * - * Revision 1.39 2002/08/20 04:12:22 steve - * Copy gate delays when doing gate delay substitutions. - * - * Revision 1.38 2002/08/12 01:34:58 steve - * conditional ident string using autoconfig. - * - * Revision 1.37 2002/06/25 01:33:22 steve - * Cache calculated driven value. - * - * Revision 1.36 2002/06/24 01:49:38 steve - * Make link_drive_constant cache its results in - * the Nexus, to improve cprop performance. - * - * Revision 1.35 2002/05/26 01:39:02 steve - * Carry Verilog 2001 attributes with processes, - * all the way through to the ivl_target API. - * - * Divide signal reference counts between rval - * and lval references. - */ - diff --git a/tgt-vvp/vvp_scope.c b/tgt-vvp/vvp_scope.c index 79036b54b..026c70816 100644 --- a/tgt-vvp/vvp_scope.c +++ b/tgt-vvp/vvp_scope.c @@ -412,17 +412,8 @@ static char* draw_C4_to_string(ivl_net_const_t cptr) dp += strlen(dp); for (idx = 0 ; idx < ivl_const_width(cptr) ; idx += 1) { - switch (bits[ivl_const_width(cptr)-idx-1]) { - case '0': - *dp++ = '0'; - break; - case '1': - *dp++ = '1'; - break; - default: - *dp++ = bits[idx]; - break; - } + char bitchar = bits[ivl_const_width(cptr)-idx-1]; + *dp++ = bitchar; assert((dp - result) < result_len); } From c7edace243cd5bb7f7a68616a4e393aa193c19ae Mon Sep 17 00:00:00 2001 From: Stephen Williams Date: Mon, 8 Oct 2007 19:58:49 -0700 Subject: [PATCH 5/5] Unsized integers have minimum size Fix the handling of expressions that have unsized integers and are in self determined context. Unsized integers are generally assumed to have at least 32bits. Signed-off-by: Stephen Williams --- compiler.h | 71 ++++------------------------------------------------ elab_expr.cc | 5 ++++ net_expr.cc | 11 ++++++-- 3 files changed, 19 insertions(+), 68 deletions(-) diff --git a/compiler.h b/compiler.h index d9bbd27ec..f8e791b60 100644 --- a/compiler.h +++ b/compiler.h @@ -18,9 +18,6 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ -#ifdef HAVE_CVS_IDENT -#ident "$Id: compiler.h,v 1.33 2007/04/19 02:52:53 steve Exp $" -#endif # include # include @@ -32,7 +29,11 @@ */ -/* The integer_width is the width of integer variables. */ +/* + * The integer_width is the width of integer variables. This is also + * the minimum width of unsized integers when they are found in + * self-determined contexts. + */ extern unsigned integer_width; /* The TIME_WIDTH is the width of time variables. */ @@ -154,66 +155,4 @@ struct sfunc_return_type { extern const struct sfunc_return_type* lookup_sys_func(const char*name); extern int load_sys_func_table(const char*path); -/* - * $Log: compiler.h,v $ - * Revision 1.33 2007/04/19 02:52:53 steve - * Add support for -v flag in command file. - * - * Revision 1.32 2007/03/07 04:24:59 steve - * Make integer width controllable. - * - * Revision 1.31 2006/09/28 04:35:18 steve - * Support selective control of specify and xtypes features. - * - * Revision 1.30 2005/07/11 16:56:50 steve - * Remove NetVariable and ivl_variable_t structures. - * - * Revision 1.29 2005/07/07 16:22:49 steve - * Generalize signals to carry types. - * - * Revision 1.28 2005/06/28 04:25:55 steve - * Remove reference to SystemVerilog. - * - * Revision 1.27 2005/04/24 23:44:01 steve - * Update DFF support to new data flow. - * - * Revision 1.26 2004/10/04 01:10:52 steve - * Clean up spurious trailing white space. - * - * Revision 1.25 2004/09/25 01:58:44 steve - * Add a debug_elaborate flag - * - * Revision 1.24 2004/09/10 23:51:42 steve - * Fix the evaluation of constant ternary expressions. - * - * Revision 1.23 2004/09/05 17:44:41 steve - * Add support for module instance arrays. - * - * Revision 1.22 2004/03/10 04:51:24 steve - * Add support for system function table files. - * - * Revision 1.21 2004/03/09 04:29:42 steve - * Separate out the lookup_sys_func table, for eventual - * support for function type tables. - * - * Remove ipal compile flags. - * - * Revision 1.20 2004/02/18 17:11:54 steve - * Use perm_strings for named langiage items. - * - * Revision 1.19 2003/11/13 05:55:33 steve - * Move the DLL= flag to target config files. - * - * Revision 1.18 2003/11/08 20:06:21 steve - * Spelling fixes in comments. - * - * Revision 1.17 2003/09/25 00:25:14 steve - * Summary list of missing modules. - * - * Revision 1.16 2003/03/01 06:25:30 steve - * Add the lex_strings string handler, and put - * scope names and system task/function names - * into this table. Also, permallocate event - * names from the beginning. - */ #endif diff --git a/elab_expr.cc b/elab_expr.cc index 5a9e8f295..df84cbcd4 100644 --- a/elab_expr.cc +++ b/elab_expr.cc @@ -146,6 +146,11 @@ NetEBinary* PEBinary::elaborate_expr_base_(Design*des, { bool flag; + if (debug_elaborate) { + cerr << get_line() << ": debug: elaborate expression " + << *this << " expr_wid=" << expr_wid << endl; + } + NetEBinary*tmp; switch (op_) { diff --git a/net_expr.cc b/net_expr.cc index 8c7be82a5..ee80713d8 100644 --- a/net_expr.cc +++ b/net_expr.cc @@ -45,14 +45,19 @@ NetEBAdd::NetEBAdd(char op, NetExpr*l, NetExpr*r, bool lossless_flag) one. This expands the expression to account for the largest possible result. + Remember to handle the special case of an unsized constant, + which we define to be at least "integer_width" bits. + The set_width applied to a constant value will only truncate the constant so far as it can still hold its logical value, so this is safe to do. */ if ( (tmp = dynamic_cast(r)) && (! tmp->has_width()) - && (tmp->expr_width() > l->expr_width()) ) { + && (tmp->expr_width() > l->expr_width() || integer_width > l->expr_width()) ) { unsigned target_width = l->expr_width() + 1; + if (target_width < integer_width) + target_width = integer_width; r->set_width(target_width); /* Note: This constant value will not gain a defined @@ -61,9 +66,11 @@ NetEBAdd::NetEBAdd(char op, NetExpr*l, NetExpr*r, bool lossless_flag) } else if ( (tmp = dynamic_cast(l)) && (! tmp->has_width()) - && (tmp->expr_width() > r->expr_width()) ) { + && (tmp->expr_width() > r->expr_width() || integer_width > r->expr_width()) ) { unsigned target_width = r->expr_width() + 1; + if (target_width < integer_width) + target_width = integer_width; l->set_width(target_width); /* Note: This constant value will not gain a defined