Some support for unpacked arrays in class properties.

This commit is contained in:
Stephen Williams 2014-09-02 09:23:54 -07:00
parent 1465fd1570
commit 3b0dfaadba
9 changed files with 245 additions and 69 deletions

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,
@ -389,7 +396,9 @@ NetAssign_* PEIdent::elaborate_lval_method_class_member_(Design*des,
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;
@ -402,6 +411,46 @@ NetAssign_* PEIdent::elaborate_lval_method_class_member_(Design*des,
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.
@ -438,6 +487,7 @@ NetAssign_* PEIdent::elaborate_lval_method_class_member_(Design*des,
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

@ -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)
{
@ -1288,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));
@ -4595,6 +4620,16 @@ NetProc* PForeach::elaborate(Design*des, NetScope*scope) const
pform_name_t array_name;
array_name.push_back(name_component_t(array_var_));
NetNet*array_sig = des->find_signal(scope, array_name);
if (array_sig == 0) {
cerr << get_fileline() << ": error:"
<< " Unable to find " << array_name
<< " in scope " << scope_path(scope)
<< "." << endl;
des->errors += 1;
return 0;
}
ivl_assert(*this, array_sig);
if (debug_elaborate) {

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

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

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

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