The NetNet class carries multiple packed dimensions.

This commit is contained in:
Stephen Williams 2012-02-06 17:47:53 -08:00
parent ae11010707
commit e5c49022b4
9 changed files with 143 additions and 143 deletions

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 1998-2011 Stephen Williams (steve@icarus.com)
* Copyright (c) 1998-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
@ -187,6 +187,15 @@ void NetDelaySrc::dump(ostream&o, unsigned ind) const
dump_node_pins(o, ind+4);
}
ostream&operator<<(ostream&out, const list<NetNet::range_t>&rlist)
{
for (list<NetNet::range_t>::const_iterator cur = rlist.begin()
; cur != rlist.end() ; ++cur) {
out << "[" << cur->msb << ":" << cur->lsb << "]";
}
return out;
}
/* Dump a net. This can be a wire or register. */
void NetNet::dump_net(ostream&o, unsigned ind) const
{
@ -217,6 +226,8 @@ void NetNet::dump_net(ostream&o, unsigned ind) const
if (ivl_discipline_t dis = get_discipline())
o << " discipline=" << dis->name();
o << " packed dims: " << packed_dims_;
o << " (eref=" << peek_eref() << ", lref=" << peek_lref() << ")";
if (scope())
o << " scope=" << scope_path(scope());
@ -1045,8 +1056,7 @@ void NetFuncDef::dump(ostream&o, unsigned ind) const
if (result_sig_) {
o << setw(ind+2) << "" << "Return signal: ";
if (result_sig_->get_signed()) o << "+";
o << result_sig_->name() << "[" << result_sig_->msb() << ":"
<< result_sig_->lsb() << "]" << endl;
o << result_sig_->name() << result_sig_->packed_dims() << endl;
}
o << setw(ind+2) << "" << "Arguments: ";
if (port_count() == 0) o << "<none>";
@ -1068,8 +1078,7 @@ void NetFuncDef::dump(ostream&o, unsigned ind) const
break;
}
if (port(idx)->get_signed()) o << "+";
o << port(idx)->name() << "[" << port(idx)->msb() << ":"
<< port(idx)->lsb() << "]" << endl;
o << port(idx)->name() << port(idx)->packed_dims() << endl;
}
if (statement_)
statement_->dump(o, ind+2);

View File

@ -3435,8 +3435,7 @@ NetExpr* PEIdent::elaborate_expr_net_bit_(Design*des, NetScope*scope,
else cerr << "vector ";
cerr << net->name();
if (net->word_index()) cerr << "[]";
cerr << "[" << net->sig()->msb() << ":"
<< net->sig()->lsb() << "]." << endl;
cerr << net->sig()->packed_dims() << "." << endl;
cerr << get_fileline() << ": : "
<< "Replacing select with a constant 1'bx."
<< endl;
@ -3470,8 +3469,9 @@ NetExpr* PEIdent::elaborate_expr_net_bit_(Design*des, NetScope*scope,
// complicated task because we need to generate
// expressions to convert calculated bit select
// values to canonical values that are used internally.
ex = normalize_variable_base(ex, net->sig()->msb(), net->sig()->lsb(),
1, true);
const list<NetNet::range_t>& sig_packed = net->sig()->packed_dims();
assert(sig_packed.size() == 1);
ex = normalize_variable_base(ex, sig_packed, 1, true);
NetESelect*ss = new NetESelect(net, ex, 1);
ss->set_line(*this);

View File

@ -365,14 +365,20 @@ bool PEIdent::elaborate_lval_net_bit_(Design*des,
mux = 0;
}
// For now, we only understand 1-dim packed arrays.
const list<NetNet::range_t>&packed = reg->packed_dims();
ivl_assert(*this, packed.size() == 1);
const NetNet::range_t rng = packed.back();
if (mux) {
// Non-constant bit mux. Correct the mux for the range
// of the vector, then set the l-value part select expression.
mux = normalize_variable_base(mux, reg->msb(), reg->lsb(), 1, true);
// of the vector, then set the l-value part select
// expression.
mux = normalize_variable_base(mux, reg->packed_dims(), 1, true);
lv->set_part(mux, 1);
} else if (lsb == reg->msb() && lsb == reg->lsb()) {
} else if (lsb == rng.msb && lsb == rng.lsb) {
// Constant bit mux that happens to select the only bit
// of the l-value. Don't bother with any select at all.
@ -410,9 +416,13 @@ bool PEIdent::elaborate_lval_net_part_(Design*des,
ivl_assert(*this, parts_defined_flag);
NetNet*reg = lv->sig();
assert(reg);
ivl_assert(*this, reg);
if (msb == reg->msb() && lsb == reg->lsb()) {
const list<NetNet::range_t>&packed = reg->packed_dims();
ivl_assert(*this, packed.size() == 1);
const NetNet::range_t&rng = packed.back();
if (msb == rng.msb && lsb == rng.lsb) {
/* Part select covers the entire vector. Simplest case. */
@ -487,9 +497,14 @@ bool PEIdent::elaborate_lval_net_idx_(Design*des,
if (base_c->value().is_defined()) {
long lsv = base_c->value().as_long();
long offset = 0;
if (((reg->msb() < reg->lsb()) &&
// This is a work-around for limited dimenions support.
const list<NetNet::range_t>&packed = reg->packed_dims();
ivl_assert(*this, packed.size() == 1);
const NetNet::range_t&rng = packed.back();
if (((rng.msb < rng.lsb) &&
use_sel == index_component_t::SEL_IDX_UP) ||
((reg->msb() > reg->lsb()) &&
((rng.msb > rng.lsb) &&
use_sel == index_component_t::SEL_IDX_DO)) {
offset = -wid + 1;
}
@ -538,12 +553,12 @@ bool PEIdent::elaborate_lval_net_idx_(Design*des,
} else {
/* Correct the mux for the range of the vector. */
if (use_sel == index_component_t::SEL_IDX_UP) {
base = normalize_variable_base(base, reg->msb(), reg->lsb(),
base = normalize_variable_base(base, reg->packed_dims(),
wid, true);
sel_type = IVL_SEL_IDX_UP;
} else {
// This is assumed to be a SEL_IDX_DO.
base = normalize_variable_base(base, reg->msb(), reg->lsb(),
base = normalize_variable_base(base, reg->packed_dims(),
wid, false);
sel_type = IVL_SEL_IDX_DOWN;
}

View File

@ -494,7 +494,9 @@ void PFunction::elaborate_sig(Design*des, NetScope*scope) const
des->errors += 1;
}
ret_sig = new NetNet(scope, fname, NetNet::REG, mnum, lnum);
list<NetNet::range_t> packed;
packed.push_back(NetNet::range_t(mnum, lnum));
ret_sig = new NetNet(scope, fname, NetNet::REG, packed);
ret_sig->set_scalar(false);
} else {
@ -888,31 +890,6 @@ bool test_ranges_eeq(const list<NetNet::range_t>&lef, const list<NetNet::range_t
return true;
}
static unsigned packed_ranges_to_wid(const list<NetNet::range_t>&packed)
{
unsigned wid = 1;
for (list<NetNet::range_t>::const_iterator cur = packed.begin()
; cur != packed.begin() ; ++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;
}
static ostream&operator<<(ostream&out, const list<NetNet::range_t>&rlist)
{
for (list<NetNet::range_t>::const_iterator cur = rlist.begin()
; cur != rlist.end() ; ++cur) {
out << "[" << cur->msb << ":" << cur->lsb << "]";
}
return out;
}
/*
* Elaborate a source wire. The "wire" is the declaration of wires,
* registers, ports and memories. The parser has already merged the
@ -1041,7 +1018,7 @@ NetNet* PWire::elaborate_sig(Design*des, NetScope*scope) const
}
packed_dimensions = nlist;
wid = packed_ranges_to_wid(packed_dimensions);
wid = NetNet::vector_width(packed_dimensions);
}
@ -1177,14 +1154,10 @@ NetNet* PWire::elaborate_sig(Design*des, NetScope*scope) const
<< "packed arrays not supported." << endl;
des->errors += 1;
}
long msb = 0, lsb = 0;
if (packed_dimensions.size() >= 1) {
msb = packed_dimensions.front().msb;
lsb = packed_dimensions.front().lsb;
}
sig = array_dimensions > 0
? new NetNet(scope, name_, wtype, msb, lsb, array_s0, array_e0)
: new NetNet(scope, name_, wtype, msb, lsb);
? new NetNet(scope, name_, wtype, packed_dimensions, array_s0, array_e0)
: new NetNet(scope, name_, wtype, packed_dimensions);
}
// If this is an enumeration, then set the enumeration set for

View File

@ -452,12 +452,14 @@ NetNet::NetNet(NetScope*s, perm_string n, Type t, unsigned npins)
type_(t), port_type_(NOT_A_PORT), data_type_(IVL_VT_NO_TYPE),
signed_(false), isint_(false), is_scalar_(false), local_flag_(false),
enumeration_(0), struct_type_(0), discipline_(0),
msb_(npins-1), lsb_(0), dimensions_(0),
s0_(0), e0_(0), eref_count_(0), lref_count_(0)
dimensions_(0), s0_(0), e0_(0), eref_count_(0), lref_count_(0)
{
assert(s);
assert(npins>0);
// Synthesize a single range to describe this canonical vector.
packed_dims_.push_back(NetNet::range_t(npins-1, 0));
Link::DIR dir = Link::PASSIVE;
switch (t) {
@ -494,15 +496,15 @@ void NetNet::initialize_dir_(Link::DIR dir)
}
NetNet::NetNet(NetScope*s, perm_string n, Type t,
long ms, long ls)
const list<NetNet::range_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),
enumeration_(0), struct_type_(0), discipline_(0),
msb_(ms), lsb_(ls),
dimensions_(0), s0_(0), e0_(0),
eref_count_(0), lref_count_(0)
{
packed_dims_ = packed;
assert(s);
Link::DIR dir = Link::PASSIVE;
@ -542,16 +544,16 @@ static unsigned calculate_count(long s, long e)
}
NetNet::NetNet(NetScope*s, perm_string n, Type t,
long ms, long ls, long array_s, long array_e)
const list<NetNet::range_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),
is_scalar_(false), local_flag_(false), enumeration_(0), struct_type_(0),
discipline_(0),
msb_(ms), lsb_(ls),
dimensions_(1), s0_(array_s), e0_(array_e),
eref_count_(0), lref_count_(0)
{
packed_dims_ = packed;
ivl_assert(*this, s);
if (pin_count() == 0) {
cerr << "Array too big [" << array_s << ":" << array_e << "]" << endl;
@ -599,10 +601,11 @@ NetNet::NetNet(NetScope*s, perm_string n, Type t, netstruct_t*ty)
type_(t), port_type_(NOT_A_PORT),
data_type_(IVL_VT_NO_TYPE), signed_(false), isint_(false),
is_scalar_(false), local_flag_(false), enumeration_(0), struct_type_(ty),
discipline_(0), msb_(calculate_count(ty)-1), lsb_(0),
discipline_(0),
dimensions_(0), s0_(0), e0_(0),
eref_count_(0), lref_count_(0)
{
packed_dims_.push_back(range_t(calculate_count(ty)-1, 0));
Link::DIR dir = Link::PASSIVE;
switch (t) {
@ -761,38 +764,40 @@ void NetNet::set_discipline(ivl_discipline_t dis)
discipline_ = dis;
}
long NetNet::lsb() const
unsigned long NetNet::vector_width(const list<NetNet::range_t>&packed)
{
return lsb_;
}
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;
}
long NetNet::msb() const
{
return msb_;
}
unsigned long NetNet::vector_width() const
{
if (msb_ > lsb_)
return msb_ - lsb_ + 1;
else
return lsb_ - msb_ + 1;
return wid;
}
bool NetNet::sb_is_valid(long sb) const
{
if (msb_ >= lsb_)
return (sb <= msb_) && (sb >= lsb_);
assert(packed_dims_.size() == 1);
const range_t&rng = packed_dims_.back();
if (rng.msb >= rng.lsb)
return (sb <= rng.msb) && (sb >= rng.lsb);
else
return (sb <= lsb_) && (sb >= msb_);
return (sb <= rng.lsb) && (sb >= rng.msb);
}
long NetNet::sb_to_idx(long sb) const
{
if (msb_ >= lsb_)
return sb - lsb_;
assert(packed_dims_.size() == 1);
const range_t&rng = packed_dims_.back();
if (rng.msb >= rng.lsb)
return sb - rng.lsb;
else
return lsb_ - sb;
return rng.lsb - sb;
}
unsigned NetNet::array_dimensions() const
@ -2370,14 +2375,23 @@ NetNet* NetESignal::sig()
return net_;
}
/*
* The lsi() and msi() methods should be removed from the NetESignal
* class, to be replaced with packed dimensions aware methods of
* getting at dimensions.
*/
long NetESignal::lsi() const
{
return net_->lsb();
const list<NetNet::range_t>&packed = net_->packed_dims();
ivl_assert(*this, packed.size() == 1);
return packed.back().lsb;
}
long NetESignal::msi() const
{
return net_->msb();
const list<NetNet::range_t>&packed = net_->packed_dims();
ivl_assert(*this, packed.size() == 1);
return packed.back().msb;
}
ivl_variable_type_t NetESignal::expr_type() const

View File

@ -564,6 +564,13 @@ class NetNet : public NetObj {
enum PortType { NOT_A_PORT, PIMPLICIT, PINPUT, POUTPUT, PINOUT };
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;
};
@ -579,9 +586,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,
long ms, long ls);
const std::list<range_t>&packed);
explicit NetNet(NetScope*s, perm_string n, Type t,
long ms, long ls, long s0, long e0);
const std::list<range_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);
@ -619,13 +626,18 @@ class NetNet : public NetObj {
ivl_discipline_t get_discipline() const;
void set_discipline(ivl_discipline_t dis);
/* These methods return the msb and lsb indices for the most
significant and least significant bits. These are signed
longs, and may be different from pin numbers. For example,
reg [1:8] has 8 bits, msb==1 and lsb==8. */
long msb() const;
long lsb() const;
unsigned long vector_width() const;
/* This method returns a reference to the packed dimensions
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_; }
/* 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_); }
/* This method converts a signed index (the type that might be
found in the Verilog source) to a pin number. It accounts
@ -692,7 +704,7 @@ class NetNet : public NetObj {
netstruct_t*struct_type_;
ivl_discipline_t discipline_;
long msb_, lsb_;
std::list<range_t> packed_dims_;
const unsigned dimensions_;
long s0_, e0_;
@ -706,6 +718,8 @@ class NetNet : public NetObj {
vector<class NetDelaySrc*> delay_paths_;
};
extern std::ostream&operator << (std::ostream&out, const std::list<NetNet::range_t>&rlist);
/*
* This object type is used to contain a logical scope within a
* design. The scope doesn't represent any executable hardware, but is

View File

@ -27,55 +27,6 @@
# include "compiler.h"
# include "ivl_assert.h"
// This routines is not currently used!
#if 0
NetNet* add_to_net(Design*des, NetNet*sig, long val)
{
if (val == 0)
return sig;
cerr << sig->get_fileline() << ": XXXX: Forgot how to implement add_to_net" << endl;
return 0;
NetScope*scope = sig->scope();
unsigned long abs_val = (val >= 0)? val : (-val);
unsigned width = sig->pin_count();
verinum val_v (abs_val, width);
NetConst*val_c = new NetConst(scope, scope->local_symbol(), val_v);
NetNet*val_s = new NetNet(scope, scope->local_symbol(),
NetNet::IMPLICIT, width);
val_s->local_flag(true);
NetNet*res = new NetNet(scope, scope->local_symbol(),
NetNet::IMPLICIT, width);
res->local_flag(true);
NetAddSub*add = new NetAddSub(scope, scope->local_symbol(), width);
for (unsigned idx = 0 ; idx < width ; idx += 1)
connect(sig->pin(idx), add->pin_DataA(idx));
for (unsigned idx = 0 ; idx < width ; idx += 1)
connect(val_c->pin(idx), add->pin_DataB(idx));
for (unsigned idx = 0 ; idx < width ; idx += 1)
connect(val_s->pin(idx), add->pin_DataB(idx));
for (unsigned idx = 0 ; idx < width ; idx += 1)
connect(res->pin(idx), add->pin_Result(idx));
if (val < 0)
add->attribute(perm_string::literal("LPM_Direction"), verinum("SUB"));
else
add->attribute(perm_string::literal("LPM_Direction"), verinum("ADD"));
des->add_node(add);
des->add_node(val_c);
return res;
}
#endif
NetNet* sub_net_from(Design*des, NetScope*scope, long val, NetNet*sig)
{
@ -344,6 +295,21 @@ NetExpr *normalize_variable_base(NetExpr *base, long msb, long lsb,
return base;
}
/*
* This method is how indices should work except that the base should
* be a vector of expressions that matches the size of the dims list,
* so that we can generate an expression based on the entire packed
* 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,
unsigned long wid, bool is_up)
{
ivl_assert(*base, dims.size() == 1);
const NetNet::range_t&rng = dims.back();
return normalize_variable_base(base, rng.msb, rng.lsb, wid, is_up);
}
/*
* This routine generates the normalization expression needed for a variable
* array word select.

View File

@ -100,6 +100,9 @@ extern NetNet*crop_to_width(Design*des, NetNet*n, unsigned w);
*/
extern NetExpr*normalize_variable_base(NetExpr *base, long msb, long lsb,
unsigned long wid, bool is_up);
extern NetExpr*normalize_variable_base(NetExpr *base,
const list<NetNet::range_t>&dims,
unsigned long wid, bool is_up);
extern NetExpr*normalize_variable_array_base(NetExpr *base, long offset,
unsigned count);

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2000-2011 Stephen Williams (steve@icarus.com)
* Copyright (c) 2000-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
@ -2399,10 +2399,16 @@ void dll_target::signal(const NetNet*net)
/* Save the primitive properties of the signal in the
ivl_signal_t object. */
// FIX ME: This is a temporary workaround until the ivl_target
// API gets a way to represent multiple packed dimensions.
const list<NetNet::range_t>&packed = net->packed_dims();
ivl_assert(*net, packed.size() <= 1);
const NetNet::range_t rng = packed.empty()? NetNet::range_t(0,0) : packed.back();
obj->width_ = net->vector_width();
obj->signed_= net->get_signed()? 1 : 0;
obj->lsb_index = net->lsb();
obj->lsb_dist = net->msb() >= net->lsb() ? 1 : -1;
obj->lsb_index = rng.lsb;
obj->lsb_dist = rng.msb >= rng.lsb ? 1 : -1;
obj->isint_ = false;
obj->local_ = net->local_flag()? 1 : 0;
obj->forced_net_ = (net->type() != NetNet::REG) &&