Support struct members that are packed arrays.

This commit is contained in:
Stephen Williams 2012-03-25 17:59:05 -07:00
parent 9b816f6478
commit 78b0b49a4e
14 changed files with 335 additions and 190 deletions

View File

@ -106,7 +106,8 @@ O = main.o async.o design_dump.o discipline.o dup_expr.o elaborate.o \
elab_expr.o elaborate_analog.o elab_lval.o elab_net.o \
elab_scope.o elab_sig.o elab_sig_analog.o emit.o eval.o eval_attrib.o \
eval_tree.o expr_synth.o functor.o lexor.o lexor_keyword.o link_const.o \
load_module.o netlist.o netmisc.o net_analog.o net_assign.o net_design.o \
load_module.o netlist.o netmisc.o nettypes.o net_analog.o net_assign.o \
net_design.o \
netenum.o netstruct.o net_event.o net_expr.o net_func.o net_link.o net_modulo.o \
net_nex_input.o net_nex_output.o net_proc.o net_scope.o net_tran.o \
net_udp.o pad_to_width.o parse.o parse_misc.o pform.o pform_analog.o \

View File

@ -187,9 +187,9 @@ void NetDelaySrc::dump(ostream&o, unsigned ind) const
dump_node_pins(o, ind+4);
}
ostream&operator<<(ostream&out, const list<NetNet::range_t>&rlist)
ostream&operator<<(ostream&out, const list<netrange_t>&rlist)
{
for (list<NetNet::range_t>::const_iterator cur = rlist.begin()
for (list<netrange_t>::const_iterator cur = rlist.begin()
; cur != rlist.end() ; ++cur) {
out << "[" << cur->msb << ":" << cur->lsb << "]";
}

View File

@ -1442,24 +1442,59 @@ static const netstruct_t::member_t*get_struct_member(const LineInfo*li,
return type->packed_member(method_name, off);
}
/*
* Test if the tail name (method_name argument) is a member name and
* the net is a struct. If that turns out to be the case, and the
* struct is packed, then return a NetExpr that selects the member out
* of the variable.
*/
static NetExpr* check_for_struct_members(const LineInfo*li,
Design*des, NetScope*,
NetNet*net, perm_string method_name)
Design*des, NetScope*scope,
NetNet*net, const name_component_t&comp)
{
unsigned long off;
const netstruct_t::member_t*mem = get_struct_member(li, des, 0, net,
method_name, off);
comp.name, off);
if (mem == 0) return 0;
if (debug_elaborate) {
cerr << li->get_fileline() << ": debug: Found struct member " <<mem->name
cerr << li->get_fileline() << ": debug: Found struct member " << mem->name
<< " At offset " << off << endl;
}
unsigned use_width = mem->width();
if ( ! comp.index.empty() ) {
// Evaluate all but the last index expression, into prefix_indices.
list<long>prefix_indices;
bool rc = evaluate_index_prefix(des, scope, prefix_indices, comp.index);
ivl_assert(*li, rc);
// Evaluate the last index expression into a constant long.
NetExpr*texpr = elab_and_eval(des, scope, comp.index.back().msb, -1, true);
long tmp;
if (texpr == 0 || !eval_as_long(tmp, texpr)) {
cerr << li->get_fileline() << ": error: "
"Array index expressions must be constant here." << endl;
des->errors += 1;
return false;
}
delete texpr;
// Now use the prefix_to_slice function to calculate the
// offset and width of the addressed slice of the member.
long loff;
unsigned long lwid;
prefix_to_slice(mem->packed_dims, prefix_indices, tmp, loff, lwid);
off += loff;
use_width = lwid;
}
NetESignal*sig = new NetESignal(net);
NetEConst*base = make_const_val(off);
NetESelect*sel = new NetESelect(sig, base, mem->width());
NetESelect*sel = new NetESelect(sig, base, use_width);
return sel;
}
@ -2350,7 +2385,7 @@ NetExpr* PEIdent::elaborate_expr(Design*des, NetScope*scope,
// really a method attached to an object.
if (gn_system_verilog() && found_in==0 && path_.size() >= 2) {
pform_name_t use_path = path_;
perm_string method_name = peek_tail_name(use_path);
name_component_t member_comp = use_path.back();
use_path.pop_back();
found_in = symbol_search(this, des, scope, use_path,
@ -2372,7 +2407,7 @@ NetExpr* PEIdent::elaborate_expr(Design*des, NetScope*scope,
return check_for_enum_methods(this, des, scope,
netenum,
use_path, method_name,
use_path, member_comp.name,
expr, expr_wid, NULL, 0);
}
@ -2382,7 +2417,7 @@ NetExpr* PEIdent::elaborate_expr(Design*des, NetScope*scope,
ivl_assert(*this, use_path.back().index.empty());
return check_for_struct_members(this, des, scope,
net, method_name);
net, member_comp);
}
}
@ -3279,11 +3314,11 @@ NetExpr* PEIdent::elaborate_expr_net_idx_up_(Design*des, NetScope*scope,
long lsv = base_c->value().as_long();
long offset = 0;
// Get the signal range.
const list<NetNet::range_t>&packed = net->sig()->packed_dims();
const list<netrange_t>&packed = net->sig()->packed_dims();
ivl_assert(*this, packed.size() == prefix_indices.size()+1);
// We want the last range, which is where we work.
const NetNet::range_t&rng = packed.back();
const netrange_t&rng = packed.back();
if (rng.msb < rng.lsb) {
offset = -wid + 1;
}
@ -3494,7 +3529,7 @@ NetExpr* PEIdent::elaborate_expr_net_bit_(Design*des, NetScope*scope,
long msv = msc->value().as_long();
const list<NetNet::range_t>& sig_packed = net->sig()->packed_dims();
const list<netrange_t>& sig_packed = net->sig()->packed_dims();
if (prefix_indices.size()+2 <= sig_packed.size()) {
// Special case: this is a slice of a multi-dimensional
// packed array. For example:
@ -3561,7 +3596,7 @@ NetExpr* PEIdent::elaborate_expr_net_bit_(Design*des, NetScope*scope,
return res;
}
const list<NetNet::range_t>& sig_packed = net->sig()->packed_dims();
const list<netrange_t>& sig_packed = net->sig()->packed_dims();
if (prefix_indices.size()+2 <= sig_packed.size()) {
// Special case: this is a slice of a multi-dimensional
// packed array. For example:

View File

@ -455,7 +455,7 @@ bool PEIdent::elaborate_lval_net_part_(Design*des,
NetNet*reg = lv->sig();
ivl_assert(*this, reg);
const list<NetNet::range_t>&packed = reg->packed_dims();
const list<netrange_t>&packed = reg->packed_dims();
// Part selects cannot select slices. So there must be enough
// prefix_indices to get all the way to the final dimension.
@ -544,11 +544,11 @@ bool PEIdent::elaborate_lval_net_idx_(Design*des,
long lsv = base_c->value().as_long();
long offset = 0;
// Get the signal range.
const list<NetNet::range_t>&packed = reg->packed_dims();
const list<netrange_t>&packed = reg->packed_dims();
ivl_assert(*this, packed.size() == prefix_indices.size()+1);
// We want the last range, which is where we work.
const NetNet::range_t&rng = packed.back();
const netrange_t&rng = packed.back();
if (((rng.msb < rng.lsb) &&
use_sel == index_component_t::SEL_IDX_UP) ||
((rng.msb > rng.lsb) &&
@ -621,8 +621,7 @@ bool PEIdent::elaborate_lval_net_idx_(Design*des,
return true;
}
bool PEIdent::elaborate_lval_net_packed_member_(Design*des,
NetScope*,
bool PEIdent::elaborate_lval_net_packed_member_(Design*des, NetScope*scope,
NetAssign_*lv,
const perm_string&member_name) const
{
@ -649,7 +648,57 @@ bool PEIdent::elaborate_lval_net_packed_member_(Design*des,
return false;
}
lv->set_part(new NetEConst(verinum(off)), member->width());
unsigned long use_width = member->width();
// 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. Of course, "c" is the name of the member
// we are working on and "a.b" is the name of reg.
const name_component_t&name_tail = path_.back();
if (name_tail.index.size() > member->packed_dims.size()) {
cerr << get_fileline() << ": error: Too make index expressions for member." << endl;
des->errors += 1;
return false;
}
// Get the index component type. At this point, we only
// support bit select or none.
index_component_t::ctype_t use_sel = index_component_t::SEL_NONE;
if (!name_tail.index.empty())
use_sel = name_tail.index.back().sel;
ivl_assert(*this, use_sel == index_component_t::SEL_NONE || use_sel == index_component_t::SEL_BIT);
if (name_tail.index.size() > 0) {
// Evaluate all but the last index expression, into prefix_indices.
list<long>prefix_indices;
bool rc = evaluate_index_prefix(des, scope, prefix_indices, name_tail.index);
ivl_assert(*this, rc);
// Evaluate the last index expression into a constant long.
NetExpr*texpr = elab_and_eval(des, scope, name_tail.index.back().msb, -1, true);
long tmp;
if (texpr == 0 || !eval_as_long(tmp, texpr)) {
cerr << get_fileline() << ": error: "
"Array index expressions must be constant here." << endl;
des->errors += 1;
return false;
}
delete texpr;
// Now use the prefix_to_slice function to calculate the
// offset and width of the addressed slice of the member.
long loff;
unsigned long lwid;
prefix_to_slice(member->packed_dims, prefix_indices, tmp, loff, lwid);
off += loff;
use_width = lwid;
}
lv->set_part(new NetEConst(verinum(off)), use_width);
return true;
}

View File

@ -514,8 +514,8 @@ void PFunction::elaborate_sig(Design*des, NetScope*scope) const
des->errors += 1;
}
list<NetNet::range_t> packed;
packed.push_back(NetNet::range_t(mnum, lnum));
list<netrange_t> packed;
packed.push_back(netrange_t(mnum, lnum));
ret_sig = new NetNet(scope, fname, NetNet::REG, packed);
ret_sig->set_scalar(false);
@ -813,61 +813,15 @@ void PWhile::elaborate_sig(Design*des, NetScope*scope) const
statement_->elaborate_sig(des, scope);
}
static netstruct_t* elaborate_struct_type(Design*des, NetScope*scope,
struct_type_t*struct_type)
{
netstruct_t*res = new netstruct_t;
res->packed(struct_type->packed_flag);
for (list<struct_member_t*>::iterator cur = struct_type->members->begin()
; cur != struct_type->members->end() ; ++ cur) {
struct_member_t*curp = *cur;
long use_msb = 0;
long use_lsb = 0;
if (curp->range.get() && ! curp->range->empty()) {
ivl_assert(*curp, curp->range->size() == 1);
pform_range_t&rangep = curp->range->front();
PExpr*msb_pex = rangep.first;
PExpr*lsb_pex = rangep.second;
NetExpr*tmp = elab_and_eval(des, scope, msb_pex, -2, true);
ivl_assert(*curp, tmp);
bool rc = eval_as_long(use_msb, tmp);
ivl_assert(*curp, rc);
tmp = elab_and_eval(des, scope, lsb_pex, -2, true);
ivl_assert(*curp, tmp);
rc = eval_as_long(use_lsb, tmp);
ivl_assert(*curp, rc);
}
for (list<decl_assignment_t*>::iterator name = curp->names->begin()
; name != curp->names->end() ; ++ name) {
decl_assignment_t*namep = *name;
netstruct_t::member_t memb;
memb.name = namep->name;
memb.type = curp->type;
memb.msb = use_msb;
memb.lsb = use_lsb;
res->append_member(memb);
}
}
return res;
}
static bool evaluate_ranges(Design*des, NetScope*scope,
list<NetNet::range_t>&llist,
list<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) {
NetNet::range_t lrng;
netrange_t lrng;
NetExpr*texpr = elab_and_eval(des, scope, cur->first, -1, true);
if (! eval_as_long(lrng.msb, texpr)) {
@ -901,13 +855,49 @@ static bool evaluate_ranges(Design*des, NetScope*scope,
return bad_msb | bad_lsb;
}
bool test_ranges_eeq(const list<NetNet::range_t>&lef, const list<NetNet::range_t>&rig)
static netstruct_t* elaborate_struct_type(Design*des, NetScope*scope,
struct_type_t*struct_type)
{
netstruct_t*res = new netstruct_t;
res->packed(struct_type->packed_flag);
for (list<struct_member_t*>::iterator cur = struct_type->members->begin()
; cur != struct_type->members->end() ; ++ cur) {
list<netrange_t>packed_dimensions;
struct_member_t*curp = *cur;
if (curp->range.get() && ! curp->range->empty()) {
bool bad_range;
bad_range = evaluate_ranges(des, scope, packed_dimensions, *curp->range);
ivl_assert(*curp, !bad_range);
} else {
packed_dimensions.push_back(netrange_t(0,0));
}
for (list<decl_assignment_t*>::iterator name = curp->names->begin()
; name != curp->names->end() ; ++ name) {
decl_assignment_t*namep = *name;
netstruct_t::member_t memb;
memb.name = namep->name;
memb.type = curp->type;
memb.packed_dims = packed_dimensions;
res->append_member(memb);
}
}
return res;
}
bool test_ranges_eeq(const list<netrange_t>&lef, const list<netrange_t>&rig)
{
if (lef.size() != rig.size())
return false;
list<NetNet::range_t>::const_iterator lcur = lef.begin();
list<NetNet::range_t>::const_iterator rcur = rig.begin();
list<netrange_t>::const_iterator lcur = lef.begin();
list<netrange_t>::const_iterator rcur = rig.begin();
while (lcur != lef.end()) {
if (lcur->msb != rcur->msb)
return false;
@ -942,7 +932,7 @@ NetNet* PWire::elaborate_sig(Design*des, NetScope*scope) const
}
unsigned wid = 1;
list<NetNet::range_t>packed_dimensions;
list<netrange_t>packed_dimensions;
des->errors += error_cnt_;
@ -983,7 +973,7 @@ NetNet* PWire::elaborate_sig(Design*des, NetScope*scope) const
if (port_set_ || net_set_) {
bool bad_range = false;
list<NetNet::range_t> plist, nlist;
list<netrange_t> plist, nlist;
/* If they exist get the port definition MSB and LSB */
if (port_set_ && !port_.empty()) {
bad_range |= evaluate_ranges(des, scope, plist, port_);
@ -1049,7 +1039,7 @@ NetNet* PWire::elaborate_sig(Design*des, NetScope*scope) const
}
packed_dimensions = nlist;
wid = NetNet::vector_width(packed_dimensions);
wid = netrange_width(packed_dimensions);
}

View File

@ -458,7 +458,7 @@ NetNet::NetNet(NetScope*s, perm_string n, Type t, unsigned npins)
assert(npins>0);
// Synthesize a single range to describe this canonical vector.
packed_dims_.push_back(NetNet::range_t(npins-1, 0));
packed_dims_.push_back(netrange_t(npins-1, 0));
Link::DIR dir = Link::PASSIVE;
@ -496,7 +496,7 @@ void NetNet::initialize_dir_(Link::DIR dir)
}
NetNet::NetNet(NetScope*s, perm_string n, Type t,
const list<NetNet::range_t>&packed)
const list<netrange_t>&packed)
: NetObj(s, n, 1), type_(t),
port_type_(NOT_A_PORT), data_type_(IVL_VT_NO_TYPE), signed_(false),
isint_(false), is_scalar_(false), local_flag_(false),
@ -544,7 +544,7 @@ static unsigned calculate_count(long s, long e)
}
NetNet::NetNet(NetScope*s, perm_string n, Type t,
const list<NetNet::range_t>&packed, long array_s, long array_e)
const list<netrange_t>&packed, long array_s, long array_e)
: NetObj(s, n, calculate_count(array_s, array_e)),
type_(t), port_type_(NOT_A_PORT),
data_type_(IVL_VT_NO_TYPE), signed_(false), isint_(false),
@ -605,7 +605,7 @@ NetNet::NetNet(NetScope*s, perm_string n, Type t, netstruct_t*ty)
dimensions_(0), s0_(0), e0_(0),
eref_count_(0), lref_count_(0)
{
packed_dims_.push_back(range_t(calculate_count(ty)-1, 0));
packed_dims_.push_back(netrange_t(calculate_count(ty)-1, 0));
Link::DIR dir = Link::PASSIVE;
switch (t) {
@ -764,27 +764,11 @@ void NetNet::set_discipline(ivl_discipline_t dis)
discipline_ = dis;
}
unsigned long NetNet::vector_width(const list<NetNet::range_t>&packed)
{
unsigned wid = 1;
for (list<NetNet::range_t>::const_iterator cur = packed.begin()
; cur != packed.end() ; ++cur) {
unsigned use_wid;
if (cur->msb >= cur->lsb)
use_wid = cur->msb - cur->lsb + 1;
else
use_wid = cur->lsb - cur->msb + 1;
wid *= use_wid;
}
return wid;
}
bool NetNet::sb_is_valid(const list<long>&indices, long sb) const
{
ivl_assert(*this, indices.size()+1 == packed_dims_.size());
assert(packed_dims_.size() == 1);
const range_t&rng = packed_dims_.back();
const netrange_t&rng = packed_dims_.back();
if (rng.msb >= rng.lsb)
return (sb <= rng.msb) && (sb >= rng.lsb);
else
@ -795,7 +779,7 @@ long NetNet::sb_to_idx(const list<long>&indices, long sb) const
{
ivl_assert(*this, indices.size()+1 == packed_dims_.size());
list<range_t>::const_iterator pcur = packed_dims_.end();
list<netrange_t>::const_iterator pcur = packed_dims_.end();
-- pcur;
long acc_off;
@ -832,50 +816,7 @@ long NetNet::sb_to_idx(const list<long>&indices, long sb) const
bool NetNet::sb_to_slice(const list<long>&indices, long sb, long&loff, unsigned long&lwid) const
{
ivl_assert(*this, indices.size() < packed_dims_.size());
size_t acc_wid = 1;
list<range_t>::const_iterator pcur = packed_dims_.end();
for (size_t idx = indices.size()+1 ; idx < packed_dims_.size() ; idx += 1) {
-- pcur;
acc_wid *= pcur->width();
}
lwid = acc_wid;
-- pcur;
if (sb < pcur->msb && sb < pcur->lsb)
return false;
if (sb > pcur->msb && sb > pcur->lsb)
return false;
long acc_off = 0;
if (pcur->msb >= pcur->lsb)
acc_off += (sb - pcur->lsb) * acc_wid;
else
acc_off += (sb - pcur->msb) * acc_wid;
if (indices.size() == 0) {
loff = acc_off;
return true;
}
lwid *= pcur->width();
list<long>::const_iterator icur = indices.end();
do {
-- pcur;
-- icur;
acc_wid *= pcur->width();
if (pcur->msb >= pcur->lsb)
acc_off += (*icur - pcur->lsb) * acc_wid;
else
acc_off += (*icur - pcur->msb) * acc_wid;
} while (icur != indices.begin());
loff = acc_off;
return true;
return prefix_to_slice(packed_dims_, indices, sb, loff, lwid);
}
@ -2461,14 +2402,14 @@ NetNet* NetESignal::sig()
*/
long NetESignal::lsi() const
{
const list<NetNet::range_t>&packed = net_->packed_dims();
const list<netrange_t>&packed = net_->packed_dims();
ivl_assert(*this, packed.size() == 1);
return packed.back().lsb;
}
long NetESignal::msi() const
{
const list<NetNet::range_t>&packed = net_->packed_dims();
const list<netrange_t>&packed = net_->packed_dims();
ivl_assert(*this, packed.size() == 1);
return packed.back().msb;
}

View File

@ -35,6 +35,7 @@
# include "ivl_target_priv.h"
# include "pform_types.h"
# include "config.h"
# include "nettypes.h"
# include "verinum.h"
# include "verireal.h"
# include "StringHeap.h"
@ -563,21 +564,6 @@ class NetNet : public NetObj {
enum PortType { NOT_A_PORT, PIMPLICIT, PINPUT, POUTPUT, PINOUT, PREF };
struct range_t {
inline range_t() : msb(0), lsb(0) { }
inline range_t(long m, long l) : msb(m), lsb(l) { }
inline range_t(const range_t&that)
: msb(that.msb), lsb(that.lsb) { }
inline range_t& operator = (const range_t&that)
{ msb = that.msb; lsb = that.lsb; return *this; }
long msb;
long lsb;
inline unsigned long width()const
{ if (msb >= lsb) return msb-lsb+1; else return lsb-msb+1; }
};
public:
// The width in this case is a shorthand for ms=width-1 and
// ls=0. Only one pin is created, the width is of the vector
@ -589,9 +575,9 @@ class NetNet : public NetObj {
// dimensions. If s0==e0, then this is not an array after
// all.
explicit NetNet(NetScope*s, perm_string n, Type t,
const std::list<range_t>&packed);
const std::list<netrange_t>&packed);
explicit NetNet(NetScope*s, perm_string n, Type t,
const std::list<range_t>&packed, long s0, long e0);
const std::list<netrange_t>&packed, long s0, long e0);
// This form builds a NetNet from its record definition.
explicit NetNet(NetScope*s, perm_string n, Type t, netstruct_t*type);
@ -633,14 +619,11 @@ class NetNet : public NetObj {
for the vector. These are arranged as a list where the
first range in the list (front) is the left-most range in
the verilog declaration. */
const std::list<range_t>& packed_dims() const { return packed_dims_; }
const std::list<netrange_t>& packed_dims() const { return packed_dims_; }
/* The vector_width returns the bit width of the packed array,
vector or scaler that is this NetNet object. The static
method is also a convenient way to convert a range list to
a vector width. */
static unsigned long vector_width(const std::list<NetNet::range_t>&);
unsigned long vector_width() const { return vector_width(packed_dims_); }
vector or scaler that is this NetNet object. */
unsigned long vector_width() const { return netrange_width(packed_dims_); }
/* Given a prefix of indices, figure out how wide the
resulting slice would be. This is a generalization of the
@ -722,7 +705,7 @@ class NetNet : public NetObj {
netstruct_t*struct_type_;
ivl_discipline_t discipline_;
std::list<range_t> packed_dims_;
std::list<netrange_t> packed_dims_;
const unsigned dimensions_;
long s0_, e0_;
@ -736,7 +719,7 @@ class NetNet : public NetObj {
vector<class NetDelaySrc*> delay_paths_;
};
extern std::ostream&operator << (std::ostream&out, const std::list<NetNet::range_t>&rlist);
extern std::ostream&operator << (std::ostream&out, const std::list<netrange_t>&rlist);
/*
* This object type is used to contain a logical scope within a

View File

@ -320,24 +320,24 @@ NetExpr *normalize_variable_base(NetExpr *base, long msb, long lsb,
* vector. For now, we assert that there is only one set of dimensions.
*/
NetExpr *normalize_variable_base(NetExpr *base,
const list<NetNet::range_t>&dims,
const list<netrange_t>&dims,
unsigned long wid, bool is_up)
{
ivl_assert(*base, dims.size() == 1);
const NetNet::range_t&rng = dims.back();
const netrange_t&rng = dims.back();
return normalize_variable_base(base, rng.msb, rng.lsb, wid, is_up);
}
NetExpr *normalize_variable_bit_base(const list<long>&indices, NetExpr*base,
const NetNet*reg)
{
const list<NetNet::range_t>&packed_dims = reg->packed_dims();
const list<netrange_t>&packed_dims = reg->packed_dims();
ivl_assert(*base, indices.size()+1 == packed_dims.size());
// Get the canonical offset of the slice within which we are
// addressing. We need that address as a slice offset to
// calculate the proper complete address
const NetNet::range_t&rng = packed_dims.back();
const netrange_t&rng = packed_dims.back();
long slice_off = reg->sb_to_idx(indices, rng.lsb);
return normalize_variable_base(base, rng.msb, rng.lsb, 1, true, slice_off);
@ -347,13 +347,13 @@ NetExpr *normalize_variable_part_base(const list<long>&indices, NetExpr*base,
const NetNet*reg,
unsigned long wid, bool is_up)
{
const list<NetNet::range_t>&packed_dims = reg->packed_dims();
const list<netrange_t>&packed_dims = reg->packed_dims();
ivl_assert(*base, indices.size()+1 == packed_dims.size());
// Get the canonical offset of the slice within which we are
// addressing. We need that address as a slice offset to
// calculate the proper complete address
const NetNet::range_t&rng = packed_dims.back();
const netrange_t&rng = packed_dims.back();
long slice_off = reg->sb_to_idx(indices, rng.lsb);
return normalize_variable_base(base, rng.msb, rng.lsb, wid, is_up, slice_off);
@ -362,10 +362,10 @@ NetExpr *normalize_variable_part_base(const list<long>&indices, NetExpr*base,
NetExpr *normalize_variable_slice_base(const list<long>&indices, NetExpr*base,
const NetNet*reg, unsigned long&lwid)
{
const list<NetNet::range_t>&packed_dims = reg->packed_dims();
const list<netrange_t>&packed_dims = reg->packed_dims();
ivl_assert(*base, indices.size() < packed_dims.size());
list<NetNet::range_t>::const_iterator pcur = packed_dims.end();
list<netrange_t>::const_iterator pcur = packed_dims.end();
for (size_t idx = indices.size() ; idx < packed_dims.size(); idx += 1) {
-- pcur;
}

View File

@ -102,7 +102,7 @@ extern NetExpr*normalize_variable_base(NetExpr *base, long msb, long lsb,
unsigned long wid, bool is_up,
long slice_off =0);
extern NetExpr*normalize_variable_base(NetExpr *base,
const list<NetNet::range_t>&dims,
const list<netrange_t>&dims,
unsigned long wid, bool is_up);
/*

View File

@ -22,6 +22,7 @@
# include "LineInfo.h"
# include <vector>
# include "ivl_target.h"
# include "nettypes.h"
class netstruct_t : public LineInfo {
@ -29,8 +30,7 @@ class netstruct_t : public LineInfo {
struct member_t {
perm_string name;
ivl_variable_type_t type;
long msb;
long lsb;
list<netrange_t> packed_dims;
long width() const;
ivl_variable_type_t data_type() const { return type; };
// We need to keep the individual element sign information.
@ -63,11 +63,6 @@ class netstruct_t : public LineInfo {
inline bool netstruct_t::packed(void) const { return packed_; }
inline long netstruct_t::member_t::width() const
{
if (msb >= lsb)
return msb - lsb + 1;
else
return lsb - msb + 1;
}
{ return netrange_width(packed_dims); }
#endif

96
nettypes.cc Normal file
View File

@ -0,0 +1,96 @@
/*
* Copyright (c) 2012 Stephen Williams (steve@icarus.com)
*
* This source code is free software; you can redistribute it
* and/or modify it in source code form under the terms of the GNU
* General Public License as published by the Free Software
* Foundation; either version 2 of the License, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
# include "nettypes.h"
# include <cassert>
using namespace std;
unsigned long netrange_width(const list<netrange_t>&packed)
{
unsigned wid = 1;
for (list<netrange_t>::const_iterator cur = packed.begin()
; cur != packed.end() ; ++cur) {
unsigned use_wid;
if (cur->msb >= cur->lsb)
use_wid = cur->msb - cur->lsb + 1;
else
use_wid = cur->lsb - cur->msb + 1;
wid *= use_wid;
}
return wid;
}
/*
* Given a netrange_t list (which represent packed dimensions) and a
* prefix of calculated index values, calculate the canonical offset
* and width of the resulting slice. In this case, the "sb" argument
* is an extra index of the prefix.
*/
bool prefix_to_slice(const std::list<netrange_t>&dims,
const std::list<long>&prefix, long sb,
long&loff, unsigned long&lwid)
{
assert(prefix.size() < dims.size());
size_t acc_wid = 1;
list<netrange_t>::const_iterator pcur = dims.end();
for (size_t idx = prefix.size()+1 ; idx < dims.size() ; idx += 1) {
-- pcur;
acc_wid *= pcur->width();
}
lwid = acc_wid;
-- pcur;
if (sb < pcur->msb && sb < pcur->lsb)
return false;
if (sb > pcur->msb && sb > pcur->lsb)
return false;
long acc_off = 0;
if (pcur->msb >= pcur->lsb)
acc_off += (sb - pcur->lsb) * acc_wid;
else
acc_off += (sb - pcur->msb) * acc_wid;
if (prefix.size() == 0) {
loff = acc_off;
return true;
}
lwid *= pcur->width();
list<long>::const_iterator icur = prefix.end();
do {
-- pcur;
-- icur;
acc_wid *= pcur->width();
if (pcur->msb >= pcur->lsb)
acc_off += (*icur - pcur->lsb) * acc_wid;
else
acc_off += (*icur - pcur->msb) * acc_wid;
} while (icur != prefix.begin());
loff = acc_off;
return true;
}

55
nettypes.h Normal file
View File

@ -0,0 +1,55 @@
#ifndef __nettypes_H
#define __nettypes_H
/*
* Copyright (c) 2012 Stephen Williams (steve@icarus.com)
*
* This source code is free software; you can redistribute it
* and/or modify it in source code form under the terms of the GNU
* General Public License as published by the Free Software
* Foundation; either version 2 of the License, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
# include <list>
class netrange_t {
public:
inline netrange_t() : msb(0), lsb(0) { }
inline netrange_t(long m, long l) : msb(m), lsb(l) { }
inline netrange_t(const netrange_t&that)
: msb(that.msb), lsb(that.lsb) { }
inline netrange_t& operator = (const netrange_t&that)
{ msb = that.msb; lsb = that.lsb; return *this; }
public:
long msb;
long lsb;
inline unsigned long width()const
{ if (msb >= lsb) return msb-lsb+1; else return lsb-msb+1; }
};
extern unsigned long netrange_width(const std::list<netrange_t>&dims);
/*
* Take as input a list of packed dimensions and a list of prefix
* indices, and calculate the offset/width of the resulting slice into
* the packed array.
*/
extern bool prefix_to_slice(const std::list<netrange_t>&dims,
const std::list<long>&prefix, long sb,
long&loff, unsigned long&lwid);
#endif

View File

@ -2387,7 +2387,7 @@ void dll_target::signal(const NetNet*net)
ivl_signal_t object. */
{ size_t idx = 0;
list<NetNet::range_t>::const_iterator cur;
list<netrange_t>::const_iterator cur;
obj->packed_dims.resize(net->packed_dims().size());
for (cur = net->packed_dims().begin(), idx = 0
; cur != net->packed_dims().end() ; ++cur, idx += 1) {

View File

@ -690,7 +690,7 @@ struct ivl_signal_s {
/* These encode the declared packed dimensions for the
signal, in case they are needed by the run-time */
std::vector<NetNet::range_t> packed_dims;
std::vector<netrange_t> packed_dims;
perm_string name_;
ivl_scope_t scope_;