Add support for explicit parameter types, including real.

Before this, the types of parameters were always logic, only the
width and signed-ness could be controlled. A parameter may take
on implicit real values if the expression were real.

With this patch, the type for the parameter can be explicitly set
to logic or real. This also means that the parameter real valued
expressions need to be more crefully treated, possibly with casting
integral expressions to real values, or real expressions to integral
values.
This commit is contained in:
Stephen Williams 2008-05-17 16:25:58 -07:00
parent f588656dd5
commit c76e88cad5
14 changed files with 675 additions and 510 deletions

View File

@ -94,10 +94,14 @@ class Module : public PScope, public LineInfo {
module is elaborated. During parsing, I put the parameters module is elaborated. During parsing, I put the parameters
into this map. */ into this map. */
struct param_expr_t : public LineInfo { struct param_expr_t : public LineInfo {
PExpr*expr; param_expr_t() : range(0) { }
// Type information
ivl_variable_type_t type;
PExpr*msb; PExpr*msb;
PExpr*lsb; PExpr*lsb;
bool signed_flag; bool signed_flag;
// Value expression
PExpr*expr;
// If there are range constrants, list them here // If there are range constrants, list them here
range_t*range; range_t*range;
}; };

View File

@ -1290,11 +1290,9 @@ void NetESignal::dump(ostream&o) const
void NetEParam::dump(ostream&o) const void NetEParam::dump(ostream&o) const
{ {
if (scope_ != 0) if (scope_ != 0)
o << "<" << scope_path(scope_) << "." << name_ << ">"; o << "<" << scope_path(scope_) << "." << (*reference_).first << ">";
else if (name_)
o << "<" << name_ << ">";
else else
o << "<" "???" ">"; o << "<" << (*reference_).first << ">";
} }
void NetETernary::dump(ostream&o) const void NetETernary::dump(ostream&o) const

View File

@ -63,9 +63,11 @@ void Module::elaborate_parm_item_(perm_string name, const param_expr_t&cur,
parameter value is coerced to have the correct parameter value is coerced to have the correct
and defined width. */ and defined width. */
if (cur.msb) { if (cur.msb) {
assert(cur.lsb);
msb = cur.msb ->elaborate_pexpr(des, scope); msb = cur.msb ->elaborate_pexpr(des, scope);
assert(msb); assert(msb);
lsb = cur.lsb ->elaborate_pexpr(des, scope); lsb = cur.lsb ->elaborate_pexpr(des, scope);
assert(lsb);
} }
if (signed_flag) { if (signed_flag) {
@ -102,7 +104,7 @@ void Module::elaborate_parm_item_(perm_string name, const param_expr_t&cur,
range_list = tmp; range_list = tmp;
} }
val = scope->set_parameter(name, val, msb, lsb, signed_flag, range_list, cur); val = scope->set_parameter(name, val, cur.type, msb, lsb, signed_flag, range_list, cur);
assert(val); assert(val);
delete val; delete val;
} }
@ -140,7 +142,8 @@ bool Module::elaborate_scope(Design*des, NetScope*scope,
tmp->set_line(*((*cur).second.expr)); tmp->set_line(*((*cur).second.expr));
tmp->cast_signed( (*cur).second.signed_flag ); tmp->cast_signed( (*cur).second.signed_flag );
scope->set_parameter((*cur).first, tmp, 0, 0, false, 0, (*cur).second); scope->set_parameter((*cur).first, tmp, (*cur).second.type,
0, 0, false, 0, (*cur).second);
} }
for (mparm_it_t cur = localparams.begin() for (mparm_it_t cur = localparams.begin()
@ -151,7 +154,8 @@ bool Module::elaborate_scope(Design*des, NetScope*scope,
if ((*cur).second.msb) if ((*cur).second.msb)
tmp->cast_signed( (*cur).second.signed_flag ); tmp->cast_signed( (*cur).second.signed_flag );
scope->set_parameter((*cur).first, tmp, 0, 0, false, 0, (*cur).second); scope->set_parameter((*cur).first, tmp, (*cur).second.type,
0, 0, false, 0, (*cur).second);
} }
@ -183,6 +187,8 @@ bool Module::elaborate_scope(Design*des, NetScope*scope,
<< "Replace " << (*cur).first << "Replace " << (*cur).first
<< " with expression " << *val << " with expression " << *val
<< " from " << val->get_fileline() << "." << endl; << " from " << val->get_fileline() << "." << endl;
cerr << get_fileline() << ": : "
<< "Type=" << val->expr_type() << endl;
} }
bool flag = scope->replace_parameter((*cur).first, val); bool flag = scope->replace_parameter((*cur).first, val);
if (! flag) { if (! flag) {

View File

@ -1171,17 +1171,11 @@ NetExpr* NetEParam::eval_tree(int prune_to_width)
} }
assert(scope_); assert(scope_);
const NetExpr*expr_msb; perm_string name = (*reference_).first;
const NetExpr*expr_lsb; const NetExpr*expr_msb = (*reference_).second.msb;
const NetExpr*expr = scope_->get_parameter(name_, expr_msb, expr_lsb); const NetExpr*expr_lsb = (*reference_).second.lsb;
if (expr == 0) { const NetExpr*expr = (*reference_).second.expr;
cerr << get_fileline() << ": internal error: Unable to match " ivl_assert(*this, expr);
<< "parameter " << name_ << " in scope "
<< scope_path(scope_) << endl;
return 0;
}
assert(expr);
NetExpr*nexpr = expr->dup_expr(); NetExpr*nexpr = expr->dup_expr();
assert(nexpr); assert(nexpr);
@ -1190,7 +1184,7 @@ NetExpr* NetEParam::eval_tree(int prune_to_width)
// return the constant value. // return the constant value.
if (NetEConst*tmp = dynamic_cast<NetEConst*>(nexpr)) { if (NetEConst*tmp = dynamic_cast<NetEConst*>(nexpr)) {
verinum val = tmp->value(); verinum val = tmp->value();
NetEConstParam*ptmp = new NetEConstParam(scope_, name_, val); NetEConstParam*ptmp = new NetEConstParam(scope_, name, val);
ptmp->set_line(*this); ptmp->set_line(*this);
delete nexpr; delete nexpr;
return ptmp; return ptmp;
@ -1198,7 +1192,7 @@ NetExpr* NetEParam::eval_tree(int prune_to_width)
if (NetECReal*tmp = dynamic_cast<NetECReal*>(nexpr)) { if (NetECReal*tmp = dynamic_cast<NetECReal*>(nexpr)) {
verireal val = tmp->value(); verireal val = tmp->value();
NetECRealParam*ptmp = new NetECRealParam(scope_, name_, val); NetECRealParam*ptmp = new NetECRealParam(scope_, name, val);
ptmp->set_line(*this); ptmp->set_line(*this);
delete nexpr; delete nexpr;
return ptmp; return ptmp;
@ -1209,7 +1203,7 @@ NetExpr* NetEParam::eval_tree(int prune_to_width)
NetExpr*res = nexpr->eval_tree(); NetExpr*res = nexpr->eval_tree();
if (res == 0) { if (res == 0) {
cerr << get_fileline() << ": internal error: Unable to evaluate " cerr << get_fileline() << ": internal error: Unable to evaluate "
<< "parameter " << name_ << " expression: " << "parameter " << name << " expression: "
<< *nexpr << endl; << *nexpr << endl;
delete nexpr; delete nexpr;
return 0; return 0;
@ -1217,10 +1211,10 @@ NetExpr* NetEParam::eval_tree(int prune_to_width)
// The result can be saved as the value of the parameter for // The result can be saved as the value of the parameter for
// future reference, and return a copy to the caller. // future reference, and return a copy to the caller.
bool flag = scope_->replace_parameter(name_, res); bool flag = scope_->replace_parameter(name, res);
if (!flag) { if (!flag) {
cerr << get_fileline() << ": internal error: Could not " cerr << get_fileline() << ": internal error: Could not "
<< "replace parameter expression for " << name_ << endl; << "replace parameter expression for " << name << endl;
return 0; return 0;
} }
@ -1234,7 +1228,7 @@ NetExpr* NetEParam::eval_tree(int prune_to_width)
{ NetEConst*tmp = dynamic_cast<NetEConst*>(res); { NetEConst*tmp = dynamic_cast<NetEConst*>(res);
if (tmp == 0) { if (tmp == 0) {
cerr << get_fileline() << ": internal error: parameter " cerr << get_fileline() << ": internal error: parameter "
<< name_ << " evaluates to incomprehensible " << name << " evaluates to incomprehensible "
<< *res << "." << endl; << *res << "." << endl;
return 0; return 0;
} }
@ -1242,7 +1236,7 @@ NetExpr* NetEParam::eval_tree(int prune_to_width)
assert(tmp); assert(tmp);
verinum val = tmp->value(); verinum val = tmp->value();
NetEConstParam*ptmp = new NetEConstParam(scope_, name_, val); NetEConstParam*ptmp = new NetEConstParam(scope_, name, val);
return ptmp; return ptmp;
} }
@ -1251,7 +1245,7 @@ NetExpr* NetEParam::eval_tree(int prune_to_width)
{ NetECReal*tmp = dynamic_cast<NetECReal*>(res); { NetECReal*tmp = dynamic_cast<NetECReal*>(res);
if (tmp == 0) { if (tmp == 0) {
cerr << get_fileline() << ": internal error: parameter " cerr << get_fileline() << ": internal error: parameter "
<< name_ << " evaluates to incomprehensible " << name << " evaluates to incomprehensible "
<< *res << "." << endl; << *res << "." << endl;
return 0; return 0;
} }
@ -1259,7 +1253,7 @@ NetExpr* NetEParam::eval_tree(int prune_to_width)
assert(tmp); assert(tmp);
verireal val = tmp->value(); verireal val = tmp->value();
NetECRealParam*ptmp = new NetECRealParam(scope_, name_, val); NetECRealParam*ptmp = new NetECRealParam(scope_, name, val);
return ptmp; return ptmp;
} }

View File

@ -243,141 +243,73 @@ void Design::evaluate_parameters()
(*scope)->evaluate_parameters(this); (*scope)->evaluate_parameters(this);
} }
void NetScope::evaluate_parameters(Design*des) void NetScope::evaluate_parameter_logic_(Design*des, param_ref_t cur)
{ {
NetScope*cur = sub_;
while (cur) {
cur->evaluate_parameters(des);
cur = cur->sib_;
}
// Evaluate the parameter values. The parameter expressions
// have already been elaborated and replaced by the scope
// scanning code. Now the parameter expression can be fully
// evaluated, or it cannot be evaluated at all.
typedef map<perm_string,param_expr_t>::iterator mparm_it_t;
for (mparm_it_t cur = parameters.begin()
; cur != parameters.end() ; cur ++) {
long msb = 0; long msb = 0;
long lsb = 0; long lsb = 0;
bool range_flag = false; bool range_flag = false;
NetExpr*expr;
/* Evaluate the msb expression, if it is present. */ /* Evaluate the msb expression, if it is present. */
expr = (*cur).second.msb; if ((*cur).second.msb) {
eval_expr((*cur).second.msb);
if (expr) { if (! eval_as_long(msb, (*cur).second.msb)) {
NetEConst*tmp = dynamic_cast<NetEConst*>(expr);
if (! tmp) {
NetExpr*nexpr = expr->eval_tree();
if (nexpr == 0) {
cerr << (*cur).second.expr->get_fileline() cerr << (*cur).second.expr->get_fileline()
<< ": internal error: " << ": internal error: "
<< "unable to evaluate msb expression " << "unable to evaluate msb expression "
<< "for parameter " << (*cur).first << ": " << "for parameter " << (*cur).first << ": "
<< *expr << endl; << *(*cur).second.msb << endl;
des->errors += 1; des->errors += 1;
continue; return;
} }
assert(nexpr);
delete expr;
(*cur).second.msb = nexpr;
tmp = dynamic_cast<NetEConst*>(nexpr);
}
assert(tmp);
msb = tmp->value().as_long();
range_flag = true; range_flag = true;
} }
/* Evaluate the lsb expression, if it is present. */ /* Evaluate the lsb expression, if it is present. */
expr = (*cur).second.lsb; if ((*cur).second.lsb) {
if (expr) { eval_expr((*cur).second.lsb);
if (! eval_as_long(lsb, (*cur).second.lsb)) {
NetEConst*tmp = dynamic_cast<NetEConst*>(expr);
if (! tmp) {
NetExpr*nexpr = expr->eval_tree();
if (nexpr == 0) {
cerr << (*cur).second.expr->get_fileline() cerr << (*cur).second.expr->get_fileline()
<< ": internal error: " << ": internal error: "
<< "unable to evaluate lsb expression " << "unable to evaluate lsb expression "
<< "for parameter " << (*cur).first << ": " << "for parameter " << (*cur).first << ": "
<< *expr << endl; << *(*cur).second.lsb << endl;
des->errors += 1; des->errors += 1;
continue; return;
} }
assert(nexpr); range_flag = true;
delete expr;
(*cur).second.lsb = nexpr;
tmp = dynamic_cast<NetEConst*>(nexpr);
}
assert(tmp);
lsb = tmp->value().as_long();
assert(range_flag);
} }
/* Evaluate the parameter expression, if necessary. */ /* Evaluate the parameter expression, if necessary. */
expr = (*cur).second.expr; NetExpr*expr = (*cur).second.expr;
assert(expr); assert(expr);
eval_expr(expr);
switch (expr->expr_type()) { switch (expr->expr_type()) {
case IVL_VT_REAL: case IVL_VT_REAL:
if (! dynamic_cast<const NetECReal*>(expr)) { if (! dynamic_cast<const NetECReal*>(expr)) {
NetExpr*nexpr = expr->eval_tree();
if (nexpr == 0) {
cerr << (*cur).second.expr->get_fileline() cerr << (*cur).second.expr->get_fileline()
<< ": internal error: " << ": internal error: "
<< "unable to evaluate real parameter value: " << "unable to evaluate real parameter value: "
<< *expr << endl; << *expr << endl;
des->errors += 1; des->errors += 1;
continue; return;
}
assert(nexpr);
delete expr;
(*cur).second.expr = nexpr;
} }
break; break;
case IVL_VT_LOGIC: case IVL_VT_LOGIC:
case IVL_VT_BOOL: case IVL_VT_BOOL:
if (! dynamic_cast<const NetEConst*>(expr)) { if (! dynamic_cast<const NetEConst*>(expr)) {
// Try to evaluate the expression.
NetExpr*nexpr = expr->eval_tree();
if (nexpr == 0) {
cerr << (*cur).second.expr->get_fileline() cerr << (*cur).second.expr->get_fileline()
<< ": internal error: " << ": internal error: "
<< "unable to evaluate parameter " << "unable to evaluate parameter "
<< (*cur).first << (*cur).first
<< " value: " << << " value: " << *expr << endl;
*expr << endl;
des->errors += 1; des->errors += 1;
continue; return;
}
// The evaluate worked, replace the old
// expression with this constant value.
assert(nexpr);
delete expr;
(*cur).second.expr = nexpr;
} }
break; break;
@ -386,7 +318,7 @@ void NetScope::evaluate_parameters(Design*des)
<< ": internal error: " << ": internal error: "
<< "unhandled expression type?" << endl; << "unhandled expression type?" << endl;
des->errors += 1; des->errors += 1;
continue; return;
} }
/* If the parameter has range information, then make /* If the parameter has range information, then make
@ -397,7 +329,7 @@ void NetScope::evaluate_parameters(Design*des)
unsigned long wid = (msb >= lsb)? msb - lsb : lsb - msb; unsigned long wid = (msb >= lsb)? msb - lsb : lsb - msb;
wid += 1; wid += 1;
NetEConst*val = dynamic_cast<NetEConst*>((*cur).second.expr); NetEConst*val = dynamic_cast<NetEConst*>(expr);
assert(val); assert(val);
verinum value = val->value(); verinum value = val->value();
@ -410,12 +342,20 @@ void NetScope::evaluate_parameters(Design*des)
tmp.has_sign ( (*cur).second.signed_flag ); tmp.has_sign ( (*cur).second.signed_flag );
delete val; delete val;
val = new NetEConst(tmp); val = new NetEConst(tmp);
(*cur).second.expr = val; expr = val;
} }
} }
if (NetEConst*val = dynamic_cast<NetEConst*>((*cur).second.expr)) { // Done fiddling with the expression, save it back in the parameter.
expr->set_line(*(*cur).second.expr);
(*cur).second.expr = expr;
NetEConst*val = dynamic_cast<NetEConst*>((*cur).second.expr);
ivl_assert(*(*cur).second.expr, (*cur).second.expr);
ivl_assert(*(*cur).second.expr, val);
verinum value = val->value(); verinum value = val->value();
bool from_flag = (*cur).second.range == 0? true : false; bool from_flag = (*cur).second.range == 0? true : false;
for (range_t*value_range = (*cur).second.range for (range_t*value_range = (*cur).second.range
; value_range ; value_range = value_range->next) { ; value_range ; value_range = value_range->next) {
@ -452,6 +392,7 @@ void NetScope::evaluate_parameters(Design*des)
} }
// OH NO! In an excluded range. signal an error. // OH NO! In an excluded range. signal an error.
from_flag = false;
break; break;
} }
@ -464,10 +405,124 @@ void NetScope::evaluate_parameters(Design*des)
<< "." << endl; << "." << endl;
des->errors += 1; des->errors += 1;
} }
}
} else if (NetECReal*val = dynamic_cast<NetECReal*>((*cur).second.expr)) { void NetScope::evaluate_parameter_real_(Design*des, param_ref_t cur)
// XXXX Haven't implemented this yet {
ivl_assert(*val, (*cur).second.range == 0); NetExpr*expr = (*cur).second.expr;
assert(expr);
NetECReal*res = 0;
eval_expr(expr);
switch (expr->expr_type()) {
case IVL_VT_REAL:
if (NetECReal*tmp = dynamic_cast<NetECReal*>(expr)) {
res = tmp;
} else {
ivl_assert(*expr, 0);
}
break;
case IVL_VT_LOGIC:
case IVL_VT_BOOL:
if (NetEConst*tmp = dynamic_cast<NetEConst*>(expr)) {
verireal val (tmp->value().as_long());
res = new NetECReal(val);
res->set_line(*tmp);
} else {
ivl_assert(*expr, 0);
}
break;
default:
ivl_assert(*expr, 0);
break;
}
(*cur).second.expr = res;
double value = res->value().as_double();
bool from_flag = (*cur).second.range == 0? true : false;
for (range_t*value_range = (*cur).second.range
; value_range ; value_range = value_range->next) {
if (from_flag && value_range->exclude_flag==false)
continue;
if (value_range->low_expr) {
double tmp;
bool flag = eval_as_double(tmp, value_range->low_expr);
ivl_assert(*value_range->low_expr, flag);
if (value_range->low_open_flag && value <= tmp)
continue;
else if (value < tmp)
continue;
}
if (value_range->high_expr) {
double tmp;
bool flag = eval_as_double(tmp, value_range->high_expr);
ivl_assert(*value_range->high_expr, flag);
if (value_range->high_open_flag && value >= tmp)
continue;
else if (value > tmp)
continue;
}
if (value_range->exclude_flag == false) {
from_flag = true;
continue;
}
// All the above tests failed, so we must have tripped
// an exclude rule.
from_flag = false;
break;
}
if (! from_flag) {
cerr << res->get_fileline() << ": error: "
<< "Parameter value " << value
<< " is out of range for parameter " << (*cur).first
<< "." << endl;
des->errors += 1;
}
}
void NetScope::evaluate_parameters(Design*des)
{
NetScope*cur = sub_;
while (cur) {
cur->evaluate_parameters(des);
cur = cur->sib_;
}
// Evaluate the parameter values. The parameter expressions
// have already been elaborated and replaced by the scope
// scanning code. Now the parameter expression can be fully
// evaluated, or it cannot be evaluated at all.
for (param_ref_t cur = parameters.begin()
; cur != parameters.end() ; cur ++) {
switch ((*cur).second.type) {
case IVL_VT_BOOL:
case IVL_VT_LOGIC:
evaluate_parameter_logic_(des, cur);
break;
case IVL_VT_REAL:
evaluate_parameter_real_(des, cur);
break;
default:
cerr << (*cur).second.get_fileline() << ": internal error: "
<< "Unexpected expression type " << (*cur).second.type
<< "." << endl;
ivl_assert((*cur).second, 0);
break;
} }
} }

View File

@ -476,7 +476,12 @@ NetEParam::NetEParam()
} }
NetEParam::NetEParam(Design*d, NetScope*s, perm_string n) NetEParam::NetEParam(Design*d, NetScope*s, perm_string n)
: des_(d), scope_(s), name_(n) : des_(d), scope_(s), reference_(scope_->find_parameter(n))
{
}
NetEParam::NetEParam(Design*d, NetScope*s, ref_t ref)
: des_(d), scope_(s), reference_(ref)
{ {
} }
@ -489,9 +494,14 @@ bool NetEParam::has_width() const
return false; return false;
} }
ivl_variable_type_t NetEParam::expr_type() const
{
return (*reference_).second.type;
}
NetEParam* NetEParam::dup_expr() const NetEParam* NetEParam::dup_expr() const
{ {
NetEParam*tmp = new NetEParam(des_, scope_, name_); NetEParam*tmp = new NetEParam(des_, scope_, reference_);
tmp->set_line(*this); tmp->set_line(*this);
return tmp; return tmp;
} }

View File

@ -105,6 +105,7 @@ void NetScope::set_line(perm_string file, perm_string def_file,
} }
NetExpr* NetScope::set_parameter(perm_string key, NetExpr*expr, NetExpr* NetScope::set_parameter(perm_string key, NetExpr*expr,
ivl_variable_type_t type,
NetExpr*msb, NetExpr*lsb, bool signed_flag, NetExpr*msb, NetExpr*lsb, bool signed_flag,
NetScope::range_t*range_list, NetScope::range_t*range_list,
const LineInfo&file_line) const LineInfo&file_line)
@ -112,6 +113,7 @@ NetExpr* NetScope::set_parameter(perm_string key, NetExpr*expr,
param_expr_t&ref = parameters[key]; param_expr_t&ref = parameters[key];
NetExpr* res = ref.expr; NetExpr* res = ref.expr;
ref.expr = expr; ref.expr = expr;
ref.type = type;
ref.msb = msb; ref.msb = msb;
ref.lsb = lsb; ref.lsb = lsb;
ref.signed_flag = signed_flag; ref.signed_flag = signed_flag;
@ -204,6 +206,20 @@ const NetExpr* NetScope::get_parameter(const char* key,
return 0; return 0;
} }
map<perm_string,NetScope::param_expr_t>::iterator NetScope::find_parameter(perm_string key)
{
map<perm_string,param_expr_t>::iterator idx;
idx = parameters.find(key);
if (idx != parameters.end())
return idx;
idx = localparams.find(perm_string::literal(key));
if (idx != localparams.end())
return idx;
return 0;
}
NetScope::TYPE NetScope::type() const NetScope::TYPE NetScope::type() const
{ {

453
netlist.h
View File

@ -49,6 +49,7 @@ class ostream;
class Design; class Design;
class Link; class Link;
class Nexus; class Nexus;
class NetEvent;
class NetNet; class NetNet;
class NetNode; class NetNode;
class NetProc; class NetProc;
@ -60,6 +61,7 @@ class NetExpr;
class NetESignal; class NetESignal;
class NetFuncDef; class NetFuncDef;
class NetRamDq; class NetRamDq;
class NetTaskDef;
class NetEvTrig; class NetEvTrig;
class NetEvWait; class NetEvWait;
@ -578,6 +580,234 @@ class NetNet : public NetObj {
vector<class NetDelaySrc*> delay_paths_; vector<class NetDelaySrc*> delay_paths_;
}; };
/*
* This object type is used to contain a logical scope within a
* design. The scope doesn't represent any executable hardware, but is
* just a handle that netlist processors can use to grab at the design.
*/
class NetScope : public Attrib {
public:
enum TYPE { MODULE, TASK, FUNC, BEGIN_END, FORK_JOIN, GENBLOCK };
/* Create a new scope, and attach it to the given parent. The
name is expected to have been permallocated. */
NetScope(NetScope*up, const hname_t&name, TYPE t);
~NetScope();
/* Rename the scope using the name generated by inserting as
many pad characters as required between prefix and suffix
to make the name unique in the parent scope. Return false
if a unique name couldn't be generated. */
bool auto_name(const char* prefix, char pad, const char* suffix);
/* Parameters exist within a scope, and these methods allow
one to manipulate the set. In these cases, the name is the
*simple* name of the parameter, the hierarchy is implicit in
the scope. The return value from set_parameter is the
previous expression, if there was one. */
struct range_t;
NetExpr* set_parameter(perm_string name, NetExpr*val,
ivl_variable_type_t type,
NetExpr*msb, NetExpr*lsb, bool signed_flag,
NetScope::range_t*range_list,
const LineInfo&file_line);
NetExpr* set_localparam(perm_string name, NetExpr*val,
const LineInfo&file_line);
const NetExpr*get_parameter(const char* name,
const NetExpr*&msb,
const NetExpr*&lsb) const;
/* These are used by defparam elaboration to replace the
expression with a new expression, without affecting the
range or signed_flag. Return false if the name does not
exist. */
bool replace_parameter(perm_string name, NetExpr*val);
/* These methods set or access events that live in this
scope. */
void add_event(NetEvent*);
void rem_event(NetEvent*);
NetEvent*find_event(perm_string name);
/* These methods manage signals. The add_ and rem_signal
methods are used by the NetNet objects to make themselves
available to the scope, and the find_signal method can be
used to locate signals within a scope. */
void add_signal(NetNet*);
void rem_signal(NetNet*);
NetNet* find_signal(perm_string name);
/* The parent and child() methods allow users of NetScope
objects to locate nearby scopes. */
NetScope* parent();
NetScope* child(const hname_t&name);
const NetScope* parent() const;
const NetScope* child(const hname_t&name) const;
TYPE type() const;
void set_task_def(NetTaskDef*);
void set_func_def(NetFuncDef*);
void set_module_name(perm_string);
NetTaskDef* task_def();
NetFuncDef* func_def();
void set_line(perm_string file, perm_string def_file,
unsigned lineno, unsigned def_lineno);
void set_line(perm_string file, unsigned lineno);
void set_line(const LineInfo *info);
perm_string get_file() const { return file_; };
perm_string get_def_file() const { return def_file_; };
unsigned get_lineno() const { return lineno_; };
unsigned get_def_lineno() const { return def_lineno_; };
bool in_func();
const NetTaskDef* task_def() const;
const NetFuncDef* func_def() const;
/* If the scope represents a module instance, the module_name
is the name of the module itself. */
perm_string module_name() const;
/* Scopes have their own time units and time precision. The
unit and precision are given as power of 10, i.e., -3 is
units of milliseconds.
If a NetScope is created with a parent scope, the new scope
will initially inherit the unit and precision of the
parent scope. */
void time_unit(int);
void time_precision(int);
int time_unit() const;
int time_precision() const;
void default_nettype(NetNet::Type);
NetNet::Type default_nettype() const;
/* The fullname of the scope is the hierarchical name
component (which includes the name and array index) whereas
the basename is just my name. */
perm_string basename() const;
const hname_t& fullname() const { return name_; }
void run_defparams(class Design*);
void evaluate_parameters(class Design*);
/* This method generates a non-hierarchical name that is
guaranteed to be unique within this scope. */
perm_string local_symbol();
void dump(ostream&) const;
void emit_scope(struct target_t*tgt) const;
bool emit_defs(struct target_t*tgt) const;
/* This method runs the functor on me. Recurse through the
children of this node as well. */
void run_functor(Design*des, functor_t*fun);
/* This member is used during elaboration to pass defparam
assignments from the scope pass to the parameter evaluation
step. After that, it is not used. */
map<pform_name_t,NetExpr*>defparams;
public:
struct range_t {
bool exclude_flag;
// Lower bound
bool low_open_flag;
NetExpr*low_expr;
// Upper bound
bool high_open_flag;
NetExpr*high_expr;
// Link to the next range specification
struct range_t*next;
};
/* After everything is all set up, the code generators like
access to these things to make up the parameter lists. */
struct param_expr_t : public LineInfo {
param_expr_t() : type(IVL_VT_NO_TYPE), range(0) { }
// Type information
ivl_variable_type_t type;
bool signed_flag;
NetExpr*msb;
NetExpr*lsb;
// range constraints
struct range_t*range;
// Expression value
NetExpr*expr;
};
map<perm_string,param_expr_t>parameters;
map<perm_string,param_expr_t>localparams;
typedef map<perm_string,param_expr_t>::iterator param_ref_t;
param_ref_t find_parameter(perm_string name);
struct spec_val_t {
ivl_variable_type_t type;
union {
double real_val; // type == IVL_VT_REAL
long integer; // type == IVL_VT_BOOL
};
};
map<perm_string,spec_val_t>specparams;
/* Module instance arrays are collected here for access during
the multiple elaboration passes. */
typedef svector<NetScope*> scope_vec_t;
map<perm_string, scope_vec_t>instance_arrays;
/* Loop generate uses this as scratch space during
elaboration. Expression evaluation can use this to match
names. */
perm_string genvar_tmp;
long genvar_tmp_val;
private:
void evaluate_parameter_logic_(Design*des, param_ref_t cur);
void evaluate_parameter_real_(Design*des, param_ref_t cur);
private:
TYPE type_;
hname_t name_;
perm_string file_;
perm_string def_file_;
unsigned lineno_;
unsigned def_lineno_;
signed char time_unit_, time_prec_;
NetNet::Type default_nettype_;
NetEvent *events_;
NetNet *signals_;
perm_string module_name_;
union {
NetTaskDef*task_;
NetFuncDef*func_;
};
NetScope*up_;
NetScope*sib_;
NetScope*sub_;
unsigned lcounter_;
};
/* /*
* This class implements the LPM_ABS component. The node has a single * This class implements the LPM_ABS component. The node has a single
* input, a signe expression, that it converts to the absolute * input, a signe expression, that it converts to the absolute
@ -3006,6 +3236,7 @@ class NetEParam : public NetExpr {
virtual bool set_width(unsigned w, bool last_chance); virtual bool set_width(unsigned w, bool last_chance);
virtual bool has_width() const; virtual bool has_width() const;
virtual void expr_scan(struct expr_scan_t*) const; virtual void expr_scan(struct expr_scan_t*) const;
virtual ivl_variable_type_t expr_type() const;
virtual NetExpr* eval_tree(int prune_to_width = -1); virtual NetExpr* eval_tree(int prune_to_width = -1);
virtual NetEParam* dup_expr() const; virtual NetEParam* dup_expr() const;
@ -3014,7 +3245,10 @@ class NetEParam : public NetExpr {
private: private:
Design*des_; Design*des_;
NetScope*scope_; NetScope*scope_;
perm_string name_; typedef map<perm_string,NetScope::param_expr_t>::iterator ref_t;
ref_t reference_;
NetEParam(class Design*des, NetScope*scope, ref_t ref);
}; };
@ -3287,223 +3521,6 @@ class NetESignal : public NetExpr {
}; };
/*
* This object type is used to contain a logical scope within a
* design. The scope doesn't represent any executable hardware, but is
* just a handle that netlist processors can use to grab at the design.
*/
class NetScope : public Attrib {
public:
enum TYPE { MODULE, TASK, FUNC, BEGIN_END, FORK_JOIN, GENBLOCK };
/* Create a new scope, and attach it to the given parent. The
name is expected to have been permallocated. */
NetScope(NetScope*up, const hname_t&name, TYPE t);
~NetScope();
/* Rename the scope using the name generated by inserting as
many pad characters as required between prefix and suffix
to make the name unique in the parent scope. Return false
if a unique name couldn't be generated. */
bool auto_name(const char* prefix, char pad, const char* suffix);
/* Parameters exist within a scope, and these methods allow
one to manipulate the set. In these cases, the name is the
*simple* name of the parameter, the hierarchy is implicit in
the scope. The return value from set_parameter is the
previous expression, if there was one. */
struct range_t;
NetExpr* set_parameter(perm_string name, NetExpr*val,
NetExpr*msb, NetExpr*lsb, bool signed_flag,
NetScope::range_t*range_list,
const LineInfo&file_line);
NetExpr* set_localparam(perm_string name, NetExpr*val,
const LineInfo&file_line);
const NetExpr*get_parameter(const char* name,
const NetExpr*&msb,
const NetExpr*&lsb) const;
/* These are used by defparam elaboration to replace the
expression with a new expression, without affecting the
range or signed_flag. Return false if the name does not
exist. */
bool replace_parameter(perm_string name, NetExpr*val);
/* These methods set or access events that live in this
scope. */
void add_event(NetEvent*);
void rem_event(NetEvent*);
NetEvent*find_event(perm_string name);
/* These methods manage signals. The add_ and rem_signal
methods are used by the NetNet objects to make themselves
available to the scope, and the find_signal method can be
used to locate signals within a scope. */
void add_signal(NetNet*);
void rem_signal(NetNet*);
NetNet* find_signal(perm_string name);
/* The parent and child() methods allow users of NetScope
objects to locate nearby scopes. */
NetScope* parent();
NetScope* child(const hname_t&name);
const NetScope* parent() const;
const NetScope* child(const hname_t&name) const;
TYPE type() const;
void set_task_def(NetTaskDef*);
void set_func_def(NetFuncDef*);
void set_module_name(perm_string);
NetTaskDef* task_def();
NetFuncDef* func_def();
void set_line(perm_string file, perm_string def_file,
unsigned lineno, unsigned def_lineno);
void set_line(perm_string file, unsigned lineno);
void set_line(const LineInfo *info);
perm_string get_file() const { return file_; };
perm_string get_def_file() const { return def_file_; };
unsigned get_lineno() const { return lineno_; };
unsigned get_def_lineno() const { return def_lineno_; };
bool in_func();
const NetTaskDef* task_def() const;
const NetFuncDef* func_def() const;
/* If the scope represents a module instance, the module_name
is the name of the module itself. */
perm_string module_name() const;
/* Scopes have their own time units and time precision. The
unit and precision are given as power of 10, i.e., -3 is
units of milliseconds.
If a NetScope is created with a parent scope, the new scope
will initially inherit the unit and precision of the
parent scope. */
void time_unit(int);
void time_precision(int);
int time_unit() const;
int time_precision() const;
void default_nettype(NetNet::Type);
NetNet::Type default_nettype() const;
/* The fullname of the scope is the hierarchical name
component (which includes the name and array index) whereas
the basename is just my name. */
perm_string basename() const;
const hname_t& fullname() const { return name_; }
void run_defparams(class Design*);
void evaluate_parameters(class Design*);
/* This method generates a non-hierarchical name that is
guaranteed to be unique within this scope. */
perm_string local_symbol();
void dump(ostream&) const;
void emit_scope(struct target_t*tgt) const;
bool emit_defs(struct target_t*tgt) const;
/* This method runs the functor on me. Recurse through the
children of this node as well. */
void run_functor(Design*des, functor_t*fun);
/* This member is used during elaboration to pass defparam
assignments from the scope pass to the parameter evaluation
step. After that, it is not used. */
map<pform_name_t,NetExpr*>defparams;
public:
struct range_t {
bool exclude_flag;
// Lower bound
bool low_open_flag;
NetExpr*low_expr;
// Upper bound
bool high_open_flag;
NetExpr*high_expr;
// Link to the next range specification
struct range_t*next;
};
/* After everything is all set up, the code generators like
access to these things to make up the parameter lists. */
struct param_expr_t : public LineInfo {
param_expr_t() : range(0) { }
// Type information
bool signed_flag;
NetExpr*msb;
NetExpr*lsb;
// range constraints
struct range_t*range;
// Expression value
NetExpr*expr;
};
map<perm_string,param_expr_t>parameters;
map<perm_string,param_expr_t>localparams;
struct spec_val_t {
ivl_variable_type_t type;
union {
double real_val; // type == IVL_VT_REAL
long integer; // type == IVL_VT_BOOL
};
};
map<perm_string,spec_val_t>specparams;
/* Module instance arrays are collected here for access during
the multiple elaboration passes. */
typedef svector<NetScope*> scope_vec_t;
map<perm_string, scope_vec_t>instance_arrays;
/* Loop generate uses this as scratch space during
elaboration. Expression evaluation can use this to match
names. */
perm_string genvar_tmp;
long genvar_tmp_val;
private:
TYPE type_;
hname_t name_;
perm_string file_;
perm_string def_file_;
unsigned lineno_;
unsigned def_lineno_;
signed char time_unit_, time_prec_;
NetNet::Type default_nettype_;
NetEvent *events_;
NetNet *signals_;
perm_string module_name_;
union {
NetTaskDef*task_;
NetFuncDef*func_;
};
NetScope*up_;
NetScope*sib_;
NetScope*sub_;
unsigned lcounter_;
};
/* /*
* This class contains an entire design. It includes processes and a * This class contains an entire design. It includes processes and a
* netlist, and can be passed around from function to function. * netlist, and can be passed around from function to function.

View File

@ -182,6 +182,21 @@ bool eval_as_long(long&value, NetExpr*expr)
return false; return false;
} }
bool eval_as_double(double&value, NetExpr*expr)
{
if (NetEConst*tmp = dynamic_cast<NetEConst*>(expr) ) {
value = tmp->value().as_long();
return true;
}
if (NetECReal*rtmp = dynamic_cast<NetECReal*>(expr)) {
value = rtmp->value().as_double();
return true;
}
return false;
}
std::list<hname_t> eval_scope_path(Design*des, NetScope*scope, std::list<hname_t> eval_scope_path(Design*des, NetScope*scope,
const pform_name_t&path) const pform_name_t&path)
{ {

View File

@ -138,6 +138,7 @@ void eval_expr(NetExpr*&expr, int prune_width =-1);
* down to a constant) then return false and leave value unchanged. * down to a constant) then return false and leave value unchanged.
*/ */
bool eval_as_long(long&value, NetExpr*expr); bool eval_as_long(long&value, NetExpr*expr);
bool eval_as_double(double&value, NetExpr*expr);
extern std::list<hname_t> eval_scope_path(Design*des, NetScope*scope, extern std::list<hname_t> eval_scope_path(Design*des, NetScope*scope,
const pform_name_t&path); const pform_name_t&path);

111
parse.y
View File

@ -35,8 +35,9 @@ class PSpecPath;
extern void lex_start_table(); extern void lex_start_table();
extern void lex_end_table(); extern void lex_end_table();
static svector<PExpr*>* active_range = 0; static svector<PExpr*>* param_active_range = 0;
static bool active_signed = false; static bool param_active_signed = false;
static ivl_variable_type_t param_active_type = IVL_VT_LOGIC;
/* Port declaration lists use this structure for context. */ /* Port declaration lists use this structure for context. */
static struct { static struct {
@ -2357,20 +2358,45 @@ var_type
parameter_assign_decl parameter_assign_decl
: parameter_assign_list : parameter_assign_list
| range { active_range = $1; active_signed = false; } | range
parameter_assign_list { param_active_range = $1;
{ active_range = 0; param_active_signed = false;
active_signed = false; param_active_type = IVL_VT_LOGIC;
} }
| K_signed range { active_range = $2; active_signed = true; }
parameter_assign_list parameter_assign_list
{ active_range = 0; { param_active_range = 0;
active_signed = false; param_active_signed = false;
param_active_type = IVL_VT_LOGIC;
}
| K_signed range
{ param_active_range = $2;
param_active_signed = true;
param_active_type = IVL_VT_LOGIC;
} }
| K_integer { active_range = 0; active_signed = true; }
parameter_assign_list parameter_assign_list
{ active_range = 0; { param_active_range = 0;
active_signed = false; param_active_signed = false;
param_active_type = IVL_VT_LOGIC;
}
| K_integer
{ param_active_range = 0;
param_active_signed = true;
param_active_type = IVL_VT_LOGIC;
}
parameter_assign_list
{ param_active_range = 0;
param_active_signed = false;
param_active_type = IVL_VT_LOGIC;
}
| K_real
{ param_active_range = 0;
param_active_signed = true;
param_active_type = IVL_VT_REAL;
}
parameter_assign_list
{ param_active_range = 0;
param_active_signed = false;
param_active_type = IVL_VT_LOGIC;
} }
; ;
@ -2382,8 +2408,8 @@ parameter_assign_list
parameter_assign parameter_assign
: IDENTIFIER '=' expression parameter_value_ranges_opt : IDENTIFIER '=' expression parameter_value_ranges_opt
{ PExpr*tmp = $3; { PExpr*tmp = $3;
pform_set_parameter(@1, lex_strings.make($1), pform_set_parameter(@1, lex_strings.make($1), param_active_type,
active_signed, active_range, tmp, $4); param_active_signed, param_active_range, tmp, $4);
delete[]$1; delete[]$1;
} }
; ;
@ -2426,36 +2452,55 @@ from_exclude : K_from { $$ = false; } | K_exclude { $$ = true; } ;
localparam_assign localparam_assign
: IDENTIFIER '=' expression : IDENTIFIER '=' expression
{ PExpr*tmp = $3; { PExpr*tmp = $3;
if (!pform_expression_is_constant(tmp)) {
yyerror(@3, "error: parameter value "
"must be constant.");
delete tmp;
tmp = 0;
} else {
pform_set_localparam(@1, lex_strings.make($1), pform_set_localparam(@1, lex_strings.make($1),
active_signed, param_active_type,
active_range, tmp); param_active_signed,
} param_active_range, tmp);
delete[]$1; delete[]$1;
} }
; ;
localparam_assign_decl localparam_assign_decl
: localparam_assign_list : localparam_assign_list
| range { active_range = $1; active_signed = false; } | range
localparam_assign_list { param_active_range = $1;
{ active_range = 0; param_active_signed = false;
active_signed = false; param_active_type = IVL_VT_LOGIC;
} }
| K_signed range { active_range = $2; active_signed = true; }
localparam_assign_list localparam_assign_list
{ active_range = 0; { param_active_range = 0;
active_signed = false; param_active_signed = false;
param_active_type = IVL_VT_NO_TYPE;
}
| K_signed range
{ param_active_range = $2;
param_active_signed = true;
param_active_type = IVL_VT_LOGIC;
} }
| K_integer { active_range = 0; active_signed = true; }
localparam_assign_list localparam_assign_list
{ active_range = 0; { param_active_range = 0;
active_signed = false; param_active_signed = false;
param_active_type = IVL_VT_NO_TYPE;
}
| K_integer
{ param_active_range = 0;
param_active_signed = true;
param_active_type = IVL_VT_LOGIC;
}
localparam_assign_list
{ param_active_range = 0;
param_active_signed = false;
param_active_type = IVL_VT_NO_TYPE;
}
| K_real
{ param_active_range = 0;
param_active_signed = true;
param_active_type = IVL_VT_REAL;
}
localparam_assign_list
{ param_active_range = 0;
param_active_signed = false;
param_active_type = IVL_VT_NO_TYPE;
} }
; ;

View File

@ -1654,8 +1654,8 @@ Module::range_t* pform_parameter_value_range(bool exclude_flag,
} }
void pform_set_parameter(const struct vlltype&loc, void pform_set_parameter(const struct vlltype&loc,
perm_string name, bool signed_flag, perm_string name, ivl_variable_type_t type,
svector<PExpr*>*range, PExpr*expr, bool signed_flag, svector<PExpr*>*range, PExpr*expr,
Module::range_t*value_range) Module::range_t*value_range)
{ {
assert(expr); assert(expr);
@ -1664,6 +1664,7 @@ void pform_set_parameter(const struct vlltype&loc,
parm.expr = expr; parm.expr = expr;
parm.type = type;
if (range) { if (range) {
assert(range->count() == 2); assert(range->count() == 2);
assert((*range)[0]); assert((*range)[0]);
@ -1681,8 +1682,8 @@ void pform_set_parameter(const struct vlltype&loc,
} }
void pform_set_localparam(const struct vlltype&loc, void pform_set_localparam(const struct vlltype&loc,
perm_string name, bool signed_flag, perm_string name, ivl_variable_type_t type,
svector<PExpr*>*range, PExpr*expr) bool signed_flag, svector<PExpr*>*range, PExpr*expr)
{ {
assert(expr); assert(expr);
Module::param_expr_t&parm = pform_cur_module->localparams[name]; Module::param_expr_t&parm = pform_cur_module->localparams[name];
@ -1690,6 +1691,7 @@ void pform_set_localparam(const struct vlltype&loc,
parm.expr = expr; parm.expr = expr;
parm.type = type;
if (range) { if (range) {
assert(range->count() == 2); assert(range->count() == 2);
assert((*range)[0]); assert((*range)[0]);

View File

@ -272,11 +272,13 @@ extern Module::range_t* pform_parameter_value_range(bool exclude_flag,
extern void pform_set_parameter(const struct vlltype&loc, extern void pform_set_parameter(const struct vlltype&loc,
perm_string name, perm_string name,
ivl_variable_type_t type,
bool signed_flag, bool signed_flag,
svector<PExpr*>*range, svector<PExpr*>*range,
PExpr*expr, Module::range_t*value_range); PExpr*expr, Module::range_t*value_range);
extern void pform_set_localparam(const struct vlltype&loc, extern void pform_set_localparam(const struct vlltype&loc,
perm_string name, perm_string name,
ivl_variable_type_t type,
bool signed_flag, bool signed_flag,
svector<PExpr*>*range, svector<PExpr*>*range,
PExpr*expr); PExpr*expr);

View File

@ -994,7 +994,7 @@ void Module::dump(ostream&out) const
typedef map<pform_name_t,PExpr*>::const_iterator parm_hiter_t; typedef map<pform_name_t,PExpr*>::const_iterator parm_hiter_t;
for (parm_iter_t cur = parameters.begin() for (parm_iter_t cur = parameters.begin()
; cur != parameters.end() ; cur ++) { ; cur != parameters.end() ; cur ++) {
out << " parameter "; out << " parameter " << (*cur).second.type << " ";
if ((*cur).second.signed_flag) if ((*cur).second.signed_flag)
out << "signed "; out << "signed ";
if ((*cur).second.msb) if ((*cur).second.msb)