Skip to content
Browse files

Major rework of the ternary operator elaboration code.

This patch reworks much of the ternary code to short circuit when
possible and supports real values better. It adds a blend operator
for real values that returns 0.0 when the values differ and the value
when they match. This deviates slightly from the standard which
specifies that the value for reals is always 0.0 when the conditional
is 'bx. There are also a couple bug fixes.

These fixes have not been ported to continuous assignments yet.
Ternary operators used at compile time and in procedural assignments
should be complete (short circuit and support real values).
  • Loading branch information...
1 parent c2bae1a commit fe72d02cf63c76f34d1ee1c6fa519669e1658eee @caryr caryr committed with Mar 7, 2008
Showing with 325 additions and 390 deletions.
  1. +3 −65 PDelays.cc
  2. +12 −29 elab_expr.cc
  3. +2 −5 elab_lval.cc
  4. +29 −16 elab_net.cc
  5. +16 −9 elab_pexpr.cc
  6. +2 −1 elab_scope.cc
  7. +3 −16 elaborate.cc
  8. +137 −200 eval_tree.cc
  9. +1 −7 expr_synth.cc
  10. +2 −9 net_expr.cc
  11. +5 −0 netlist.cc
  12. +0 −3 netlist.h
  13. +56 −6 netmisc.cc
  14. +17 −0 netmisc.h
  15. +23 −22 tgt-vvp/eval_real.c
  16. +1 −1 tgt-vvp/vvp_process.c
  17. +1 −0 vvp/codes.h
  18. +2 −1 vvp/compile.cc
  19. +5 −0 vvp/opcodes.txt
  20. +8 −0 vvp/vthread.cc
View
68 PDelays.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
@@ -24,6 +24,7 @@
# include "PDelays.h"
# include "PExpr.h"
# include "verinum.h"
+# include "netmisc.h"
PDelays::PDelays()
{
@@ -63,10 +64,7 @@ static NetExpr*calculate_val(Design*des, NetScope*scope, const PExpr*expr)
{
NetExpr*dex = expr->elaborate_expr(des, scope, -1, false);
- if (NetExpr*tmp = dex->eval_tree()) {
- delete dex;
- dex = tmp;
- }
+ eval_expr(dex);
/* If the delay expression is a real constant or vector
constant, then evaluate it, scale it to the local time
@@ -163,63 +161,3 @@ void PDelays::eval_delays(Design*des, NetScope*scope,
decay_time = 0;
}
}
-
-/*
- * $Log: PDelays.cc,v $
- * Revision 1.15 2006/07/08 21:48:46 steve
- * Handle real valued literals in net contexts.
- *
- * Revision 1.14 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.13 2006/01/03 05:22:14 steve
- * Handle complex net node delays.
- *
- * Revision 1.12 2006/01/02 05:33:19 steve
- * Node delays can be more general expressions in structural contexts.
- *
- * Revision 1.11 2003/06/21 01:21:42 steve
- * Harmless fixup of warnings.
- *
- * Revision 1.10 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.9 2002/08/12 01:34:58 steve
- * conditional ident string using autoconfig.
- *
- * Revision 1.8 2001/12/29 20:19:31 steve
- * Do not delete delay expressions of UDP instances.
- *
- * Revision 1.7 2001/11/22 06:20:59 steve
- * Use NetScope instead of string for scope path.
- *
- * Revision 1.6 2001/11/07 04:01:59 steve
- * eval_const uses scope instead of a string path.
- *
- * Revision 1.5 2001/07/25 03:10:48 steve
- * Create a config.h.in file to hold all the config
- * junk, and support gcc 3.0. (Stephan Boettcher)
- *
- * Revision 1.4 2001/01/20 02:15:50 steve
- * apologize for not supporting non-constant delays.
- *
- * Revision 1.3 2001/01/14 23:04:55 steve
- * Generalize the evaluation of floating point delays, and
- * get it working with delay assignment statements.
- *
- * Allow parameters to be referenced by hierarchical name.
- *
- * Revision 1.2 2000/02/23 02:56:53 steve
- * Macintosh compilers do not support ident.
- *
- * Revision 1.1 1999/09/04 19:11:46 steve
- * Add support for delayed non-blocking assignments.
- *
- */
-
View
41 elab_expr.cc
@@ -135,19 +135,8 @@ NetEBinary* PEBinary::elaborate_eval_expr_base_(Design*des,
{
/* If either expression can be evaluated ahead of time, then
do so. This can prove helpful later. */
- { NetExpr*tmp;
- tmp = lp->eval_tree();
- if (tmp) {
- delete lp;
- lp = tmp;
- }
-
- tmp = rp->eval_tree();
- if (tmp) {
- delete rp;
- rp = tmp;
- }
- }
+ eval_expr(lp);
+ eval_expr(rp);
return elaborate_expr_base_(des, lp, rp, expr_wid);
}
@@ -533,12 +522,8 @@ NetExpr* PECallFunction::elaborate_sfunc_(Design*des, NetScope*scope, int expr_w
PExpr*expr = parms_[idx];
if (expr) {
NetExpr*tmp1 = expr->elaborate_expr(des, scope, -1, true);
- if (NetExpr*tmp2 = tmp1->eval_tree()) {
- delete tmp1;
- fun->parm(idx, tmp2);
- } else {
- fun->parm(idx, tmp1);
- }
+ eval_expr(tmp1);
+ fun->parm(idx, tmp1);
} else {
missing_parms += 1;
@@ -1147,13 +1132,7 @@ NetExpr* PEIdent::elaborate_expr_param(Design*des,
select attached to it. Generate a NetESelect
object to select the bit as desired. */
NetExpr*mtmp = index_tail.msb->elaborate_expr(des, scope, -1,false);
- if (! dynamic_cast<NetEConst*>(mtmp)) {
- NetExpr*re = mtmp->eval_tree();
- if (re) {
- delete mtmp;
- mtmp = re;
- }
- }
+ eval_expr(mtmp);
/* Let's first try to get constant values for both
the parameter and the bit select. If they are
@@ -1305,9 +1284,7 @@ NetExpr* PEIdent::elaborate_expr_net_word_(Design*des, NetScope*scope,
if (long base = net->array_first()) {
word_index = make_add_expr(word_index, 0-base);
- if (NetExpr*tmp = word_index->eval_tree()) {
- word_index = tmp;
- }
+ eval_expr(word_index);
}
}
@@ -1683,6 +1660,12 @@ static bool test_ternary_operand_compat(ivl_variable_type_t l,
return true;
if (l == IVL_VT_BOOL && r == IVL_VT_LOGIC)
return true;
+
+ if (l == IVL_VT_REAL && (r == IVL_VT_LOGIC || r == IVL_VT_BOOL))
+ return true;
+ if (r == IVL_VT_REAL && (l == IVL_VT_LOGIC || l == IVL_VT_BOOL))
+ return true;
+
if (l == r)
return true;
View
7 elab_lval.cc
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2000-2007 Stephen Williams (steve@icarus.com)
+ * Copyright (c) 2000-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
@@ -333,9 +333,7 @@ NetAssign_* PEIdent::elaborate_lval_net_word_(Design*des,
if (long base = reg->array_first()) {
word = make_add_expr(word, 0-base);
- if (NetExpr*tmp = word->eval_tree()) {
- word = tmp;
- }
+ eval_expr(word);
}
NetAssign_*lv = new NetAssign_(reg);
@@ -485,4 +483,3 @@ NetAssign_* PENumber::elaborate_lval(Design*des, NetScope*, bool) const
des->errors += 1;
return 0;
}
-
View
45 elab_net.cc
@@ -1713,20 +1713,14 @@ NetNet* PEIdent::elaborate_net_bitmux_(Design*des, NetScope*scope,
if (sig->msb() < sig->lsb()) {
NetExpr*sel_expr = index_tail.msb->elaborate_expr(des, scope, -1, false);
sel_expr = make_sub_expr(sig->lsb(), sel_expr);
- if (NetExpr*tmp = sel_expr->eval_tree()) {
- delete sel_expr;
- sel_expr = tmp;
- }
+ eval_expr(sel_expr);
sel = sel_expr->synthesize(des);
} else if (sig->lsb() != 0) {
NetExpr*sel_expr = index_tail.msb->elaborate_expr(des, scope, -1,false);
sel_expr = make_add_expr(sel_expr, - sig->lsb());
- if (NetExpr*tmp = sel_expr->eval_tree()) {
- delete sel_expr;
- sel_expr = tmp;
- }
+ eval_expr(sel_expr);
sel = sel_expr->synthesize(des);
@@ -2935,9 +2929,31 @@ NetNet* PETernary::elaborate_net(Design*des, NetScope*scope,
Link::strength_t drive0,
Link::strength_t drive1) const
{
- NetNet*expr_sig = expr_->elaborate_net(des, scope, 0, 0, 0, 0),
- *tru_sig = tru_->elaborate_net(des, scope, width, 0, 0, 0),
- *fal_sig = fal_->elaborate_net(des, scope, width, 0, 0, 0);
+ NetNet *expr_sig, *tru_sig, *fal_sig;
+
+ NetExpr*expr = elab_and_eval(des, scope, expr_, 0);
+ if (expr == 0) return 0;
+
+ /* If we have a constant conditional we can avoid some steps. */
+ switch (const_logical(expr)) {
+ case C_0:
+ fal_sig = fal_->elaborate_net(des, scope, width, 0, 0, 0);
+ if (fal_sig == 0) return 0;
+tru_sig = tru_->elaborate_net(des, scope, width, 0, 0, 0);
+ break;
+
+ case C_1:
+ tru_sig = tru_->elaborate_net(des, scope, width, 0, 0, 0);
+ if (tru_sig == 0) return 0;
+fal_sig = fal_->elaborate_net(des, scope, width, 0, 0, 0);
+ break;
+
+ default:
+ tru_sig = tru_->elaborate_net(des, scope, width, 0, 0, 0);
+ fal_sig = fal_->elaborate_net(des, scope, width, 0, 0, 0);
+ break;
+ }
+ expr_sig = expr->synthesize(des);
if (expr_sig == 0 || tru_sig == 0 || fal_sig == 0) return 0;
@@ -2970,14 +2986,11 @@ NetNet* PETernary::elaborate_net(Design*des, NetScope*scope,
but if we do not get a size from the context, or the
expressions resist, we need to cope. */
unsigned iwidth = tru_sig->vector_width();
- if (fal_sig->vector_width() > iwidth)
- iwidth = fal_sig->vector_width();
-
+ if (fal_sig->vector_width() > iwidth) iwidth = fal_sig->vector_width();
/* If the width is not passed from the context, then take the
widest result as our width. */
- if (width == 0)
- width = iwidth;
+ if (width == 0) width = iwidth;
/* If the expression has width, then generate a boolean result
by connecting an OR gate to calculate the truth value of
View
25 elab_pexpr.cc
@@ -78,6 +78,7 @@ NetEConcat* PEConcat::elaborate_pexpr(Design*des, NetScope*scope) const
"concatenation repeat expression cannot be evaluated."
<< endl;
des->errors += 1;
+ return 0;
}
/* continue on even if the repeat expression doesn't
@@ -108,7 +109,8 @@ NetEConcat* PEConcat::elaborate_pexpr(Design*des, NetScope*scope) const
<< "concatenation has indefinite width: "
<< *ex << endl;
des->errors += 1;
-
+ delete tmp;
+ return 0;
}
tmp->set(idx, ex);
@@ -173,22 +175,26 @@ NetExpr*PEIdent::elaborate_pexpr(Design*des, NetScope*scope) const
switch (use_sel) {
case index_component_t::SEL_NONE:
break;
+
default:
case index_component_t::SEL_PART:
cerr << get_fileline() << ": sorry: Cannot part select "
- "bits of parameters." << endl;
+ "bits of parameters." << endl;
des->errors += 1;
- break;
+ delete res;
+ return 0;
case index_component_t::SEL_BIT:
/* We have here a bit select. Insert a NetESelect node
to handle it. */
NetExpr*tmp = name_tail.index.back().msb->elaborate_pexpr(des, scope);
- if (tmp != 0) {
- res = new NetESelect(res, tmp, 1);
- res->set_line(*this);
+ if (tmp == 0) {
+ delete res;
+ return 0;
}
+ res = new NetESelect(res, tmp, 1);
+ res->set_line(*this);
break;
}
@@ -214,9 +220,7 @@ NetETernary* PETernary::elaborate_pexpr(Design*des, NetScope*scope) const
NetExpr*c = expr_->elaborate_pexpr(des, scope);
NetExpr*t = tru_->elaborate_pexpr(des, scope);
NetExpr*f = fal_->elaborate_pexpr(des, scope);
- if (c == 0) return 0;
- if (t == 0) return 0;
- if (f == 0) return 0;
+ if (c == 0 || t == 0 || f == 0) return 0;
NetETernary*tmp = new NetETernary(c, t, f);
tmp->set_line(*this);
@@ -238,10 +242,12 @@ NetExpr*PEUnary::elaborate_pexpr (Design*des, NetScope*scope) const
tmp = new NetEUnary(op_, ip);
tmp->set_line(*this);
break;
+
case '~':
tmp = new NetEUBits(op_, ip);
tmp->set_line(*this);
break;
+
case '!': // Logical NOT
case '&': // Reduction AND
case '|': // Reduction OR
@@ -253,5 +259,6 @@ NetExpr*PEUnary::elaborate_pexpr (Design*des, NetScope*scope) const
tmp->set_line(*this);
break;
}
+
return tmp;
}
View
3 elab_scope.cc
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2000-2007 Stephen Williams (steve@icarus.com)
+ * Copyright (c) 2000-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
@@ -51,6 +51,7 @@ void Module::elaborate_parm_item_(perm_string name, const param_expr_t&cur,
assert(ex);
NetExpr*val = ex->elaborate_pexpr(des, scope);
+ if (val == 0) return;
NetExpr*msb = 0;
NetExpr*lsb = 0;
bool signed_flag = cur.signed_flag;
View
19 elaborate.cc
@@ -2123,12 +2123,7 @@ NetProc* PCallTask::elaborate_sys(Design*des, NetScope*scope) const
/* Attempt to pre-evaluate the parameters. It may be
possible to at least partially reduce the
expression. */
- if (eparms[idx]) {
- if (NetExpr*tmp = eparms[idx]->eval_tree()) {
- delete eparms[idx];
- eparms[idx] = tmp;
- }
- }
+ if (eparms[idx]) eval_expr(eparms[idx]);
}
NetSTask*cur = new NetSTask(peek_tail_name(path_), eparms);
@@ -2725,10 +2720,7 @@ NetProc* PEventStatement::elaborate_wait(Design*des, NetScope*scope,
}
/* precalculate as much as possible of the wait expression. */
- if (NetExpr*tmp = expr->eval_tree()) {
- delete expr;
- expr = tmp;
- }
+ eval_expr(expr);
/* Detect the unusual case that the wait expression is
constant. Constant true is OK (it becomes transparent) but
@@ -2771,11 +2763,7 @@ NetProc* PEventStatement::elaborate_wait(Design*des, NetScope*scope,
wait. */
assert(expr->expr_width() == 1);
expr = new NetEBComp('N', expr, new NetEConst(verinum(verinum::V1)));
- NetExpr*tmp = expr->eval_tree();
- if (tmp) {
- delete expr;
- expr = tmp;
- }
+ eval_expr(expr);
NetEvent*wait_event = new NetEvent(scope->local_symbol());
scope->add_event(wait_event);
@@ -3766,4 +3754,3 @@ Design* elaborate(list<perm_string>roots)
return des;
}
-
View
337 eval_tree.cc
@@ -25,82 +25,51 @@
# include "netlist.h"
# include "ivl_assert.h"
+# include "netmisc.h"
NetExpr* NetExpr::eval_tree(int prune_to_width)
{
return 0;
}
-/*
- * Some of the derived classes can be evaluated by the compiler, this
- * method provides the common aid of evaluating the parameter
- * expressions.
- */
-void NetEBinary::eval_sub_tree_()
-{
- NetExpr*tmp = left_->eval_tree();
- if (tmp) {
- delete left_;
- left_ = tmp;
- }
- tmp = right_->eval_tree();
- if (tmp){
- delete right_;
- right_ = tmp;
- }
-}
-
-bool NetEBinary::get_real_arguments_(verireal&lval, verireal&rval)
+static bool get_real_arg_(NetExpr*expr, verireal&val)
{
- switch (left_->expr_type()) {
+ switch (expr->expr_type()) {
case IVL_VT_REAL: {
- NetECReal*lc = dynamic_cast<NetECReal*> (left_);
- if (lc == 0) return false;
- lval = lc->value();
+ NetECReal*c = dynamic_cast<NetECReal*> (expr);
+ if (c == 0) return false;
+ val = c->value();
break;
}
case IVL_VT_BOOL:
case IVL_VT_LOGIC: {
- NetEConst*lc = dynamic_cast<NetEConst*>(left_);
- if (lc == 0) return false;
- verinum tmp = lc->value();
- lval = verireal(tmp.as_double());
+ NetEConst*c = dynamic_cast<NetEConst*>(expr);
+ if (c == 0) return false;
+ verinum tmp = c->value();
+ val = verireal(tmp.as_double());
break;
}
default:
assert(0);
}
- switch (right_->expr_type()) {
- case IVL_VT_REAL: {
- NetECReal*rc = dynamic_cast<NetECReal*> (right_);
- if (rc == 0) return 0;
- rval = rc->value();
- break;
- }
-
- case IVL_VT_BOOL:
- case IVL_VT_LOGIC: {
- NetEConst*rc = dynamic_cast<NetEConst*>(right_);
- if (rc == 0) return 0;
- verinum tmp = rc->value();
- rval = verireal(tmp.as_double());
- break;
- }
-
- default:
- assert(0);
- }
+ return true;
+}
+bool NetEBinary::get_real_arguments_(verireal&lval, verireal&rval)
+{
+ if (!get_real_arg_(left_, lval)) return false;
+ if (!get_real_arg_(right_, rval)) return false;
return true;
}
NetExpr* NetEBAdd::eval_tree(int prune_to_width)
{
- eval_sub_tree_();
+ eval_expr(left_, prune_to_width);
+ eval_expr(right_, prune_to_width);
if (left_->expr_type() == IVL_VT_REAL || right_->expr_type()==IVL_VT_REAL)
return eval_tree_real_();
@@ -170,6 +139,7 @@ NetExpr* NetEBAdd::eval_tree(int prune_to_width)
NetEConst*tmp = new NetEConst(val);
left_ = se->left_->dup_expr();
delete se;
+ tmp->set_line(*right_);
delete right_;
right_ = tmp;
/* We've changed the subexpression, but the result is
@@ -208,27 +178,26 @@ NetECReal* NetEBAdd::eval_tree_real_()
NetEConst* NetEBBits::eval_tree(int prune_to_width)
{
- eval_sub_tree_();
+ eval_expr(left_);
+ eval_expr(right_);
NetEConst*lc = dynamic_cast<NetEConst*>(left_);
NetEConst*rc = dynamic_cast<NetEConst*>(right_);
+ if (lc == 0 || rc == 0) return 0;
/* Notice the special case where one of the operands is 0 and
this is a bitwise &. If this happens, then the result is
known to be 0. */
- if ((op() == '&') && lc && (lc->value() == verinum(0))) {
+ if ((op() == '&') && (lc->value() == verinum(0))) {
verinum res (verinum::V0, expr_width());
return new NetEConst(res);
}
- if ((op() == '&') && rc && (rc->value() == verinum(0))) {
+ if ((op() == '&') && (rc->value() == verinum(0))) {
verinum res (verinum::V0, expr_width());
return new NetEConst(res);
}
- if (lc == 0) return 0;
- if (rc == 0) return 0;
-
verinum lval = lc->value();
verinum rval = rc->value();
@@ -737,12 +706,14 @@ NetEConst* NetEBComp::eval_neeqeq_()
res = new NetEConst(verinum(verinum::V0,1));
delete tmp;
+ res->set_line(*this);
return res;
}
NetEConst* NetEBComp::eval_tree(int prune_to_width)
{
- eval_sub_tree_();
+ eval_expr(left_);
+ eval_expr(right_);
switch (op_) {
case 'E': // Case equality (===)
@@ -780,7 +751,8 @@ NetEConst* NetEBComp::eval_tree(int prune_to_width)
*/
NetExpr* NetEBDiv::eval_tree(int prune_to_width)
{
- eval_sub_tree_();
+ eval_expr(left_);
+ eval_expr(right_);
if (expr_type() == IVL_VT_REAL) {
NetECReal*lc = dynamic_cast<NetECReal*>(left_);
@@ -850,11 +822,12 @@ NetExpr* NetEBDiv::eval_tree(int prune_to_width)
NetEConst* NetEBLogic::eval_tree(int prune_to_width)
{
- eval_sub_tree_();
+ eval_expr(left_);
+ eval_expr(right_);
+
NetEConst*lc = dynamic_cast<NetEConst*>(left_);
- if (lc == 0) return 0;
NetEConst*rc = dynamic_cast<NetEConst*>(right_);
- if (rc == 0) return 0;
+ if (lc == 0 || rc == 0) return 0;
verinum::V lv = verinum::V0;
verinum::V rv = verinum::V0;
@@ -931,17 +904,17 @@ NetExpr* NetEBMult::eval_tree_real_()
NetExpr* NetEBMult::eval_tree(int prune_to_width)
{
- eval_sub_tree_();
+ eval_expr(left_);
+ eval_expr(right_);
if (expr_type() == IVL_VT_REAL)
return eval_tree_real_();
assert(expr_type() == IVL_VT_LOGIC);
NetEConst*lc = dynamic_cast<NetEConst*>(left_);
- if (lc == 0) return 0;
NetEConst*rc = dynamic_cast<NetEConst*>(right_);
- if (rc == 0) return 0;
+ if (lc == 0 || rc == 0) return 0;
verinum lval = lc->value();
verinum rval = rc->value();
@@ -964,17 +937,17 @@ NetExpr* NetEBPow::eval_tree_real_()
NetExpr* NetEBPow::eval_tree(int prune_to_width)
{
- eval_sub_tree_();
+ eval_expr(left_);
+ eval_expr(right_);
if (expr_type() == IVL_VT_REAL)
return eval_tree_real_();
assert(expr_type() == IVL_VT_LOGIC);
NetEConst*lc = dynamic_cast<NetEConst*>(left_);
- if (lc == 0) return 0;
NetEConst*rc = dynamic_cast<NetEConst*>(right_);
- if (rc == 0) return 0;
+ if (lc == 0 || rc == 0) return 0;
verinum lval = lc->value();
verinum rval = rc->value();
@@ -988,14 +961,12 @@ NetExpr* NetEBPow::eval_tree(int prune_to_width)
*/
NetEConst* NetEBShift::eval_tree(int prune_to_width)
{
- eval_sub_tree_();
- NetEConst*re = dynamic_cast<NetEConst*>(right_);
- if (re == 0)
- return 0;
+ eval_expr(left_);
+ eval_expr(right_);
NetEConst*le = dynamic_cast<NetEConst*>(left_);
- if (le == 0)
- return 0;
+ NetEConst*re = dynamic_cast<NetEConst*>(right_);
+ if (le == 0 || re == 0) return 0;
NetEConst*res;
@@ -1018,7 +989,7 @@ NetEConst* NetEBShift::eval_tree(int prune_to_width)
if ((wid == 0) || ! lv.has_len()) {
/* If the caller doesn't care what the width is,
- then calcuate a width from the trimmed left
+ then calculate a width from the trimmed left
expression, plus the shift. This avoids
data loss. */
lv = trim_vnum(lv);
@@ -1064,8 +1035,7 @@ NetEConst* NetEBShift::eval_tree(int prune_to_width)
res = new NetEConst(nv);
} else {
- if (wid == 0)
- wid = left_->expr_width();
+ if (wid == 0) wid = left_->expr_width();
verinum nv (verinum::Vx, wid);
res = new NetEConst(nv);
@@ -1089,9 +1059,7 @@ NetEConst* NetEConcat::eval_tree(int prune_to_width)
// Parameter not here? This is an error, but presumably
// already caught and we are here just to catch more.
- if (parms_[idx] == 0)
- continue;
-
+ if (parms_[idx] == 0) continue;
// If this parameter is already a constant, all is well
// so go on.
@@ -1106,6 +1074,7 @@ NetEConst* NetEConcat::eval_tree(int prune_to_width)
assert(parms_[idx]);
NetExpr*expr = parms_[idx]->eval_tree(0);
if (expr) {
+ expr->set_line(*parms_[idx]);
delete parms_[idx];
parms_[idx] = expr;
@@ -1126,8 +1095,7 @@ NetEConst* NetEConcat::eval_tree(int prune_to_width)
}
- if (local_errors > 0)
- return 0;
+ if (local_errors > 0) return 0;
// Handle the special case that the repeat expression is
// zero. In this case, just return a 0 value with the expected
@@ -1282,38 +1250,20 @@ NetExpr* NetEParam::eval_tree(int prune_to_width)
NetEConst* NetESelect::eval_tree(int prune_to_width)
{
+ eval_expr(expr_);
NetEConst*expr = dynamic_cast<NetEConst*>(expr_);
- if (expr == 0) {
- NetExpr*tmp = expr_->eval_tree();
- if (tmp != 0) {
- delete expr_;
- expr_ = tmp;
- }
-
- expr = dynamic_cast<NetEConst*>(expr_);
- }
long bval = 0;
if (base_) {
+ eval_expr(base_);
NetEConst*base = dynamic_cast<NetEConst*>(base_);
- if (base == 0) {
- NetExpr*tmp = base_->eval_tree();
- if (tmp != 0) {
- delete base_;
- base_ = tmp;
- }
-
- base = dynamic_cast<NetEConst*>(base_);
- }
- if (base == 0)
- return 0;
+ if (base == 0) return 0;
bval = base->value().as_long();
}
- if (expr == 0)
- return 0;
+ if (expr == 0) return 0;
verinum eval = expr->value();
verinum oval (verinum::V0, expr_width(), true);
@@ -1348,6 +1298,19 @@ NetEConst* NetESelect::eval_tree(int prune_to_width)
}
+static void print_ternary_cond(NetExpr*expr)
+{
+ if (NetEConst*c = dynamic_cast<NetEConst*>(expr)) {
+ cerr << c->value() << endl;
+ return;
+ }
+ if (NetECReal*c = dynamic_cast<NetECReal*>(expr)) {
+ cerr << c->value() << endl;
+ return;
+ }
+ assert(0);
+}
+
/*
* A ternary expression evaluation is controlled by the condition
* expression. If the condition evaluates to true or false, then
@@ -1357,98 +1320,89 @@ NetEConst* NetESelect::eval_tree(int prune_to_width)
*/
NetExpr* NetETernary::eval_tree(int prune_to_width)
{
- NetExpr*tmp;
-
- assert(cond_);
- if (0 == dynamic_cast<NetEConst*>(cond_)) {
- tmp = cond_->eval_tree();
- if (tmp != 0) {
- delete cond_;
- cond_ = tmp;
- }
- }
-
- assert(true_val_);
- if (0 == dynamic_cast<NetEConst*>(true_val_)) {
- tmp = true_val_->eval_tree();
- if (tmp != 0) {
- delete true_val_;
- true_val_ = tmp;
- }
- }
-
- assert(false_val_);
- if (0 == dynamic_cast<NetEConst*>(false_val_)) {
- tmp = false_val_->eval_tree();
- if (tmp != 0) {
- delete false_val_;
- false_val_ = tmp;
+ eval_expr(cond_);
+ switch (const_logical(cond_)) {
+ case C_0:
+ eval_expr(false_val_);
+ if (debug_eval_tree) {
+
+ cerr << get_fileline() << ": debug: Evaluate ternary with "
+ << "constant condition value: ";
+ print_ternary_cond(cond_);
+ cerr << get_fileline() << ": : Selecting false case: "
+ << *false_val_ << endl;
}
- }
-
- NetEConst*c = dynamic_cast<NetEConst*>(cond_);
- if (c == 0)
- return 0;
-
- /* Check the boolean value of the constant condition
- expression. Note that the X case is handled explicitly, so
- we must differentiate. */
-
- verinum cond_value = c->value();
- bool true_flag = false;
- bool x_flag = false;
-
- for (unsigned idx = 0 ; idx < cond_value.len() ; idx += 1) {
- switch (cond_value.get(idx)) {
- case verinum::V1:
- true_flag = true;
- break;
- case verinum::V0:
- break;
- default:
- x_flag = true;
+ if (expr_type() == IVL_VT_REAL &&
+ false_val_->expr_type() != IVL_VT_REAL) {
+ verireal f;
+ if (get_real_arg_(false_val_, f)) {
+ NetECReal*rc = new NetECReal(f);
+ rc->set_line(*this);
+ return rc;
+ }
}
- }
+ return false_val_->dup_expr();
- /* If the condition is 1 or 0, return the true or false
- expression. Try to evaluate the expression down as far as
- we can. */
-
- if (true_flag) {
+ case C_1:
+ eval_expr(true_val_);
if (debug_eval_tree) {
cerr << get_fileline() << ": debug: Evaluate ternary with "
- << "constant condition value: " << c->value() << endl;
+ << "constant condition value: ";
+ print_ternary_cond(cond_);
cerr << get_fileline() << ": : Selecting true case: "
<< *true_val_ << endl;
}
- return true_val_->dup_expr();
- }
- if (! x_flag) {
- if (debug_eval_tree) {
- cerr << get_fileline() << ": debug: Evaluate ternary with "
- << "constant condition value: " << c->value() << endl;
- cerr << get_fileline() << ": : Selecting false case: "
- << *true_val_ << endl;
+ if (expr_type() == IVL_VT_REAL &&
+ true_val_->expr_type() != IVL_VT_REAL) {
+ verireal t;
+ if (get_real_arg_(true_val_, t)) {
+ NetECReal*rc = new NetECReal(t);
+ rc->set_line(*this);
+ return rc;
+ }
}
- return false_val_->dup_expr();
+
+ return true_val_->dup_expr();
+
+ case C_X:
+ break;
+
+ default:
+ return 0;
}
/* Here we have a more complex case. We need to evaluate both
expressions down to constants then compare the values to
build up a constant result. */
+ eval_expr(true_val_);
+ eval_expr(false_val_);
+
NetEConst*t = dynamic_cast<NetEConst*>(true_val_);
- if (t == 0)
- return 0;
+ NetEConst*f = dynamic_cast<NetEConst*>(false_val_);
+ if (t == 0 || f == 0) {
+ verireal tv, fv;
+ if (!get_real_arg_(true_val_, tv)) return 0;
+ if (!get_real_arg_(false_val_, fv)) return 0;
+ verireal val = verireal(0.0);
+ if (tv.as_double() == fv.as_double()) val = tv;
- NetEConst*f = dynamic_cast<NetEConst*>(false_val_);
- if (f == 0)
- return 0;
+ if (debug_eval_tree) {
+ cerr << get_fileline() << ": debug: Evaluate ternary with "
+ << "constant condition value: ";
+ print_ternary_cond(cond_);
+ cerr << get_fileline() << ": : Blending real cases "
+ << "to get " << val << endl;
+ }
+ NetECReal*rc = new NetECReal(val);
+ rc->set_line(*this);
+ return rc;
+ }
unsigned tsize = t->expr_width();
unsigned fsize = f->expr_width();
@@ -1458,17 +1412,16 @@ NetExpr* NetETernary::eval_tree(int prune_to_width)
verinum val (verinum::V0, rsize);
for (unsigned idx = 0 ; idx < rsize ; idx += 1) {
verinum::V tv = idx < tsize? t->value().get(idx) : verinum::V0;
- verinum::V fv = idx < rsize? f->value().get(idx) : verinum::V0;
+ verinum::V fv = idx < fsize? f->value().get(idx) : verinum::V0;
- if (tv == fv)
- val.set(idx, tv);
- else
- val.set(idx, verinum::Vx);
+ if (tv == fv) val.set(idx, tv);
+ else val.set(idx, verinum::Vx);
}
if (debug_eval_tree) {
cerr << get_fileline() << ": debug: Evaluate ternary with "
- << "constant condition value: " << c->value() << endl;
+ << "constant condition value: ";
+ print_ternary_cond(cond_);
cerr << get_fileline() << ": : Blending cases to get "
<< val << endl;
}
@@ -1478,22 +1431,6 @@ NetExpr* NetETernary::eval_tree(int prune_to_width)
return rc;
}
-void NetEUnary::eval_expr_()
-{
- assert(expr_);
- if (dynamic_cast<NetEConst*>(expr_))
- return;
- if (dynamic_cast<NetECReal*>(expr_))
- return;
-
- NetExpr*oper = expr_->eval_tree();
- if (oper == 0)
- return;
-
- delete expr_;
- expr_ = oper;
-}
-
NetExpr* NetEUnary::eval_tree_real_()
{
NetECReal*val= dynamic_cast<NetECReal*> (expr_), *res;
@@ -1504,23 +1441,24 @@ NetExpr* NetEUnary::eval_tree_real_()
res = new NetECReal(val->value());
res->set_line(*this);
return res;
+
case '-':
res = new NetECReal(-(val->value()));
res->set_line(*this);
return res;
+
default:
return 0;
}
}
NetExpr* NetEUnary::eval_tree(int prune_to_width)
{
- eval_expr_();
+ eval_expr(expr_);
if (expr_type() == IVL_VT_REAL) return eval_tree_real_();
NetEConst*rval = dynamic_cast<NetEConst*>(expr_);
- if (rval == 0)
- return 0;
+ if (rval == 0) return 0;
verinum val = rval->value();
@@ -1579,10 +1517,9 @@ NetExpr* NetEUBits::eval_tree(int prune_to_width)
NetEConst* NetEUReduce::eval_tree(int prune_to_width)
{
- eval_expr_();
+ eval_expr(expr_);
NetEConst*rval = dynamic_cast<NetEConst*>(expr_);
- if (rval == 0)
- return 0;
+ if (rval == 0) return 0;
verinum val = rval->value();
verinum::V res;
View
8 expr_synth.cc
@@ -554,13 +554,7 @@ NetNet* NetEBLogic::synthesize(Design*des)
NetNet* NetEBShift::synthesize(Design*des)
{
- if (! dynamic_cast<NetEConst*>(right_)) {
- NetExpr*tmp = right_->eval_tree();
- if (tmp) {
- delete right_;
- right_ = tmp;
- }
- }
+ eval_expr(right_);
NetNet*lsig = left_->synthesize(des);
View
11 net_expr.cc
@@ -20,6 +20,7 @@
# include "config.h"
# include "netlist.h"
# include "compiler.h"
+# include "netmisc.h"
# include <iostream>
/*
@@ -366,15 +367,7 @@ unsigned NetEConcat::repeat()
if (repeat_calculated_)
return repeat_value_;
- assert(repeat_);
-
- if (! dynamic_cast<NetEConst*>(repeat_)) {
- NetExpr*tmp = repeat_->eval_tree();
- if (tmp != 0) {
- delete repeat_;
- repeat_ = tmp;
- }
- }
+ eval_expr(repeat_);
NetEConst*repeat_const = dynamic_cast<NetEConst*>(repeat_);
View
5 netlist.cc
@@ -2263,6 +2263,11 @@ ivl_variable_type_t NetETernary::expr_type() const
if (tru == IVL_VT_BOOL && fal == IVL_VT_LOGIC)
return IVL_VT_LOGIC;
+ if (tru == IVL_VT_REAL && (fal == IVL_VT_LOGIC || fal == IVL_VT_BOOL))
+ return IVL_VT_REAL;
+ if (fal == IVL_VT_REAL && (tru == IVL_VT_LOGIC || tru == IVL_VT_BOOL))
+ return IVL_VT_REAL;
+
if (tru != fal) {
cerr << get_fileline() << ": internal error:"
<< " Unexpected ?: type clash:"
View
3 netlist.h
@@ -2678,7 +2678,6 @@ class NetEBinary : public NetExpr {
NetExpr* left_;
NetExpr* right_;
- void eval_sub_tree_();
bool get_real_arguments_(verireal&lv, verireal&rv);
};
@@ -3152,8 +3151,6 @@ class NetEUnary : public NetExpr {
char op_;
NetExpr* expr_;
- void eval_expr_();
-
private:
virtual NetExpr* eval_tree_real_();
};
View
62 netmisc.cc
@@ -127,17 +127,27 @@ NetExpr* elab_and_eval(Design*des, NetScope*scope,
const PExpr*pe, int expr_wid, int prune_width)
{
NetExpr*tmp = pe->elaborate_expr(des, scope, expr_wid, false);
- if (tmp == 0)
- return 0;
+ if (tmp == 0) return 0;
- if (NetExpr*tmp2 = tmp->eval_tree(prune_width)) {
- delete tmp;
- tmp = tmp2;
- }
+ eval_expr(tmp, prune_width);
return tmp;
}
+void eval_expr(NetExpr*&expr, int prune_width)
+{
+ assert(expr);
+ if (dynamic_cast<NetEConst*>(expr)) return;
+ if (dynamic_cast<NetECReal*>(expr)) return;
+
+ NetExpr*tmp = expr->eval_tree(prune_width);
+ if (tmp != 0) {
+ tmp->set_line(*expr);
+ delete expr;
+ expr = tmp;
+ }
+}
+
bool eval_as_long(long&value, NetExpr*expr)
{
if (NetEConst*tmp = dynamic_cast<NetEConst*>(expr) ) {
@@ -221,3 +231,43 @@ const char *human_readable_op(const char op)
}
return type;
}
+
+const_bool const_logical(const NetExpr*expr)
+{
+ switch (expr->expr_type()) {
+ case IVL_VT_REAL: {
+ const NetECReal*val = dynamic_cast<const NetECReal*> (expr);
+ if (val == 0) return C_NON;
+ if (val->value().as_double() == 0.0) return C_0;
+ else return C_1;
+ }
+
+ case IVL_VT_BOOL:
+ case IVL_VT_LOGIC: {
+ const NetEConst*val = dynamic_cast<const NetEConst*> (expr);
+ if (val == 0) return C_NON;
+ verinum cval = val->value();
+ const_bool res = C_0;
+ for (unsigned idx = 0; idx < cval.len(); idx += 1) {
+ switch (cval.get(idx)) {
+ case verinum::V1:
+ res = C_1;
+ break;
+
+ case verinum::V0:
+ break;
+
+ default:
+ if (res == C_0) res = C_X;
+ break;
+ }
+ }
+ return res;
+ }
+
+ default:
+ break;
+ }
+
+ return C_NON;
+}
View
17 netmisc.h
@@ -119,6 +119,11 @@ class PExpr;
extern NetExpr* elab_and_eval(Design*des, NetScope*scope,
const PExpr*pe, int expr_wid,
int prune_width =-1);
+/*
+ * This procedure elaborates an expression and if the elaboration is
+ * successful the original expression is replaced with the new one.
+ */
+void eval_expr(NetExpr*&expr, int prune_width =-1);
/*
* Get the long integer value for the passed in expression, if
@@ -135,4 +140,16 @@ extern std::list<hname_t> eval_scope_path(Design*des, NetScope*scope,
*/
const char *human_readable_op(const char op);
+/*
+ * Is the expression a constant value and if so what is its logical
+ * value.
+ *
+ * C_NON - the expression is not a constant value.
+ * C_0 - the expression is constant and it has a false value.
+ * C_1 - the expression is constant and it has a true value.
+ * C_X - the expression is constant and it has an 'bX value.
+ */
+enum const_bool { C_NON, C_0, C_1, C_X };
+const_bool const_logical(const NetExpr*expr);
+
#endif
View
45 tgt-vvp/eval_real.c
@@ -80,17 +80,6 @@ static int draw_binary_real(ivl_expr_t exp)
case '%':
fprintf(vvp_out, " %%mod/wr %d, %d;\n", l, r);
break;
-#if 0
- case '%':
- { struct vector_info res = draw_eval_expr(exp, STUFF_OK_XZ);
- l = allocate_word();
- fprintf(vvp_out, " %%ix/get %d, %u, %u;\n",
- l, res.base, res.wid);
- fprintf(vvp_out, " %%cvt/ri %d, %d;\n", l, l);
- clr_vector(res);
- }
- break;
-#endif
case 'p':
fprintf(vvp_out, " %%pow/wr %d, %d;\n", l, r);
break;
@@ -285,7 +274,7 @@ static int draw_signal_real_real(ivl_expr_t exp)
word = get_number_immediate(ix);
}
- fprintf(vvp_out, " %%load/wr %d, v%p_%lu;\n", res, sig, word);
+ fprintf(vvp_out, " %%load/wr %d, v%p_%lu;\n", res, sig, word);
return res;
}
@@ -316,6 +305,7 @@ static int draw_ternary_real(ivl_expr_t exp)
unsigned lab_true = local_count++;
unsigned lab_false = local_count++;
+ unsigned lab_out = local_count++;
int tru, fal;
int res = allocate_word();
@@ -335,21 +325,32 @@ static int draw_ternary_real(ivl_expr_t exp)
tst.wid = 1;
}
- fprintf(vvp_out, " %%jmp/0 T_%d.%d, %u;\n",
+ fprintf(vvp_out, " %%jmp/0 T_%d.%d, %u;\n",
thread_count, lab_true, tst.base);
tru = draw_eval_real(true_ex);
- fprintf(vvp_out, " %%mov/wr %d, %d;\n", res, tru);
- fprintf(vvp_out, " %%jmp T_%d.%d;\n", thread_count, lab_false);
+ fprintf(vvp_out, " %%mov/wr %d, %d;\n", res, tru);
+ fprintf(vvp_out, " %%jmp/1 T_%d.%d, %u; End of true expr.\n",
+ thread_count, lab_out, tst.base);
clr_word(tru);
fprintf(vvp_out, "T_%d.%d ;\n", thread_count, lab_true);
-
fal = draw_eval_real(false_ex);
- fprintf(vvp_out, " %%mov/wr %d, %d;\n", res, fal);
+ fprintf(vvp_out, " %%jmp/0 T_%d.%d, %u; End of false expr.\n",
+ thread_count, lab_false, tst.base);
+
+ fprintf(vvp_out, " %%blend/wr %d, %d;\n", res, fal);
+ fprintf(vvp_out, " %%jmp T_%d.%d; End of blend\n",
+ thread_count, lab_out);
+
+ fprintf(vvp_out, "T_%d.%d ; Move false result.\n",
+ thread_count, lab_false);
+
+ fprintf(vvp_out, " %%mov/wr %d, %d;\n", res, fal);
clr_word(fal);
- fprintf(vvp_out, "T_%d.%d ;\n", thread_count, lab_false);
+ /* This is the out label. */
+ fprintf(vvp_out, "T_%d.%d ;\n", thread_count, lab_out);
clr_vector(tst);
@@ -366,8 +367,8 @@ static int draw_unary_real(ivl_expr_t exp)
if (ivl_expr_opcode(exp) == '-') {
int res = allocate_word();
- fprintf(vvp_out, " %%loadi/wr %d, 0, 0; load 0.0\n", res);
- fprintf(vvp_out, " %%sub/wr %d, %d;\n", res, sub);
+ fprintf(vvp_out, " %%loadi/wr %d, 0, 0; load 0.0\n", res);
+ fprintf(vvp_out, " %%sub/wr %d, %d;\n", res, sub);
clr_word(sub);
return res;
@@ -424,10 +425,10 @@ int draw_eval_real(ivl_expr_t exp)
clr_vector(sv);
res = allocate_word();
- fprintf(vvp_out, " %%ix/get%s %d, %u, %u;\n",
+ fprintf(vvp_out, " %%ix/get%s %d, %u, %u;\n",
sign_flag, res, sv.base, sv.wid);
- fprintf(vvp_out, " %%cvt/ri %d, %d;\n", res, res);
+ fprintf(vvp_out, " %%cvt/ri %d, %d;\n", res, res);
} else {
fprintf(stderr, "XXXX Evaluate real expression (%d)\n",
View
2 tgt-vvp/vvp_process.c
@@ -394,7 +394,7 @@ static int show_stmt_assign_sig_real(ivl_statement_t net)
assert(ivl_signal_array_count(var) == 1);
- fprintf(vvp_out, " %%set/wr v%p_0, %d;\n", var, res);
+ fprintf(vvp_out, " %%set/wr v%p_0, %d;\n", var, res);
return 0;
}
View
1 vvp/codes.h
@@ -47,6 +47,7 @@ extern bool of_ASSIGN_V0X1D(vthread_t thr, vvp_code_t code);
extern bool of_ASSIGN_WR(vthread_t thr, vvp_code_t code);
extern bool of_ASSIGN_X0(vthread_t thr, vvp_code_t code);
extern bool of_BLEND(vthread_t thr, vvp_code_t code);
+extern bool of_BLEND_WR(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);
View
3 vvp/compile.cc
@@ -95,7 +95,8 @@ const static struct opcode_table_s opcode_table[] = {
{ "%assign/v0/x1/d",of_ASSIGN_V0X1D,3,{OA_FUNC_PTR,OA_BIT1,OA_BIT2} },
{ "%assign/wr",of_ASSIGN_WR,3,{OA_VPI_PTR,OA_BIT1, OA_BIT2} },
{ "%assign/x0",of_ASSIGN_X0,3,{OA_FUNC_PTR,OA_BIT1, OA_BIT2} },
- { "%blend", of_BLEND, 3, {OA_BIT1, OA_BIT2, OA_NUMBER} },
+ { "%blend", of_BLEND, 3, {OA_BIT1, OA_BIT2, OA_NUMBER} },
+ { "%blend/wr", of_BLEND_WR,2, {OA_BIT1, OA_BIT2, OA_NONE} },
{ "%breakpoint", of_BREAKPOINT, 0, {OA_NONE, OA_NONE, OA_NONE} },
{ "%cassign/link",of_CASSIGN_LINK,2,{OA_FUNC_PTR,OA_FUNC_PTR2,OA_NONE} },
{ "%cassign/v",of_CASSIGN_V,3,{OA_FUNC_PTR,OA_BIT1, OA_BIT2} },
View
5 vvp/opcodes.txt
@@ -139,6 +139,11 @@ manner like the expression (x ? <a> : <b>). The truth table is:
In other words, if the bits are identical, then take that
value. Otherwise, the value is x.
+* %blend/wr <bit-l>, <bit-r>
+
+This instruction blends real values for the ternary operator. If the
+values match return that otherwise return 0.0.
+
* %breakpoint
This instruction unconditionally breaks the simulator into the
View
8 vvp/vthread.cc
@@ -738,6 +738,14 @@ bool of_BLEND(vthread_t thr, vvp_code_t cp)
return true;
}
+bool of_BLEND_WR(vthread_t thr, vvp_code_t cp)
+{
+ double t = thr->words[cp->bit_idx[0]].w_real;
+ double f = thr->words[cp->bit_idx[1]].w_real;
+ thr->words[cp->bit_idx[0]].w_real = (t == f) ? t : 0.0;
+ return true;
+}
+
bool of_BREAKPOINT(vthread_t thr, vvp_code_t cp)
{
return true;

0 comments on commit fe72d02

Please sign in to comment.
Something went wrong with that request. Please try again.