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:
parent
4ef3ac5ca6
commit
5326790932
6
PExpr.h
6
PExpr.h
|
|
@ -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;
|
||||||
|
|
|
||||||
21
elab_expr.cc
21
elab_expr.cc
|
|
@ -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;
|
||||||
|
|
|
||||||
28
elab_lval.cc
28
elab_lval.cc
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
19
elab_sig.cc
19
elab_sig.cc
|
|
@ -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) {
|
||||||
|
|
|
||||||
21
elaborate.cc
21
elaborate.cc
|
|
@ -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) {
|
||||||
|
|
|
||||||
|
|
@ -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_) {
|
||||||
|
|
|
||||||
|
|
@ -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".
|
||||||
|
|
|
||||||
|
|
@ -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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue