Merge branch 'master' of github.com:steveicarus/iverilog
This commit is contained in:
commit
75c78c7c5b
|
|
@ -1,7 +1,7 @@
|
|||
#ifndef __compiler_H
|
||||
#define __compiler_H
|
||||
/*
|
||||
* Copyright (c) 1999-2011 Stephen Williams (steve@icarus.com)
|
||||
* Copyright (c) 1999-2013 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
|
||||
|
|
@ -107,6 +107,10 @@ extern bool debug_optimizer;
|
|||
/* Possibly temporary flag to control virtualization of pin arrays */
|
||||
extern bool disable_virtual_pins;
|
||||
|
||||
/* The vlog95 code generator does not want the compiler to generate concat-Z
|
||||
* LPM objects so this flag is used to block them from being generated. */
|
||||
extern bool disable_concatz_generation;
|
||||
|
||||
/* Limit to size of devirtualized arrays */
|
||||
extern unsigned long array_size_limit;
|
||||
|
||||
|
|
|
|||
|
|
@ -176,11 +176,12 @@ void PGAssign::elaborate(Design*des, NetScope*scope) const
|
|||
need_driver_flag = false;
|
||||
}
|
||||
|
||||
/* When we are given a non-default strength value and if the
|
||||
* drive source is a bit, part or indexed select we need to
|
||||
* add a driver (BUFZ) to convey the strength information. */
|
||||
/* When we are given a non-default strength value and if the drive
|
||||
* source is a bit, part, indexed select or a concatenation we need
|
||||
* to add a driver (BUFZ) to convey the strength information. */
|
||||
if ((drive0 != IVL_DR_STRONG || drive1 != IVL_DR_STRONG) &&
|
||||
(dynamic_cast<NetESelect*>(rval_expr))) {
|
||||
((dynamic_cast<NetESelect*>(rval_expr)) ||
|
||||
(dynamic_cast<NetEConcat*>(rval_expr)))) {
|
||||
need_driver_flag = true;
|
||||
}
|
||||
|
||||
|
|
|
|||
487
eval_tree.cc
487
eval_tree.cc
|
|
@ -34,6 +34,18 @@ NetExpr* NetExpr::eval_tree()
|
|||
return 0;
|
||||
}
|
||||
|
||||
static void eval_debug(const NetExpr*expr, NetExpr*res, bool is_real)
|
||||
{
|
||||
if (res != 0) {
|
||||
res->set_line(*expr);
|
||||
if (debug_eval_tree) {
|
||||
cerr << expr->get_fileline() << ": debug: Evaluated";
|
||||
if (is_real) cerr << " (real)";
|
||||
cerr << ": " << *expr << " --> " << *res << endl;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static bool get_real_arg_(const NetExpr*expr, verireal&val)
|
||||
{
|
||||
switch (expr->expr_type()) {
|
||||
|
|
@ -82,18 +94,7 @@ NetExpr* NetEBinary::eval_tree()
|
|||
eval_expr(left_);
|
||||
eval_expr(right_);
|
||||
|
||||
NetExpr*res = eval_arguments_(left_, right_);
|
||||
if (res != 0) {
|
||||
res->set_line(*this);
|
||||
if (debug_eval_tree) {
|
||||
cerr << get_fileline() << ": debug: Evaluated";
|
||||
if (left_->expr_type() == IVL_VT_REAL ||
|
||||
right_->expr_type() == IVL_VT_REAL)
|
||||
cerr << " (real)";
|
||||
cerr << ": " << *this << " --> " << *res << endl;
|
||||
}
|
||||
}
|
||||
return res;
|
||||
return eval_arguments_(left_, right_);
|
||||
}
|
||||
|
||||
NetExpr* NetEBinary::eval_arguments_(const NetExpr*, const NetExpr*) const
|
||||
|
|
@ -126,6 +127,7 @@ NetECReal* NetEBAdd::eval_tree_real_(const NetExpr*l, const NetExpr*r) const
|
|||
|
||||
NetECReal*res = new NetECReal( verireal(res_val) );
|
||||
ivl_assert(*this, res);
|
||||
eval_debug(this, res, true);
|
||||
return res;
|
||||
}
|
||||
|
||||
|
|
@ -136,17 +138,7 @@ NetExpr* NetEBAdd::eval_tree()
|
|||
|
||||
// First try to elaborate the expression completely.
|
||||
NetExpr*res = eval_arguments_(left_,right_);
|
||||
if (res != 0) {
|
||||
res->set_line(*this);
|
||||
if (debug_eval_tree) {
|
||||
cerr << get_fileline() << ": debug: Evaluated";
|
||||
if (left_->expr_type() == IVL_VT_REAL ||
|
||||
right_->expr_type() == IVL_VT_REAL)
|
||||
cerr << " (real)";
|
||||
cerr << ": " << *this << " --> " << *res << endl;
|
||||
}
|
||||
return res;
|
||||
}
|
||||
if (res != 0) return res;
|
||||
|
||||
// If the expression type is real, then do not attempt the
|
||||
// following alternative processing.
|
||||
|
|
@ -236,6 +228,7 @@ NetExpr* NetEBAdd::eval_arguments_(const NetExpr*l, const NetExpr*r) const
|
|||
|
||||
NetEConst *res = new NetEConst(val);
|
||||
ivl_assert(*this, res);
|
||||
eval_debug(this, res, false);
|
||||
return res;
|
||||
}
|
||||
|
||||
|
|
@ -257,6 +250,7 @@ NetEConst* NetEBBits::eval_arguments_(const NetExpr*l, const NetExpr*r) const
|
|||
verinum res (verinum::V0, expr_width());
|
||||
NetEConst*tmp = new NetEConst(res);
|
||||
ivl_assert(*this, tmp);
|
||||
eval_debug(this, tmp, false);
|
||||
return tmp;
|
||||
}
|
||||
|
||||
|
|
@ -264,6 +258,7 @@ NetEConst* NetEBBits::eval_arguments_(const NetExpr*l, const NetExpr*r) const
|
|||
verinum res (verinum::V0, expr_width());
|
||||
NetEConst*tmp = new NetEConst(res);
|
||||
ivl_assert(*this, tmp);
|
||||
eval_debug(this, tmp, false);
|
||||
return tmp;
|
||||
}
|
||||
|
||||
|
|
@ -306,6 +301,7 @@ NetEConst* NetEBBits::eval_arguments_(const NetExpr*l, const NetExpr*r) const
|
|||
|
||||
NetEConst*tmp = new NetEConst(res);
|
||||
ivl_assert(*this, tmp);
|
||||
eval_debug(this, tmp, false);
|
||||
return tmp;
|
||||
}
|
||||
|
||||
|
|
@ -754,6 +750,8 @@ NetEConst* NetEBComp::eval_arguments_(const NetExpr*l, const NetExpr*r) const
|
|||
break;
|
||||
|
||||
}
|
||||
eval_debug(this, res, l->expr_type() == IVL_VT_REAL ||
|
||||
r->expr_type() == IVL_VT_REAL);
|
||||
return res;
|
||||
}
|
||||
|
||||
|
|
@ -780,6 +778,7 @@ NetExpr* NetEBDiv::eval_tree_real_(const NetExpr*l, const NetExpr*r) const
|
|||
}
|
||||
NetECReal*res = new NetECReal( verireal(res_val) );
|
||||
ivl_assert(*this, res);
|
||||
eval_debug(this, res, true);
|
||||
return res;
|
||||
}
|
||||
|
||||
|
|
@ -813,6 +812,7 @@ NetExpr* NetEBDiv::eval_arguments_(const NetExpr*l, const NetExpr*r) const
|
|||
}
|
||||
NetExpr*tmp = new NetEConst(val);
|
||||
ivl_assert(*this, tmp);
|
||||
eval_debug(this, tmp, false);
|
||||
return tmp;
|
||||
}
|
||||
|
||||
|
|
@ -846,6 +846,7 @@ NetEConst* NetEBLogic::eval_tree_real_(const NetExpr*l, const NetExpr*r) const
|
|||
|
||||
NetEConst*tmp = new NetEConst(verinum(res, 1));
|
||||
ivl_assert(*this, tmp);
|
||||
eval_debug(this, tmp, true);
|
||||
return tmp;
|
||||
}
|
||||
|
||||
|
|
@ -912,6 +913,7 @@ NetEConst* NetEBLogic::eval_arguments_(const NetExpr*l, const NetExpr*r) const
|
|||
|
||||
NetEConst*tmp = new NetEConst(verinum(res, 1));
|
||||
ivl_assert(*this, tmp);
|
||||
eval_debug(this, tmp, false);
|
||||
return tmp;
|
||||
}
|
||||
|
||||
|
|
@ -937,6 +939,7 @@ NetExpr* NetEBMinMax::eval_tree_real_(const NetExpr*l, const NetExpr*r) const
|
|||
|
||||
NetECReal*res = new NetECReal( verireal(res_val) );
|
||||
ivl_assert(*this, res);
|
||||
eval_debug(this, res, true);
|
||||
return res;
|
||||
}
|
||||
|
||||
|
|
@ -974,6 +977,7 @@ NetExpr* NetEBMinMax::eval_arguments_(const NetExpr*l, const NetExpr*r) const
|
|||
}
|
||||
NetEConst*res = new NetEConst(res_val);
|
||||
ivl_assert(*this, res);
|
||||
eval_debug(this, res, false);
|
||||
return res;
|
||||
}
|
||||
|
||||
|
|
@ -987,6 +991,7 @@ NetExpr* NetEBMult::eval_tree_real_(const NetExpr*l, const NetExpr*r) const
|
|||
|
||||
NetECReal*res = new NetECReal( verireal(lval * rval) );
|
||||
ivl_assert(*this, res);
|
||||
eval_debug(this, res, true);
|
||||
return res;
|
||||
}
|
||||
|
||||
|
|
@ -1010,6 +1015,7 @@ NetExpr* NetEBMult::eval_arguments_(const NetExpr*l, const NetExpr*r) const
|
|||
verinum val(lval * rval, wid);
|
||||
NetEConst*tmp = new NetEConst(val);
|
||||
ivl_assert(*this, tmp);
|
||||
eval_debug(this, tmp, false);
|
||||
return tmp;
|
||||
}
|
||||
|
||||
|
|
@ -1023,6 +1029,7 @@ NetExpr* NetEBPow::eval_tree_real_(const NetExpr*l, const NetExpr*r) const
|
|||
|
||||
NetECReal*res = new NetECReal( verireal( pow(lval,rval) ) );
|
||||
ivl_assert(*this, res);
|
||||
eval_debug(this, res, true);
|
||||
return res;
|
||||
}
|
||||
|
||||
|
|
@ -1045,6 +1052,7 @@ NetExpr* NetEBPow::eval_arguments_(const NetExpr*l, const NetExpr*r) const
|
|||
verinum val(pow(lval, rval), wid);
|
||||
NetEConst*res = new NetEConst(val);
|
||||
ivl_assert(*this, res);
|
||||
eval_debug(this, res, false);
|
||||
return res;
|
||||
}
|
||||
|
||||
|
|
@ -1085,19 +1093,14 @@ NetEConst* NetEBShift::eval_arguments_(const NetExpr*l, const NetExpr*r) const
|
|||
val.has_sign(has_sign());
|
||||
res = new NetEConst(val);
|
||||
ivl_assert(*this, res);
|
||||
eval_debug(this, res, false);
|
||||
return res;
|
||||
}
|
||||
|
||||
NetEConst* NetEConcat::eval_tree()
|
||||
{
|
||||
unsigned repeat_val = repeat();
|
||||
unsigned local_errors = 0;
|
||||
|
||||
if (debug_eval_tree) {
|
||||
cerr << get_fileline() << ": debug: Evaluating expression:"
|
||||
<< *this << endl;
|
||||
}
|
||||
|
||||
unsigned gap = 0;
|
||||
for (unsigned idx = 0 ; idx < parms_.size() ; idx += 1) {
|
||||
|
||||
|
|
@ -1141,6 +1144,14 @@ NetEConst* NetEConcat::eval_tree()
|
|||
|
||||
if (local_errors > 0) return 0;
|
||||
|
||||
return eval_arguments_(parms_, gap);
|
||||
}
|
||||
|
||||
NetEConst* NetEConcat::eval_arguments_(const vector<NetExpr*>&vals,
|
||||
unsigned gap) const
|
||||
{
|
||||
unsigned repeat_val = repeat();
|
||||
|
||||
// At this point, the "gap" is the width of a single repeat of
|
||||
// the concatenation. The total width of the result is the gap
|
||||
// times the repeat count.
|
||||
|
|
@ -1150,8 +1161,8 @@ NetEConst* NetEConcat::eval_tree()
|
|||
|
||||
unsigned cur = 0;
|
||||
bool is_string_flag = true;
|
||||
for (unsigned idx = parms_.size() ; idx > 0 ; idx -= 1) {
|
||||
NetEConst*expr = dynamic_cast<NetEConst*>(parms_[idx-1]);
|
||||
for (unsigned idx = vals.size() ; idx > 0 ; idx -= 1) {
|
||||
const NetEConst*expr = dynamic_cast<NetEConst*>(vals[idx-1]);
|
||||
if (expr == 0)
|
||||
return 0;
|
||||
|
||||
|
|
@ -1176,16 +1187,13 @@ NetEConst* NetEConcat::eval_tree()
|
|||
val.has_sign( this->has_sign() );
|
||||
|
||||
NetEConst*res = new NetEConst(val);
|
||||
ivl_assert(*this, res);
|
||||
eval_debug(this, res, false);
|
||||
return res;
|
||||
}
|
||||
|
||||
NetEConst* NetESelect::eval_tree()
|
||||
{
|
||||
if (debug_eval_tree) {
|
||||
cerr << get_fileline() << ": debug: Evaluating expression:"
|
||||
<< *this << endl;
|
||||
}
|
||||
|
||||
eval_expr(expr_);
|
||||
NetEConst*expr = dynamic_cast<NetEConst*>(expr_);
|
||||
|
||||
|
|
@ -1228,6 +1236,7 @@ NetEConst* NetESelect::eval_tree()
|
|||
oval.has_sign(has_sign());
|
||||
|
||||
NetEConst*res = new NetEConst(oval);
|
||||
eval_debug(this, res, false);
|
||||
return res;
|
||||
}
|
||||
|
||||
|
|
@ -1376,17 +1385,7 @@ NetExpr*NetETernary::blended_arguments_(const NetExpr*te, const NetExpr*fe) cons
|
|||
NetExpr* NetEUnary::eval_tree()
|
||||
{
|
||||
eval_expr(expr_);
|
||||
NetExpr*res = eval_arguments_(expr_);
|
||||
if (res != 0) {
|
||||
res->set_line(*this);
|
||||
if (debug_eval_tree) {
|
||||
cerr << get_fileline() << ": debug: Evaluated";
|
||||
if (expr_->expr_type() == IVL_VT_REAL)
|
||||
cerr << " (real)";
|
||||
cerr << ": " << *this << " --> " << *res << endl;
|
||||
}
|
||||
}
|
||||
return res;
|
||||
return eval_arguments_(expr_);
|
||||
}
|
||||
|
||||
NetExpr* NetEUnary::eval_tree_real_(const NetExpr*ex) const
|
||||
|
|
@ -1412,6 +1411,7 @@ NetExpr* NetEUnary::eval_tree_real_(const NetExpr*ex) const
|
|||
}
|
||||
NetECReal *res = new NetECReal( verireal(res_val) );
|
||||
ivl_assert(*this, res);
|
||||
eval_debug(this, res, true);
|
||||
return res;
|
||||
}
|
||||
|
||||
|
|
@ -1478,6 +1478,7 @@ NetExpr* NetEUnary::eval_arguments_(const NetExpr*ex) const
|
|||
|
||||
NetEConst *res = new NetEConst(val);
|
||||
ivl_assert(*this, res);
|
||||
eval_debug(this, res, false);
|
||||
return res;
|
||||
}
|
||||
|
||||
|
|
@ -1494,6 +1495,7 @@ NetEConst* NetEUReduce::eval_tree_real_(const NetExpr*ex) const
|
|||
|
||||
NetEConst*tmp = new NetEConst(verinum(res, 1));
|
||||
ivl_assert(*this, tmp);
|
||||
eval_debug(this, tmp, true);
|
||||
return tmp;
|
||||
}
|
||||
|
||||
|
|
@ -1585,15 +1587,14 @@ NetEConst* NetEUReduce::eval_arguments_(const NetExpr*ex) const
|
|||
|
||||
NetEConst*tmp = new NetEConst(verinum(res, 1));
|
||||
ivl_assert(*this, tmp);
|
||||
eval_debug(this, tmp, false);
|
||||
return tmp;
|
||||
}
|
||||
|
||||
static NetEConst* evaluate_clog2(NetExpr*&arg_)
|
||||
NetEConst* NetESFunc::evaluate_clog2_(const NetExpr*arg_) const
|
||||
{
|
||||
eval_expr(arg_);
|
||||
|
||||
NetEConst*tmpi = dynamic_cast<NetEConst *>(arg_);
|
||||
NetECReal*tmpr = dynamic_cast<NetECReal *>(arg_);
|
||||
const NetEConst*tmpi = dynamic_cast<const NetEConst*>(arg_);
|
||||
const NetECReal*tmpr = dynamic_cast<const NetECReal*>(arg_);
|
||||
|
||||
if (tmpi == 0 && tmpr == 0) return 0;
|
||||
|
||||
|
|
@ -1612,7 +1613,7 @@ static NetEConst* evaluate_clog2(NetExpr*&arg_)
|
|||
tmp.has_sign(true);
|
||||
|
||||
rtn = new NetEConst(tmp);
|
||||
ivl_assert(*arg_, rtn);
|
||||
ivl_assert(*this, rtn);
|
||||
} else {
|
||||
bool is_neg = false;
|
||||
uint64_t res = 0;
|
||||
|
|
@ -1641,18 +1642,17 @@ static NetEConst* evaluate_clog2(NetExpr*&arg_)
|
|||
tmp.has_sign(true);
|
||||
|
||||
rtn = new NetEConst(tmp);
|
||||
ivl_assert(*arg_, rtn);
|
||||
ivl_assert(*this, rtn);
|
||||
}
|
||||
|
||||
eval_debug(this, rtn, false);
|
||||
return rtn;
|
||||
}
|
||||
|
||||
static NetECReal* evaluate_math_one_arg(NetExpr*&arg_, const char*name)
|
||||
NetECReal* NetESFunc::evaluate_math_one_arg_(ID id, const NetExpr*arg_) const
|
||||
{
|
||||
eval_expr(arg_);
|
||||
|
||||
NetEConst*tmpi = dynamic_cast<NetEConst *>(arg_);
|
||||
NetECReal*tmpr = dynamic_cast<NetECReal *>(arg_);
|
||||
const NetEConst*tmpi = dynamic_cast<const NetEConst*>(arg_);
|
||||
const NetECReal*tmpr = dynamic_cast<const NetECReal*>(arg_);
|
||||
|
||||
NetECReal*res = 0;
|
||||
|
||||
|
|
@ -1664,79 +1664,79 @@ static NetECReal* evaluate_math_one_arg(NetExpr*&arg_, const char*name)
|
|||
arg = tmpr->value().as_double();
|
||||
}
|
||||
|
||||
if (strcmp(name, "$ln") == 0) {
|
||||
switch (id) {
|
||||
case LN:
|
||||
res = new NetECReal(verireal(log(arg)));
|
||||
ivl_assert(*arg_, res);
|
||||
} else if (strcmp(name, "$log10") == 0) {
|
||||
break;
|
||||
case LOG10:
|
||||
res = new NetECReal(verireal(log10(arg)));
|
||||
ivl_assert(*arg_, res);
|
||||
} else if (strcmp(name, "$exp") == 0) {
|
||||
break;
|
||||
case EXP:
|
||||
res = new NetECReal(verireal(exp(arg)));
|
||||
ivl_assert(*arg_, res);
|
||||
} else if (strcmp(name, "$sqrt") == 0) {
|
||||
break;
|
||||
case SQRT:
|
||||
res = new NetECReal(verireal(sqrt(arg)));
|
||||
ivl_assert(*arg_, res);
|
||||
} else if (strcmp(name, "$floor") == 0) {
|
||||
break;
|
||||
case FLOOR:
|
||||
res = new NetECReal(verireal(floor(arg)));
|
||||
ivl_assert(*arg_, res);
|
||||
} else if (strcmp(name, "$ceil") == 0) {
|
||||
break;
|
||||
case CEIL:
|
||||
res = new NetECReal(verireal(ceil(arg)));
|
||||
ivl_assert(*arg_, res);
|
||||
} else if (strcmp(name, "$sin") == 0) {
|
||||
break;
|
||||
case SIN:
|
||||
res = new NetECReal(verireal(sin(arg)));
|
||||
ivl_assert(*arg_, res);
|
||||
} else if (strcmp(name, "$cos") == 0) {
|
||||
break;
|
||||
case COS:
|
||||
res = new NetECReal(verireal(cos(arg)));
|
||||
ivl_assert(*arg_, res);
|
||||
} else if (strcmp(name, "$tan") == 0) {
|
||||
break;
|
||||
case TAN:
|
||||
res = new NetECReal(verireal(tan(arg)));
|
||||
ivl_assert(*arg_, res);
|
||||
} else if (strcmp(name, "$asin") == 0) {
|
||||
break;
|
||||
case ASIN:
|
||||
res = new NetECReal(verireal(asin(arg)));
|
||||
ivl_assert(*arg_, res);
|
||||
} else if (strcmp(name, "$acos") == 0) {
|
||||
break;
|
||||
case ACOS:
|
||||
res = new NetECReal(verireal(acos(arg)));
|
||||
ivl_assert(*arg_, res);
|
||||
} else if (strcmp(name, "$atan") == 0) {
|
||||
break;
|
||||
case ATAN:
|
||||
res = new NetECReal(verireal(atan(arg)));
|
||||
ivl_assert(*arg_, res);
|
||||
} else if (strcmp(name, "$sinh") == 0) {
|
||||
break;
|
||||
case SINH:
|
||||
res = new NetECReal(verireal(sinh(arg)));
|
||||
ivl_assert(*arg_, res);
|
||||
} else if (strcmp(name, "$cosh") == 0) {
|
||||
break;
|
||||
case COSH:
|
||||
res = new NetECReal(verireal(cosh(arg)));
|
||||
ivl_assert(*arg_, res);
|
||||
} else if (strcmp(name, "$tanh") == 0) {
|
||||
break;
|
||||
case TANH:
|
||||
res = new NetECReal(verireal(tanh(arg)));
|
||||
ivl_assert(*arg_, res);
|
||||
} else if (strcmp(name, "$asinh") == 0) {
|
||||
break;
|
||||
case ASINH:
|
||||
res = new NetECReal(verireal(asinh(arg)));
|
||||
ivl_assert(*arg_, res);
|
||||
} else if (strcmp(name, "$acosh") == 0) {
|
||||
break;
|
||||
case ACOSH:
|
||||
res = new NetECReal(verireal(acosh(arg)));
|
||||
ivl_assert(*arg_, res);
|
||||
} else if (strcmp(name, "$atanh") == 0) {
|
||||
break;
|
||||
case ATANH:
|
||||
res = new NetECReal(verireal(atanh(arg)));
|
||||
ivl_assert(*arg_, res);
|
||||
} else {
|
||||
cerr << arg_->get_fileline() << ": warning: Unhandled"
|
||||
"constant system function " << name << "." << endl;
|
||||
break;
|
||||
default:
|
||||
ivl_assert(*this, 0);
|
||||
break;
|
||||
}
|
||||
ivl_assert(*this, res);
|
||||
}
|
||||
|
||||
eval_debug(this, res, true);
|
||||
return res;
|
||||
}
|
||||
|
||||
static NetECReal* evaluate_math_two_args(NetExpr*&arg0_, NetExpr*&arg1_,
|
||||
const char*name)
|
||||
NetECReal* NetESFunc::evaluate_math_two_arg_(ID id, const NetExpr*arg0_,
|
||||
const NetExpr*arg1_) const
|
||||
{
|
||||
eval_expr(arg0_);
|
||||
eval_expr(arg1_);
|
||||
|
||||
NetEConst*tmpi0 = dynamic_cast<NetEConst *>(arg0_);
|
||||
NetECReal*tmpr0 = dynamic_cast<NetECReal *>(arg0_);
|
||||
NetEConst*tmpi1 = dynamic_cast<NetEConst *>(arg1_);
|
||||
NetECReal*tmpr1 = dynamic_cast<NetECReal *>(arg1_);
|
||||
const NetEConst*tmpi0 = dynamic_cast<const NetEConst*>(arg0_);
|
||||
const NetECReal*tmpr0 = dynamic_cast<const NetECReal*>(arg0_);
|
||||
const NetEConst*tmpi1 = dynamic_cast<const NetEConst*>(arg1_);
|
||||
const NetECReal*tmpr1 = dynamic_cast<const NetECReal*>(arg1_);
|
||||
|
||||
NetECReal*res = 0;
|
||||
|
||||
|
|
@ -1753,73 +1753,78 @@ static NetECReal* evaluate_math_two_args(NetExpr*&arg0_, NetExpr*&arg1_,
|
|||
arg1 = tmpr1->value().as_double();
|
||||
}
|
||||
|
||||
if (strcmp(name, "$pow") == 0) {
|
||||
switch (id) {
|
||||
case POW:
|
||||
res = new NetECReal(verireal(pow(arg0, arg1)));
|
||||
ivl_assert(*arg0_, res);
|
||||
} else if (strcmp(name, "$atan2") == 0) {
|
||||
break;
|
||||
case ATAN2:
|
||||
res = new NetECReal(verireal(atan2(arg0, arg1)));
|
||||
ivl_assert(*arg0_, res);
|
||||
} else if (strcmp(name, "$hypot") == 0) {
|
||||
break;
|
||||
case HYPOT:
|
||||
res = new NetECReal(verireal(hypot(arg0, arg1)));
|
||||
ivl_assert(*arg0_, res);
|
||||
} else {
|
||||
cerr << arg0_->get_fileline() << ": warning: Unhandled"
|
||||
"constant system function " << name << "." << endl;
|
||||
break;
|
||||
default:
|
||||
ivl_assert(*this, 0);
|
||||
break;
|
||||
}
|
||||
ivl_assert(*this, res);
|
||||
}
|
||||
|
||||
eval_debug(this, res, true);
|
||||
return res;
|
||||
}
|
||||
|
||||
static NetExpr* evaluate_abs(NetExpr*&arg_)
|
||||
NetExpr* NetESFunc::evaluate_abs_(const NetExpr*arg_) const
|
||||
{
|
||||
eval_expr(arg_);
|
||||
|
||||
NetExpr*res = 0;
|
||||
|
||||
NetEConst*tmpi = dynamic_cast<NetEConst *>(arg_);
|
||||
const NetEConst*tmpi = dynamic_cast<const NetEConst*>(arg_);
|
||||
if (tmpi) {
|
||||
verinum arg = tmpi->value();
|
||||
if (arg.is_negative()) {
|
||||
arg = v_not(arg) + verinum(1);
|
||||
}
|
||||
res = new NetEConst(arg);
|
||||
ivl_assert(*arg_, res);
|
||||
ivl_assert(*this, res);
|
||||
}
|
||||
|
||||
NetECReal*tmpr = dynamic_cast<NetECReal *>(arg_);
|
||||
const NetECReal*tmpr = dynamic_cast<const NetECReal*>(arg_);
|
||||
if (tmpr) {
|
||||
double arg = tmpr->value().as_double();
|
||||
res = new NetECReal(verireal(fabs(arg)));
|
||||
ivl_assert(*arg_, res);
|
||||
ivl_assert(*this, res);
|
||||
}
|
||||
|
||||
eval_debug(this, res, tmpr != 0);
|
||||
return res;
|
||||
}
|
||||
|
||||
static NetExpr* evaluate_min_max(NetExpr*&arg0_, NetExpr*&arg1_,
|
||||
const char*name)
|
||||
NetExpr* NetESFunc::evaluate_min_max_(ID id, const NetExpr*arg0_,
|
||||
const NetExpr*arg1_) const
|
||||
{
|
||||
eval_expr(arg0_);
|
||||
eval_expr(arg1_);
|
||||
|
||||
NetEConst*tmpi0 = dynamic_cast<NetEConst *>(arg0_);
|
||||
NetECReal*tmpr0 = dynamic_cast<NetECReal *>(arg0_);
|
||||
NetEConst*tmpi1 = dynamic_cast<NetEConst *>(arg1_);
|
||||
NetECReal*tmpr1 = dynamic_cast<NetECReal *>(arg1_);
|
||||
const NetEConst*tmpi0 = dynamic_cast<const NetEConst*>(arg0_);
|
||||
const NetECReal*tmpr0 = dynamic_cast<const NetECReal*>(arg0_);
|
||||
const NetEConst*tmpi1 = dynamic_cast<const NetEConst*>(arg1_);
|
||||
const NetECReal*tmpr1 = dynamic_cast<const NetECReal*>(arg1_);
|
||||
|
||||
NetExpr*res = 0;
|
||||
|
||||
if (tmpi0 && tmpi1) {
|
||||
verinum arg0 = tmpi0->value();
|
||||
verinum arg1 = tmpi1->value();
|
||||
if (strcmp(name, "$min") == 0) {
|
||||
switch (id) {
|
||||
case MIN:
|
||||
res = new NetEConst( arg0 < arg1 ? arg0 : arg1);
|
||||
ivl_assert(*arg0_, res);
|
||||
} else if (strcmp(name, "$max") == 0) {
|
||||
break;
|
||||
case MAX:
|
||||
res = new NetEConst( arg0 < arg1 ? arg1 : arg0);
|
||||
ivl_assert(*arg0_, res);
|
||||
break;
|
||||
default:
|
||||
ivl_assert(*this, 0);
|
||||
break;
|
||||
}
|
||||
ivl_assert(*this, res);
|
||||
|
||||
} else if ((tmpi0 || tmpr0) && (tmpi1 || tmpr1)) {
|
||||
double arg0, arg1;
|
||||
if (tmpi0) {
|
||||
|
|
@ -1832,118 +1837,128 @@ static NetExpr* evaluate_min_max(NetExpr*&arg0_, NetExpr*&arg1_,
|
|||
} else {
|
||||
arg1 = tmpr1->value().as_double();
|
||||
}
|
||||
if (strcmp(name, "$min") == 0) {
|
||||
switch (id) {
|
||||
case MIN:
|
||||
res = new NetECReal(verireal(arg0 < arg1 ? arg0 : arg1));
|
||||
ivl_assert(*arg0_, res);
|
||||
} else if (strcmp(name, "$max") == 0) {
|
||||
break;
|
||||
case MAX:
|
||||
res = new NetECReal(verireal(arg0 < arg1 ? arg1 : arg0));
|
||||
ivl_assert(*arg0_, res);
|
||||
} else {
|
||||
cerr << arg0_->get_fileline() << ": warning: Unhandled"
|
||||
"constant system function " << name << "." << endl;
|
||||
break;
|
||||
default:
|
||||
ivl_assert(*this, 0);
|
||||
break;
|
||||
}
|
||||
ivl_assert(*this, res);
|
||||
}
|
||||
|
||||
eval_debug(this, res, tmpr0 || tmpr1);
|
||||
return res;
|
||||
}
|
||||
|
||||
NetExpr* NetESFunc::evaluate_one_arg_(ID id, const NetExpr*arg) const
|
||||
{
|
||||
switch (id) {
|
||||
case ABS:
|
||||
return evaluate_abs_(arg);
|
||||
case CLOG2:
|
||||
return evaluate_clog2_(arg);
|
||||
default:
|
||||
return evaluate_math_one_arg_(id, arg);
|
||||
}
|
||||
}
|
||||
|
||||
NetExpr* NetESFunc::evaluate_two_arg_(ID id, const NetExpr*arg0,
|
||||
const NetExpr*arg1) const
|
||||
{
|
||||
switch (id) {
|
||||
case MIN:
|
||||
case MAX:
|
||||
return evaluate_min_max_(id, arg0, arg1);
|
||||
default:
|
||||
return evaluate_math_two_arg_(id, arg0, arg1);
|
||||
}
|
||||
}
|
||||
|
||||
NetESFunc::ID NetESFunc::built_in_id_() const
|
||||
{
|
||||
/* If we are not targeting at least Verilog-2005, Verilog-AMS
|
||||
* or using the Icarus misc flag then we do not treat these
|
||||
* functions as built-in. */
|
||||
if (generation_flag < GN_VER2005 &&
|
||||
!gn_icarus_misc_flag && !gn_verilog_ams_flag) {
|
||||
return NOT_BUILT_IN;
|
||||
}
|
||||
|
||||
static map<string,ID> built_in_func;
|
||||
|
||||
if (built_in_func.empty()) {
|
||||
built_in_func["$clog2"] = CLOG2;
|
||||
built_in_func["$ln" ] = LN;
|
||||
built_in_func["$log10"] = LOG10;
|
||||
built_in_func["$exp" ] = EXP;
|
||||
built_in_func["$sqrt" ] = SQRT;
|
||||
built_in_func["$floor"] = FLOOR;
|
||||
built_in_func["$ceil" ] = CEIL;
|
||||
built_in_func["$sin" ] = SIN;
|
||||
built_in_func["$cos" ] = COS;
|
||||
built_in_func["$tan" ] = TAN;
|
||||
built_in_func["$asin" ] = ASIN;
|
||||
built_in_func["$acos" ] = ACOS;
|
||||
built_in_func["$atan" ] = ATAN;
|
||||
built_in_func["$sinh" ] = SINH;
|
||||
built_in_func["$cosh" ] = COSH;
|
||||
built_in_func["$tanh" ] = TANH;
|
||||
built_in_func["$asinh"] = ASINH;
|
||||
built_in_func["$acosh"] = ACOSH;
|
||||
built_in_func["$atanh"] = ATANH;
|
||||
built_in_func["$abs" ] = ABS;
|
||||
built_in_func["$pow" ] = POW;
|
||||
built_in_func["$atan2"] = ATAN2;
|
||||
built_in_func["$hypot"] = HYPOT;
|
||||
built_in_func["$min" ] = MIN;
|
||||
built_in_func["$max" ] = MAX;
|
||||
}
|
||||
|
||||
map<string,ID>::iterator idx = built_in_func.find(name_);
|
||||
if (idx == built_in_func.end())
|
||||
return NOT_BUILT_IN;
|
||||
|
||||
ID id = idx->second;
|
||||
|
||||
if (is_ams_(id) && !gn_icarus_misc_flag && !gn_verilog_ams_flag)
|
||||
return NOT_BUILT_IN;
|
||||
|
||||
return id;
|
||||
}
|
||||
|
||||
NetExpr* NetESFunc::eval_tree()
|
||||
{
|
||||
/* If we are not targeting at least Verilog-2005, Verilog-AMS
|
||||
* or using the Icarus misc flag then we do not support these
|
||||
* functions as constant. */
|
||||
if (generation_flag < GN_VER2005 &&
|
||||
!gn_icarus_misc_flag && !gn_verilog_ams_flag) {
|
||||
ID id = built_in_id_();
|
||||
if (id == NOT_BUILT_IN)
|
||||
return 0;
|
||||
|
||||
switch (nargs_(id)) {
|
||||
case 1:
|
||||
if (parms_.size() != 1) {
|
||||
cerr << get_fileline() << ": error: " << name_
|
||||
<< " takes one argument." << endl;
|
||||
return 0;
|
||||
}
|
||||
eval_expr(parms_[0]);
|
||||
return evaluate_one_arg_(id, parms_[0]);
|
||||
case 2:
|
||||
if (parms_.size() != 2) {
|
||||
cerr << get_fileline() << ": error: " << name_
|
||||
<< " takes two arguments." << endl;
|
||||
return 0;
|
||||
}
|
||||
eval_expr(parms_[0]);
|
||||
eval_expr(parms_[1]);
|
||||
return evaluate_two_arg_(id, parms_[0], parms_[1]);
|
||||
default:
|
||||
ivl_assert(*this, 0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
const char*nm = name();
|
||||
NetExpr*rtn = 0;
|
||||
/* Only $clog2 and the builtin mathematical functions can
|
||||
* be a constant system function. */
|
||||
if (strcmp(nm, "$clog2") == 0 ||
|
||||
strcmp(nm, "$ln") == 0 ||
|
||||
strcmp(nm, "$log10") == 0 ||
|
||||
strcmp(nm, "$exp") == 0 ||
|
||||
strcmp(nm, "$sqrt") == 0 ||
|
||||
strcmp(nm, "$floor") == 0 ||
|
||||
strcmp(nm, "$ceil") == 0 ||
|
||||
strcmp(nm, "$sin") == 0 ||
|
||||
strcmp(nm, "$cos") == 0 ||
|
||||
strcmp(nm, "$tan") == 0 ||
|
||||
strcmp(nm, "$asin") == 0 ||
|
||||
strcmp(nm, "$acos") == 0 ||
|
||||
strcmp(nm, "$atan") == 0 ||
|
||||
strcmp(nm, "$sinh") == 0 ||
|
||||
strcmp(nm, "$cosh") == 0 ||
|
||||
strcmp(nm, "$tanh") == 0 ||
|
||||
strcmp(nm, "$asinh") == 0 ||
|
||||
strcmp(nm, "$acosh") == 0 ||
|
||||
strcmp(nm, "$atanh") == 0) {
|
||||
if (nparms() != 1 || parm(0) == 0) {
|
||||
cerr << get_fileline() << ": error: " << nm
|
||||
<< " takes a single argument." << endl;
|
||||
return 0;
|
||||
}
|
||||
NetExpr*arg = parm(0)->dup_expr();
|
||||
if (strcmp(nm, "$clog2") == 0) {
|
||||
rtn = evaluate_clog2(arg);
|
||||
} else {
|
||||
rtn = evaluate_math_one_arg(arg, nm);
|
||||
}
|
||||
delete arg;
|
||||
}
|
||||
|
||||
if (strcmp(nm, "$pow") == 0 ||
|
||||
strcmp(nm, "$atan2") == 0 ||
|
||||
strcmp(nm, "$hypot") == 0) {
|
||||
if (nparms() != 2 || parm(0) == 0 || parm(1) == 0) {
|
||||
cerr << get_fileline() << ": error: " << nm
|
||||
<< " takes two arguments." << endl;
|
||||
return 0;
|
||||
}
|
||||
NetExpr*arg0 = parm(0)->dup_expr();
|
||||
NetExpr*arg1 = parm(1)->dup_expr();
|
||||
rtn = evaluate_math_two_args(arg0, arg1, nm);
|
||||
delete arg0;
|
||||
delete arg1;
|
||||
}
|
||||
|
||||
if ((gn_icarus_misc_flag || gn_verilog_ams_flag) &&
|
||||
(strcmp(nm, "$abs") == 0)) {
|
||||
if (nparms() != 1 || parm(0) == 0) {
|
||||
cerr << get_fileline() << ": error: " << nm
|
||||
<< " takes a single argument." << endl;
|
||||
return 0;
|
||||
}
|
||||
NetExpr*arg = parm(0)->dup_expr();
|
||||
rtn = evaluate_abs(arg);
|
||||
delete arg;
|
||||
}
|
||||
|
||||
if ((gn_icarus_misc_flag || gn_verilog_ams_flag) &&
|
||||
(strcmp(nm, "$min") == 0 || strcmp(nm, "$max") == 0)) {
|
||||
if (nparms() != 2 || parm(0) == 0 || parm(1) == 0) {
|
||||
cerr << get_fileline() << ": error: " << nm
|
||||
<< " takes two arguments." << endl;
|
||||
return 0;
|
||||
}
|
||||
NetExpr*arg0 = parm(0)->dup_expr();
|
||||
NetExpr*arg1 = parm(1)->dup_expr();
|
||||
rtn = evaluate_min_max(arg0, arg1, nm);
|
||||
delete arg0;
|
||||
delete arg1;
|
||||
}
|
||||
|
||||
if (rtn != 0) {
|
||||
rtn->set_line(*this);
|
||||
|
||||
if (debug_eval_tree)
|
||||
cerr << get_fileline() << ": debug: Evaluated: " << *this
|
||||
<< " --> " << *rtn << endl;
|
||||
}
|
||||
|
||||
return rtn;
|
||||
}
|
||||
|
||||
NetExpr* NetEUFunc::eval_tree()
|
||||
|
|
|
|||
6
main.cc
6
main.cc
|
|
@ -1,5 +1,5 @@
|
|||
const char COPYRIGHT[] =
|
||||
"Copyright (c) 1998-2012 Stephen Williams (steve@icarus.com)";
|
||||
"Copyright (c) 1998-2013 Stephen Williams (steve@icarus.com)";
|
||||
|
||||
/*
|
||||
* This source code is free software; you can redistribute it
|
||||
|
|
@ -175,6 +175,7 @@ bool debug_optimizer = false;
|
|||
bool disable_virtual_pins = false;
|
||||
unsigned long array_size_limit = 16777216; // Minimum required by IEEE-1364?
|
||||
unsigned recursive_mod_limit = 10;
|
||||
bool disable_concatz_generation = false;
|
||||
|
||||
/*
|
||||
* Verbose messages enabled.
|
||||
|
|
@ -967,6 +968,9 @@ int main(int argc, char*argv[])
|
|||
flag_tmp = flags["RECURSIVE_MOD_LIMIT"];
|
||||
if (flag_tmp) recursive_mod_limit = strtoul(flag_tmp,NULL,0);
|
||||
|
||||
flag_tmp = flags["DISABLE_CONCATZ_GENERATION"];
|
||||
if (flag_tmp) disable_concatz_generation = strcmp(flag_tmp,"true")==0;
|
||||
|
||||
/* Parse the input. Make the pform. */
|
||||
pform_set_timescale(def_ts_units, def_ts_prec, 0, 0);
|
||||
int rc = pform_parse(argv[optind]);
|
||||
|
|
|
|||
|
|
@ -55,8 +55,10 @@ NetExpr* NetFuncDef::evaluate_function(const LineInfo&loc, const std::vector<Net
|
|||
// fills in the context_map with local variables held by the scope.
|
||||
scope_->evaluate_function_find_locals(loc, context_map);
|
||||
|
||||
// Perform the evaluation
|
||||
bool flag = statement_->evaluate_function(loc, context_map);
|
||||
// Perform the evaluation. Note that if there were errors
|
||||
// when compiling the function definition, we may not have
|
||||
// a valid statement.
|
||||
bool flag = statement_ && statement_->evaluate_function(loc, context_map);
|
||||
|
||||
// Extract the result...
|
||||
ptr = context_map.find(scope_->basename());
|
||||
|
|
@ -280,21 +282,38 @@ NetExpr* NetEBinary::evaluate_function(const LineInfo&loc,
|
|||
}
|
||||
|
||||
NetExpr*res = eval_arguments_(lval, rval);
|
||||
if (res != 0) {
|
||||
res->set_line(*this);
|
||||
if (debug_eval_tree) {
|
||||
cerr << get_fileline() << ": debug: Evaluated";
|
||||
if (lval->expr_type() == IVL_VT_REAL ||
|
||||
rval->expr_type() == IVL_VT_REAL)
|
||||
cerr << " (real)";
|
||||
cerr << ": " << *this << " --> " << *res << endl;
|
||||
}
|
||||
}
|
||||
delete lval;
|
||||
delete rval;
|
||||
return res;
|
||||
}
|
||||
|
||||
NetExpr* NetEConcat::evaluate_function(const LineInfo&loc,
|
||||
map<perm_string,NetExpr*>&context_map) const
|
||||
{
|
||||
vector<NetExpr*>vals(parms_.size());
|
||||
unsigned gap = 0;
|
||||
|
||||
unsigned valid_vals = 0;
|
||||
for (unsigned idx = 0 ; idx < parms_.size() ; idx += 1) {
|
||||
ivl_assert(*this, parms_[idx]);
|
||||
vals[idx] = parms_[idx]->evaluate_function(loc, context_map);
|
||||
if (vals[idx] == 0) continue;
|
||||
|
||||
gap += vals[idx]->expr_width();
|
||||
|
||||
valid_vals += 1;
|
||||
}
|
||||
|
||||
NetExpr*res = 0;
|
||||
if (valid_vals == parms_.size()) {
|
||||
res = eval_arguments_(vals, gap);
|
||||
}
|
||||
for (unsigned idx = 0 ; idx < vals.size() ; idx += 1) {
|
||||
delete vals[idx];
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
NetExpr* NetEConst::evaluate_function(const LineInfo&,
|
||||
map<perm_string,NetExpr*>&) const
|
||||
{
|
||||
|
|
@ -397,19 +416,45 @@ NetExpr* NetEUnary::evaluate_function(const LineInfo&loc,
|
|||
if (val == 0) return 0;
|
||||
|
||||
NetExpr*res = eval_arguments_(val);
|
||||
if (res != 0) {
|
||||
res->set_line(*this);
|
||||
if (debug_eval_tree) {
|
||||
cerr << get_fileline() << ": debug: Evaluated";
|
||||
if (val->expr_type() == IVL_VT_REAL)
|
||||
cerr << " (real)";
|
||||
cerr << ": " << *this << " --> " << *res << endl;
|
||||
}
|
||||
}
|
||||
delete val;
|
||||
return res;
|
||||
}
|
||||
|
||||
NetExpr* NetESFunc::evaluate_function(const LineInfo&loc,
|
||||
map<perm_string,NetExpr*>&context_map) const
|
||||
{
|
||||
ID id = built_in_id_();
|
||||
if (id == NOT_BUILT_IN) {
|
||||
cerr << get_fileline() << ": error: " << name_
|
||||
<< " is not a built-in function, so cannot"
|
||||
<< " be used in a constant function." << endl;
|
||||
return 0;
|
||||
}
|
||||
|
||||
NetExpr*val0 = 0;
|
||||
NetExpr*val1 = 0;
|
||||
NetExpr*res = 0;
|
||||
switch (nargs_(id)) {
|
||||
case 1:
|
||||
val0 = parms_[0]->evaluate_function(loc, context_map);
|
||||
if (val0 == 0) break;
|
||||
res = evaluate_one_arg_(id, val0);
|
||||
break;
|
||||
case 2:
|
||||
val0 = parms_[0]->evaluate_function(loc, context_map);
|
||||
val1 = parms_[1]->evaluate_function(loc, context_map);
|
||||
if (val0 == 0 || val1 == 0) break;
|
||||
res = evaluate_two_arg_(id, val0, val1);
|
||||
break;
|
||||
default:
|
||||
ivl_assert(*this, 0);
|
||||
break;
|
||||
}
|
||||
delete val0;
|
||||
delete val1;
|
||||
return res;
|
||||
}
|
||||
|
||||
NetExpr* NetEUFunc::evaluate_function(const LineInfo&loc,
|
||||
map<perm_string,NetExpr*>&context_map) const
|
||||
{
|
||||
|
|
|
|||
38
netlist.h
38
netlist.h
|
|
@ -3789,6 +3789,8 @@ class NetEConcat : public NetExpr {
|
|||
virtual bool has_width() const;
|
||||
virtual NetEConcat* dup_expr() const;
|
||||
virtual NetEConst* eval_tree();
|
||||
virtual NetExpr* evaluate_function(const LineInfo&loc,
|
||||
std::map<perm_string,NetExpr*>&ctx) const;
|
||||
virtual NetNet*synthesize(Design*, NetScope*scope, NetExpr*root);
|
||||
virtual void expr_scan(struct expr_scan_t*) const;
|
||||
virtual void dump(ostream&) const;
|
||||
|
|
@ -3797,6 +3799,8 @@ class NetEConcat : public NetExpr {
|
|||
std::vector<NetExpr*>parms_;
|
||||
unsigned repeat_;
|
||||
ivl_variable_type_t expr_type_;
|
||||
|
||||
NetEConst* eval_arguments_(const vector<NetExpr*>&vals, unsigned gap) const;
|
||||
};
|
||||
|
||||
|
||||
|
|
@ -4001,6 +4005,8 @@ class NetESFunc : public NetExpr {
|
|||
const NetExpr* parm(unsigned idx) const;
|
||||
|
||||
virtual NetExpr* eval_tree();
|
||||
virtual NetExpr* evaluate_function(const LineInfo&loc,
|
||||
std::map<perm_string,NetExpr*>&ctx) const;
|
||||
|
||||
virtual ivl_variable_type_t expr_type() const;
|
||||
virtual NexusSet* nex_input(bool rem_out = true);
|
||||
|
|
@ -4012,11 +4018,43 @@ class NetESFunc : public NetExpr {
|
|||
virtual NetNet*synthesize(Design*, NetScope*scope, NetExpr*root);
|
||||
|
||||
private:
|
||||
enum ID { NOT_BUILT_IN = 0x0,
|
||||
MATH_ONE_ARG = 0x100,
|
||||
CLOG2, LN, LOG10, EXP, SQRT, FLOOR, CEIL,
|
||||
SIN, COS, TAN, ASIN, ACOS, ATAN,
|
||||
SINH, COSH, TANH, ASINH, ACOSH, ATANH,
|
||||
AMS_ONE_ARG = 0x180,
|
||||
ABS,
|
||||
MATH_TWO_ARG = 0x200,
|
||||
POW, ATAN2, HYPOT,
|
||||
AMS_TWO_ARG = 0x280,
|
||||
MIN, MAX };
|
||||
|
||||
bool is_ams_(ID id) const { return id & 0x80; };
|
||||
unsigned nargs_(ID id) const { return id >> 8; };
|
||||
|
||||
const char* name_;
|
||||
ivl_variable_type_t type_;
|
||||
netenum_t*enum_type_;
|
||||
std::vector<NetExpr*>parms_;
|
||||
|
||||
ID built_in_id_() const;
|
||||
|
||||
NetExpr* evaluate_one_arg_(ID id, const NetExpr*arg) const;
|
||||
NetExpr* evaluate_two_arg_(ID id, const NetExpr*arg0,
|
||||
const NetExpr*arg1) const;
|
||||
|
||||
NetEConst* evaluate_clog2_(const NetExpr*arg) const;
|
||||
|
||||
NetECReal* evaluate_math_one_arg_(ID id, const NetExpr*arg) const;
|
||||
NetECReal* evaluate_math_two_arg_(ID id, const NetExpr*arg0,
|
||||
const NetExpr*arg1) const;
|
||||
|
||||
NetExpr* evaluate_abs_(const NetExpr*arg) const;
|
||||
|
||||
NetExpr* evaluate_min_max_(ID id, const NetExpr*arg0,
|
||||
const NetExpr*arg1) const;
|
||||
|
||||
private: // not implemented
|
||||
NetESFunc(const NetESFunc&);
|
||||
NetESFunc& operator= (const NetESFunc&);
|
||||
|
|
|
|||
13
netmisc.cc
13
netmisc.cc
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 2001-2012 Stephen Williams (steve@icarus.com)
|
||||
* Copyright (c) 2001-2013 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
|
||||
|
|
@ -1127,6 +1127,17 @@ void collapse_partselect_pv_to_concat(Design*des, NetNet*sig)
|
|||
|
||||
ivl_assert(*sig, idx == ps_map.size());
|
||||
|
||||
/* The vlog95 and possibly other code generators do not want
|
||||
* to have a group of part selects turned into a transparent
|
||||
* concatenation. */
|
||||
if (disable_concatz_generation) {
|
||||
// HERE: If the part selects have matching strengths then we can use
|
||||
// a normal concat with a buf-Z after if the strengths are not
|
||||
// both strong. We would ideally delete any buf-Z driving the
|
||||
// concat, but that is not required for the vlog95 generator.
|
||||
return;
|
||||
}
|
||||
|
||||
// Ah HAH! The NetPartSelect::PV objects exactly cover the
|
||||
// target signal. We can replace all of them with a single
|
||||
// concatenation.
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (C) 2011-2012 Cary R. (cygcary@yahoo.com)
|
||||
* Copyright (C) 2011-2013 Cary R. (cygcary@yahoo.com)
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
|
|
@ -105,6 +105,8 @@ static void emit_expr_binary(ivl_scope_t scope, ivl_expr_t expr, unsigned wid)
|
|||
case 'l': oper = "<<"; break;
|
||||
case 'r': oper = ">>"; break;
|
||||
case 'R': oper = ">>>"; break;
|
||||
case 'm': oper = "<"; break;
|
||||
case 'M': oper = ">"; break;
|
||||
}
|
||||
|
||||
fprintf(vlog_out, "(");
|
||||
|
|
@ -174,6 +176,20 @@ static void emit_expr_binary(ivl_scope_t scope, ivl_expr_t expr, unsigned wid)
|
|||
vlog_errors += 1;
|
||||
}
|
||||
break;
|
||||
/* Convert Verilog-A min() or max() functions. This only works
|
||||
* when the arguments have no side effect. */
|
||||
case 'm':
|
||||
case 'M':
|
||||
fprintf(vlog_out, "((");
|
||||
emit_expr(scope, ivl_expr_oper1(expr), wid);
|
||||
fprintf(vlog_out, ") %s (", oper);
|
||||
emit_expr(scope, ivl_expr_oper2(expr), wid);
|
||||
fprintf(vlog_out, ") ? (");
|
||||
emit_expr(scope, ivl_expr_oper1(expr), wid);
|
||||
fprintf(vlog_out, ") : (");
|
||||
emit_expr(scope, ivl_expr_oper2(expr), wid);
|
||||
fprintf(vlog_out, "))");
|
||||
break;
|
||||
default:
|
||||
emit_expr(scope, ivl_expr_oper1(expr), wid);
|
||||
fprintf(vlog_out, "<unknown>");
|
||||
|
|
@ -381,6 +397,16 @@ static void emit_expr_select(ivl_scope_t scope, ivl_expr_t expr, unsigned wid)
|
|||
ivl_expr_t sel_expr = ivl_expr_oper2(expr);
|
||||
ivl_expr_t sig_expr = ivl_expr_oper1(expr);
|
||||
ivl_select_type_t sel_type = ivl_expr_sel_type(expr);
|
||||
/* If this is a dynamic array select, translate it differently. */
|
||||
if ((ivl_expr_type(sig_expr) == IVL_EX_SIGNAL) &&
|
||||
(ivl_signal_data_type(ivl_expr_signal(sig_expr)) == IVL_VT_DARRAY)) {
|
||||
assert(sel_expr);
|
||||
emit_select_name(scope, sig_expr, wid);
|
||||
fprintf(vlog_out, "[");
|
||||
emit_expr(scope, sel_expr, 0);
|
||||
fprintf(vlog_out, "]");
|
||||
return;
|
||||
}
|
||||
if (sel_expr) {
|
||||
unsigned width = ivl_expr_width(expr);
|
||||
ivl_expr_type_t type = ivl_expr_type(sig_expr);
|
||||
|
|
@ -456,6 +482,9 @@ static void emit_expr_func(ivl_scope_t scope, ivl_expr_t expr, unsigned wid)
|
|||
}
|
||||
emit_expr(scope, ivl_expr_parm(expr, count), 0);
|
||||
fprintf(vlog_out, ")");
|
||||
/* User functions without arguments are not supported. */
|
||||
} else if (ivl_expr_type(expr) == IVL_EX_UFUNC) {
|
||||
fprintf(vlog_out, "()");
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -558,6 +587,20 @@ static void emit_expr_unary(ivl_scope_t scope, ivl_expr_t expr, unsigned wid)
|
|||
ivl_expr_lineno(expr));
|
||||
vlog_errors += 1;
|
||||
break;
|
||||
/* Convert Verilog-A abs() function. This only works when the
|
||||
* argument has no side effect. */
|
||||
case 'm':
|
||||
fprintf(vlog_out, "((");
|
||||
emit_expr(scope, ivl_expr_oper1(expr), wid);
|
||||
fprintf(vlog_out, ") > ");
|
||||
if (ivl_expr_value(expr) == IVL_VT_REAL) fprintf(vlog_out, "0.0");
|
||||
else fprintf(vlog_out, "0");
|
||||
fprintf(vlog_out, " ? (");
|
||||
emit_expr(scope, ivl_expr_oper1(expr), wid);
|
||||
fprintf(vlog_out, ") : -(");
|
||||
emit_expr(scope, ivl_expr_oper1(expr), wid);
|
||||
fprintf(vlog_out, "))");
|
||||
break;
|
||||
default:
|
||||
fprintf(vlog_out, "<unknown>");
|
||||
emit_expr(scope, ivl_expr_oper1(expr), wid);
|
||||
|
|
@ -571,6 +614,17 @@ static void emit_expr_unary(ivl_scope_t scope, ivl_expr_t expr, unsigned wid)
|
|||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Class properties are not supported in vlog95, but they can be translated.
|
||||
*/
|
||||
void emit_class_property(ivl_scope_t scope, ivl_expr_t expr, unsigned wid)
|
||||
{
|
||||
ivl_signal_t sig = ivl_expr_signal(expr);
|
||||
emit_scope_call_path(scope, ivl_signal_scope(sig));
|
||||
emit_id(ivl_signal_basename(sig));
|
||||
fprintf(vlog_out, ".%s", ivl_expr_name(expr));
|
||||
}
|
||||
|
||||
void emit_expr(ivl_scope_t scope, ivl_expr_t expr, unsigned wid)
|
||||
{
|
||||
switch (ivl_expr_type(expr)) {
|
||||
|
|
@ -597,11 +651,30 @@ void emit_expr(ivl_scope_t scope, ivl_expr_t expr, unsigned wid)
|
|||
case IVL_EX_EVENT:
|
||||
emit_expr_event(scope, expr, wid);
|
||||
break;
|
||||
case IVL_EX_NEW:
|
||||
fprintf(vlog_out, "<new>");
|
||||
fprintf(stderr, "%s:%u: vlog95 error: New operator "
|
||||
"is not supported.\n",
|
||||
ivl_expr_file(expr),
|
||||
ivl_expr_lineno(expr));
|
||||
vlog_errors += 1;
|
||||
break;
|
||||
case IVL_EX_NULL:
|
||||
fprintf(vlog_out, "<null>");
|
||||
fprintf(stderr, "%s:%u: vlog95 error: Null operator "
|
||||
"is not supported.\n",
|
||||
ivl_expr_file(expr),
|
||||
ivl_expr_lineno(expr));
|
||||
vlog_errors += 1;
|
||||
break;
|
||||
case IVL_EX_NUMBER:
|
||||
emit_number(ivl_expr_bits(expr), ivl_expr_width(expr),
|
||||
ivl_expr_signed(expr), ivl_expr_file(expr),
|
||||
ivl_expr_lineno(expr));
|
||||
break;
|
||||
case IVL_EX_PROPERTY:
|
||||
emit_class_property(scope, expr, wid);
|
||||
break;
|
||||
case IVL_EX_REALNUM:
|
||||
emit_real_number(ivl_expr_dvalue(expr));
|
||||
break;
|
||||
|
|
|
|||
|
|
@ -108,10 +108,53 @@ static void emit_gate_strength(ivl_net_logic_t nlogic, unsigned strength_type)
|
|||
"gate", ivl_logic_file(nlogic), ivl_logic_lineno(nlogic));
|
||||
}
|
||||
|
||||
/*
|
||||
* Look for a single driver behind an LPM that passes strength information
|
||||
* and get the real drive information from it.
|
||||
*/
|
||||
static void get_unique_lpm_drive(ivl_lpm_t lpm, ivl_drive_t *drive1,
|
||||
ivl_drive_t *drive0)
|
||||
{
|
||||
ivl_nexus_t nex = ivl_lpm_data(lpm, 0);
|
||||
unsigned idx, count = ivl_nexus_ptrs(nex);
|
||||
unsigned have_driver = 0;
|
||||
|
||||
for (idx = 0; idx < count; idx += 1) {
|
||||
ivl_nexus_ptr_t nex_ptr = ivl_nexus_ptr(nex, idx);
|
||||
ivl_drive_t cur_drive1 = ivl_nexus_ptr_drive1(nex_ptr);
|
||||
ivl_drive_t cur_drive0 = ivl_nexus_ptr_drive0(nex_ptr);
|
||||
if ((cur_drive1 == IVL_DR_HiZ) &&
|
||||
(cur_drive0 == IVL_DR_HiZ)) continue;
|
||||
assert(! have_driver);
|
||||
*drive1 = cur_drive1;
|
||||
*drive0 = cur_drive0;
|
||||
have_driver = 1;
|
||||
}
|
||||
|
||||
/* This should never happen. */
|
||||
if (! have_driver) {
|
||||
fprintf(stderr, "%s:%u: vlog95 error: Unable to find drive "
|
||||
"information for strength transparent LPM.\n",
|
||||
ivl_lpm_file(lpm), ivl_lpm_lineno(lpm));
|
||||
vlog_errors += 1;
|
||||
}
|
||||
}
|
||||
|
||||
static void emit_lpm_strength(ivl_lpm_t lpm)
|
||||
{
|
||||
emit_strength(ivl_lpm_drive1(lpm), ivl_lpm_drive0(lpm), 2,
|
||||
"LPM", ivl_lpm_file(lpm), ivl_lpm_lineno(lpm));
|
||||
ivl_lpm_type_t type = ivl_lpm_type(lpm);
|
||||
ivl_drive_t drive1 = IVL_DR_STRONG;
|
||||
ivl_drive_t drive0 = IVL_DR_STRONG;
|
||||
/* This LPM object passes strength information so we need to look
|
||||
* for the strength information at the real driver. */
|
||||
if (type == IVL_LPM_PART_PV) {
|
||||
get_unique_lpm_drive(lpm, &drive1, &drive0);
|
||||
} else {
|
||||
drive1 = ivl_lpm_drive1(lpm);
|
||||
drive0 = ivl_lpm_drive0(lpm);
|
||||
}
|
||||
emit_strength(drive1, drive0, 2, "LPM",
|
||||
ivl_lpm_file(lpm), ivl_lpm_lineno(lpm));
|
||||
}
|
||||
|
||||
static void emit_delay(ivl_scope_t scope, ivl_expr_t rise, ivl_expr_t fall,
|
||||
|
|
@ -193,6 +236,7 @@ static ivl_nexus_t get_lpm_output(ivl_scope_t scope, ivl_lpm_t lpm)
|
|||
{
|
||||
ivl_nexus_t output = 0;
|
||||
switch (ivl_lpm_type(lpm)) {
|
||||
case IVL_LPM_ABS:
|
||||
case IVL_LPM_ADD:
|
||||
case IVL_LPM_ARRAY:
|
||||
case IVL_LPM_CAST_INT:
|
||||
|
|
@ -213,6 +257,7 @@ static ivl_nexus_t get_lpm_output(ivl_scope_t scope, ivl_lpm_t lpm)
|
|||
case IVL_LPM_MUX:
|
||||
case IVL_LPM_PART_PV:
|
||||
case IVL_LPM_PART_VP:
|
||||
case IVL_LPM_POW:
|
||||
case IVL_LPM_RE_AND:
|
||||
case IVL_LPM_RE_NAND:
|
||||
case IVL_LPM_RE_NOR:
|
||||
|
|
@ -773,6 +818,19 @@ static void emit_lpm_func(ivl_scope_t scope, ivl_lpm_t lpm)
|
|||
static void emit_lpm_as_ca(ivl_scope_t scope, ivl_lpm_t lpm)
|
||||
{
|
||||
switch (ivl_lpm_type(lpm)) {
|
||||
/* Convert Verilog-A abs() function. This only works when the
|
||||
* argument has no side effect. */
|
||||
case IVL_LPM_ABS:
|
||||
fprintf(vlog_out, "((");
|
||||
emit_nexus_as_ca(scope, ivl_lpm_data(lpm, 0), 0);
|
||||
fprintf(vlog_out, ") > ");
|
||||
// HERE: If this is a real net then use 0.0. See the expr code.
|
||||
fprintf(vlog_out, "0 ? (");
|
||||
emit_nexus_as_ca(scope, ivl_lpm_data(lpm, 0), 0);
|
||||
fprintf(vlog_out, ") : -(");
|
||||
emit_nexus_as_ca(scope, ivl_lpm_data(lpm, 0), 0);
|
||||
fprintf(vlog_out, "))");
|
||||
break;
|
||||
case IVL_LPM_ADD:
|
||||
fprintf(vlog_out, "(");
|
||||
emit_nexus_as_ca(scope, ivl_lpm_data(lpm, 0), 0);
|
||||
|
|
@ -830,8 +888,14 @@ static void emit_lpm_as_ca(ivl_scope_t scope, ivl_lpm_t lpm)
|
|||
emit_nexus_as_ca(scope, ivl_lpm_data(lpm, 1), 0);
|
||||
fprintf(vlog_out, ")");
|
||||
break;
|
||||
case IVL_LPM_CONCAT:
|
||||
/* A concat-Z should never be generated, but report it as an
|
||||
* error if one is generated. */
|
||||
case IVL_LPM_CONCATZ:
|
||||
fprintf(stderr, "%s:%u: vlog95 error: Transparent concatenations "
|
||||
"should not be generated.\n",
|
||||
ivl_lpm_file(lpm), ivl_lpm_lineno(lpm));
|
||||
vlog_errors += 1;
|
||||
case IVL_LPM_CONCAT:
|
||||
emit_lpm_concat(scope, lpm);
|
||||
break;
|
||||
case IVL_LPM_DIVIDE:
|
||||
|
|
@ -877,6 +941,17 @@ static void emit_lpm_as_ca(ivl_scope_t scope, ivl_lpm_t lpm)
|
|||
case IVL_LPM_PART_VP:
|
||||
emit_lpm_part_select(scope, lpm);
|
||||
break;
|
||||
case IVL_LPM_POW:
|
||||
fprintf(vlog_out, "(");
|
||||
emit_nexus_as_ca(scope, ivl_lpm_data(lpm, 0), 0);
|
||||
fprintf(vlog_out, " ** ");
|
||||
emit_nexus_as_ca(scope, ivl_lpm_data(lpm, 1), 0);
|
||||
fprintf(vlog_out, ")");
|
||||
fprintf(stderr, "%s:%u: vlog95 error: Power operator is not "
|
||||
"supported.\n",
|
||||
ivl_lpm_file(lpm), ivl_lpm_lineno(lpm));
|
||||
vlog_errors += 1;
|
||||
break;
|
||||
case IVL_LPM_RE_AND:
|
||||
fprintf(vlog_out, "(&");
|
||||
emit_nexus_as_ca(scope, ivl_lpm_data(lpm, 0), 0);
|
||||
|
|
|
|||
|
|
@ -717,7 +717,14 @@ int emit_scope(ivl_scope_t scope, ivl_scope_t parent)
|
|||
case IVL_SCT_FUNCTION:
|
||||
assert(indent != 0);
|
||||
fprintf(vlog_out, "\n%*cfunction", indent, ' ');
|
||||
assert(ivl_scope_ports(scope) >= 2);
|
||||
if (ivl_scope_ports(scope) < 2) {
|
||||
fprintf(stderr, "%s:%u: vlog95 error: Function (%s) has "
|
||||
"no argments (or return value).\n",
|
||||
ivl_scope_file(scope),
|
||||
ivl_scope_lineno(scope),
|
||||
ivl_scope_tname(scope));
|
||||
vlog_errors += 1;
|
||||
}
|
||||
/* The function return information is the zero port. */
|
||||
emit_func_return(ivl_scope_port(scope, 0));
|
||||
fprintf(vlog_out, " ");
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (C) 2011-2012 Cary R. (cygcary@yahoo.com)
|
||||
* Copyright (C) 2011-2013 Cary R. (cygcary@yahoo.com)
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
|
|
@ -174,6 +174,39 @@ static void emit_stmt_lval_ips(ivl_scope_t scope, ivl_lval_t lval,
|
|||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Dynamic arrays are not supported in vlog95, but this assignment can be
|
||||
* translated correctly.
|
||||
*/
|
||||
static void emit_stmt_lval_darray(ivl_scope_t scope, ivl_lval_t lval,
|
||||
ivl_signal_t sig)
|
||||
{
|
||||
ivl_expr_t idx = ivl_lval_idx(lval);
|
||||
emit_scope_call_path(scope, ivl_signal_scope(sig));
|
||||
emit_id(ivl_signal_basename(sig));
|
||||
if (idx) {
|
||||
fprintf(vlog_out, "[");
|
||||
emit_expr(scope, idx, 0);
|
||||
fprintf(vlog_out, "]");
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Class or class properties are not supported in vlog95, but this assignment
|
||||
* can be translated correctly.
|
||||
*/
|
||||
static void emit_stmt_lval_class(ivl_scope_t scope, ivl_lval_t lval,
|
||||
ivl_signal_t sig)
|
||||
{
|
||||
int idx = ivl_lval_property_idx(lval);
|
||||
emit_scope_call_path(scope, ivl_signal_scope(sig));
|
||||
emit_id(ivl_signal_basename(sig));
|
||||
if (idx >= 0) {
|
||||
ivl_type_t sig_type = ivl_signal_net_type(sig);
|
||||
fprintf(vlog_out, ".%s", ivl_type_prop_name(sig_type, idx));
|
||||
}
|
||||
}
|
||||
|
||||
static void emit_stmt_lval_piece(ivl_scope_t scope, ivl_lval_t lval)
|
||||
{
|
||||
ivl_signal_t sig = ivl_lval_sig(lval);
|
||||
|
|
@ -182,6 +215,18 @@ static void emit_stmt_lval_piece(ivl_scope_t scope, ivl_lval_t lval)
|
|||
unsigned width = ivl_lval_width(lval);
|
||||
int msb, lsb;
|
||||
assert(width > 0);
|
||||
assert(sig);
|
||||
|
||||
switch (ivl_signal_data_type(sig)) {
|
||||
case IVL_VT_DARRAY:
|
||||
emit_stmt_lval_darray(scope, lval, sig);
|
||||
return;
|
||||
case IVL_VT_CLASS:
|
||||
emit_stmt_lval_class(scope, lval, sig);
|
||||
return;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
/* If there are no selects then just print the name. */
|
||||
sel_expr = ivl_lval_part_off(lval);
|
||||
|
|
@ -688,6 +733,9 @@ static void emit_port(ivl_scope_t scope, struct port_expr_s port_expr)
|
|||
* appropriate task call. It returns true (1) if it successfully
|
||||
* translated the block to a task call, otherwise it returns false
|
||||
* (0) to indicate the block needs to be emitted.
|
||||
*
|
||||
* When calling automatic tasks there is an initial ALLOC statement
|
||||
* and a final FREE statement.
|
||||
*/
|
||||
static unsigned is_utask_call_with_args(ivl_scope_t scope,
|
||||
ivl_statement_t stmt)
|
||||
|
|
@ -695,17 +743,31 @@ static unsigned is_utask_call_with_args(ivl_scope_t scope,
|
|||
unsigned idx, ports, task_idx = 0;
|
||||
unsigned count = ivl_stmt_block_count(stmt);
|
||||
unsigned lineno = ivl_stmt_lineno(stmt);
|
||||
unsigned start, stop, is_auto = 0;
|
||||
ivl_scope_t task_scope = 0;
|
||||
port_expr_t port_exprs;
|
||||
/* Check to see if the block is of the basic form first. */
|
||||
for (idx = 0; idx < count; idx += 1) {
|
||||
ivl_statement_t tmp = ivl_stmt_block_stmt(stmt, idx);
|
||||
/* For an automatic task the ALLOC must be first. */
|
||||
if (ivl_statement_type(tmp) == IVL_ST_ALLOC) {
|
||||
if (idx == 0) {
|
||||
is_auto = 1;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
if (ivl_statement_type(tmp) == IVL_ST_ASSIGN) continue;
|
||||
if (ivl_statement_type(tmp) == IVL_ST_UTASK && !task_scope) {
|
||||
task_idx = idx;
|
||||
task_scope = ivl_stmt_call(tmp);
|
||||
assert(ivl_scope_type(task_scope) == IVL_SCT_TASK);
|
||||
continue;
|
||||
}
|
||||
/* For an automatic task the FREE must be last. */
|
||||
if (ivl_statement_type(tmp) == IVL_ST_FREE) {
|
||||
if (idx == count-1) {
|
||||
if (is_auto) continue;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -720,8 +782,11 @@ static unsigned is_utask_call_with_args(ivl_scope_t scope,
|
|||
port_exprs[idx].type = IVL_SIP_NONE;
|
||||
port_exprs[idx].expr.rval = 0;
|
||||
}
|
||||
|
||||
/* Check that the input arguments are correct. */
|
||||
for (idx = 0; idx < task_idx; idx += 1) {
|
||||
if (is_auto) start = 1;
|
||||
else start = 0;
|
||||
for (idx = start; idx < task_idx; idx += 1) {
|
||||
ivl_statement_t assign = ivl_stmt_block_stmt(stmt, idx);
|
||||
unsigned port = utask_in_port_idx(task_scope, assign);
|
||||
if ((port == ports) || (lineno != ivl_stmt_lineno(assign))) {
|
||||
|
|
@ -732,7 +797,9 @@ static unsigned is_utask_call_with_args(ivl_scope_t scope,
|
|||
port_exprs[port].expr.rval = ivl_stmt_rval(assign);
|
||||
}
|
||||
/* Check that the output arguments are correct. */
|
||||
for (idx = task_idx + 1; idx < count; idx += 1) {
|
||||
if (is_auto) stop = count-1;
|
||||
else stop = count;
|
||||
for (idx = task_idx + 1; idx < stop; idx += 1) {
|
||||
ivl_statement_t assign = ivl_stmt_block_stmt(stmt, idx);
|
||||
unsigned port = utask_out_port_idx(task_scope, assign);
|
||||
if ((port == ports) || (lineno != ivl_stmt_lineno(assign))) {
|
||||
|
|
|
|||
|
|
@ -2,3 +2,4 @@ functor:synth2
|
|||
functor:synth
|
||||
functor:syn-rules
|
||||
flag:DLL=vlog95.tgt
|
||||
flag:DISABLE_CONCATZ_GENERATION=true
|
||||
|
|
|
|||
|
|
@ -1 +1,2 @@
|
|||
flag:DLL=vlog95.tgt
|
||||
flag:DISABLE_CONCATZ_GENERATION=true
|
||||
|
|
|
|||
Loading…
Reference in New Issue