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
into this map. */
struct param_expr_t : public LineInfo {
PExpr*expr;
param_expr_t() : range(0) { }
// Type information
ivl_variable_type_t type;
PExpr*msb;
PExpr*lsb;
bool signed_flag;
// Value expression
PExpr*expr;
// If there are range constrants, list them here
range_t*range;
};

View File

@ -1290,11 +1290,9 @@ void NetESignal::dump(ostream&o) const
void NetEParam::dump(ostream&o) const
{
if (scope_ != 0)
o << "<" << scope_path(scope_) << "." << name_ << ">";
else if (name_)
o << "<" << name_ << ">";
o << "<" << scope_path(scope_) << "." << (*reference_).first << ">";
else
o << "<" "???" ">";
o << "<" << (*reference_).first << ">";
}
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
and defined width. */
if (cur.msb) {
assert(cur.lsb);
msb = cur.msb ->elaborate_pexpr(des, scope);
assert(msb);
lsb = cur.lsb ->elaborate_pexpr(des, scope);
assert(lsb);
}
if (signed_flag) {
@ -102,7 +104,7 @@ void Module::elaborate_parm_item_(perm_string name, const param_expr_t&cur,
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);
delete val;
}
@ -140,7 +142,8 @@ bool Module::elaborate_scope(Design*des, NetScope*scope,
tmp->set_line(*((*cur).second.expr));
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()
@ -151,7 +154,8 @@ bool Module::elaborate_scope(Design*des, NetScope*scope,
if ((*cur).second.msb)
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
<< " with expression " << *val
<< " from " << val->get_fileline() << "." << endl;
cerr << get_fileline() << ": : "
<< "Type=" << val->expr_type() << endl;
}
bool flag = scope->replace_parameter((*cur).first, val);
if (! flag) {

View File

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

View File

@ -243,6 +243,253 @@ void Design::evaluate_parameters()
(*scope)->evaluate_parameters(this);
}
void NetScope::evaluate_parameter_logic_(Design*des, param_ref_t cur)
{
long msb = 0;
long lsb = 0;
bool range_flag = false;
/* Evaluate the msb expression, if it is present. */
if ((*cur).second.msb) {
eval_expr((*cur).second.msb);
if (! eval_as_long(msb, (*cur).second.msb)) {
cerr << (*cur).second.expr->get_fileline()
<< ": internal error: "
<< "unable to evaluate msb expression "
<< "for parameter " << (*cur).first << ": "
<< *(*cur).second.msb << endl;
des->errors += 1;
return;
}
range_flag = true;
}
/* Evaluate the lsb expression, if it is present. */
if ((*cur).second.lsb) {
eval_expr((*cur).second.lsb);
if (! eval_as_long(lsb, (*cur).second.lsb)) {
cerr << (*cur).second.expr->get_fileline()
<< ": internal error: "
<< "unable to evaluate lsb expression "
<< "for parameter " << (*cur).first << ": "
<< *(*cur).second.lsb << endl;
des->errors += 1;
return;
}
range_flag = true;
}
/* Evaluate the parameter expression, if necessary. */
NetExpr*expr = (*cur).second.expr;
assert(expr);
eval_expr(expr);
switch (expr->expr_type()) {
case IVL_VT_REAL:
if (! dynamic_cast<const NetECReal*>(expr)) {
cerr << (*cur).second.expr->get_fileline()
<< ": internal error: "
<< "unable to evaluate real parameter value: "
<< *expr << endl;
des->errors += 1;
return;
}
break;
case IVL_VT_LOGIC:
case IVL_VT_BOOL:
if (! dynamic_cast<const NetEConst*>(expr)) {
cerr << (*cur).second.expr->get_fileline()
<< ": internal error: "
<< "unable to evaluate parameter "
<< (*cur).first
<< " value: " << *expr << endl;
des->errors += 1;
return;
}
break;
default:
cerr << (*cur).second.expr->get_fileline()
<< ": internal error: "
<< "unhandled expression type?" << endl;
des->errors += 1;
return;
}
/* If the parameter has range information, then make
sure the value is set right. Note that if the
parameter doesn't have an explicit range, then it
will get the signedness from the expression itself. */
if (range_flag) {
unsigned long wid = (msb >= lsb)? msb - lsb : lsb - msb;
wid += 1;
NetEConst*val = dynamic_cast<NetEConst*>(expr);
assert(val);
verinum value = val->value();
if (! (value.has_len()
&& (value.len() == wid)
&& (value.has_sign() == (*cur).second.signed_flag))) {
verinum tmp (value, wid);
tmp.has_sign ( (*cur).second.signed_flag );
delete val;
val = new NetEConst(tmp);
expr = val;
}
}
// 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();
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 we already know that the value is
// within a "from" range, then do not test
// any more of the from ranges.
if (from_flag && value_range->exclude_flag==false)
continue;
if (value_range->low_expr) {
NetEConst*tmp = dynamic_cast<NetEConst*>(value_range->low_expr);
ivl_assert(*value_range->low_expr, tmp);
if (value_range->low_open_flag && value <= tmp->value())
continue;
else if (value < tmp->value())
continue;
}
if (value_range->high_expr) {
NetEConst*tmp = dynamic_cast<NetEConst*>(value_range->high_expr);
ivl_assert(*value_range->high_expr, tmp);
if (value_range->high_open_flag && value >= tmp->value())
continue;
else if (value > tmp->value())
continue;
}
// Within the range. If this is a "from"
// range, then set the from_flag and continue.
if (value_range->exclude_flag == false) {
from_flag = true;
continue;
}
// OH NO! In an excluded range. signal an error.
from_flag = false;
break;
}
// If we found no from range that contains the
// value, then report an error.
if (! from_flag) {
cerr << val->get_fileline() << ": error: "
<< "Parameter value " << value
<< " is out of range for parameter " << (*cur).first
<< "." << endl;
des->errors += 1;
}
}
void NetScope::evaluate_parameter_real_(Design*des, param_ref_t cur)
{
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_;
@ -257,217 +504,25 @@ void NetScope::evaluate_parameters(Design*des)
// 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()
for (param_ref_t cur = parameters.begin()
; cur != parameters.end() ; cur ++) {
long msb = 0;
long lsb = 0;
bool range_flag = false;
NetExpr*expr;
/* Evaluate the msb expression, if it is present. */
expr = (*cur).second.msb;
if (expr) {
NetEConst*tmp = dynamic_cast<NetEConst*>(expr);
if (! tmp) {
NetExpr*nexpr = expr->eval_tree();
if (nexpr == 0) {
cerr << (*cur).second.expr->get_fileline()
<< ": internal error: "
<< "unable to evaluate msb expression "
<< "for parameter " << (*cur).first << ": "
<< *expr << endl;
des->errors += 1;
continue;
}
assert(nexpr);
delete expr;
(*cur).second.msb = nexpr;
tmp = dynamic_cast<NetEConst*>(nexpr);
}
assert(tmp);
msb = tmp->value().as_long();
range_flag = true;
}
/* Evaluate the lsb expression, if it is present. */
expr = (*cur).second.lsb;
if (expr) {
NetEConst*tmp = dynamic_cast<NetEConst*>(expr);
if (! tmp) {
NetExpr*nexpr = expr->eval_tree();
if (nexpr == 0) {
cerr << (*cur).second.expr->get_fileline()
<< ": internal error: "
<< "unable to evaluate lsb expression "
<< "for parameter " << (*cur).first << ": "
<< *expr << endl;
des->errors += 1;
continue;
}
assert(nexpr);
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. */
expr = (*cur).second.expr;
assert(expr);
switch (expr->expr_type()) {
case IVL_VT_REAL:
if (! dynamic_cast<const NetECReal*>(expr)) {
NetExpr*nexpr = expr->eval_tree();
if (nexpr == 0) {
cerr << (*cur).second.expr->get_fileline()
<< ": internal error: "
<< "unable to evaluate real parameter value: "
<< *expr << endl;
des->errors += 1;
continue;
}
assert(nexpr);
delete expr;
(*cur).second.expr = nexpr;
}
switch ((*cur).second.type) {
case IVL_VT_BOOL:
case IVL_VT_LOGIC:
evaluate_parameter_logic_(des, cur);
break;
case IVL_VT_LOGIC:
case IVL_VT_BOOL:
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()
<< ": internal error: "
<< "unable to evaluate parameter "
<< (*cur).first
<< " value: " <<
*expr << endl;
des->errors += 1;
continue;
}
// The evaluate worked, replace the old
// expression with this constant value.
assert(nexpr);
delete expr;
(*cur).second.expr = nexpr;
}
case IVL_VT_REAL:
evaluate_parameter_real_(des, cur);
break;
default:
cerr << (*cur).second.expr->get_fileline()
<< ": internal error: "
<< "unhandled expression type?" << endl;
des->errors += 1;
continue;
}
/* If the parameter has range information, then make
sure the value is set right. Note that if the
parameter doesn't have an explicit range, then it
will get the signedness from the expression itself. */
if (range_flag) {
unsigned long wid = (msb >= lsb)? msb - lsb : lsb - msb;
wid += 1;
NetEConst*val = dynamic_cast<NetEConst*>((*cur).second.expr);
assert(val);
verinum value = val->value();
if (! (value.has_len()
&& (value.len() == wid)
&& (value.has_sign() == (*cur).second.signed_flag))) {
verinum tmp (value, wid);
tmp.has_sign ( (*cur).second.signed_flag );
delete val;
val = new NetEConst(tmp);
(*cur).second.expr = val;
}
}
if (NetEConst*val = dynamic_cast<NetEConst*>((*cur).second.expr)) {
verinum value = val->value();
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 we already know that the value is
// within a "from" range, then do not test
// any more of the from ranges.
if (from_flag && value_range->exclude_flag==false)
continue;
if (value_range->low_expr) {
NetEConst*tmp = dynamic_cast<NetEConst*>(value_range->low_expr);
ivl_assert(*value_range->low_expr, tmp);
if (value_range->low_open_flag && value <= tmp->value())
continue;
else if (value < tmp->value())
continue;
}
if (value_range->high_expr) {
NetEConst*tmp = dynamic_cast<NetEConst*>(value_range->high_expr);
ivl_assert(*value_range->high_expr, tmp);
if (value_range->high_open_flag && value >= tmp->value())
continue;
else if (value > tmp->value())
continue;
}
// Within the range. If this is a "from"
// range, then set the from_flag and continue.
if (value_range->exclude_flag == false) {
from_flag = true;
continue;
}
// OH NO! In an excluded range. signal an error.
break;
}
// If we found no from range that contains the
// value, then report an error.
if (! from_flag) {
cerr << val->get_fileline() << ": error: "
<< "Parameter value " << value
<< " is out of range for parameter " << (*cur).first
<< "." << endl;
des->errors += 1;
}
} else if (NetECReal*val = dynamic_cast<NetECReal*>((*cur).second.expr)) {
// XXXX Haven't implemented this yet
ivl_assert(*val, (*cur).second.range == 0);
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)
: 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;
}
ivl_variable_type_t NetEParam::expr_type() const
{
return (*reference_).second.type;
}
NetEParam* NetEParam::dup_expr() const
{
NetEParam*tmp = new NetEParam(des_, scope_, name_);
NetEParam*tmp = new NetEParam(des_, scope_, reference_);
tmp->set_line(*this);
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,
ivl_variable_type_t type,
NetExpr*msb, NetExpr*lsb, bool signed_flag,
NetScope::range_t*range_list,
const LineInfo&file_line)
@ -112,6 +113,7 @@ NetExpr* NetScope::set_parameter(perm_string key, NetExpr*expr,
param_expr_t&ref = parameters[key];
NetExpr* res = ref.expr;
ref.expr = expr;
ref.type = type;
ref.msb = msb;
ref.lsb = lsb;
ref.signed_flag = signed_flag;
@ -204,6 +206,20 @@ const NetExpr* NetScope::get_parameter(const char* key,
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
{

453
netlist.h
View File

@ -49,6 +49,7 @@ class ostream;
class Design;
class Link;
class Nexus;
class NetEvent;
class NetNet;
class NetNode;
class NetProc;
@ -60,6 +61,7 @@ class NetExpr;
class NetESignal;
class NetFuncDef;
class NetRamDq;
class NetTaskDef;
class NetEvTrig;
class NetEvWait;
@ -578,6 +580,234 @@ class NetNet : public NetObj {
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
* 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 has_width() 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 NetEParam* dup_expr() const;
@ -3014,7 +3245,10 @@ class NetEParam : public NetExpr {
private:
Design*des_;
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
* 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;
}
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,
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.
*/
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,
const pform_name_t&path);

151
parse.y
View File

@ -35,8 +35,9 @@ class PSpecPath;
extern void lex_start_table();
extern void lex_end_table();
static svector<PExpr*>* active_range = 0;
static bool active_signed = false;
static svector<PExpr*>* param_active_range = 0;
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. */
static struct {
@ -2356,23 +2357,48 @@ var_type
generates a type (optional) and a list of assignments. */
parameter_assign_decl
: parameter_assign_list
| range { active_range = $1; active_signed = false; }
parameter_assign_list
{ active_range = 0;
active_signed = false;
}
| K_signed range { active_range = $2; active_signed = true; }
parameter_assign_list
{ active_range = 0;
active_signed = false;
}
| K_integer { active_range = 0; active_signed = true; }
parameter_assign_list
{ active_range = 0;
active_signed = false;
}
;
: parameter_assign_list
| range
{ param_active_range = $1;
param_active_signed = false;
param_active_type = IVL_VT_LOGIC;
}
parameter_assign_list
{ param_active_range = 0;
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;
}
parameter_assign_list
{ param_active_range = 0;
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;
}
;
parameter_assign_list
: parameter_assign
@ -2382,8 +2408,8 @@ parameter_assign_list
parameter_assign
: IDENTIFIER '=' expression parameter_value_ranges_opt
{ PExpr*tmp = $3;
pform_set_parameter(@1, lex_strings.make($1),
active_signed, active_range, tmp, $4);
pform_set_parameter(@1, lex_strings.make($1), param_active_type,
param_active_signed, param_active_range, tmp, $4);
delete[]$1;
}
;
@ -2424,40 +2450,59 @@ from_exclude : K_from { $$ = false; } | K_exclude { $$ = true; } ;
behave differently when someone tries to override them. */
localparam_assign
: IDENTIFIER '=' expression
{ 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),
active_signed,
active_range, tmp);
}
delete[]$1;
}
;
: IDENTIFIER '=' expression
{ PExpr*tmp = $3;
pform_set_localparam(@1, lex_strings.make($1),
param_active_type,
param_active_signed,
param_active_range, tmp);
delete[]$1;
}
;
localparam_assign_decl
: localparam_assign_list
| range { active_range = $1; active_signed = false; }
localparam_assign_list
{ active_range = 0;
active_signed = false;
}
| K_signed range { active_range = $2; active_signed = true; }
localparam_assign_list
{ active_range = 0;
active_signed = false;
}
| K_integer { active_range = 0; active_signed = true; }
localparam_assign_list
{ active_range = 0;
active_signed = false;
}
;
: localparam_assign_list
| range
{ param_active_range = $1;
param_active_signed = false;
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_signed range
{ param_active_range = $2;
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_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;
}
;
localparam_assign_list
: localparam_assign

View File

@ -1654,8 +1654,8 @@ Module::range_t* pform_parameter_value_range(bool exclude_flag,
}
void pform_set_parameter(const struct vlltype&loc,
perm_string name, bool signed_flag,
svector<PExpr*>*range, PExpr*expr,
perm_string name, ivl_variable_type_t type,
bool signed_flag, svector<PExpr*>*range, PExpr*expr,
Module::range_t*value_range)
{
assert(expr);
@ -1664,6 +1664,7 @@ void pform_set_parameter(const struct vlltype&loc,
parm.expr = expr;
parm.type = type;
if (range) {
assert(range->count() == 2);
assert((*range)[0]);
@ -1681,8 +1682,8 @@ void pform_set_parameter(const struct vlltype&loc,
}
void pform_set_localparam(const struct vlltype&loc,
perm_string name, bool signed_flag,
svector<PExpr*>*range, PExpr*expr)
perm_string name, ivl_variable_type_t type,
bool signed_flag, svector<PExpr*>*range, PExpr*expr)
{
assert(expr);
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.type = type;
if (range) {
assert(range->count() == 2);
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,
perm_string name,
ivl_variable_type_t type,
bool signed_flag,
svector<PExpr*>*range,
PExpr*expr, Module::range_t*value_range);
extern void pform_set_localparam(const struct vlltype&loc,
perm_string name,
ivl_variable_type_t type,
bool signed_flag,
svector<PExpr*>*range,
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;
for (parm_iter_t cur = parameters.begin()
; cur != parameters.end() ; cur ++) {
out << " parameter ";
out << " parameter " << (*cur).second.type << " ";
if ((*cur).second.signed_flag)
out << "signed ";
if ((*cur).second.msb)