Major rework of array handling. Memories are replaced with the

more general concept of arrays. The NetMemory and NetEMemory
 classes are removed from the ivl core program, and the IVL_LPM_RAM
 lpm type is removed from the ivl_target API.
This commit is contained in:
steve 2007-01-16 05:44:14 +00:00
parent 5c3b2f4193
commit 91d84e7dc7
62 changed files with 2388 additions and 2204 deletions

51
PExpr.h
View File

@ -19,7 +19,7 @@
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#ifdef HAVE_CVS_IDENT
#ident "$Id: PExpr.h,v 1.86 2006/11/10 04:54:26 steve Exp $"
#ident "$Id: PExpr.h,v 1.87 2007/01/16 05:44:14 steve Exp $"
#endif
# include <string>
@ -294,9 +294,10 @@ class PEIdent : public PExpr {
bool calculate_up_do_width_(Design*, NetScope*, unsigned long&wid) const;
private:
NetAssign_*elaborate_lval_net_part_(Design*, NetScope*, NetNet*) const;
NetAssign_*elaborate_lval_net_idx_up_(Design*, NetScope*, NetNet*) const;
NetAssign_*elaborate_lval_net_idx_do_(Design*, NetScope*, NetNet*) const;
NetAssign_*elaborate_lval_net_word_(Design*, NetScope*, NetNet*) const;
bool elaborate_lval_net_part_(Design*, NetScope*, NetAssign_*) const;
bool elaborate_lval_net_idx_up_(Design*, NetScope*, NetAssign_*) const;
bool elaborate_lval_net_idx_do_(Design*, NetScope*, NetAssign_*) const;
private:
NetExpr*elaborate_expr_param(Design*des,
@ -306,24 +307,30 @@ class PEIdent : public PExpr {
const NetExpr*par_msb,
const NetExpr*par_lsb) const;
NetExpr*elaborate_expr_net(Design*des,
NetScope*scope,
NetNet*net,
NetScope*found) const;
NetScope*scope,
NetNet*net,
NetScope*found,
bool sys_task_arg) const;
NetExpr*elaborate_expr_net_word_(Design*des,
NetScope*scope,
NetNet*net,
NetScope*found,
bool sys_task_arg) const;
NetExpr*elaborate_expr_net_part_(Design*des,
NetScope*scope,
NetNet*net,
NetESignal*net,
NetScope*found) const;
NetExpr*elaborate_expr_net_idx_up_(Design*des,
NetScope*scope,
NetNet*net,
NetESignal*net,
NetScope*found) const;
NetExpr*elaborate_expr_net_idx_do_(Design*des,
NetScope*scope,
NetNet*net,
NetESignal*net,
NetScope*found) const;
NetExpr*elaborate_expr_net_bit_(Design*des,
NetScope*scope,
NetNet*net,
NetESignal*net,
NetScope*found) const;
hname_t path_;
@ -338,12 +345,13 @@ class PEIdent : public PExpr {
// expression. If this is a reference to a vector, this is a
// bit select.
std::vector<PExpr*> idx_;
NetNet* elaborate_net_ram_(Design*des, NetScope*scope,
NetMemory*mem, unsigned lwidth,
const NetExpr* rise,
const NetExpr* fall,
const NetExpr* decay) const;
NetNet* elaborate_net_array_(Design*des, NetScope*scope,
NetNet*sig, unsigned lwidth,
const NetExpr* rise,
const NetExpr* fall,
const NetExpr* decay,
Link::strength_t drive0,
Link::strength_t drive1) const;
NetNet* elaborate_net_bitmux_(Design*des, NetScope*scope,
NetNet*sig,
@ -354,9 +362,6 @@ class PEIdent : public PExpr {
Link::strength_t drive1) const;
private:
NetAssign_* elaborate_mem_lval_(Design*des, NetScope*scope,
NetMemory*mem) const;
NetNet* elaborate_lnet_common_(Design*des, NetScope*scope,
bool implicit_net_ok,
bool bidirectional_flag) const;
@ -650,6 +655,12 @@ class PECallFunction : public PExpr {
/*
* $Log: PExpr.h,v $
* Revision 1.87 2007/01/16 05:44:14 steve
* Major rework of array handling. Memories are replaced with the
* more general concept of arrays. The NetMemory and NetEMemory
* classes are removed from the ivl core program, and the IVL_LPM_RAM
* lpm type is removed from the ivl_target API.
*
* Revision 1.86 2006/11/10 04:54:26 steve
* Add test_width methods for PETernary and PEString.
*

View File

@ -17,7 +17,7 @@
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#ifdef HAVE_CVS_IDENT
#ident "$Id: PWire.cc,v 1.11 2005/07/07 16:22:49 steve Exp $"
#ident "$Id: PWire.cc,v 1.12 2007/01/16 05:44:14 steve Exp $"
#endif
# include "config.h"
@ -154,13 +154,18 @@ void PWire::set_memory_idx(PExpr*ldx, PExpr*rdx)
{
assert(lidx_ == 0);
assert(ridx_ == 0);
assert(type_ == NetNet::REG);
lidx_ = ldx;
ridx_ = rdx;
}
/*
* $Log: PWire.cc,v $
* Revision 1.12 2007/01/16 05:44:14 steve
* Major rework of array handling. Memories are replaced with the
* more general concept of arrays. The NetMemory and NetEMemory
* classes are removed from the ivl core program, and the IVL_LPM_RAM
* lpm type is removed from the ivl_target API.
*
* Revision 1.11 2005/07/07 16:22:49 steve
* Generalize signals to carry types.
*

View File

@ -17,7 +17,7 @@
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#ifdef HAVE_CVS_IDENT
#ident "$Id: design_dump.cc,v 1.171 2006/10/30 05:44:49 steve Exp $"
#ident "$Id: design_dump.cc,v 1.172 2007/01/16 05:44:14 steve Exp $"
#endif
# include "config.h"
@ -112,8 +112,8 @@ void NetDelaySrc::dump(ostream&o, unsigned ind) const
/* Dump a net. This can be a wire or register. */
void NetNet::dump_net(ostream&o, unsigned ind) const
{
o << setw(ind) << "" << type() << ": " << name() << "[" <<
pin_count() << "]";
o << setw(ind) << "" << type() << ": " << name()
<< "[" << s0_ << ":" << e0_ << " count=" << pin_count() << "]";
if (local_flag_)
o << " (local)";
o << " " << data_type_;
@ -167,13 +167,6 @@ void NetNet::dump_net(ostream&o, unsigned ind) const
dump_obj_attr(o, ind+4);
}
void NetMemory::dump(ostream&o, unsigned ind) const
{
o << setw(ind) << "" << name_ << "[" << width_ << "] " <<
"[" << idxh_ << ":" << idxl_ << "]" << endl;
}
/* Dump a NetNode and its pins. Dump what I know about the netnode on
the first line, then list all the pins, with the name of the
connected signal. */
@ -239,6 +232,15 @@ void NetAddSub::dump_node(ostream&o, unsigned ind) const
dump_obj_attr(o, ind+4);
}
void NetArrayDq::dump_node(ostream&o, unsigned ind) const
{
o << setw(ind) << "" << "NetArrayDq: " << name()
<< " array=" << mem_->name()
<< endl;
dump_node_pins(o, ind+4);
dump_obj_attr(o, ind+4);
}
void NetCLShift::dump_node(ostream&o, unsigned ind) const
{
o << setw(ind) << "" << "Combinatorial shift (NetCLShift): " <<
@ -427,14 +429,6 @@ void NetPartSelect::dump_node(ostream&o, unsigned ind) const
dump_obj_attr(o, ind+4);
}
void NetRamDq::dump_node(ostream&o, unsigned ind) const
{
o << setw(ind) << "" << "LPM_RAM_DQ (" << mem_->name() << "): "
<< name() << endl;
dump_node_pins(o, ind+4);
dump_obj_attr(o, ind+4);
}
void NetReplicate::dump_node(ostream&o, unsigned ind) const
{
o << setw(ind) << "" << "NetReplicate: "
@ -566,21 +560,9 @@ void NetAssign_::dump_lval(ostream&o) const
{
if (sig_) {
o << sig_->name();
if (bmux_) {
o << "[" << *bmux_ << "]";
} else if (base_) {
o << "[" << *base_ << " +: " << lwid_ << "]";
if (word_) {
o << "[word=" << *word_ << "]";
}
} else if (mem_) {
// Is there an obvious way to flag memories in the dump
// as different from the _real_ bit mux case?
// o << "**memory**";
o << mem_->name() << "[";
if (bmux_) o << *bmux_;
else o << "**oops**";
o << "]";
if (base_) {
o << "[" << *base_ << " +: " << lwid_ << "]";
}
@ -906,15 +888,6 @@ void NetScope::dump(ostream&o) const
} while (cur != signals_->sig_next_);
}
// Dump the memories,
if (memories_) {
NetMemory*cur = memories_->snext_;
do {
cur->dump(o, 4);
cur = cur->snext_;
} while (cur != memories_->snext_);
}
// Dump specparams
typedef map<perm_string,spec_val_t>::const_iterator specparam_it_t;
for (specparam_it_t cur = specparams.begin()
@ -1148,14 +1121,9 @@ void NetESignal::dump(ostream&o) const
{
if (has_sign())
o << "+";
o << name() << "[" << msi()<<":"<<lsi() << "]";
}
void NetEMemory::dump(ostream&o) const
{
o << mem_->name() << "[";
if (idx_) idx_->dump(o);
o << "]";
o << name();
if (word_) o << "[word=" << *word_ << "]";
o << "[" << msi()<<":"<<lsi() << "]";
}
void NetEParam::dump(ostream&o) const
@ -1165,7 +1133,7 @@ void NetEParam::dump(ostream&o) const
else if (name_)
o << "<" << name_ << ">";
else
o << "<???>";
o << "<" "???" ">";
}
void NetETernary::dump(ostream&o) const
@ -1231,6 +1199,12 @@ void Design::dump(ostream&o) const
/*
* $Log: design_dump.cc,v $
* Revision 1.172 2007/01/16 05:44:14 steve
* Major rework of array handling. Memories are replaced with the
* more general concept of arrays. The NetMemory and NetEMemory
* classes are removed from the ivl core program, and the IVL_LPM_RAM
* lpm type is removed from the ivl_target API.
*
* Revision 1.171 2006/10/30 05:44:49 steve
* Expression widths with unsized literals are pseudo-infinite width.
*

View File

@ -17,7 +17,7 @@
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#ifdef HAVE_CVS_IDENT
#ident "$Id: elab_expr.cc,v 1.116 2006/11/10 04:54:26 steve Exp $"
#ident "$Id: elab_expr.cc,v 1.117 2007/01/16 05:44:14 steve Exp $"
#endif
# include "config.h"
@ -687,14 +687,13 @@ unsigned PEIdent::test_width(Design*des, NetScope*scope,
bool&unsized_flag) const
{
NetNet* net = 0;
NetMemory* mem = 0;
const NetExpr*par = 0;
NetEvent* eve = 0;
const NetExpr*ex1, *ex2;
NetScope*found_in = symbol_search(des, scope, path_,
net, mem, par, eve,
net, par, eve,
ex1, ex2);
if (net != 0) {
@ -741,14 +740,13 @@ NetExpr* PEIdent::elaborate_expr(Design*des, NetScope*scope,
assert(scope);
NetNet* net = 0;
NetMemory* mem = 0;
const NetExpr*par = 0;
NetEvent* eve = 0;
const NetExpr*ex1, *ex2;
NetScope*found_in = symbol_search(des, scope, path_,
net, mem, par, eve,
net, par, eve,
ex1, ex2);
// If the identifier name is a parameter name, then return
@ -760,126 +758,7 @@ NetExpr* PEIdent::elaborate_expr(Design*des, NetScope*scope,
// If the identifier names a signal (a register or wire)
// then create a NetESignal node to handle it.
if (net != 0)
return elaborate_expr_net(des, scope, net, found_in);
// If the identifier names a memory, then this is a
// memory reference and I must generate a NetEMemory
// object to handle it.
if (mem != 0) {
if (idx_.empty()) {
if (msb_ || lsb_) {
cerr << get_line() << ": error: "
<< "Part select of a memory: "
<< mem->name() << endl;
des->errors += 1;
}
// If this memory is an argument to a system task,
// then it is OK for it to not have an index.
if (sys_task_arg) {
NetEMemory*node = new NetEMemory(mem);
node->set_line(*this);
return node;
}
// If it is not a simple system task argument,
// this a missing index is an error.
cerr << get_line() << ": error: memory " << mem->name()
<< " needs an index in this context." << endl;
des->errors += 1;
return 0;
}
if (idx_.size() != mem->dimensions()) {
cerr << get_line() << ": error: " << idx_.size()
<< " indices do not properly address a "
<< mem->dimensions() << "-dimension memory/array."
<< endl;
des->errors += 1;
return 0;
}
// XXXX For now, only support single word index.
assert(idx_.size() == 1);
PExpr*addr = idx_[0];
assert(addr);
NetExpr*i = addr->elaborate_expr(des, scope, -1, false);
if (i == 0) {
cerr << get_line() << ": error: Unable to elaborate "
"index expression `" << *addr << "'" << endl;
des->errors += 1;
return 0;
}
NetEMemory*node = new NetEMemory(mem, i);
node->set_line(*this);
if (msb_ == 0 && lsb_ == 0)
return node;
assert(msb_ && lsb_);
assert(sel_ != SEL_NONE);
if (sel_ == SEL_PART) {
NetExpr*le = elab_and_eval(des, scope, lsb_, -1);
NetExpr*me = elab_and_eval(des, scope, msb_, -1);
NetEConst*lec = dynamic_cast<NetEConst*>(le);
NetEConst*mec = dynamic_cast<NetEConst*>(me);
if (lec == 0 || mec == 0) {
cerr << get_line() << ": error: Part select "
<< "expressions must be constant." << endl;
des->errors += 1;
delete le;
delete me;
return node;
}
verinum wedv = mec->value() - lec->value();
unsigned wid = wedv.as_long() + 1;
NetESelect*se = new NetESelect(node, le, wid);
delete me;
return se;
}
assert(sel_ == SEL_IDX_UP || sel_ == SEL_IDX_DO);
NetExpr*wid_ex = elab_and_eval(des, scope, lsb_, -1);
NetEConst*wid_ec = dynamic_cast<NetEConst*> (wid_ex);
if (wid_ec == 0) {
cerr << lsb_->get_line() << ": error: "
<< "Second expression of indexed part select "
<< "most be constant." << endl;
des->errors += 1;
return node;
}
unsigned wid = wid_ec->value().as_ulong();
NetExpr*idx_ex = elab_and_eval(des, scope, msb_, -1);
if (idx_ex == 0) {
return 0;
}
if (sel_ == SEL_IDX_DO && wid > 1) {
idx_ex = make_add_expr(idx_ex, 1-(long)wid);
}
/* Wrap the param expression with a part select. */
NetESelect*se = new NetESelect(node, idx_ex, wid);
se->set_line(*this);
return se;
}
return elaborate_expr_net(des, scope, net, found_in, sys_task_arg);
// If the identifier is a named event.
// is a variable reference.
@ -1176,11 +1055,64 @@ NetExpr* PEIdent::elaborate_expr_param(Design*des,
return tmp;
}
/*
* Handle word selects of vector arrays.
*/
NetExpr* PEIdent::elaborate_expr_net_word_(Design*des, NetScope*scope,
NetNet*net, NetScope*found_in,
bool sys_task_arg) const
{
assert(sys_task_arg || !idx_.empty());
NetExpr*word_index = idx_.empty()
? 0
: elab_and_eval(des, scope, idx_[0], -1);
if (word_index == 0 && !sys_task_arg)
return 0;
if (NetEConst*word_addr = dynamic_cast<NetEConst*>(word_index)) {
long addr = word_addr->value().as_long();
// Special case: The index is out of range, so the value
// of this expression is a 'bx vector the width of a word.
if (!net->array_index_is_valid(addr)) {
verinum xxx (verinum::Vx, net->vector_width());
NetEConst*resx = new NetEConst(xxx);
resx->set_line(*this);
delete word_index;
return resx;
}
// Recalculate the constant address with the adjusted base.
unsigned use_addr = net->array_index_to_address(addr);
if (use_addr != addr) {
verinum val (use_addr, 8*sizeof(use_addr));
NetEConst*tmp = new NetEConst(val);
tmp->set_line(*this);
delete word_index;
word_index = tmp;
}
}
NetESignal*res = new NetESignal(net, word_index);
res->set_line(*this);
if (sel_ == SEL_PART)
return elaborate_expr_net_part_(des, scope, res, found_in);
if (sel_ == SEL_IDX_UP)
return elaborate_expr_net_idx_up_(des, scope, res, found_in);
if (sel_ == SEL_IDX_DO)
return elaborate_expr_net_idx_do_(des, scope, res, found_in);
return res;
}
/*
* Handle part selects of NetNet identifiers.
*/
NetExpr* PEIdent::elaborate_expr_net_part_(Design*des, NetScope*scope,
NetNet*net, NetScope*found_in)const
NetESignal*net, NetScope*found_in) const
{
long msv, lsv;
assert(idx_.empty());
@ -1199,40 +1131,37 @@ NetExpr* PEIdent::elaborate_expr_net_part_(Design*des, NetScope*scope,
des->errors += 1;
//delete lsn;
//delete msn;
return 0;
return net;
}
assert(wid <= net->vector_width());
if (net->sb_to_idx(msv) < net->sb_to_idx(lsv)) {
if (net->sig()->sb_to_idx(msv) < net->sig()->sb_to_idx(lsv)) {
cerr << get_line() << ": error: part select ["
<< msv << ":" << lsv << "] out of order." << endl;
des->errors += 1;
//delete lsn;
//delete msn;
return 0;
return net;
}
if (net->sb_to_idx(msv) >= net->vector_width()) {
if (net->sig()->sb_to_idx(msv) >= net->vector_width()) {
cerr << get_line() << ": error: part select ["
<< msv << ":" << lsv << "] out of range." << endl;
des->errors += 1;
//delete lsn;
//delete msn;
return 0;
return net;
}
NetESignal*tmp = new NetESignal(net);
tmp->set_line(*this);
// If the part select convers exactly the entire
// vector, then do not bother with it. Return the
// signal itself.
if (net->sb_to_idx(lsv) == 0 && wid == net->vector_width())
return tmp;
if (net->sig()->sb_to_idx(lsv) == 0 && wid == net->vector_width())
return net;
NetExpr*ex = new NetEConst(verinum(net->sb_to_idx(lsv)));
NetESelect*ss = new NetESelect(tmp, ex, wid);
NetExpr*ex = new NetEConst(verinum(net->sig()->sb_to_idx(lsv)));
NetESelect*ss = new NetESelect(net, ex, wid);
ss->set_line(*this);
return ss;
@ -1242,14 +1171,10 @@ NetExpr* PEIdent::elaborate_expr_net_part_(Design*des, NetScope*scope,
* Part select indexed up, i.e. net[<m> +: <l>]
*/
NetExpr* PEIdent::elaborate_expr_net_idx_up_(Design*des, NetScope*scope,
NetNet*net, NetScope*found_in)const
NetESignal*net, NetScope*found_in) const
{
assert(lsb_ != 0);
assert(msb_ != 0);
assert(idx_.empty());
NetESignal*sig = new NetESignal(net);
sig->set_line(*this);
NetExpr*base = elab_and_eval(des, scope, msb_, -1);
@ -1266,11 +1191,11 @@ NetExpr* PEIdent::elaborate_expr_net_idx_up_(Design*des, NetScope*scope,
// If the part select convers exactly the entire
// vector, then do not bother with it. Return the
// signal itself.
if (net->sb_to_idx(lsv) == 0 && wid == net->vector_width())
return sig;
if (net->sig()->sb_to_idx(lsv) == 0 && wid == net->vector_width())
return net;
}
NetESelect*ss = new NetESelect(sig, base, wid);
NetESelect*ss = new NetESelect(net, base, wid);
ss->set_line(*this);
if (debug_elaborate) {
@ -1285,14 +1210,10 @@ NetExpr* PEIdent::elaborate_expr_net_idx_up_(Design*des, NetScope*scope,
* Part select up, i.e. net[<m> +: <l>]
*/
NetExpr* PEIdent::elaborate_expr_net_idx_do_(Design*des, NetScope*scope,
NetNet*net, NetScope*found_in)const
NetESignal*net, NetScope*found_in)const
{
assert(lsb_ != 0);
assert(msb_ != 0);
assert(idx_.empty());
NetESignal*sig = new NetESignal(net);
sig->set_line(*this);
NetExpr*base = elab_and_eval(des, scope, msb_, -1);
@ -1308,12 +1229,13 @@ NetExpr* PEIdent::elaborate_expr_net_idx_do_(Design*des, NetScope*scope,
// If the part select convers exactly the entire
// vector, then do not bother with it. Return the
// signal itself.
if (net->sb_to_idx(lsv) == (wid-1) && wid == net->vector_width())
return sig;
if (net->sig()->sb_to_idx(lsv) == (wid-1)
&& wid == net->vector_width())
return net;
}
NetExpr*base_adjusted = wid > 1? make_add_expr(base,1-wid) : base;
NetESelect*ss = new NetESelect(sig, base_adjusted, wid);
NetESelect*ss = new NetESelect(net, base_adjusted, wid);
ss->set_line(*this);
if (debug_elaborate) {
@ -1325,7 +1247,7 @@ NetExpr* PEIdent::elaborate_expr_net_idx_do_(Design*des, NetScope*scope,
}
NetExpr* PEIdent::elaborate_expr_net_bit_(Design*des, NetScope*scope,
NetNet*net, NetScope*found_in) const
NetESignal*net, NetScope*found_in) const
{
assert(msb_ == 0);
assert(lsb_ == 0);
@ -1338,7 +1260,7 @@ NetExpr* PEIdent::elaborate_expr_net_bit_(Design*des, NetScope*scope,
// making a mux part in the netlist.
if (NetEConst*msc = dynamic_cast<NetEConst*> (ex)) {
long msv = msc->value().as_long();
unsigned idx = net->sb_to_idx(msv);
unsigned idx = net->sig()->sb_to_idx(msv);
if (idx >= net->vector_width()) {
/* The bit select is out of range of the
@ -1350,69 +1272,72 @@ NetExpr* PEIdent::elaborate_expr_net_bit_(Design*des, NetScope*scope,
cerr << get_line() << ": warning: Bit select ["
<< msv << "] out of range of vector "
<< net->name() << "[" << net->msb()
<< ":" << net->lsb() << "]." << endl;
<< net->name() << "[" << net->sig()->msb()
<< ":" << net->sig()->lsb() << "]." << endl;
cerr << get_line() << ": : Replacing "
<< "expression with a constant 1'bx." << endl;
delete ex;
return tmp;
}
NetESignal*tmp = new NetESignal(net);
tmp->set_line(*this);
// If the vector is only one bit, we are done. The
// bit select will return the scaler itself.
if (net->vector_width() == 1)
return tmp;
return net;
// Make an expression out of the index
NetEConst*idx_c = new NetEConst(verinum(idx));
idx_c->set_line(*net);
// Make a bit select with the canonical index
NetESelect*res = new NetESelect(tmp, idx_c, 1);
NetESelect*res = new NetESelect(net, idx_c, 1);
res->set_line(*net);
return res;
}
NetESignal*node = new NetESignal(net);
// Non-constant bit select? punt and make a subsignal
// device to mux the bit in the net. This is a fairly
// complicated task because we need to generate
// expressions to convert calculated bit select
// values to canonical values that are used internally.
if (net->msb() < net->lsb()) {
ex = make_sub_expr(net->lsb(), ex);
if (net->sig()->msb() < net->sig()->lsb()) {
ex = make_sub_expr(net->sig()->lsb(), ex);
} else {
ex = make_add_expr(ex, - net->lsb());
ex = make_add_expr(ex, - net->sig()->lsb());
}
NetESelect*ss = new NetESelect(node, ex, 1);
NetESelect*ss = new NetESelect(net, ex, 1);
ss->set_line(*this);
return ss;
}
NetExpr* PEIdent::elaborate_expr_net(Design*des, NetScope*scope,
NetNet*net, NetScope*found_in) const
NetNet*net, NetScope*found_in,
bool sys_task_arg) const
{
if (net->array_dimensions() > 0)
return elaborate_expr_net_word_(des, scope, net, found_in, sys_task_arg);
NetESignal*node = new NetESignal(net);
node->set_line(*this);
// If this is a part select of a signal, then make a new
// temporary signal that is connected to just the
// selected bits. The lsb_ and msb_ expressions are from
// the foo[msb:lsb] expression in the original.
if (sel_ == SEL_PART)
return elaborate_expr_net_part_(des, scope, net, found_in);
return elaborate_expr_net_part_(des, scope, node, found_in);
if (sel_ == SEL_IDX_UP)
return elaborate_expr_net_idx_up_(des, scope, net, found_in);
return elaborate_expr_net_idx_up_(des, scope, node, found_in);
if (sel_ == SEL_IDX_DO)
return elaborate_expr_net_idx_do_(des, scope, net, found_in);
return elaborate_expr_net_idx_do_(des, scope, node, found_in);
if (!idx_.empty())
return elaborate_expr_net_bit_(des, scope, net, found_in);
return elaborate_expr_net_bit_(des, scope, node, found_in);
// It's not anything else, so this must be a simple identifier
// expression with no part or bit select. Return the signal
@ -1422,8 +1347,6 @@ NetExpr* PEIdent::elaborate_expr_net(Design*des, NetScope*scope,
assert(lsb_ == 0);
assert(idx_.empty());
NetESignal*node = new NetESignal(net);
node->set_line(*this);
return node;
}
@ -1675,6 +1598,12 @@ NetExpr* PEUnary::elaborate_expr(Design*des, NetScope*scope,
/*
* $Log: elab_expr.cc,v $
* Revision 1.117 2007/01/16 05:44:14 steve
* Major rework of array handling. Memories are replaced with the
* more general concept of arrays. The NetMemory and NetEMemory
* classes are removed from the ivl core program, and the IVL_LPM_RAM
* lpm type is removed from the ivl_target API.
*
* Revision 1.116 2006/11/10 04:54:26 steve
* Add test_width methods for PETernary and PEString.
*

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2000 Stephen Williams (steve@icarus.com)
* Copyright (c) 2000-2006 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
@ -17,7 +17,7 @@
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#ifdef HAVE_CVS_IDENT
#ident "$Id: elab_lval.cc,v 1.37 2006/11/04 06:19:25 steve Exp $"
#ident "$Id: elab_lval.cc,v 1.38 2007/01/16 05:44:15 steve Exp $"
#endif
# include "config.h"
@ -25,7 +25,7 @@
# include "PExpr.h"
# include "netlist.h"
# include "netmisc.h"
# include "compiler.h"
# include <iostream>
/*
@ -149,25 +149,10 @@ NetAssign_* PEIdent::elaborate_lval(Design*des,
bool is_force) const
{
NetNet* reg = 0;
NetMemory* mem = 0;
const NetExpr*par = 0;
NetEvent* eve = 0;
symbol_search(des, scope, path_, reg, mem, par, eve);
if (mem) {
if (is_force) {
cerr << get_line() << ": error: Memories "
<< "(" << path_ << " in this case)"
<< " are not allowed"
<< " as l-values to force statements." << endl;
des->errors += 1;
return 0;
}
return elaborate_mem_lval_(des, scope, mem);
}
symbol_search(des, scope, path_, reg, par, eve);
if (reg == 0) {
cerr << get_line() << ": error: Could not find variable ``"
<< path_ << "'' in ``" << scope->name() <<
@ -179,14 +164,26 @@ NetAssign_* PEIdent::elaborate_lval(Design*des,
assert(reg);
if (sel_ == SEL_PART)
return elaborate_lval_net_part_(des, scope, reg);
if (reg->array_dimensions() > 0)
return elaborate_lval_net_word_(des, scope, reg);
if (sel_ == SEL_IDX_UP)
return elaborate_lval_net_idx_up_(des, scope, reg);
if (sel_ == SEL_PART) {
NetAssign_*lv = new NetAssign_(reg);
elaborate_lval_net_part_(des, scope, lv);
return lv;
}
if (sel_ == SEL_IDX_DO)
return elaborate_lval_net_idx_do_(des, scope, reg);
if (sel_ == SEL_IDX_UP) {
NetAssign_*lv = new NetAssign_(reg);
elaborate_lval_net_idx_up_(des, scope, lv);
return lv;
}
if (sel_ == SEL_IDX_DO) {
NetAssign_*lv = new NetAssign_(reg);
elaborate_lval_net_idx_do_(des, scope, lv);
return lv;
}
/* Get the signal referenced by the identifier, and make sure
it is a register. Wires are not allows in this context,
@ -300,22 +297,60 @@ NetAssign_* PEIdent::elaborate_lval(Design*des,
return lv;
}
NetAssign_* PEIdent::elaborate_lval_net_part_(Design*des,
NetAssign_* PEIdent::elaborate_lval_net_word_(Design*des,
NetScope*scope,
NetNet*reg) const
{
assert(idx_.size() == 1);
NetExpr*word = elab_and_eval(des, scope, idx_[0], -1);
// If there is a non-zero base to the memory, then build an
// expression to calculate the canonical address.
if (long base = reg->array_first()) {
word = make_add_expr(word, 0-base);
if (NetExpr*tmp = word->eval_tree()) {
word = tmp;
}
}
NetAssign_*lv = new NetAssign_(reg);
lv->set_word(word);
if (debug_elaborate)
cerr << get_line() << ": debug: Set array word=" << *word << endl;
/* An array word may also have part selects applied to them. */
if (sel_ == SEL_PART)
elaborate_lval_net_part_(des, scope, lv);
if (sel_ == SEL_IDX_UP)
elaborate_lval_net_idx_up_(des, scope, lv);
if (sel_ == SEL_IDX_DO)
elaborate_lval_net_idx_do_(des, scope, lv);
return lv;
}
bool PEIdent::elaborate_lval_net_part_(Design*des,
NetScope*scope,
NetAssign_*lv) const
{
long msb, lsb;
bool flag = calculate_parts_(des, scope, msb, lsb);
if (!flag)
return 0;
return false;
NetAssign_*lv = 0;
NetNet*reg = lv->sig();
assert(reg);
if (msb == reg->msb() && lsb == reg->lsb()) {
/* No bit select, and part select covers the entire
vector. Simplest case. */
lv = new NetAssign_(reg);
} else {
@ -331,7 +366,7 @@ NetAssign_* PEIdent::elaborate_lval_net_part_(Design*des,
<< reg->name() << "[" << msb<<":"<<lsb<<"]"
<< " is reversed." << endl;
des->errors += 1;
return 0;
return false;
}
/* If the part select extends beyond the extreme of the
@ -344,23 +379,25 @@ NetAssign_* PEIdent::elaborate_lval_net_part_(Design*des,
<< reg->name() << "[" << msb<<":"<<lsb<<"]"
<< " is out of range." << endl;
des->errors += 1;
return 0;
return false;
}
lv = new NetAssign_(reg);
lv->set_part(new NetEConst(verinum(loff)), wid);
}
return lv;
return true;
}
NetAssign_* PEIdent::elaborate_lval_net_idx_up_(Design*des,
NetScope*scope,
NetNet*reg) const
bool PEIdent::elaborate_lval_net_idx_up_(Design*des,
NetScope*scope,
NetAssign_*lv) const
{
assert(lsb_);
assert(msb_);
NetNet*reg = lv->sig();
assert(reg);
if (reg->type() != NetNet::REG) {
cerr << get_line() << ": error: " << path_ <<
" is not a reg/integer/time in " << scope->name() <<
@ -368,7 +405,7 @@ NetAssign_* PEIdent::elaborate_lval_net_idx_up_(Design*des,
cerr << reg->get_line() << ": : " << path_ <<
" is declared here as " << reg->type() << "." << endl;
des->errors += 1;
return 0;
return false;
}
unsigned long wid;
@ -382,112 +419,25 @@ NetAssign_* PEIdent::elaborate_lval_net_idx_up_(Design*des,
else if (reg->lsb() != 0)
base = make_add_expr(base, - reg->lsb());
NetAssign_*lv = new NetAssign_(reg);
if (debug_elaborate)
cerr << get_line() << ": debug: Set part select width="
<< wid << ", base=" << *base << endl;
lv->set_part(base, wid);
return lv;
return true;
}
NetAssign_* PEIdent::elaborate_lval_net_idx_do_(Design*des,
NetScope*scope,
NetNet*reg) const
bool PEIdent::elaborate_lval_net_idx_do_(Design*des,
NetScope*scope,
NetAssign_*lv) const
{
assert(lsb_);
assert(msb_);
cerr << get_line() << ": internal error: don't know how to "
"deal with SEL_IDX_DO in lval?" << endl;
des->errors += 1;
return 0;
}
NetAssign_* PEIdent::elaborate_mem_lval_(Design*des, NetScope*scope,
NetMemory*mem) const
{
if (idx_.empty()) {
cerr << get_line() << ": error: Assign to memory \""
<< mem->name() << "\" requires a word select index."
<< endl;
des->errors += 1;
return 0;
}
if (idx_.size() != mem->dimensions()) {
cerr << get_line() << ": error: " << idx_.size()
<< " indices do not properly address a "
<< mem->dimensions() << "-dimension memory/array."
<< endl;
des->errors += 1;
return 0;
}
// XXXX For now, require exactly 1 index.
assert(idx_.size() == 1);
/* Elaborate the address expression. */
NetExpr*ix = elab_and_eval(des, scope, idx_[0], -1);
if (ix == 0)
return 0;
NetAssign_*lv = new NetAssign_(mem);
lv->set_bmux(ix);
/* If there is no extra part select, then we are done. */
if (msb_ == 0 && lsb_ == 0) {
lv->set_part(0, mem->width());
return lv;
}
assert(sel_ != SEL_NONE);
assert(msb_ && lsb_);
if (sel_ == SEL_PART) {
NetExpr*le = elab_and_eval(des, scope, lsb_, -1);
NetExpr*me = elab_and_eval(des, scope, msb_, -1);
NetEConst*lec = dynamic_cast<NetEConst*>(le);
NetEConst*mec = dynamic_cast<NetEConst*>(me);
if (lec == 0 || mec == 0) {
cerr << get_line() << ": error: Part select "
<< "expressions must be constant." << endl;
des->errors += 1;
delete le;
delete me;
return lv;
}
verinum wedv = mec->value() - lec->value();
unsigned wid = wedv.as_long() + 1;
lv->set_part(lec, wid);
return lv;
}
assert(sel_ == SEL_IDX_UP || sel_ == SEL_IDX_DO);
NetExpr*wid_ex = elab_and_eval(des, scope, lsb_, -1);
NetEConst*wid_ec = dynamic_cast<NetEConst*> (wid_ex);
if (wid_ec == 0) {
cerr << lsb_->get_line() << ": error: "
<< "Second expression of indexed part select "
<< "most be constant." << endl;
des->errors += 1;
return lv;
}
unsigned wid = wid_ec->value().as_ulong();
NetExpr*base_ex = elab_and_eval(des, scope, msb_, -1);
if (base_ex == 0) {
return 0;
}
if (sel_ == SEL_IDX_DO && wid > 1) {
base_ex = make_add_expr(base_ex, 1-(long)wid);
}
lv->set_part(base_ex, wid);
return lv;
return false;
}
NetAssign_* PENumber::elaborate_lval(Design*des, NetScope*, bool) const
@ -500,6 +450,12 @@ NetAssign_* PENumber::elaborate_lval(Design*des, NetScope*, bool) const
/*
* $Log: elab_lval.cc,v $
* Revision 1.38 2007/01/16 05:44:15 steve
* Major rework of array handling. Memories are replaced with the
* more general concept of arrays. The NetMemory and NetEMemory
* classes are removed from the ivl core program, and the IVL_LPM_RAM
* lpm type is removed from the ivl_target API.
*
* Revision 1.37 2006/11/04 06:19:25 steve
* Remove last bits of relax_width methods, and use test_width
* to calculate the width of an r-value expression that may

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 1999-2005 Stephen Williams (steve@icarus.com)
* Copyright (c) 1999-2007 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
@ -17,7 +17,7 @@
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#ifdef HAVE_CVS_IDENT
#ident "$Id: elab_net.cc,v 1.191 2006/12/08 03:43:26 steve Exp $"
#ident "$Id: elab_net.cc,v 1.192 2007/01/16 05:44:15 steve Exp $"
#endif
# include "config.h"
@ -1594,18 +1594,10 @@ NetNet* PEIdent::elaborate_net(Design*des, NetScope*scope,
assert(scope);
NetNet* sig = 0;
NetMemory* mem = 0;
const NetExpr*par = 0;
const NetExpr*par = 0;
NetEvent* eve = 0;
symbol_search(des, scope, path_, sig, mem, par, eve);
/* If the identifier is a memory instead of a signal,
then handle it elsewhere. Create a RAM. */
if (mem != 0) {
return elaborate_net_ram_(des, scope, mem, lwidth,
rise, fall, decay);
}
symbol_search(des, scope, path_, sig, par, eve);
/* If this is a parameter name, then create a constant node
that connects to a signal with the correct name. */
@ -1681,6 +1673,13 @@ NetNet* PEIdent::elaborate_net(Design*des, NetScope*scope,
assert(sig);
/* Handle the case that this is an array elsewhere. */
if (sig->array_dimensions() > 0) {
return elaborate_net_array_(des, scope, sig, lwidth,
rise, fall, decay,
drive0, drive1);
}
/* Catch the case of a non-constant bit select. That should be
handled elsewhere. */
if (! idx_.empty()) {
@ -1728,68 +1727,77 @@ NetNet* PEIdent::elaborate_net(Design*des, NetScope*scope,
return sig;
}
/*
* When I run into an identifier in an expression that refers to a
* memory, create a RAM port object.
*/
NetNet* PEIdent::elaborate_net_ram_(Design*des, NetScope*scope,
NetMemory*mem, unsigned lwidth,
const NetExpr* rise,
const NetExpr* fall,
const NetExpr* decay) const
NetNet* PEIdent::elaborate_net_array_(Design*des, NetScope*scope,
NetNet*sig, unsigned lwidth,
const NetExpr* rise,
const NetExpr* fall,
const NetExpr* decay,
Link::strength_t drive0,
Link::strength_t drive1) const
{
assert(scope);
if (idx_.empty()) {
cerr << get_line() << ": error: memory reference without"
" the required index expression." << endl;
des->errors += 1;
return 0;
}
assert(msb_ == 0);
assert(lsb_ == 0);
assert(idx_.size() == 1);
/* Even if this expression must be fully self determined, the
index expression does not, so make sure this flag is off
while elaborating the address expression. */
const bool must_be_self_determined_save = must_be_self_determined_flag;
must_be_self_determined_flag = false;
NetExpr*adr_expr = elab_and_eval(des, scope, idx_[0], -1);
/* If an offset is needed, subtract it from the address to get
an expression for the canonical address. */
if (mem->index_to_address(0) != 0) {
adr_expr = make_add_expr(adr_expr, mem->index_to_address(0));
if (NetExpr*tmp = adr_expr->eval_tree()) {
delete adr_expr;
adr_expr = tmp;
}
}
NetNet*adr = adr_expr->synthesize(des);
delete adr_expr;
must_be_self_determined_flag = must_be_self_determined_save;
if (adr == 0)
NetExpr*index_ex = elab_and_eval(des, scope, idx_[0], -1);
if (index_ex == 0)
return 0;
NetRamDq*ram = new NetRamDq(scope, scope->local_symbol(),
mem, adr->vector_width());
des->add_node(ram);
if (NetEConst*index_co = dynamic_cast<NetEConst*> (index_ex)) {
long index = index_co->value().as_long();
connect(ram->pin_Address(), adr->pin(0));
if (!sig->array_index_is_valid(index)) {
// Oops! The index is a constant known to be
// outside the array. Change the expression to a
// constant X vector.
verinum xxx (verinum::Vx, sig->vector_width());
NetConst*con_n = new NetConst(scope, scope->local_symbol(), xxx);
des->add_node(con_n);
con_n->set_line(*index_co);
NetNet*osig = new NetNet(scope, scope->local_symbol(),
NetNet::IMPLICIT, ram->width());
osig->data_type(IVL_VT_LOGIC);
osig->local_flag(true);
NetNet*tmp = new NetNet(scope, scope->local_symbol(),
NetNet::IMPLICIT, sig->vector_width());
tmp->set_line(*this);
tmp->local_flag(true);
tmp->data_type(sig->data_type());
connect(tmp->pin(0), con_n->pin(0));
return tmp;
}
connect(ram->pin_Q(), osig->pin(0));
assert(sig->array_index_is_valid(index));
index = sig->array_index_to_address(index);
return osig;
NetNet*tmp = new NetNet(scope, scope->local_symbol(),
NetNet::IMPLICIT, sig->vector_width());
tmp->set_line(*this);
tmp->local_flag(true);
connect(tmp->pin(0), sig->pin(index));
return tmp;
}
unsigned selwid = index_ex->expr_width();
NetArrayDq*mux = new NetArrayDq(scope, scope->local_symbol(),
sig, selwid);
mux->set_line(*this);
des->add_node(mux);
// Adjust the expression to calculate the canonical offset?
if (long array_base = sig->array_first()) {
index_ex = make_add_expr(index_ex, 0-array_base);
}
NetNet*index_net = index_ex->synthesize(des);
connect(mux->pin_Address(), index_net->pin(0));
NetNet*tmp = new NetNet(scope, scope->local_symbol(),
NetNet::IMPLICIT, sig->vector_width());
tmp->set_line(*this);
tmp->local_flag(true);
tmp->data_type(sig->data_type());
connect(tmp->pin(0), mux->pin_Result());
return tmp;
}
/*
@ -2127,19 +2135,10 @@ NetNet* PEIdent::elaborate_lnet_common_(Design*des, NetScope*scope,
assert(scope);
NetNet* sig = 0;
NetMemory* mem = 0;
const NetExpr*par = 0;
NetEvent* eve = 0;
symbol_search(des, scope, path_, sig, mem, par, eve);
if (mem != 0) {
cerr << get_line() << ": error: memories (" << path_
<< ") cannot be l-values in continuous "
<< "assignments." << endl;
des->errors += 1;
return 0;
}
symbol_search(des, scope, path_, sig, par, eve);
if (eve != 0) {
cerr << get_line() << ": error: named events (" << path_
@ -2184,12 +2183,44 @@ NetNet* PEIdent::elaborate_lnet_common_(Design*des, NetScope*scope,
sig->port_type(NetNet::PINOUT);
}
unsigned midx, lidx;
if (! eval_part_select_(des, scope, sig, midx, lidx))
return 0;
// Default part select is the entire word.
unsigned midx = sig->vector_width()-1, lidx = 0;
// The default word select is the first.
unsigned widx = 0;
if (sig->array_dimensions() > 0) {
assert(!idx_.empty());
NetExpr*tmp_ex = elab_and_eval(des, scope, idx_[0], -1);
NetEConst*tmp = dynamic_cast<NetEConst*>(tmp_ex);
assert(tmp);
long widx_val = tmp->value().as_long();
widx = sig->array_index_to_address(widx_val);
delete tmp_ex;
if (debug_elaborate)
cerr << get_line() << ": debug: Use [" << widx << "]"
<< " to index l-value array." << endl;
} else {
if (! eval_part_select_(des, scope, sig, midx, lidx))
return 0;
}
unsigned subnet_wid = midx-lidx+1;
if (sig->pin_count() > 1) {
assert(widx < sig->pin_count());
NetNet*tmp = new NetNet(scope, scope->local_symbol(),
sig->type(), sig->vector_width());
tmp->set_line(*this);
tmp->local_flag(true);
connect(sig->pin(widx), tmp->pin(0));
sig = tmp;
}
/* If the desired l-value vector is narrower then the
signal itself, then use a NetPartSelect node to
arrange for connection to the desired bits. All this
@ -2850,6 +2881,12 @@ NetNet* PEUnary::elaborate_net(Design*des, NetScope*scope,
/*
* $Log: elab_net.cc,v $
* Revision 1.192 2007/01/16 05:44:15 steve
* Major rework of array handling. Memories are replaced with the
* more general concept of arrays. The NetMemory and NetEMemory
* classes are removed from the ivl core program, and the IVL_LPM_RAM
* lpm type is removed from the ivl_target API.
*
* Revision 1.191 2006/12/08 03:43:26 steve
* Prevent name clash when processing parameter in net.
*

View File

@ -17,7 +17,7 @@
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#ifdef HAVE_CVS_IDENT
#ident "$Id: elab_sig.cc,v 1.42 2006/06/02 04:48:50 steve Exp $"
#ident "$Id: elab_sig.cc,v 1.43 2007/01/16 05:44:15 steve Exp $"
#endif
# include "config.h"
@ -616,6 +616,9 @@ void PWire::elaborate_sig(Design*des, NetScope*scope) const
attrib_list_t*attrib_list = evaluate_attributes(attributes, nattrib,
des, scope);
long array_s0 = 0;
long array_e0 = 0;
/* If the ident has idx expressions, then this is a
memory. It can only have the idx registers after the msb
and lsb expressions are filled. And, if it has one index,
@ -639,7 +642,7 @@ void PWire::elaborate_sig(Design*des, NetScope*scope) const
if ((lcon == 0) || (rcon == 0)) {
cerr << get_line() << ": internal error: The indices "
<< "are not constant for memory ``"
<< "are not constant for array ``"
<< hname_.peek_tail_name() << "''." << endl;
des->errors += 1;
return;
@ -653,73 +656,74 @@ void PWire::elaborate_sig(Design*des, NetScope*scope) const
perm_string name = lex_strings.make(hname_.peek_tail_name());
long lnum = lval.as_long();
long rnum = rval.as_long();
new NetMemory(scope, name, wid, lnum, rnum);
// The constructor automatically adds the memory object
// to the scope. Do I need to set line number information?
} else {
/* If the net type is supply0 or supply1, replace it
with a simple wire with a pulldown/pullup with supply
strength. In other words, transform:
supply0 foo;
to:
wire foo;
pulldown #(supply0) (foo);
This reduces the backend burden, and behaves exactly
the same. */
NetLogic*pull = 0;
if (wtype == NetNet::SUPPLY0 || wtype == NetNet::SUPPLY1) {
NetLogic::TYPE pull_type = (wtype==NetNet::SUPPLY1)
? NetLogic::PULLUP
: NetLogic::PULLDOWN;
pull = new NetLogic(scope, scope->local_symbol(),
1, pull_type, wid);
pull->set_line(*this);
pull->pin(0).drive0(Link::SUPPLY);
pull->pin(0).drive1(Link::SUPPLY);
des->add_node(pull);
wtype = NetNet::WIRE;
if (debug_elaborate) {
cerr << get_line() << ": debug: "
<< "Generate a SUPPLY pulldown for the "
<< "supply0 net." << endl;
}
}
perm_string name = lex_strings.make(hname_.peek_tail_name());
if (debug_elaborate) {
cerr << get_line() << ": debug: Create signal "
<< name << "["<<msb<<":"<<lsb<<"]"
<< " in scope " << scope->name() << endl;
}
NetNet*sig = new NetNet(scope, name, wtype, msb, lsb);
sig->data_type(data_type_);
sig->set_line(*this);
sig->port_type(port_type_);
sig->set_signed(get_signed());
sig->set_isint(get_isint());
if (pull)
connect(sig->pin(0), pull->pin(0));
for (unsigned idx = 0 ; idx < nattrib ; idx += 1)
sig->attribute(attrib_list[idx].key, attrib_list[idx].val);
array_s0 = lval.as_long();
array_e0 = rval.as_long();
}
/* If the net type is supply0 or supply1, replace it
with a simple wire with a pulldown/pullup with supply
strength. In other words, transform:
supply0 foo;
to:
wire foo;
pulldown #(supply0) (foo);
This reduces the backend burden, and behaves exactly
the same. */
NetLogic*pull = 0;
if (wtype == NetNet::SUPPLY0 || wtype == NetNet::SUPPLY1) {
NetLogic::TYPE pull_type = (wtype==NetNet::SUPPLY1)
? NetLogic::PULLUP
: NetLogic::PULLDOWN;
pull = new NetLogic(scope, scope->local_symbol(),
1, pull_type, wid);
pull->set_line(*this);
pull->pin(0).drive0(Link::SUPPLY);
pull->pin(0).drive1(Link::SUPPLY);
des->add_node(pull);
wtype = NetNet::WIRE;
if (debug_elaborate) {
cerr << get_line() << ": debug: "
<< "Generate a SUPPLY pulldown for the "
<< "supply0 net." << endl;
}
}
perm_string name = lex_strings.make(hname_.peek_tail_name());
if (debug_elaborate) {
cerr << get_line() << ": debug: Create signal "
<< name << "["<<msb<<":"<<lsb<<"]"
<< " in scope " << scope->name() << endl;
}
NetNet*sig = new NetNet(scope, name, wtype, msb, lsb,
array_s0, array_e0);
sig->data_type(data_type_);
sig->set_line(*this);
sig->port_type(port_type_);
sig->set_signed(get_signed());
sig->set_isint(get_isint());
if (pull)
connect(sig->pin(0), pull->pin(0));
for (unsigned idx = 0 ; idx < nattrib ; idx += 1)
sig->attribute(attrib_list[idx].key, attrib_list[idx].val);
}
/*
* $Log: elab_sig.cc,v $
* Revision 1.43 2007/01/16 05:44:15 steve
* Major rework of array handling. Memories are replaced with the
* more general concept of arrays. The NetMemory and NetEMemory
* classes are removed from the ivl core program, and the IVL_LPM_RAM
* lpm type is removed from the ivl_target API.
*
* Revision 1.42 2006/06/02 04:48:50 steve
* Make elaborate_expr methods aware of the width that the context
* requires of it. In the process, fix sizing of the width of unary

View File

@ -17,7 +17,7 @@
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#ifdef HAVE_CVS_IDENT
#ident "$Id: elaborate.cc,v 1.354 2006/12/09 01:59:35 steve Exp $"
#ident "$Id: elaborate.cc,v 1.355 2007/01/16 05:44:15 steve Exp $"
#endif
# include "config.h"
@ -2295,12 +2295,11 @@ NetProc* PEventStatement::elaborate_st(Design*des, NetScope*scope,
if (PEIdent*id = dynamic_cast<PEIdent*>(expr_[idx]->expr())) {
NetNet* sig = 0;
NetMemory* mem = 0;
const NetExpr*par = 0;
NetEvent* eve = 0;
NetScope*found_in = symbol_search(des, scope, id->path(),
sig, mem, par, eve);
sig, par, eve);
if (found_in && eve) {
wa->add_event(eve);
@ -2874,12 +2873,11 @@ NetProc* PTrigger::elaborate(Design*des, NetScope*scope) const
assert(scope);
NetNet* sig = 0;
NetMemory* mem = 0;
const NetExpr*par = 0;
NetEvent* eve = 0;
NetScope*found_in = symbol_search(des, scope, event_,
sig, mem, par, eve);
sig, par, eve);
if (found_in == 0) {
cerr << get_line() << ": error: event <" << event_ << ">"
@ -3349,6 +3347,12 @@ Design* elaborate(list<perm_string>roots)
/*
* $Log: elaborate.cc,v $
* Revision 1.355 2007/01/16 05:44:15 steve
* Major rework of array handling. Memories are replaced with the
* more general concept of arrays. The NetMemory and NetEMemory
* classes are removed from the ivl core program, and the IVL_LPM_RAM
* lpm type is removed from the ivl_target API.
*
* Revision 1.354 2006/12/09 01:59:35 steve
* Fix an uninitialized variable warning.
*

31
emit.cc
View File

@ -17,7 +17,7 @@
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#ifdef HAVE_CVS_IDENT
#ident "$Id: emit.cc,v 1.88 2006/11/10 05:44:44 steve Exp $"
#ident "$Id: emit.cc,v 1.89 2007/01/16 05:44:15 steve Exp $"
#endif
# include "config.h"
@ -57,6 +57,11 @@ bool NetAddSub::emit_node(struct target_t*tgt) const
return true;
}
bool NetArrayDq::emit_node(struct target_t*tgt) const
{
return tgt->lpm_array_dq(this);
}
bool NetCaseCmp::emit_node(struct target_t*tgt) const
{
tgt->net_case_cmp(this);
@ -125,12 +130,6 @@ bool NetPartSelect::emit_node(struct target_t*tgt) const
return tgt->part_select(this);
}
bool NetRamDq::emit_node(struct target_t*tgt) const
{
tgt->lpm_ram_dq(this);
return true;
}
bool NetReplicate::emit_node(struct target_t*tgt) const
{
return tgt->replicate(this);
@ -357,13 +356,6 @@ void NetScope::emit_scope(struct target_t*tgt) const
} while (cur != signals_->sig_next_);
}
if (memories_) {
NetMemory*cur = memories_->snext_;
do {
tgt->memory(cur);
cur = cur->snext_;
} while (cur != memories_->snext_);
}
}
bool NetScope::emit_defs(struct target_t*tgt) const
@ -472,11 +464,6 @@ void NetECRealParam::expr_scan(struct expr_scan_t*tgt) const
tgt->expr_rparam(this);
}
void NetEMemory::expr_scan(struct expr_scan_t*tgt) const
{
tgt->expr_memory(this);
}
void NetEParam::expr_scan(struct expr_scan_t*tgt) const
{
cerr << get_line() << ":internal error: unexpected NetEParam."
@ -540,6 +527,12 @@ int emit(const Design*des, const char*type)
/*
* $Log: emit.cc,v $
* Revision 1.89 2007/01/16 05:44:15 steve
* Major rework of array handling. Memories are replaced with the
* more general concept of arrays. The NetMemory and NetEMemory
* classes are removed from the ivl core program, and the IVL_LPM_RAM
* lpm type is removed from the ivl_target API.
*
* Revision 1.88 2006/11/10 05:44:44 steve
* Process delay paths in second path over signals.
*

11
eval.cc
View File

@ -17,7 +17,7 @@
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#ifdef HAVE_CVS_IDENT
#ident "$Id: eval.cc,v 1.43 2006/08/08 05:11:37 steve Exp $"
#ident "$Id: eval.cc,v 1.44 2007/01/16 05:44:15 steve Exp $"
#endif
# include "config.h"
@ -174,7 +174,6 @@ verinum* PEIdent::eval_const(const Design*des, NetScope*scope) const
{
assert(scope);
NetNet*net;
NetMemory*mem;
NetEvent*eve;
const NetExpr*expr;
@ -187,7 +186,7 @@ verinum* PEIdent::eval_const(const Design*des, NetScope*scope) const
}
NetScope*found_in = symbol_search(des, scope, path_,
net, mem, expr, eve);
net, expr, eve);
if (expr == 0)
return 0;
@ -276,6 +275,12 @@ verinum* PEUnary::eval_const(const Design*des, NetScope*scope) const
/*
* $Log: eval.cc,v $
* Revision 1.44 2007/01/16 05:44:15 steve
* Major rework of array handling. Memories are replaced with the
* more general concept of arrays. The NetMemory and NetEMemory
* classes are removed from the ivl core program, and the IVL_LPM_RAM
* lpm type is removed from the ivl_target API.
*
* Revision 1.43 2006/08/08 05:11:37 steve
* Handle 64bit delay constants.
*

View File

@ -17,7 +17,7 @@
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#ifdef HAVE_CVS_IDENT
#ident "$Id: eval_tree.cc,v 1.72 2006/11/04 06:16:27 steve Exp $"
#ident "$Id: eval_tree.cc,v 1.73 2007/01/16 05:44:15 steve Exp $"
#endif
# include "config.h"
@ -1190,50 +1190,6 @@ NetEConst* NetEConcat::eval_tree()
return res;
}
/*
* There are limits to our ability to evaluate a memory reference
* expression, because the content of a memory is never
* constant. However, the index expression may be precalculated, and
* there are certain index values that do give us constant results.
*/
NetExpr* NetEMemory::eval_tree()
{
/* Attempt to evaluate the index expression to a constant, if
it is not already. */
if (idx_ && !dynamic_cast<NetEConst*>(idx_)) {
NetExpr* tmp = idx_->eval_tree();
if (tmp) {
delete idx_;
idx_ = tmp;
}
}
NetEConst*itmp = dynamic_cast<NetEConst*>(idx_);
if (itmp == 0)
return 0;
verinum ival = itmp->value();
/* If the index expression has any x or z bits, then we know
already that the expression result is a constant x. */
if (! ival.is_defined()) {
verinum xres (verinum::Vx, mem_->width(), false);
NetEConst*res = new NetEConst(xres);
return res;
}
/* If the index expression is outside the range of the memory,
then the result is a constant x. */
unsigned norm_idx = mem_->index_to_address(ival.as_long());
if (norm_idx >= mem_->count()) {
verinum xres (verinum::Vx, mem_->width(), false);
NetEConst*res = new NetEConst(xres);
return res;
}
return 0;
}
NetExpr* NetEParam::eval_tree()
{
if (des_ == 0) {
@ -1696,6 +1652,12 @@ NetEConst* NetEUReduce::eval_tree()
/*
* $Log: eval_tree.cc,v $
* Revision 1.73 2007/01/16 05:44:15 steve
* Major rework of array handling. Memories are replaced with the
* more general concept of arrays. The NetMemory and NetEMemory
* classes are removed from the ivl core program, and the IVL_LPM_RAM
* lpm type is removed from the ivl_target API.
*
* Revision 1.72 2006/11/04 06:16:27 steve
* Fix padding of constant eval of NetESelect.
*

View File

@ -17,7 +17,7 @@
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#ifdef HAVE_CVS_IDENT
#ident "$Id: expr_synth.cc,v 1.80 2006/08/08 05:11:37 steve Exp $"
#ident "$Id: expr_synth.cc,v 1.81 2007/01/16 05:44:15 steve Exp $"
#endif
# include "config.h"
@ -692,7 +692,7 @@ NetNet* NetEUReduce::synthesize(Design*des)
return osig;
}
#if 0
NetNet* NetEMemory::synthesize(Design *des)
{
NetNet*adr = idx_->synthesize(des);
@ -719,7 +719,7 @@ NetNet* NetEMemory::synthesize(Design *des)
return osig;
}
#endif
NetNet* NetESelect::synthesize(Design *des)
{
@ -890,6 +890,12 @@ NetNet* NetESignal::synthesize(Design*des)
/*
* $Log: expr_synth.cc,v $
* Revision 1.81 2007/01/16 05:44:15 steve
* Major rework of array handling. Memories are replaced with the
* more general concept of arrays. The NetMemory and NetEMemory
* classes are removed from the ivl core program, and the IVL_LPM_RAM
* lpm type is removed from the ivl_target API.
*
* Revision 1.80 2006/08/08 05:11:37 steve
* Handle 64bit delay constants.
*

View File

@ -62,6 +62,7 @@ ivl_logic_type
ivl_logic_udp
ivl_logic_width
ivl_lpm_array
ivl_lpm_aset_value
ivl_lpm_async_clr
ivl_lpm_async_set

View File

@ -19,7 +19,7 @@
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#ifdef HAVE_CVS_IDENT
#ident "$Id: ivl_target.h,v 1.171 2006/09/23 04:57:19 steve Exp $"
#ident "$Id: ivl_target.h,v 1.172 2007/01/16 05:44:15 steve Exp $"
#endif
# include <stdint.h>
@ -59,6 +59,10 @@ _BEGIN_DECL
* The following typedefs list the various cookies that may be passed
* around.
*
* ivl_array_t
* This object represent an array that can be a memory or a net
* array. (They are the same from the perspective of ivl_target.h.)
*
* ivl_design_t
* This object represents the entire elaborated design. Various
* global properties and methods are available from this.
@ -137,6 +141,7 @@ _BEGIN_DECL
* scope. These names are unique within a scope, but not necessarily
* throughout the design.
*/
typedef struct ivl_array_s *ivl_array_t;
typedef struct ivl_delaypath_s*ivl_delaypath_t;
typedef struct ivl_design_s *ivl_design_t;
typedef struct ivl_event_s *ivl_event_t;
@ -153,7 +158,7 @@ typedef struct ivl_parameter_s*ivl_parameter_t;
typedef struct ivl_process_s *ivl_process_t;
typedef struct ivl_scope_s *ivl_scope_t;
typedef struct ivl_signal_s *ivl_signal_t;
typedef struct ivl_memory_s *ivl_memory_t;
typedef struct ivl_memory_s *ivl_memory_t; /* DEPRECATED */
typedef struct ivl_statement_s*ivl_statement_t;
/*
@ -178,7 +183,7 @@ typedef enum ivl_drive_e {
and incompatibilities to be introduced. */
typedef enum ivl_expr_type_e {
IVL_EX_NONE = 0,
/* IVL_EX_BITSEL = 1, */
IVL_EX_ARRAY = 18,
IVL_EX_BINARY = 2,
IVL_EX_CONCAT = 3,
IVL_EX_EVENT = 17,
@ -225,6 +230,7 @@ typedef enum ivl_logic_e {
/* This is the type of an LPM object. */
typedef enum ivl_lpm_type_e {
IVL_LPM_ADD = 0,
IVL_LPM_ARRAY = 30,
IVL_LPM_CONCAT = 16,
IVL_LPM_CMP_EEQ= 18, /* Case EQ (===) */
IVL_LPM_CMP_EQ = 10,
@ -252,7 +258,7 @@ typedef enum ivl_lpm_type_e {
IVL_LPM_SHIFTR = 7,
IVL_LPM_SIGN_EXT=27,
IVL_LPM_SUB = 8,
IVL_LPM_RAM = 9,
_IVL_LPM_RAM = 9, /* obsolete */
IVL_LPM_UFUNC = 14
} ivl_lpm_type_t;
@ -574,6 +580,14 @@ extern ivl_nexus_t ivl_event_pos(ivl_event_t net, unsigned idx);
*
* SEMANTIC NOTES
*
* - IVL_EX_ARRAY
* This expression type is a special case of the IVL_EX_SIGNAL where
* the target is an array (ivl_signal_t with an array_count) but there
* is no index expression. This is used only in the special situation
* where the array is passed to a system task/function. The function
* ivl_expr_signal returns the ivl_signal_t of the array object, and
* from that all the properties of the array can be determined.
*
* - IVL_EX_BINARY
*
* - IVL_EX_SELECT
@ -583,6 +597,21 @@ extern ivl_nexus_t ivl_event_pos(ivl_event_t net, unsigned idx);
* is the base of a vector. The compiler has already figured out any
* conversion from signal units to vector units, so the result of
* ivl_expr_oper1 should range from 0 to ivl_expr_width().
*
* - IVL_EX_SIGNAL
* This expression references a signal vector. The ivl_expr_signal
* function gets a handle for the signal that is referenced. The
* signal may be an array (see the ivl_signal_array_count function)
* that is addressed by the expression returned by the ivl_expr_oper1
* function. This expression returns a *canonical* address. The core
* compiler already corrected the expression to account for index
* bases.
*
* The ivl_expr_width function returns the vector width of the signal
* word. The ivl_expr_value returns the data type of the word.
*
* Bit and part selects are not done here. The IVL_EX_SELECT
* expression does bit/part selects on the word read from the signal.
*/
extern ivl_expr_type_t ivl_expr_type(ivl_expr_t net);
@ -975,7 +1004,7 @@ extern const char* ivl_udp_name(ivl_udp_t net);
* single ivl_lpm_data input are the same with, ivl_lpm_width. This
* device carries a vector like other LPM devices.
*
* - Memory port (IVL_LPM_RAM)
* - Memory port (IVL_LPM_RAM) (deprecated in favor of IVL_LPM_ARRAY)
* These are structural ports into a memory device. They represent
* address/data ports of a memory device that the context can hook to
* for read or write. Read devices have an ivl_lpm_q output port that
@ -1069,34 +1098,33 @@ extern ivl_expr_t ivl_lpm_aset_value(ivl_lpm_t net);
extern ivl_nexus_t ivl_lpm_sync_clr(ivl_lpm_t net);
extern ivl_nexus_t ivl_lpm_sync_set(ivl_lpm_t net);
extern ivl_expr_t ivl_lpm_sset_value(ivl_lpm_t net);
/* IVL_LPM_ARRAY */
extern ivl_signal_t ivl_lpm_array(ivl_lpm_t net);
/* IVL_LPM_PART */
extern unsigned ivl_lpm_base(ivl_lpm_t net);
/* IVL_LPM_FF IVL_LPM_RAM */
/* IVL_LPM_FF */
extern ivl_nexus_t ivl_lpm_clk(ivl_lpm_t net);
/* IVL_LPM_UFUNC */
extern ivl_scope_t ivl_lpm_define(ivl_lpm_t net);
/* IVL_LPM_FF IVL_LPM_RAM */
/* IVL_LPM_FF */
extern ivl_nexus_t ivl_lpm_enable(ivl_lpm_t net);
/* IVL_LPM_ADD IVL_LPM_CONCAT IVL_LPM_FF IVL_LPM_PART IVL_LPM_MULT
IVL_LPM_MUX IVL_LPM_RAM IVL_LPM_SHIFTL IVL_LPM_SHIFTR IVL_LPM_SUB
IVL_LPM_MUX IVL_LPM_SHIFTL IVL_LPM_SHIFTR IVL_LPM_SUB
IVL_LPM_UFUNC */
extern ivl_nexus_t ivl_lpm_data(ivl_lpm_t net, unsigned idx);
/* IVL_LPM_ADD IVL_LPM_MULT IVL_LPM_SUB */
extern ivl_nexus_t ivl_lpm_datab(ivl_lpm_t net, unsigned idx);
/* IVL_LPM_ADD IVL_LPM_FF IVL_LPM_MULT IVL_LPM_PART IVL_LPM_RAM
/* IVL_LPM_ADD IVL_LPM_FF IVL_LPM_MULT IVL_LPM_PART
IVL_LPM_SUB IVL_LPM_UFUNC */
extern ivl_nexus_t ivl_lpm_q(ivl_lpm_t net, unsigned idx);
/* IVL_LPM_MUX IVL_LPM_RAM */
/* IVL_LPM_MUX */
extern unsigned ivl_lpm_selects(ivl_lpm_t net);
/* IVL_LPM_MUX IVL_LPM_RAM */
/* IVL_LPM_MUX */
extern ivl_nexus_t ivl_lpm_select(ivl_lpm_t net);
/* IVL_LPM_CONCAT IVL_LPM_MUX IVL_LPM_REPEAT IVL_LPM_UFUNC */
extern unsigned ivl_lpm_size(ivl_lpm_t net);
/* IVL_LPM_SFUNC */
extern const char*ivl_lpm_string(ivl_lpm_t net);
/* IVL_LPM_RAM */
extern ivl_memory_t ivl_lpm_memory(ivl_lpm_t net);
/* LVAL
* The l-values of assignments are concatenation of ivl_lval_t
@ -1149,12 +1177,21 @@ extern ivl_memory_t ivl_lpm_memory(ivl_lpm_t net);
* The ivl_lval_part_off is the canonical base of a part or
* bit select.
*
* - Memory words
* - Memory words (Replace this with Array words below)
* If the l-value is a memory word, the ivl_lval_mem function returns
* a non-nil value. The ivl_lval_idx function will return an
* expression that calculates an address for the memory. The compiler
* will assure that the ivl_lval_width will exactly match the
* ivl_memory_width of the memory word.
*
* - Array words
* If the l-value is an array, then ivl_lval_idx function will return
* an expression that calculates the address of the array word. If
* the referenced signal has more then one word, this expression must
* be present. If the signal has exactly one word (it is not an array)
* then the ivl_lval_idx exression must *not* be present.
*
* For array words, the ivl_lval_width is the width of the word.
*/
extern unsigned ivl_lval_width(ivl_lval_t net);
@ -1432,17 +1469,22 @@ extern int ivl_scope_time_units(ivl_scope_t net);
* Signals have a name (obviously) and types. A signal may also be
* signed or unsigned.
*
* ivl_signal_pins (replace these with ivl_signal_nex)
* ivl_signal_pin
* The ivl_signal_pin function returns the nexus connected to the
* signal. If the signal is a vector, the idx can be a non-zero
* value, and the result is the nexus for the specified bit.
*
* ivl_signal_nex
* This is the nexus of the signal. This is used for managing
* connections to the rest of the net. There is exactly one pin for
* a signal. If the signal represents a vector, then the entire
* vector is carried through the single output.
* each word of a signal. Each word may in turn be a vector. The
* word address is the zero-based index for the word. It is up to
* the context to translate different bases to the canonical address.
*
* ivl_signal_array_base
* ivl_signal_array_count
* The signal may be arrayed. If so, the array_count is >1. Each
* word of the array has its own nexus. The array_base is the
* address is the Verilg source for the canonical zero word. This
* may be negative, positive or zero.
*
* Note that arraying of the signal into words is distinct from the
* vectors. The width of a signal is the width of a WORD.
*
* ivl_signal_msb
* ivl_signal_lsb
@ -1503,7 +1545,9 @@ extern int ivl_scope_time_units(ivl_scope_t net);
* key does not exist, the function returns 0.
*/
extern ivl_nexus_t ivl_signal_nex(ivl_signal_t net);
extern ivl_nexus_t ivl_signal_nex(ivl_signal_t net, unsigned word);
extern int ivl_signal_array_base(ivl_signal_t net);
extern unsigned ivl_signal_array_count(ivl_signal_t net);
extern int ivl_signal_msb(ivl_signal_t net);
extern int ivl_signal_lsb(ivl_signal_t net);
extern unsigned ivl_signal_width(ivl_signal_t net);
@ -1706,10 +1750,6 @@ extern unsigned ivl_stmt_lvals(ivl_statement_t net);
extern unsigned ivl_stmt_lwidth(ivl_statement_t net);
/* IVL_ST_STASK */
extern const char* ivl_stmt_name(ivl_statement_t net);
#if 0
extern ivl_nexus_t ivl_stmt_nexus(ivl_statement_t net, unsigned idx);
extern unsigned ivl_stmt_nexus_count(ivl_statement_t net);
#endif
/* IVL_ST_STASK */
extern ivl_expr_t ivl_stmt_parm(ivl_statement_t net, unsigned idx);
/* IVL_ST_STASK */
@ -1752,6 +1792,12 @@ _END_DECL
/*
* $Log: ivl_target.h,v $
* Revision 1.172 2007/01/16 05:44:15 steve
* Major rework of array handling. Memories are replaced with the
* more general concept of arrays. The NetMemory and NetEMemory
* classes are removed from the ivl core program, and the IVL_LPM_RAM
* lpm type is removed from the ivl_target API.
*
* Revision 1.171 2006/09/23 04:57:19 steve
* Basic support for specify timing.
*
@ -1781,181 +1827,5 @@ _END_DECL
*
* Revision 1.162 2005/11/20 15:58:25 steve
* Document the IVL_ST_DELAY statements.
*
* Revision 1.161 2005/09/19 21:45:35 steve
* Spelling patches from Larry.
*
* Revision 1.160 2005/09/01 04:11:37 steve
* Generate code to handle real valued muxes.
*
* Revision 1.159 2005/08/06 17:58:16 steve
* Implement bi-directional part selects.
*
* Revision 1.158 2005/07/11 16:56:50 steve
* Remove NetVariable and ivl_variable_t structures.
*
* Revision 1.157 2005/07/07 16:22:49 steve
* Generalize signals to carry types.
*
* Revision 1.156 2005/06/13 22:25:37 steve
* Document ivl_logic_delay function.
*
* Revision 1.155 2005/05/24 01:44:28 steve
* Do sign extension of structuran nets.
*
* Revision 1.154 2005/05/08 23:44:08 steve
* Add support for variable part select.
*
* Revision 1.153 2005/05/07 03:14:00 steve
* Clarify internal delays for assignments.
*
* Revision 1.152 2005/04/24 23:44:02 steve
* Update DFF support to new data flow.
*
* Revision 1.151 2005/04/13 06:35:11 steve
* Make logic aware of strength.
*
* Revision 1.150 2005/04/08 04:52:31 steve
* Make clear that memory addresses are cannonical.
*
* Revision 1.149 2005/04/06 05:29:08 steve
* Rework NetRamDq and IVL_LPM_RAM nodes.
*
* Revision 1.148 2005/04/01 06:04:30 steve
* Clean up handle of UDPs.
*
* Revision 1.147 2005/03/18 02:56:03 steve
* Add support for LPM_UFUNC user defined functions.
*
* Revision 1.146 2005/03/09 04:53:40 steve
* Generate code for new form of memory ports.
*
* Revision 1.145 2005/03/05 05:47:42 steve
* Handle memory words in l-value concatenations.
*
* Revision 1.144 2005/03/03 04:34:42 steve
* Rearrange how memories are supported as vvp_vector4 arrays.
*
* Revision 1.143 2005/02/19 02:43:38 steve
* Support shifts and divide.
*
* Revision 1.142 2005/02/14 01:51:39 steve
* Handle bit selects in l-values to assignments.
*
* Revision 1.141 2005/02/13 01:15:07 steve
* Replace supply nets with wires connected to pullup/down supply devices.
*
* Revision 1.140 2005/02/12 06:25:40 steve
* Restructure NetMux devices to pass vectors.
* Generate NetMux devices from ternary expressions,
* Reduce NetMux devices to bufif when appropriate.
*
* Revision 1.139 2005/02/08 00:12:36 steve
* Add the NetRepeat node, and code generator support.
*
* Revision 1.138 2005/02/03 04:56:20 steve
* laborate reduction gates into LPM_RED_ nodes.
*
* Revision 1.137 2005/01/29 18:46:18 steve
* Netlist boolean expressions generate gate vectors.
*
* Revision 1.136 2005/01/29 16:47:20 steve
* Clarify width of nexus.
*
* Revision 1.135 2005/01/28 05:39:33 steve
* Simplified NetMult and IVL_LPM_MULT.
*
* Revision 1.134 2005/01/24 05:28:30 steve
* Remove the NetEBitSel and combine all bit/part select
* behavior into the NetESelect node and IVL_EX_SELECT
* ivl_target expression type.
*
* Revision 1.133 2005/01/22 17:36:59 steve
* stub dump signed flags of magnitude compare.
*
* Revision 1.132 2005/01/22 01:06:55 steve
* Change case compare from logic to an LPM node.
*
* Revision 1.131 2005/01/09 20:16:01 steve
* Use PartSelect/PV and VP to handle part selects through ports.
*
* Revision 1.130 2004/12/29 23:55:43 steve
* Unify elaboration of l-values for all proceedural assignments,
* including assing, cassign and force.
*
* Generate NetConcat devices for gate outputs that feed into a
* vector results. Use this to hande gate arrays. Also let gate
* arrays handle vectors of gates when the outputs allow for it.
*
* Revision 1.129 2004/12/18 18:56:18 steve
* Add ivl_event_scope, and better document ivl_event_X methods.
*
* Revision 1.128 2004/12/15 17:10:40 steve
* Fixup force statement elaboration.
*
* Revision 1.127 2004/12/11 02:31:26 steve
* Rework of internals to carry vectors through nexus instead
* of single bits. Make the ivl, tgt-vvp and vvp initial changes
* down this path.
*
* Revision 1.126 2004/10/04 01:10:53 steve
* Clean up spurious trailing white space.
*
* Revision 1.125 2004/09/25 01:58:12 steve
* Some commentary on ivl_logic_pin.
*
* Revision 1.124 2003/12/03 02:46:24 steve
* Add support for wait on list of named events.
*
* Revision 1.123 2003/11/08 20:06:21 steve
* Spelling fixes in comments.
*
* Revision 1.122 2003/08/22 23:14:26 steve
* Preserve variable ranges all the way to the vpi.
*
* Revision 1.121 2003/08/15 02:23:52 steve
* Add synthesis support for synchronous reset.
*
* Revision 1.120 2003/07/30 01:13:28 steve
* Add support for triand and trior.
*
* Revision 1.119 2003/06/23 01:25:44 steve
* Module attributes make it al the way to ivl_target.
*
* Revision 1.118 2003/05/14 05:26:41 steve
* Support real expressions in case statements.
*
* Revision 1.117 2003/04/22 04:48:29 steve
* Support event names as expressions elements.
*
* Revision 1.116 2003/04/11 05:18:08 steve
* Handle signed magnitude compare all the
* way through to the vvp code generator.
*
* Revision 1.115 2003/03/10 23:40:53 steve
* Keep parameter constants for the ivl_target API.
*
* Revision 1.114 2003/03/06 01:24:37 steve
* Obsolete the ivl_event_name function.
*
* Revision 1.113 2003/03/06 00:28:41 steve
* All NetObj objects have lex_string base names.
*
* Revision 1.112 2003/02/26 01:29:24 steve
* LPM objects store only their base names.
*
* Revision 1.111 2003/01/30 16:23:07 steve
* Spelling fixes.
*
* Revision 1.110 2003/01/26 21:15:58 steve
* Rework expression parsing and elaboration to
* accommodate real/realtime values and expressions.
*
* Revision 1.109 2002/12/21 00:55:58 steve
* The $time system task returns the integer time
* scaled to the local units. Change the internal
* implementation of vpiSystemTime the $time functions
* to properly account for this. Also add $simtime
* to get the simulation time.
*/
#endif

View File

@ -17,7 +17,7 @@
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#ifdef HAVE_CVS_IDENT
#ident "$Id: net_assign.cc,v 1.21 2006/02/02 02:43:58 steve Exp $"
#ident "$Id: net_assign.cc,v 1.22 2007/01/16 05:44:15 steve Exp $"
#endif
# include "config.h"
@ -39,20 +39,13 @@ unsigned count_lval_width(const NetAssign_*idx)
}
NetAssign_::NetAssign_(NetNet*s)
: sig_(s), mem_(0), bmux_(0), base_(0)
: sig_(s), word_(0), base_(0)
{
lwid_ = sig_->vector_width();
sig_->incr_lref();
more = 0;
}
NetAssign_::NetAssign_(NetMemory*s)
: sig_(0), mem_(s), bmux_(0), base_(0)
{
lwid_ = mem_->width();
more = 0;
}
NetAssign_::~NetAssign_()
{
if (sig_) {
@ -62,23 +55,23 @@ NetAssign_::~NetAssign_()
}
assert( more == 0 );
if (bmux_) delete bmux_;
if (word_) delete word_;
}
void NetAssign_::set_bmux(NetExpr*r)
void NetAssign_::set_word(NetExpr*r)
{
assert(bmux_ == 0);
bmux_ = r;
assert(word_ == 0);
word_ = r;
}
NetExpr* NetAssign_::bmux()
NetExpr* NetAssign_::word()
{
return bmux_;
return word_;
}
const NetExpr* NetAssign_::bmux() const
const NetExpr* NetAssign_::word() const
{
return bmux_;
return word_;
}
const NetExpr* NetAssign_::get_base() const
@ -88,17 +81,13 @@ const NetExpr* NetAssign_::get_base() const
unsigned NetAssign_::lwidth() const
{
if (mem_) return lwid_;
else if (bmux_) return 1;
else return lwid_;
return lwid_;
}
perm_string NetAssign_::name() const
{
if (sig_) {
return sig_->name();
} else if (mem_) {
return mem_->name();
} else {
return perm_string::literal("");
}
@ -109,11 +98,6 @@ NetNet* NetAssign_::sig() const
return sig_;
}
NetMemory* NetAssign_::mem() const
{
return mem_;
}
void NetAssign_::set_part(NetExpr*base, unsigned wid)
{
base_ = base;
@ -275,6 +259,12 @@ NetRelease::~NetRelease()
/*
* $Log: net_assign.cc,v $
* Revision 1.22 2007/01/16 05:44:15 steve
* Major rework of array handling. Memories are replaced with the
* more general concept of arrays. The NetMemory and NetEMemory
* classes are removed from the ivl core program, and the IVL_LPM_RAM
* lpm type is removed from the ivl_target API.
*
* Revision 1.21 2006/02/02 02:43:58 steve
* Allow part selects of memory words in l-values.
*

View File

@ -17,7 +17,7 @@
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#ifdef HAVE_CVS_IDENT
#ident "$Id: net_nex_input.cc,v 1.15 2006/04/16 00:15:43 steve Exp $"
#ident "$Id: net_nex_input.cc,v 1.16 2007/01/16 05:44:15 steve Exp $"
#endif
# include "config.h"
@ -78,12 +78,6 @@ NexusSet* NetECReal::nex_input()
return new NexusSet;
}
NexusSet* NetEMemory::nex_input()
{
NexusSet*result = idx_->nex_input();
return result;
}
/*
* A parameter by definition has no inputs. It represents a constant
* value, even if that value is a constant expression.
@ -171,8 +165,8 @@ NexusSet* NetEUnary::nex_input()
NexusSet* NetAssign_::nex_input()
{
NexusSet*result = new NexusSet;
if (bmux_) {
NexusSet*tmp = bmux_->nex_input();
if (word_) {
NexusSet*tmp = word_->nex_input();
result->add(*tmp);
delete tmp;
}
@ -393,6 +387,12 @@ NexusSet* NetWhile::nex_input()
/*
* $Log: net_nex_input.cc,v $
* Revision 1.16 2007/01/16 05:44:15 steve
* Major rework of array handling. Memories are replaced with the
* more general concept of arrays. The NetMemory and NetEMemory
* classes are removed from the ivl core program, and the IVL_LPM_RAM
* lpm type is removed from the ivl_target API.
*
* Revision 1.15 2006/04/16 00:15:43 steve
* Fix part selects in l-values.
*

View File

@ -17,7 +17,7 @@
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#ifdef HAVE_CVS_IDENT
#ident "$Id: net_scope.cc,v 1.35 2005/11/27 05:56:20 steve Exp $"
#ident "$Id: net_scope.cc,v 1.36 2007/01/16 05:44:15 steve Exp $"
#endif
# include "config.h"
@ -38,7 +38,6 @@
NetScope::NetScope(NetScope*up, perm_string n, NetScope::TYPE t)
: type_(t), up_(up), sib_(0), sub_(0)
{
memories_ = 0;
signals_ = 0;
events_ = 0;
lcounter_ = 0;
@ -358,50 +357,6 @@ NetNet* NetScope::find_signal_in_child(const hname_t&path)
return cur->find_signal(path.peek_name(idx));
}
void NetScope::add_memory(NetMemory*mem)
{
if (memories_ == 0) {
mem->snext_ = mem;
mem->sprev_ = mem;
} else {
mem->snext_ = memories_->snext_;
mem->sprev_ = memories_;
mem->snext_->sprev_ = mem;
mem->sprev_->snext_ = mem;
}
memories_ = mem;
mem->scope_ = this;
}
void NetScope::rem_memory(NetMemory*mem)
{
assert(mem->scope_ == this);
if (memories_ == mem)
memories_ = mem->sprev_;
if (memories_ == mem) {
memories_ = 0;
} else {
mem->sprev_->snext_ = mem->snext_;
mem->snext_->sprev_ = mem->sprev_;
}
mem->scope_ = 0;
}
NetMemory* NetScope::find_memory(const string&key)
{
if (memories_ == 0)
return 0;
NetMemory*cur = memories_;
do {
if (cur->name() == key.c_str())
return cur;
cur = cur->sprev_;
} while (cur != memories_);
return 0;
}
/*
* This method locates a child scope by name. The name is the simple
* name of the child, no hierarchy is searched.
@ -457,6 +412,12 @@ string NetScope::local_hsymbol()
/*
* $Log: net_scope.cc,v $
* Revision 1.36 2007/01/16 05:44:15 steve
* Major rework of array handling. Memories are replaced with the
* more general concept of arrays. The NetMemory and NetEMemory
* classes are removed from the ivl core program, and the IVL_LPM_RAM
* lpm type is removed from the ivl_target API.
*
* Revision 1.35 2005/11/27 05:56:20 steve
* Handle bit select of parameter with ranges.
*

View File

@ -17,7 +17,7 @@
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#ifdef HAVE_CVS_IDENT
#ident "$Id: netlist.cc,v 1.250 2006/11/10 04:54:26 steve Exp $"
#ident "$Id: netlist.cc,v 1.251 2007/01/16 05:44:15 steve Exp $"
#endif
# include "config.h"
@ -333,7 +333,7 @@ uint64_t NetDelaySrc::get_delay(unsigned idx) const
NetNet::NetNet(NetScope*s, perm_string n, Type t, unsigned npins)
: NetObj(s, n, 1), sig_next_(0), sig_prev_(0),
type_(t), port_type_(NOT_A_PORT), data_type_(IVL_VT_NO_TYPE),
signed_(false), msb_(npins-1), lsb_(0),
signed_(false), msb_(npins-1), lsb_(0), s0_(0), e0_(0),
local_flag_(false), eref_count_(0), lref_count_(0)
{
assert(s);
@ -367,11 +367,20 @@ NetNet::NetNet(NetScope*s, perm_string n, Type t, unsigned npins)
s->add_signal(this);
}
NetNet::NetNet(NetScope*s, perm_string n, Type t, long ms, long ls)
: NetObj(s, n, 1),
static unsigned calculate_count(long s, long e)
{
if (s >= e)
return s - e + 1;
else
return e - s + 1;
}
NetNet::NetNet(NetScope*s, perm_string n, Type t,
long ms, long ls, long array_s, long array_e)
: NetObj(s, n, calculate_count(array_s, array_e)),
sig_next_(0), sig_prev_(0), type_(t),
port_type_(NOT_A_PORT), data_type_(IVL_VT_NO_TYPE), signed_(false),
msb_(ms), lsb_(ls),
msb_(ms), lsb_(ls), s0_(array_s), e0_(array_e),
local_flag_(false), eref_count_(0), lref_count_(0)
{
assert(s);
@ -533,6 +542,43 @@ unsigned NetNet::sb_to_idx(long sb) const
return lsb_ - sb;
}
unsigned NetNet::array_dimensions() const
{
if (s0_ == e0_)
return 0;
return 1;
}
long NetNet::array_first() const
{
if (s0_ < e0_)
return s0_;
else
return e0_;
}
unsigned NetNet::array_count() const
{
return calculate_count(s0_, e0_);
}
bool NetNet::array_index_is_valid(long sb) const
{
if (sb < s0_ && sb < e0_)
return false;
if (sb > e0_ && sb > s0_)
return false;
return true;
}
unsigned NetNet::array_index_to_address(long sb) const
{
if (s0_ <= e0_)
return sb - s0_;
else
return sb - e0_;
}
void NetNet::incr_eref()
{
eref_count_ += 1;
@ -973,6 +1019,55 @@ const Link& NetAddSub::pin_Result() const
return pin(8);
}
NetArrayDq::NetArrayDq(NetScope*s, perm_string n, NetNet*mem, unsigned awid)
: NetNode(s, n, 2),
mem_(mem), awidth_(awid)
{
pin(0).set_dir(Link::OUTPUT);
pin(0).set_name(perm_string::literal("Result"), 0);
pin(1).set_dir(Link::INPUT);
pin(1).set_name(perm_string::literal("Address"), 0);
}
NetArrayDq::~NetArrayDq()
{
}
unsigned NetArrayDq::width() const
{
return mem_->vector_width();
}
unsigned NetArrayDq::awidth() const
{
return awidth_;
}
const NetNet* NetArrayDq::mem() const
{
return mem_;
}
Link& NetArrayDq::pin_Result()
{
return pin(0);
}
Link& NetArrayDq::pin_Address()
{
return pin(1);
}
const Link& NetArrayDq::pin_Result() const
{
return pin(0);
}
const Link& NetArrayDq::pin_Address() const
{
return pin(1);
}
/*
* The pinout for the NetCLShift is:
* 0 -- Result
@ -1428,190 +1523,6 @@ const Link& NetMux::pin_Data(unsigned s) const
return pin(2+s);
}
NetRamDq::NetRamDq(NetScope*s, perm_string n, NetMemory*mem, unsigned awid)
: NetNode(s, n, 6),
mem_(mem), awidth_(awid)
{
pin(0).set_dir(Link::INPUT);
pin(0).set_name(perm_string::literal("InClock"), 0);
pin(1).set_dir(Link::INPUT);
pin(1).set_name(perm_string::literal("OutClock"), 0);
pin(2).set_dir(Link::INPUT);
pin(2).set_name(perm_string::literal("WE"), 0);
pin(3).set_dir(Link::INPUT);
pin(3).set_name(perm_string::literal("Address"), 0);
pin(4).set_dir(Link::INPUT);
pin(4).set_name(perm_string::literal("Data"), 0);
pin(5).set_dir(Link::OUTPUT);
pin(5).set_name(perm_string::literal("Q"), 0);
next_ = mem_->ram_list_;
mem_->ram_list_ = this;
}
NetRamDq::~NetRamDq()
{
if (mem_->ram_list_ == this) {
mem_->ram_list_ = next_;
} else {
NetRamDq*cur = mem_->ram_list_;
while (cur->next_ != this) {
assert(cur->next_);
cur = cur->next_;
}
assert(cur->next_ == this);
cur->next_ = next_;
}
}
unsigned NetRamDq::width() const
{
return mem_->width();
}
unsigned NetRamDq::awidth() const
{
return awidth_;
}
unsigned NetRamDq::size() const
{
return mem_->count();
}
const NetMemory* NetRamDq::mem() const
{
return mem_;
}
unsigned NetRamDq::count_partners() const
{
unsigned count = 0;
for (NetRamDq*cur = mem_->ram_list_ ; cur ; cur = cur->next_)
count += 1;
return count;
}
void NetRamDq::absorb_partners()
{
NetRamDq*cur, *tmp;
for (cur = mem_->ram_list_, tmp = 0
; cur||tmp ; cur = cur? cur->next_ : tmp) {
tmp = 0;
if (cur == this) continue;
bool ok_flag = true;
ok_flag &= pin_Address().is_linked(cur->pin_Address());
if (!ok_flag) continue;
if (pin_InClock().is_linked()
&& cur->pin_InClock().is_linked()
&& ! pin_InClock().is_linked(cur->pin_InClock()))
continue;
if (pin_OutClock().is_linked()
&& cur->pin_OutClock().is_linked()
&& ! pin_OutClock().is_linked(cur->pin_OutClock()))
continue;
if (pin_WE().is_linked()
&& cur->pin_WE().is_linked()
&& ! pin_WE().is_linked(cur->pin_WE()))
continue;
if (pin_Data().is_linked() && cur->pin_Data().is_linked()) {
ok_flag &= pin_Data().is_linked(cur->pin_Data());
}
if (! ok_flag) continue;
if (pin_Q().is_linked() && cur->pin_Q().is_linked()) {
ok_flag &= pin_Q().is_linked(cur->pin_Q());
}
if (! ok_flag) continue;
// I see no other reason to reject cur, so link up all
// my pins and delete it.
connect(pin_InClock(), cur->pin_InClock());
connect(pin_OutClock(), cur->pin_OutClock());
connect(pin_WE(), cur->pin_WE());
connect(pin_Address(), cur->pin_Address());
connect(pin_Data(), cur->pin_Data());
connect(pin_Q(), cur->pin_Q());
tmp = cur->next_;
delete cur;
cur = 0;
}
}
Link& NetRamDq::pin_InClock()
{
return pin(0);
}
const Link& NetRamDq::pin_InClock() const
{
return pin(0);
}
Link& NetRamDq::pin_OutClock()
{
return pin(1);
}
const Link& NetRamDq::pin_OutClock() const
{
return pin(1);
}
Link& NetRamDq::pin_WE()
{
return pin(2);
}
const Link& NetRamDq::pin_WE() const
{
return pin(2);
}
Link& NetRamDq::pin_Address()
{
return pin(3);
}
const Link& NetRamDq::pin_Address() const
{
return pin(3);
}
Link& NetRamDq::pin_Data()
{
return pin(4);
}
const Link& NetRamDq::pin_Data() const
{
return pin(4);
}
Link& NetRamDq::pin_Q()
{
return pin(5);
}
const Link& NetRamDq::pin_Q() const
{
return pin(5);
}
NetSignExtend::NetSignExtend(NetScope*s, perm_string n, unsigned w)
: NetNode(s, n, 2), width_(w)
{
@ -2027,68 +1938,6 @@ const NetScope* NetEConstParam::scope() const
return scope_;
}
NetEMemory::NetEMemory(NetMemory*m, NetExpr*i)
: NetExpr(m->width()), mem_(m), idx_(i)
{
}
NetEMemory::~NetEMemory()
{
}
perm_string NetEMemory::name() const
{
return mem_->name();
}
const NetExpr* NetEMemory::index() const
{
return idx_;
}
NetMemory::NetMemory(NetScope*sc, perm_string n, long w, long s, long e)
: width_(w), idxh_(s), idxl_(e), ram_list_(0), scope_(sc)
{
name_ = n;
scope_->add_memory(this);
}
NetMemory::~NetMemory()
{
assert(scope_);
scope_->rem_memory(this);
}
unsigned NetMemory::count() const
{
if (idxh_ < idxl_)
return idxl_ - idxh_ + 1;
else
return idxh_ - idxl_ + 1;
}
perm_string NetMemory::name() const
{
return name_;
}
long NetMemory::index_to_address(long idx) const
{
if (idxh_ < idxl_)
return idx - idxh_;
else
return idx - idxl_;
}
NetEMemory* NetEMemory::dup_expr() const
{
assert(0);
return 0;
}
NetEEvent::NetEEvent(NetEvent*e)
: event_(e)
{
@ -2119,25 +1968,20 @@ const NetScope* NetEScope::scope() const
}
NetESignal::NetESignal(NetNet*n)
: NetExpr(n->vector_width()), net_(n)
: NetExpr(n->vector_width()), net_(n), word_(0)
{
net_->incr_eref();
set_line(*n);
cast_signed(net_->get_signed());
}
#if 0
NetESignal::NetESignal(NetNet*n, unsigned m, unsigned l)
: NetExpr(m - l + 1), net_(n)
NetESignal::NetESignal(NetNet*n, NetExpr*w)
: NetExpr(n->vector_width()), net_(n), word_(w)
{
assert(m >= l);
msi_ = m;
lsi_ = l;
net_->incr_eref();
set_line(*n);
cast_signed(net_->get_signed());
}
#endif
NetESignal::~NetESignal()
{
@ -2149,18 +1993,22 @@ perm_string NetESignal::name() const
return net_->name();
}
unsigned NetESignal::bit_count() const
const NetExpr* NetESignal::word_index() const
{
return word_;
}
unsigned NetESignal::vector_width() const
{
return net_->vector_width();
}
Link& NetESignal::bit(unsigned idx)
const NetNet* NetESignal::sig() const
{
assert(idx <= 0);
return net_->pin(idx);
return net_;
}
const NetNet* NetESignal::sig() const
NetNet* NetESignal::sig()
{
return net_;
}
@ -2342,6 +2190,12 @@ const NetProc*NetTaskDef::proc() const
/*
* $Log: netlist.cc,v $
* Revision 1.251 2007/01/16 05:44:15 steve
* Major rework of array handling. Memories are replaced with the
* more general concept of arrays. The NetMemory and NetEMemory
* classes are removed from the ivl core program, and the IVL_LPM_RAM
* lpm type is removed from the ivl_target API.
*
* Revision 1.250 2006/11/10 04:54:26 steve
* Add test_width methods for PETernary and PEString.
*

253
netlist.h
View File

@ -19,7 +19,7 @@
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#ifdef HAVE_CVS_IDENT
#ident "$Id: netlist.h,v 1.365 2006/11/04 06:19:25 steve Exp $"
#ident "$Id: netlist.h,v 1.366 2007/01/16 05:44:15 steve Exp $"
#endif
/*
@ -447,7 +447,12 @@ class NetNet : public NetObj {
// that passed through.
explicit NetNet(NetScope*s, perm_string n, Type t, unsigned width =1);
explicit NetNet(NetScope*s, perm_string n, Type t, long ms, long ls);
// This form supports an array of vectors. The [ms:ls] define
// the base vector, and the [s0:e0] define the array
// 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, long s0 =0, long e0 =0);
virtual ~NetNet();
@ -488,6 +493,21 @@ class NetNet : public NetObj {
the pin# from the index. */
bool sb_is_valid(long sb) const;
/* This method returns 0 for scalers and vectors, and greater
for arrays. The value is the number of array
indices. (Currently only one array index is supported.) */
unsigned array_dimensions() const;
long array_first() const;
// This is the number of array elements.
unsigned array_count() const;
// This method returns a 0 based address of an array entry as
// indexed by idx. The Verilog source may give index ranges
// that are not zero based.
bool array_index_is_valid(long idx) const;
unsigned array_index_to_address(long idx) const;
bool local_flag() const { return local_flag_; }
void local_flag(bool f) { local_flag_ = f; }
@ -524,6 +544,7 @@ class NetNet : public NetObj {
bool isint_; // original type of integer
long msb_, lsb_;
long s0_, e0_;
bool local_flag_;
unsigned eref_count_;
@ -571,6 +592,37 @@ class NetAddSub : public NetNode {
unsigned width_;
};
/*
* The NetArrayDq node represents an array dereference. The NetNet
* that this object refers to is an array, and the Address pin selects
* which word of the array to place on the Result.
*/
class NetArrayDq : public NetNode {
public:
NetArrayDq(NetScope*s, perm_string name, NetNet*mem, unsigned awid);
~NetArrayDq();
unsigned width() const;
unsigned awidth() const;
unsigned size() const;
const NetNet*mem() const;
Link& pin_Address();
Link& pin_Result();
const Link& pin_Address() const;
const Link& pin_Result() const;
virtual void dump_node(ostream&, unsigned ind) const;
virtual bool emit_node(struct target_t*) const;
private:
NetNet*mem_;
unsigned awidth_;
};
/*
* This type represents the LPM_CLSHIFT device.
*/
@ -819,62 +871,6 @@ class NetFF : public NetNode {
verinum sset_value_;
};
/*
* This class represents the declared memory object. The parser
* creates one of these for each declared memory in the elaborated
* design. A reference to one of these is handled by the NetEMemory
* object, which is derived from NetExpr. This is not a node because
* memory objects can only be accessed by behavioral code.
*/
class NetMemory {
public:
NetMemory(NetScope*sc, perm_string n, long w, long s, long e);
~NetMemory();
// This is the BASE name of the memory object. It does not
// include scope name, get that from the scope itself.
perm_string name() const;
// This is the width (in bits) of a single memory position.
unsigned width() const { return width_; }
// This is the number of dimensions for the memory. A baseline
// verilog memory has always 1 dimension, but N-dimensional
// arrays have N.
unsigned dimensions() const { return 1; }
const NetScope*scope() const { return scope_; };
// This is the number of memory positions.
unsigned count() const;
// This method returns a 0 based address of a memory entry as
// indexed by idx. The Verilog source may give index ranges
// that are not zero based.
long index_to_address(long idx) const;
void dump(ostream&o, unsigned lm) const;
private:
perm_string name_;
unsigned width_;
long idxh_;
long idxl_;
friend class NetRamDq;
NetRamDq* ram_list_;
friend class NetScope;
NetMemory*snext_, *sprev_;
NetScope*scope_;
private: // not implemented
NetMemory(const NetMemory&);
NetMemory& operator= (const NetMemory&);
};
/*
* This class implements a basic LPM_MULT combinational multiplier. It
* is used as a structural representation of the * operator. The
@ -965,57 +961,6 @@ class NetMux : public NetNode {
unsigned swidth_;
};
/*
* This device represents an LPM_RAM_DQ device. The actual content is
* represented by a NetMemory object allocated elsewhere, but that
* object fixes the width and size of the device. The pin count of the
* address input is given in the constructor.
*/
class NetRamDq : public NetNode {
public:
NetRamDq(NetScope*s, perm_string name, NetMemory*mem, unsigned awid);
~NetRamDq();
unsigned width() const;
unsigned awidth() const;
unsigned size() const;
const NetMemory*mem() const;
Link& pin_InClock();
Link& pin_OutClock();
Link& pin_WE();
Link& pin_Address();
Link& pin_Data();
Link& pin_Q();
const Link& pin_InClock() const;
const Link& pin_OutClock() const;
const Link& pin_WE() const;
const Link& pin_Address() const;
const Link& pin_Data() const;
const Link& pin_Q() const;
virtual void dump_node(ostream&, unsigned ind) const;
virtual bool emit_node(struct target_t*) const;
// Use this method to absorb other NetRamDq objects that are
// connected to the same memory, and have compatible pin
// connections.
void absorb_partners();
// Use this method to count the partners (including myself)
// that are ports to the attached memory.
unsigned count_partners() const;
private:
NetMemory*mem_;
NetRamDq*next_;
unsigned awidth_;
};
/*
* The NetReplicate node takes a vector input and makes it into a larger
@ -1710,20 +1655,18 @@ class NetAssign_ {
public:
NetAssign_(NetNet*sig);
NetAssign_(NetMemory*mem);
~NetAssign_();
// If this expression exists, then only a single bit is to be
// set from the rval, and the value of this expression selects
// the pin that gets the value.
NetExpr*bmux();
const NetExpr*bmux() const;
// If this expression exists, then it is used to select a word
// from an array/memory.
NetExpr*word();
const NetExpr*word() const;
// Get the base index of the part select, or 0 if there is no
// part select.
const NetExpr* get_base() const;
void set_bmux(NetExpr*);
void set_word(NetExpr*);
void set_part(NetExpr* loff, unsigned wid);
// Get the width of the r-value that this node expects. This
@ -1735,7 +1678,6 @@ class NetAssign_ {
perm_string name() const;
NetNet* sig() const;
NetMemory*mem() const;
// Mark that the synthesizer has worked with this l-value, so
// when it is released, the l-value signal should be turned
@ -1755,9 +1697,8 @@ class NetAssign_ {
private:
NetNet *sig_;
NetMemory*mem_;
// Memory word index
NetExpr*bmux_;
NetExpr*word_;
bool turn_sig_to_wire_on_release_;
// indexed part select base
@ -3149,52 +3090,21 @@ class NetEUReduce : public NetEUnary {
};
/*
* A reference to a memory is represented by this expression. If the
* index is not supplied, then the node is only valid in certain
* specific contexts.
*/
class NetEMemory : public NetExpr {
public:
NetEMemory(NetMemory*mem, NetExpr*idx =0);
virtual ~NetEMemory();
perm_string name () const;
const NetExpr* index() const;
virtual bool set_width(unsigned, bool last_chance);
virtual NetNet* synthesize(Design*des);
NetExpr* eval_tree();
virtual NetEMemory*dup_expr() const;
virtual NexusSet* nex_input();
virtual void expr_scan(struct expr_scan_t*) const;
virtual void dump(ostream&) const;
const NetMemory*memory() const { return mem_; };
private:
NetMemory*mem_;
NetExpr* idx_;
};
/*
* When a signal shows up in an expression, this type represents
* it. From this the expression can get any kind of access to the
* structural signal.
* structural signal, including arrays.
*
* A signal shows up as a node in the netlist so that structural
* activity can invoke the expression. This node also supports part
* select by indexing a range of the NetNet that is associated with
* it. The msi() is the more significant index, and lsi() the least
* significant index.
* The NetESignal may refer to an array, if the word_index is
* included. This expression calculates the index of the word in the
* array. It may only be nil if the expression refers to the whole
* array, and that is legal only in limited situation.
*/
class NetESignal : public NetExpr {
public:
NetESignal(NetNet*n);
NetESignal(NetNet*n, NetExpr*word_index);
~NetESignal();
perm_string name() const;
@ -3204,12 +3114,16 @@ class NetESignal : public NetExpr {
NetNet* synthesize(Design*des);
NexusSet* nex_input();
// These methods actually reference the properties of the
// NetNet object that I point to.
unsigned bit_count() const;
Link& bit(unsigned idx);
// This is the expression for selecting an array word, if this
// signal refers to an array.
const NetExpr* word_index() const;
// This is the width of the vector that this signal refers to.
unsigned vector_width() const;
// Point back to the signal that this expression node references.
const NetNet* sig() const;
NetNet* sig();
// Declared vector dimensions for the signal.
unsigned msi() const;
unsigned lsi() const;
@ -3220,6 +3134,8 @@ class NetESignal : public NetExpr {
private:
NetNet*net_;
// Expression to select a word from the net.
NetExpr*word_;
};
@ -3278,15 +3194,6 @@ class NetScope : public Attrib {
NetNet* find_signal_in_child(const hname_t&name);
/* ... and these methods manage memory the same way as signals
are managed above. */
void add_memory(NetMemory*);
void rem_memory(NetMemory*);
NetMemory* find_memory(const string&name);
/* The parent and child() methods allow users of NetScope
objects to locate nearby scopes. */
NetScope* parent();
@ -3399,8 +3306,6 @@ class NetScope : public Attrib {
NetEvent *events_;
NetNet *signals_;
NetMemory*memories_;
perm_string module_name_;
union {
NetTaskDef*task_;
@ -3567,6 +3472,12 @@ extern ostream& operator << (ostream&, NetNet::Type);
/*
* $Log: netlist.h,v $
* Revision 1.366 2007/01/16 05:44:15 steve
* Major rework of array handling. Memories are replaced with the
* more general concept of arrays. The NetMemory and NetEMemory
* classes are removed from the ivl core program, and the IVL_LPM_RAM
* lpm type is removed from the ivl_target API.
*
* Revision 1.365 2006/11/04 06:19:25 steve
* Remove last bits of relax_width methods, and use test_width
* to calculate the width of an r-value expression that may

View File

@ -19,7 +19,7 @@
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#ifdef HAVE_CVS_IDENT
#ident "$Id: netmisc.h,v 1.26 2006/09/28 00:29:49 steve Exp $"
#ident "$Id: netmisc.h,v 1.27 2007/01/16 05:44:15 steve Exp $"
#endif
# include "netlist.h"
@ -42,7 +42,6 @@
extern NetScope* symbol_search(const Design*des,
NetScope*start, hname_t path,
NetNet*&net, /* net/reg */
NetMemory*&mem, /* memory */
const NetExpr*&par,/* parameter */
NetEvent*&eve, /* named event */
const NetExpr*&ex1, const NetExpr*&ex2);
@ -50,12 +49,11 @@ extern NetScope* symbol_search(const Design*des,
inline NetScope* symbol_search(const Design*des,
NetScope*start, const hname_t&path,
NetNet*&net, /* net/reg */
NetMemory*&mem, /* memory */
const NetExpr*&par,/* parameter */
NetEvent*&eve /* named event */)
{
const NetExpr*ex1, *ex2;
return symbol_search(des, start, path, net, mem, par, eve, ex1, ex2);
return symbol_search(des, start, path, net, /*mem,*/ par, eve, ex1, ex2);
}
/*
@ -122,6 +120,12 @@ extern NetExpr* elab_and_eval(Design*des, NetScope*scope,
/*
* $Log: netmisc.h,v $
* Revision 1.27 2007/01/16 05:44:15 steve
* Major rework of array handling. Memories are replaced with the
* more general concept of arrays. The NetMemory and NetEMemory
* classes are removed from the ivl core program, and the IVL_LPM_RAM
* lpm type is removed from the ivl_target API.
*
* Revision 1.26 2006/09/28 00:29:49 steve
* Allow specparams as constants in expressions.
*

42
parse.y
View File

@ -19,7 +19,7 @@
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#ifdef HAVE_CVS_IDENT
#ident "$Id: parse.y,v 1.223 2006/12/06 05:32:36 steve Exp $"
#ident "$Id: parse.y,v 1.224 2007/01/16 05:44:15 steve Exp $"
#endif
# include "config.h"
@ -191,8 +191,8 @@ static list<perm_string>* list_from_identifier(list<perm_string>*tmp, char*id)
%type <expr> udp_initial_expr_opt
%type <hier> identifier
%type <text> register_variable
%type <perm_strings> register_variable_list list_of_identifiers
%type <text> register_variable net_variable
%type <perm_strings> register_variable_list net_variable_list list_of_identifiers
%type <net_decl_assign> net_decl_assign net_decl_assigns
@ -1629,7 +1629,7 @@ module_item
: attribute_list_opt net_type
primitive_type_opt signed_opt range_opt
delay3_opt
list_of_identifiers ';'
net_variable_list ';'
{ ivl_variable_type_t dtype = $3;
if (dtype == IVL_VT_NO_TYPE)
@ -2477,6 +2477,40 @@ register_variable_list
}
;
net_variable
: IDENTIFIER
{ pform_makewire(@1, $1, NetNet::IMPLICIT,
NetNet::NOT_A_PORT,
IVL_VT_NO_TYPE, 0);
$$ = $1;
}
| IDENTIFIER '[' expression ':' expression ']'
{ pform_makewire(@1, $1, NetNet::IMPLICIT,
NetNet::NOT_A_PORT,
IVL_VT_NO_TYPE, 0);
if (! pform_expression_is_constant($3))
yyerror(@3, "error: msb of net range must be constant.");
if (! pform_expression_is_constant($5))
yyerror(@3, "error: lsb of net range must be constant.");
pform_set_reg_idx($1, $3, $5);
$$ = $1;
}
;
net_variable_list
: net_variable
{ list<perm_string>*tmp = new list<perm_string>;
tmp->push_back(lex_strings.make($1));
$$ = tmp;
delete[]$1;
}
| net_variable_list ',' net_variable
{ list<perm_string>*tmp = $1;
tmp->push_back(lex_strings.make($3));
$$ = tmp;
delete[]$3;
}
;
specify_item
: K_specparam specparam_list ';'
| specify_simple_path_decl ';'

View File

@ -17,7 +17,7 @@
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#ifdef HAVE_CVS_IDENT
#ident "$Id: pform.cc,v 1.137 2006/09/23 04:57:19 steve Exp $"
#ident "$Id: pform.cc,v 1.138 2007/01/16 05:44:15 steve Exp $"
#endif
# include "config.h"
@ -1197,24 +1197,21 @@ void pform_makewire(const vlltype&li, const char*nm,
PWire*cur = get_wire_in_module(name);
if (cur) {
if ((cur->get_wire_type() != NetNet::IMPLICIT)
&& (cur->get_wire_type() != NetNet::IMPLICIT_REG)) {
// If this is not implicit ("implicit" meaning we don't know
// what the type is yet) then set thay type now.
if (cur && type != NetNet::IMPLICIT) {
bool rc = cur->set_wire_type(type);
if (rc == false) {
ostringstream msg;
msg << name << " previously defined at " <<
cur->get_line() << ".";
msg << name << " definition conflicts with "
<< "definition at " << cur->get_line()
<< ".";
VLerror(msg.str().c_str());
} else {
bool rc = cur->set_wire_type(type);
if (rc == false) {
ostringstream msg;
msg << name << " definition conflicts with "
<< "definition at " << cur->get_line()
<< ".";
VLerror(msg.str().c_str());
}
cerr << "XXXX type=" << type <<", curtype=" << cur->get_wire_type() << endl;
}
}
if (cur) {
cur->set_file(li.text);
cur->set_lineno(li.first_line);
return;
@ -1747,6 +1744,12 @@ int pform_parse(const char*path, FILE*file)
/*
* $Log: pform.cc,v $
* Revision 1.138 2007/01/16 05:44:15 steve
* Major rework of array handling. Memories are replaced with the
* more general concept of arrays. The NetMemory and NetEMemory
* classes are removed from the ivl core program, and the IVL_LPM_RAM
* lpm type is removed from the ivl_target API.
*
* Revision 1.137 2006/09/23 04:57:19 steve
* Basic support for specify timing.
*

View File

@ -17,7 +17,7 @@
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#ifdef HAVE_CVS_IDENT
#ident "$Id: set_width.cc,v 1.41 2006/11/04 06:19:25 steve Exp $"
#ident "$Id: set_width.cc,v 1.42 2007/01/16 05:44:15 steve Exp $"
#endif
# include "config.h"
@ -340,7 +340,7 @@ bool NetECReal::set_width(unsigned w, bool)
expr_width(w);
return true;
}
#if 0
bool NetEMemory::set_width(unsigned w, bool)
{
if (w != mem_->width())
@ -349,7 +349,7 @@ bool NetEMemory::set_width(unsigned w, bool)
expr_width(w);
return true;
}
#endif
bool NetEParam::set_width(unsigned, bool)
{
return false;
@ -374,7 +374,7 @@ bool NetESFunc::set_width(unsigned w, bool)
*/
bool NetESignal::set_width(unsigned w, bool)
{
if (w != bit_count())
if (w != vector_width())
return false;
return true;
@ -441,6 +441,12 @@ bool NetEUReduce::set_width(unsigned w, bool)
/*
* $Log: set_width.cc,v $
* Revision 1.42 2007/01/16 05:44:15 steve
* Major rework of array handling. Memories are replaced with the
* more general concept of arrays. The NetMemory and NetEMemory
* classes are removed from the ivl core program, and the IVL_LPM_RAM
* lpm type is removed from the ivl_target API.
*
* Revision 1.41 2006/11/04 06:19:25 steve
* Remove last bits of relax_width methods, and use test_width
* to calculate the width of an r-value expression that may

View File

@ -17,7 +17,7 @@
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#ifdef HAVE_CVS_IDENT
#ident "$Id: symbol_search.cc,v 1.3 2005/11/27 05:56:20 steve Exp $"
#ident "$Id: symbol_search.cc,v 1.4 2007/01/16 05:44:15 steve Exp $"
#endif
# include "netlist.h"
@ -29,7 +29,6 @@
*/
NetScope*symbol_search(const Design*des, NetScope*scope, hname_t path,
NetNet*&net,
NetMemory*&mem,
const NetExpr*&par,
NetEvent*&eve,
const NetExpr*&ex1, const NetExpr*&ex2)
@ -41,7 +40,6 @@ NetScope*symbol_search(const Design*des, NetScope*scope, hname_t path,
/* Initialize output argument to cleared. */
net = 0;
mem = 0;
par = 0;
eve = 0;
@ -56,11 +54,6 @@ NetScope*symbol_search(const Design*des, NetScope*scope, hname_t path,
return scope;
}
if ( (mem = scope->find_memory(key)) ) {
delete key;
return scope;
}
if ( (eve = scope->find_event(key)) ) {
delete key;
return scope;
@ -83,6 +76,12 @@ NetScope*symbol_search(const Design*des, NetScope*scope, hname_t path,
/*
* $Log: symbol_search.cc,v $
* Revision 1.4 2007/01/16 05:44:15 steve
* Major rework of array handling. Memories are replaced with the
* more general concept of arrays. The NetMemory and NetEMemory
* classes are removed from the ivl core program, and the IVL_LPM_RAM
* lpm type is removed from the ivl_target API.
*
* Revision 1.3 2005/11/27 05:56:20 steve
* Handle bit select of parameter with ranges.
*

View File

@ -19,7 +19,7 @@
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#ifdef HAVE_CVS_IDENT
#ident "$Id: syn-rules.y,v 1.33 2005/04/24 23:44:02 steve Exp $"
#ident "$Id: syn-rules.y,v 1.34 2007/01/16 05:44:15 steve Exp $"
#endif
# include "config.h"
@ -118,7 +118,7 @@ static void hookup_DFF_CE(NetFF*ff, NetESignal*d, NetEvProbe*pclk,
// where lval is really a "reg [7:0]". In other words, part
// selects in the l-value are handled by loff and the lwidth().
connect(ff->pin_Data(), d->bit(0));
connect(ff->pin_Data(), d->sig()->pin(0));
connect(ff->pin_Q(), a->sig()->pin(0));
connect(ff->pin_Clock(), pclk->pin(0));
@ -137,41 +137,6 @@ static void hookup_DFF_CE(NetFF*ff, NetESignal*d, NetEvProbe*pclk,
a->turn_sig_to_wire_on_release();
}
static void hookup_RAMDQ(NetRamDq*ram, NetESignal*d, NetNet*adr,
NetEvProbe*pclk, NetNet*ce,
NetAssign_*a, unsigned rval_pinoffset)
{
assert(d);
assert(a);
/* Connect the input Data bits of the RAM, from the r-value of
the assignment. */
connect(ram->pin_Data(), d->bit(rval_pinoffset));
/* Connect the Address pins from the addr net discovered by the
caller. */
connect(ram->pin_Address(), adr->pin(0));
/* Connect the input clock and the WE of the RAM. */
assert(pclk);
connect(ram->pin_InClock(), pclk->pin(0));
if (ce) {
connect(ram->pin_WE(), ce->pin(0));
} /* XXX does ram CE default to true if not connected? */
/* This notices any other NetRamDq objects connected to the
same NetMemory, that have the same address pins and are
otherwise compatible. This absorbs them into this object. */
ram->absorb_partners();
/* This lval_ represents a reg that is a WIRE in the
synthesized results. This function signals the destructor
to change the REG that this l-value refers to into a
WIRE. It is done then, at the last minute, so that pending
synthesis can continue to work with it as a WIRE. */
a->turn_sig_to_wire_on_release();
}
static void make_DFF_CE(Design*des, NetProcTop*top, NetEvWait*wclk,
NetEvent*eclk, NetExpr*cexp, NetAssignBase*asn)
{
@ -207,13 +172,6 @@ static void make_DFF_CE(Design*des, NetProcTop*top, NetEvWait*wclk,
a->sig()->vector_width());
hookup_DFF_CE(ff, d, pclk, ce, a, rval_pinoffset);
des->add_node(ff);
} else if (a->mem()) {
NetMemory *m=a->mem();
NetNet *adr = a->bmux()->synthesize(des);
NetRamDq*ram = new NetRamDq(top->scope(), m->name(),
m, adr->pin_count());
hookup_RAMDQ(ram, d, adr, pclk, ce, a, rval_pinoffset);
des->add_node(ram);
}
rval_pinoffset += a->lwidth();
}
@ -233,7 +191,7 @@ static void make_initializer(Design*des, NetProcTop*top, NetAssignBase*asn)
for (unsigned idx = 0 ; idx < asn->l_val(0)->lwidth() ; idx += 1) {
verinum::V bit = rsig->bit(idx).nexus()->driven_value();
verinum::V bit = rsig->sig()->pin(idx).nexus()->driven_value();
Nexus*nex = asn->l_val(0)->sig()->pin(idx).nexus();
for (Link*cur = nex->first_nlink()

View File

@ -17,7 +17,7 @@
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#ifdef HAVE_CVS_IDENT
#ident "$Id: t-dll-api.cc,v 1.137 2006/09/23 04:57:19 steve Exp $"
#ident "$Id: t-dll-api.cc,v 1.138 2007/01/16 05:44:15 steve Exp $"
#endif
# include "config.h"
@ -317,6 +317,9 @@ extern "C" ivl_expr_t ivl_expr_oper1(ivl_expr_t net)
case IVL_EX_MEMORY:
return net->u_.memory_.idx_;
case IVL_EX_SIGNAL:
return net->u_.signal_.word;
case IVL_EX_TERNARY:
return net->u_.ternary_.cond;
@ -443,6 +446,7 @@ extern "C" ivl_signal_t ivl_expr_signal(ivl_expr_t net)
switch (net->type_) {
case IVL_EX_SIGNAL:
case IVL_EX_ARRAY:
return net->u_.signal_.sig;
default:
@ -707,6 +711,18 @@ extern "C" ivl_nexus_t ivl_lpm_sync_set(ivl_lpm_t net)
}
}
extern "C" ivl_signal_t ivl_lpm_array(ivl_lpm_t net)
{
assert(net);
switch (net->type) {
case IVL_LPM_ARRAY:
return net->u_.array.sig;
default:
assert(0);
return 0;
}
}
extern "C" unsigned ivl_lpm_base(ivl_lpm_t net)
{
assert(net);
@ -726,7 +742,6 @@ extern "C" ivl_nexus_t ivl_lpm_clk(ivl_lpm_t net)
assert(net);
switch (net->type) {
case IVL_LPM_FF:
case IVL_LPM_RAM:
return net->u_.ff.clk;
default:
assert(0);
@ -739,7 +754,6 @@ extern "C" ivl_expr_t ivl_lpm_aset_value(ivl_lpm_t net)
assert(net);
switch (net->type) {
case IVL_LPM_FF:
case IVL_LPM_RAM:
return net->u_.ff.aset_value;
default:
assert(0);
@ -751,7 +765,6 @@ extern "C" ivl_expr_t ivl_lpm_sset_value(ivl_lpm_t net)
assert(net);
switch (net->type) {
case IVL_LPM_FF:
case IVL_LPM_RAM:
return net->u_.ff.sset_value;
default:
assert(0);
@ -775,7 +788,6 @@ extern "C" ivl_nexus_t ivl_lpm_enable(ivl_lpm_t net)
{
assert(net);
switch (net->type) {
case IVL_LPM_RAM:
case IVL_LPM_FF:
return net->u_.ff.we;
default:
@ -827,10 +839,6 @@ extern "C" ivl_nexus_t ivl_lpm_data(ivl_lpm_t net, unsigned idx)
else
return net->u_.shift.s;
case IVL_LPM_RAM:
assert(idx == 0);
return net->u_.ff.d.pin;
case IVL_LPM_FF:
assert(idx == 0);
return net->u_.ff.d.pin;
@ -945,10 +953,6 @@ extern "C" ivl_nexus_t ivl_lpm_q(ivl_lpm_t net, unsigned idx)
assert(idx == 0);
return net->u_.arith.q;
case IVL_LPM_RAM:
assert(idx == 0);
return net->u_.ff.q.pin;
case IVL_LPM_FF:
assert(idx == 0);
return net->u_.ff.q.pin;
@ -993,6 +997,10 @@ extern "C" ivl_nexus_t ivl_lpm_q(ivl_lpm_t net, unsigned idx)
assert(idx == 0);
return net->u_.repeat.q;
case IVL_LPM_ARRAY:
assert(idx == 0);
return net->u_.array.q;
default:
assert(0);
return 0;
@ -1008,12 +1016,13 @@ extern "C" ivl_scope_t ivl_lpm_scope(ivl_lpm_t net)
extern "C" ivl_nexus_t ivl_lpm_select(ivl_lpm_t net)
{
switch (net->type) {
case IVL_LPM_RAM:
return net->u_.ff.s.pin;
case IVL_LPM_MUX:
return net->u_.mux.s;
case IVL_LPM_ARRAY:
return net->u_.array.a;
default:
assert(0);
return 0;
@ -1023,10 +1032,10 @@ extern "C" ivl_nexus_t ivl_lpm_select(ivl_lpm_t net)
extern "C" unsigned ivl_lpm_selects(ivl_lpm_t net)
{
switch (net->type) {
case IVL_LPM_RAM:
return net->u_.ff.swid;
case IVL_LPM_MUX:
return net->u_.mux.swid;
case IVL_LPM_ARRAY:
return net->u_.array.swid;
case IVL_LPM_CONCAT:
return net->u_.concat.inputs;
default:
@ -1040,7 +1049,6 @@ extern "C" int ivl_lpm_signed(ivl_lpm_t net)
assert(net);
switch (net->type) {
case IVL_LPM_FF:
case IVL_LPM_RAM:
case IVL_LPM_MUX:
return 0;
case IVL_LPM_ADD:
@ -1079,6 +1087,8 @@ extern "C" int ivl_lpm_signed(ivl_lpm_t net)
return net->u_.part.signed_flag;
case IVL_LPM_REPEAT:
return 0;
case IVL_LPM_ARRAY: // Array ports take the signedness of the array.
return net->u_.array.sig->signed_;
default:
assert(0);
return 0;
@ -1119,18 +1129,6 @@ extern "C" unsigned ivl_lpm_width(ivl_lpm_t net)
return net->width;
}
extern "C" ivl_memory_t ivl_lpm_memory(ivl_lpm_t net)
{
assert(net);
switch (net->type) {
case IVL_LPM_RAM:
return net->u_.ff.mem;
default:
assert(0);
return 0;
}
}
extern "C" ivl_expr_t ivl_lval_mux(ivl_lval_t net)
{
assert(net);
@ -1144,6 +1142,8 @@ extern "C" ivl_expr_t ivl_lval_idx(ivl_lval_t net)
assert(net);
if (net->type_ == IVL_LVAL_MEM)
return net->idx;
if (net->type_ == IVL_LVAL_ARR)
return net->idx;
return 0x0;
}
@ -1174,6 +1174,7 @@ extern "C" ivl_signal_t ivl_lval_sig(ivl_lval_t net)
case IVL_LVAL_REG:
case IVL_LVAL_NET:
case IVL_LVAL_MUX:
case IVL_LVAL_ARR:
return net->n.sig;
default:
return 0;
@ -1520,6 +1521,16 @@ extern "C" const char* ivl_scope_tname(ivl_scope_t net)
return net->tname_;
}
extern "C" int ivl_signal_array_base(ivl_signal_t net)
{
return net->array_base;
}
extern "C" unsigned ivl_signal_array_count(ivl_signal_t net)
{
return net->array_words;
}
extern "C" const char* ivl_signal_attr(ivl_signal_t net, const char*key)
{
if (net->nattr == 0)
@ -1571,9 +1582,13 @@ extern "C" const char* ivl_signal_name(ivl_signal_t net)
return name_buffer;
}
extern "C" ivl_nexus_t ivl_signal_nex(ivl_signal_t net)
extern "C" ivl_nexus_t ivl_signal_nex(ivl_signal_t net, unsigned word)
{
return net->pin_;
assert(word < net->array_words);
if (net->array_words > 1)
return net->pins[word];
else
return net->pin;
}
extern "C" int ivl_signal_msb(ivl_signal_t net)
@ -1889,6 +1904,7 @@ extern "C" unsigned ivl_stmt_lwidth(ivl_statement_t net)
sum += 1;
break;
case IVL_LVAL_REG:
case IVL_LVAL_ARR:
sum += ivl_lval_width(cur);
break;
case IVL_LVAL_MEM:
@ -1976,6 +1992,12 @@ extern "C" ivl_statement_t ivl_stmt_sub_stmt(ivl_statement_t net)
/*
* $Log: t-dll-api.cc,v $
* Revision 1.138 2007/01/16 05:44:15 steve
* Major rework of array handling. Memories are replaced with the
* more general concept of arrays. The NetMemory and NetEMemory
* classes are removed from the ivl core program, and the IVL_LPM_RAM
* lpm type is removed from the ivl_target API.
*
* Revision 1.137 2006/09/23 04:57:19 steve
* Basic support for specify timing.
*

View File

@ -17,7 +17,7 @@
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#ifdef HAVE_CVS_IDENT
#ident "$Id: t-dll-expr.cc,v 1.43 2005/09/14 02:53:15 steve Exp $"
#ident "$Id: t-dll-expr.cc,v 1.44 2007/01/16 05:44:15 steve Exp $"
#endif
# include "config.h"
@ -200,27 +200,6 @@ void dll_target::expr_concat(const NetEConcat*net)
expr_ = cur;
}
void dll_target::expr_memory(const NetEMemory*net)
{
assert(expr_ == 0);
if (net->index()) {
net->index()->expr_scan(this);
assert(expr_);
}
ivl_expr_t cur = (ivl_expr_t)calloc(1, sizeof(struct ivl_expr_s));
assert(cur);
cur->type_ = IVL_EX_MEMORY;
cur->value_ = IVL_VT_VECTOR;
cur->width_= net->expr_width();
cur->signed_ = net->has_sign()? 1 : 0;
cur->u_.memory_.mem_ = find_memory(des_, net->memory());
cur->u_.memory_.idx_ = expr_;
expr_ = cur;
}
void dll_target::expr_const(const NetEConst*net)
{
assert(expr_ == 0);
@ -410,8 +389,19 @@ void dll_target::expr_ternary(const NetETernary*net)
void dll_target::expr_signal(const NetESignal*net)
{
ivl_signal_t sig = find_signal(des_, net->sig());
assert(expr_ == 0);
/* If there is a word expression, generate it. */
ivl_expr_t word_expr = 0;
if (const NetExpr*word = net->word_index()) {
word->expr_scan(this);
assert(expr_);
word_expr = expr_;
expr_ = 0;
}
expr_ = (ivl_expr_t)calloc(1, sizeof(struct ivl_expr_s));
assert(expr_);
@ -419,7 +409,18 @@ void dll_target::expr_signal(const NetESignal*net)
expr_->value_= net->expr_type();
expr_->width_= net->expr_width();
expr_->signed_ = net->has_sign()? 1 : 0;
expr_->u_.signal_.sig = find_signal(des_, net->sig());
expr_->u_.signal_.word = word_expr;
expr_->u_.signal_.sig = sig;
/* Make account for the special case that this is a reference
to an array as a whole. We detect this case by noting that
this is an array (more then 1 word) and there is no word
select expression. In that case, this is an IVL_EX_ARRAY
expression instead of a SIGNAL expression. */
if (sig->array_words > 1 && word_expr == 0) {
expr_->type_ = IVL_EX_ARRAY;
expr_->width_ = 0; // Doesn't make much sense for arrays.
}
}
@ -473,6 +474,12 @@ void dll_target::expr_unary(const NetEUnary*net)
/*
* $Log: t-dll-expr.cc,v $
* Revision 1.44 2007/01/16 05:44:15 steve
* Major rework of array handling. Memories are replaced with the
* more general concept of arrays. The NetMemory and NetEMemory
* classes are removed from the ivl core program, and the IVL_LPM_RAM
* lpm type is removed from the ivl_target API.
*
* Revision 1.43 2005/09/14 02:53:15 steve
* Support bool expressions and compares handle them optimally.
*

View File

@ -18,7 +18,7 @@
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#ifdef HAVE_CVS_IDENT
#ident "$Id: t-dll-proc.cc,v 1.68 2006/02/02 02:43:59 steve Exp $"
#ident "$Id: t-dll-proc.cc,v 1.69 2007/01/16 05:44:15 steve Exp $"
#endif
# include "config.h"
@ -171,30 +171,21 @@ void dll_target::make_assign_lvals_(const NetAssignBase*net)
cur->n.sig = find_signal(des_, asn->sig());
cur->idx = 0;
if (asn->bmux()) {
// If there is a word select expression, it is
// really an array index.
if (asn->word()) {
assert(expr_ == 0);
asn->bmux()->expr_scan(this);
asn->word()->expr_scan(this);
if (cur->n.sig->lsb_index != 0)
sub_off_from_expr_(asn->sig()->lsb());
if (cur->n.sig->lsb_dist != 1)
mul_expr_by_const_(cur->n.sig->lsb_dist);
cur->type_ = IVL_LVAL_MUX;
cur->type_ = IVL_LVAL_ARR;
cur->idx = expr_;
expr_ = 0;
}
} else if (asn->mem()) {
assert(asn->mem());
cur->type_ = IVL_LVAL_MEM;
cur->n.mem = find_memory(des_, asn->mem());
assert(cur->n.mem);
cur->width_ = ivl_memory_width(cur->n.mem);
assert(expr_ == 0);
asn->bmux()->expr_scan(this);
cur->idx = expr_;
expr_ = 0;
} else {
assert(0);
}
@ -741,6 +732,12 @@ void dll_target::proc_while(const NetWhile*net)
/*
* $Log: t-dll-proc.cc,v $
* Revision 1.69 2007/01/16 05:44:15 steve
* Major rework of array handling. Memories are replaced with the
* more general concept of arrays. The NetMemory and NetEMemory
* classes are removed from the ivl core program, and the IVL_LPM_RAM
* lpm type is removed from the ivl_target API.
*
* Revision 1.68 2006/02/02 02:43:59 steve
* Allow part selects of memory words in l-values.
*

181
t-dll.cc
View File

@ -17,7 +17,7 @@
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#ifdef HAVE_CVS_IDENT
#ident "$Id: t-dll.cc,v 1.161 2006/11/10 05:44:45 steve Exp $"
#ident "$Id: t-dll.cc,v 1.162 2007/01/16 05:44:15 steve Exp $"
#endif
# include "config.h"
@ -242,27 +242,6 @@ ivl_signal_t dll_target::find_signal(ivl_design_s &des, const NetNet*net)
return 0;
}
/*
* This function locates an ivl_memory_t object that matches the
* NetMemory object. The search works by looking for the parent scope,
* then scanning the parent scope for the NetMemory object.
*/
ivl_memory_t dll_target::find_memory(ivl_design_s &des, const NetMemory*net)
{
ivl_scope_t scope = find_scope(des, net->scope());
assert(scope);
const char*nname = net->name();
for (unsigned idx = 0 ; idx < scope->nmem_ ; idx += 1) {
if (strcmp(scope->mem_[idx]->basename_, nname) == 0)
return scope->mem_[idx];
}
assert(0);
return 0;
}
static ivl_nexus_t nexus_sig_make(ivl_signal_t net, unsigned pin)
{
ivl_nexus_t tmp = new struct ivl_nexus_s;
@ -417,14 +396,6 @@ static void scope_add_lpm(ivl_scope_t scope, ivl_lpm_t net)
}
}
static void scope_add_mem(ivl_scope_t scope, ivl_memory_t net)
{
scope->nmem_ += 1;
scope->mem_ = (ivl_memory_t*)
realloc(scope->mem_, scope->nmem_*sizeof(ivl_memory_t));
scope->mem_[scope->nmem_-1] = net;
}
ivl_parameter_t dll_target::scope_find_param(ivl_scope_t scope,
const char*name)
{
@ -1186,20 +1157,6 @@ void dll_target::udp(const NetUDP*net)
scope_add_logic(scope, obj);
}
void dll_target::memory(const NetMemory*net)
{
ivl_memory_t obj = new struct ivl_memory_s;
obj->scope_ = find_scope(des_, net->scope());
obj->basename_ = net->name();
obj->width_ = net->width();
obj->signed_ = 0;
obj->size_ = net->count();
obj->root_ = -net->index_to_address(0);
scope_add_mem(obj->scope_, obj);
}
void dll_target::lpm_add_sub(const NetAddSub*net)
{
ivl_lpm_t obj = new struct ivl_lpm_s;
@ -1252,6 +1209,35 @@ void dll_target::lpm_add_sub(const NetAddSub*net)
scope_add_lpm(obj->scope, obj);
}
bool dll_target::lpm_array_dq(const NetArrayDq*net)
{
ivl_lpm_t obj = new struct ivl_lpm_s;
obj->type = IVL_LPM_ARRAY;
obj->name = net->name();
obj->u_.array.sig = find_signal(des_, net->mem());
assert(obj->u_.array.sig);
obj->scope = find_scope(des_, net->scope());
assert(obj->scope);
obj->width = net->width();
obj->u_.array.swid = net->awidth();
scope_add_lpm(obj->scope, obj);
const Nexus*nex;
nex = net->pin_Address().nexus();
assert(nex->t_cookie());
obj->u_.array.a = (ivl_nexus_t) nex->t_cookie();
nexus_lpm_add(obj->u_.array.a, obj, 0, IVL_DR_HiZ, IVL_DR_HiZ);
nex = net->pin_Result().nexus();
assert(nex->t_cookie());
obj->u_.array.q = (ivl_nexus_t) nex->t_cookie();
nexus_lpm_add(obj->u_.array.q, obj, 0, IVL_DR_STRONG, IVL_DR_STRONG);
return true;
}
/*
* The lpm_clshift device represents both left and right shifts,
* depending on what is connected to the Direction pin. We convert
@ -1578,73 +1564,6 @@ void dll_target::lpm_ff(const NetFF*net)
}
void dll_target::lpm_ram_dq(const NetRamDq*net)
{
ivl_lpm_t obj = new struct ivl_lpm_s;
obj->type = IVL_LPM_RAM;
obj->name = net->name();
obj->u_.ff.mem = find_memory(des_, net->mem());
assert(obj->u_.ff.mem);
obj->scope = find_scope(des_, net->mem()->scope());
assert(obj->scope);
obj->width = net->width();
obj->u_.ff.swid = net->awidth();
scope_add_lpm(obj->scope, obj);
const Nexus*nex;
// A write port is present only if something is connected to
// the clock input.
bool has_write_port = net->pin_InClock().is_linked();
// Connect the write clock and write enable
if (has_write_port) {
nex = net->pin_InClock().nexus();
assert(nex->t_cookie());
obj->u_.ff.clk = (ivl_nexus_t) nex->t_cookie();
assert(obj->u_.ff.clk);
nexus_lpm_add(obj->u_.ff.clk, obj, 0, IVL_DR_HiZ, IVL_DR_HiZ);
nex = net->pin_WE().nexus();
if (nex && nex->t_cookie()) {
obj->u_.ff.we = (ivl_nexus_t) nex->t_cookie();
assert(obj->u_.ff.we);
nexus_lpm_add(obj->u_.ff.we, obj, 0, IVL_DR_HiZ, IVL_DR_HiZ);
}
else
obj->u_.ff.we = 0x0;
}
else {
obj->u_.ff.clk = 0x0;
obj->u_.ff.we = 0x0;
}
// Connect the address bus
nex = net->pin_Address().nexus();
assert(nex->t_cookie());
obj->u_.ff.s.pin = (ivl_nexus_t) nex->t_cookie();
nexus_lpm_add(obj->u_.ff.s.pin, obj, 0, IVL_DR_HiZ, IVL_DR_HiZ);
// Connect the data busses
nex = net->pin_Q().nexus();
assert(nex->t_cookie());
obj->u_.ff.q.pin = (ivl_nexus_t) nex->t_cookie();
nexus_lpm_add(obj->u_.ff.q.pin, obj, 0, IVL_DR_STRONG, IVL_DR_STRONG);
if (has_write_port) {
nex = net->pin_Data().nexus();
assert(nex->t_cookie());
obj->u_.ff.d.pin = (ivl_nexus_t) nex->t_cookie();
nexus_lpm_add(obj->u_.ff.d.pin, obj, 0, IVL_DR_HiZ, IVL_DR_HiZ);
}
}
/*
* Make the NetMult object into an IVL_LPM_MULT node.
*/
@ -2192,18 +2111,32 @@ void dll_target::signal(const NetNet*net)
t_cookie of the Nexus object so that I find it again when I
next encounter the nexus. */
const Nexus*nex = net->pin(0).nexus();
if (nex->t_cookie()) {
obj->pin_ = (ivl_nexus_t)nex->t_cookie();
nexus_sig_add(obj->pin_, obj, 0);
obj->array_base = net->array_first();
obj->array_words = net->array_count();
if (obj->array_words > 1)
obj->pins = new ivl_nexus_t[obj->array_words];
} else {
ivl_nexus_t tmp = nexus_sig_make(obj, 0);
tmp->name_ = strings_.add(nex->name());
nex->t_cookie(tmp);
obj->pin_ = tmp;
for (unsigned idx = 0 ; idx < obj->array_words ; idx += 1) {
const Nexus*nex = net->pin(idx).nexus();
if (nex->t_cookie()) {
if (obj->array_words > 1) {
obj->pins[idx] = (ivl_nexus_t)nex->t_cookie();
nexus_sig_add(obj->pins[idx], obj, idx);
} else {
obj->pin = (ivl_nexus_t)nex->t_cookie();
nexus_sig_add(obj->pin, obj, idx);
}
} else {
ivl_nexus_t tmp = nexus_sig_make(obj, idx);
tmp->name_ = strings_.add(nex->name());
nex->t_cookie(tmp);
if (obj->array_words > 1)
obj->pins[idx] = tmp;
else
obj->pin = tmp;
}
}
}
bool dll_target::signal_paths(const NetNet*net)
@ -2258,6 +2191,12 @@ extern const struct target tgt_dll = { "dll", &dll_target_obj };
/*
* $Log: t-dll.cc,v $
* Revision 1.162 2007/01/16 05:44:15 steve
* Major rework of array handling. Memories are replaced with the
* more general concept of arrays. The NetMemory and NetEMemory
* classes are removed from the ivl core program, and the IVL_LPM_RAM
* lpm type is removed from the ivl_target API.
*
* Revision 1.161 2006/11/10 05:44:45 steve
* Process delay paths in second path over signals.
*

40
t-dll.h
View File

@ -19,7 +19,7 @@
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#ifdef HAVE_CVS_IDENT
#ident "$Id: t-dll.h,v 1.134 2006/11/10 05:44:45 steve Exp $"
#ident "$Id: t-dll.h,v 1.135 2007/01/16 05:44:16 steve Exp $"
#endif
# include "target.h"
@ -74,6 +74,7 @@ struct dll_target : public target_t, public expr_scan_t {
void net_case_cmp(const NetCaseCmp*);
void udp(const NetUDP*);
void lpm_add_sub(const NetAddSub*);
bool lpm_array_dq(const NetArrayDq*);
void lpm_clshift(const NetCLShift*);
void lpm_compare(const NetCompare*);
void lpm_divide(const NetDivide*);
@ -81,7 +82,6 @@ struct dll_target : public target_t, public expr_scan_t {
void lpm_modulo(const NetModulo*);
void lpm_mult(const NetMult*);
void lpm_mux(const NetMux*);
void lpm_ram_dq(const NetRamDq*);
bool concat(const NetConcat*);
bool part_select(const NetPartSelect*);
bool replicate(const NetReplicate*);
@ -97,8 +97,6 @@ struct dll_target : public target_t, public expr_scan_t {
void scope(const NetScope*);
void signal(const NetNet*);
bool signal_paths(const NetNet*);
void memory(const NetMemory*);
ivl_dll_t dll_;
ivl_design_s des_;
@ -134,7 +132,6 @@ struct dll_target : public target_t, public expr_scan_t {
struct ivl_expr_s*expr_;
void expr_binary(const NetEBinary*);
void expr_concat(const NetEConcat*);
void expr_memory(const NetEMemory*);
void expr_const(const NetEConst*);
void expr_creal(const NetECReal*);
void expr_param(const NetEConstParam*);
@ -157,8 +154,6 @@ struct dll_target : public target_t, public expr_scan_t {
static ivl_scope_t find_scope(ivl_design_s &des, const NetScope*cur);
static ivl_signal_t find_signal(ivl_design_s &des, const NetNet*net);
static ivl_memory_t find_memory(ivl_design_s &des, const NetMemory*net);
static ivl_parameter_t scope_find_param(ivl_scope_t scope,
const char*name);
@ -231,6 +226,7 @@ struct ivl_expr_s {
struct {
ivl_signal_t sig;
ivl_expr_t word;
} signal_;
struct {
@ -294,7 +290,6 @@ struct ivl_lpm_s {
union {
struct ivl_lpm_ff_s {
unsigned swid; // ram only
ivl_nexus_t clk;
ivl_nexus_t we;
ivl_nexus_t aclr;
@ -309,11 +304,6 @@ struct ivl_lpm_s {
ivl_nexus_t*pins;
ivl_nexus_t pin;
} d;
union { // ram only
ivl_nexus_t*pins;
ivl_nexus_t pin;
} s;
ivl_memory_t mem; // ram only
ivl_expr_t aset_value;
ivl_expr_t sset_value;
} ff;
@ -336,6 +326,12 @@ struct ivl_lpm_s {
ivl_nexus_t q, a, b;
} arith;
struct ivl_lpm_array_s {
ivl_signal_t sig;
unsigned swid;
ivl_nexus_t q, a;
} array;
struct ivl_concat_s {
unsigned inputs;
ivl_nexus_t*pins;
@ -380,8 +376,9 @@ struct ivl_lpm_s {
enum ivl_lval_type_t {
IVL_LVAL_REG = 0,
IVL_LVAL_MUX = 1,
IVL_LVAL_MEM = 2,
IVL_LVAL_NET = 3 /* Only force can have NET l-values */
IVL_LVAL_MEM = 2, /* Deprecated in favor of LVAL_ARR? */
IVL_LVAL_NET = 3, /* Only force can have NET l-values */
IVL_LVAL_ARR = 4
};
struct ivl_lval_s {
@ -589,7 +586,12 @@ struct ivl_signal_s {
perm_string name_;
ivl_scope_t scope_;
ivl_nexus_t pin_;
unsigned array_words;
int array_base;
union {
ivl_nexus_t pin;
ivl_nexus_t*pins;
};
ivl_delaypath_s*path;
unsigned npath;
@ -680,6 +682,12 @@ struct ivl_statement_s {
/*
* $Log: t-dll.h,v $
* Revision 1.135 2007/01/16 05:44:16 steve
* Major rework of array handling. Memories are replaced with the
* more general concept of arrays. The NetMemory and NetEMemory
* classes are removed from the ivl core program, and the IVL_LPM_RAM
* lpm type is removed from the ivl_target API.
*
* Revision 1.134 2006/11/10 05:44:45 steve
* Process delay paths in second path over signals.
*

View File

@ -17,7 +17,7 @@
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#ifdef HAVE_CVS_IDENT
#ident "$Id: target.cc,v 1.79 2006/11/10 05:44:45 steve Exp $"
#ident "$Id: target.cc,v 1.80 2007/01/16 05:44:16 steve Exp $"
#endif
# include "config.h"
@ -45,13 +45,6 @@ bool target_t::signal_paths(const NetNet*)
{
return true;
}
void target_t::memory(const NetMemory*)
{
cerr << "target (" << typeid(*this).name() << "): "
"Unhandled memory." << endl;
}
bool target_t::func_def(const NetScope*)
{
cerr << "target (" << typeid(*this).name() << "): "
@ -97,6 +90,13 @@ void target_t::lpm_add_sub(const NetAddSub*)
"Unhandled NetAddSub." << endl;
}
bool target_t::lpm_array_dq(const NetArrayDq*)
{
cerr << "target (" << typeid(*this).name() << "): "
"Unhandled NetArrayDq." << endl;
return false;
}
void target_t::lpm_clshift(const NetCLShift*)
{
cerr << "target (" << typeid(*this).name() << "): "
@ -138,13 +138,6 @@ void target_t::lpm_mux(const NetMux*)
cerr << "target (" << typeid(*this).name() << "): "
"Unhandled NetMux." << endl;
}
void target_t::lpm_ram_dq(const NetRamDq*)
{
cerr << "target (" << typeid(*this).name() << "): "
"Unhandled NetRamDq." << endl;
}
bool target_t::concat(const NetConcat*)
{
cerr << "target (" << typeid(*this).name() << "): "
@ -380,13 +373,6 @@ void expr_scan_t::expr_concat(const NetEConcat*that)
cerr << that->get_line() << ": expr_scan_t (" <<
typeid(*this).name() << "): unhandled expr_concat." << endl;
}
void expr_scan_t::expr_memory(const NetEMemory*)
{
cerr << "expr_scan_t (" << typeid(*this).name() << "): "
"unhandled expr_memory." << endl;
}
void expr_scan_t::expr_event(const NetEEvent*)
{
cerr << "expr_scan_t (" << typeid(*this).name() << "): "
@ -443,6 +429,12 @@ void expr_scan_t::expr_binary(const NetEBinary*ex)
/*
* $Log: target.cc,v $
* Revision 1.80 2007/01/16 05:44:16 steve
* Major rework of array handling. Memories are replaced with the
* more general concept of arrays. The NetMemory and NetEMemory
* classes are removed from the ivl core program, and the IVL_LPM_RAM
* lpm type is removed from the ivl_target API.
*
* Revision 1.79 2006/11/10 05:44:45 steve
* Process delay paths in second path over signals.
*

View File

@ -19,7 +19,7 @@
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#ifdef HAVE_CVS_IDENT
#ident "$Id: target.h,v 1.76 2006/11/10 05:44:45 steve Exp $"
#ident "$Id: target.h,v 1.77 2007/01/16 05:44:16 steve Exp $"
#endif
# include "netlist.h"
@ -66,15 +66,13 @@ struct target_t {
virtual void signal(const NetNet*) =0;
virtual bool signal_paths(const NetNet*);
/* Output a memory (called for each memory object) */
virtual void memory(const NetMemory*);
/* Output a defined task. */
virtual void task_def(const NetScope*);
virtual bool func_def(const NetScope*);
/* LPM style components are handled here. */
virtual void lpm_add_sub(const NetAddSub*);
virtual bool lpm_array_dq(const NetArrayDq*);
virtual void lpm_clshift(const NetCLShift*);
virtual void lpm_compare(const NetCompare*);
virtual void lpm_divide(const NetDivide*);
@ -82,7 +80,6 @@ struct target_t {
virtual void lpm_ff(const NetFF*);
virtual void lpm_mult(const NetMult*);
virtual void lpm_mux(const NetMux*);
virtual void lpm_ram_dq(const NetRamDq*);
virtual bool concat(const NetConcat*);
virtual bool part_select(const NetPartSelect*);
@ -139,7 +136,6 @@ struct expr_scan_t {
virtual void expr_rparam(const NetECRealParam*);
virtual void expr_creal(const NetECReal*);
virtual void expr_concat(const NetEConcat*);
virtual void expr_memory(const NetEMemory*);
virtual void expr_event(const NetEEvent*);
virtual void expr_scope(const NetEScope*);
virtual void expr_select(const NetESelect*);
@ -172,6 +168,12 @@ extern const struct target *target_table[];
/*
* $Log: target.h,v $
* Revision 1.77 2007/01/16 05:44:16 steve
* Major rework of array handling. Memories are replaced with the
* more general concept of arrays. The NetMemory and NetEMemory
* classes are removed from the ivl core program, and the IVL_LPM_RAM
* lpm type is removed from the ivl_target API.
*
* Revision 1.76 2006/11/10 05:44:45 steve
* Process delay paths in second path over signals.
*

View File

@ -16,7 +16,7 @@
# 59 Temple Place - Suite 330
# Boston, MA 02111-1307, USA
#
#ident "$Id: Makefile.in,v 1.17 2006/10/30 22:45:37 steve Exp $"
#ident "$Id: Makefile.in,v 1.18 2007/01/16 05:44:16 steve Exp $"
#
#
SHELL = /bin/sh
@ -52,7 +52,7 @@ dep:
$(CC) $(CPPFLAGS) $(CFLAGS) -MD -c $< -o $*.o
mv $*.d dep
O = stub.o memory.o statement.o
O = stub.o expression.o memory.o statement.o
ifeq (@WIN32@,yes)
TGTLDFLAGS=-L.. -livl

273
tgt-stub/expression.c Normal file
View File

@ -0,0 +1,273 @@
/*
* Copyright (c) 2007 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
*/
#ifdef HAVE_CVS_IDENT
#ident "$Id: expression.c,v 1.1 2007/01/16 05:44:16 steve Exp $"
#endif
# include "config.h"
# include "priv.h"
# include <stdlib.h>
# include <inttypes.h>
# include <assert.h>
static const char*vt_type_string(ivl_expr_t net)
{
return data_type_string(ivl_expr_value(net));
}
static void show_array_expression(ivl_expr_t net, unsigned ind)
{
ivl_signal_t sig = ivl_expr_signal(net);
const char*name = ivl_signal_basename(sig);
unsigned width = ivl_signal_width(sig);
const char*vt = vt_type_string(net);
fprintf(out, "%*sArray: %s, word_count=%u, width=%u, type=%s\n",
ind, "", name, ivl_signal_array_count(sig), width, vt);
}
static void show_binary_expression(ivl_expr_t net, unsigned ind)
{
unsigned width = ivl_expr_width(net);
const char*sign = ivl_expr_signed(net)? "signed" : "unsigned";
const char*vt = vt_type_string(net);
fprintf(out, "%*s<\"%c\" width=%u, %s, type=%s>\n", ind, "",
ivl_expr_opcode(net), width, sign, vt);
show_expression(ivl_expr_oper1(net), ind+3);
show_expression(ivl_expr_oper2(net), ind+3);
switch (ivl_expr_opcode(net)) {
case '*':
/* The width of multiply expressions is the sum of the
widths of the operands. This is slightly different
from the way the Verilog standard does it, but allows
us to keep operands smaller. */
width = ivl_expr_width(ivl_expr_oper1(net));
width += ivl_expr_width(ivl_expr_oper2(net));
if (ivl_expr_width(net) != width) {
fprintf(out, "%*sERROR: Result width incorrect\n",
ind+3, "");
stub_errors += 1;
}
break;
default:
break;
}
}
static void show_function_call(ivl_expr_t net, unsigned ind)
{
ivl_scope_t def = ivl_expr_def(net);
const char*vt = vt_type_string(net);
fprintf(out, "%*s<%s function %s>\n", ind, "",
vt, ivl_scope_name(def));
}
static void show_memory_expression(ivl_expr_t net, unsigned ind)
{
unsigned width = ivl_expr_width(net);
fprintf(out, "%*s<memory width=%u>\n", ind, "",
width);
}
static void show_signal_expression(ivl_expr_t net, unsigned ind)
{
unsigned width = ivl_expr_width(net);
const char*sign = ivl_expr_signed(net)? "signed" : "unsigned";
const char*vt = vt_type_string(net);
ivl_expr_t word = ivl_expr_oper1(net);
ivl_signal_t sig = ivl_expr_signal(net);
unsigned word_count = ivl_signal_array_count(sig);
fprintf(out, "%*s<signal=%s, words=%u, width=%u, %s type=%s>\n", ind, "",
ivl_expr_name(net), word_count, width, sign, vt);
/* If the expression refers to a signal array, then there must
also be a word select expression, and if the signal is not an
array, there must NOT be a word expression. */
if (word_count == 1 && word != 0) {
fprintf(out, "%*sERROR: Unexpected word expression\n", ind+2, "");
stub_errors += 1;
}
if (word_count > 1 && word == 0) {
fprintf(out, "%*sERROR: Missing word expression\n", ind+2, "");
stub_errors += 1;
}
if (word != 0) {
fprintf(out, "%*sAddress-0 word address:\n", ind+2, "");
show_expression(word, ind+2);
}
}
static void show_ternary_expression(ivl_expr_t net, unsigned ind)
{
unsigned width = ivl_expr_width(net);
const char*sign = ivl_expr_signed(net)? "signed" : "unsigned";
fprintf(out, "%*s<ternary width=%u, %s>\n", ind, "", width, sign);
show_expression(ivl_expr_oper1(net), ind+4);
show_expression(ivl_expr_oper2(net), ind+4);
show_expression(ivl_expr_oper3(net), ind+4);
if (ivl_expr_width(ivl_expr_oper2(net)) != width) {
fprintf(out, "ERROR: Width of TRUE expressions is %u, not %u\n",
ivl_expr_width(ivl_expr_oper2(net)), width);
stub_errors += 1;
}
if (ivl_expr_width(ivl_expr_oper3(net)) != width) {
fprintf(out, "ERROR: Width of FALSE expressions is %u, not %u\n",
ivl_expr_width(ivl_expr_oper3(net)), width);
stub_errors += 1;
}
}
void show_expression(ivl_expr_t net, unsigned ind)
{
unsigned idx;
const ivl_expr_type_t code = ivl_expr_type(net);
ivl_parameter_t par = ivl_expr_parameter(net);
unsigned width = ivl_expr_width(net);
const char*sign = ivl_expr_signed(net)? "signed" : "unsigned";
const char*vt = vt_type_string(net);
switch (code) {
case IVL_EX_ARRAY:
show_array_expression(net, ind);
break;
case IVL_EX_BINARY:
show_binary_expression(net, ind);
break;
case IVL_EX_CONCAT:
fprintf(out, "%*s<concat repeat=%u, width=%u, %s, type=%s>\n",
ind, "", ivl_expr_repeat(net), width, sign, vt);
for (idx = 0 ; idx < ivl_expr_parms(net) ; idx += 1)
show_expression(ivl_expr_parm(net, idx), ind+3);
break;
case IVL_EX_MEMORY:
show_memory_expression(net, ind);
break;
case IVL_EX_NUMBER: {
const char*bits = ivl_expr_bits(net);
fprintf(out, "%*s<number=%u'b", ind, "", width);
for (idx = width ; idx > 0 ; idx -= 1)
fprintf(out, "%c", bits[idx-1]);
fprintf(out, ", %s %s", sign, vt);
if (par != 0)
fprintf(out, ", parameter=%s",
ivl_parameter_basename(par));
fprintf(out, ">\n");
break;
}
case IVL_EX_SELECT:
/* The SELECT expression can be used to express part
select, or if the base is null vector extension. */
if (ivl_expr_oper2(net)) {
fprintf(out, "%*s<select: width=%u, %s>\n", ind, "",
width, sign);
show_expression(ivl_expr_oper1(net), ind+3);
show_expression(ivl_expr_oper2(net), ind+3);
} else {
fprintf(out, "%*s<expr pad: width=%u, %s>\n", ind, "",
width, sign);
show_expression(ivl_expr_oper1(net), ind+3);
}
break;
case IVL_EX_STRING:
fprintf(out, "%*s<string=\"%s\", width=%u", ind, "",
ivl_expr_string(net), ivl_expr_width(net));
if (par != 0)
fprintf(out, ", parameter=%s",
ivl_parameter_basename(par));
fprintf(out, ">\n");
break;
case IVL_EX_SFUNC:
fprintf(out, "%*s<function=\"%s\", width=%u, %s, type=%s>\n",
ind, "", ivl_expr_name(net), width, sign, vt);
{ unsigned cnt = ivl_expr_parms(net);
unsigned idx;
for (idx = 0 ; idx < cnt ; idx += 1)
show_expression(ivl_expr_parm(net, idx), ind+3);
}
break;
case IVL_EX_SIGNAL:
show_signal_expression(net, ind);
break;
case IVL_EX_TERNARY:
show_ternary_expression(net, ind);
break;
case IVL_EX_UNARY:
fprintf(out, "%*s<unary \"%c\" width=%u, %s>\n", ind, "",
ivl_expr_opcode(net), width, sign);
show_expression(ivl_expr_oper1(net), ind+4);
break;
case IVL_EX_UFUNC:
show_function_call(net, ind);
break;
case IVL_EX_REALNUM:
{
int idx;
union foo {
double rv;
unsigned char bv[sizeof(double)];
} tmp;
tmp.rv = ivl_expr_dvalue(net);
fprintf(out, "%*s<realnum=%f (", ind, "", tmp.rv);
for (idx = sizeof(double) ; idx > 0 ; idx -= 1)
fprintf(out, "%02x", tmp.bv[idx-1]);
fprintf(out, ")");
if (par != 0)
fprintf(out, ", parameter=%s",
ivl_parameter_basename(par));
fprintf(out, ">\n");
}
break;
default:
fprintf(out, "%*s<expr_type=%u>\n", ind, "", code);
break;
}
}

View File

@ -17,7 +17,7 @@
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#ifdef HAVE_CVS_IDENT
#ident "$Id: priv.h,v 1.3 2005/03/05 05:47:42 steve Exp $"
#ident "$Id: priv.h,v 1.4 2007/01/16 05:44:16 steve Exp $"
#endif
# include <ivl_target.h>
@ -47,3 +47,6 @@ extern void show_memory(ivl_memory_t mem);
*/
extern void show_statement(ivl_statement_t net, unsigned ind);
/*
*/
extern const char*data_type_string(ivl_variable_type_t vtype);

View File

@ -17,7 +17,7 @@
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#ifdef HAVE_CVS_IDENT
#ident "$Id: statement.c,v 1.10 2006/08/08 05:11:37 steve Exp $"
#ident "$Id: statement.c,v 1.11 2007/01/16 05:44:16 steve Exp $"
#endif
# include "config.h"
@ -56,12 +56,30 @@ static unsigned show_assign_lval(ivl_lval_t lval, unsigned ind)
} else {
ivl_signal_t sig = ivl_lval_sig(lval);
assert(sig);
fprintf(out, "%*s{name=%s width=%u lvwidth=%u}\n",
ind, "",
ivl_signal_name(sig),
ivl_signal_width(sig),
ivl_lval_width(lval));
if (ivl_lval_idx(lval)) {
fprintf(out, "%*sAddress-0 select expression:\n", ind+4, "");
show_expression(ivl_lval_idx(lval), ind+6);
if (ivl_signal_array_count(sig) <= 1) {
fprintf(out, "%*sERROR: Address on signal with "
"word count=%u\n", ind+4, "",
ivl_signal_array_count(sig));
stub_errors += 1;
}
} else if (ivl_signal_array_count(sig) > 1) {
fprintf(out, "%*sERROR: Address missing on signal with "
"word count=%u\n", ind+4, "",
ivl_signal_array_count(sig));
stub_errors += 1;
}
if (ivl_lval_mux(lval)) {
fprintf(out, "%*sBit select expression:\n", ind+4, "");
show_expression(ivl_lval_mux(lval), ind+8);

View File

@ -17,9 +17,16 @@
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#ifdef HAVE_CVS_IDENT
#ident "$Id: stub.c,v 1.142 2006/11/28 05:56:41 steve Exp $"
#ident "$Id: stub.c,v 1.143 2007/01/16 05:44:16 steve Exp $"
#endif
/*
* This is a sample target module. All this does is write to the
* output file some information about each object handle when each of
* the various object functions is called. This can be used to
* understand the behavior of the core as it uses a target module.
*/
# include "config.h"
# include "priv.h"
# include <stdlib.h>
@ -127,213 +134,6 @@ const char*data_type_string(ivl_variable_type_t vtype)
return vt;
}
const char*vt_type_string(ivl_expr_t net)
{
return data_type_string(ivl_expr_value(net));
}
void show_binary_expression(ivl_expr_t net, unsigned ind)
{
unsigned width = ivl_expr_width(net);
const char*sign = ivl_expr_signed(net)? "signed" : "unsigned";
const char*vt = vt_type_string(net);
fprintf(out, "%*s<\"%c\" width=%u, %s, type=%s>\n", ind, "",
ivl_expr_opcode(net), width, sign, vt);
show_expression(ivl_expr_oper1(net), ind+3);
show_expression(ivl_expr_oper2(net), ind+3);
switch (ivl_expr_opcode(net)) {
case '*':
/* The width of multiply expressions is the sum of the
widths of the operands. This is slightly different
from the way the Verilog standard does it, but allows
us to keep operands smaller. */
width = ivl_expr_width(ivl_expr_oper1(net));
width += ivl_expr_width(ivl_expr_oper2(net));
if (ivl_expr_width(net) != width) {
fprintf(out, "%*sERROR: Result width incorrect\n",
ind+3, "");
stub_errors += 1;
}
break;
default:
break;
}
}
void show_function_call(ivl_expr_t net, unsigned ind)
{
ivl_scope_t def = ivl_expr_def(net);
const char*vt = vt_type_string(net);
fprintf(out, "%*s<%s function %s>\n", ind, "",
vt, ivl_scope_name(def));
}
void show_memory_expression(ivl_expr_t net, unsigned ind)
{
unsigned width = ivl_expr_width(net);
fprintf(out, "%*s<memory width=%u>\n", ind, "",
width);
}
/*
* This is a sample target module. All this does is write to the
* output file some information about each object handle when each of
* the various object functions is called. This can be used to
* understand the behavior of the core as it uses a target module.
*/
void show_ternary_expression(ivl_expr_t net, unsigned ind)
{
unsigned width = ivl_expr_width(net);
const char*sign = ivl_expr_signed(net)? "signed" : "unsigned";
fprintf(out, "%*s<ternary width=%u, %s>\n", ind, "", width, sign);
show_expression(ivl_expr_oper1(net), ind+4);
show_expression(ivl_expr_oper2(net), ind+4);
show_expression(ivl_expr_oper3(net), ind+4);
if (ivl_expr_width(ivl_expr_oper2(net)) != width) {
fprintf(out, "ERROR: Width of TRUE expressions is %u, not %u\n",
ivl_expr_width(ivl_expr_oper2(net)), width);
stub_errors += 1;
}
if (ivl_expr_width(ivl_expr_oper3(net)) != width) {
fprintf(out, "ERROR: Width of FALSE expressions is %u, not %u\n",
ivl_expr_width(ivl_expr_oper3(net)), width);
stub_errors += 1;
}
}
void show_expression(ivl_expr_t net, unsigned ind)
{
unsigned idx;
const ivl_expr_type_t code = ivl_expr_type(net);
ivl_parameter_t par = ivl_expr_parameter(net);
unsigned width = ivl_expr_width(net);
const char*sign = ivl_expr_signed(net)? "signed" : "unsigned";
const char*vt = vt_type_string(net);
switch (code) {
case IVL_EX_BINARY:
show_binary_expression(net, ind);
break;
case IVL_EX_CONCAT:
fprintf(out, "%*s<concat repeat=%u, width=%u, %s, type=%s>\n",
ind, "", ivl_expr_repeat(net), width, sign, vt);
for (idx = 0 ; idx < ivl_expr_parms(net) ; idx += 1)
show_expression(ivl_expr_parm(net, idx), ind+3);
break;
case IVL_EX_MEMORY:
show_memory_expression(net, ind);
break;
case IVL_EX_NUMBER: {
const char*bits = ivl_expr_bits(net);
fprintf(out, "%*s<number=%u'b", ind, "", width);
for (idx = width ; idx > 0 ; idx -= 1)
fprintf(out, "%c", bits[idx-1]);
fprintf(out, ", %s %s", sign, vt);
if (par != 0)
fprintf(out, ", parameter=%s",
ivl_parameter_basename(par));
fprintf(out, ">\n");
break;
}
case IVL_EX_SELECT:
/* The SELECT expression can be used to express part
select, or if the base is null vector extension. */
if (ivl_expr_oper2(net)) {
fprintf(out, "%*s<select: width=%u, %s>\n", ind, "",
width, sign);
show_expression(ivl_expr_oper1(net), ind+3);
show_expression(ivl_expr_oper2(net), ind+3);
} else {
fprintf(out, "%*s<expr pad: width=%u, %s>\n", ind, "",
width, sign);
show_expression(ivl_expr_oper1(net), ind+3);
}
break;
case IVL_EX_STRING:
fprintf(out, "%*s<string=\"%s\", width=%u", ind, "",
ivl_expr_string(net), ivl_expr_width(net));
if (par != 0)
fprintf(out, ", parameter=%s",
ivl_parameter_basename(par));
fprintf(out, ">\n");
break;
case IVL_EX_SFUNC:
fprintf(out, "%*s<function=\"%s\", width=%u, %s, type=%s>\n",
ind, "", ivl_expr_name(net), width, sign, vt);
{ unsigned cnt = ivl_expr_parms(net);
unsigned idx;
for (idx = 0 ; idx < cnt ; idx += 1)
show_expression(ivl_expr_parm(net, idx), ind+3);
}
break;
case IVL_EX_SIGNAL:
fprintf(out, "%*s<signal=%s, width=%u, %s type=%s>\n", ind, "",
ivl_expr_name(net), width, sign, vt);
break;
case IVL_EX_TERNARY:
show_ternary_expression(net, ind);
break;
case IVL_EX_UNARY:
fprintf(out, "%*s<unary \"%c\" width=%u, %s>\n", ind, "",
ivl_expr_opcode(net), width, sign);
show_expression(ivl_expr_oper1(net), ind+4);
break;
case IVL_EX_UFUNC:
show_function_call(net, ind);
break;
case IVL_EX_REALNUM:
{
int idx;
union foo {
double rv;
unsigned char bv[sizeof(double)];
} tmp;
tmp.rv = ivl_expr_dvalue(net);
fprintf(out, "%*s<realnum=%f (", ind, "", tmp.rv);
for (idx = sizeof(double) ; idx > 0 ; idx -= 1)
fprintf(out, "%02x", tmp.bv[idx-1]);
fprintf(out, ")");
if (par != 0)
fprintf(out, ", parameter=%s",
ivl_parameter_basename(par));
fprintf(out, ">\n");
}
break;
default:
fprintf(out, "%*s<expr_type=%u>\n", ind, "", code);
break;
}
}
/*
* The compare-like LPM nodes have input widths that match the
* ivl_lpm_width() value, and an output width of 1. This function
@ -388,6 +188,35 @@ static void show_lpm_add(ivl_lpm_t net)
show_lpm_arithmetic_pins(net);
}
static void show_lpm_array(ivl_lpm_t net)
{
ivl_nexus_t nex;
unsigned width = ivl_lpm_width(net);
ivl_signal_t array = ivl_lpm_array(net);
fprintf(out, " LPM_ARRAY: <width=%u, signal=%s>\n",
width, ivl_signal_basename(array));
nex = ivl_lpm_q(net, 0);
assert(nex);
fprintf(out, " Q: %s\n", ivl_nexus_name(nex));
nex = ivl_lpm_select(net);
assert(nex);
fprintf(out, " Address: %s (address width=%u)\n",
ivl_nexus_name(nex), ivl_lpm_selects(net));
if (width_of_nexus(ivl_lpm_q(net,0)) != width) {
fprintf(out, " ERROR: Data Q width doesn't match "
"nexus width=%u\n", width_of_nexus(ivl_lpm_q(net,0)));
stub_errors += 1;
}
if (ivl_signal_width(array) != width) {
fprintf(out, " ERROR: Data width doesn't match "
"word width=%u\n", ivl_signal_width(array));
stub_errors += 1;
}
}
static void show_lpm_divide(ivl_lpm_t net)
{
unsigned width = ivl_lpm_width(net);
@ -735,42 +564,6 @@ static void show_lpm_part_bi(ivl_lpm_t net)
}
static void show_lpm_ram(ivl_lpm_t net)
{
ivl_nexus_t nex;
unsigned width = ivl_lpm_width(net);
ivl_memory_t mem = ivl_lpm_memory(net);
fprintf(out, " LPM_RAM: <width=%u>\n", width);
nex = ivl_lpm_q(net, 0);
assert(nex);
fprintf(out, " Q: %s\n", ivl_nexus_name(nex));
nex = ivl_lpm_select(net);
fprintf(out, " Address: %s (address width=%u)\n",
ivl_nexus_name(nex), ivl_lpm_selects(net));
if (width_of_nexus(ivl_lpm_q(net,0)) != width) {
fprintf(out, " ERROR: Data width doesn't match "
"nexus width=%u\n", width_of_nexus(ivl_lpm_q(net,0)));
stub_errors += 1;
}
if (width_of_nexus(ivl_lpm_select(net)) != ivl_lpm_selects(net)) {
fprintf(out, " ERROR: Width of address doesn't match "
"nexus width=%u\n", width_of_nexus(ivl_lpm_select(net)));
stub_errors += 1;
}
/* The width of the port must match the width of the memory
word. the compile assures that for us. */
if (width != ivl_memory_width(mem)) {
fprintf(out, " ERROR: Width doesn't match"
" memory word width=%u\n", ivl_memory_width(mem));
stub_errors += 1;
}
}
/*
* The reduction operators have similar characteristics and are
* displayed here.
@ -983,6 +776,10 @@ static void show_lpm(ivl_lpm_t net)
show_lpm_add(net);
break;
case IVL_LPM_ARRAY:
show_lpm_array(net);
break;
case IVL_LPM_DIVIDE:
show_lpm_divide(net);
break;
@ -1012,10 +809,6 @@ static void show_lpm(ivl_lpm_t net)
show_lpm_concat(net);
break;
case IVL_LPM_RAM:
show_lpm_ram(net);
break;
case IVL_LPM_RE_AND:
case IVL_LPM_RE_NAND:
case IVL_LPM_RE_NOR:
@ -1203,6 +996,57 @@ static void signal_nexus_const(ivl_signal_t sig,
}
}
static void show_nexus_details(ivl_signal_t net, ivl_nexus_t nex)
{
unsigned idx;
for (idx = 0 ; idx < ivl_nexus_ptrs(nex) ; idx += 1) {
ivl_net_const_t con;
ivl_net_logic_t log;
ivl_lpm_t lpm;
ivl_signal_t sig;
ivl_nexus_ptr_t ptr = ivl_nexus_ptr(nex, idx);
const char*dr0 = str_tab[ivl_nexus_ptr_drive0(ptr)];
const char*dr1 = str_tab[ivl_nexus_ptr_drive1(ptr)];
if ((sig = ivl_nexus_ptr_sig(ptr))) {
fprintf(out, " SIG %s word=%u (%s0, %s1)",
ivl_signal_name(sig), ivl_nexus_ptr_pin(ptr), dr0, dr1);
if (ivl_signal_width(sig) != ivl_signal_width(net)) {
fprintf(out, " (ERROR: Width=%u)",
ivl_signal_width(sig));
stub_errors += 1;
}
if (ivl_signal_data_type(sig) != ivl_signal_data_type(net)) {
fprintf(out, " (ERROR: data type mismatch)");
stub_errors += 1;
}
fprintf(out, "\n");
} else if ((log = ivl_nexus_ptr_log(ptr))) {
fprintf(out, " LOG %s.%s[%u] (%s0, %s1)\n",
ivl_scope_name(ivl_logic_scope(log)),
ivl_logic_basename(log),
ivl_nexus_ptr_pin(ptr), dr0, dr1);
} else if ((lpm = ivl_nexus_ptr_lpm(ptr))) {
fprintf(out, " LPM %s.%s (%s0, %s1)\n",
ivl_scope_name(ivl_lpm_scope(lpm)),
ivl_lpm_basename(lpm), dr0, dr1);
} else if ((con = ivl_nexus_ptr_con(ptr))) {
signal_nexus_const(net, ptr, con);
} else {
fprintf(out, " ?[%u] (%s0, %s1)\n",
ivl_nexus_ptr_pin(ptr), dr0, dr1);
}
}
}
static void show_signal(ivl_signal_t net)
{
@ -1268,68 +1112,19 @@ static void show_signal(ivl_signal_t net)
break;
}
nex = ivl_signal_nex(net);
for (idx = 0 ; idx < ivl_signal_array_count(net) ; idx += 1) {
fprintf(out, " %s %s %s%s[%d:%d] %s <width=%u> nexus=%s\n",
type, sign, port, data_type,
ivl_signal_msb(net), ivl_signal_lsb(net),
ivl_signal_basename(net), ivl_signal_width(net),
ivl_nexus_name(nex));
nex = ivl_signal_nex(net, idx);
fprintf(out, " %s %s %s%s[%d:%d] %s[word=%u, adr=%d] <width=%u> nexus=%s\n",
type, sign, port, data_type,
ivl_signal_msb(net), ivl_signal_lsb(net),
ivl_signal_basename(net),
idx, ivl_signal_array_base(net)+idx,
ivl_signal_width(net),
ivl_nexus_name(nex));
for (idx = 0 ; idx < ivl_nexus_ptrs(nex) ; idx += 1) {
ivl_net_const_t con;
ivl_net_logic_t log;
ivl_lpm_t lpm;
ivl_signal_t sig;
ivl_nexus_ptr_t ptr = ivl_nexus_ptr(nex, idx);
const char*dr0 = str_tab[ivl_nexus_ptr_drive0(ptr)];
const char*dr1 = str_tab[ivl_nexus_ptr_drive1(ptr)];
if ((sig = ivl_nexus_ptr_sig(ptr))) {
fprintf(out, " SIG %s (%s0, %s1)",
ivl_signal_name(sig), dr0, dr1);
/* Only pin-0 of signals is used. If this is
something other then pin-0, report an error. */
if (ivl_nexus_ptr_pin(ptr) != 0) {
fprintf(out, " (pin=%u, should be 0)",
ivl_nexus_ptr_pin(ptr));
stub_errors += 1;
}
if (ivl_signal_width(sig) != ivl_signal_width(net)) {
fprintf(out, " (ERROR: Width=%u)",
ivl_signal_width(sig));
stub_errors += 1;
}
if (ivl_signal_data_type(sig) != ivl_signal_data_type(net)) {
fprintf(out, " (ERROR: data type mismatch)");
stub_errors += 1;
}
fprintf(out, "\n");
} else if ((log = ivl_nexus_ptr_log(ptr))) {
fprintf(out, " LOG %s.%s[%u] (%s0, %s1)\n",
ivl_scope_name(ivl_logic_scope(log)),
ivl_logic_basename(log),
ivl_nexus_ptr_pin(ptr), dr0, dr1);
} else if ((lpm = ivl_nexus_ptr_lpm(ptr))) {
fprintf(out, " LPM %s.%s (%s0, %s1)\n",
ivl_scope_name(ivl_lpm_scope(lpm)),
ivl_lpm_basename(lpm), dr0, dr1);
} else if ((con = ivl_nexus_ptr_con(ptr))) {
signal_nexus_const(net, ptr, con);
} else {
fprintf(out, " ?[%u] (%s0, %s1)\n",
ivl_nexus_ptr_pin(ptr), dr0, dr1);
}
show_nexus_details(net, nex);
}
for (idx = 0 ; idx < ivl_signal_npath(net) ; idx += 1) {
@ -1677,6 +1472,12 @@ int target_design(ivl_design_t des)
/*
* $Log: stub.c,v $
* Revision 1.143 2007/01/16 05:44:16 steve
* Major rework of array handling. Memories are replaced with the
* more general concept of arrays. The NetMemory and NetEMemory
* classes are removed from the ivl core program, and the IVL_LPM_RAM
* lpm type is removed from the ivl_target API.
*
* Revision 1.142 2006/11/28 05:56:41 steve
* Dump nand logic.
*

View File

@ -17,7 +17,7 @@
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#ifdef HAVE_CVS_IDENT
#ident "$Id: draw_mux.c,v 1.13 2005/10/12 17:26:17 steve Exp $"
#ident "$Id: draw_mux.c,v 1.14 2007/01/16 05:44:16 steve Exp $"
#endif
# include "vvp_priv.h"
@ -76,9 +76,9 @@ static void draw_lpm_mux_nest(ivl_lpm_t net, const char*muxz)
for (idx = 0 ; idx < (ivl_lpm_size(net) >> level); idx += 2) {
fprintf(vvp_out, "L_%p/%d/%d .functor %s %u",
net, width, level, muxz, idx);
fprintf(vvp_out, ", L_%p/%d/%d", net, level-1, idx/2+0);
fprintf(vvp_out, ", L_%p/%d/%d", net, level-1, idx/2+1);
net, level, idx/2, muxz, width);
fprintf(vvp_out, ", L_%p/%d/%d", net, level-1, idx+0);
fprintf(vvp_out, ", L_%p/%d/%d", net, level-1, idx+1);
fprintf(vvp_out, ", L_%p/%ds", net, level);
fprintf(vvp_out, ", C4<>;\n");
}
@ -127,6 +127,12 @@ void draw_lpm_mux(ivl_lpm_t net)
/*
* $Log: draw_mux.c,v $
* Revision 1.14 2007/01/16 05:44:16 steve
* Major rework of array handling. Memories are replaced with the
* more general concept of arrays. The NetMemory and NetEMemory
* classes are removed from the ivl core program, and the IVL_LPM_RAM
* lpm type is removed from the ivl_target API.
*
* Revision 1.13 2005/10/12 17:26:17 steve
* MUX nodes get inputs from nets, not from net inputs,
* Detect and draw alias nodes to reduce net size and

View File

@ -17,7 +17,7 @@
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#ifdef HAVE_CVS_IDENT
#ident "$Id: draw_ufunc.c,v 1.1 2005/07/13 04:52:31 steve Exp $"
#ident "$Id: draw_ufunc.c,v 1.2 2007/01/16 05:44:16 steve Exp $"
#endif
# include "vvp_priv.h"
@ -32,10 +32,12 @@ static void function_argument_logic(ivl_signal_t port, ivl_expr_t exp)
{
struct vector_info res;
/* ports cannot be arrays. */
assert(ivl_signal_array_count(port) == 1);
res = draw_eval_expr_wid(exp, ivl_signal_width(port), 0);
assert(res.wid <= ivl_signal_width(port));
fprintf(vvp_out, " %%set/v V_%s, %u, %u;\n",
vvp_signal_label(port), res.base, res.wid);
fprintf(vvp_out, " %%set/v v%p_0, %u, %u;\n", port, res.base, res.wid);
clr_vector(res);
}
@ -44,8 +46,10 @@ static void function_argument_real(ivl_signal_t port, ivl_expr_t exp)
{
int res = draw_eval_real(exp);
fprintf(vvp_out, " %%set/wr V_%s, %d;\n",
vvp_signal_label(port), res);
/* ports cannot be arrays. */
assert(ivl_signal_array_count(port) == 1);
fprintf(vvp_out, " %%set/wr v%p_0, %d;\n", port, res);
}
static void draw_function_argument(ivl_signal_t port, ivl_expr_t exp)
@ -113,8 +117,9 @@ struct vector_info draw_ufunc_expr(ivl_expr_t exp, unsigned wid)
if (load_wid > ivl_signal_width(retval))
load_wid = ivl_signal_width(retval);
fprintf(vvp_out, " %%load/v %u, V_%s, %u;\n",
res.base, vvp_signal_label(retval), load_wid);
assert(ivl_signal_array_count(retval) == 1);
fprintf(vvp_out, " %%load/v %u, v%p_0, %u;\n",
res.base, retval, load_wid);
if (load_wid < swid)
fprintf(vvp_out, " %%mov %u, 0, %u;\n",
@ -148,10 +153,12 @@ int draw_ufunc_real(ivl_expr_t exp)
fprintf(vvp_out, ", S_%p;\n", def);
fprintf(vvp_out, " %%join;\n");
/* Return value signal cannot be an array. */
assert(ivl_signal_array_count(retval) == 1);
/* Load the result into a word. */
res = allocate_word();
fprintf(vvp_out, " %%load/wr %d, V_%s;\n",
res, vvp_signal_label(retval));
fprintf(vvp_out, " %%load/wr %d, v%p_0;\n", res, retval);
return res;
}

View File

@ -17,7 +17,7 @@
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#ifdef HAVE_CVS_IDENT
#ident "$Id: draw_vpi.c,v 1.13 2005/10/11 18:30:50 steve Exp $"
#ident "$Id: draw_vpi.c,v 1.14 2007/01/16 05:44:16 steve Exp $"
#endif
# include "vvp_priv.h"
@ -75,6 +75,7 @@ static void draw_vpi_taskfunc_args(const char*call_string,
with VPI handles of their own. Therefore, skip
them in the process of evaluating expressions. */
case IVL_EX_NONE:
case IVL_EX_ARRAY:
case IVL_EX_NUMBER:
case IVL_EX_STRING:
case IVL_EX_EVENT:
@ -107,7 +108,8 @@ static void draw_vpi_taskfunc_args(const char*call_string,
} else if (ivl_expr_signed(expr) !=
ivl_signal_signed(ivl_expr_signal(expr))) {
break;
} else if (ivl_signal_array_count(ivl_expr_signal(expr))>1){
break;
} else {
continue;
}
@ -153,6 +155,10 @@ static void draw_vpi_taskfunc_args(const char*call_string,
fprintf(vvp_out, ", \" \"");
continue;
case IVL_EX_ARRAY:
fprintf(vvp_out, ", v%p", ivl_expr_signal(expr));
continue;
case IVL_EX_NUMBER: {
unsigned bit, wid = ivl_expr_width(expr);
const char*bits = ivl_expr_bits(expr);
@ -176,13 +182,16 @@ static void draw_vpi_taskfunc_args(const char*call_string,
ivl_signal_signed(ivl_expr_signal(expr))) {
break;
} else if (ivl_signal_array_count(ivl_expr_signal(expr))>1){
break;
} else {
fprintf(vvp_out, ", V_%s",
vvp_signal_label(ivl_expr_signal(expr)));
ivl_signal_t sig = ivl_expr_signal(expr);
assert(ivl_signal_array_count(sig) == 1);
fprintf(vvp_out, ", v%p_0", sig);
continue;
}
fprintf(vvp_out, ", V_%s",
vvp_signal_label(ivl_expr_signal(expr)));
assert(0);
continue;
case IVL_EX_STRING:
@ -291,6 +300,12 @@ int draw_vpi_rfunc_call(ivl_expr_t fnet)
/*
* $Log: draw_vpi.c,v $
* Revision 1.14 2007/01/16 05:44:16 steve
* Major rework of array handling. Memories are replaced with the
* more general concept of arrays. The NetMemory and NetEMemory
* classes are removed from the ivl core program, and the IVL_LPM_RAM
* lpm type is removed from the ivl_target API.
*
* Revision 1.13 2005/10/11 18:30:50 steve
* Remove obsolete vvp_memory_label function.
*

View File

@ -17,7 +17,7 @@
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#ifdef HAVE_CVS_IDENT
#ident "$Id: eval_expr.c,v 1.130 2006/02/02 02:43:59 steve Exp $"
#ident "$Id: eval_expr.c,v 1.131 2007/01/16 05:44:16 steve Exp $"
#endif
# include "vvp_priv.h"
@ -1531,21 +1531,39 @@ static struct vector_info draw_string_expr(ivl_expr_t exp, unsigned wid)
*/
static void draw_signal_dest(ivl_expr_t exp, struct vector_info res)
{
unsigned idx;
unsigned swid = ivl_expr_width(exp);
ivl_signal_t sig = ivl_expr_signal(exp);
unsigned word = 0;
if (swid > res.wid)
swid = res.wid;
/* If this is an access to an array, handle that by emiting a
load/av instruction. */
if (ivl_signal_array_count(sig) > 1) {
ivl_expr_t ix = ivl_expr_oper1(exp);
if (!number_is_immediate(ix, 8*sizeof(unsigned long))) {
draw_eval_expr_into_integer(ix, 3);
fprintf(vvp_out, " %%load/av %u, v%p, %u;\n",
res.base, sig, swid);
return;
}
/* The index is constant, so we can return to direct
readout with the specific word selected. */
word = get_number_immediate(ix);
}
/* If this is a REG (a variable) then I can do a vector read. */
fprintf(vvp_out, " %%load/v %u, V_%s, %u;\n",
res.base, vvp_signal_label(sig), swid);
fprintf(vvp_out, " %%load/v %u, v%p_%u, %u;\n",
res.base, sig, word, swid);
/* Pad the signal value with zeros. */
if (swid < res.wid) {
if (ivl_expr_signed(exp)) {
unsigned idx;
for (idx = swid ; idx < res.wid ; idx += 1)
fprintf(vvp_out, " %%mov %u, %u, 1;\n",
res.base+idx, res.base+swid-1);
@ -1671,6 +1689,24 @@ static struct vector_info draw_select_signal(ivl_expr_t sube,
struct vector_info res;
unsigned idx;
/* Use this word of the signal. */
unsigned use_word = 0;
/* If this is an access to an array, handle that by emiting a
load/av instruction. */
if (ivl_signal_array_count(sig) > 1) {
ivl_expr_t ix = ivl_expr_oper1(sube);
if (!number_is_immediate(ix, 8*sizeof(unsigned long))) {
draw_eval_expr_into_integer(ix, 3);
assert(0); /* XXXX Don't know how to load part
select! */
return res;
}
/* The index is constant, so we can return to direct
readout with the specific word selected. */
use_word = get_number_immediate(ix);
}
shiv = draw_eval_expr(bit_idx, STUFF_OK_XZ|STUFF_OK_RO);
fprintf(vvp_out, " %%ix/get 0, %u, %u;\n", shiv.base, shiv.wid);
@ -1683,8 +1719,8 @@ static struct vector_info draw_select_signal(ivl_expr_t sube,
if (shiv.base == 0 && ivl_expr_width(sube) == wid) {
res.base = allocate_vector(wid);
res.wid = wid;
fprintf(vvp_out, " %%load/v %u, V_%p, %u;\n",
res.base, sig, ivl_expr_width(sube));
fprintf(vvp_out, " %%load/v %u, v%p_%u, %u;\n",
res.base, sig, use_word, ivl_expr_width(sube));
return res;
}
@ -1698,10 +1734,10 @@ static struct vector_info draw_select_signal(ivl_expr_t sube,
res.base = allocate_vector(ivl_expr_width(sube));
res.wid = ivl_expr_width(sube);
fprintf(vvp_out, " %%load/v %u, V_%p, %u; Only need %u bits\n",
res.base, sig, ivl_expr_width(sube), wid);
fprintf(vvp_out, " %%load/v %u, v%p_%u, %u; Only need %u bits\n",
res.base, sig, use_word, ivl_expr_width(sube), wid);
save_signal_lookaside(res.base, sig, res.wid);
save_signal_lookaside(res.base, sig, use_word, res.wid);
{
struct vector_info tmp;
@ -1724,8 +1760,8 @@ static struct vector_info draw_select_signal(ivl_expr_t sube,
ivl_expr_width(sube), wid);
break;
}
fprintf(vvp_out, " %%load/x.p %u, V_%p, 0;\n",
res.base+idx, sig);
fprintf(vvp_out, " %%load/x.p %u, v%p_%u, 0;\n",
res.base+idx, sig, use_word);
}
return res;
@ -2209,6 +2245,12 @@ struct vector_info draw_eval_expr(ivl_expr_t exp, int stuff_ok_flag)
/*
* $Log: eval_expr.c,v $
* Revision 1.131 2007/01/16 05:44:16 steve
* Major rework of array handling. Memories are replaced with the
* more general concept of arrays. The NetMemory and NetEMemory
* classes are removed from the ivl core program, and the IVL_LPM_RAM
* lpm type is removed from the ivl_target API.
*
* Revision 1.130 2006/02/02 02:43:59 steve
* Allow part selects of memory words in l-values.
*

View File

@ -17,7 +17,7 @@
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#ifdef HAVE_CVS_IDENT
#ident "$Id: eval_real.c,v 1.16 2006/10/10 23:54:28 steve Exp $"
#ident "$Id: eval_real.c,v 1.17 2007/01/16 05:44:16 steve Exp $"
#endif
/*
@ -245,9 +245,22 @@ static int draw_signal_real_real(ivl_expr_t exp)
{
ivl_signal_t sig = ivl_expr_signal(exp);
int res = allocate_word();
unsigned long word = 0;
fprintf(vvp_out, " %%load/wr %d, V_%s;\n",
res, vvp_signal_label(sig));
if (ivl_signal_array_count(sig) > 1) {
ivl_expr_t ix = ivl_expr_oper1(exp);
if (!number_is_immediate(ix, 8*sizeof(word))) {
/* XXXX Need to generate a %load/ar instruction. */
assert(0);
return res;
}
/* The index is constant, so we can return to direct
readout with the specific word selected. */
word = get_number_immediate(ix);
}
fprintf(vvp_out, " %%load/wr %d, v%p_%lu;\n", res, sig, word);
return res;
}
@ -326,6 +339,12 @@ int draw_eval_real(ivl_expr_t exp)
/*
* $Log: eval_real.c,v $
* Revision 1.17 2007/01/16 05:44:16 steve
* Major rework of array handling. Memories are replaced with the
* more general concept of arrays. The NetMemory and NetEMemory
* classes are removed from the ivl core program, and the IVL_LPM_RAM
* lpm type is removed from the ivl_target API.
*
* Revision 1.16 2006/10/10 23:54:28 steve
* Fix rendering of signed numbers in real expressions.
*

View File

@ -16,7 +16,7 @@
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#ifdef HAVE_CVS_IDENT
#ident "$Id: vector.c,v 1.7 2005/09/17 01:01:00 steve Exp $"
#ident "$Id: vector.c,v 1.8 2007/01/16 05:44:16 steve Exp $"
#endif
# include "vvp_priv.h"
@ -32,6 +32,7 @@
static struct allocation_score_s {
ivl_expr_t exp;
ivl_signal_t sig;
unsigned sig_word;
unsigned exp_bit : 24;
unsigned sig_bit : 24;
unsigned alloc : 8;
@ -56,9 +57,10 @@ static inline void set_exp(unsigned addr, ivl_expr_t exp, unsigned ebit)
allocation_map[addr].exp_bit = ebit;
}
static inline void set_sig(unsigned addr, ivl_signal_t exp, unsigned ebit)
static inline void set_sig(unsigned addr, ivl_signal_t exp, unsigned sig_word, unsigned ebit)
{
allocation_map[addr].sig = exp;
allocation_map[addr].sig_word = sig_word;
allocation_map[addr].sig_bit = ebit;
}
@ -139,7 +141,7 @@ void clear_expression_lookaside(void)
for (idx = 0 ; idx < lookaside_top ; idx += 1) {
set_exp(idx, 0, 0);
set_sig(idx, 0, 0);
set_sig(idx, 0, 0, 0);
}
lookaside_top = 0;
@ -157,14 +159,14 @@ void save_expression_lookaside(unsigned addr, ivl_expr_t exp, unsigned wid)
bits. */
for (idx = 0 ; idx < wid ; idx += 1) {
set_exp(addr+idx, exp, idx);
set_sig(addr+idx, 0, 0);
set_sig(addr+idx, 0, 0, 0);
}
if ((addr+wid) > lookaside_top)
lookaside_top = addr+wid;
}
void save_signal_lookaside(unsigned addr, ivl_signal_t sig, unsigned wid)
void save_signal_lookaside(unsigned addr, ivl_signal_t sig, unsigned sig_word, unsigned wid)
{
unsigned idx;
/* Don't bind any of hte low bits to a signal. */
@ -174,7 +176,7 @@ void save_signal_lookaside(unsigned addr, ivl_signal_t sig, unsigned wid)
assert((addr+wid) <= MAX_VEC);
for (idx = 0 ; idx < wid ; idx += 1)
set_sig(addr+idx, sig, idx);
set_sig(addr+idx, sig, sig_word, idx);
if ((addr+wid) > lookaside_top)
lookaside_top = addr+wid;
@ -321,6 +323,12 @@ unsigned allocate_vector_exp(ivl_expr_t exp, unsigned wid,
/*
* $Log: vector.c,v $
* Revision 1.8 2007/01/16 05:44:16 steve
* Major rework of array handling. Memories are replaced with the
* more general concept of arrays. The NetMemory and NetEMemory
* classes are removed from the ivl core program, and the IVL_LPM_RAM
* lpm type is removed from the ivl_target API.
*
* Revision 1.7 2005/09/17 01:01:00 steve
* More robust use of precalculated expressions, and
* Separate lookaside for written variables that can

View File

@ -19,7 +19,7 @@
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#ifdef HAVE_CVS_IDENT
#ident "$Id: vvp_priv.h,v 1.40 2006/02/02 02:43:59 steve Exp $"
#ident "$Id: vvp_priv.h,v 1.41 2007/01/16 05:44:16 steve Exp $"
#endif
# include "vvp_config.h"
@ -212,7 +212,7 @@ extern void save_expression_lookaside(unsigned addr,
ivl_expr_t exp,
unsigned wid);
extern void save_signal_lookaside(unsigned addr,
ivl_signal_t sig,
ivl_signal_t sig, unsigned use_word,
unsigned wid);
extern unsigned allocate_vector_exp(ivl_expr_t exp, unsigned wid,
@ -252,6 +252,12 @@ extern unsigned thread_count;
/*
* $Log: vvp_priv.h,v $
* Revision 1.41 2007/01/16 05:44:16 steve
* Major rework of array handling. Memories are replaced with the
* more general concept of arrays. The NetMemory and NetEMemory
* classes are removed from the ivl core program, and the IVL_LPM_RAM
* lpm type is removed from the ivl_target API.
*
* Revision 1.40 2006/02/02 02:43:59 steve
* Allow part selects of memory words in l-values.
*

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2001-2005 Stephen Williams (steve@icarus.com)
* Copyright (c) 2001-2007 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
@ -17,7 +17,7 @@
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#ifdef HAVE_CVS_IDENT
#ident "$Id: vvp_process.c,v 1.126 2006/10/05 01:37:34 steve Exp $"
#ident "$Id: vvp_process.c,v 1.127 2007/01/16 05:44:16 steve Exp $"
#endif
# include "vvp_priv.h"
@ -78,6 +78,12 @@ static void set_to_lvariable(ivl_lval_t lval,
ivl_expr_t part_off_ex = ivl_lval_part_off(lval);
unsigned part_off = 0;
/* Although Verilog doesn't support it, we'll handle
here the case of an l-value part select of an array
word if the address is constant. */
ivl_expr_t word_ix = ivl_lval_idx(lval);
unsigned long use_word = 0;
if (part_off_ex == 0) {
part_off = 0;
} else if (number_is_immediate(part_off_ex, 64)) {
@ -85,6 +91,14 @@ static void set_to_lvariable(ivl_lval_t lval,
part_off_ex = 0;
}
/* If the word index is a constand expression, then evaluate
it to select the word, and pay no further heed to the
expression itself. */
if (word_ix && number_is_immediate(word_ix, 8*sizeof(use_word))) {
use_word = get_number_immediate(word_ix);
word_ix = 0;
}
if (ivl_lval_mux(lval))
part_off_ex = ivl_lval_mux(lval);
@ -95,12 +109,13 @@ static void set_to_lvariable(ivl_lval_t lval,
a bit-select l-val. Presumably, the x0 index register
has been loaded wit the result of the evaluated
part select base expression. */
assert(!word_ix);
draw_eval_expr_into_integer(part_off_ex, 0);
fprintf(vvp_out, " %%jmp/1 t_%u, 4;\n", skip_set);
fprintf(vvp_out, " %%set/x0 V_%s, %u, %u;\n",
vvp_signal_label(sig), bit, wid);
fprintf(vvp_out, " %%set/x0 v%p_%lu, %u, %u;\n",
sig, use_word, bit, wid);
fprintf(vvp_out, "t_%u ;\n", skip_set);
} else if (part_off>0 || ivl_lval_width(lval)!=ivl_signal_width(sig)) {
@ -108,15 +123,35 @@ static void set_to_lvariable(ivl_lval_t lval,
offset. Load that into index x0 and generate a
vector set instruction. */
assert(ivl_lval_width(lval) == wid);
assert(!word_ix);
fprintf(vvp_out, " %%ix/load 0, %u;\n", part_off);
fprintf(vvp_out, " %%set/x0 V_%s, %u, %u;\n",
vvp_signal_label(sig), bit, wid);
fprintf(vvp_out, " %%set/x0 v%p_%lu, %u, %u;\n",
sig, use_word, bit, wid);
} else if (ivl_signal_array_count(sig) > 1) {
/* If the word index is a constant, then we can write
directly to the word and save the index calculation. */
if (word_ix == 0) {
fprintf(vvp_out, " %%set/v v%p_%lu, %u, %u;\n",
sig, use_word, bit, wid);
} else {
unsigned skip_set = transient_id++;
unsigned index_reg = 3;
draw_eval_expr_into_integer(word_ix, index_reg);
fprintf(vvp_out, " %%jmp/1 t_%u, 4;\n", skip_set);
fprintf(vvp_out, " %%ix/load 1, 0;\n");
fprintf(vvp_out, " %%set/av v%p, %u, %u;\n",
sig, bit, wid);
fprintf(vvp_out, "t_%u ;\n", skip_set);
}
} else {
save_signal_lookaside(bit, sig, wid);
fprintf(vvp_out, " %%set/v V_%s, %u, %u;\n",
vvp_signal_label(sig), bit, wid);
save_signal_lookaside(bit, sig, use_word, wid);
fprintf(vvp_out, " %%set/v v%p_%lu, %u, %u;\n",
sig, use_word, bit, wid);
}
}
@ -149,6 +184,26 @@ static void set_to_memory_word(ivl_lval_t lval, unsigned idx,
fprintf(vvp_out, "t_%u ;\n", skip_set);
}
static void assign_to_array_word(ivl_signal_t lsig, ivl_expr_t word_ix,
unsigned bit, unsigned delay, unsigned width)
{
unsigned skip_assign = transient_id++;
/* Store expression width into index word 0 */
fprintf(vvp_out, " %%ix/load 0, %u;\n", width);
/* Store constant (0) word part select into index 1 */
fprintf(vvp_out, " %%ix/load 1, 0;\n");
/* Calculate array word index into index register 3 */
draw_eval_expr_into_integer(word_ix, 3);
/* Skip assignment if word expression is not defined. */
fprintf(vvp_out, " %%jmp/1 t_%u, 4;\n", skip_assign);
fprintf(vvp_out, " %%assign/av v%p, %u, %u;\n", lsig, delay, bit);
fprintf(vvp_out, "t_%u ;\n", skip_assign);
clear_expression_lookaside();
}
static void assign_to_lvector(ivl_lval_t lval, unsigned bit,
unsigned delay, ivl_expr_t dexp,
unsigned width)
@ -157,6 +212,20 @@ static void assign_to_lvector(ivl_lval_t lval, unsigned bit,
ivl_expr_t part_off_ex = ivl_lval_part_off(lval);
unsigned part_off = 0;
ivl_expr_t word_ix = ivl_lval_idx(lval);
unsigned long use_word = 0;
if (ivl_signal_array_count(sig) > 1) {
assert(word_ix);
if (! number_is_immediate(word_ix, 8*sizeof(use_word))) {
assert(!dexp);
assign_to_array_word(sig, word_ix, bit, delay, width);
return;
}
use_word = get_number_immediate(word_ix);
}
if (part_off_ex == 0) {
part_off = 0;
} else if (number_is_immediate(part_off_ex, 64)) {
@ -174,8 +243,8 @@ static void assign_to_lvector(ivl_lval_t lval, unsigned bit,
/* If the index expression has XZ bits, skip the assign. */
fprintf(vvp_out, " %%jmp/1 t_%u, 4;\n", skip_assign);
fprintf(vvp_out, " %%ix/load 0, %u;\n", width);
fprintf(vvp_out, " %%assign/v0/x1 V_%s, %u, %u;\n",
vvp_signal_label(sig), delay, bit);
fprintf(vvp_out, " %%assign/v0/x1 v%p_%lu, %u, %u;\n",
sig, use_word, delay, bit);
fprintf(vvp_out, "t_%u ;\n", skip_assign);
} else if (part_off>0 || ivl_lval_width(lval)!=ivl_signal_width(sig)) {
@ -188,8 +257,8 @@ static void assign_to_lvector(ivl_lval_t lval, unsigned bit,
/* Constant delay... */
fprintf(vvp_out, " %%ix/load 0, %u;\n", width);
fprintf(vvp_out, " %%ix/load 1, %u;\n", part_off);
fprintf(vvp_out, " %%assign/v0/x1 V_%s, %u, %u;\n",
vvp_signal_label(sig), delay, bit);
fprintf(vvp_out, " %%assign/v0/x1 v%p_%lu, %u, %u;\n",
sig, use_word, delay, bit);
} else {
/* Calculated delay... */
@ -197,20 +266,20 @@ static void assign_to_lvector(ivl_lval_t lval, unsigned bit,
draw_eval_expr_into_integer(dexp, delay_index);
fprintf(vvp_out, " %%ix/load 0, %u;\n", width);
fprintf(vvp_out, " %%ix/load 1, %u;\n", part_off);
fprintf(vvp_out, " %%assign/v0/x1/d V_%s, %u, %u;\n",
vvp_signal_label(sig), delay_index, bit);
fprintf(vvp_out, " %%assign/v0/x1/d v%p_%lu, %u, %u;\n",
sig, use_word, delay_index, bit);
clr_word(delay_index);
}
} else if (dexp != 0) {
draw_eval_expr_into_integer(dexp, 1);
fprintf(vvp_out, " %%ix/load 0, %u;\n", width);
fprintf(vvp_out, " %%assign/v0/d V_%s, 1, %u;\n",
vvp_signal_label(sig), bit);
fprintf(vvp_out, " %%assign/v0/d v%p_%lu, 1, %u;\n",
sig, use_word, bit);
} else {
fprintf(vvp_out, " %%ix/load 0, %u;\n", width);
fprintf(vvp_out, " %%assign/v0 V_%s, %u, %u;\n",
vvp_signal_label(sig), delay, bit);
fprintf(vvp_out, " %%assign/v0 v%p_%lu, %u, %u;\n",
sig, use_word, delay, bit);
}
}
@ -345,8 +414,9 @@ static int show_stmt_assign_sig_real(ivl_statement_t net)
var = ivl_lval_sig(lval);
assert(var != 0);
fprintf(vvp_out, " %%set/wr V_%s, %d;\n",
vvp_signal_label(var), res);
assert(ivl_signal_array_count(var) == 1);
fprintf(vvp_out, " %%set/wr v%p_0, %d;\n", var, res);
return 0;
}
@ -390,13 +460,27 @@ static int show_stmt_assign_nb_real(ivl_statement_t net)
ivl_signal_t sig;
ivl_expr_t rval = ivl_stmt_rval(net);
ivl_expr_t del = ivl_stmt_delay_expr(net);
/* variables for the selection of word from an array. */
ivl_expr_t word_ix;
unsigned long use_word = 0;
/* thread address for a word value. */
int word;
unsigned long delay;
/* Must be exactly 1 l-value. */
assert(ivl_stmt_lvals(net) == 1);
lval = ivl_stmt_lval(net, 0);
sig = ivl_lval_sig(lval);
assert(sig);
if (ivl_signal_array_count(sig) > 1) {
word_ix = ivl_lval_idx(lval);
assert(word_ix);
assert(number_is_immediate(word_ix, 8*sizeof(use_word)));
use_word = get_number_immediate(word_ix);
}
delay = 0;
if (del && (ivl_expr_type(del) == IVL_EX_ULONG)) {
delay = ivl_expr_uvalue(del);
@ -409,11 +493,8 @@ static int show_stmt_assign_nb_real(ivl_statement_t net)
/* Evaluate the r-value */
word = draw_eval_real(rval);
lval = ivl_stmt_lval(net, 0);
sig = ivl_lval_sig(lval);
assert(sig);
fprintf(vvp_out, " %%assign/wr V_%s, %lu, %u;\n",
vvp_signal_label(sig), delay, word);
fprintf(vvp_out, " %%assign/wr v%p_%lu, %lu, %u;\n",
sig, use_word, delay, word);
clr_word(word);
@ -750,6 +831,8 @@ static void force_vector_to_lval(ivl_statement_t net, struct vector_info rvec)
unsigned use_wid = ivl_lval_width(lval);
ivl_expr_t part_off_ex = ivl_lval_part_off(lval);
unsigned part_off;
ivl_expr_t word_idx = ivl_lval_idx(lval);
unsigned long use_word = 0;
if (part_off_ex == 0) {
part_off = 0;
@ -758,6 +841,11 @@ static void force_vector_to_lval(ivl_statement_t net, struct vector_info rvec)
part_off = get_number_immediate(part_off_ex);
}
if (word_idx != 0) {
assert(number_is_immediate(word_idx, 8*sizeof(unsigned long)));
use_word = get_number_immediate(word_idx);
}
/* L-Value must be a signal: reg or wire */
assert(lsig != 0);
@ -775,8 +863,8 @@ static void force_vector_to_lval(ivl_statement_t net, struct vector_info rvec)
assert((roff + use_wid) <= rvec.wid);
}
fprintf(vvp_out, " %s V_%s, %u, %u;\n", command_name,
vvp_signal_label(lsig), rvec.base+roff, use_wid);
fprintf(vvp_out, " %s v%p_%lu, %u, %u;\n", command_name,
lsig, use_word, rvec.base+roff, use_wid);
if (rvec.base >= 4)
roff += use_wid;
@ -790,6 +878,9 @@ static void force_link_rval(ivl_statement_t net, ivl_expr_t rval)
ivl_signal_t lsig;
const char*command_name;
ivl_expr_t lword_idx, rword_idx;
unsigned long use_lword = 0, use_rword = 0;
if (ivl_expr_type(rval) != IVL_EX_SIGNAL)
return;
@ -811,9 +902,23 @@ static void force_link_rval(ivl_statement_t net, ivl_expr_t rval)
lval = ivl_stmt_lval(net, 0);
lsig = ivl_lval_sig(lval);
/* At least for now, only handle force to fixed words of an array. */
if ((lword_idx = ivl_lval_idx(lval)) != 0) {
assert(number_is_immediate(lword_idx, 8*sizeof(unsigned long)));
use_lword = get_number_immediate(lword_idx);
}
if ((rword_idx = ivl_expr_oper1(rval)) != 0) {
assert(number_is_immediate(rword_idx, 8*sizeof(unsigned long)));
use_rword = get_number_immediate(rword_idx);
}
assert(ivl_signal_array_count(rsig) == 1);
use_rword = 0;
fprintf(vvp_out, " %s/link", command_name);
fprintf(vvp_out, " V_%s", vvp_signal_label(lsig));
fprintf(vvp_out, ", V_%s;\n", vvp_signal_label(rsig));
fprintf(vvp_out, " v%p_%lu", lsig, use_lword);
fprintf(vvp_out, ", v%p_%lu;\n", rsig, use_rword);
}
static int show_stmt_cassign(ivl_statement_t net)
@ -848,11 +953,20 @@ static int show_stmt_deassign(ivl_statement_t net)
ivl_lval_t lval = ivl_stmt_lval(net, lidx);
ivl_signal_t lsig = ivl_lval_sig(lval);
ivl_expr_t word_idx = ivl_lval_idx(lval);
unsigned long use_word = 0;
assert(lsig != 0);
assert(ivl_lval_mux(lval) == 0);
assert(ivl_lval_part_off(lval) == 0);
fprintf(vvp_out, " %%deassign V_%s;\n", vvp_signal_label(lsig));
if (word_idx != 0) {
assert(number_is_immediate(word_idx, 8*sizeof(use_word)));
use_word = get_number_immediate(word_idx);
}
fprintf(vvp_out, " %%deassign v%p_%lu;\n", lsig, use_word);
}
return 0;
@ -1086,6 +1200,8 @@ static int show_stmt_release(ivl_statement_t net)
ivl_signal_t lsig = ivl_lval_sig(lval);
const char*opcode = 0;
ivl_expr_t word_idx = ivl_lval_idx(lval);
unsigned long use_word = 0;
assert(lsig != 0);
assert(ivl_lval_mux(lval) == 0);
assert(ivl_lval_part_off(lval) == 0);
@ -1099,10 +1215,15 @@ static int show_stmt_release(ivl_statement_t net)
break;
}
if (word_idx != 0) {
assert(number_is_immediate(word_idx, 8*sizeof(use_word)));
use_word = get_number_immediate(word_idx);
}
/* Generate the appropriate release statement for this
l-value. */
fprintf(vvp_out, " %%release/%s V_%s;\n",
opcode, vvp_signal_label(lsig));
fprintf(vvp_out, " %%release/%s v%p_%lu;\n",
opcode, lsig, use_word);
}
return 0;
@ -1491,6 +1612,12 @@ int draw_func_definition(ivl_scope_t scope)
/*
* $Log: vvp_process.c,v $
* Revision 1.127 2007/01/16 05:44:16 steve
* Major rework of array handling. Memories are replaced with the
* more general concept of arrays. The NetMemory and NetEMemory
* classes are removed from the ivl core program, and the IVL_LPM_RAM
* lpm type is removed from the ivl_target API.
*
* Revision 1.126 2006/10/05 01:37:34 steve
* Remove dead code.
*

View File

@ -17,7 +17,7 @@
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#ifdef HAVE_CVS_IDENT
#ident "$Id: vvp_scope.c,v 1.150 2006/11/23 22:42:48 steve Exp $"
#ident "$Id: vvp_scope.c,v 1.151 2007/01/16 05:44:16 steve Exp $"
#endif
# include "vvp_priv.h"
@ -178,7 +178,7 @@ const char* vvp_signal_label(ivl_signal_t sig)
return buf;
}
ivl_signal_t signal_of_nexus(ivl_nexus_t nex)
ivl_signal_t signal_of_nexus(ivl_nexus_t nex, unsigned*word)
{
unsigned idx;
for (idx = 0 ; idx < ivl_nexus_ptrs(nex) ; idx += 1) {
@ -188,9 +188,8 @@ ivl_signal_t signal_of_nexus(ivl_nexus_t nex)
continue;
if (ivl_signal_local(sig))
continue;
*word = ivl_nexus_ptr_pin(ptr);
return sig;
}
return 0;
@ -575,11 +574,9 @@ static const char* draw_net_input_drive(ivl_nexus_t nex, ivl_nexus_ptr_t nptr)
sptr = ivl_nexus_ptr_sig(nptr);
if (sptr && (ivl_signal_type(sptr) == IVL_SIT_REG)) {
/* Input is a .var. Note that these devices have only
exactly one pin (that carries a vector) so nptr_pin
must be 0. */
assert(nptr_pin == 0);
sprintf(result, "V_%s", vvp_signal_label(sptr));
/* Input is a .var. This device may be a non-zero pin
because it may be an array of reg vectors. */
snprintf(result, sizeof result, "v%p_%u", sptr, nptr_pin);
return result;
}
@ -620,8 +617,8 @@ static const char* draw_net_input_drive(ivl_nexus_t nex, ivl_nexus_ptr_t nptr)
if (lpm) switch (ivl_lpm_type(lpm)) {
case IVL_LPM_FF:
case IVL_LPM_RAM:
case IVL_LPM_ADD:
case IVL_LPM_ARRAY:
case IVL_LPM_CONCAT:
case IVL_LPM_CMP_EEQ:
case IVL_LPM_CMP_EQ:
@ -936,12 +933,13 @@ const char*draw_net_input(ivl_nexus_t nex)
const char*draw_input_from_net(ivl_nexus_t nex)
{
static char result[32];
unsigned word;
ivl_signal_t sig = signal_of_nexus(nex);
ivl_signal_t sig = signal_of_nexus(nex, &word);
if (sig == 0)
return draw_net_input(nex);
snprintf(result, sizeof result, "V_%p", sig);
snprintf(result, sizeof result, "v%p_%u", sig, word);
return result;
}
@ -949,7 +947,8 @@ const char*draw_input_from_net(ivl_nexus_t nex)
/*
* This function draws a reg/int/variable in the scope. This is a very
* simple device to draw as there are no inputs to connect so no need
* to scan the nexus.
* to scan the nexus. We do have to account for the possibility that
* the device is arrayed, though, by making a node for each array element.
*/
static void draw_reg_in_scope(ivl_signal_t sig)
{
@ -967,9 +966,29 @@ static void draw_reg_in_scope(ivl_signal_t sig)
break;
}
fprintf(vvp_out, "V_%s .var%s \"%s\", %d, %d;\n",
vvp_signal_label(sig), datatype_flag,
vvp_mangle_name(ivl_signal_basename(sig)), msb, lsb);
/* If the reg objects are collected into an array, then first
write out the .array record to declare the array indices. */
if (ivl_signal_array_count(sig) > 1) {
unsigned word_count = ivl_signal_array_count(sig);
unsigned iword;
int last = ivl_signal_array_base(sig)+ivl_signal_array_count(sig)-1;
int first = ivl_signal_array_base(sig);
fprintf(vvp_out, "v%p .array \"%s\", %d %d;\n",
sig, vvp_mangle_name(ivl_signal_basename(sig)),
last, first);
/* Scan the words of the array... */
for (iword = 0 ; iword < word_count ; iword += 1) {
fprintf(vvp_out, "v%p_%u .var%s v%p, %d %d;\n",
sig, iword, datatype_flag, sig, msb, lsb);
}
} else {
fprintf(vvp_out, "v%p_0 .var%s \"%s\", %d %d;\n",
sig, datatype_flag,
vvp_mangle_name(ivl_signal_basename(sig)), msb, lsb);
}
}
@ -981,28 +1000,14 @@ static void draw_net_in_scope(ivl_signal_t sig)
{
int msb = ivl_signal_msb(sig);
int lsb = ivl_signal_lsb(sig);
typedef const char*const_charp;
const char* arg;
const char* driver;
const char*datatype_flag = ivl_signal_signed(sig)? "/s" : "";
struct vvp_nexus_data*nex_data;
unsigned iword;
/* Skip the local signal. */
if (ivl_signal_local(sig))
return;
/* Connect the pin of the signal to something. */
{
ivl_nexus_t nex = ivl_signal_nex(sig);
driver = draw_net_input(nex);
arg = driver;
nex_data = (struct vvp_nexus_data*)ivl_nexus_get_private(nex);
assert(nex_data);
}
switch (ivl_signal_data_type(sig)) {
case IVL_VT_REAL:
datatype_flag = "/real";
@ -1011,30 +1016,70 @@ static void draw_net_in_scope(ivl_signal_t sig)
break;
}
if (nex_data->net == 0) {
const char*vec8 = "";
if (nex_data->drivers_count > 1)
vec8 = "8";
if (nex_data->flags & VVP_NEXUS_DATA_STR)
vec8 = "8";
for (iword = 0 ; iword < ivl_signal_array_count(sig); iword += 1) {
fprintf(vvp_out, "V_%p .net%s%s \"%s\", %d, %d, %s;"
" %u drivers%s\n",
sig, vec8, datatype_flag,
vvp_mangle_name(ivl_signal_basename(sig)),
msb, lsb, arg,
nex_data->drivers_count,
nex_data->flags&VVP_NEXUS_DATA_STR?", strength-aware":"");
nex_data->net = sig;
unsigned word_count = ivl_signal_array_count(sig);
struct vvp_nexus_data*nex_data;
} else {
/* Detect that this is an alias of nex_data->net. Create
a different kind of node that refers to the alias
source data instead of holding our own data. */
fprintf(vvp_out, "V_%p .alias%s \"%s\", %d, %d, V_%p;\n",
sig, datatype_flag,
vvp_mangle_name(ivl_signal_basename(sig)),
msb, lsb, nex_data->net);
/* Connect the pin of the signal to something. */
ivl_nexus_t nex = ivl_signal_nex(sig, iword);
const char*driver = draw_net_input(nex);
nex_data = (struct vvp_nexus_data*)ivl_nexus_get_private(nex);
assert(nex_data);
if (nex_data->net == 0) {
int strength_aware_flag = 0;
const char*vec8 = "";
if (nex_data->flags&VVP_NEXUS_DATA_STR)
strength_aware_flag = 1;
if (nex_data->drivers_count > 1)
vec8 = "8";
if (strength_aware_flag)
vec8 = "8";
if (iword == 0 && word_count > 1) {
int last = ivl_signal_array_base(sig) + word_count-1;
int first = ivl_signal_array_base(sig);
fprintf(vvp_out, "v%p .array \"%s\", %d %d;\n",
sig, vvp_mangle_name(ivl_signal_basename(sig)),
last, first);
}
if (word_count > 1) {
/* If this is a word of an array, then use an
array reference in place of the net name. */
fprintf(vvp_out, "v%p_%u .net%s%s v%p, %d %d, %s;"
" %u drivers%s\n",
sig, iword, vec8, datatype_flag, sig,
msb, lsb, driver,
nex_data->drivers_count,
strength_aware_flag?", strength-aware":"");
} else {
/* If this is an isolated word, it uses its
own name. */
fprintf(vvp_out, "v%p_%u .net%s%s \"%s\", %d %d, %s;"
" %u drivers%s\n",
sig, iword, vec8, datatype_flag,
vvp_mangle_name(ivl_signal_basename(sig)),
msb, lsb, driver,
nex_data->drivers_count,
strength_aware_flag?", strength-aware":"");
}
nex_data->net = sig;
} else {
assert(word_count == 1);
assert(ivl_signal_array_count(nex_data->net) == 1);
/* Detect that this is an alias of nex_data->net. Create
a different kind of node that refers to the alias
source data instead of holding our own data. */
fprintf(vvp_out, "v%p_0 .alias%s \"%s\", %d %d, v%p_0;\n",
sig, datatype_flag,
vvp_mangle_name(ivl_signal_basename(sig)),
msb, lsb, nex_data->net);
}
}
}
@ -1373,13 +1418,16 @@ static void draw_logic_in_scope(ivl_net_logic_t lptr)
fprintf(vvp_out, "L_%p .delay L_%p/d", lptr, lptr);
sig = ivl_expr_signal(rise_exp);
fprintf(vvp_out, ", V_%p", sig);
assert(ivl_signal_array_count(sig) == 1);
fprintf(vvp_out, ", v%p_0", sig);
sig = ivl_expr_signal(fall_exp);
fprintf(vvp_out, ", V_%p", sig);
assert(ivl_signal_array_count(sig) == 1);
fprintf(vvp_out, ", v%p_0", sig);
sig = ivl_expr_signal(decay_exp);
fprintf(vvp_out, ", V_%p;\n", sig);
assert(ivl_signal_array_count(sig) == 1);
fprintf(vvp_out, ", v%p_0;\n", sig);
}
}
}
@ -1515,38 +1563,6 @@ static void draw_event_in_scope(ivl_event_t obj)
}
}
static void draw_lpm_ram(ivl_lpm_t net)
{
ivl_memory_t mem = ivl_lpm_memory(net);
ivl_nexus_t clk = ivl_lpm_clk(net);
ivl_nexus_t pin;
if (clk) {
fprintf(vvp_out, "CLK_%p .event posedge, %s;\n",
net, draw_net_input(clk));
}
fprintf(vvp_out, "L_%p .mem/port M_%p, ", net, mem);
pin = ivl_lpm_select(net);
fprintf(vvp_out, "%s", draw_net_input(pin));
if (clk) {
fprintf(vvp_out, ", CLK_%p, ", net);
pin = ivl_lpm_enable(net);
if (pin)
fprintf(vvp_out, "%s", draw_net_input(pin));
else
fprintf(vvp_out, "C4<1>");
pin = ivl_lpm_data(net, 0);
fprintf(vvp_out, ", %s", draw_net_input(pin));
}
fprintf(vvp_out, ";\n");
}
/*
* This function draws any functors needed to calculate the input to
* this nexus, and leaves in the data array strings that can be used
@ -1611,6 +1627,23 @@ static void draw_lpm_add(ivl_lpm_t net)
net, type, width, src_table[0], src_table[1]);
}
/*
* The read port to an array is generated as a single record that takes
* the address as an input.
*/
static void draw_lpm_array(ivl_lpm_t net)
{
ivl_nexus_t nex;
ivl_signal_t mem = ivl_lpm_array(net);
fprintf(vvp_out, "L_%p .array/port v%p, ", net, mem);
nex = ivl_lpm_select(net);
fprintf(vvp_out, "%s", draw_net_input(nex));
fprintf(vvp_out, ";\n");
}
static void draw_lpm_cmp(ivl_lpm_t net)
{
const char*src_table[2];
@ -1951,7 +1984,8 @@ static void draw_lpm_ufunc(ivl_lpm_t net)
else
fprintf(vvp_out, ", ");
fprintf(vvp_out, "V_%s", vvp_signal_label(psig));
assert(ivl_signal_array_count(psig) == 1);
fprintf(vvp_out, "v%p_0", psig);
}
fprintf(vvp_out, ")");
@ -1960,8 +1994,9 @@ static void draw_lpm_ufunc(ivl_lpm_t net)
result is collected. */
{ ivl_signal_t psig = ivl_scope_port(def, 0);
assert(ivl_lpm_width(net) == ivl_signal_width(psig));
assert(ivl_signal_array_count(psig) == 1);
fprintf(vvp_out, " V_%s", vvp_signal_label(psig));
fprintf(vvp_out, " v%p_0", psig);
}
fprintf(vvp_out, ";\n");
@ -2123,10 +2158,6 @@ static void draw_lpm_in_scope(ivl_lpm_t net)
{
switch (ivl_lpm_type(net)) {
case IVL_LPM_RAM:
draw_lpm_ram(net);
return;
case IVL_LPM_ADD:
case IVL_LPM_SUB:
case IVL_LPM_MULT:
@ -2135,6 +2166,10 @@ static void draw_lpm_in_scope(ivl_lpm_t net)
draw_lpm_add(net);
return;
case IVL_LPM_ARRAY:
draw_lpm_array(net);
return;
case IVL_LPM_PART_BI:
draw_lpm_part_bi(net);
return;
@ -2335,6 +2370,12 @@ int draw_scope(ivl_scope_t net, ivl_scope_t parent)
/*
* $Log: vvp_scope.c,v $
* Revision 1.151 2007/01/16 05:44:16 steve
* Major rework of array handling. Memories are replaced with the
* more general concept of arrays. The NetMemory and NetEMemory
* classes are removed from the ivl core program, and the IVL_LPM_RAM
* lpm type is removed from the ivl_target API.
*
* Revision 1.150 2006/11/23 22:42:48 steve
* Do not intertangle modpaths due to references to input nets.
*

View File

@ -16,7 +16,7 @@
# 59 Temple Place - Suite 330
# Boston, MA 02111-1307, USA
#
#ident "$Id: Makefile.in,v 1.71 2006/10/30 22:45:38 steve Exp $"
#ident "$Id: Makefile.in,v 1.72 2007/01/16 05:44:16 steve Exp $"
#
#
SHELL = /bin/sh
@ -81,7 +81,8 @@ vpi_priv.o vpi_scope.o vpi_real.o vpi_signal.o vpi_tasks.o vpi_time.o \
vpi_memory.o vpi_vthr_vector.o vpip_bin.o vpip_hex.o vpip_oct.o \
vpip_to_dec.o vpip_format.o vvp_vpi.o
O = main.o parse.o parse_misc.o lexor.o arith.o bufif.o compile.o concat.o \
O = main.o parse.o parse_misc.o lexor.o arith.o array.o bufif.o compile.o \
concat.o \
dff.o extend.o npmos.o part.o reduce.o resolv.o sfunc.o stop.o symbols.o \
ufunc.o codes.o \
vthread.o schedule.o statistics.o tables.o udp.o vvp_net.o memory.o \

View File

@ -1,7 +1,7 @@
/*
* Copyright (c) 2001 Stephen Williams (steve@icarus.com)
*
* $Id: README.txt,v 1.79 2006/11/23 23:02:36 steve Exp $
* $Id: README.txt,v 1.80 2007/01/16 05:44:16 steve Exp $
*/
VVP SIMULATION ENGINE
@ -370,6 +370,16 @@ activates the delay.
.modpath <input> , [ <src> (<delays>) ] ;
ARRAY INDEX STATEMENTS:
Variables can be collected into arrays. The words of the array are
declared seperately, this statement collects them together:
<label> .array "name", <last> <first> ;
the .var or .net statements after this array statement, that have the
same "name" are collected, in order, as words.
MEMORY STATEMENTS:
Memories are arrays of words, each word a vvp_vector4_t vector of the

View File

@ -1,7 +1,7 @@
#ifndef __codes_H
#define __codes_H
/*
* Copyright (c) 2001-2003 Stephen Williams (steve@icarus.com)
* Copyright (c) 2001-2007 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
@ -19,13 +19,14 @@
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#ifdef HAVE_CVS_IDENT
#ident "$Id: codes.h,v 1.80 2006/10/05 01:23:53 steve Exp $"
#ident "$Id: codes.h,v 1.81 2007/01/16 05:44:16 steve Exp $"
#endif
# include "pointers.h"
# include "vvp_net.h"
# include "memory.h"
# include "array.h"
# include "vthread.h"
typedef bool (*vvp_code_fun)(vthread_t thr, vvp_code_t code);
@ -40,6 +41,7 @@ extern bool of_ADD_WR(vthread_t thr, vvp_code_t code);
extern bool of_ADDI(vthread_t thr, vvp_code_t code);
extern bool of_AND(vthread_t thr, vvp_code_t code);
extern bool of_ANDR(vthread_t thr, vvp_code_t code);
extern bool of_ASSIGN_AV(vthread_t thr, vvp_code_t code);
extern bool of_ASSIGN_D(vthread_t thr, vvp_code_t code);
extern bool of_ASSIGN_MV(vthread_t thr, vvp_code_t code);
extern bool of_ASSIGN_V0(vthread_t thr, vvp_code_t code);
@ -86,7 +88,7 @@ extern bool of_JMP0(vthread_t thr, vvp_code_t code);
extern bool of_JMP0XZ(vthread_t thr, vvp_code_t code);
extern bool of_JMP1(vthread_t thr, vvp_code_t code);
extern bool of_JOIN(vthread_t thr, vvp_code_t code);
extern bool of_LOAD_MEM(vthread_t thr, vvp_code_t code);
extern bool of_LOAD_AV(vthread_t thr, vvp_code_t code);
extern bool of_LOAD_MV(vthread_t thr, vvp_code_t code);
extern bool of_LOAD_NX(vthread_t thr, vvp_code_t code);
extern bool of_LOAD_VEC(vthread_t thr, vvp_code_t code);
@ -110,6 +112,7 @@ extern bool of_OR(vthread_t thr, vvp_code_t code);
extern bool of_ORR(vthread_t thr, vvp_code_t code);
extern bool of_RELEASE_NET(vthread_t thr, vvp_code_t code);
extern bool of_RELEASE_REG(vthread_t thr, vvp_code_t code);
extern bool of_SET_AV(vthread_t thr, vvp_code_t code);
extern bool of_SET_MV(vthread_t thr, vvp_code_t code);
extern bool of_SET_VEC(vthread_t thr, vvp_code_t code);
extern bool of_SET_WORDR(vthread_t thr, vvp_code_t code);
@ -146,6 +149,7 @@ struct vvp_code_s {
vvp_net_t *net;
vvp_code_t cptr;
vvp_memory_t mem;
vvp_array_t array;
struct __vpiHandle*handle;
struct __vpiScope*scope;
functor_t fun_ptr;
@ -180,6 +184,12 @@ extern vvp_code_t codespace_null(void);
/*
* $Log: codes.h,v $
* Revision 1.81 2007/01/16 05:44:16 steve
* Major rework of array handling. Memories are replaced with the
* more general concept of arrays. The NetMemory and NetEMemory
* classes are removed from the ivl core program, and the IVL_LPM_RAM
* lpm type is removed from the ivl_target API.
*
* Revision 1.80 2006/10/05 01:23:53 steve
* Handle non-constant delays on indexed non-blocking assignments.
*

View File

@ -17,7 +17,7 @@
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#ifdef HAVE_CVS_IDENT
#ident "$Id: compile.cc,v 1.226 2006/10/05 01:23:53 steve Exp $"
#ident "$Id: compile.cc,v 1.227 2007/01/16 05:44:16 steve Exp $"
#endif
# include "arith.h"
@ -58,6 +58,8 @@ enum operand_e {
OA_NONE,
/* The operand is a number, an immediate unsigned integer */
OA_NUMBER,
/* The operand is a pointer to an array. */
OA_ARR_PTR,
/* The operand is a thread bit index or short integer */
OA_BIT1,
OA_BIT2,
@ -87,6 +89,7 @@ const static struct opcode_table_s opcode_table[] = {
{ "%addi", of_ADDI, 3, {OA_BIT1, OA_BIT2, OA_NUMBER} },
{ "%and", of_AND, 3, {OA_BIT1, OA_BIT2, OA_NUMBER} },
{ "%and/r", of_ANDR, 3, {OA_BIT1, OA_BIT2, OA_NUMBER} },
{ "%assign/av",of_ASSIGN_AV,3,{OA_ARR_PTR,OA_BIT1, OA_BIT2} },
{ "%assign/mv",of_ASSIGN_MV,3,{OA_MEM_PTR,OA_BIT1, OA_BIT2} },
{ "%assign/v0",of_ASSIGN_V0,3,{OA_FUNC_PTR,OA_BIT1, OA_BIT2} },
{ "%assign/v0/d",of_ASSIGN_V0D,3,{OA_FUNC_PTR,OA_BIT1, OA_BIT2} },
@ -130,7 +133,7 @@ const static struct opcode_table_s opcode_table[] = {
{ "%jmp/0xz",of_JMP0XZ, 2, {OA_CODE_PTR, OA_BIT1, OA_NONE} },
{ "%jmp/1", of_JMP1, 2, {OA_CODE_PTR, OA_BIT1, OA_NONE} },
{ "%join", of_JOIN, 0, {OA_NONE, OA_NONE, OA_NONE} },
{ "%load/m", of_LOAD_MEM,2, {OA_BIT1, OA_MEM_PTR, OA_NONE} },
{ "%load/av",of_LOAD_AV,3, {OA_BIT1, OA_ARR_PTR, OA_BIT2} },
{ "%load/mv",of_LOAD_MV,3, {OA_BIT1, OA_MEM_PTR, OA_BIT2} },
{ "%load/nx",of_LOAD_NX,3, {OA_BIT1, OA_VPI_PTR, OA_BIT2} },
{ "%load/v", of_LOAD_VEC,3, {OA_BIT1, OA_FUNC_PTR, OA_BIT2} },
@ -154,6 +157,7 @@ const static struct opcode_table_s opcode_table[] = {
{ "%or/r", of_ORR, 3, {OA_BIT1, OA_BIT2, OA_NUMBER} },
{ "%release/net",of_RELEASE_NET,1,{OA_FUNC_PTR,OA_NONE,OA_NONE} },
{ "%release/reg",of_RELEASE_REG,1,{OA_FUNC_PTR,OA_NONE,OA_NONE} },
{ "%set/av", of_SET_AV, 3, {OA_ARR_PTR, OA_BIT1, OA_BIT2} },
{ "%set/mv", of_SET_MV, 3, {OA_MEM_PTR, OA_BIT1, OA_BIT2} },
{ "%set/v", of_SET_VEC,3, {OA_FUNC_PTR, OA_BIT1, OA_BIT2} },
{ "%set/wr", of_SET_WORDR,2,{OA_VPI_PTR, OA_BIT1, OA_NONE} },
@ -570,6 +574,37 @@ static void compile_mem_lookup(struct vvp_code_s *code, char *label)
resolv_submit(res);
}
struct array_resolv_list_s: public resolv_list_s {
struct vvp_code_s *code;
char *label;
virtual bool resolve(bool mes);
};
bool array_resolv_list_s::resolve(bool mes)
{
code->array = array_find(label);
if (code->array != 0) {
free(label);
return true;
}
if (mes)
fprintf(stderr, "Array unresolved: %s\n", label);
return false;
}
static void compile_array_lookup(struct vvp_code_s*code, char*label)
{
struct array_resolv_list_s *res
= new struct array_resolv_list_s;
res->code = code;
res->label = label;
resolv_submit(res);
}
/*
* When parsing is otherwise complete, this function is called to do
* the final stuff. Clean up deferred linking here.
@ -1312,6 +1347,15 @@ void compile_code(char*label, char*mnem, comp_operands_t opa)
case OA_NONE:
break;
case OA_ARR_PTR:
if (opa->argv[idx].ltype != L_SYMB) {
yyerror("operand format");
break;
}
compile_array_lookup(code, opa->argv[idx].symb.text);
break;
case OA_BIT1:
if (opa->argv[idx].ltype != L_NUMB) {
yyerror("operand format");
@ -1535,6 +1579,12 @@ void compile_param_string(char*label, char*name, char*value)
/*
* $Log: compile.cc,v $
* Revision 1.227 2007/01/16 05:44:16 steve
* Major rework of array handling. Memories are replaced with the
* more general concept of arrays. The NetMemory and NetEMemory
* classes are removed from the ivl core program, and the IVL_LPM_RAM
* lpm type is removed from the ivl_target API.
*
* Revision 1.226 2006/10/05 01:23:53 steve
* Handle non-constant delays on indexed non-blocking assignments.
*

View File

@ -19,7 +19,7 @@
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#ifdef HAVE_CVS_IDENT
#ident "$Id: compile.h,v 1.84 2006/11/22 06:10:05 steve Exp $"
#ident "$Id: compile.h,v 1.85 2007/01/16 05:44:16 steve Exp $"
#endif
# include <stdio.h>
@ -237,6 +237,10 @@ extern char **compile_udp_table(char **table, char *row);
* Memory Instances, Ports, and Initialization
*/
extern void compile_array(char*label, char*name, int last, int first);
extern void compile_array_port(char*label, char*name, char*addr);
extern void compile_memory(char *label, char *name, int lsb, int msb,
unsigned idxs, long *idx);
@ -326,7 +330,11 @@ extern void compile_thread(char*start_sym, char*flag);
*/
extern void compile_variable(char*label, char*name,
int msb, int lsb, char signed_flag);
extern void compile_var_real(char*label, char*nane,
extern void compile_var_real(char*label, char*name,
int msb, int lsb);
extern void compile_variablew(char*label, char*array_symbol,
int msb, int lsb, char signed_flag);
extern void compile_varw_real(char*label, char*array_symbol,
int msb, int lsb);
extern void compile_net(char*label, char*name,
@ -337,6 +345,14 @@ extern void compile_net_real(char*label, char*name,
int msb, int lsb,
unsigned argc, struct symb_s*argv);
extern void compile_netw(char*label, char*array_symbol,
int msb, int lsb, bool signed_flag,
bool net8_flag,
unsigned argc, struct symb_s*argv);
extern void compile_netw_real(char*label, char*array_symbol,
int msb, int lsb,
unsigned argc, struct symb_s*argv);
extern void compile_alias(char*label, char*name,
int msb, int lsb, bool signed_flag,
unsigned argc, struct symb_s*argv);
@ -346,6 +362,12 @@ extern void compile_alias_real(char*label, char*name,
/*
* $Log: compile.h,v $
* Revision 1.85 2007/01/16 05:44:16 steve
* Major rework of array handling. Memories are replaced with the
* more general concept of arrays. The NetMemory and NetEMemory
* classes are removed from the ivl core program, and the IVL_LPM_RAM
* lpm type is removed from the ivl_target API.
*
* Revision 1.84 2006/11/22 06:10:05 steve
* Fix spurious event from net8 that is forced.
*

View File

@ -21,7 +21,7 @@
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#ifdef HAVE_CVS_IDENT
#ident "$Id: lexor.lex,v 1.64 2006/11/22 06:10:05 steve Exp $"
#ident "$Id: lexor.lex,v 1.65 2007/01/16 05:44:16 steve Exp $"
#endif
# include "parse_misc.h"
@ -96,6 +96,8 @@
".arith/sub" { return K_ARITH_SUB; }
".arith/sub.r" { return K_ARITH_SUB_R; }
".arith/sum" { return K_ARITH_SUM; }
".array" { return K_ARRAY; }
".array/port" { return K_ARRAY_PORT; }
".cmp/eeq" { return K_CMP_EEQ; }
".cmp/eq" { return K_CMP_EQ; }
".cmp/nee" { return K_CMP_NEE; }
@ -212,6 +214,12 @@ int yywrap()
/*
* $Log: lexor.lex,v $
* Revision 1.65 2007/01/16 05:44:16 steve
* Major rework of array handling. Memories are replaced with the
* more general concept of arrays. The NetMemory and NetEMemory
* classes are removed from the ivl core program, and the IVL_LPM_RAM
* lpm type is removed from the ivl_target API.
*
* Revision 1.64 2006/11/22 06:10:05 steve
* Fix spurious event from net8 that is forced.
*

View File

@ -1,7 +1,7 @@
/*
* Copyright (c) 2001-2003 Stephen Williams (steve@icarus.com)
*
* $Id: opcodes.txt,v 1.72 2006/10/05 01:23:54 steve Exp $
* $Id: opcodes.txt,v 1.73 2007/01/16 05:44:16 steve Exp $
*/
@ -57,7 +57,21 @@ means the following:
1 and 1 --> 1
otherwise x
* %assign/mv <memory-label>, <delay>, <bit>
* %assign/av <array-label>, <delay>, <bit>
The %assign/av instruction assigns a vector value to a word in the
labeled array. The <delay> is the delay in simulation time to the
assignment (0 for non-blocking assignment) and the <bit> is the base
of the vector to write.
The width of the word is retrieved from index register 0.
The base of a part select is retrieved from index register 1.
The address of the word in the memory is from index register 3. The
address is canonical form.
* %assign/mv <memory-label>, <delay>, <bit> (DEPRECATED)
the %assign/mv instruction assigns a vector value to a word in the
labeled memory. The <delay> is the delay in simulation time to the
@ -360,12 +374,11 @@ If the matching child instruction is still running, a %join suspends
the calling thread until the child ends. If the child is already
ended, then the %join does not block or yield the thread.
* %load/m <bit>, <memory-label> (OBSOLETE)
* %load/av <bit>, <array-label>, <wid>
This instruction loads a value from a memory bit into the specified
thread register bit. The memory bit is addressed by index register 3.
Bit address zero is the LSB of the first memory word. This
instruction loads only a single bit.
This instruction loads a word from the specified array. The word
address is in index register 3. The width should match the width of
the array word.
* %load/mv <bit>, <memory-label>, <wid>
@ -535,6 +548,20 @@ register that contains the LSB of the vector, and the <wid> is the
size of the vector. The width must exactly match the width of the
signal.
* %set/av <array-label>, <bit>, <wid>
This sets a thread vector to an array word. The <array-label>
addresses an array device, and the <bit>,<wid> describe a vector to be
written. Index register 3 contains the address of the word within the
array.
The base of a part select is retrieved from index register 1. The
width is implied from the <wid> that is the argument. This is the part
*within* the word.
The address (in canonical form) is precalculated and loaded into index
register 3. This is the address of the word within the array.
* %set/mv <memory-label>, <bit>, <wid>
This sets a thread vector to a memory word. The <memory-label>

View File

@ -19,7 +19,7 @@
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#ifdef HAVE_CVS_IDENT
#ident "$Id: parse.y,v 1.86 2006/11/22 06:10:05 steve Exp $"
#ident "$Id: parse.y,v 1.87 2007/01/16 05:44:16 steve Exp $"
#endif
# include "parse_misc.h"
@ -67,7 +67,7 @@ static vvp_fun_modpath*modpath_dst = 0;
%token K_ALIAS K_ALIAS_S K_ALIAS_R
%token K_ARITH_DIV K_ARITH_DIV_R K_ARITH_DIV_S K_ARITH_MOD K_ARITH_MULT
%token K_ARITH_SUB K_ARITH_SUB_R K_ARITH_SUM
%token K_ARITH_SUB K_ARITH_SUB_R K_ARITH_SUM K_ARRAY K_ARRAY_PORT
%token K_CMP_EEQ K_CMP_EQ K_CMP_NEE K_CMP_NE
%token K_CMP_GE K_CMP_GE_S K_CMP_GT K_CMP_GT_S
%token K_CONCAT K_DEBUG K_DELAY K_DFF
@ -177,8 +177,13 @@ statement
| mem_init_stmt
| T_LABEL K_ARRAY T_STRING ',' signed_t_number signed_t_number ';'
{ compile_array($1, $3, $5, $6); }
| T_LABEL K_ARRAY_PORT T_SYMBOL ',' T_SYMBOL ';'
{ compile_array_port($1, $3, $5); }
/* The .ufunc functor is for implementing user defined functions, or
/* The .ufunc functor is for implementing user defined functions, or
other thread code that is automatically invoked if any of the
bits in the symbols list change. */
@ -476,52 +481,69 @@ statement
creates a functor with the same name that acts as the output of
the variable in the netlist. */
| T_LABEL K_VAR T_STRING ',' signed_t_number ',' signed_t_number ';'
{ compile_variable($1, $3, $5, $7, 0 /* unsigned */ ); }
| T_LABEL K_VAR T_STRING ',' signed_t_number signed_t_number ';'
{ compile_variable($1, $3, $5, $6, 0 /* unsigned */ ); }
| T_LABEL K_VAR_S T_STRING ',' signed_t_number ',' signed_t_number ';'
{ compile_variable($1, $3, $5, $7, 1 /* signed */ ); }
| T_LABEL K_VAR_S T_STRING ',' signed_t_number signed_t_number ';'
{ compile_variable($1, $3, $5, $6, 1 /* signed */ ); }
| T_LABEL K_VAR_I T_STRING ',' T_NUMBER ',' T_NUMBER ';'
{ compile_variable($1, $3, $5, $7, 2 /* integer */); }
| T_LABEL K_VAR_I T_STRING ',' T_NUMBER T_NUMBER ';'
{ compile_variable($1, $3, $5, $6, 2 /* integer */); }
| T_LABEL K_VAR_R T_STRING ',' signed_t_number ',' signed_t_number ';'
{ compile_var_real($1, $3, $5, $7); }
| T_LABEL K_VAR_R T_STRING ',' signed_t_number signed_t_number ';'
{ compile_var_real($1, $3, $5, $6); }
/* Arrayed versions of variable directives. */
| T_LABEL K_VAR T_SYMBOL ',' signed_t_number signed_t_number ';'
{ compile_variablew($1, $3, $5, $6, 0 /* unsigned */ ); }
| T_LABEL K_VAR_S T_SYMBOL ',' signed_t_number signed_t_number ';'
{ compile_variablew($1, $3, $5, $6, 1 /* signed */ ); }
| T_LABEL K_VAR_I T_SYMBOL ',' T_NUMBER T_NUMBER ';'
{ compile_variablew($1, $3, $5, $6, 2 /* integer */); }
/* Net statements are similar to .var statements, except that they
declare nets, and they have an input list. */
| T_LABEL K_NET T_STRING ',' signed_t_number ',' signed_t_number
| T_LABEL K_NET T_STRING ',' signed_t_number signed_t_number
',' symbols_net ';'
{ compile_net($1, $3, $5, $7, false, false, $9.cnt, $9.vect); }
{ compile_net($1, $3, $5, $6, false, false, $8.cnt, $8.vect); }
| T_LABEL K_NET_S T_STRING ',' signed_t_number ',' signed_t_number
| T_LABEL K_NET_S T_STRING ',' signed_t_number signed_t_number
',' symbols_net ';'
{ compile_net($1, $3, $5, $7, true, false, $9.cnt, $9.vect); }
{ compile_net($1, $3, $5, $6, true, false, $8.cnt, $8.vect); }
| T_LABEL K_NET8 T_STRING ',' signed_t_number ',' signed_t_number
| T_LABEL K_NET8 T_STRING ',' signed_t_number signed_t_number
',' symbols_net ';'
{ compile_net($1, $3, $5, $7, false, true, $9.cnt, $9.vect); }
{ compile_net($1, $3, $5, $6, false, true, $8.cnt, $8.vect); }
| T_LABEL K_NET8_S T_STRING ',' signed_t_number ',' signed_t_number
| T_LABEL K_NET8_S T_STRING ',' signed_t_number signed_t_number
',' symbols_net ';'
{ compile_net($1, $3, $5, $7, true, true, $9.cnt, $9.vect); }
{ compile_net($1, $3, $5, $6, true, true, $8.cnt, $8.vect); }
| T_LABEL K_NET_R T_STRING ',' signed_t_number ',' signed_t_number
| T_LABEL K_NET_R T_STRING ',' signed_t_number signed_t_number
',' symbols_net ';'
{ compile_net_real($1, $3, $5, $7, $9.cnt, $9.vect); }
{ compile_net_real($1, $3, $5, $6, $8.cnt, $8.vect); }
| T_LABEL K_ALIAS T_STRING ',' signed_t_number ',' signed_t_number
| T_LABEL K_ALIAS T_STRING ',' signed_t_number signed_t_number
',' symbols_net ';'
{ compile_alias($1, $3, $5, $7, false, $9.cnt, $9.vect); }
{ compile_alias($1, $3, $5, $6, false, $8.cnt, $8.vect); }
| T_LABEL K_ALIAS_S T_STRING ',' signed_t_number ',' signed_t_number
| T_LABEL K_ALIAS_S T_STRING ',' signed_t_number signed_t_number
',' symbols_net ';'
{ compile_alias($1, $3, $5, $7, true, $9.cnt, $9.vect); }
{ compile_alias($1, $3, $5, $6, true, $8.cnt, $8.vect); }
| T_LABEL K_ALIAS_R T_STRING ',' signed_t_number ',' signed_t_number
| T_LABEL K_ALIAS_R T_STRING ',' signed_t_number signed_t_number
',' symbols_net ';'
{ compile_alias_real($1, $3, $5, $7, $9.cnt, $9.vect); }
{ compile_alias_real($1, $3, $5, $6, $8.cnt, $8.vect); }
/* Arrayed versions of net directives. */
| T_LABEL K_NET T_SYMBOL ',' signed_t_number signed_t_number
',' symbols_net ';'
{ compile_netw($1, $3, $5, $6, false, false, $8.cnt, $8.vect); }
/* Parameter statements come in a few simple forms. The most basic
is the string parameter. */
@ -781,6 +803,12 @@ int compile_design(const char*path)
/*
* $Log: parse.y,v $
* Revision 1.87 2007/01/16 05:44:16 steve
* Major rework of array handling. Memories are replaced with the
* more general concept of arrays. The NetMemory and NetEMemory
* classes are removed from the ivl core program, and the IVL_LPM_RAM
* lpm type is removed from the ivl_target API.
*
* Revision 1.86 2006/11/22 06:10:05 steve
* Fix spurious event from net8 that is forced.
*

View File

@ -17,7 +17,7 @@
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#ifdef HAVE_CVS_IDENT
#ident "$Id: schedule.cc,v 1.44 2006/09/29 16:55:04 steve Exp $"
#ident "$Id: schedule.cc,v 1.45 2007/01/16 05:44:16 steve Exp $"
#endif
# include "schedule.h"
@ -147,6 +147,20 @@ void assign_memory_word_s::run_run(void)
memory_set_word(mem, adr, off, val);
}
struct assign_array_word_s : public event_s {
vvp_array_t mem;
unsigned adr;
vvp_vector4_t val;
unsigned off;
void run_run(void);
};
void assign_array_word_s::run_run(void)
{
count_assign_events += 1;
array_set_word(mem, adr, off, val);
}
struct generic_event_s : public event_s {
vvp_gen_event_t obj;
unsigned char val;
@ -467,6 +481,20 @@ void schedule_assign_memory_word(vvp_memory_t mem,
schedule_event_(cur, delay, SEQ_NBASSIGN);
}
void schedule_assign_array_word(vvp_array_t mem,
unsigned word_addr,
unsigned off,
vvp_vector4_t val,
vvp_time64_t delay)
{
struct assign_array_word_s*cur = new struct assign_array_word_s;
cur->mem = mem;
cur->adr = word_addr;
cur->off = off;
cur->val = val;
schedule_event_(cur, delay, SEQ_NBASSIGN);
}
void schedule_set_vector(vvp_net_ptr_t ptr, vvp_vector4_t bit)
{
struct assign_vector4_event_s*cur = new struct assign_vector4_event_s;
@ -617,6 +645,12 @@ void schedule_simulate(void)
/*
* $Log: schedule.cc,v $
* Revision 1.45 2007/01/16 05:44:16 steve
* Major rework of array handling. Memories are replaced with the
* more general concept of arrays. The NetMemory and NetEMemory
* classes are removed from the ivl core program, and the IVL_LPM_RAM
* lpm type is removed from the ivl_target API.
*
* Revision 1.44 2006/09/29 16:55:04 steve
* Allow rosync events to create new rosync events.
*

View File

@ -19,13 +19,14 @@
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#ifdef HAVE_CVS_IDENT
#ident "$Id: schedule.h,v 1.28 2006/09/29 01:24:34 steve Exp $"
#ident "$Id: schedule.h,v 1.29 2007/01/16 05:44:16 steve Exp $"
#endif
# include "vthread.h"
# include "pointers.h"
# include "vvp_net.h"
# include "memory.h"
# include "array.h"
/*
* This causes a thread to be scheduled for execution. The schedule
@ -54,6 +55,11 @@ extern void schedule_assign_vector(vvp_net_ptr_t ptr,
const vvp_vector4_t&val,
vvp_time64_t delay);
extern void schedule_assign_array_word(vvp_array_t mem,
unsigned word_address,
unsigned off,
vvp_vector4_t val,
vvp_time64_t delay);
extern void schedule_assign_memory_word(vvp_memory_t mem,
unsigned word_address,
unsigned off,
@ -142,6 +148,12 @@ extern unsigned long count_event_pool;
/*
* $Log: schedule.h,v $
* Revision 1.29 2007/01/16 05:44:16 steve
* Major rework of array handling. Memories are replaced with the
* more general concept of arrays. The NetMemory and NetEMemory
* classes are removed from the ivl core program, and the IVL_LPM_RAM
* lpm type is removed from the ivl_target API.
*
* Revision 1.28 2006/09/29 01:24:34 steve
* rwsync callback fixes from Ben Staveley (with modifications.)
*

View File

@ -17,7 +17,7 @@
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#ifdef HAVE_CVS_IDENT
#ident "$Id: vpi_callback.cc,v 1.44 2006/09/29 01:24:34 steve Exp $"
#ident "$Id: vpi_callback.cc,v 1.45 2007/01/16 05:44:16 steve Exp $"
#endif
/*
@ -436,11 +436,14 @@ void callback_execute(struct __vpiCallback*cur)
vvp_vpi_callback::vvp_vpi_callback()
{
vpi_callbacks_ = 0;
array_ = 0;
array_word_ = 0;
}
vvp_vpi_callback::~vvp_vpi_callback()
{
assert(vpi_callbacks_ == 0);
assert(array_ == 0);
}
void vvp_vpi_callback::add_vpi_callback(__vpiCallback*cb)
@ -449,6 +452,13 @@ void vvp_vpi_callback::add_vpi_callback(__vpiCallback*cb)
vpi_callbacks_ = cb;
}
void vvp_vpi_callback::attach_as_word(vvp_array_t arr, unsigned long addr)
{
assert(array_ == 0);
array_ = arr;
array_word_ = addr;
}
/*
* A vvp_fun_signal uses this method to run its callbacks whenever it
* has a value change. If the cb_rtn is non-nil, then call the
@ -460,6 +470,8 @@ void vvp_vpi_callback::run_vpi_callbacks()
struct __vpiCallback *next = vpi_callbacks_;
struct __vpiCallback *prev = 0;
if (array_) array_word_change(array_, array_word_);
while (next) {
struct __vpiCallback*cur = next;
next = cur->next;
@ -576,6 +588,12 @@ void vvp_fun_signal_real::get_value(struct t_vpi_value*vp)
/*
* $Log: vpi_callback.cc,v $
* Revision 1.45 2007/01/16 05:44:16 steve
* Major rework of array handling. Memories are replaced with the
* more general concept of arrays. The NetMemory and NetEMemory
* classes are removed from the ivl core program, and the IVL_LPM_RAM
* lpm type is removed from the ivl_target API.
*
* Revision 1.44 2006/09/29 01:24:34 steve
* rwsync callback fixes from Ben Staveley (with modifications.)
*

View File

@ -19,7 +19,7 @@
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#ifdef HAVE_CVS_IDENT
#ident "$Id: vpi_priv.h,v 1.71 2006/06/18 04:15:50 steve Exp $"
#ident "$Id: vpi_priv.h,v 1.72 2007/01/16 05:44:16 steve Exp $"
#endif
# include "vpi_user.h"
@ -170,7 +170,7 @@ extern void vpip_make_root_iterator(struct __vpiHandle**&table,
struct __vpiSignal {
struct __vpiHandle base;
struct __vpiScope* scope;
/* The name of this reg/net object */
/* The name of this reg/net, or nil if this is an array word. */
const char*name;
/* The indices that define the width and access offset. */
int msb, lsb;
@ -187,6 +187,12 @@ extern vpiHandle vpip_make_reg(const char*name, int msb, int lsb,
extern vpiHandle vpip_make_net(const char*name, int msb, int lsb,
bool signed_flag, vvp_net_t*node);
/*
* This function safely converts a vpiHandle back to a
* __vpiSignal. Return a nil if the type is not appropriate.
*/
extern __vpiSignal* vpip_signal_from_handle(vpiHandle obj);
/*
* These methods support the vpi creation of events. The name string
@ -444,6 +450,12 @@ extern char *need_result_buf(unsigned cnt, vpi_rbuf_t type);
/*
* $Log: vpi_priv.h,v $
* Revision 1.72 2007/01/16 05:44:16 steve
* Major rework of array handling. Memories are replaced with the
* more general concept of arrays. The NetMemory and NetEMemory
* classes are removed from the ivl core program, and the IVL_LPM_RAM
* lpm type is removed from the ivl_target API.
*
* Revision 1.71 2006/06/18 04:15:50 steve
* Add support for system functions in continuous assignments.
*

View File

@ -17,7 +17,7 @@
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#ifdef HAVE_CVS_IDENT
#ident "$Id: vpi_signal.cc,v 1.75 2006/12/09 19:06:53 steve Exp $"
#ident "$Id: vpi_signal.cc,v 1.76 2007/01/16 05:44:16 steve Exp $"
#endif
/*
@ -75,15 +75,22 @@ char *need_result_buf(unsigned cnt, vpi_rbuf_t type)
return result_buf[type];
}
struct __vpiSignal* vpip_signal_from_handle(vpiHandle ref)
{
if ((ref->vpi_type->type_code != vpiNet)
&& (ref->vpi_type->type_code != vpiReg))
return 0;
return (struct __vpiSignal*)ref;
}
/*
* implement vpi_get for vpiReg objects.
*/
static int signal_get(int code, vpiHandle ref)
{
assert((ref->vpi_type->type_code==vpiNet)
|| (ref->vpi_type->type_code==vpiReg));
struct __vpiSignal*rfp = (struct __vpiSignal*)ref;
struct __vpiSignal*rfp = vpip_signal_from_handle(ref);
assert(rfp);
switch (code) {
@ -581,31 +588,19 @@ static vpiHandle signal_put_value(vpiHandle ref, s_vpi_value*vp)
}
break;
#endif
#if 0
case vpiVectorVal:
for (unsigned idx = 0 ; idx < wid ; idx += 1) {
unsigned long aval = vp->value.vector[idx/32].aval;
unsigned long bval = vp->value.vector[idx/32].bval;
aval >>= idx%32;
bval >>= idx%32;
int bit = (aval&1) | ((bval<<1)&2);
switch (bit) {
case 0: /* zero */
functor_poke(rfp,idx, 0, St0, 0);
break;
case 1: /* one */
functor_poke(rfp,idx, 1, St1, 0);
break;
case 2: /* z */
functor_poke(rfp,idx, 3, HiZ, 0);
break;
case 3: /* x */
functor_poke(rfp,idx, 2, StX, 0);
break;
}
int bitmask = (aval&1) | ((bval<<1)&2);
static const vvp_bit4_t bit_table[4] = {
BIT4_0, BIT4_1, BIT4_X, BIT4_Z };
vvp_bit4_t bit = bit_table[bitmask];
val.set_bit(idx, bit);
}
break;
#endif
case vpiBinStrVal:
vpip_bin_str_to_vec4(val, vp->value.str, false);
break;
@ -707,7 +702,7 @@ vpiHandle vpip_make_net(const char*name, int msb, int lsb,
{
struct __vpiSignal*obj = allocate_vpiSignal();
obj->base.vpi_type = &vpip_net_rt;
obj->name = vpip_name_string(name);
obj->name = name? vpip_name_string(name) : 0;
obj->msb = msb;
obj->lsb = lsb;
obj->signed_flag = signed_flag? 1 : 0;
@ -724,6 +719,12 @@ vpiHandle vpip_make_net(const char*name, int msb, int lsb,
/*
* $Log: vpi_signal.cc,v $
* Revision 1.76 2007/01/16 05:44:16 steve
* Major rework of array handling. Memories are replaced with the
* more general concept of arrays. The NetMemory and NetEMemory
* classes are removed from the ivl core program, and the IVL_LPM_RAM
* lpm type is removed from the ivl_target API.
*
* Revision 1.75 2006/12/09 19:06:53 steve
* Handle vpiRealVal reads of signals, and real anyedge events.
*

View File

@ -17,7 +17,7 @@
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#ifdef HAVE_CVS_IDENT
#ident "$Id: vthread.cc,v 1.157 2006/10/05 01:23:54 steve Exp $"
#ident "$Id: vthread.cc,v 1.158 2007/01/16 05:44:16 steve Exp $"
#endif
# include "config.h"
@ -536,6 +536,28 @@ bool of_ADDI(vthread_t thr, vvp_code_t cp)
return true;
}
/* %assign/av <array>, <delay>, <bit>
* This generates an assignment event to an array. Index register 0
* contains the width of the vector (and the word) and index register
* 3 contains the canonical address of the word in memory.
*/
bool of_ASSIGN_AV(vthread_t thr, vvp_code_t cp)
{
unsigned wid = thr->words[0].w_int;
unsigned off = thr->words[1].w_int;
unsigned adr = thr->words[3].w_int;
assert(wid > 0);
unsigned delay = cp->bit_idx[0];
unsigned bit = cp->bit_idx[1];
vvp_vector4_t value = vthread_bits_to_vector(thr, bit, wid);
schedule_assign_array_word(cp->array, adr, off, value, delay);
return true;
}
/*
* This is %assign/v0 <label>, <delay>, <bit>
* Index register 0 contains a vector width.
@ -1886,15 +1908,34 @@ bool of_JOIN(vthread_t thr, vvp_code_t cp)
return false;
}
bool of_LOAD_MEM(vthread_t thr, vvp_code_t cp)
/*
* %load/av <bit>, <array-label>, <wid> ;
*
* <bit> is the thread bit address for the result
* <array-label> is the array to access, and
* <wid> is the width of the word to read.
*
* The address of the word in the array is in index register 3.
*/
bool of_LOAD_AV(vthread_t thr, vvp_code_t cp)
{
#if 0
assert(cp->bit_idx[0] >= 4);
unsigned char val = memory_get(cp->mem, thr->words[3].w_int);
thr_put_bit(thr, cp->bit_idx[0], val);
#else
fprintf(stderr, "XXXX %%load/m is obsolete\n");
#endif
unsigned bit = cp->bit_idx[0];
unsigned wid = cp->bit_idx[1];
unsigned adr = thr->words[3].w_int;
vvp_vector4_t word = array_get_word(cp->array, adr);
if (word.size() != wid) {
fprintf(stderr, "internal error: array width=%u, word.size()=%u, wid=%u\n",
0, word.size(), wid);
}
assert(word.size() == wid);
for (unsigned idx = 0 ; idx < wid ; idx += 1, bit += 1) {
vvp_bit4_t val = word.value(idx);
thr_put_bit(thr, bit, val);
}
return true;
}
@ -2863,6 +2904,25 @@ bool of_RELEASE_REG(vthread_t thr, vvp_code_t cp)
}
/*
* This implements the "%set/av <label>, <bit>, <wid>" instruction. In
* this case, the <label> is an array label, and the <bit> and <wid>
* are the thread vector of a value to be written in.
*/
bool of_SET_AV(vthread_t thr, vvp_code_t cp)
{
unsigned bit = cp->bit_idx[0];
unsigned wid = cp->bit_idx[1];
unsigned off = thr->words[1].w_int;
unsigned adr = thr->words[3].w_int;
/* Make a vector of the desired width. */
vvp_vector4_t value = vthread_bits_to_vector(thr, bit, wid);
array_set_word(cp->array, adr, off, value);
return true;
}
/*
* This implements the "%set/mv <label>, <bit>, <wid>" instruction. In
* this case, the <label> is a memory label, and the <bit> and <wid>
@ -3312,6 +3372,12 @@ bool of_JOIN_UFUNC(vthread_t thr, vvp_code_t cp)
/*
* $Log: vthread.cc,v $
* Revision 1.158 2007/01/16 05:44:16 steve
* Major rework of array handling. Memories are replaced with the
* more general concept of arrays. The NetMemory and NetEMemory
* classes are removed from the ivl core program, and the IVL_LPM_RAM
* lpm type is removed from the ivl_target API.
*
* Revision 1.157 2006/10/05 01:23:54 steve
* Handle non-constant delays on indexed non-blocking assignments.
*

View File

@ -18,7 +18,7 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#ident "$Id: vvp_net.h,v 1.53 2006/12/09 19:06:53 steve Exp $"
#ident "$Id: vvp_net.h,v 1.54 2007/01/16 05:44:17 steve Exp $"
# include "config.h"
# include <stddef.h>
@ -765,6 +765,10 @@ class vvp_fun_extend_signed : public vvp_net_fun_t {
* propagate starting at the next input change.
*/
/*
* Things derived from vvp_vpi_callback may also be array'ed, so it
* includes some members that arrays use.
*/
class vvp_vpi_callback {
public:
@ -776,8 +780,12 @@ class vvp_vpi_callback {
virtual void get_value(struct t_vpi_value*value) =0;
void attach_as_word(class __vpiArray* arr, unsigned long addr);
private:
struct __vpiCallback*vpi_callbacks_;
class __vpiArray* array_;
unsigned long array_word_;
};
class vvp_fun_signal_base : public vvp_net_fun_t, public vvp_vpi_callback {
@ -1027,6 +1035,12 @@ inline void vvp_send_vec4_pv(vvp_net_ptr_t ptr, const vvp_vector4_t&val,
/*
* $Log: vvp_net.h,v $
* Revision 1.54 2007/01/16 05:44:17 steve
* Major rework of array handling. Memories are replaced with the
* more general concept of arrays. The NetMemory and NetEMemory
* classes are removed from the ivl core program, and the IVL_LPM_RAM
* lpm type is removed from the ivl_target API.
*
* Revision 1.53 2006/12/09 19:06:53 steve
* Handle vpiRealVal reads of signals, and real anyedge events.
*

View File

@ -17,11 +17,12 @@
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#ifdef HAVE_CVS_IDENT
#ident "$Id: words.cc,v 1.7 2005/11/27 16:47:14 steve Exp $"
#ident "$Id: words.cc,v 1.8 2007/01/16 05:44:17 steve Exp $"
#endif
# include "compile.h"
# include "vpi_priv.h"
# include "array.h"
# include <stdio.h>
# include <stdlib.h>
# include <string.h>
@ -51,13 +52,17 @@ void compile_var_real(char*label, char*name, int msb, int lsb)
* A variable is a special functor, so we allocate that functor and
* write the label into the symbol table.
*/
void compile_variable(char*label, char*name, int msb, int lsb,
char signed_flag)
static void __compile_var(char*label, char*name, char*array_label,
int msb, int lsb, char signed_flag)
{
unsigned wid = ((msb > lsb)? msb-lsb : lsb-msb) + 1;
vvp_fun_signal*vsig = new vvp_fun_signal(wid);
vvp_net_t*node = new vvp_net_t;
vvp_array_t array = array_label? array_find(array_label) : 0;
assert(array_label? array!=0 : true);
node->fun = vsig;
define_functor_symbol(label, node);
@ -66,10 +71,33 @@ void compile_variable(char*label, char*name, int msb, int lsb,
vpip_make_int(name, msb, lsb, node) :
vpip_make_reg(name, msb, lsb, signed_flag!=0, node);
compile_vpi_symbol(label, obj);
vpip_attach_to_current_scope(obj);
// If the signal has a name, then it goes into the current
// scope as a signal.
if (name) {
assert(!array);
vpip_attach_to_current_scope(obj);
}
// If this is an array word, then it does not have a name, and
// it is attached to the addressed array.
if (array) {
assert(!name);
array_attach_word(array, obj);
}
free(label);
free(name);
if (name) free(name);
if (array_label) free(array_label);
}
void compile_variable(char*label, char*name,
int msb, int lsb, char signed_flag)
{
__compile_var(label, name, 0, msb, lsb, signed_flag);
}
void compile_variablew(char*label, char*array_label,
int msb, int lsb, char signed_flag)
{
__compile_var(label, 0, array_label, msb, lsb, signed_flag);
}
/*
@ -83,14 +111,18 @@ void compile_variable(char*label, char*name, int msb, int lsb,
* Create a VPI handle to represent it, and fill that handle in with
* references into the net.
*/
void compile_net(char*label, char*name, int msb, int lsb,
bool signed_flag, bool net8_flag,
unsigned argc, struct symb_s*argv)
static void __compile_net(char*label, char*name, char*array_label,
int msb, int lsb,
bool signed_flag, bool net8_flag,
unsigned argc, struct symb_s*argv)
{
unsigned wid = ((msb > lsb)? msb-lsb : lsb-msb) + 1;
vvp_net_t*node = new vvp_net_t;
vvp_array_t array = array_label? array_find(array_label) : 0;
assert(array_label? array!=0 : true);
vvp_fun_signal_base*vsig = net8_flag
? dynamic_cast<vvp_fun_signal_base*>(new vvp_fun_signal8(wid))
: dynamic_cast<vvp_fun_signal_base*>(new vvp_fun_signal(wid));
@ -108,12 +140,35 @@ void compile_net(char*label, char*name, int msb, int lsb,
vpiHandle obj = vpip_make_net(name, msb, lsb, signed_flag, node);
compile_vpi_symbol(label, obj);
vpip_attach_to_current_scope(obj);
if (array)
array_attach_word(array, obj);
free(label);
free(name);
if (name) free(name);
if (array_label) free(array_label);
free(argv);
}
void compile_net(char*label, char*name,
int msb, int lsb,
bool signed_flag, bool net8_flag,
unsigned argc, struct symb_s*argv)
{
__compile_net(label, name, 0,
msb, lsb, signed_flag, net8_flag,
argc, argv);
}
void compile_netw(char*label, char*array_label,
int msb, int lsb,
bool signed_flag, bool net8_flag,
unsigned argc, struct symb_s*argv)
{
__compile_net(label, 0, array_label,
msb, lsb, signed_flag, net8_flag,
argc, argv);
}
void compile_net_real(char*label, char*name, int msb, int lsb,
unsigned argc, struct symb_s*argv)
{
@ -186,6 +241,12 @@ void compile_alias_real(char*label, char*name, int msb, int lsb,
/*
* $Log: words.cc,v $
* Revision 1.8 2007/01/16 05:44:17 steve
* Major rework of array handling. Memories are replaced with the
* more general concept of arrays. The NetMemory and NetEMemory
* classes are removed from the ivl core program, and the IVL_LPM_RAM
* lpm type is removed from the ivl_target API.
*
* Revision 1.7 2005/11/27 16:47:14 steve
* Fix type safety warning from gcc.
*