Merge branch 'master' of ssh://steve-icarus@icarus.com/home/u/icarus/steve/git/verilog
This commit is contained in:
commit
e141d2bb37
68
PDelays.cc
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.
|
||||
*
|
||||
*/
|
||||
|
||||
|
|
|
|||
41
elab_expr.cc
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;
|
||||
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
|||
45
elab_net.cc
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
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
@ -741,7 +742,11 @@ void PGModule::elaborate_scope_mod_(Design*des, Module*mod, NetScope*sc) const
|
|||
|
||||
/* Stash the instance array of scopes into the parent
|
||||
scope. Later elaboration passes will use this vector to
|
||||
further elaborate the array. */
|
||||
further elaborate the array.
|
||||
|
||||
Note that the array is ordered from LSB to MSB. We will use
|
||||
that fact in the main elaborate to connect things in the
|
||||
correct order. */
|
||||
sc->instance_arrays[get_name()] = instances;
|
||||
}
|
||||
|
||||
|
|
|
|||
23
elaborate.cc
23
elaborate.cc
|
|
@ -1037,7 +1037,9 @@ void PGModule::elaborate_mod_(Design*des, Module*rmod, NetScope*scope) const
|
|||
unsigned prts_vector_width = 0;
|
||||
|
||||
for (unsigned inst = 0 ; inst < instance.count() ; inst += 1) {
|
||||
NetScope*inst_scope = instance[inst];
|
||||
// Scan the instances from MSB to LSB. The port
|
||||
// will be assembled in that order as well.
|
||||
NetScope*inst_scope = instance[instance.count()-inst-1];
|
||||
|
||||
// Scan the module sub-ports for this instance...
|
||||
for (unsigned ldx = 0 ; ldx < mport.count() ; ldx += 1) {
|
||||
|
|
@ -2121,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);
|
||||
|
|
@ -2723,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
|
||||
|
|
@ -2769,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);
|
||||
|
|
@ -3764,4 +3754,3 @@ Design* elaborate(list<perm_string>roots)
|
|||
|
||||
return des;
|
||||
}
|
||||
|
||||
|
|
|
|||
357
eval_tree.cc
357
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_()
|
||||
static bool get_real_arg_(NetExpr*expr, verireal&val)
|
||||
{
|
||||
NetExpr*tmp = left_->eval_tree();
|
||||
if (tmp) {
|
||||
delete left_;
|
||||
left_ = tmp;
|
||||
}
|
||||
tmp = right_->eval_tree();
|
||||
if (tmp){
|
||||
delete right_;
|
||||
right_ = tmp;
|
||||
switch (expr->expr_type()) {
|
||||
case IVL_VT_REAL: {
|
||||
NetECReal*c = dynamic_cast<NetECReal*> (expr);
|
||||
if (c == 0) return false;
|
||||
val = c->value();
|
||||
break;
|
||||
}
|
||||
|
||||
case IVL_VT_BOOL:
|
||||
case IVL_VT_LOGIC: {
|
||||
NetEConst*c = dynamic_cast<NetEConst*>(expr);
|
||||
if (c == 0) return false;
|
||||
verinum tmp = c->value();
|
||||
val = verireal(tmp.as_double());
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
assert(0);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool NetEBinary::get_real_arguments_(verireal&lval, verireal&rval)
|
||||
{
|
||||
switch (left_->expr_type()) {
|
||||
case IVL_VT_REAL: {
|
||||
NetECReal*lc = dynamic_cast<NetECReal*> (left_);
|
||||
if (lc == 0) return false;
|
||||
lval = lc->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());
|
||||
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);
|
||||
}
|
||||
|
||||
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,7 +904,8 @@ 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_();
|
||||
|
|
@ -939,9 +913,8 @@ NetExpr* NetEBMult::eval_tree(int prune_to_width)
|
|||
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,7 +937,8 @@ 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_();
|
||||
|
|
@ -972,9 +946,8 @@ NetExpr* NetEBPow::eval_tree(int prune_to_width)
|
|||
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;
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
assert(true_val_);
|
||||
if (0 == dynamic_cast<NetEConst*>(true_val_)) {
|
||||
tmp = true_val_->eval_tree();
|
||||
if (tmp != 0) {
|
||||
delete true_val_;
|
||||
true_val_ = tmp;
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
assert(false_val_);
|
||||
if (0 == dynamic_cast<NetEConst*>(false_val_)) {
|
||||
tmp = false_val_->eval_tree();
|
||||
if (tmp != 0) {
|
||||
delete false_val_;
|
||||
false_val_ = tmp;
|
||||
}
|
||||
}
|
||||
return false_val_->dup_expr();
|
||||
|
||||
|
||||
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 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 (f == 0)
|
||||
return 0;
|
||||
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;
|
||||
|
||||
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,10 +1441,12 @@ 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;
|
||||
}
|
||||
|
|
@ -1515,12 +1454,11 @@ NetExpr* NetEUnary::eval_tree_real_()
|
|||
|
||||
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;
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
||||
|
|
|
|||
11
net_expr.cc
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_);
|
||||
|
||||
|
|
|
|||
|
|
@ -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:"
|
||||
|
|
|
|||
|
|
@ -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_();
|
||||
};
|
||||
|
|
|
|||
62
netmisc.cc
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;
|
||||
}
|
||||
|
|
|
|||
17
netmisc.h
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
|
||||
|
|
|
|||
4
parse.y
4
parse.y
|
|
@ -1,7 +1,7 @@
|
|||
|
||||
%{
|
||||
/*
|
||||
* Copyright (c) 1998-2007 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
|
||||
|
|
@ -595,6 +595,7 @@ delay_value_simple
|
|||
$$ = new PENumber(tmp);
|
||||
FILE_NAME($$, @1);
|
||||
}
|
||||
based_size = 0;
|
||||
}
|
||||
| REALTIME
|
||||
{ verireal*tmp = $1;
|
||||
|
|
@ -2207,6 +2208,7 @@ parameter_value_opt
|
|||
(*lst->by_order)[0] = tmp;
|
||||
lst->by_name = 0;
|
||||
$$ = lst;
|
||||
based_size = 0;
|
||||
}
|
||||
| '#' error
|
||||
{ yyerror(@1, "error: syntax error in parameter value "
|
||||
|
|
|
|||
|
|
@ -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",
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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} },
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
Loading…
Reference in New Issue