Enum names in r-value expressions

When enum names are used as r-values in expressions, use their
values. Treat the enum names similar to (but not exactly as)
localparams so that they fit into the rest of the elaboration
flow naturally.
This commit is contained in:
Stephen Williams 2010-10-31 11:26:09 -07:00
parent cced1e771b
commit a14fa038b4
15 changed files with 304 additions and 44 deletions

View File

@ -99,6 +99,9 @@ class LexicalScope {
list<PProcess*> behaviors;
list<AProcess*> analog_behaviors;
// Enumeration sets.
list<enum_set_t> enum_sets;
LexicalScope* parent_scope() const { return parent_; }
protected:
@ -106,6 +109,8 @@ class LexicalScope {
void dump_localparams_(ostream&out, unsigned indent) const;
void dump_enumerations_(ostream&out, unsigned indent) const;
void dump_events_(ostream&out, unsigned indent) const;
void dump_wires_(ostream&out, unsigned indent) const;

View File

@ -30,7 +30,7 @@ PWire::PWire(perm_string n,
signed_(false), isint_(false),
port_msb_(0), port_lsb_(0), port_set_(false),
net_msb_(0), net_lsb_(0), net_set_(false), is_scalar_(false),
error_cnt_(0), lidx_(0), ridx_(0), discipline_(0)
error_cnt_(0), lidx_(0), ridx_(0), enum_set_(0), discipline_(0)
{
if (t == NetNet::INTEGER) {
type_ = NetNet::REG;
@ -206,6 +206,12 @@ void PWire::set_memory_idx(PExpr*ldx, PExpr*rdx)
}
}
void PWire::set_enumeration(enum_set_t enum_set)
{
assert(enum_set_ == 0);
enum_set_ = enum_set;
}
void PWire::set_discipline(ivl_discipline_t d)
{
assert(discipline_ == 0);

View File

@ -79,6 +79,8 @@ class PWire : public LineInfo {
void set_memory_idx(PExpr*ldx, PExpr*rdx);
void set_enumeration(enum_set_t enum_set);
void set_discipline(ivl_discipline_t);
ivl_discipline_t get_discipline(void) const;
@ -113,6 +115,8 @@ class PWire : public LineInfo {
PExpr*lidx_;
PExpr*ridx_;
enum_set_t enum_set_;
ivl_discipline_t discipline_;
private: // not implemented

View File

@ -1187,6 +1187,23 @@ void NetScope::dump(ostream&o) const
}
}
o << " enum sets {" << endl;
/* Dump the enumerations and enum names in this scope. */
for (list<enum_set_t>::const_iterator cur = enum_sets_.begin()
; cur != enum_sets_.end() ; ++ cur) {
o << " " << *cur << endl;
}
o << " }" << endl;
o << " enum names {" << endl;
for (map<perm_string,NetEConstEnum*>::const_iterator cur = enum_names_.begin()
; cur != enum_names_.end() ; ++ cur) {
o << " " << cur->first << " = " << cur->second->value()
<< " from " << cur->second->enumeration() << endl;
}
o << " }" << endl;
/* Dump the events in this scope. */
for (NetEvent*cur = events_ ; cur ; cur = cur->snext_) {
o << " event " << cur->name() << "; nprobe="
@ -1401,6 +1418,13 @@ void NetEConst::dump(ostream&o) const
o << value_;
}
void NetEConstEnum::dump(ostream&o) const
{
o << "<" << name_ << "=";
NetEConst::dump(o);
o << ", wid=" << expr_width() << ">";
}
void NetEConstParam::dump(ostream&o) const
{
o << "<" << name_ << "=";

View File

@ -49,6 +49,14 @@ NetEConst* NetEConst::dup_expr() const
return tmp;
}
NetEConstEnum* NetEConstEnum::dup_expr() const
{
NetEConstEnum*tmp = new NetEConstEnum(scope_, name_, enum_set_, value());
assert(tmp);
tmp->set_line(*this);
return tmp;
}
NetEConstParam* NetEConstParam::dup_expr() const
{
NetEConstParam*tmp = new NetEConstParam(scope_, name_, value());

View File

@ -206,6 +206,31 @@ static void elaborate_scope_localparams_(Design*des, NetScope*scope,
}
}
static void elaborate_scope_enumeration(Design*des, NetScope*scope,
enum_set_t enum_set)
{
scope->add_enumeration_set(enum_set);
for (map<perm_string,verinum>::const_iterator cur = enum_set->begin()
; cur != enum_set->end() ; ++ cur) {
bool rc = scope->add_enumeration_name(enum_set, cur->first);
if (! rc) {
cerr << "<>:0: error: Duplicate enumeration name " << cur->first << endl;
des->errors += 1;
}
}
}
static void elaborate_scope_enumerations(Design*des, NetScope*scope,
const list<enum_set_t>&enum_sets)
{
for (list<enum_set_t>::const_iterator cur = enum_sets.begin()
; cur != enum_sets.end() ; ++ cur) {
elaborate_scope_enumeration(des, scope, *cur);
}
}
static void replace_scope_parameters_(NetScope*scope, const LineInfo&loc,
const Module::replace_t&replacements)
{
@ -434,6 +459,8 @@ bool Module::elaborate_scope(Design*des, NetScope*scope,
elaborate_scope_localparams_(des, scope, localparams);
elaborate_scope_enumerations(des, scope, enum_sets);
// Run through the defparams for this module, elaborate the
// expressions in this context and save the result is a table
// for later final override.

View File

@ -516,6 +516,11 @@ void NetEConst::expr_scan(struct expr_scan_t*tgt) const
tgt->expr_const(this);
}
void NetEConstEnum::expr_scan(struct expr_scan_t*tgt) const
{
tgt->expr_const(this);
}
void NetEConstParam::expr_scan(struct expr_scan_t*tgt) const
{
tgt->expr_param(this);

View File

@ -432,6 +432,20 @@ unsigned NetEConcat::repeat() const
return repeat_value_;
}
NetEConstEnum::NetEConstEnum(NetScope*s, perm_string n, enum_set_t eset, const verinum&v)
: NetEConst(v), scope_(s), enum_set_(eset)
{
}
NetEConstEnum::~NetEConstEnum()
{
}
const enum_set_t NetEConstEnum::enumeration() const
{
return enum_set_;
}
NetECReal::NetECReal(const verireal&val)
: value_(val)
{

View File

@ -207,25 +207,42 @@ NetExpr* NetScope::set_localparam(perm_string key, NetExpr*expr,
const NetExpr* NetScope::get_parameter(const char* key,
const NetExpr*&msb,
const NetExpr*&lsb) const
{
return get_parameter(perm_string::literal(key), msb, lsb);
}
const NetExpr* NetScope::get_parameter(perm_string key,
const NetExpr*&msb,
const NetExpr*&lsb) const
{
map<perm_string,param_expr_t>::const_iterator idx;
idx = parameters.find(perm_string::literal(key));
idx = parameters.find(key);
if (idx != parameters.end()) {
msb = (*idx).second.msb;
lsb = (*idx).second.lsb;
return (*idx).second.expr;
}
idx = localparams.find(perm_string::literal(key));
idx = localparams.find(key);
if (idx != localparams.end()) {
msb = (*idx).second.msb;
lsb = (*idx).second.lsb;
return (*idx).second.expr;
}
map<perm_string,NetEConstEnum*>::const_iterator eidx;
eidx = enum_names_.find(key);
if (eidx != enum_names_.end()) {
msb = 0;
lsb = 0;
return eidx->second;
}
return 0;
}
map<perm_string,NetScope::param_expr_t>::iterator NetScope::find_parameter(perm_string key)
{
map<perm_string,param_expr_t>::iterator idx;
@ -436,6 +453,25 @@ NetNet* NetScope::find_signal(perm_string key)
return 0;
}
void NetScope::add_enumeration_set(enum_set_t enum_set)
{
enum_sets_.push_back(enum_set);
}
bool NetScope::add_enumeration_name(enum_set_t enum_set, perm_string name)
{
enum_set_m::const_iterator enum_val = enum_set->find(name);
assert(enum_val != enum_set->end());
NetEConstEnum*val = new NetEConstEnum(this, name, enum_set, enum_val->second);
pair<map<perm_string,NetEConstEnum*>::iterator, bool> cur;
cur = enum_names_.insert(make_pair(name,val));
// Return TRUE if the name is added (i.e. is NOT a duplicate.)
return cur.second;
}
/*
* This method locates a child scope by name. The name is the simple
* name of the child, no hierarchy is searched.

View File

@ -64,6 +64,7 @@ class NetScope;
class NetEvProbe;
class NetExpr;
class NetEAccess;
class NetEConstEnum;
class NetESignal;
class NetFuncDef;
class NetRamDq;
@ -718,6 +719,9 @@ class NetScope : public Attrib {
const NetExpr*get_parameter(const char* name,
const NetExpr*&msb,
const NetExpr*&lsb) const;
const NetExpr*get_parameter(perm_string 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
@ -745,6 +749,9 @@ class NetScope : public Attrib {
void rem_signal(NetNet*);
NetNet* find_signal(perm_string name);
void add_enumeration_set(enum_set_t enum_set);
bool add_enumeration_name(enum_set_t enum_set, perm_string);
/* The parent and child() methods allow users of NetScope
objects to locate nearby scopes. */
NetScope* parent() { return up_; }
@ -920,6 +927,13 @@ class NetScope : public Attrib {
NetFuncDef*func_;
};
// Enumerations. The enum_sets_ is a list of all the
// enumerations present in this scope. The enum_names_ is a
// map of all the enumeration names back to the sets that
// contain them.
std::list<enum_set_t> enum_sets_;
std::map<perm_string,NetEConstEnum*> enum_names_;
NetScope*up_;
map<hname_t,NetScope*> children_;
@ -1707,6 +1721,29 @@ class NetEConst : public NetExpr {
verinum value_;
};
class NetEConstEnum : public NetEConst {
public:
explicit NetEConstEnum(NetScope*scope, perm_string name,
enum_set_t enum_set, const verinum&val);
~NetEConstEnum();
perm_string name() const;
const NetScope*scope() const;
const enum_set_t enumeration() const;
virtual bool set_width(unsigned w, bool last_chance =false);
virtual void expr_scan(struct expr_scan_t*) const;
virtual void dump(ostream&) const;
virtual NetEConstEnum* dup_expr() const;
private:
NetScope*scope_;
enum_set_t enum_set_;
perm_string name_;
};
class NetEConstParam : public NetEConst {
public:

View File

@ -41,7 +41,7 @@ extern NetScope* symbol_search(const LineInfo*li,
NetScope*start,
pform_name_t path,
NetNet*&net, /* net/reg */
const NetExpr*&par,/* parameter */
const NetExpr*&par,/* parameter/expr */
NetEvent*&eve, /* named event */
const NetExpr*&ex1, const NetExpr*&ex2);
@ -50,7 +50,7 @@ inline NetScope* symbol_search(const LineInfo*li,
NetScope*start,
const pform_name_t&path,
NetNet*&net, /* net/reg */
const NetExpr*&par,/* parameter */
const NetExpr*&par,/* parameter/expr */
NetEvent*&eve /* named event */)
{
const NetExpr*ex1, *ex2;

138
pform.cc
View File

@ -378,6 +378,27 @@ static void pform_put_wire_in_scope(perm_string name, PWire*net)
lexical_scope->wires[name] = net;
}
static void pform_put_enum_set_in_scope(enum_set_t enum_set)
{
lexical_scope->enum_sets.push_back(enum_set);
}
static PWire*pform_get_make_wire_in_scope(perm_string name, NetNet::Type net_type, NetNet::PortType port_type, ivl_variable_type_t vt_type)
{
PWire*cur = pform_get_wire_in_scope(name);
if (cur == 0) {
cur = new PWire(name, net_type, port_type, vt_type);
pform_put_wire_in_scope(name, cur);
} else {
bool rc = cur->set_wire_type(net_type);
assert(rc);
rc = cur->set_data_type(vt_type);
assert(rc);
}
return cur;
}
static void pform_put_behavior_in_scope(PProcess*pp)
{
lexical_scope->behaviors.push_back(pp);
@ -2377,19 +2398,7 @@ void pform_set_port_type(const struct vlltype&li,
static void pform_set_reg_integer(perm_string name)
{
PWire*cur = pform_get_wire_in_scope(name);
if (cur == 0) {
cur = new PWire(name, NetNet::INTEGER,
NetNet::NOT_A_PORT,
IVL_VT_LOGIC);
cur->set_signed(true);
pform_put_wire_in_scope(name, cur);
} else {
bool rc = cur->set_wire_type(NetNet::INTEGER);
assert(rc);
cur->set_data_type(IVL_VT_LOGIC);
cur->set_signed(true);
}
PWire*cur = pform_get_make_wire_in_scope(name, NetNet::INTEGER, NetNet::NOT_A_PORT, IVL_VT_LOGIC);
assert(cur);
cur->set_range(new PENumber(new verinum(integer_width-1, integer_width)),
@ -2411,16 +2420,7 @@ void pform_set_reg_integer(list<perm_string>*names)
static void pform_set_reg_time(perm_string name)
{
PWire*cur = pform_get_wire_in_scope(name);
if (cur == 0) {
cur = new PWire(name, NetNet::REG, NetNet::NOT_A_PORT, IVL_VT_LOGIC);
pform_put_wire_in_scope(name, cur);
} else {
bool rc = cur->set_wire_type(NetNet::REG);
assert(rc);
rc = cur->set_data_type(IVL_VT_LOGIC);
assert(rc);
}
PWire*cur = pform_get_make_wire_in_scope(name, NetNet::REG, NetNet::NOT_A_PORT, IVL_VT_LOGIC);
assert(cur);
cur->set_range(new PENumber(new verinum(TIME_WIDTH-1, integer_width)),
@ -2441,17 +2441,7 @@ void pform_set_reg_time(list<perm_string>*names)
static void pform_set_integer_2atom(uint64_t width, bool signed_flag, perm_string name)
{
PWire*cur = pform_get_wire_in_scope(name);
if (cur == 0) {
cur = new PWire(name, NetNet::REG, NetNet::NOT_A_PORT, IVL_VT_BOOL);
pform_put_wire_in_scope(name, cur);
} else {
bool rc = cur->set_wire_type(NetNet::REG);
assert(rc);
rc = cur->set_data_type(IVL_VT_BOOL);
assert(rc);
}
PWire*cur = pform_get_make_wire_in_scope(name, NetNet::REG, NetNet::NOT_A_PORT, IVL_VT_BOOL);
assert(cur);
cur->set_signed(signed_flag);
@ -2471,13 +2461,85 @@ void pform_set_integer_2atom(uint64_t width, bool signed_flag, list<perm_string>
delete names;
}
static void pform_set_enum(const struct vlltype&li, enum_type_t*enum_type,
enum_set_t enum_set, perm_string name)
{
PWire*cur = pform_get_make_wire_in_scope(name, NetNet::REG, NetNet::NOT_A_PORT, enum_type->base_type);
assert(cur);
cur->set_signed(enum_type->signed_flag);
assert(enum_type->range.get() != 0);
assert(enum_type->range->size() == 2);
cur->set_range(enum_type->range->front(), enum_type->range->back(), SR_NET, false);
cur->set_enumeration(enum_set);
}
void pform_set_enum(const struct vlltype&li, enum_type_t*enum_type, list<perm_string>*names)
{
cerr << li.text << ":" << li.first_line << ": "
<< "sorry: enum types not supported yet." << endl;
error_count += 1;
delete enum_type;
// By definition, the base type can only be IVL_VT_LOGIC or
// IVL_VT_BOOL.
assert(enum_type->base_type==IVL_VT_LOGIC || enum_type->base_type==IVL_VT_BOOL);
assert(enum_type->range.get() != 0);
assert(enum_type->range->size() == 2);
// Scan the list of enum name declarations and evaluate them
// to a map of names with values. This expands out the
// inferred values (if any) and checks for duplicates.
enum_set_t enum_map = new enum_set_m;
verinum cur_value (0);
verinum one_value (1);
for (list<named_number_t>::iterator cur = enum_type->names->begin()
; cur != enum_type->names->end() ; ++ cur) {
verinum next_value = cur->parm;
if (next_value.len() == 0) {
if (! cur_value.is_defined()) {
cerr << li.text << ":" << li.first_line << ": "
<< "error: Enumeration name " << cur->name
<< " cannot have inferred value." << endl;
next_value = cur_value;
error_count += 1;
} else {
next_value = cur_value;
cur_value = cur_value + one_value;
}
} else {
if (enum_type->base_type==IVL_VT_BOOL && ! next_value.is_defined()) {
cerr << li.text << ":" << li.first_line << ": "
<< "error: Enumeration name " << cur->name
<< " Cannot have logic value " << next_value << "." << endl;
error_count += 1;
}
cur_value = next_value + one_value;
}
map<perm_string,verinum>::iterator map_name = enum_map->find(cur->name);
if (map_name == enum_map->end()) {
enum_map->insert(make_pair(cur->name, next_value));;
} else {
cerr << li.text << ":" << li.first_line << ": "
<< "error: Enumeration name " << cur->name
<< " is already defined." << endl;
error_count += 1;
}
}
// Attach the enumeration to the current scope.
pform_put_enum_set_in_scope(enum_map);
// Now apply the checked enumeration type to the variables
// that are being declared with this type.
for (list<perm_string>::iterator cur = names->begin()
; cur != names->end() ; ++ cur) {
perm_string txt = *cur;
pform_set_enum(li, enum_type, enum_map, txt);
}
delete names;
delete enum_type;
}
svector<PWire*>* pform_make_udp_input_ports(list<perm_string>*names)

View File

@ -1106,6 +1106,22 @@ void LexicalScope::dump_localparams_(ostream&out, unsigned indent) const
}
}
void LexicalScope::dump_enumerations_(ostream&out, unsigned indent) const
{
for (list<enum_set_t>::const_iterator cur = enum_sets.begin()
; cur != enum_sets.end() ; ++ cur) {
out << setw(indent) << "" << "enum {" << endl;
for (map<perm_string,verinum>::const_iterator idx = (*cur)->begin()
; idx != (*cur)->end() ; ++ idx) {
out << setw(indent+4) << "" << idx->first
<< " = " << idx->second << endl;
}
out << setw(indent) << "" << "}" << endl;
}
}
void LexicalScope::dump_events_(ostream&out, unsigned indent) const
{
for (map<perm_string,PEvent*>::const_iterator cur = events.begin()
@ -1167,6 +1183,8 @@ void Module::dump(ostream&out) const
dump_localparams_(out, 4);
dump_enumerations_(out, 4);
typedef map<perm_string,LineInfo*>::const_iterator genvar_iter_t;
for (genvar_iter_t cur = genvars.begin()
; cur != genvars.end() ; cur++) {

View File

@ -21,8 +21,10 @@
// This for the perm_string type.
# include "StringHeap.h"
# include "verinum.h"
# include <iostream>
# include <list>
# include <map>
/*
* parse-form types.
@ -47,6 +49,13 @@ struct name_component_t {
std::list<index_component_t>index;
};
/*
* The enum_map_t holds the values that represent the enumeration. An
* enumeration, then, is defined by its pointer to the set.
*/
typedef map<perm_string,verinum> enum_set_m;
typedef enum_set_m *enum_set_t;
/*
* The pform_name_t is the general form for a hierarchical

View File

@ -377,13 +377,18 @@ void NetEConst::cast_signed(bool sign_flag)
/*
* Parameter vectors cannot be resized because they refer to a common
* value.
* value. Ditto for enumeration names.
*/
bool NetEConstParam::set_width(unsigned w, bool)
{
return w == expr_width();
}
bool NetEConstEnum::set_width(unsigned w, bool)
{
return w == expr_width();
}
/*
* Real constants can have whatever width the environment wants,
* because it isn't really a vector. The environment will convert this