Merge branch 'master' of github.com:steveicarus/iverilog

This commit is contained in:
Stephen Williams 2013-02-13 19:51:31 -08:00
commit 75c78c7c5b
13 changed files with 614 additions and 272 deletions

View File

@ -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;

View File

@ -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;
}

View File

@ -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()

View File

@ -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]);

View File

@ -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
{

View File

@ -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&);

View File

@ -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.

View File

@ -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;

View File

@ -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);

View File

@ -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, " ");

View File

@ -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))) {

View File

@ -2,3 +2,4 @@ functor:synth2
functor:synth
functor:syn-rules
flag:DLL=vlog95.tgt
flag:DISABLE_CONCATZ_GENERATION=true

View File

@ -1 +1,2 @@
flag:DLL=vlog95.tgt
flag:DISABLE_CONCATZ_GENERATION=true