Merge branch 'x-mil15'
This commit is contained in:
commit
853512868b
4
PExpr.h
4
PExpr.h
|
|
@ -245,6 +245,10 @@ class PEConcat : public PExpr {
|
|||
|
||||
virtual NetNet* elaborate_lnet(Design*des, NetScope*scope) const;
|
||||
virtual NetNet* elaborate_bi_net(Design*des, NetScope*scope) const;
|
||||
|
||||
virtual NetExpr*elaborate_expr(Design*des, NetScope*scope,
|
||||
ivl_type_t type, unsigned flags) const;
|
||||
|
||||
virtual NetExpr*elaborate_expr(Design*des, NetScope*,
|
||||
unsigned expr_wid,
|
||||
unsigned flags) const;
|
||||
|
|
|
|||
|
|
@ -336,9 +336,13 @@ PForce::~PForce()
|
|||
delete expr_;
|
||||
}
|
||||
|
||||
PForeach::PForeach(perm_string av, perm_string ix, Statement*s)
|
||||
: array_var_(av), index_var_(ix), statement_(s)
|
||||
PForeach::PForeach(perm_string av, const list<perm_string>&ix, Statement*s)
|
||||
: array_var_(av), index_vars_(ix.size()), statement_(s)
|
||||
{
|
||||
size_t idx = 0;
|
||||
for (list<perm_string>::const_iterator cur = ix.begin()
|
||||
; cur != ix.end() ; ++cur)
|
||||
index_vars_[idx++] = *cur;
|
||||
}
|
||||
|
||||
PForeach::~PForeach()
|
||||
|
|
|
|||
|
|
@ -445,7 +445,7 @@ class PForce : public Statement {
|
|||
|
||||
class PForeach : public Statement {
|
||||
public:
|
||||
explicit PForeach(perm_string var, perm_string ix, Statement*stmt);
|
||||
explicit PForeach(perm_string var, const std::list<perm_string>&ix, Statement*stmt);
|
||||
~PForeach();
|
||||
|
||||
virtual NetProc* elaborate(Design*des, NetScope*scope) const;
|
||||
|
|
@ -453,9 +453,13 @@ class PForeach : public Statement {
|
|||
virtual void elaborate_sig(Design*des, NetScope*scope) const;
|
||||
virtual void dump(ostream&out, unsigned ind) const;
|
||||
|
||||
private:
|
||||
NetProc* elaborate_static_array_(Design*des, NetScope*scope,
|
||||
const std::vector<netrange_t>&dims) const;
|
||||
|
||||
private:
|
||||
perm_string array_var_;
|
||||
perm_string index_var_;
|
||||
std::vector<perm_string> index_vars_;
|
||||
Statement*statement_;
|
||||
};
|
||||
|
||||
|
|
|
|||
116
elab_expr.cc
116
elab_expr.cc
|
|
@ -30,6 +30,7 @@
|
|||
# include "netlist.h"
|
||||
# include "netclass.h"
|
||||
# include "netenum.h"
|
||||
# include "netparray.h"
|
||||
# include "netvector.h"
|
||||
# include "discipline.h"
|
||||
# include "netmisc.h"
|
||||
|
|
@ -2497,6 +2498,24 @@ unsigned PEConcat::test_width(Design*des, NetScope*scope, width_mode_t&)
|
|||
// Keep track of the concatenation/repeat depth.
|
||||
static int concat_depth = 0;
|
||||
|
||||
NetExpr* PEConcat::elaborate_expr(Design*, NetScope*,
|
||||
ivl_type_t type, unsigned /*flags*/) const
|
||||
{
|
||||
switch (type->base_type()) {
|
||||
case IVL_VT_QUEUE:
|
||||
if (parms_.size() == 0) {
|
||||
NetENull*tmp = new NetENull;
|
||||
tmp->set_line(*this);
|
||||
return tmp;
|
||||
}
|
||||
default:
|
||||
cerr << get_fileline() << ": internal error: "
|
||||
<< "I don't know how to elaborate(ivl_type_t)"
|
||||
<< " this expression: " << *this << endl;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
NetExpr* PEConcat::elaborate_expr(Design*des, NetScope*scope,
|
||||
unsigned expr_wid, unsigned flags) const
|
||||
{
|
||||
|
|
@ -3113,8 +3132,10 @@ unsigned PEIdent::test_width(Design*des, NetScope*scope, width_mode_t&mode)
|
|||
|
||||
|
||||
NetExpr* PEIdent::elaborate_expr(Design*des, NetScope*scope,
|
||||
ivl_type_t ntype, unsigned) const
|
||||
ivl_type_t ntype, unsigned flags) const
|
||||
{
|
||||
bool need_const = NEED_CONST & flags;
|
||||
|
||||
NetNet* net = 0;
|
||||
const NetExpr*par = 0;
|
||||
NetEvent* eve = 0;
|
||||
|
|
@ -3126,6 +3147,10 @@ NetExpr* PEIdent::elaborate_expr(Design*des, NetScope*scope,
|
|||
ivl_assert(*this, use_scope);
|
||||
}
|
||||
|
||||
if (NetExpr* tmp = elaborate_expr_class_member_(des, scope, 0, flags)) {
|
||||
return tmp;
|
||||
}
|
||||
|
||||
/* NetScope*found_in = */ symbol_search(this, des, use_scope, path_,
|
||||
net, par, eve,
|
||||
ex1, ex2);
|
||||
|
|
@ -3185,7 +3210,69 @@ NetExpr* PEIdent::elaborate_expr(Design*des, NetScope*scope,
|
|||
}
|
||||
ivl_assert(*this, ntype->type_compatible(net->net_type()));
|
||||
|
||||
NetESignal*tmp = new NetESignal(net);
|
||||
const name_component_t&use_comp = path_.back();
|
||||
|
||||
if (debug_elaborate) {
|
||||
cerr << get_fileline() << ": PEIdent::elaborate_expr: "
|
||||
<< "Typed ident " << net->name()
|
||||
<< " with " << use_comp.index.size() << " indices"
|
||||
<< " and " << net->unpacked_dimensions() << " expected."
|
||||
<< endl;
|
||||
}
|
||||
|
||||
if (net->unpacked_dimensions() != use_comp.index.size()) {
|
||||
cerr << get_fileline() << ": sorry: "
|
||||
<< "Net " << net->name()
|
||||
<< " expects " << net->unpacked_dimensions()
|
||||
<< ", but got " << use_comp.index.size() << "."
|
||||
<< endl;
|
||||
des->errors += 1;
|
||||
|
||||
NetESignal*tmp = new NetESignal(net);
|
||||
tmp->set_line(*this);
|
||||
return tmp;
|
||||
}
|
||||
|
||||
if (net->unpacked_dimensions() == 0) {
|
||||
NetESignal*tmp = new NetESignal(net);
|
||||
tmp->set_line(*this);
|
||||
return tmp;
|
||||
}
|
||||
|
||||
// Convert a set of index expressions to a single expression
|
||||
// that addresses the canonical element.
|
||||
list<NetExpr*>unpacked_indices;
|
||||
list<long> unpacked_indices_const;
|
||||
indices_flags idx_flags;
|
||||
indices_to_expressions(des, scope, this,
|
||||
use_comp.index, net->unpacked_dimensions(),
|
||||
need_const,
|
||||
idx_flags,
|
||||
unpacked_indices,
|
||||
unpacked_indices_const);
|
||||
|
||||
NetExpr*canon_index = 0;
|
||||
|
||||
if (idx_flags.invalid) {
|
||||
// Nothing to do
|
||||
|
||||
} else if (idx_flags.undefined) {
|
||||
cerr << get_fileline() << ": warning: "
|
||||
<< "returning 'bx for undefined array access "
|
||||
<< net->name() << as_indices(unpacked_indices)
|
||||
<< "." << endl;
|
||||
|
||||
} else if (idx_flags.variable) {
|
||||
ivl_assert(*this, unpacked_indices.size() == net->unpacked_dimensions());
|
||||
canon_index = normalize_variable_unpacked(net, unpacked_indices);
|
||||
|
||||
} else {
|
||||
ivl_assert(*this, unpacked_indices_const.size() == net->unpacked_dimensions());
|
||||
canon_index = normalize_variable_unpacked(net, unpacked_indices_const);
|
||||
}
|
||||
|
||||
ivl_assert(*this, canon_index);
|
||||
NetESignal*tmp = new NetESignal(net, canon_index);
|
||||
tmp->set_line(*this);
|
||||
|
||||
return tmp;
|
||||
|
|
@ -3207,7 +3294,7 @@ NetExpr* PEIdent::elaborate_expr_class_member_(Design*des, NetScope*scope,
|
|||
if (path_.size() != 1)
|
||||
return 0;
|
||||
|
||||
const netclass_t*class_type = scope->parent()->class_def();
|
||||
const netclass_t*class_type = find_class_containing_scope(*this, scope);
|
||||
if (class_type == 0)
|
||||
return 0;
|
||||
|
||||
|
|
@ -3216,10 +3303,13 @@ NetExpr* PEIdent::elaborate_expr_class_member_(Design*des, NetScope*scope,
|
|||
if (pidx < 0)
|
||||
return 0;
|
||||
|
||||
NetNet*this_net = scope->find_signal(perm_string::literal("@"));
|
||||
NetScope*scope_method = find_method_containing_scope(*this, scope);
|
||||
ivl_assert(*this, scope_method);
|
||||
|
||||
NetNet*this_net = scope_method->find_signal(perm_string::literal("@"));
|
||||
if (this_net == 0) {
|
||||
cerr << get_fileline() << ": internal error: "
|
||||
<< "Unable to find 'this' port of " << scope_path(scope)
|
||||
<< "Unable to find 'this' port of " << scope_path(scope_method)
|
||||
<< "." << endl;
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -3229,7 +3319,8 @@ NetExpr* PEIdent::elaborate_expr_class_member_(Design*des, NetScope*scope,
|
|||
<< "Found member " << member_name
|
||||
<< " is a member of class " << class_type->get_name()
|
||||
<< ", context scope=" << scope_path(scope)
|
||||
<< ", so synthesizing a NetEProperty." << endl;
|
||||
<< ", type=" << *class_type->get_prop_type(pidx)
|
||||
<< ", so making a NetEProperty." << endl;
|
||||
}
|
||||
|
||||
property_qualifier_t qual = class_type->get_prop_qual(pidx);
|
||||
|
|
@ -3245,6 +3336,13 @@ NetExpr* PEIdent::elaborate_expr_class_member_(Design*des, NetScope*scope,
|
|||
return class_static_property_expression(this, class_type, member_name);
|
||||
}
|
||||
|
||||
ivl_type_t tmp_type = class_type->get_prop_type(pidx);
|
||||
if (/* const netuarray_t*tmp_ua =*/ dynamic_cast<const netuarray_t*>(tmp_type)) {
|
||||
cerr << get_fileline() << ": sorry: "
|
||||
<< "Unpacked array properties not supported yet." << endl;
|
||||
des->errors += 1;
|
||||
}
|
||||
|
||||
NetEProperty*tmp = new NetEProperty(this_net, member_name);
|
||||
tmp->set_line(*this);
|
||||
return tmp;
|
||||
|
|
@ -3295,6 +3393,12 @@ NetExpr* PEIdent::elaborate_expr_method_(Design*des, NetScope*scope,
|
|||
return 0;
|
||||
}
|
||||
|
||||
if (debug_elaborate) {
|
||||
cerr << get_fileline() << ": PEIdent::elaborate_expr_method_: "
|
||||
<< "Give up trying to find method " << member_name
|
||||
<< " of " << path_ << "." << endl;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
|||
68
elab_lval.cc
68
elab_lval.cc
|
|
@ -27,6 +27,7 @@
|
|||
# include "netstruct.h"
|
||||
# include "netclass.h"
|
||||
# include "netdarray.h"
|
||||
# include "netparray.h"
|
||||
# include "netvector.h"
|
||||
# include "compiler.h"
|
||||
# include <cstdlib>
|
||||
|
|
@ -259,6 +260,12 @@ NetAssign_* PEIdent::elaborate_lval(Design*des,
|
|||
}
|
||||
|
||||
ivl_assert(*this, reg);
|
||||
|
||||
if (debug_elaborate) {
|
||||
cerr << get_fileline() << ": PEIdent::elaborate_lval: "
|
||||
<< "Lval reg = " << reg->name() << endl;
|
||||
}
|
||||
|
||||
// We are processing the tail of a string of names. For
|
||||
// example, the verilog may be "a.b.c", so we are processing
|
||||
// "c" at this point. (Note that if method_name is not nil,
|
||||
|
|
@ -385,23 +392,68 @@ NetAssign_* PEIdent::elaborate_lval_method_class_member_(Design*des,
|
|||
if (path_.size() != 1)
|
||||
return 0;
|
||||
|
||||
const netclass_t*class_type = scope->parent()->class_def();
|
||||
const netclass_t*class_type = find_class_containing_scope(*this, scope);
|
||||
if (class_type == 0)
|
||||
return 0;
|
||||
|
||||
perm_string member_name = peek_tail_name(path_);
|
||||
const name_component_t&name_comp = path_.back();
|
||||
|
||||
perm_string member_name = name_comp.name;
|
||||
int pidx = class_type->property_idx_from_name(member_name);
|
||||
if (pidx < 0)
|
||||
return 0;
|
||||
|
||||
NetNet*this_net = scope->find_signal(perm_string::literal("@"));
|
||||
NetScope*scope_method = find_method_containing_scope(*this, scope);
|
||||
ivl_assert(*this, scope_method);
|
||||
|
||||
NetNet*this_net = scope_method->find_signal(perm_string::literal("@"));
|
||||
if (this_net == 0) {
|
||||
cerr << get_fileline() << ": internal error: "
|
||||
<< "Unable to find 'this' port of " << scope_path(scope)
|
||||
<< "Unable to find 'this' port of " << scope_path(scope_method)
|
||||
<< "." << endl;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (debug_elaborate) {
|
||||
cerr << get_fileline() << ": PEIdent::elaborate_lval_method_class_member_: "
|
||||
<< "Ident " << member_name
|
||||
<< " is a property of class " << class_type->get_name() << endl;
|
||||
}
|
||||
|
||||
NetExpr*canon_index = 0;
|
||||
if (name_comp.index.size() > 0) {
|
||||
ivl_type_t property_type = class_type->get_prop_type(pidx);
|
||||
|
||||
if (const netsarray_t* stype = dynamic_cast<const netsarray_t*> (property_type)) {
|
||||
list<long> indices_const;
|
||||
list<NetExpr*> indices_expr;
|
||||
indices_flags flags;
|
||||
indices_to_expressions(des, scope, this,
|
||||
name_comp.index, name_comp.index.size(),
|
||||
false, flags,
|
||||
indices_expr, indices_const);
|
||||
|
||||
if (flags.undefined) {
|
||||
cerr << get_fileline() << ": warning: "
|
||||
<< "ignoring undefined l-value array access "
|
||||
<< member_name
|
||||
<< " (" << path_ << ")"
|
||||
<< "." << endl;
|
||||
} else if (flags.variable) {
|
||||
canon_index = normalize_variable_unpacked(*this, stype, indices_expr);
|
||||
|
||||
} else {
|
||||
canon_index = normalize_variable_unpacked(stype, indices_const);
|
||||
}
|
||||
|
||||
|
||||
} else {
|
||||
cerr << get_fileline() << ": error: "
|
||||
<< "Index expressions don't apply to this type of property." << endl;
|
||||
des->errors += 1;
|
||||
}
|
||||
}
|
||||
|
||||
// Detect assignment to constant properties. Note that the
|
||||
// initializer constructor MAY assign to constant properties,
|
||||
// as this is how the property gets its value.
|
||||
|
|
@ -436,8 +488,16 @@ NetAssign_* PEIdent::elaborate_lval_method_class_member_(Design*des,
|
|||
}
|
||||
}
|
||||
|
||||
ivl_type_t tmp_type = class_type->get_prop_type(pidx);
|
||||
if (const netuarray_t*tmp_ua = dynamic_cast<const netuarray_t*>(tmp_type)) {
|
||||
cerr << get_fileline() << ": sorry: "
|
||||
<< "Unpacked array properties (l-values) not supported yet." << endl;
|
||||
des->errors += 1;
|
||||
}
|
||||
|
||||
NetAssign_*this_lval = new NetAssign_(this_net);
|
||||
this_lval->set_property(member_name);
|
||||
if (canon_index) this_lval->set_word(canon_index);
|
||||
|
||||
return this_lval;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -434,17 +434,19 @@ static void elaborate_scope_class(Design*des, NetScope*scope, PClass*pclass)
|
|||
class_scope->set_line(pclass);
|
||||
class_scope->set_class_def(use_class);
|
||||
use_class->set_class_scope(class_scope);
|
||||
use_class->set_definition_scope(scope);
|
||||
|
||||
// Collect the properties, elaborate them, and add them to the
|
||||
// elaborated class definition.
|
||||
for (map<perm_string, class_type_t::prop_info_t>::iterator cur = use_type->properties.begin()
|
||||
; cur != use_type->properties.end() ; ++ cur) {
|
||||
if (debug_scopes) {
|
||||
cerr << pclass->get_fileline() << ": elaborate_scope_class: "
|
||||
<< " Property " << cur->first << endl;
|
||||
}
|
||||
ivl_type_s*tmp = cur->second.type->elaborate_type(des, scope);
|
||||
ivl_assert(*pclass, tmp);
|
||||
if (debug_scopes) {
|
||||
cerr << pclass->get_fileline() << ": elaborate_scope_class: "
|
||||
<< " Property " << cur->first
|
||||
<< " type=" << *tmp << endl;
|
||||
}
|
||||
use_class->set_property(cur->first, cur->second.qual, tmp);
|
||||
}
|
||||
|
||||
|
|
|
|||
53
elab_sig.cc
53
elab_sig.cc
|
|
@ -836,48 +836,6 @@ void PWhile::elaborate_sig(Design*des, NetScope*scope) const
|
|||
statement_->elaborate_sig(des, scope);
|
||||
}
|
||||
|
||||
static bool evaluate_ranges(Design*des, NetScope*scope,
|
||||
vector<netrange_t>&llist,
|
||||
const list<pform_range_t>&rlist)
|
||||
{
|
||||
bool bad_msb = false, bad_lsb = false;
|
||||
|
||||
for (list<pform_range_t>::const_iterator cur = rlist.begin()
|
||||
; cur != rlist.end() ; ++cur) {
|
||||
long use_msb, use_lsb;
|
||||
|
||||
NetExpr*texpr = elab_and_eval(des, scope, cur->first, -1, true);
|
||||
if (! eval_as_long(use_msb, texpr)) {
|
||||
cerr << cur->first->get_fileline() << ": error: "
|
||||
"Range expressions must be constant." << endl;
|
||||
cerr << cur->first->get_fileline() << " : "
|
||||
"This MSB expression violates the rule: "
|
||||
<< *cur->first << endl;
|
||||
des->errors += 1;
|
||||
bad_msb = true;
|
||||
}
|
||||
|
||||
delete texpr;
|
||||
|
||||
texpr = elab_and_eval(des, scope, cur->second, -1, true);
|
||||
if (! eval_as_long(use_lsb, texpr)) {
|
||||
cerr << cur->second->get_fileline() << ": error: "
|
||||
"Range expressions must be constant." << endl;
|
||||
cerr << cur->second->get_fileline() << " : "
|
||||
"This LSB expression violates the rule: "
|
||||
<< *cur->second << endl;
|
||||
des->errors += 1;
|
||||
bad_lsb = true;
|
||||
}
|
||||
|
||||
delete texpr;
|
||||
|
||||
llist.push_back(netrange_t(use_msb, use_lsb));
|
||||
}
|
||||
|
||||
return bad_msb | bad_lsb;
|
||||
}
|
||||
|
||||
static netclass_t* locate_class_type(Design*, NetScope*scope,
|
||||
class_type_t*class_type)
|
||||
{
|
||||
|
|
@ -1222,13 +1180,12 @@ NetNet* PWire::elaborate_sig(Design*des, NetScope*scope) const
|
|||
}
|
||||
ivl_assert(*this, use_type);
|
||||
if (debug_elaborate) {
|
||||
cerr << get_fileline() << ": debug: "
|
||||
cerr << get_fileline() << ": PWire::elaborate_sig: "
|
||||
<< "Create class instance signal " << wtype
|
||||
<< " " << name_ << endl;
|
||||
<< " " << packed_dimensions << name_ << unpacked_dimensions << endl;
|
||||
}
|
||||
// (No arrays of classes)
|
||||
list<netrange_t> use_unpacked;
|
||||
sig = new NetNet(scope, name_, wtype, use_unpacked, use_type);
|
||||
|
||||
sig = new NetNet(scope, name_, wtype, unpacked_dimensions, use_type);
|
||||
|
||||
} else if (struct_type_t*struct_type = dynamic_cast<struct_type_t*>(set_data_type_)) {
|
||||
// If this is a struct type, then build the net with the
|
||||
|
|
@ -1289,7 +1246,7 @@ NetNet* PWire::elaborate_sig(Design*des, NetScope*scope) const
|
|||
|
||||
if (debug_elaborate) {
|
||||
cerr << get_fileline() << ": debug: Create signal " << wtype
|
||||
<< " parray=" << use_type->packed_dimensions()
|
||||
<< " parray=" << use_type->static_dimensions()
|
||||
<< " " << name_ << unpacked_dimensions
|
||||
<< " in scope " << scope_path(scope) << endl;
|
||||
}
|
||||
|
|
|
|||
19
elab_type.cc
19
elab_type.cc
|
|
@ -22,6 +22,7 @@
|
|||
# include "netclass.h"
|
||||
# include "netdarray.h"
|
||||
# include "netenum.h"
|
||||
# include "netparray.h"
|
||||
# include "netscalar.h"
|
||||
# include "netstruct.h"
|
||||
# include "netvector.h"
|
||||
|
|
@ -203,9 +204,21 @@ ivl_type_s* uarray_type_t::elaborate_type_raw(Design*des, NetScope*scope) const
|
|||
|
||||
ivl_type_t btype = base_type->elaborate_type(des, scope);
|
||||
|
||||
assert(dims->size() == 1);
|
||||
assert(dims->size() >= 1);
|
||||
list<pform_range_t>::const_iterator cur = dims->begin();
|
||||
assert(cur->first == 0 && cur->second==0);
|
||||
ivl_type_s*res = new netdarray_t(btype);
|
||||
|
||||
// Special case: if the dimension is nil:nil, this is a
|
||||
// dynamic array. Note that we only know how to handle dynamic
|
||||
// arrays with 1 dimension at a time.
|
||||
if (cur->first==0 && cur->second==0) {
|
||||
assert(dims->size()==1);
|
||||
ivl_type_s*res = new netdarray_t(btype);
|
||||
return res;
|
||||
}
|
||||
|
||||
vector<netrange_t> dimensions;
|
||||
bool bad_range = evaluate_ranges(des, scope, dimensions, *dims);
|
||||
|
||||
ivl_type_s*res = new netuarray_t(dimensions, btype);
|
||||
return res;
|
||||
}
|
||||
|
|
|
|||
202
elaborate.cc
202
elaborate.cc
|
|
@ -40,6 +40,7 @@
|
|||
# include "netlist.h"
|
||||
# include "netvector.h"
|
||||
# include "netdarray.h"
|
||||
# include "netparray.h"
|
||||
# include "netclass.h"
|
||||
# include "netmisc.h"
|
||||
# include "util.h"
|
||||
|
|
@ -2290,6 +2291,14 @@ NetAssign_* PAssign_::elaborate_lval(Design*des, NetScope*scope) const
|
|||
NetAssign_*lv = new NetAssign_(tmp);
|
||||
return lv;
|
||||
}
|
||||
|
||||
if (debug_elaborate) {
|
||||
cerr << get_fileline() << ": PAssign_::elaborate_lval: "
|
||||
<< "lval_ = " << *lval_ << endl;
|
||||
cerr << get_fileline() << ": PAssign_::elaborate_lval: "
|
||||
<< "lval_ expr type = " << typeid(*lval_).name() << endl;
|
||||
}
|
||||
|
||||
return lval_->elaborate_lval(des, scope, false, false);
|
||||
}
|
||||
|
||||
|
|
@ -2520,6 +2529,22 @@ NetProc* PAssign::elaborate(Design*des, NetScope*scope) const
|
|||
|
||||
rv = elaborate_rval_(des, scope, use_lv_type);
|
||||
|
||||
} else if (const netuarray_t*utype = dynamic_cast<const netuarray_t*>(lv_net_type)) {
|
||||
ivl_assert(*this, lv->more==0);
|
||||
if (debug_elaborate) {
|
||||
if (lv->word())
|
||||
cerr << get_fileline() << ": PAssign::elaborate: "
|
||||
<< "lv->word() = " << *lv->word() << endl;
|
||||
else
|
||||
cerr << get_fileline() << ": PAssign::elaborate: "
|
||||
<< "lv->word() = <nil>" << endl;
|
||||
}
|
||||
ivl_type_t use_lv_type = lv_net_type;
|
||||
ivl_assert(*this, lv->word());
|
||||
use_lv_type = utype->element_type();
|
||||
|
||||
rv = elaborate_rval_(des, scope, use_lv_type);
|
||||
|
||||
} else {
|
||||
/* Elaborate the r-value expression, then try to evaluate it. */
|
||||
rv = elaborate_rval_(des, scope, lv_net_type, lv->expr_type(), count_lval_width(lv));
|
||||
|
|
@ -4580,6 +4605,20 @@ NetForce* PForce::elaborate(Design*des, NetScope*scope) const
|
|||
return dev;
|
||||
}
|
||||
|
||||
static void find_property_in_class(const LineInfo&loc, const NetScope*scope, perm_string name, const netclass_t*&found_in, int&property)
|
||||
{
|
||||
found_in = find_class_containing_scope(loc, scope);
|
||||
property = -1;
|
||||
|
||||
if (found_in==0) return;
|
||||
|
||||
property = found_in->property_idx_from_name(name);
|
||||
if (property < 0) {
|
||||
found_in = 0;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* The foreach statement can be written as a for statement like so:
|
||||
*
|
||||
|
|
@ -4591,24 +4630,104 @@ NetForce* PForce::elaborate(Design*des, NetScope*scope) const
|
|||
*/
|
||||
NetProc* PForeach::elaborate(Design*des, NetScope*scope) const
|
||||
{
|
||||
// Get the signal for the index variable.
|
||||
pform_name_t index_name;
|
||||
index_name.push_back(name_component_t(index_var_));
|
||||
NetNet*idx_sig = des->find_signal(scope, index_name);
|
||||
ivl_assert(*this, idx_sig);
|
||||
|
||||
NetESignal*idx_exp = new NetESignal(idx_sig);
|
||||
idx_exp->set_line(*this);
|
||||
|
||||
// Get the signal for the array variable
|
||||
// Locate the signal for the array variable
|
||||
pform_name_t array_name;
|
||||
array_name.push_back(name_component_t(array_var_));
|
||||
NetNet*array_sig = des->find_signal(scope, array_name);
|
||||
|
||||
// And if necessary, look for the class property that is
|
||||
// referenced.
|
||||
const netclass_t*class_scope = 0;
|
||||
int class_property = -1;
|
||||
if (array_sig == 0)
|
||||
find_property_in_class(*this, scope, array_var_, class_scope, class_property);
|
||||
|
||||
if (debug_elaborate && array_sig) {
|
||||
cerr << get_fileline() << ": PForeach::elaborate: "
|
||||
<< "Found array_sig in " << scope_path(array_sig->scope()) << "." << endl;
|
||||
}
|
||||
|
||||
if (debug_elaborate && class_scope) {
|
||||
cerr << get_fileline() << ": PForeach::elaborate: "
|
||||
<< "Found array_sig property (" << class_property
|
||||
<< ") in class " << class_scope->get_name()
|
||||
<< " as " << *class_scope->get_prop_type(class_property) << "." << endl;
|
||||
}
|
||||
|
||||
if (class_scope!=0 && class_property >= 0) {
|
||||
ivl_type_t ptype = class_scope->get_prop_type(class_property);
|
||||
const netsarray_t*atype = dynamic_cast<const netsarray_t*> (ptype);
|
||||
if (atype == 0) {
|
||||
cerr << get_fileline() << ": error: "
|
||||
<< "I can't handle the type of " << array_var_
|
||||
<< " as a foreach loop." << endl;
|
||||
des->errors += 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
const std::vector<netrange_t>&dims = atype->static_dimensions();
|
||||
if (dims.size() < index_vars_.size()) {
|
||||
cerr << get_fileline() << ": error: "
|
||||
<< "class " << class_scope->get_name()
|
||||
<< " property " << array_var_
|
||||
<< " has too few dimensions for foreach dimension list." << endl;
|
||||
des->errors += 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
return elaborate_static_array_(des, scope, dims);
|
||||
}
|
||||
|
||||
if (array_sig == 0) {
|
||||
cerr << get_fileline() << ": error:"
|
||||
<< " Unable to find foreach array " << array_name
|
||||
<< " in scope " << scope_path(scope)
|
||||
<< "." << endl;
|
||||
des->errors += 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
ivl_assert(*this, array_sig);
|
||||
|
||||
if (debug_elaborate) {
|
||||
cerr << get_fileline() << ": PForeach::elaborate: "
|
||||
<< "Scan array " << array_sig->name()
|
||||
<< " of " << array_sig->data_type()
|
||||
<< " with " << array_sig->unpacked_dimensions() << " unpacked"
|
||||
<< " and " << array_sig->packed_dimensions()
|
||||
<< " packed dimensions." << endl;
|
||||
}
|
||||
|
||||
// Classic arrays are processed this way.
|
||||
if (array_sig->data_type()==IVL_VT_BOOL)
|
||||
return elaborate_static_array_(des, scope, array_sig->unpacked_dims());
|
||||
if (array_sig->data_type()==IVL_VT_LOGIC)
|
||||
return elaborate_static_array_(des, scope, array_sig->unpacked_dims());
|
||||
if (array_sig->unpacked_dimensions() >= index_vars_.size())
|
||||
return elaborate_static_array_(des, scope, array_sig->unpacked_dims());
|
||||
|
||||
|
||||
// At this point, we know that the array is dynamic so we
|
||||
// handle that slightly differently, using run-time tests.
|
||||
|
||||
if (index_vars_.size() != 1) {
|
||||
cerr << get_fileline() << ": sorry: "
|
||||
<< "Multi-index foreach loops not supported." << endl;
|
||||
des->errors += 1;
|
||||
}
|
||||
|
||||
// Get the signal for the index variable.
|
||||
pform_name_t index_name;
|
||||
index_name.push_back(name_component_t(index_vars_[0]));
|
||||
NetNet*idx_sig = des->find_signal(scope, index_name);
|
||||
ivl_assert(*this, idx_sig);
|
||||
|
||||
NetESignal*array_exp = new NetESignal(array_sig);
|
||||
array_exp->set_line(*this);
|
||||
|
||||
NetESignal*idx_exp = new NetESignal(idx_sig);
|
||||
idx_exp->set_line(*this);
|
||||
|
||||
// Make an initialization expression for the index.
|
||||
NetESFunc*init_expr = new NetESFunc("$low", IVL_VT_BOOL, 32, 1);
|
||||
init_expr->set_line(*this);
|
||||
|
|
@ -4639,6 +4758,69 @@ NetProc* PForeach::elaborate(Design*des, NetScope*scope) const
|
|||
return stmt;
|
||||
}
|
||||
|
||||
/*
|
||||
* This is a variant of the PForeach::elaborate() method that handles
|
||||
* the case that the array has static dimensions. We can use constants
|
||||
* and possibly do some optimizations.
|
||||
*/
|
||||
NetProc* PForeach::elaborate_static_array_(Design*des, NetScope*scope,
|
||||
const vector<netrange_t>&dims) const
|
||||
{
|
||||
if (debug_elaborate) {
|
||||
cerr << get_fileline() << ": PForeach::elaborate_static_array_: "
|
||||
<< "Handle as array with static dimensions." << endl;
|
||||
}
|
||||
|
||||
ivl_assert(*this, index_vars_.size() > 0);
|
||||
ivl_assert(*this, dims.size() == index_vars_.size());
|
||||
|
||||
NetProc*sub = statement_->elaborate(des, scope);
|
||||
NetForLoop*stmt = 0;
|
||||
|
||||
for (int idx_idx = index_vars_.size()-1 ; idx_idx >= 0 ; idx_idx -= 1) {
|
||||
const netrange_t&idx_range = dims[idx_idx];
|
||||
|
||||
// Get the $high and $low constant values for this slice
|
||||
// of the array.
|
||||
NetEConst*hig_expr = make_const_val_s(idx_range.get_msb());
|
||||
NetEConst*low_expr = make_const_val_s(idx_range.get_lsb());
|
||||
if (idx_range.get_msb() < idx_range.get_lsb()) {
|
||||
NetEConst*tmp = hig_expr;
|
||||
hig_expr = low_expr;
|
||||
low_expr = tmp;
|
||||
}
|
||||
|
||||
hig_expr->set_line(*this);
|
||||
low_expr->set_line(*this);
|
||||
|
||||
pform_name_t idx_name;
|
||||
idx_name.push_back(name_component_t(index_vars_[idx_idx]));
|
||||
NetNet*idx_sig = des->find_signal(scope, idx_name);
|
||||
ivl_assert(*this, idx_sig);
|
||||
|
||||
// Make the condition expression <idx> <= $high(slice)
|
||||
NetESignal*idx_expr = new NetESignal(idx_sig);
|
||||
idx_expr->set_line(*this);
|
||||
|
||||
NetEBComp*cond_expr = new NetEBComp('L', idx_expr, hig_expr);
|
||||
cond_expr->set_line(*this);
|
||||
|
||||
// Make the step statement: <idx> += 1
|
||||
NetAssign_*idx_lv = new NetAssign_(idx_sig);
|
||||
NetEConst*step_val = make_const_val_s(1);
|
||||
NetAssign*step = new NetAssign(idx_lv, '+', step_val);
|
||||
step->set_line(*this);
|
||||
|
||||
stmt = new NetForLoop(idx_sig, low_expr, cond_expr, sub, step);
|
||||
stmt->set_line(*this);
|
||||
stmt->wrap_up();
|
||||
|
||||
sub = stmt;
|
||||
}
|
||||
|
||||
return stmt? stmt : sub;
|
||||
}
|
||||
|
||||
/*
|
||||
* elaborate the for loop as the equivalent while loop. This eases the
|
||||
* task for the target code generator. The structure is:
|
||||
|
|
|
|||
16
emit.cc
16
emit.cc
|
|
@ -409,14 +409,13 @@ void NetRepeat::emit_recurse(struct target_t*tgt) const
|
|||
void netclass_t::emit_scope(struct target_t*tgt) const
|
||||
{
|
||||
class_scope_->emit_scope(tgt);
|
||||
class_scope_->emit_defs(tgt);
|
||||
}
|
||||
|
||||
void NetScope::emit_scope(struct target_t*tgt) const
|
||||
{
|
||||
if (debug_emit) {
|
||||
cerr << "NetScope::emit_scope: "
|
||||
<< "Emit scope basename=" << basename() << endl;
|
||||
<< "Emit scope " << scope_path(this) << endl;
|
||||
}
|
||||
|
||||
tgt->scope(this);
|
||||
|
|
@ -461,12 +460,20 @@ bool NetScope::emit_defs(struct target_t*tgt) const
|
|||
{
|
||||
bool flag = true;
|
||||
|
||||
if (debug_emit) {
|
||||
cerr << "NetScope::emit_defs: "
|
||||
<< "Emit definitions for " << scope_path(this) << endl;
|
||||
}
|
||||
|
||||
switch (type_) {
|
||||
case PACKAGE:
|
||||
case MODULE:
|
||||
for (map<hname_t,NetScope*>::const_iterator cur = children_.begin()
|
||||
; cur != children_.end() ; ++ cur )
|
||||
flag &= cur->second->emit_defs(tgt);
|
||||
for (map<perm_string,netclass_t*>::const_iterator cur = classes_.begin()
|
||||
; cur != classes_.end() ; ++ cur)
|
||||
flag &= cur->second->emit_defs(tgt);
|
||||
break;
|
||||
|
||||
case FUNC:
|
||||
|
|
@ -485,6 +492,11 @@ bool NetScope::emit_defs(struct target_t*tgt) const
|
|||
return flag;
|
||||
}
|
||||
|
||||
bool netclass_t::emit_defs(struct target_t*tgt) const
|
||||
{
|
||||
return class_scope_->emit_defs(tgt);
|
||||
}
|
||||
|
||||
int Design::emit(struct target_t*tgt) const
|
||||
{
|
||||
int rc = 0;
|
||||
|
|
|
|||
|
|
@ -139,7 +139,7 @@ void NetForLoop::wrap_up()
|
|||
NetBlock*internal_block = new NetBlock(NetBlock::SEQU, 0);
|
||||
internal_block->set_line(*this);
|
||||
|
||||
internal_block->append(statement_);
|
||||
if (statement_) internal_block->append(statement_);
|
||||
internal_block->append(step_statement_);
|
||||
|
||||
NetWhile*wloop = new NetWhile(condition_, internal_block);
|
||||
|
|
|
|||
|
|
@ -654,6 +654,13 @@ netclass_t*NetScope::find_class(perm_string name)
|
|||
if (type_==MODULE)
|
||||
return 0;
|
||||
|
||||
if (up_==0 && type_==CLASS) {
|
||||
assert(class_def_);
|
||||
|
||||
NetScope*def_parent = class_def_->definition_scope();
|
||||
return def_parent->find_class(name);
|
||||
}
|
||||
|
||||
// If there is no further to look, ...
|
||||
if (up_ == 0)
|
||||
return 0;
|
||||
|
|
|
|||
|
|
@ -24,7 +24,7 @@
|
|||
using namespace std;
|
||||
|
||||
netclass_t::netclass_t(perm_string name, netclass_t*sup)
|
||||
: name_(name), super_(sup), class_scope_(0)
|
||||
: name_(name), super_(sup), class_scope_(0), definition_scope_(0)
|
||||
{
|
||||
}
|
||||
|
||||
|
|
@ -56,6 +56,12 @@ void netclass_t::set_class_scope(NetScope*class_scope)
|
|||
class_scope_ = class_scope;
|
||||
}
|
||||
|
||||
void netclass_t::set_definition_scope(NetScope*definition_scope)
|
||||
{
|
||||
assert(definition_scope_ == 0);
|
||||
definition_scope_ = definition_scope;
|
||||
}
|
||||
|
||||
ivl_variable_type_t netclass_t::base_type() const
|
||||
{
|
||||
return IVL_VT_CLASS;
|
||||
|
|
|
|||
24
netclass.h
24
netclass.h
|
|
@ -43,9 +43,19 @@ class netclass_t : public ivl_type_s {
|
|||
bool set_property(perm_string pname, property_qualifier_t qual, ivl_type_s*ptype);
|
||||
|
||||
// Set the scope for the class. The scope has no parents and
|
||||
// is used for the elaboration of methods (tasks/functions).
|
||||
// is used for the elaboration of methods
|
||||
// (tasks/functions). In other words, this is the class itself.
|
||||
void set_class_scope(NetScope*cscope);
|
||||
|
||||
// Set the scope for the class definition. This is the scope
|
||||
// where the class definition was encountered, and may be used
|
||||
// to locate symbols that the class definition may inherit
|
||||
// from its context. This can be nil, or a package or module
|
||||
// where a class is defined.
|
||||
void set_definition_scope(NetScope*dscope);
|
||||
|
||||
NetScope*definition_scope(void);
|
||||
|
||||
// As an ivl_type_s object, the netclass is always an
|
||||
// ivl_VT_CLASS object.
|
||||
ivl_variable_type_t base_type() const;
|
||||
|
|
@ -74,7 +84,8 @@ class netclass_t : public ivl_type_s {
|
|||
|
||||
bool test_for_missing_initializers(void) const;
|
||||
|
||||
// Map the name of a property to its index.
|
||||
// Map the name of a property to its index. Return <0 if the
|
||||
// name is not a property in the class.
|
||||
int property_idx_from_name(perm_string pname) const;
|
||||
|
||||
// The task method scopes from the method name.
|
||||
|
|
@ -94,6 +105,7 @@ class netclass_t : public ivl_type_s {
|
|||
void elaborate(Design*des, PClass*pclass);
|
||||
|
||||
void emit_scope(struct target_t*tgt) const;
|
||||
bool emit_defs(struct target_t*tgt) const;
|
||||
|
||||
void dump_scope(ostream&fd) const;
|
||||
|
||||
|
|
@ -115,6 +127,14 @@ class netclass_t : public ivl_type_s {
|
|||
|
||||
// This holds task/function definitions for methods.
|
||||
NetScope*class_scope_;
|
||||
|
||||
// This holds the context for the class type definition.
|
||||
NetScope*definition_scope_;
|
||||
};
|
||||
|
||||
inline NetScope*netclass_t::definition_scope(void)
|
||||
{
|
||||
return definition_scope_;
|
||||
}
|
||||
|
||||
#endif /* IVL_netclass_H */
|
||||
|
|
|
|||
116
netmisc.cc
116
netmisc.cc
|
|
@ -22,6 +22,7 @@
|
|||
# include <cstdlib>
|
||||
# include <climits>
|
||||
# include "netlist.h"
|
||||
# include "netparray.h"
|
||||
# include "netvector.h"
|
||||
# include "netmisc.h"
|
||||
# include "PExpr.h"
|
||||
|
|
@ -526,10 +527,8 @@ static void make_strides(const vector<netrange_t>&dims,
|
|||
* word. If any of the indices are out of bounds, return nil instead
|
||||
* of an expression.
|
||||
*/
|
||||
NetExpr* normalize_variable_unpacked(const NetNet*net, list<long>&indices)
|
||||
static NetExpr* normalize_variable_unpacked(const vector<netrange_t>&dims, list<long>&indices)
|
||||
{
|
||||
const vector<netrange_t>&dims = net->unpacked_dims();
|
||||
|
||||
// Make strides for each index. The stride is the distance (in
|
||||
// words) to the next element in the canonical array.
|
||||
vector<long> stride (dims.size());
|
||||
|
|
@ -559,10 +558,20 @@ NetExpr* normalize_variable_unpacked(const NetNet*net, list<long>&indices)
|
|||
return canonical_expr;
|
||||
}
|
||||
|
||||
NetExpr* normalize_variable_unpacked(const NetNet*net, list<NetExpr*>&indices)
|
||||
NetExpr* normalize_variable_unpacked(const NetNet*net, list<long>&indices)
|
||||
{
|
||||
const vector<netrange_t>&dims = net->unpacked_dims();
|
||||
return normalize_variable_unpacked(dims, indices);
|
||||
}
|
||||
|
||||
NetExpr* normalize_variable_unpacked(const netsarray_t*stype, list<long>&indices)
|
||||
{
|
||||
const vector<netrange_t>&dims = stype->static_dimensions();
|
||||
return normalize_variable_unpacked(dims, indices);
|
||||
}
|
||||
|
||||
NetExpr* normalize_variable_unpacked(const LineInfo&loc, const vector<netrange_t>&dims, list<NetExpr*>&indices)
|
||||
{
|
||||
// Make strides for each index. The stride is the distance (in
|
||||
// words) to the next element in the canonical array.
|
||||
vector<long> stride (dims.size());
|
||||
|
|
@ -602,7 +611,7 @@ NetExpr* normalize_variable_unpacked(const NetNet*net, list<NetExpr*>&indices)
|
|||
if (use_stride != 1)
|
||||
min_wid += num_bits(use_stride);
|
||||
|
||||
tmp = pad_to_width(tmp, min_wid, *net);
|
||||
tmp = pad_to_width(tmp, min_wid, loc);
|
||||
|
||||
// Now generate the math to calculate the canonical address.
|
||||
NetExpr*tmp_scaled = 0;
|
||||
|
|
@ -641,11 +650,23 @@ NetExpr* normalize_variable_unpacked(const NetNet*net, list<NetExpr*>&indices)
|
|||
// If we don't have an expression at this point, all the indices were
|
||||
// constant zero. But this variant of normalize_variable_unpacked()
|
||||
// is only used when at least one index is not a constant.
|
||||
ivl_assert(*net, canonical_expr);
|
||||
ivl_assert(loc, canonical_expr);
|
||||
|
||||
return canonical_expr;
|
||||
}
|
||||
|
||||
NetExpr* normalize_variable_unpacked(const NetNet*net, list<NetExpr*>&indices)
|
||||
{
|
||||
const vector<netrange_t>&dims = net->unpacked_dims();
|
||||
return normalize_variable_unpacked(*net, dims, indices);
|
||||
}
|
||||
|
||||
NetExpr* normalize_variable_unpacked(const LineInfo&loc, const netsarray_t*stype, list<NetExpr*>&indices)
|
||||
{
|
||||
const vector<netrange_t>&dims = stype->static_dimensions();
|
||||
return normalize_variable_unpacked(loc, dims, indices);
|
||||
}
|
||||
|
||||
NetEConst* make_const_x(unsigned long wid)
|
||||
{
|
||||
verinum xxx (verinum::Vx, wid);
|
||||
|
|
@ -667,6 +688,14 @@ NetEConst* make_const_val(unsigned long value)
|
|||
return res;
|
||||
}
|
||||
|
||||
NetEConst* make_const_val_s(long value)
|
||||
{
|
||||
verinum tmp (value, integer_width);
|
||||
tmp.has_sign(true);
|
||||
NetEConst*res = new NetEConst(tmp);
|
||||
return res;
|
||||
}
|
||||
|
||||
NetNet* make_const_x(Design*des, NetScope*scope, unsigned long wid)
|
||||
{
|
||||
verinum xxx (verinum::Vx, wid);
|
||||
|
|
@ -877,6 +906,48 @@ NetExpr* elab_sys_task_arg(Design*des, NetScope*scope, perm_string name,
|
|||
return tmp;
|
||||
}
|
||||
|
||||
bool evaluate_ranges(Design*des, NetScope*scope,
|
||||
vector<netrange_t>&llist,
|
||||
const list<pform_range_t>&rlist)
|
||||
{
|
||||
bool bad_msb = false, bad_lsb = false;
|
||||
|
||||
for (list<pform_range_t>::const_iterator cur = rlist.begin()
|
||||
; cur != rlist.end() ; ++cur) {
|
||||
long use_msb, use_lsb;
|
||||
|
||||
NetExpr*texpr = elab_and_eval(des, scope, cur->first, -1, true);
|
||||
if (! eval_as_long(use_msb, texpr)) {
|
||||
cerr << cur->first->get_fileline() << ": error: "
|
||||
"Range expressions must be constant." << endl;
|
||||
cerr << cur->first->get_fileline() << " : "
|
||||
"This MSB expression violates the rule: "
|
||||
<< *cur->first << endl;
|
||||
des->errors += 1;
|
||||
bad_msb = true;
|
||||
}
|
||||
|
||||
delete texpr;
|
||||
|
||||
texpr = elab_and_eval(des, scope, cur->second, -1, true);
|
||||
if (! eval_as_long(use_lsb, texpr)) {
|
||||
cerr << cur->second->get_fileline() << ": error: "
|
||||
"Range expressions must be constant." << endl;
|
||||
cerr << cur->second->get_fileline() << " : "
|
||||
"This LSB expression violates the rule: "
|
||||
<< *cur->second << endl;
|
||||
des->errors += 1;
|
||||
bad_lsb = true;
|
||||
}
|
||||
|
||||
delete texpr;
|
||||
|
||||
llist.push_back(netrange_t(use_msb, use_lsb));
|
||||
}
|
||||
|
||||
return bad_msb | bad_lsb;
|
||||
}
|
||||
|
||||
void eval_expr(NetExpr*&expr, int context_width)
|
||||
{
|
||||
assert(expr);
|
||||
|
|
@ -1425,3 +1496,36 @@ NetPartSelect* detect_partselect_lval(Link&pin)
|
|||
|
||||
return found_ps;
|
||||
}
|
||||
|
||||
const netclass_t* find_class_containing_scope(const LineInfo&loc, const NetScope*scope)
|
||||
{
|
||||
while (scope && scope->type() != NetScope::CLASS)
|
||||
scope = scope->parent();
|
||||
|
||||
if (scope == 0)
|
||||
return 0;
|
||||
|
||||
const netclass_t*found_in = scope->class_def();
|
||||
ivl_assert(loc, found_in);
|
||||
return found_in;
|
||||
}
|
||||
/*
|
||||
* Find the scope that contains this scope, that is the method for a
|
||||
* class scope. Look for the scope whose PARENT is the scope for a
|
||||
* class. This is going to be a method.
|
||||
*/
|
||||
NetScope* find_method_containing_scope(const LineInfo&, NetScope*scope)
|
||||
{
|
||||
NetScope*up = scope->parent();
|
||||
|
||||
while (up && up->type() != NetScope::CLASS) {
|
||||
scope = up;
|
||||
up = up->parent();
|
||||
}
|
||||
|
||||
if (up == 0) return 0;
|
||||
|
||||
// Should I check if this scope is a TASK or FUNC?
|
||||
|
||||
return scope;
|
||||
}
|
||||
|
|
|
|||
16
netmisc.h
16
netmisc.h
|
|
@ -21,6 +21,8 @@
|
|||
|
||||
# include "netlist.h"
|
||||
|
||||
class netsarray_t;
|
||||
|
||||
/*
|
||||
* Search for a symbol using the "start" scope as the starting
|
||||
* point. If the path includes a scope part, then locate the
|
||||
|
|
@ -184,7 +186,10 @@ extern void indices_to_expressions(Design*des, NetScope*scope,
|
|||
list<NetExpr*>&indices,list<long>&indices_const);
|
||||
|
||||
extern NetExpr*normalize_variable_unpacked(const NetNet*net, list<long>&indices);
|
||||
extern NetExpr*normalize_variable_unpacked(const netsarray_t*net, list<long>&indices);
|
||||
|
||||
extern NetExpr*normalize_variable_unpacked(const NetNet*net, list<NetExpr*>&indices);
|
||||
extern NetExpr*normalize_variable_unpacked(const LineInfo&loc, const netsarray_t*net, list<NetExpr*>&indices);
|
||||
|
||||
/*
|
||||
* This function takes as input a NetNet signal and adds a constant
|
||||
|
|
@ -204,6 +209,7 @@ extern NetNet*sub_net_from(Design*des, NetScope*scope, long val, NetNet*sig);
|
|||
extern NetEConst*make_const_x(unsigned long wid);
|
||||
extern NetEConst*make_const_0(unsigned long wid);
|
||||
extern NetEConst*make_const_val(unsigned long val);
|
||||
extern NetEConst*make_const_val_s(long val);
|
||||
|
||||
/*
|
||||
* Make A const net
|
||||
|
|
@ -277,6 +283,9 @@ extern NetExpr* elaborate_rval_expr(Design*des, NetScope*scope,
|
|||
unsigned lv_width, PExpr*expr,
|
||||
bool need_const =false);
|
||||
|
||||
extern bool evaluate_ranges(Design*des, NetScope*scope,
|
||||
std::vector<netrange_t>&llist,
|
||||
const std::list<pform_range_t>&rlist);
|
||||
/*
|
||||
* This procedure evaluates an expression and if the evaluation is
|
||||
* successful the original expression is replaced with the new one.
|
||||
|
|
@ -300,6 +309,13 @@ extern hname_t eval_path_component(Design*des, NetScope*scope,
|
|||
const name_component_t&comp,
|
||||
bool&error_flag);
|
||||
|
||||
/*
|
||||
* If this scope is contained within a class scope (i.e. a method of a
|
||||
* class) then return the class definition that contains it.
|
||||
*/
|
||||
extern const netclass_t*find_class_containing_scope(const LineInfo&loc,const NetScope*scope);
|
||||
extern NetScope* find_method_containing_scope(const LineInfo&log, NetScope*scope);
|
||||
|
||||
/*
|
||||
* Return true if the data type is a type that is normally available
|
||||
* in vector for. IVL_VT_BOOL and IVL_VT_LOGIC are vectorable,
|
||||
|
|
|
|||
22
netparray.cc
22
netparray.cc
|
|
@ -22,6 +22,10 @@
|
|||
|
||||
using namespace std;
|
||||
|
||||
netsarray_t::~netsarray_t()
|
||||
{
|
||||
}
|
||||
|
||||
netparray_t::~netparray_t()
|
||||
{
|
||||
}
|
||||
|
|
@ -34,8 +38,8 @@ long netparray_t::packed_width(void) const
|
|||
{
|
||||
long cur_width = element_type()->packed_width();
|
||||
|
||||
for (vector<netrange_t>::const_iterator cur = packed_dims_.begin()
|
||||
; cur != packed_dims_.end() ; ++cur) {
|
||||
for (vector<netrange_t>::const_iterator cur = static_dimensions().begin()
|
||||
; cur != static_dimensions().end() ; ++cur) {
|
||||
cur_width *= cur->width();
|
||||
}
|
||||
|
||||
|
|
@ -44,14 +48,20 @@ long netparray_t::packed_width(void) const
|
|||
|
||||
vector<netrange_t> netparray_t::slice_dimensions() const
|
||||
{
|
||||
const vector<netrange_t>&packed_dims = static_dimensions();
|
||||
|
||||
vector<netrange_t> elem_dims = element_type()->slice_dimensions();
|
||||
|
||||
vector<netrange_t> res (packed_dims_.size() + elem_dims.size());
|
||||
vector<netrange_t> res (packed_dims.size() + elem_dims.size());
|
||||
|
||||
for (size_t idx = 0 ; idx < packed_dims_.size() ; idx += 1)
|
||||
res[idx] = packed_dims_[idx];
|
||||
for (size_t idx = 0 ; idx < packed_dims.size() ; idx += 1)
|
||||
res[idx] = packed_dims[idx];
|
||||
for (size_t idx = 0 ; idx < elem_dims.size() ; idx += 1)
|
||||
res[idx+packed_dims_.size()] = elem_dims[idx];
|
||||
res[idx+packed_dims.size()] = elem_dims[idx];
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
netuarray_t::~netuarray_t()
|
||||
{
|
||||
}
|
||||
|
|
|
|||
57
netparray.h
57
netparray.h
|
|
@ -23,10 +23,39 @@
|
|||
# include "nettypes.h"
|
||||
# include <vector>
|
||||
|
||||
/*
|
||||
* Arrays with static dimensions (packed and unpacked) share this
|
||||
* common base type.
|
||||
*/
|
||||
class netsarray_t : public netarray_t {
|
||||
|
||||
public:
|
||||
explicit netsarray_t(const std::vector<netrange_t>&packed,
|
||||
ivl_type_t etype);
|
||||
~netsarray_t();
|
||||
|
||||
public:
|
||||
// Virtual methods from the ivl_type_s type...
|
||||
|
||||
public:
|
||||
inline const std::vector<netrange_t>& static_dimensions() const
|
||||
{ return dims_; }
|
||||
|
||||
private:
|
||||
std::vector<netrange_t> dims_;
|
||||
|
||||
};
|
||||
|
||||
inline netsarray_t::netsarray_t(const std::vector<netrange_t>&pd,
|
||||
ivl_type_t etype)
|
||||
: netarray_t(etype), dims_(pd)
|
||||
{
|
||||
}
|
||||
|
||||
/*
|
||||
* Packed arrays.
|
||||
*/
|
||||
class netparray_t : public netarray_t {
|
||||
class netparray_t : public netsarray_t {
|
||||
|
||||
public:
|
||||
explicit netparray_t(const std::vector<netrange_t>&packed,
|
||||
|
|
@ -38,18 +67,28 @@ class netparray_t : public netarray_t {
|
|||
long packed_width(void) const;
|
||||
std::vector<netrange_t> slice_dimensions() const;
|
||||
|
||||
public:
|
||||
inline const std::vector<netrange_t>& packed_dimensions() const
|
||||
{ return packed_dims_; }
|
||||
|
||||
private:
|
||||
std::vector<netrange_t> packed_dims_;
|
||||
|
||||
};
|
||||
|
||||
inline netparray_t::netparray_t(const std::vector<netrange_t>&pd,
|
||||
ivl_type_t etype)
|
||||
: netarray_t(etype), packed_dims_(pd)
|
||||
: netsarray_t(pd, etype)
|
||||
{
|
||||
}
|
||||
|
||||
/*
|
||||
* Unpacked arrays are very similar, but lack packed slices.
|
||||
*/
|
||||
class netuarray_t : public netsarray_t {
|
||||
|
||||
public:
|
||||
explicit netuarray_t(const std::vector<netrange_t>&packed,
|
||||
ivl_type_t etype);
|
||||
~netuarray_t();
|
||||
};
|
||||
|
||||
inline netuarray_t::netuarray_t(const std::vector<netrange_t>&pd,
|
||||
ivl_type_t etype)
|
||||
: netsarray_t(pd, etype)
|
||||
{
|
||||
}
|
||||
|
||||
|
|
|
|||
7
parse.y
7
parse.y
|
|
@ -3457,11 +3457,14 @@ expr_primary
|
|||
| '{' '}'
|
||||
{ // This is the empty queue syntax.
|
||||
if (gn_system_verilog()) {
|
||||
yyerror(@1, "sorry: Expty queue expressions not supported.");
|
||||
list<PExpr*> empty_list;
|
||||
PEConcat*tmp = new PEConcat(empty_list);
|
||||
FILE_NAME(tmp, @1);
|
||||
$$ = tmp;
|
||||
} else {
|
||||
yyerror(@1, "error: Concatenations are not allowed to be empty.");
|
||||
$$ = 0;
|
||||
}
|
||||
$$ = 0;
|
||||
}
|
||||
|
||||
/* Cast expressions are primaries */
|
||||
|
|
|
|||
15
pform.cc
15
pform.cc
|
|
@ -739,19 +739,18 @@ PForeach* pform_make_foreach(const struct vlltype&loc,
|
|||
perm_string use_name = lex_strings.make(name);
|
||||
delete[]name;
|
||||
|
||||
perm_string use_index = loop_vars->front();
|
||||
loop_vars->pop_front();
|
||||
|
||||
if (! loop_vars->empty()) {
|
||||
cerr << loc.get_fileline() << ": sorry: "
|
||||
<< "Multi-dimension foreach indices not supported." << endl;
|
||||
if (loop_vars==0 || loop_vars->empty()) {
|
||||
cerr << loc.get_fileline() << ": error: "
|
||||
<< "No loop variables at all in foreach index." << endl;
|
||||
error_count += 1;
|
||||
}
|
||||
delete loop_vars;
|
||||
|
||||
PForeach*fe = new PForeach(use_name, use_index, stmt);
|
||||
ivl_assert(loc, loop_vars);
|
||||
PForeach*fe = new PForeach(use_name, *loop_vars, stmt);
|
||||
FILE_NAME(fe, loc);
|
||||
|
||||
delete loop_vars;
|
||||
|
||||
return fe;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -973,8 +973,13 @@ void PForeach::dump(ostream&fd, unsigned ind) const
|
|||
{
|
||||
fd << setw(ind) << "" << "foreach "
|
||||
<< "variable=" << array_var_
|
||||
<< ", index=" << index_var_
|
||||
<< " /* " << get_fileline() << " */" << endl;
|
||||
<< ", indices=[";
|
||||
for (size_t idx = 0 ; idx < index_vars_.size() ; idx += 1) {
|
||||
if (idx > 0) fd << ",";
|
||||
fd << index_vars_[idx];
|
||||
}
|
||||
|
||||
fd << "] /* " << get_fileline() << " */" << endl;
|
||||
statement_->dump(fd, ind+3);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -651,6 +651,11 @@ void dll_target::expr_ufunc(const NetEUFunc*net)
|
|||
FILE_NAME(expr, net);
|
||||
|
||||
expr->u_.ufunc_.def = lookup_scope_(net->func());
|
||||
if (expr->u_.ufunc_.def == 0) {
|
||||
cerr << net->get_fileline() << ": internal error: "
|
||||
<< "dll_target::expr_ufunc: "
|
||||
<< "Unable to match scope " << scope_path(net->func()) << endl;
|
||||
}
|
||||
ivl_assert(*net, expr->u_.ufunc_.def);
|
||||
ivl_assert(*net, expr->u_.ufunc_.def->type_ == IVL_SCT_FUNCTION);
|
||||
|
||||
|
|
|
|||
|
|
@ -519,7 +519,27 @@ static struct vector_info draw_binary_expr_eq_class(ivl_expr_t expr)
|
|||
}
|
||||
|
||||
if (ivl_expr_type(re) == IVL_EX_NULL && ivl_expr_type(le)==IVL_EX_SIGNAL) {
|
||||
fprintf(vvp_out, " %%test_nul v%p_0;\n", ivl_expr_signal(le));
|
||||
ivl_signal_t sig = ivl_expr_signal(le);
|
||||
|
||||
if (ivl_signal_dimensions(sig) == 0) {
|
||||
fprintf(vvp_out, " %%test_nul v%p_0;\n", sig);
|
||||
} else {
|
||||
ivl_expr_t word_ex = ivl_expr_oper1(le);
|
||||
int word_ix = allocate_word();
|
||||
draw_eval_expr_into_integer(word_ex, word_ix);
|
||||
fprintf(vvp_out, " %%test_nul/a v%p, %d;\n", sig, word_ix);
|
||||
clr_word(word_ix);
|
||||
}
|
||||
fprintf(vvp_out, " %%mov %u, 4, 1;\n", res.base);
|
||||
if (ivl_expr_opcode(expr) == 'n')
|
||||
fprintf(vvp_out, " %%inv %u, 1;\n", res.base);
|
||||
return res;
|
||||
}
|
||||
|
||||
if (ivl_expr_type(re) == IVL_EX_NULL && ivl_expr_value(le)==IVL_VT_CLASS) {
|
||||
draw_eval_object(le);
|
||||
fprintf(vvp_out, " %%test_nul/obj;\n");
|
||||
fprintf(vvp_out, " %%pop/obj 1, 0;\n");
|
||||
fprintf(vvp_out, " %%mov %u, 4, 1;\n", res.base);
|
||||
if (ivl_expr_opcode(expr) == 'n')
|
||||
fprintf(vvp_out, " %%inv %u, 1;\n", res.base);
|
||||
|
|
|
|||
|
|
@ -195,10 +195,25 @@ static int eval_object_shallowcopy(ivl_expr_t ex)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int eval_object_signal(ivl_expr_t ex)
|
||||
static int eval_object_signal(ivl_expr_t expr)
|
||||
{
|
||||
ivl_signal_t sig = ivl_expr_signal(ex);
|
||||
fprintf(vvp_out, " %%load/obj v%p_0;\n", sig);
|
||||
ivl_signal_t sig = ivl_expr_signal(expr);
|
||||
|
||||
/* Simple case: This is a simple variable. Generate a load
|
||||
statement to load the string into the stack. */
|
||||
if (ivl_signal_dimensions(sig) == 0) {
|
||||
fprintf(vvp_out, " %%load/obj v%p_0;\n", sig);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* There is a word select expression, so load the index into a
|
||||
register and load from the array. */
|
||||
ivl_expr_t word_ex = ivl_expr_oper1(expr);
|
||||
int word_ix = allocate_word();
|
||||
draw_eval_expr_into_integer(word_ex, word_ix);
|
||||
fprintf(vvp_out, " %%load/obja v%p, %d;\n", sig, word_ix);
|
||||
clr_word(word_ix);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -976,6 +976,30 @@ static int show_stmt_assign_sig_darray(ivl_statement_t net)
|
|||
return errors;
|
||||
}
|
||||
|
||||
static int show_stmt_assign_sig_queue(ivl_statement_t net)
|
||||
{
|
||||
int errors = 0;
|
||||
ivl_lval_t lval = ivl_stmt_lval(net, 0);
|
||||
ivl_expr_t rval = ivl_stmt_rval(net);
|
||||
ivl_signal_t var= ivl_lval_sig(lval);
|
||||
ivl_type_t var_type= ivl_signal_net_type(var);
|
||||
assert(ivl_type_base(var_type) == IVL_VT_QUEUE);
|
||||
|
||||
switch (ivl_expr_type(rval)) {
|
||||
case IVL_EX_NULL:
|
||||
errors += draw_eval_object(rval);
|
||||
break;
|
||||
default:
|
||||
fprintf(stderr, "XXXX: I don't know how to handle expr_type=%d here\n", ivl_expr_type(rval));
|
||||
fprintf(vvp_out, " ; XXXX expr_type=%d\n", ivl_expr_type(rval));
|
||||
errors += 1;
|
||||
break;
|
||||
}
|
||||
|
||||
fprintf(vvp_out, " %%store/obj v%p_0;\n", var);
|
||||
return errors;
|
||||
}
|
||||
|
||||
static int show_stmt_assign_sig_cobject(ivl_statement_t net)
|
||||
{
|
||||
int errors = 0;
|
||||
|
|
@ -1066,7 +1090,19 @@ static int show_stmt_assign_sig_cobject(ivl_statement_t net)
|
|||
as an object and assign the entire object to the
|
||||
variable. */
|
||||
errors += draw_eval_object(rval);
|
||||
fprintf(vvp_out, " %%store/obj v%p_0;\n", sig);
|
||||
|
||||
if (ivl_signal_array_count(sig) > 1) {
|
||||
unsigned ix;
|
||||
ivl_expr_t aidx = ivl_lval_idx(lval);
|
||||
|
||||
draw_eval_expr_into_integer(aidx, (ix = allocate_word()));
|
||||
fprintf(vvp_out, " %%store/obja v%p, %u;\n", sig, ix);
|
||||
clr_word(ix);
|
||||
|
||||
} else {
|
||||
/* Not an array, so no index expression */
|
||||
fprintf(vvp_out, " %%store/obj v%p_0;\n", sig);
|
||||
}
|
||||
}
|
||||
|
||||
return errors;
|
||||
|
|
@ -1094,6 +1130,10 @@ int show_stmt_assign(ivl_statement_t net)
|
|||
return show_stmt_assign_sig_darray(net);
|
||||
}
|
||||
|
||||
if (sig && (ivl_signal_data_type(sig) == IVL_VT_QUEUE)) {
|
||||
return show_stmt_assign_sig_queue(net);
|
||||
}
|
||||
|
||||
if (sig && (ivl_signal_data_type(sig) == IVL_VT_CLASS)) {
|
||||
return show_stmt_assign_sig_cobject(net);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -469,6 +469,10 @@ static void draw_reg_in_scope(ivl_signal_t sig)
|
|||
datatype_flag = "/str";
|
||||
vector_dims = 0;
|
||||
break;
|
||||
case IVL_VT_CLASS:
|
||||
datatype_flag = "/obj";
|
||||
vector_dims = 0;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
|
|
|||
51
vvp/array.cc
51
vvp/array.cc
|
|
@ -1055,6 +1055,18 @@ void array_set_word(vvp_array_t arr, unsigned address, const string&val)
|
|||
array_word_change(arr, address);
|
||||
}
|
||||
|
||||
void array_set_word(vvp_array_t arr, unsigned address, const vvp_object_t&val)
|
||||
{
|
||||
assert(arr->vals != 0);
|
||||
assert(arr->nets == 0);
|
||||
|
||||
if (address >= arr->vals->get_size())
|
||||
return;
|
||||
|
||||
arr->vals->set_word(address, val);
|
||||
array_word_change(arr, address);
|
||||
}
|
||||
|
||||
vvp_vector4_t array_get_word(vvp_array_t arr, unsigned address)
|
||||
{
|
||||
if (arr->vals4) {
|
||||
|
|
@ -1129,6 +1141,28 @@ double array_get_word_r(vvp_array_t arr, unsigned address)
|
|||
|
||||
}
|
||||
|
||||
void array_get_word_obj(vvp_array_t arr, unsigned address, vvp_object_t&val)
|
||||
{
|
||||
if (arr->vals) {
|
||||
assert(arr->vals4 == 0);
|
||||
assert(arr->nets == 0);
|
||||
// In this context, address out of bounds returns 0.0
|
||||
// instead of an error.
|
||||
if (address >= arr->vals->get_size()) {
|
||||
val = vvp_object_t();
|
||||
return;
|
||||
}
|
||||
|
||||
arr->vals->get_word(address, val);
|
||||
return;
|
||||
}
|
||||
|
||||
assert(arr->nets);
|
||||
// Arrays of string nets not implemented!
|
||||
assert(0);
|
||||
return;
|
||||
}
|
||||
|
||||
string array_get_word_str(vvp_array_t arr, unsigned address)
|
||||
{
|
||||
if (arr->vals) {
|
||||
|
|
@ -1354,6 +1388,23 @@ void compile_string_array(char*label, char*name, int last, int first)
|
|||
delete[] name;
|
||||
}
|
||||
|
||||
void compile_object_array(char*label, char*name, int last, int first)
|
||||
{
|
||||
vpiHandle obj = vpip_make_array(label, name, first, last, true);
|
||||
|
||||
struct __vpiArray*arr = dynamic_cast<__vpiArray*>(obj);
|
||||
|
||||
/* Make the words. */
|
||||
arr->vals = new vvp_darray_object(arr->array_count);
|
||||
arr->vals_width = 1;
|
||||
|
||||
count_real_arrays += 1;
|
||||
count_real_array_words += arr->array_count;
|
||||
|
||||
free(label);
|
||||
delete[] name;
|
||||
}
|
||||
|
||||
void compile_net_array(char*label, char*name, int last, int first)
|
||||
{
|
||||
// At this point we don't know the array data type, so we
|
||||
|
|
|
|||
|
|
@ -45,9 +45,12 @@ extern void array_set_word(vvp_array_t arr, unsigned idx,
|
|||
double val);
|
||||
extern void array_set_word(vvp_array_t arr, unsigned idx,
|
||||
const std::string&val);
|
||||
extern void array_set_word(vvp_array_t arr, unsigned idx,
|
||||
const vvp_object_t&val);
|
||||
|
||||
extern vvp_vector4_t array_get_word(vvp_array_t array, unsigned address);
|
||||
extern double array_get_word_r(vvp_array_t array, unsigned address);
|
||||
extern void array_get_word_obj(vvp_array_t array, unsigned address, vvp_object_t&val);
|
||||
extern std::string array_get_word_str(vvp_array_t array, unsigned address);
|
||||
|
||||
/* VPI hooks */
|
||||
|
|
|
|||
|
|
@ -133,6 +133,7 @@ extern bool of_LOAD_REAL(vthread_t thr, vvp_code_t code);
|
|||
extern bool of_LOAD_DAR_R(vthread_t thr, vvp_code_t code);
|
||||
extern bool of_LOAD_DAR_STR(vthread_t thr, vvp_code_t code);
|
||||
extern bool of_LOAD_OBJ(vthread_t thr, vvp_code_t code);
|
||||
extern bool of_LOAD_OBJA(vthread_t thr, vvp_code_t code);
|
||||
extern bool of_LOAD_STR(vthread_t thr, vvp_code_t code);
|
||||
extern bool of_LOAD_STRA(vthread_t thr, vvp_code_t code);
|
||||
extern bool of_LOAD_VEC(vthread_t thr, vvp_code_t code);
|
||||
|
|
@ -203,6 +204,7 @@ extern bool of_STORE_QB_STR(vthread_t thr, vvp_code_t code);
|
|||
extern bool of_STORE_QF_R(vthread_t thr, vvp_code_t code);
|
||||
extern bool of_STORE_QF_STR(vthread_t thr, vvp_code_t code);
|
||||
extern bool of_STORE_OBJ(vthread_t thr, vvp_code_t code);
|
||||
extern bool of_STORE_OBJA(vthread_t thr, vvp_code_t code);
|
||||
extern bool of_STORE_PROP_OBJ(vthread_t thr, vvp_code_t code);
|
||||
extern bool of_STORE_PROP_R(vthread_t thr, vvp_code_t code);
|
||||
extern bool of_STORE_PROP_STR(vthread_t thr, vvp_code_t code);
|
||||
|
|
@ -217,6 +219,8 @@ extern bool of_SUBI(vthread_t thr, vvp_code_t code);
|
|||
extern bool of_SUBSTR(vthread_t thr, vvp_code_t code);
|
||||
extern bool of_SUBSTR_V(vthread_t thr, vvp_code_t code);
|
||||
extern bool of_TEST_NUL(vthread_t thr, vvp_code_t code);
|
||||
extern bool of_TEST_NUL_A(vthread_t thr, vvp_code_t code);
|
||||
extern bool of_TEST_NUL_OBJ(vthread_t thr, vvp_code_t code);
|
||||
extern bool of_VPI_CALL(vthread_t thr, vvp_code_t code);
|
||||
extern bool of_WAIT(vthread_t thr, vvp_code_t code);
|
||||
extern bool of_WAIT_FORK(vthread_t thr, vvp_code_t code);
|
||||
|
|
|
|||
|
|
@ -180,6 +180,7 @@ static const struct opcode_table_s opcode_table[] = {
|
|||
{ "%load/dar/r", of_LOAD_DAR_R, 1, {OA_FUNC_PTR, OA_NONE, OA_NONE}},
|
||||
{ "%load/dar/str",of_LOAD_DAR_STR, 1, {OA_FUNC_PTR, OA_NONE, OA_NONE} },
|
||||
{ "%load/obj", of_LOAD_OBJ, 1,{OA_FUNC_PTR,OA_NONE, OA_NONE} },
|
||||
{ "%load/obja", of_LOAD_OBJA,2,{OA_ARR_PTR, OA_BIT1, OA_NONE} },
|
||||
{ "%load/real", of_LOAD_REAL,1,{OA_VPI_PTR, OA_NONE, OA_NONE} },
|
||||
{ "%load/str", of_LOAD_STR, 1,{OA_FUNC_PTR,OA_NONE, OA_NONE} },
|
||||
{ "%load/stra", of_LOAD_STRA,2,{OA_ARR_PTR, OA_BIT1, OA_NONE} },
|
||||
|
|
@ -224,8 +225,8 @@ static const struct opcode_table_s opcode_table[] = {
|
|||
{ "%pushv/str", of_PUSHV_STR, 2, {OA_BIT1,OA_BIT2, OA_NONE} },
|
||||
{ "%putc/str/v",of_PUTC_STR_V,3,{OA_FUNC_PTR,OA_BIT1, OA_BIT2} },
|
||||
{ "%qpop/b", of_QPOP_B, 3,{OA_FUNC_PTR,OA_BIT1, OA_BIT2} },
|
||||
{ "%qpop/f", of_QPOP_F, 3,{OA_FUNC_PTR,OA_BIT1, OA_BIT2} },
|
||||
{ "%qpop/b/str",of_QPOP_B_STR,1,{OA_FUNC_PTR,OA_NONE, OA_NONE} },
|
||||
{ "%qpop/f", of_QPOP_F, 3,{OA_FUNC_PTR,OA_BIT1, OA_BIT2} },
|
||||
{ "%qpop/f/str",of_QPOP_F_STR,1,{OA_FUNC_PTR,OA_NONE, OA_NONE} },
|
||||
{ "%release/net",of_RELEASE_NET,3,{OA_FUNC_PTR,OA_BIT1,OA_BIT2} },
|
||||
{ "%release/reg",of_RELEASE_REG,3,{OA_FUNC_PTR,OA_BIT1,OA_BIT2} },
|
||||
|
|
@ -246,6 +247,7 @@ static const struct opcode_table_s opcode_table[] = {
|
|||
{ "%store/dar/r", of_STORE_DAR_R, 1, {OA_FUNC_PTR, OA_NONE, OA_NONE} },
|
||||
{ "%store/dar/str",of_STORE_DAR_STR, 1, {OA_FUNC_PTR, OA_NONE, OA_NONE} },
|
||||
{ "%store/obj", of_STORE_OBJ, 1, {OA_FUNC_PTR,OA_NONE, OA_NONE} },
|
||||
{ "%store/obja", of_STORE_OBJA, 2, {OA_ARR_PTR, OA_BIT1, OA_NONE} },
|
||||
{ "%store/prop/obj",of_STORE_PROP_OBJ,1, {OA_NUMBER, OA_NONE, OA_NONE} },
|
||||
{ "%store/prop/r", of_STORE_PROP_R, 1, {OA_NUMBER, OA_NONE, OA_NONE} },
|
||||
{ "%store/prop/str",of_STORE_PROP_STR,1, {OA_NUMBER, OA_NONE, OA_NONE} },
|
||||
|
|
@ -263,7 +265,9 @@ static const struct opcode_table_s opcode_table[] = {
|
|||
{ "%subi", of_SUBI, 3, {OA_BIT1, OA_BIT2, OA_NUMBER} },
|
||||
{ "%substr", of_SUBSTR, 2,{OA_BIT1, OA_BIT2, OA_NONE} },
|
||||
{ "%substr/v",of_SUBSTR_V,3,{OA_BIT1, OA_BIT2, OA_NUMBER} },
|
||||
{ "%test_nul", of_TEST_NUL, 1,{OA_FUNC_PTR,OA_NONE, OA_NONE} },
|
||||
{ "%test_nul", of_TEST_NUL, 1,{OA_FUNC_PTR,OA_NONE, OA_NONE} },
|
||||
{ "%test_nul/a", of_TEST_NUL_A, 2,{OA_ARR_PTR, OA_BIT1, OA_NONE} },
|
||||
{ "%test_nul/obj",of_TEST_NUL_OBJ,0,{OA_NONE, OA_NONE, OA_NONE} },
|
||||
{ "%wait", of_WAIT, 1, {OA_FUNC_PTR, OA_NONE, OA_NONE} },
|
||||
{ "%wait/fork",of_WAIT_FORK,0,{OA_NONE, OA_NONE, OA_NONE} },
|
||||
{ "%xnor", of_XNOR, 3, {OA_BIT1, OA_BIT2, OA_NUMBER} },
|
||||
|
|
|
|||
|
|
@ -373,6 +373,8 @@ extern void compile_real_array(char*label, char*name,
|
|||
int last, int first);
|
||||
extern void compile_string_array(char*label, char*name,
|
||||
int last, int first);
|
||||
extern void compile_object_array(char*label, char*name,
|
||||
int last, int first);
|
||||
extern void compile_net_array(char*label, char*name,
|
||||
int last, int first);
|
||||
extern void compile_array_alias(char*label, char*name, char*src);
|
||||
|
|
|
|||
|
|
@ -124,6 +124,7 @@ static char* strdupnew(char const *str)
|
|||
".array/2s" { return K_ARRAY_2S; }
|
||||
".array/2u" { return K_ARRAY_2U; }
|
||||
".array/i" { return K_ARRAY_I; }
|
||||
".array/obj" { return K_ARRAY_OBJ; }
|
||||
".array/real" { return K_ARRAY_R; }
|
||||
".array/s" { return K_ARRAY_S; }
|
||||
".array/str" { return K_ARRAY_STR; }
|
||||
|
|
|
|||
|
|
@ -1134,10 +1134,14 @@ values into the vector space. The string value is NOT popped.
|
|||
|
||||
|
||||
* %test_nul <var-label>
|
||||
* %test_nul/obj
|
||||
|
||||
This instruction tests the contents of the addressed variable to see
|
||||
if it is null. If it is, set bit 4 to 1. Otherwise, set bit 4 to 0.
|
||||
|
||||
The %test_null/obj tests the object on the top of the stack, instead
|
||||
of any variable. The value in the stack is NOT popped.
|
||||
|
||||
This is intended to implement the SystemVerilog expression
|
||||
(<var>==null), where <var> is a class variable.
|
||||
|
||||
|
|
|
|||
|
|
@ -77,7 +77,7 @@ static struct __vpiModPath*modpath_dst = 0;
|
|||
%token K_ARITH_MOD_R K_ARITH_MOD_S
|
||||
%token K_ARITH_MULT K_ARITH_MULT_R K_ARITH_SUB K_ARITH_SUB_R
|
||||
%token K_ARITH_SUM K_ARITH_SUM_R K_ARITH_POW K_ARITH_POW_R K_ARITH_POW_S
|
||||
%token K_ARRAY K_ARRAY_2U K_ARRAY_2S K_ARRAY_I K_ARRAY_R K_ARRAY_S K_ARRAY_STR K_ARRAY_PORT
|
||||
%token K_ARRAY K_ARRAY_2U K_ARRAY_2S K_ARRAY_I K_ARRAY_OBJ K_ARRAY_R K_ARRAY_S K_ARRAY_STR K_ARRAY_PORT
|
||||
%token K_CAST_INT K_CAST_REAL K_CAST_REAL_S K_CAST_2
|
||||
%token K_CLASS
|
||||
%token K_CMP_EEQ K_CMP_EQ K_CMP_EQX K_CMP_EQZ
|
||||
|
|
@ -234,6 +234,9 @@ statement
|
|||
| T_LABEL K_ARRAY_STR T_STRING ',' signed_t_number signed_t_number ';'
|
||||
{ compile_string_array($1, $3, $5, $6); }
|
||||
|
||||
| T_LABEL K_ARRAY_OBJ T_STRING ',' signed_t_number signed_t_number ';'
|
||||
{ compile_object_array($1, $3, $5, $6); }
|
||||
|
||||
| T_LABEL K_ARRAY T_STRING ',' signed_t_number signed_t_number ';'
|
||||
{ compile_net_array($1, $3, $5, $6); }
|
||||
|
||||
|
|
|
|||
|
|
@ -3531,6 +3531,23 @@ bool of_LOAD_OBJ(vthread_t thr, vvp_code_t cp)
|
|||
return true;
|
||||
}
|
||||
|
||||
bool of_LOAD_OBJA(vthread_t thr, vvp_code_t cp)
|
||||
{
|
||||
unsigned idx = cp->bit_idx[0];
|
||||
unsigned adr = thr->words[idx].w_int;
|
||||
vvp_object_t word;
|
||||
|
||||
/* The result is 0.0 if the address is undefined. */
|
||||
if (thr_get_bit(thr, 4) == BIT4_1) {
|
||||
; // Return nil
|
||||
} else {
|
||||
array_get_word_obj(cp->array, adr, word);
|
||||
}
|
||||
|
||||
thr->push_object(word);
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
* %load/real <var-label>
|
||||
*/
|
||||
|
|
@ -5444,6 +5461,23 @@ bool of_STORE_OBJ(vthread_t thr, vvp_code_t cp)
|
|||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
* %store/obja <array-label> <index>
|
||||
*/
|
||||
bool of_STORE_OBJA(vthread_t thr, vvp_code_t cp)
|
||||
{
|
||||
unsigned idx = cp->bit_idx[0];
|
||||
unsigned adr = thr->words[idx].w_int;
|
||||
|
||||
vvp_object_t val;
|
||||
thr->pop_object(val);
|
||||
|
||||
array_set_word(cp->array, adr, val);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* %store/prop/obj <id>
|
||||
*
|
||||
|
|
@ -5798,6 +5832,36 @@ bool of_TEST_NUL(vthread_t thr, vvp_code_t cp)
|
|||
return true;
|
||||
}
|
||||
|
||||
bool of_TEST_NUL_A(vthread_t thr, vvp_code_t cp)
|
||||
{
|
||||
unsigned idx = cp->bit_idx[0];
|
||||
unsigned adr = thr->words[idx].w_int;
|
||||
vvp_object_t word;
|
||||
|
||||
/* If the address is undefined, return true. */
|
||||
if (thr_get_bit(thr, 4) == BIT4_1) {
|
||||
thr_put_bit(thr, 4, BIT4_1);
|
||||
return true;
|
||||
}
|
||||
|
||||
array_get_word_obj(cp->array, adr, word);
|
||||
if (word.test_nil())
|
||||
thr_put_bit(thr, 4, BIT4_1);
|
||||
else
|
||||
thr_put_bit(thr, 4, BIT4_0);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool of_TEST_NUL_OBJ(vthread_t thr, vvp_code_t)
|
||||
{
|
||||
if (thr->peek_object().test_nil())
|
||||
thr_put_bit(thr, 4, BIT4_1);
|
||||
else
|
||||
thr_put_bit(thr, 4, BIT4_0);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool of_VPI_CALL(vthread_t thr, vvp_code_t cp)
|
||||
{
|
||||
vpip_execute_vpi_call(thr, cp->handle);
|
||||
|
|
|
|||
|
|
@ -43,6 +43,11 @@ void vvp_darray::set_word(unsigned, const string&)
|
|||
cerr << "XXXX set_word(string) not implemented for " << typeid(*this).name() << endl;
|
||||
}
|
||||
|
||||
void vvp_darray::set_word(unsigned, const vvp_object_t&)
|
||||
{
|
||||
cerr << "XXXX set_word(vvp_object_t) not implemented for " << typeid(*this).name() << endl;
|
||||
}
|
||||
|
||||
void vvp_darray::get_word(unsigned, vvp_vector4_t&)
|
||||
{
|
||||
cerr << "XXXX get_word(vvp_vector4_t) not implemented for " << typeid(*this).name() << endl;
|
||||
|
|
@ -58,6 +63,11 @@ void vvp_darray::get_word(unsigned, string&)
|
|||
cerr << "XXXX get_word(string) not implemented for " << typeid(*this).name() << endl;
|
||||
}
|
||||
|
||||
void vvp_darray::get_word(unsigned, vvp_object_t&)
|
||||
{
|
||||
cerr << "XXXX get_word(vvp_object_t) not implemented for " << typeid(*this).name() << endl;
|
||||
}
|
||||
|
||||
template <class TYPE> vvp_darray_atom<TYPE>::~vvp_darray_atom()
|
||||
{
|
||||
}
|
||||
|
|
@ -101,6 +111,32 @@ template class vvp_darray_atom<int16_t>;
|
|||
template class vvp_darray_atom<int32_t>;
|
||||
template class vvp_darray_atom<int64_t>;
|
||||
|
||||
vvp_darray_object::~vvp_darray_object()
|
||||
{
|
||||
}
|
||||
|
||||
size_t vvp_darray_object::get_size() const
|
||||
{
|
||||
return array_.size();
|
||||
}
|
||||
|
||||
void vvp_darray_object::set_word(unsigned adr, const vvp_object_t&value)
|
||||
{
|
||||
if (adr >= array_.size())
|
||||
return;
|
||||
array_[adr] = value;
|
||||
}
|
||||
|
||||
void vvp_darray_object::get_word(unsigned adr, vvp_object_t&value)
|
||||
{
|
||||
if (adr >= array_.size()) {
|
||||
value = vvp_object_t();
|
||||
return;
|
||||
}
|
||||
|
||||
value = array_[adr];
|
||||
}
|
||||
|
||||
vvp_darray_real::~vvp_darray_real()
|
||||
{
|
||||
}
|
||||
|
|
|
|||
|
|
@ -42,6 +42,9 @@ class vvp_darray : public vvp_object {
|
|||
|
||||
virtual void set_word(unsigned adr, const std::string&value);
|
||||
virtual void get_word(unsigned adr, std::string&value);
|
||||
|
||||
virtual void set_word(unsigned adr, const vvp_object_t&value);
|
||||
virtual void get_word(unsigned adr, vvp_object_t&value);
|
||||
};
|
||||
|
||||
template <class TYPE> class vvp_darray_atom : public vvp_darray {
|
||||
|
|
@ -86,6 +89,19 @@ class vvp_darray_string : public vvp_darray {
|
|||
std::vector<std::string> array_;
|
||||
};
|
||||
|
||||
class vvp_darray_object : public vvp_darray {
|
||||
|
||||
public:
|
||||
inline vvp_darray_object(size_t siz) : array_(siz) { }
|
||||
~vvp_darray_object();
|
||||
|
||||
size_t get_size(void) const;
|
||||
void set_word(unsigned adr, const vvp_object_t&value);
|
||||
void get_word(unsigned adr, vvp_object_t&value);
|
||||
|
||||
private:
|
||||
std::vector<vvp_object_t> array_;
|
||||
};
|
||||
|
||||
class vvp_queue : public vvp_darray {
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue