Add support for class static properties.

Static properties are like variables in a named scope.
Detect these variables during elaboration so that the
code generator just sees them as variables.
This commit is contained in:
Stephen Williams 2013-07-02 19:41:58 -07:00
parent 4ef3ac5ca6
commit 5326790932
9 changed files with 103 additions and 23 deletions

View File

@ -387,9 +387,9 @@ class PEIdent : public PExpr {
bool elaborate_lval_net_idx_(Design*, NetScope*, NetAssign_*, bool elaborate_lval_net_idx_(Design*, NetScope*, NetAssign_*,
index_component_t::ctype_t, index_component_t::ctype_t,
bool need_const_idx) const; bool need_const_idx) const;
bool elaborate_lval_net_class_member_(Design*, NetScope*, NetAssign_*elaborate_lval_net_class_member_(Design*, NetScope*,
NetAssign_*, NetNet*,
const perm_string&) const; const perm_string&) const;
bool elaborate_lval_net_packed_member_(Design*, NetScope*, bool elaborate_lval_net_packed_member_(Design*, NetScope*,
NetAssign_*, NetAssign_*,
const perm_string&) const; const perm_string&) const;

View File

@ -1759,6 +1759,17 @@ static NetExpr* check_for_struct_members(const LineInfo*li,
return sel; return sel;
} }
static NetExpr* class_static_property_expression(const LineInfo*li,
const netclass_t*class_type,
perm_string name)
{
NetNet*sig = class_type->find_static_property(name);
ivl_assert(*li, sig);
NetESignal*expr = new NetESignal(sig);
expr->set_line(*li);
return expr;
}
static NetExpr* check_for_class_property(const LineInfo*li, static NetExpr* check_for_class_property(const LineInfo*li,
Design*des, NetScope*scope, Design*des, NetScope*scope,
NetNet*net, NetNet*net,
@ -1791,6 +1802,12 @@ static NetExpr* check_for_class_property(const LineInfo*li,
des->errors += 1; des->errors += 1;
} }
if (qual.test_static()) {
perm_string prop_name = lex_strings.make(class_type->get_prop_name(pidx));
return class_static_property_expression(li, class_type,
prop_name);
}
NetEProperty*tmp = new NetEProperty(net, comp.name); NetEProperty*tmp = new NetEProperty(net, comp.name);
tmp->set_line(*li); tmp->set_line(*li);
return tmp; return tmp;
@ -2888,6 +2905,10 @@ NetExpr* PEIdent::elaborate_expr_class_member_(Design*des, NetScope*scope,
des->errors += 1; des->errors += 1;
} }
if (qual.test_static()) {
return class_static_property_expression(this, class_type, member_name);
}
NetEProperty*tmp = new NetEProperty(this_net, member_name); NetEProperty*tmp = new NetEProperty(this_net, member_name);
tmp->set_line(*this); tmp->set_line(*this);
return tmp; return tmp;

View File

@ -256,8 +256,7 @@ NetAssign_* PEIdent::elaborate_lval(Design*des,
} }
if (reg->class_type() && !method_name.nil() && gn_system_verilog()) { if (reg->class_type() && !method_name.nil() && gn_system_verilog()) {
NetAssign_*lv = new NetAssign_(reg); NetAssign_*lv = elaborate_lval_net_class_member_(des, use_scope, reg, method_name);
elaborate_lval_net_class_member_(des, use_scope, lv, method_name);
return lv; return lv;
} }
@ -846,17 +845,16 @@ bool PEIdent::elaborate_lval_net_idx_(Design*des,
return true; return true;
} }
bool PEIdent::elaborate_lval_net_class_member_(Design*des, NetScope*scope, NetAssign_* PEIdent::elaborate_lval_net_class_member_(Design*des, NetScope*scope,
NetAssign_*lv, NetNet*sig, const perm_string&method_name) const
const perm_string&method_name) const
{ {
if (debug_elaborate) { if (debug_elaborate) {
cerr << get_fileline() << ": elaborate_lval_net_class_member_: " cerr << get_fileline() << ": elaborate_lval_net_class_member_: "
<< "l-value is property " << method_name << "l-value is property " << method_name
<< " of " << lv->sig()->name() << "." << endl; << " of " << sig->name() << "." << endl;
} }
const netclass_t*class_type = lv->sig()->class_type(); const netclass_t*class_type = sig->class_type();
ivl_assert(*this, class_type); ivl_assert(*this, class_type);
/* Make sure the property is really present in the class. If /* Make sure the property is really present in the class. If
@ -866,7 +864,7 @@ bool PEIdent::elaborate_lval_net_class_member_(Design*des, NetScope*scope,
cerr << get_fileline() << ": error: Class " << class_type->get_name() cerr << get_fileline() << ": error: Class " << class_type->get_name()
<< " does not have a property " << method_name << "." << endl; << " does not have a property " << method_name << "." << endl;
des->errors += 1; des->errors += 1;
return false; return 0;
} }
property_qualifier_t qual = class_type->get_prop_qual(pidx); property_qualifier_t qual = class_type->get_prop_qual(pidx);
@ -877,6 +875,17 @@ bool PEIdent::elaborate_lval_net_class_member_(Design*des, NetScope*scope,
<< " (scope=" << scope_path(scope) << ")" << endl; << " (scope=" << scope_path(scope) << ")" << endl;
des->errors += 1; des->errors += 1;
} else if (qual.test_static()) {
// Special case: this is a static property. Ignore the
// "this" sig and use the property itself, which is not
// part of the sig, as the l-value.
NetNet*psig = class_type->find_static_property(method_name);
ivl_assert(*this, psig);
NetAssign_*lv = new NetAssign_(psig);
return lv;
} else if (qual.test_const()) { } else if (qual.test_const()) {
cerr << get_fileline() << ": error: " cerr << get_fileline() << ": error: "
<< "Property " << class_type->get_prop_name(pidx) << "Property " << class_type->get_prop_name(pidx)
@ -884,6 +893,7 @@ bool PEIdent::elaborate_lval_net_class_member_(Design*des, NetScope*scope,
des->errors += 1; des->errors += 1;
} }
NetAssign_*lv = new NetAssign_(sig);
lv->set_property(method_name); lv->set_property(method_name);
ivl_type_t ptype = class_type->get_prop_type(pidx); ivl_type_t ptype = class_type->get_prop_type(pidx);
@ -898,7 +908,7 @@ bool PEIdent::elaborate_lval_net_class_member_(Design*des, NetScope*scope,
} }
} }
return true; return lv;
} }

View File

@ -314,6 +314,25 @@ bool Module::elaborate_sig(Design*des, NetScope*scope) const
void netclass_t::elaborate_sig(Design*des, PClass*pclass) void netclass_t::elaborate_sig(Design*des, PClass*pclass)
{ {
for (map<perm_string,struct class_type_t::prop_info_t>::iterator cur = pclass->type->properties.begin()
; cur != pclass->type->properties.end() ; ++ cur) {
if (! cur->second.qual.test_static())
continue;
if (debug_elaborate) {
cerr << pclass->get_fileline() << ": netclass_t::elaborate_sig: "
<< "Elaborate static property " << cur->first
<< " as signal in scope " << scope_path(class_scope_)
<< "." << endl;
}
list<netrange_t> nil_list;
ivl_type_t use_type = cur->second.type->elaborate_type(des, class_scope_);
NetNet*sig = new NetNet(class_scope_, cur->first, NetNet::REG,
nil_list, use_type);
}
for (map<perm_string,PFunction*>::iterator cur = pclass->funcs.begin() for (map<perm_string,PFunction*>::iterator cur = pclass->funcs.begin()
; cur != pclass->funcs.end() ; ++ cur) { ; cur != pclass->funcs.end() ; ++ cur) {
if (debug_elaborate) { if (debug_elaborate) {

View File

@ -2361,11 +2361,17 @@ NetProc* PAssign::elaborate_compressed_(Design*des, NetScope*scope) const
return cur; return cur;
} }
/*
* Assignments within program blocks can only write to certain types
* of variables. We can only write to:
* - variables in a program block
* - static properties of a class
*/
static bool lval_not_program_variable(const NetAssign_*lv) static bool lval_not_program_variable(const NetAssign_*lv)
{ {
while (lv) { while (lv) {
NetScope*sig_scope = lv->sig()->scope(); NetScope*sig_scope = lv->sig()->scope();
if (! sig_scope->program_block()) if (! sig_scope->program_block() && sig_scope->type()!=NetScope::CLASS)
return true; return true;
lv = lv->more; lv = lv->more;
@ -4969,6 +4975,19 @@ bool Module::elaborate(Design*des, NetScope*scope) const
*/ */
void netclass_t::elaborate(Design*des, PClass*pclass) void netclass_t::elaborate(Design*des, PClass*pclass)
{ {
if (! pclass->type->initialize_static.empty()) {
std::vector<Statement*>&stmt_list = pclass->type->initialize_static;
NetBlock*stmt = new NetBlock(NetBlock::SEQU, 0);
for (size_t idx = 0 ; idx < stmt_list.size() ; idx += 1) {
NetProc*tmp = stmt_list[idx]->elaborate(des, class_scope_);
if (tmp == 0) continue;
stmt->append(tmp);
}
NetProcTop*top = new NetProcTop(class_scope_, IVL_PR_INITIAL, stmt);
top->set_line(*pclass);
des->add_process(top);
}
for (map<perm_string,PFunction*>::iterator cur = pclass->funcs.begin() for (map<perm_string,PFunction*>::iterator cur = pclass->funcs.begin()
; cur != pclass->funcs.end() ; ++ cur) { ; cur != pclass->funcs.end() ; ++ cur) {
if (debug_elaborate) { if (debug_elaborate) {

View File

@ -122,6 +122,11 @@ NetScope*netclass_t::method_from_name(perm_string name) const
} }
NetNet* netclass_t::find_static_property(perm_string name) const
{
NetNet*tmp = class_scope_->find_signal(name);
}
bool netclass_t::test_scope_is_method(const NetScope*scope) const bool netclass_t::test_scope_is_method(const NetScope*scope) const
{ {
while (scope && scope != class_scope_) { while (scope && scope != class_scope_) {

View File

@ -27,6 +27,7 @@
# include <map> # include <map>
class Design; class Design;
class NetNet;
class NetScope; class NetScope;
class PClass; class PClass;
@ -72,6 +73,11 @@ class netclass_t : public ivl_type_s {
// The task method scopes from the method name. // The task method scopes from the method name.
NetScope*method_from_name(perm_string mname) const; NetScope*method_from_name(perm_string mname) const;
// Find the elaborated signal (NetNet) for a static
// property. Search by name. The signal is created by the
// elaborate_sig pass.
NetNet*find_static_property(perm_string name) const;
// Test if this scope is a method within the class. This is // Test if this scope is a method within the class. This is
// used to check scope for handling data protection keywords // used to check scope for handling data protection keywords
// "local" and "protected". // "local" and "protected".

View File

@ -41,15 +41,6 @@ void pform_class_property(const struct vlltype&loc,
{ {
assert(pform_cur_class); assert(pform_cur_class);
if (property_qual.test_static()) {
// I think the thing to do with static properties is to
// make them PWires directly in the PClass scope. They
// are wires like program/modules wires, and not
// instance members.
VLerror(loc, "sorry: static class properties not implemented.");
return;
}
// Add the non-static properties to the class type // Add the non-static properties to the class type
// object. Unwind the list of names to make a map of name to // object. Unwind the list of names to make a map of name to
// type. // type.
@ -72,7 +63,11 @@ void pform_class_property(const struct vlltype&loc,
FILE_NAME(lval, loc); FILE_NAME(lval, loc);
PAssign*tmp = new PAssign(lval, rval); PAssign*tmp = new PAssign(lval, rval);
FILE_NAME(tmp, loc); FILE_NAME(tmp, loc);
pform_cur_class->type->initialize.push_back(tmp);
if (property_qual.test_static())
pform_cur_class->type->initialize_static.push_back(tmp);
else
pform_cur_class->type->initialize.push_back(tmp);
} }
} }
} }

View File

@ -233,6 +233,11 @@ struct class_type_t : public data_type_t {
// the expression that is assigned. // the expression that is assigned.
std::vector<Statement*> initialize; std::vector<Statement*> initialize;
// This is an ordered list of property initializers for static
// properties. These are run in a synthetic "initial" block
// without waiting for any constructor.
std::vector<Statement*> initialize_static;
ivl_type_s* elaborate_type(Design*, NetScope*) const; ivl_type_s* elaborate_type(Design*, NetScope*) const;
}; };