From cdfe3a828996dac2125b75ae6d0673e6c1a7ec6d Mon Sep 17 00:00:00 2001 From: Stephen Williams Date: Mon, 14 Jan 2008 09:47:48 -0800 Subject: [PATCH 1/8] Use inttypes.h to get uint64_t print format string Code generators should not include _pli_types.h to get standard int types and strings. Use the inttypes.h header file instead. --- tgt-vvp/configure.in | 2 +- tgt-vvp/eval_bool.c | 12 ++++++++++-- 2 files changed, 11 insertions(+), 3 deletions(-) diff --git a/tgt-vvp/configure.in b/tgt-vvp/configure.in index 62e06d9f1..eef3ee18f 100644 --- a/tgt-vvp/configure.in +++ b/tgt-vvp/configure.in @@ -13,7 +13,7 @@ AC_CANONICAL_HOST # Combined check for Microsoft-related bogosities; sets WIN32 if found AX_WIN32 -AC_CHECK_HEADERS(malloc.h stdint.h) +AC_CHECK_HEADERS(malloc.h stdint.h inttypes.h) # may modify CPPFLAGS and CFLAGS AX_CPP_PRECOMP diff --git a/tgt-vvp/eval_bool.c b/tgt-vvp/eval_bool.c index 882170d6e..07c61d682 100644 --- a/tgt-vvp/eval_bool.c +++ b/tgt-vvp/eval_bool.c @@ -20,7 +20,6 @@ /* * This file includes functions for evaluating REAL expressions. */ -# include "_pli_types.h" /* To get the UINT64 format */ # include "vvp_config.h" # include "vvp_priv.h" # include @@ -31,6 +30,15 @@ #ifdef HAVE_STDINT_H # include #endif + +#ifdef HAVE_INTTYPES_H +# ifndef __STDC_FORMAT_MACROS +# define __STDC_FORMAT_MACROS 1 +# endif +# include +#else +#endif + # include # include @@ -64,7 +72,7 @@ static int draw_number_bool64(ivl_expr_t exp) } res = allocate_word(); - fprintf(vvp_out, " %%ix/load %d, %" PLI_UINT64_FMT ";\n", res, val); + fprintf(vvp_out, " %%ix/load %d, %" PRIu64 ";\n", res, val); return res; } From 7ff342f4dacb4f4d246b748f28e8dacf0531e5db Mon Sep 17 00:00:00 2001 From: Cary R Date: Mon, 14 Jan 2008 09:27:02 -0800 Subject: [PATCH 2/8] Fix type warning in tgt-vvp/eval_expr.c In a previous patch I missed this type inconsistency. --- tgt-vvp/eval_expr.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tgt-vvp/eval_expr.c b/tgt-vvp/eval_expr.c index 105da8b59..1de168fc2 100644 --- a/tgt-vvp/eval_expr.c +++ b/tgt-vvp/eval_expr.c @@ -1771,7 +1771,7 @@ static void draw_signal_dest(ivl_expr_t exp, struct vector_info res, /* If this is a REG (a variable) then I can do a vector read. */ fprintf(vvp_out, " %%ix/load 0, %lu;\n", immediate); - fprintf(vvp_out, " %%ix/load 2, %lu;\n", res.wid); + fprintf(vvp_out, " %%ix/load 2, %u;\n", res.wid); fprintf(vvp_out, " %%load/vp0 %u, v%p_%u, %u;\n", res.base, sig, word, swid); swid = res.wid; From e46f8220f3775c119b61d71154694bebfc71147d Mon Sep 17 00:00:00 2001 From: Cary R Date: Mon, 14 Jan 2008 15:57:01 -0800 Subject: [PATCH 3/8] Evaluate non-immediate signal selection. This patch adds code to treat non-immediate signal selection the same as the default logic evaluation --- tgt-vvp/eval_expr.c | 20 ++++++++++++++------ 1 file changed, 14 insertions(+), 6 deletions(-) diff --git a/tgt-vvp/eval_expr.c b/tgt-vvp/eval_expr.c index 1de168fc2..7d9c73ff5 100644 --- a/tgt-vvp/eval_expr.c +++ b/tgt-vvp/eval_expr.c @@ -128,12 +128,12 @@ static void eval_logic_into_integer(ivl_expr_t expr, unsigned ix) assert(0); } - fprintf(vvp_out, " %%ix/load %u, %u;\n", ix, value); + fprintf(vvp_out, " %%ix/load %u, %u;\n", ix, value); break; } case IVL_EX_ULONG: - fprintf(vvp_out, " %%ix/load %u, %lu;\n", ix, ivl_expr_uvalue(expr)); + fprintf(vvp_out, " %%ix/load %u, %lu;\n", ix, ivl_expr_uvalue(expr)); break; case IVL_EX_SIGNAL: { @@ -141,17 +141,25 @@ static void eval_logic_into_integer(ivl_expr_t expr, unsigned ix) unsigned word = 0; if (ivl_signal_array_count(sig) > 1) { ivl_expr_t ixe = ivl_expr_oper1(expr); - assert(number_is_immediate(ixe, 8*sizeof(unsigned long))); - word = get_number_immediate(ixe); + if (number_is_immediate(ixe, 8*sizeof(unsigned long))) + word = get_number_immediate(ixe); + else { + struct vector_info rv; + rv = draw_eval_expr(expr, 0); + fprintf(vvp_out, " %%ix/get %u, %u, %u;\n", + ix, rv.base, rv.wid); + clr_vector(rv); + break; + } } - fprintf(vvp_out, " %%ix/getv %u, v%p_%u;\n", ix, sig, word); + fprintf(vvp_out, " %%ix/getv %u, v%p_%u;\n", ix, sig, word); break; } default: { struct vector_info rv; rv = draw_eval_expr(expr, 0); - fprintf(vvp_out, " %%ix/get %u, %u, %u;\n", + fprintf(vvp_out, " %%ix/get %u, %u, %u;\n", ix, rv.base, rv.wid); clr_vector(rv); break; From 59ee700634585d93211b0facf0bb1d9bda708d4e Mon Sep 17 00:00:00 2001 From: Stephen Williams Date: Tue, 15 Jan 2008 19:39:53 -0800 Subject: [PATCH 4/8] Net arrays that are addressed are not dangling The nodangle functor tries to delete NetNet objects that are not used. But NetNet objects that are addressed by a NetArrayDq should never be dangling. So make sure the NetArrayDq marks the target NetNet correctly. --- design_dump.cc | 1 + netlist.cc | 3 +++ 2 files changed, 4 insertions(+) diff --git a/design_dump.cc b/design_dump.cc index b9ce6ad04..d0213725b 100644 --- a/design_dump.cc +++ b/design_dump.cc @@ -1217,6 +1217,7 @@ void Design::dump(ostream&o) const if (nodes_) { NetNode*cur = nodes_->node_next_; do { + assert(cur); cur->dump_node(o, 0); cur = cur->node_next_; } while (cur != nodes_->node_next_); diff --git a/netlist.cc b/netlist.cc index 00c1dae11..a403a3f1b 100644 --- a/netlist.cc +++ b/netlist.cc @@ -1132,6 +1132,9 @@ NetArrayDq::NetArrayDq(NetScope*s, perm_string n, NetNet*mem, unsigned awid) pin(0).set_name(perm_string::literal("Result"), 0); pin(1).set_dir(Link::INPUT); pin(1).set_name(perm_string::literal("Address"), 0); + // Increment the expression reference count for the target + // memory so that it is not deleted underneath me. + mem->incr_eref(); } NetArrayDq::~NetArrayDq() From 1ff31db2cce27c47e5296f023f89b8a5d5f47191 Mon Sep 17 00:00:00 2001 From: Cary R Date: Tue, 15 Jan 2008 10:54:04 -0800 Subject: [PATCH 5/8] Add real comparisons in continuous assignments. This patch adds real comparisons in continuous assignments. It also converts bit based constants to real values when needed by the comparisons. --- elab_net.cc | 98 ++++++++++++++++++++++---------- tgt-vvp/vvp_scope.c | 32 +++++++++-- verinum.cc | 132 +++++++++++--------------------------------- verinum.h | 117 +-------------------------------------- vvp/arith.cc | 64 +++++++++++++++++++++ vvp/arith.h | 28 ++++++++++ vvp/compile.cc | 48 ++++++++++++++++ vvp/compile.h | 4 ++ vvp/lexor.lex | 4 ++ vvp/parse.y | 25 ++++++++- 10 files changed, 301 insertions(+), 251 deletions(-) diff --git a/elab_net.cc b/elab_net.cc index ce8519bd2..0f5b1f12e 100644 --- a/elab_net.cc +++ b/elab_net.cc @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999-2007 Stephen Williams (steve@icarus.com) + * Copyright (c) 1999-2008 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 @@ -500,16 +500,24 @@ NetNet* PEBinary::elaborate_net_cmp_(Design*des, NetScope*scope, return 0; } + unsigned operand_width; + bool real_arg = false; + if (lexp->expr_type() == IVL_VT_REAL || + rexp->expr_type() == IVL_VT_REAL) { + operand_width = 1; + real_arg = true; + } else { /* Choose the operand width to be the width of the widest self-determined operand. */ - unsigned operand_width = lexp->expr_width(); - if (rexp->expr_width() > operand_width) - operand_width = rexp->expr_width(); + operand_width = lexp->expr_width(); + if (rexp->expr_width() > operand_width) + operand_width = rexp->expr_width(); - lexp->set_width(operand_width); - lexp = pad_to_width(lexp, operand_width); - rexp->set_width(operand_width); - rexp = pad_to_width(rexp, operand_width); + lexp->set_width(operand_width); + lexp = pad_to_width(lexp, operand_width); + rexp->set_width(operand_width); + rexp = pad_to_width(rexp, operand_width); + } NetNet*lsig = 0; NetNet*rsig = 0; @@ -530,12 +538,18 @@ NetNet* PEBinary::elaborate_net_cmp_(Design*des, NetScope*scope, delete lexp; lexp = 0; - NetNet*osig = compare_eq_constant(des, scope, - lsig, tmp, op_, - rise, fall, decay); - if (osig != 0) { - delete rexp; - return osig; + if (real_arg) { + verireal vrl(tmp->value().as_double()); + NetECReal rlval(vrl); + rsig = rlval.synthesize(des); + } else { + NetNet*osig = compare_eq_constant(des, scope, + lsig, tmp, op_, + rise, fall, decay); + if (osig != 0) { + delete rexp; + return osig; + } } } @@ -545,12 +559,18 @@ NetNet* PEBinary::elaborate_net_cmp_(Design*des, NetScope*scope, assert(rsig); delete rexp; - NetNet*osig = compare_eq_constant(des, scope, - rsig, tmp, op_, - rise, fall, decay); - if (osig != 0) { - delete lexp; - return osig; + if (real_arg) { + verireal vrl(tmp->value().as_double()); + NetECReal rlval(vrl); + lsig = rlval.synthesize(des); + } else { + NetNet*osig = compare_eq_constant(des, scope, + rsig, tmp, op_, + rise, fall, decay); + if (osig != 0) { + delete lexp; + return osig; + } } } @@ -572,11 +592,18 @@ NetNet* PEBinary::elaborate_net_cmp_(Design*des, NetScope*scope, /* Operands of binary compare need to be padded to equal size. Figure the pad bit needed to extend the narrowest vector. */ - if (lsig->vector_width() < dwidth) + if (!real_arg && lsig->vector_width() < dwidth) lsig = pad_to_width(des, lsig, dwidth); - if (rsig->vector_width() < dwidth) + if (!real_arg && rsig->vector_width() < dwidth) rsig = pad_to_width(des, rsig, dwidth); + /* For now the runtime cannot convert a vec4 to a real value. */ + if (real_arg && (rsig->data_type() != IVL_VT_REAL || + lsig->data_type() != IVL_VT_REAL)) { + cerr << get_fileline() << ": sorry: comparing bit based signals " + "and real values is not supported." << endl; + return 0; + } NetNet*osig = new NetNet(scope, scope->local_symbol(), NetNet::WIRE); osig->data_type(IVL_VT_LOGIC); @@ -619,6 +646,11 @@ NetNet* PEBinary::elaborate_net_cmp_(Design*des, NetScope*scope, } case 'E': // Case equals (===) + if (real_arg) { + cerr << get_fileline() << ": error: Case equality may not " + "have real operands." << endl; + return 0; + } gate = new NetCaseCmp(scope, scope->local_symbol(), dwidth, true); connect(gate->pin(0), osig->pin(0)); connect(gate->pin(1), lsig->pin(0)); @@ -626,6 +658,11 @@ NetNet* PEBinary::elaborate_net_cmp_(Design*des, NetScope*scope, break; case 'N': // Case equals (!==) + if (real_arg) { + cerr << get_fileline() << ": error: Case inequality may not " + "have real operands." << endl; + return 0; + } gate = new NetCaseCmp(scope, scope->local_symbol(), dwidth, false); connect(gate->pin(0), osig->pin(0)); connect(gate->pin(1), lsig->pin(0)); @@ -636,7 +673,7 @@ NetNet* PEBinary::elaborate_net_cmp_(Design*des, NetScope*scope, /* Handle the special case of single bit compare with a single XNOR gate. This is easy and direct. */ - if (dwidth == 1) { + if (dwidth == 1 && !real_arg){ gate = new NetLogic(scope, scope->local_symbol(), 3, NetLogic::XNOR, 1); connect(gate->pin(0), osig->pin(0)); @@ -664,7 +701,8 @@ NetNet* PEBinary::elaborate_net_cmp_(Design*des, NetScope*scope, /* Handle the special case of single bit compare with a single XOR gate. This is easy and direct. */ - if (dwidth == 1) { + if (dwidth == 1 && lsig->data_type() != IVL_VT_REAL && + rsig->data_type() != IVL_VT_REAL) { gate = new NetLogic(scope, scope->local_symbol(), 3, NetLogic::XOR, 1); connect(gate->pin(0), osig->pin(0)); @@ -1124,7 +1162,7 @@ NetNet* PEBinary::elaborate_net_shift_(Design*des, NetScope*scope, connect(cc->pin(0), osig->pin(0)); /* Make the part select of the left expression and - connect it to the lsb or msb of the concatenation, + connect it to the LSB or MSB of the concatenation, depending on the direction of the shift. */ NetPartSelect*part; @@ -1439,7 +1477,7 @@ NetNet* PEConcat::elaborate_net(Design*des, NetScope*scope, delete etmp; if (repeat == 0) { - cerr << get_fileline() << ": error: Concatenation epeat " + cerr << get_fileline() << ": error: Concatenation repeat " "may not be 0." << endl; des->errors += 1; @@ -1448,7 +1486,7 @@ NetNet* PEConcat::elaborate_net(Design*des, NetScope*scope, } if (debug_elaborate) { - cerr << get_fileline() <<": debug: PEConcat concat repeat=" + cerr << get_fileline() <<": debug: PEConcat concatenation repeat=" << repeat << "." << endl; } @@ -1861,7 +1899,7 @@ NetNet* PEIdent::elaborate_net_net_idx_up_(Design*des, NetScope*scope, // convert from -: to +: form. if (down_flag) lsv -= (wid-1); - // If the part select convers exactly the entire + // If the part select covers exactly the entire // vector, then do not bother with it. Return the // signal itself. if (sig->sb_to_idx(lsv) == 0 && wid == sig->vector_width()) @@ -2576,7 +2614,7 @@ NetNet* PEIdent::elaborate_port(Design*des, NetScope*scope) const return 0; /* This should not happen. A PWire can only become - PIMPLICIT if this is a udp reg port, and the make_udp + PIMPLICIT if this is a UDP reg port, and the make_udp function should turn it into an output.... I think. */ case NetNet::PIMPLICIT: @@ -2795,7 +2833,7 @@ NetNet* PETernary::elaborate_net(Design*des, NetScope*scope, if (tru_sig->data_type() != fal_sig->data_type()) { cerr << get_fileline() << ": error: True and False clauses of" - << " ternary expression have differnt types." << endl; + << " ternary expression have different types." << endl; cerr << get_fileline() << ": : True clause is " << tru_sig->data_type() << ", false clause is " << fal_sig->data_type() << "." << endl; diff --git a/tgt-vvp/vvp_scope.c b/tgt-vvp/vvp_scope.c index ae6cf3ed6..f3287b23f 100644 --- a/tgt-vvp/vvp_scope.c +++ b/tgt-vvp/vvp_scope.c @@ -1606,7 +1606,7 @@ static void draw_lpm_add(ivl_lpm_t net) ivl_variable_type_t dtb = data_type_of_nexus(ivl_lpm_data(net,1)); ivl_variable_type_t dto = IVL_VT_LOGIC; - if (dta == IVL_VT_REAL && dtb == IVL_VT_REAL) + if (dta == IVL_VT_REAL || dtb == IVL_VT_REAL) dto = IVL_VT_REAL; width = ivl_lpm_width(net); @@ -1676,29 +1676,51 @@ static void draw_lpm_cmp(ivl_lpm_t net) unsigned width; const char*type = ""; const char*signed_string = ivl_lpm_signed(net)? ".s" : ""; + ivl_variable_type_t dta = data_type_of_nexus(ivl_lpm_data(net,0)); + ivl_variable_type_t dtb = data_type_of_nexus(ivl_lpm_data(net,1)); + ivl_variable_type_t dtc = IVL_VT_LOGIC; + + if (dta == IVL_VT_REAL || dtb == IVL_VT_REAL) + dtc = IVL_VT_REAL; width = ivl_lpm_width(net); switch (ivl_lpm_type(net)) { case IVL_LPM_CMP_EEQ: + assert(dtc != IVL_VT_REAL); /* Should never get here! */ type = "eeq"; signed_string = ""; break; case IVL_LPM_CMP_EQ: - type = "eq"; + if (dtc == IVL_VT_REAL) + type = "eq.r"; + else + type = "eq"; signed_string = ""; break; case IVL_LPM_CMP_GE: - type = "ge"; + if (dtc == IVL_VT_REAL) { + type = "ge.r"; + signed_string = ""; + } else + type = "ge"; break; case IVL_LPM_CMP_GT: - type = "gt"; + if (dtc == IVL_VT_REAL) { + type = "gt.r"; + signed_string = ""; + } else + type = "gt"; break; case IVL_LPM_CMP_NE: - type = "ne"; + if (dtc == IVL_VT_REAL) + type = "ne.r"; + else + type = "ne"; signed_string = ""; break; case IVL_LPM_CMP_NEE: + assert(dtc != IVL_VT_REAL); /* Should never get here! */ type = "nee"; signed_string = ""; break; diff --git a/verinum.cc b/verinum.cc index 7b26a3322..98ecae9d6 100644 --- a/verinum.cc +++ b/verinum.cc @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998-2000 Stephen Williams (steve@icarus.com) + * Copyright (c) 1998-2008 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,15 +16,15 @@ * 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: verinum.cc,v 1.52 2007/02/25 23:08:24 steve Exp $" -#endif # include "config.h" # include "verinum.h" # include # include +# include // Needed to get pow for as_double(). + +static verinum::V add_with_carry(verinum::V l, verinum::V r, verinum::V&c); verinum::verinum() : bits_(0), nbits_(0), has_len_(false), has_sign_(false), string_flag_(false) @@ -332,6 +332,35 @@ signed long verinum::as_long() const return val; } +double verinum::as_double() const +{ + if (nbits_ == 0) return 0.0; + + /* Do we have a signed value? */ + bool signed_flag = false; + if (bits_[nbits_-1] == V1) { + signed_flag = true; + } + + double val = 0.0; + if (signed_flag) { + V carry = V1; + for (unsigned idx = 0; idx < nbits_; idx += 1) { + V sum = add_with_carry(~bits_[idx], V0, carry); + if (sum == V1) + val += pow(2.0, (double)idx); + } + val *= -1.0; +// val = (double) as_long(); + } else { + for (unsigned idx = 0; idx < nbits_; idx += 1) { + if (bits_[idx] == V1) + val += pow(2.0, (double)idx); + } + } + return val; +} + string verinum::as_string() const { assert( nbits_%8 == 0 ); @@ -1158,98 +1187,3 @@ verinum::V operator ^ (verinum::V l, verinum::V r) return verinum::Vx; } -/* - * $Log: verinum.cc,v $ - * Revision 1.52 2007/02/25 23:08:24 steve - * Process Verilog escape sequences much earlier. - * - * Revision 1.51 2007/01/27 05:36:11 steve - * Fix padding of x when literal is sized and unsigned. - * - * Revision 1.50 2007/01/19 05:42:04 steve - * Fix calculation of verinum pow operation. - * - * Revision 1.49 2006/12/08 19:56:09 steve - * Handle very wide signed divide. - * - * Revision 1.48 2006/08/08 05:11:37 steve - * Handle 64bit delay constants. - * - * Revision 1.47 2006/07/31 03:50:17 steve - * Add support for power in constant expressions. - * - * Revision 1.46 2006/06/02 04:48:50 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.45 2006/06/01 03:54:51 steve - * Fix broken subtraction of small constants. - * - * Revision 1.44 2005/12/07 04:04:24 steve - * Allow constant concat expressions. - * - * Revision 1.43 2004/05/18 18:43:15 steve - * Handle null string as a single nul character. - * - * Revision 1.42 2004/02/17 06:52:55 steve - * Support unsigned divide of huge numbers. - * - * Revision 1.41 2003/10/26 04:54:56 steve - * Support constant evaluation of binary ^ operator. - * - * Revision 1.40 2003/05/25 03:01:19 steve - * Get length of trimed unsigned value right. - * - * Revision 1.39 2003/04/14 03:40:21 steve - * Make some effort to preserve bits while - * operating on constant values. - * - * Revision 1.38 2003/04/03 04:30:00 steve - * Prevent overrun comparing verinums to zero. - * - * Revision 1.37 2003/02/02 00:43:16 steve - * Fix conversion of signed numbes to long - * - * Revision 1.36 2003/01/30 16:23:08 steve - * Spelling fixes. - * - * Revision 1.35 2002/08/19 02:39:17 steve - * Support parameters with defined ranges. - * - * Revision 1.34 2002/08/12 01:35:01 steve - * conditional ident string using autoconfig. - * - * Revision 1.33 2002/04/27 23:26:24 steve - * Trim leading nulls from string forms. - * - * Revision 1.32 2002/04/27 04:48:43 steve - * Display string verinums as strings. - * - * Revision 1.31 2002/02/01 05:09:14 steve - * Propagate sign in unary minus. - * - * Revision 1.30 2001/12/31 00:02:33 steve - * Include s indicator in dump of signed numbers. - * - * Revision 1.29 2001/11/19 02:54:12 steve - * Handle division and modulus by zero while - * evaluating run-time constants. - * - * Revision 1.28 2001/11/06 06:11:55 steve - * Support more real arithmetic in delay constants. - * - * Revision 1.27 2001/07/25 03:10:50 steve - * Create a config.h.in file to hold all the config - * junk, and support gcc 3.0. (Stephan Boettcher) - * - * Revision 1.26 2001/02/09 05:44:23 steve - * support evaluation of constant < in expressions. - * - * Revision 1.25 2001/02/08 05:38:18 steve - * trim the length of unsized numbers. - * - * Revision 1.24 2001/02/07 21:47:13 steve - * Fix expression widths for rvalues and parameters (PR#131,132) - */ - diff --git a/verinum.h b/verinum.h index 047f110cd..4670e45c9 100644 --- a/verinum.h +++ b/verinum.h @@ -1,7 +1,7 @@ #ifndef __verinum_H #define __verinum_H /* - * Copyright (c) 1998 Stephen Williams (steve@icarus.com) + * Copyright (c) 1998-2008 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 @@ -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: verinum.h,v 1.33 2007/02/02 04:33:01 steve Exp $" -#endif # include @@ -93,6 +90,7 @@ class verinum { uint64_t as_ulong64() const; unsigned long as_ulong() const; signed long as_long() const; + double as_double() const; string as_string() const; private: @@ -158,115 +156,4 @@ extern verinum concat(const verinum&left, const verinum&right); /* Bitwise not returns the ones complement. */ extern verinum v_not(const verinum&left); -/* - * $Log: verinum.h,v $ - * Revision 1.33 2007/02/02 04:33:01 steve - * Use inttypes.h instead of stdint.h for portability. - * - * Revision 1.32 2006/08/08 05:11:37 steve - * Handle 64bit delay constants. - * - * Revision 1.31 2006/07/31 03:50:17 steve - * Add support for power in constant expressions. - * - * Revision 1.30 2006/06/02 04:48:50 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.29 2006/06/01 03:54:51 steve - * Fix broken subtraction of small constants. - * - * Revision 1.28 2005/12/07 04:04:24 steve - * Allow constant concat expressions. - * - * Revision 1.27 2005/06/14 19:13:43 steve - * gcc3/4 compile errors. - * - * Revision 1.26 2004/02/17 06:52:55 steve - * Support unsigned divide of huge numbers. - * - * Revision 1.25 2003/10/26 04:54:56 steve - * Support constant evaluation of binary ^ operator. - * - * Revision 1.24 2003/04/14 03:40:21 steve - * Make some effort to preserve bits while - * operating on constant values. - * - * Revision 1.23 2003/04/03 04:30:00 steve - * Prevent overrun comparing verinums to zero. - * - * Revision 1.22 2003/01/30 16:23:08 steve - * Spelling fixes. - * - * Revision 1.21 2003/01/30 04:23:25 steve - * include config.h to get iosfwd flags. - * - * Revision 1.20 2002/08/12 01:35:01 steve - * conditional ident string using autoconfig. - * - * Revision 1.19 2002/06/03 04:04:24 steve - * Add verinum != operator. - * - * Revision 1.18 2001/02/10 20:29:39 steve - * In the context of range declarations, use elab_and_eval instead - * of the less robust eval_const methods. - * - * Revision 1.17 2001/02/09 05:44:23 steve - * support evaluation of constant < in expressions. - * - * Revision 1.16 2001/02/07 02:46:31 steve - * Support constant evaluation of / and % (PR#124) - * - * Revision 1.15 2001/01/16 02:44:18 steve - * Use the iosfwd header if available. - * - * Revision 1.14 2001/01/02 03:23:40 steve - * Evaluate constant &, | and unary ~. - * - * Revision 1.13 2000/12/10 22:01:36 steve - * Support decimal constants in behavioral delays. - * - * Revision 1.12 2000/09/27 18:28:37 steve - * multiply in parameter expressions. - * - * Revision 1.11 2000/02/23 04:43:43 steve - * Some compilers do not accept the not symbol. - * - * Revision 1.10 2000/02/23 02:56:56 steve - * Macintosh compilers do not support ident. - * - * Revision 1.9 2000/01/07 03:45:49 steve - * Initial support for signed constants. - * - * Revision 1.8 1999/11/06 16:00:17 steve - * Put number constants into a static table. - * - * Revision 1.7 1999/10/22 23:57:53 steve - * do the <= in bits, not numbers. - * - * Revision 1.6 1999/10/10 23:29:37 steve - * Support evaluating + operator at compile time. - * - * Revision 1.5 1999/05/13 04:02:09 steve - * More precise handling of verinum bit lengths. - * - * Revision 1.4 1998/12/20 02:05:41 steve - * Function to calculate wire initial value. - * - * Revision 1.3 1998/11/11 00:01:51 steve - * Check net ranges in declarations. - * - * Revision 1.2 1998/11/09 18:55:35 steve - * Add procedural while loops, - * Parse procedural for loops, - * Add procedural wait statements, - * Add constant nodes, - * Add XNOR logic gate, - * Make vvm output look a bit prettier. - * - * Revision 1.1 1998/11/03 23:29:08 steve - * Introduce verilog to CVS. - * - */ #endif diff --git a/vvp/arith.cc b/vvp/arith.cc index 8c7b74b37..d3f0f379e 100644 --- a/vvp/arith.cc +++ b/vvp/arith.cc @@ -821,3 +821,67 @@ void vvp_arith_sub_real::recv_real(vvp_net_ptr_t ptr, double bit) vvp_send_real(ptr.ptr()->out, val); } +/* Real compare equal. */ +vvp_cmp_eq_real::vvp_cmp_eq_real() +{ +} + +void vvp_cmp_eq_real::recv_real(vvp_net_ptr_t ptr, const double bit) +{ + dispatch_operand_(ptr, bit); + + vvp_vector4_t res (1); + if (op_a_ == op_b_) res.set_bit(0, BIT4_1); + else res.set_bit(0, BIT4_0); + + vvp_send_vec4(ptr.ptr()->out, res); +} + +/* Real compare not equal. */ +vvp_cmp_ne_real::vvp_cmp_ne_real() +{ +} + +void vvp_cmp_ne_real::recv_real(vvp_net_ptr_t ptr, const double bit) +{ + dispatch_operand_(ptr, bit); + + vvp_vector4_t res (1); + if (op_a_ != op_b_) res.set_bit(0, BIT4_1); + else res.set_bit(0, BIT4_0); + + vvp_send_vec4(ptr.ptr()->out, res); +} + +/* Real compare greater than or equal. */ +vvp_cmp_ge_real::vvp_cmp_ge_real() +{ +} + +void vvp_cmp_ge_real::recv_real(vvp_net_ptr_t ptr, const double bit) +{ + dispatch_operand_(ptr, bit); + + vvp_vector4_t res (1); + if (op_a_ >= op_b_) res.set_bit(0, BIT4_1); + else res.set_bit(0, BIT4_0); + + vvp_send_vec4(ptr.ptr()->out, res); +} + +/* Real compare greater than. */ +vvp_cmp_gt_real::vvp_cmp_gt_real() +{ +} + +void vvp_cmp_gt_real::recv_real(vvp_net_ptr_t ptr, const double bit) +{ + dispatch_operand_(ptr, bit); + + vvp_vector4_t res (1); + if (op_a_ > op_b_) res.set_bit(0, BIT4_1); + else res.set_bit(0, BIT4_0); + + vvp_send_vec4(ptr.ptr()->out, res); +} + diff --git a/vvp/arith.h b/vvp/arith.h index ad16d7b10..5a6419676 100644 --- a/vvp/arith.h +++ b/vvp/arith.h @@ -247,4 +247,32 @@ class vvp_arith_sub_real : public vvp_arith_real_ { void recv_real(vvp_net_ptr_t ptr, double bit); }; +class vvp_cmp_eq_real : public vvp_arith_real_ { + + public: + explicit vvp_cmp_eq_real(); + void recv_real(vvp_net_ptr_t ptr, const double bit); +}; + +class vvp_cmp_ne_real : public vvp_arith_real_ { + + public: + explicit vvp_cmp_ne_real(); + void recv_real(vvp_net_ptr_t ptr, const double bit); +}; + +class vvp_cmp_ge_real : public vvp_arith_real_ { + + public: + explicit vvp_cmp_ge_real(); + void recv_real(vvp_net_ptr_t ptr, const double bit); +}; + +class vvp_cmp_gt_real : public vvp_arith_real_ { + + public: + explicit vvp_cmp_gt_real(); + void recv_real(vvp_net_ptr_t ptr, const double bit); +}; + #endif diff --git a/vvp/compile.cc b/vvp/compile.cc index 6c6320598..c4eb70030 100644 --- a/vvp/compile.cc +++ b/vvp/compile.cc @@ -1052,6 +1052,18 @@ void compile_cmp_eq(char*label, long wid, unsigned argc, struct symb_s*argv) make_arith(arith, label, argc, argv); } +void compile_cmp_eq_r(char*label, unsigned argc, struct symb_s*argv) +{ + if (argc != 2) { + fprintf(stderr, "%s .cmp/eq.r has wrong number of symbols\n",label); + compile_errors += 1; + return; + } + + vvp_arith_real_ *arith = new vvp_cmp_eq_real; + make_arith(arith, label, argc, argv); +} + void compile_cmp_ne(char*label, long wid, unsigned argc, struct symb_s*argv) { assert( wid > 0 ); @@ -1066,6 +1078,18 @@ void compile_cmp_ne(char*label, long wid, unsigned argc, struct symb_s*argv) make_arith(arith, label, argc, argv); } +void compile_cmp_ne_r(char*label, unsigned argc, struct symb_s*argv) +{ + if (argc != 2) { + fprintf(stderr, "%s .cmp/ne.r has wrong number of symbols\n",label); + compile_errors += 1; + return; + } + + vvp_arith_real_ *arith = new vvp_cmp_ne_real; + make_arith(arith, label, argc, argv); +} + void compile_cmp_ge(char*label, long wid, bool signed_flag, unsigned argc, struct symb_s*argv) { @@ -1082,6 +1106,18 @@ void compile_cmp_ge(char*label, long wid, bool signed_flag, make_arith(arith, label, argc, argv); } +void compile_cmp_ge_r(char*label, unsigned argc, struct symb_s*argv) +{ + if (argc != 2) { + fprintf(stderr, "%s .cmp/ge.r has wrong number of symbols\n",label); + compile_errors += 1; + return; + } + + vvp_arith_real_ *arith = new vvp_cmp_ge_real; + make_arith(arith, label, argc, argv); +} + void compile_cmp_gt(char*label, long wid, bool signed_flag, unsigned argc, struct symb_s*argv) { @@ -1098,6 +1134,18 @@ void compile_cmp_gt(char*label, long wid, bool signed_flag, make_arith(arith, label, argc, argv); } +void compile_cmp_gt_r(char*label, unsigned argc, struct symb_s*argv) +{ + if (argc != 2) { + fprintf(stderr, "%s .cmp/gt.r has wrong number of symbols\n",label); + compile_errors += 1; + return; + } + + vvp_arith_real_ *arith = new vvp_cmp_gt_real; + make_arith(arith, label, argc, argv); +} + void compile_delay(char*label, vvp_delay_t*delay, struct symb_s arg) { diff --git a/vvp/compile.h b/vvp/compile.h index 4991e33ba..cc12fe633 100644 --- a/vvp/compile.h +++ b/vvp/compile.h @@ -174,6 +174,10 @@ extern void compile_arith_mult_r(char*label, unsigned argc, extern void compile_arith_div_r(char*label, unsigned argc, struct symb_s*argv); extern void compile_arith_sum_r(char*label, unsigned argc, struct symb_s*argv); extern void compile_arith_sub_r(char*label, unsigned argc, struct symb_s*argv); +extern void compile_cmp_eq_r(char*label, unsigned argc, struct symb_s*argv); +extern void compile_cmp_ne_r(char*label, unsigned argc, struct symb_s*argv); +extern void compile_cmp_ge_r(char*label, unsigned argc, struct symb_s*argv); +extern void compile_cmp_gt_r(char*label, unsigned argc, struct symb_s*argv); extern void compile_dff(char*label, struct symb_s arg_d, diff --git a/vvp/lexor.lex b/vvp/lexor.lex index 95a437017..69e04e6d2 100644 --- a/vvp/lexor.lex +++ b/vvp/lexor.lex @@ -104,11 +104,15 @@ ".array/port" { return K_ARRAY_PORT; } ".cmp/eeq" { return K_CMP_EEQ; } ".cmp/eq" { return K_CMP_EQ; } +".cmp/eq.r" { return K_CMP_EQ_R; } ".cmp/nee" { return K_CMP_NEE; } ".cmp/ne" { return K_CMP_NE; } +".cmp/ne.r" { return K_CMP_NE_R; } ".cmp/ge" { return K_CMP_GE; } +".cmp/ge.r" { return K_CMP_GE_R; } ".cmp/ge.s" { return K_CMP_GE_S; } ".cmp/gt" { return K_CMP_GT; } +".cmp/gt.r" { return K_CMP_GT_R; } ".cmp/gt.s" { return K_CMP_GT_S; } ".concat" { return K_CONCAT; } ".delay" { return K_DELAY; } diff --git a/vvp/parse.y b/vvp/parse.y index 72ddc1949..666031bb5 100644 --- a/vvp/parse.y +++ b/vvp/parse.y @@ -69,8 +69,8 @@ static struct __vpiModPath*modpath_dst = 0; %token K_ARITH_DIV K_ARITH_DIV_R K_ARITH_DIV_S K_ARITH_MOD K_ARITH_MULT %token K_ARITH_MULT_R K_ARITH_SUB K_ARITH_SUB_R K_ARITH_SUM K_ARITH_SUM_R %token K_ARRAY K_ARRAY_I K_ARRAY_R K_ARRAY_S K_ARRAY_PORT -%token K_CMP_EEQ K_CMP_EQ K_CMP_NEE K_CMP_NE -%token K_CMP_GE K_CMP_GE_S K_CMP_GT K_CMP_GT_S +%token K_CMP_EEQ K_CMP_EQ K_CMP_EQ_R K_CMP_NEE K_CMP_NE K_CMP_NE_R +%token K_CMP_GE K_CMP_GE_R K_CMP_GE_S K_CMP_GT K_CMP_GT_R K_CMP_GT_S %token K_CONCAT K_DEBUG K_DELAY K_DFF %token K_EVENT K_EVENT_OR K_EXTEND_S K_FUNCTOR K_MODPATH K_NET K_NET_S K_NET_R %token K_NET8 K_NET8_S @@ -315,16 +315,31 @@ statement compile_cmp_eq($1, $3, obj.cnt, obj.vect); } + | T_LABEL K_CMP_EQ_R T_NUMBER ',' symbols ';' + { struct symbv_s obj = $5; + compile_cmp_eq_r($1, obj.cnt, obj.vect); + } + | T_LABEL K_CMP_NE T_NUMBER ',' symbols ';' { struct symbv_s obj = $5; compile_cmp_ne($1, $3, obj.cnt, obj.vect); } + | T_LABEL K_CMP_NE_R T_NUMBER ',' symbols ';' + { struct symbv_s obj = $5; + compile_cmp_ne_r($1, obj.cnt, obj.vect); + } + | T_LABEL K_CMP_GE T_NUMBER ',' symbols ';' { struct symbv_s obj = $5; compile_cmp_ge($1, $3, false, obj.cnt, obj.vect); } + | T_LABEL K_CMP_GE_R T_NUMBER ',' symbols ';' + { struct symbv_s obj = $5; + compile_cmp_ge_r($1, obj.cnt, obj.vect); + } + | T_LABEL K_CMP_GE_S T_NUMBER ',' symbols ';' { struct symbv_s obj = $5; compile_cmp_ge($1, $3, true, obj.cnt, obj.vect); @@ -334,6 +349,12 @@ statement { struct symbv_s obj = $5; compile_cmp_gt($1, $3, false, obj.cnt, obj.vect); } + + | T_LABEL K_CMP_GT_R T_NUMBER ',' symbols ';' + { struct symbv_s obj = $5; + compile_cmp_gt_r($1, obj.cnt, obj.vect); + } + | T_LABEL K_CMP_GT_S T_NUMBER ',' symbols ';' { struct symbv_s obj = $5; compile_cmp_gt($1, $3, true, obj.cnt, obj.vect); From eac6333d6c6eda6915c507716ba63472a3fbe180 Mon Sep 17 00:00:00 2001 From: Cary R Date: Tue, 15 Jan 2008 18:34:25 -0800 Subject: [PATCH 6/8] Add missing deletes for patch "Add real compar..." Add two deletes that I missed in the previous patch. --- elab_net.cc | 2 ++ 1 file changed, 2 insertions(+) diff --git a/elab_net.cc b/elab_net.cc index 0f5b1f12e..62c53e931 100644 --- a/elab_net.cc +++ b/elab_net.cc @@ -542,6 +542,7 @@ NetNet* PEBinary::elaborate_net_cmp_(Design*des, NetScope*scope, verireal vrl(tmp->value().as_double()); NetECReal rlval(vrl); rsig = rlval.synthesize(des); + delete rexp; } else { NetNet*osig = compare_eq_constant(des, scope, lsig, tmp, op_, @@ -563,6 +564,7 @@ NetNet* PEBinary::elaborate_net_cmp_(Design*des, NetScope*scope, verireal vrl(tmp->value().as_double()); NetECReal rlval(vrl); lsig = rlval.synthesize(des); + delete lexp; } else { NetNet*osig = compare_eq_constant(des, scope, rsig, tmp, op_, From 0370f30b2043ab5b3879b9ec3f35d99c2f041b05 Mon Sep 17 00:00:00 2001 From: Cary R Date: Tue, 15 Jan 2008 15:25:27 -0800 Subject: [PATCH 7/8] Support variable delay of a variable selected assignment. This patch adds support for the following statement: [] <= # . It is a copy with slight modification of code from the next else/if clause. --- tgt-vvp/vvp_process.c | 30 ++++++++++++++++++++++-------- 1 file changed, 22 insertions(+), 8 deletions(-) diff --git a/tgt-vvp/vvp_process.c b/tgt-vvp/vvp_process.c index 153add4b0..a28a16224 100644 --- a/tgt-vvp/vvp_process.c +++ b/tgt-vvp/vvp_process.c @@ -236,14 +236,28 @@ static void assign_to_lvector(ivl_lval_t lval, unsigned bit, if (part_off_ex) { unsigned skip_assign = transient_id++; - assert(dexp == 0); - draw_eval_expr_into_integer(part_off_ex, 1); - /* If the index expression has XZ bits, skip the assign. */ - fprintf(vvp_out, " %%jmp/1 t_%u, 4;\n", skip_assign); - fprintf(vvp_out, " %%ix/load 0, %u;\n", width); - fprintf(vvp_out, " %%assign/v0/x1 v%p_%lu, %u, %u;\n", - sig, use_word, delay, bit); - fprintf(vvp_out, "t_%u ;\n", skip_assign); + if (dexp == 0) { + /* Constant delay... */ + draw_eval_expr_into_integer(part_off_ex, 1); + /* If the index expression has XZ bits, skip the assign. */ + fprintf(vvp_out, " %%jmp/1 t_%u, 4;\n", skip_assign); + fprintf(vvp_out, " %%ix/load 0, %u;\n", width); + fprintf(vvp_out, " %%assign/v0/x1 v%p_%lu, %u, %u;\n", + sig, use_word, delay, bit); + fprintf(vvp_out, "t_%u ;\n", skip_assign); + } else { + /* Calculated delay... */ + int delay_index = allocate_word(); + draw_eval_expr_into_integer(dexp, delay_index); + draw_eval_expr_into_integer(part_off_ex, 1); + /* If the index expression has XZ bits, skip the assign. */ + fprintf(vvp_out, " %%jmp/1 t_%u, 4;\n", skip_assign); + fprintf(vvp_out, " %%ix/load 0, %u;\n", width); + fprintf(vvp_out, " %%assign/v0/x1 v%p_%lu, %u, %u;\n", + sig, use_word, delay_index, bit); + fprintf(vvp_out, "t_%u ;\n", skip_assign); + clr_word(delay_index); + } } else if (part_off>0 || ivl_lval_width(lval)!=ivl_signal_width(sig)) { /* There is no mux expression, but a constant part From ded0fbe5ef2b91068746f0f74f16cb8b4ffd8ac2 Mon Sep 17 00:00:00 2001 From: Cary R Date: Tue, 15 Jan 2008 13:25:57 -0800 Subject: [PATCH 8/8] Fix user functions with right shift argument. A right shift may generate extra bits to preserve the proper shift characteristic. This patch replaces the assert that was forcing the input vector to not be greater than the input port width with code to only select the required lower bits from the vector if it is larger than the input port. --- tgt-vvp/draw_ufunc.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/tgt-vvp/draw_ufunc.c b/tgt-vvp/draw_ufunc.c index e5999c5ce..db5ee7dcd 100644 --- a/tgt-vvp/draw_ufunc.c +++ b/tgt-vvp/draw_ufunc.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005-2007 Stephen Williams (steve@icarus.com) + * Copyright (c) 2005-2008 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 @@ -33,8 +33,10 @@ static void function_argument_logic(ivl_signal_t port, ivl_expr_t exp) assert(ivl_signal_array_count(port) == 1); res = draw_eval_expr_wid(exp, ivl_signal_width(port), 0); - assert(res.wid <= ivl_signal_width(port)); - fprintf(vvp_out, " %%set/v v%p_0, %u, %u;\n", port, res.base, res.wid); + /* We could have extra bits so only select the ones we need. */ + unsigned pwidth = ivl_signal_width(port); + fprintf(vvp_out, " %%set/v v%p_0, %u, %u;\n", port, res.base, + (res.wid > pwidth) ? pwidth : res.wid); clr_vector(res); }