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_*,
index_component_t::ctype_t,
bool need_const_idx) const;
bool elaborate_lval_net_class_member_(Design*, NetScope*,
NetAssign_*,
const perm_string&) const;
NetAssign_*elaborate_lval_net_class_member_(Design*, NetScope*,
NetNet*,
const perm_string&) const;
bool elaborate_lval_net_packed_member_(Design*, NetScope*,
NetAssign_*,
const perm_string&) const;

View File

@ -1759,6 +1759,17 @@ static NetExpr* check_for_struct_members(const LineInfo*li,
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,
Design*des, NetScope*scope,
NetNet*net,
@ -1791,6 +1802,12 @@ static NetExpr* check_for_class_property(const LineInfo*li,
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);
tmp->set_line(*li);
return tmp;
@ -2888,6 +2905,10 @@ NetExpr* PEIdent::elaborate_expr_class_member_(Design*des, NetScope*scope,
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);
tmp->set_line(*this);
return tmp;

View File

@ -256,8 +256,7 @@ NetAssign_* PEIdent::elaborate_lval(Design*des,
}
if (reg->class_type() && !method_name.nil() && gn_system_verilog()) {
NetAssign_*lv = new NetAssign_(reg);
elaborate_lval_net_class_member_(des, use_scope, lv, method_name);
NetAssign_*lv = elaborate_lval_net_class_member_(des, use_scope, reg, method_name);
return lv;
}
@ -846,17 +845,16 @@ bool PEIdent::elaborate_lval_net_idx_(Design*des,
return true;
}
bool PEIdent::elaborate_lval_net_class_member_(Design*des, NetScope*scope,
NetAssign_*lv,
const perm_string&method_name) const
NetAssign_* PEIdent::elaborate_lval_net_class_member_(Design*des, NetScope*scope,
NetNet*sig, const perm_string&method_name) const
{
if (debug_elaborate) {
cerr << get_fileline() << ": elaborate_lval_net_class_member_: "
<< "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);
/* 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()
<< " does not have a property " << method_name << "." << endl;
des->errors += 1;
return false;
return 0;
}
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;
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()) {
cerr << get_fileline() << ": error: "
<< "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;
}
NetAssign_*lv = new NetAssign_(sig);
lv->set_property(method_name);
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)
{
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()
; cur != pclass->funcs.end() ; ++ cur) {
if (debug_elaborate) {

View File

@ -2361,11 +2361,17 @@ NetProc* PAssign::elaborate_compressed_(Design*des, NetScope*scope) const
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)
{
while (lv) {
NetScope*sig_scope = lv->sig()->scope();
if (! sig_scope->program_block())
if (! sig_scope->program_block() && sig_scope->type()!=NetScope::CLASS)
return true;
lv = lv->more;
@ -4969,6 +4975,19 @@ bool Module::elaborate(Design*des, NetScope*scope) const
*/
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()
; cur != pclass->funcs.end() ; ++ cur) {
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
{
while (scope && scope != class_scope_) {

View File

@ -27,6 +27,7 @@
# include <map>
class Design;
class NetNet;
class NetScope;
class PClass;
@ -72,6 +73,11 @@ class netclass_t : public ivl_type_s {
// The task method scopes from the method name.
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
// used to check scope for handling data protection keywords
// "local" and "protected".

View File

@ -41,15 +41,6 @@ void pform_class_property(const struct vlltype&loc,
{
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
// object. Unwind the list of names to make a map of name to
// type.
@ -72,7 +63,11 @@ void pform_class_property(const struct vlltype&loc,
FILE_NAME(lval, loc);
PAssign*tmp = new PAssign(lval, rval);
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.
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;
};