Merge branch 'x-mil15'

This commit is contained in:
Stephen Williams 2014-09-08 21:10:14 -07:00
commit 853512868b
37 changed files with 949 additions and 126 deletions

View File

@ -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;

View File

@ -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()

View File

@ -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_;
};

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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);
}

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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
View File

@ -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;

View File

@ -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);

View File

@ -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;

View File

@ -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;

View File

@ -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 */

View File

@ -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;
}

View File

@ -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,

View File

@ -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()
{
}

View File

@ -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)
{
}

View File

@ -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 */

View File

@ -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;
}

View File

@ -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);
}

View File

@ -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);

View File

@ -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);

View File

@ -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;
}

View File

@ -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);
}

View File

@ -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;
}

View File

@ -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

View File

@ -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 */

View File

@ -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);

View File

@ -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} },

View File

@ -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);

View File

@ -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; }

View File

@ -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.

View File

@ -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); }

View File

@ -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);

View File

@ -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()
{
}

View File

@ -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 {