Allow part selects of memory words in l-values.

This commit is contained in:
steve 2006-02-02 02:43:57 +00:00
parent 3158e2caa1
commit d434dd7296
27 changed files with 610 additions and 337 deletions

17
PExpr.h
View File

@ -19,10 +19,11 @@
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#ifdef HAVE_CVS_IDENT
#ident "$Id: PExpr.h,v 1.76 2006/01/02 05:33:19 steve Exp $"
#ident "$Id: PExpr.h,v 1.77 2006/02/02 02:43:57 steve Exp $"
#endif
# include <string>
# include <vector>
# include "netlist.h"
# include "verinum.h"
# include "LineInfo.h"
@ -282,15 +283,16 @@ class PEIdent : public PExpr {
hname_t path_;
public:
// Use these to support bit- and part-select operators.
// Use these to support part-select operators.
PExpr*msb_;
PExpr*lsb_;
enum { SEL_NONE, SEL_BIT, SEL_PART, SEL_IDX_UP, SEL_IDX_DO } sel_;
enum { SEL_NONE, SEL_PART, SEL_IDX_UP, SEL_IDX_DO } sel_;
// If this is a reference to a memory, this is the index
// expression.
PExpr*idx_;
// If this is a reference to a memory/array, this is the index
// 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,
@ -546,6 +548,9 @@ class PECallFunction : public PExpr {
/*
* $Log: PExpr.h,v $
* Revision 1.77 2006/02/02 02:43:57 steve
* Allow part selects of memory words in l-values.
*
* Revision 1.76 2006/01/02 05:33:19 steve
* Node delays can be more general expressions in structural contexts.
*

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.163 2005/08/27 04:32:08 steve Exp $"
#ident "$Id: design_dump.cc,v 1.164 2006/02/02 02:43:57 steve Exp $"
#endif
# include "config.h"
@ -537,8 +537,8 @@ void NetAssign_::dump_lval(ostream&o) const
if (bmux_) {
o << "[" << *bmux_ << "]";
} else {
o << "[" << (loff_+lwid_-1) << ":" << loff_ << "]";
} else if (base_) {
o << "[" << *base_ << " +: " << lwid_ << "]";
}
} else if (mem_) {
// Is there an obvious way to flag memories in the dump
@ -548,6 +548,10 @@ void NetAssign_::dump_lval(ostream&o) const
if (bmux_) o << *bmux_;
else o << "**oops**";
o << "]";
if (base_) {
o << "[" << *base_ << " +: " << lwid_ << "]";
}
} else {
o << "";
}
@ -1166,6 +1170,9 @@ void Design::dump(ostream&o) const
/*
* $Log: design_dump.cc,v $
* Revision 1.164 2006/02/02 02:43:57 steve
* Allow part selects of memory words in l-values.
*
* Revision 1.163 2005/08/27 04:32:08 steve
* Handle synthesis of fully packed case statements.
*

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.101 2005/11/27 05:56:20 steve Exp $"
#ident "$Id: elab_expr.cc,v 1.102 2006/02/02 02:43:57 steve Exp $"
#endif
# include "config.h"
@ -515,7 +515,15 @@ NetExpr* PEIdent::elaborate_expr(Design*des, NetScope*scope,
// memory reference and I must generate a NetEMemory
// object to handle it.
if (mem != 0) {
if (msb_ == 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.
@ -533,27 +541,92 @@ NetExpr* PEIdent::elaborate_expr(Design*des, NetScope*scope,
return 0;
}
assert(msb_ != 0);
if (lsb_) {
cerr << get_line() << ": error: part select of a memory: "
<< mem->name() << endl;
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;
}
assert(lsb_ == 0);
assert(idx_ == 0);
NetExpr*i = msb_->elaborate_expr(des, scope);
if (msb_ && i == 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);
if (i == 0) {
cerr << get_line() << ": error: Unable to elaborate "
"index expression `" << *msb_ << "'" << endl;
"index expression `" << *addr << "'" << endl;
des->errors += 1;
return 0;
}
NetEMemory*node = new NetEMemory(mem, i);
node->set_line(*this);
return node;
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_);
NetExpr*me = elab_and_eval(des, scope, msb_);
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_);
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_);
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;
}
// If the identifier is a named event.
@ -613,6 +686,7 @@ NetExpr* PEIdent::elaborate_expr_param(Design*des,
if (sel_ == SEL_PART) {
assert(msb_ && lsb_);
assert(idx_.empty());
/* If the identifier has a part select, we support
it by pulling the right bits out and making a
@ -681,6 +755,7 @@ NetExpr* PEIdent::elaborate_expr_param(Design*des,
} else if (sel_ == SEL_IDX_UP || sel_ == SEL_IDX_DO) {
assert(msb_);
assert(lsb_);
assert(idx_.empty());
/* Get and evaluate the width of the index
select. This must be constant. */
@ -710,14 +785,16 @@ NetExpr* PEIdent::elaborate_expr_param(Design*des,
tmp = new NetESelect(tmp, idx_ex, wid);
} else if (sel_ == SEL_BIT) {
assert(msb_);
} else if (!idx_.empty()) {
assert(!msb_);
assert(!lsb_);
assert(idx_.size() == 1);
assert(sel_ == SEL_NONE);
/* Handle the case where a parameter has a bit
select attached to it. Generate a NetESelect
object to select the bit as desired. */
NetExpr*mtmp = msb_->elaborate_expr(des, scope);
NetExpr*mtmp = idx_[0]->elaborate_expr(des, scope);
if (! dynamic_cast<NetEConst*>(mtmp)) {
NetExpr*re = mtmp->eval_tree();
if (re) {
@ -815,7 +892,7 @@ NetExpr* PEIdent::elaborate_expr_net_part_(Design*des, NetScope*scope,
{
assert(lsb_ != 0);
assert(msb_ != 0);
assert(idx_ == 0);
assert(idx_.empty());
verinum*lsn = lsb_->eval_const(des, scope);
verinum*msn = msb_->eval_const(des, scope);
@ -891,7 +968,7 @@ NetExpr* PEIdent::elaborate_expr_net_idx_up_(Design*des, NetScope*scope,
{
assert(lsb_ != 0);
assert(msb_ != 0);
assert(idx_ == 0);
assert(idx_.empty());
NetESignal*sig = new NetESignal(net);
sig->set_line(*this);
@ -944,7 +1021,7 @@ NetExpr* PEIdent::elaborate_expr_net_idx_do_(Design*des, NetScope*scope,
{
assert(lsb_ != 0);
assert(msb_ != 0);
assert(idx_ == 0);
assert(idx_.empty());
NetESignal*sig = new NetESignal(net);
sig->set_line(*this);
@ -993,14 +1070,14 @@ 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
{
assert(msb_ != 0);
assert(msb_ == 0);
assert(lsb_ == 0);
assert(idx_ == 0);
assert(idx_.size() == 1);
// If the bit select is constant, then treat it similar
// to the part select, so that I save the effort of
// making a mux part in the netlist.
if (verinum*msn = msb_->eval_const(des, scope)) {
if (verinum*msn = idx_[0]->eval_const(des, scope)) {
long msv = msn->as_long();
unsigned idx = net->sb_to_idx(msv);
@ -1047,7 +1124,7 @@ NetExpr* PEIdent::elaborate_expr_net_bit_(Design*des, NetScope*scope,
// complicated task because we need to generate
// expressions to convert calculated bit select
// values to canonical values that are used internally.
NetExpr*ex = msb_->elaborate_expr(des, scope);
NetExpr*ex = idx_[0]->elaborate_expr(des, scope);
if (net->msb() < net->lsb()) {
ex = make_sub_expr(net->lsb(), ex);
@ -1070,22 +1147,22 @@ NetExpr* PEIdent::elaborate_expr_net(Design*des, NetScope*scope,
if (sel_ == SEL_PART)
return elaborate_expr_net_part_(des, scope, net, found_in);
if (sel_ == SEL_BIT)
return elaborate_expr_net_bit_(des, scope, net, found_in);
if (sel_ == SEL_IDX_UP)
return elaborate_expr_net_idx_up_(des, scope, net, found_in);
if (sel_ == SEL_IDX_DO)
return elaborate_expr_net_idx_do_(des, scope, net, found_in);
if (!idx_.empty())
return elaborate_expr_net_bit_(des, scope, net, found_in);
// It's not anything else, so this must be a simple identifier
// expression with no part or bit select. Return the signal
// itself as the expression.
assert(sel_ == SEL_NONE);
assert(msb_ == 0);
assert(lsb_ == 0);
assert(idx_ == 0);
assert(idx_.empty());
NetESignal*node = new NetESignal(net);
node->set_line(*this);
@ -1268,6 +1345,9 @@ NetExpr* PEUnary::elaborate_expr(Design*des, NetScope*scope, bool) const
/*
* $Log: elab_expr.cc,v $
* Revision 1.102 2006/02/02 02:43:57 steve
* Allow part selects of memory words in l-values.
*
* Revision 1.101 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: elab_lval.cc,v 1.32 2005/07/11 16:56:50 steve Exp $"
#ident "$Id: elab_lval.cc,v 1.33 2006/02/02 02:43:57 steve Exp $"
#endif
# include "config.h"
@ -195,7 +195,9 @@ NetAssign_* PEIdent::elaborate_lval(Design*des,
long msb, lsb;
NetExpr*mux;
if (msb_ && lsb_) {
if (msb_ || lsb_) {
assert(msb_ && lsb_);
/* This handles part selects. In this case, there are
two bit select expressions, and both must be
constant. Evaluate them and pass the results back to
@ -225,17 +227,19 @@ NetAssign_* PEIdent::elaborate_lval(Design*des,
lsb = vl->as_long();
mux = 0;
} else if (msb_) {
} else if (! idx_.empty()) {
/* If there is only a single select expression, it is a
bit select. Evaluate the constant value and treat it
as a part select with a bit width of 1. If the
expression it not constant, then return the
expression as a mux. */
assert(msb_ == 0);
assert(lsb_ == 0);
verinum*v = msb_->eval_const(des, scope);
assert(idx_.size() == 1);
verinum*v = idx_[0]->eval_const(des, scope);
if (v == 0) {
NetExpr*m = msb_->elaborate_expr(des, scope);
NetExpr*m = idx_[0]->elaborate_expr(des, scope);
assert(m);
msb = 0;
lsb = 0;
@ -271,6 +275,12 @@ NetAssign_* PEIdent::elaborate_lval(Design*des,
lv->set_bmux(mux);
} else if (msb == reg->msb() && lsb == reg->lsb()) {
/* No bit select, and part select covers the entire
vector. Simplest case. */
lv = new NetAssign_(reg);
} else {
/* If the bit/part select is constant, then make the
@ -302,7 +312,7 @@ NetAssign_* PEIdent::elaborate_lval(Design*des,
}
lv = new NetAssign_(reg);
lv->set_part(loff, wid);
lv->set_part(new NetEConst(verinum(loff)), wid);
}
@ -312,7 +322,7 @@ NetAssign_* PEIdent::elaborate_lval(Design*des,
NetAssign_* PEIdent::elaborate_mem_lval_(Design*des, NetScope*scope,
NetMemory*mem) const
{
if (msb_ == 0) {
if (idx_.empty()) {
cerr << get_line() << ": error: Assign to memory \""
<< mem->name() << "\" requires a word select index."
<< endl;
@ -320,33 +330,82 @@ NetAssign_* PEIdent::elaborate_mem_lval_(Design*des, NetScope*scope,
return 0;
}
if (msb_ && lsb_) {
cerr << get_line() << ": error: Cannot use part select on "
<< "memory \"" << mem->name() << ".\"" << endl;
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;
}
assert(msb_ && !lsb_);
// XXXX For now, require exactly 1 index.
assert(idx_.size() == 1);
NetExpr*ix = msb_->elaborate_expr(des, scope);
/* Elaborate the address expression. */
NetExpr*ix = elab_and_eval(des, scope, idx_[0]);
if (ix == 0)
return 0;
/* Evaluate the memory index expression down as must as
possible. Ideally, we can get it down to a constant. */
if (! dynamic_cast<NetEConst*>(ix)) {
NetExpr*tmp = ix->eval_tree();
if (tmp) {
tmp->set_line(*ix);
delete ix;
ix = tmp;
}
}
NetAssign_*lv = new NetAssign_(mem);
lv->set_bmux(ix);
lv->set_part(0, mem->width());
/* If there is no extra part select, then we are done. */
if (msb_ == 0 && lsb_ == 0) {
lv->set_part(0U, mem->width());
return lv;
}
assert(sel_ != SEL_NONE);
assert(msb_ && lsb_);
if (sel_ == SEL_PART) {
NetExpr*le = elab_and_eval(des, scope, lsb_);
NetExpr*me = elab_and_eval(des, scope, msb_);
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_);
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_);
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;
}
@ -360,6 +419,9 @@ NetAssign_* PENumber::elaborate_lval(Design*des, NetScope*, bool) const
/*
* $Log: elab_lval.cc,v $
* Revision 1.33 2006/02/02 02:43:57 steve
* Allow part selects of memory words in l-values.
*
* Revision 1.32 2005/07/11 16:56:50 steve
* Remove NetVariable and ivl_variable_t structures.
*

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_net.cc,v 1.177 2006/01/02 05:33:19 steve Exp $"
#ident "$Id: elab_net.cc,v 1.178 2006/02/02 02:43:57 steve Exp $"
#endif
# include "config.h"
@ -1466,11 +1466,15 @@ NetNet* PEIdent::elaborate_net_bitmux_(Design*des, NetScope*scope,
Link::strength_t drive0,
Link::strength_t drive1) const
{
assert(msb_ == 0);
assert(lsb_ == 0);
assert(idx_.size() == 1);
/* Elaborate the selector. */
NetNet*sel;
if (sig->msb() < sig->lsb()) {
NetExpr*sel_expr = msb_->elaborate_expr(des, scope);
NetExpr*sel_expr = idx_[0]->elaborate_expr(des, scope);
sel_expr = make_sub_expr(sig->lsb(), sel_expr);
if (NetExpr*tmp = sel_expr->eval_tree()) {
delete sel_expr;
@ -1480,7 +1484,7 @@ NetNet* PEIdent::elaborate_net_bitmux_(Design*des, NetScope*scope,
sel = sel_expr->synthesize(des);
} else if (sig->lsb() != 0) {
NetExpr*sel_expr = msb_->elaborate_expr(des, scope);
NetExpr*sel_expr = idx_[0]->elaborate_expr(des, scope);
sel_expr = make_add_expr(sel_expr, - sig->lsb());
if (NetExpr*tmp = sel_expr->eval_tree()) {
delete sel_expr;
@ -1490,7 +1494,7 @@ NetNet* PEIdent::elaborate_net_bitmux_(Design*des, NetScope*scope,
sel = sel_expr->synthesize(des);
} else {
sel = msb_->elaborate_net(des, scope, 0, 0, 0, 0);
sel = idx_[0]->elaborate_net(des, scope, 0, 0, 0, 0);
}
if (debug_elaborate) {
@ -1613,8 +1617,12 @@ NetNet* PEIdent::elaborate_net(Design*des, NetScope*scope,
/* Catch the case of a non-constant bit select. That should be
handled elsewhere. */
if (msb_ && !lsb_) {
verinum*mval = msb_->eval_const(des, scope);
if (! idx_.empty()) {
assert(msb_ == 0);
assert(lsb_ == 0);
assert(idx_.size() == 1);
verinum*mval = idx_[0]->eval_const(des, scope);
if (mval == 0) {
return elaborate_net_bitmux_(des, scope, sig, rise,
fall, decay, drive0, drive1);
@ -1666,20 +1674,24 @@ NetNet* PEIdent::elaborate_net_ram_(Design*des, NetScope*scope,
{
assert(scope);
if (msb_ == 0) {
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, msb_);
NetExpr*adr_expr = elab_and_eval(des, scope, idx_[0]);
/* If an offset is needed, subtract it from the address to get
an expression for the canonical address. */
@ -1905,8 +1917,11 @@ bool PEIdent::eval_part_select_(Design*des, NetScope*scope, NetNet*sig,
des->errors += 1;
}
} else if (msb_) {
verinum*mval = msb_->eval_const(des, scope);
} else if (!idx_.empty()) {
assert(msb_ == 0);
assert(lsb_ == 0);
assert(idx_.size() == 1);
verinum*mval = idx_[0]->eval_const(des, scope);
if (mval == 0) {
cerr << get_line() << ": index of " << path_ <<
" needs to be constant in this context." <<
@ -2645,6 +2660,9 @@ NetNet* PEUnary::elaborate_net(Design*des, NetScope*scope,
/*
* $Log: elab_net.cc,v $
* Revision 1.178 2006/02/02 02:43:57 steve
* Allow part selects of memory words in l-values.
*
* Revision 1.177 2006/01/02 05:33:19 steve
* Node delays can be more general expressions in structural contexts.
*

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_pexpr.cc,v 1.22 2005/11/27 05:56:20 steve Exp $"
#ident "$Id: elab_pexpr.cc,v 1.23 2006/02/02 02:43:58 steve Exp $"
#endif
# include "config.h"
@ -154,17 +154,20 @@ NetExpr*PEIdent::elaborate_pexpr(Design*des, NetScope*scope) const
res->set_line(*this);
assert(res);
assert(idx_ == 0);
if (msb_ && lsb_) {
assert(idx_.empty());
cerr << get_line() << ": sorry: Cannot part select "
"bits of parameters." << endl;
des->errors += 1;
} else if (msb_) {
} else if (!idx_.empty()) {
assert(msb_==0);
assert(lsb_==0);
assert(idx_.size() == 1);
/* We have here a bit select. Insert a NetESelect node
to handle it. */
NetExpr*tmp = msb_->elaborate_pexpr(des, scope);
NetExpr*tmp = idx_[0]->elaborate_pexpr(des, scope);
if (tmp != 0) {
res = new NetESelect(res, tmp, 1);
}
@ -233,6 +236,9 @@ NetExpr*PEUnary::elaborate_pexpr (Design*des, NetScope*scope) const
/*
* $Log: elab_pexpr.cc,v $
* Revision 1.23 2006/02/02 02:43:58 steve
* Allow part selects of memory words in l-values.
*
* Revision 1.22 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: ivl_target.h,v 1.164 2006/01/02 05:33:19 steve Exp $"
#ident "$Id: ivl_target.h,v 1.165 2006/02/02 02:43:58 steve Exp $"
#endif
#ifdef __cplusplus
@ -323,11 +323,11 @@ typedef enum ivl_statement_type_e {
/* This is the type of a variable, and also used as the type for an
expression. */
typedef enum ivl_variable_type_e {
IVL_VT_VOID = 0, /* Not used */
IVL_VT_NO_TYPE, /* Place holder for missing/unknown type. */
IVL_VT_REAL,
IVL_VT_BOOL,
IVL_VT_LOGIC,
IVL_VT_VOID = 0, /* Not used */
IVL_VT_NO_TYPE = 1, /* Place holder for missing/unknown type. */
IVL_VT_REAL = 2,
IVL_VT_BOOL = 3,
IVL_VT_LOGIC = 4,
IVL_VT_VECTOR = IVL_VT_LOGIC /* For compatibility */
} ivl_variable_type_t;
@ -1078,6 +1078,8 @@ extern ivl_memory_t ivl_lpm_memory(ivl_lpm_t net);
* returns an ivl_expr_t that represents that
* expression. Otherwise, it returns 0.
*
* (Should this be combined with ivl_lval_idx? -Ed)
*
* ivl_lval_mem
* If the l-value is a memory, this method returns an
* ivl_memory_t that represents that memory. Otherwise, it
@ -1089,7 +1091,9 @@ extern ivl_memory_t ivl_lpm_memory(ivl_lpm_t net);
*
* ivl_lval_part_off
* The part select of the signal is based here. This is the
* canonical index of bit-0 of the part select.
* canonical index of bit-0 of the part select. The return value is
* an ivl_expr_t. If the return value is nil, then take the offset
* as zero. Otherwise, evaluate the expression to get the offset.
*
* ivl_lval_idx
* If the l-value is a memory, this method returns an
@ -1120,7 +1124,7 @@ extern unsigned ivl_lval_width(ivl_lval_t net);
extern ivl_expr_t ivl_lval_mux(ivl_lval_t net);
extern ivl_expr_t ivl_lval_idx(ivl_lval_t net);
extern ivl_memory_t ivl_lval_mem(ivl_lval_t net);
extern unsigned ivl_lval_part_off(ivl_lval_t net);
extern ivl_expr_t ivl_lval_part_off(ivl_lval_t net);
extern ivl_signal_t ivl_lval_sig(ivl_lval_t net);
@ -1703,6 +1707,9 @@ _END_DECL
/*
* $Log: ivl_target.h,v $
* Revision 1.165 2006/02/02 02:43:58 steve
* Allow part selects of memory words in l-values.
*
* Revision 1.164 2006/01/02 05:33:19 steve
* Node delays can be more general expressions in structural contexts.
*

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.20 2005/07/11 16:56:50 steve Exp $"
#ident "$Id: net_assign.cc,v 1.21 2006/02/02 02:43:58 steve Exp $"
#endif
# include "config.h"
@ -39,18 +39,16 @@ unsigned count_lval_width(const NetAssign_*idx)
}
NetAssign_::NetAssign_(NetNet*s)
: sig_(s), mem_(0), bmux_(0)
: sig_(s), mem_(0), bmux_(0), base_(0)
{
loff_ = 0;
lwid_ = sig_->vector_width();
sig_->incr_lref();
more = 0;
}
NetAssign_::NetAssign_(NetMemory*s)
: sig_(0), mem_(s), bmux_(0)
: sig_(0), mem_(s), bmux_(0), base_(0)
{
loff_ = 0;
lwid_ = mem_->width();
more = 0;
}
@ -83,6 +81,11 @@ const NetExpr* NetAssign_::bmux() const
return bmux_;
}
const NetExpr* NetAssign_::get_base() const
{
return base_;
}
unsigned NetAssign_::lwidth() const
{
if (mem_) return lwid_;
@ -111,21 +114,10 @@ NetMemory* NetAssign_::mem() const
return mem_;
}
void NetAssign_::set_part(unsigned lo, unsigned lw)
void NetAssign_::set_part(NetExpr*base, unsigned wid)
{
loff_ = lo;
lwid_ = lw;
if (sig_) {
assert(sig_->vector_width() >= (lo + lw));
} else {
assert(mem_);
assert(lwid_ == mem_->width());
}
}
unsigned NetAssign_::get_loff() const
{
return loff_;
base_ = base;
lwid_ = wid;
}
/*
@ -283,6 +275,9 @@ NetRelease::~NetRelease()
/*
* $Log: net_assign.cc,v $
* Revision 1.21 2006/02/02 02:43:58 steve
* Allow part selects of memory words in l-values.
*
* Revision 1.20 2005/07/11 16:56:50 steve
* Remove NetVariable and ivl_variable_t structures.
*

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_link.cc,v 1.18 2005/09/25 23:40:11 steve Exp $"
#ident "$Id: net_link.cc,v 1.19 2006/02/02 02:43:58 steve Exp $"
#endif
# include "config.h"
@ -58,7 +58,10 @@ void connect(Nexus*l, Link&r)
void connect(Link&l, Link&r)
{
assert(&l != &r);
connect(l.nexus_, r);
if (r.is_linked() && !l.is_linked())
connect(r.nexus_, l);
else
connect(l.nexus_, r);
}
Link::Link()
@ -522,6 +525,9 @@ bool NexusSet::intersect(const NexusSet&that) const
/*
* $Log: net_link.cc,v $
* Revision 1.19 2006/02/02 02:43:58 steve
* Allow part selects of memory words in l-values.
*
* Revision 1.18 2005/09/25 23:40:11 steve
* Simplify NexusSet set handling.
*

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.354 2006/01/02 05:33:19 steve Exp $"
#ident "$Id: netlist.h,v 1.355 2006/02/02 02:43:58 steve Exp $"
#endif
/*
@ -791,7 +791,11 @@ class NetMemory {
// This is the width (in bits) of a single memory position.
unsigned width() const { return width_; }
// NetScope*scope();
// 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.
@ -1644,10 +1648,12 @@ class NetAssign_ {
NetExpr*bmux();
const NetExpr*bmux() const;
unsigned get_loff() 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_part(unsigned loff, unsigned wid);
void set_part(NetExpr* loff, unsigned wid);
// Get the width of the r-value that this node expects. This
// method accounts for the presence of the mux, so it not
@ -1679,10 +1685,12 @@ class NetAssign_ {
private:
NetNet *sig_;
NetMemory*mem_;
// Memory word index
NetExpr*bmux_;
bool turn_sig_to_wire_on_release_;
unsigned loff_;
// indexed part select base
NetExpr*base_;
unsigned lwid_;
};
@ -3451,6 +3459,9 @@ extern ostream& operator << (ostream&, NetNet::Type);
/*
* $Log: netlist.h,v $
* Revision 1.355 2006/02/02 02:43:58 steve
* Allow part selects of memory words in l-values.
*
* Revision 1.354 2006/01/02 05:33:19 steve
* Node delays can be more general expressions in structural contexts.
*

176
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.208 2005/12/05 21:21:18 steve Exp $"
#ident "$Id: parse.y,v 1.209 2006/02/02 02:43:59 steve Exp $"
#endif
# include "config.h"
@ -104,6 +104,8 @@ const static struct str_pair_t str_strength = { PGate::STRONG, PGate::STRONG };
svector<PEEvent*>*event_expr;
PEIdent*indexed_identifier;
NetNet::Type nettype;
PGBuiltin::Type gatetype;
NetNet::PortType porttype;
@ -193,11 +195,12 @@ const static struct str_pair_t str_strength = { PGate::STRONG, PGate::STRONG };
%type <gates> gate_instance_list
%type <expr> expression expr_primary
%type <expr> lavalue lpvalue
%type <expr> lpvalue
%type <expr> delay_value delay_value_simple
%type <exprs> delay1 delay3 delay3_opt
%type <exprs> expression_list
%type <exprs> assign assign_list
%type <indexed_identifier> indexed_identifier
%type <exprs> range range_opt
%type <nettype> net_type var_type net_type_opt
@ -967,13 +970,6 @@ expr_primary
tmp->set_lineno(@1.first_line);
$$ = tmp;
}
| identifier
{ PEIdent*tmp = new PEIdent(*$1);
tmp->set_file(@1.text);
tmp->set_lineno(@1.first_line);
$$ = tmp;
delete $1;
}
| SYSTEM_IDENTIFIER
{ PECallFunction*tmp = new PECallFunction(hname_t($1));
tmp->set_file(@1.text);
@ -981,13 +977,12 @@ expr_primary
$$ = tmp;
delete $1;
}
| identifier '[' expression ']'
{ PEIdent*tmp = new PEIdent(*$1);
tmp->set_file(@1.text);
tmp->set_lineno(@1.first_line);
tmp->msb_ = $3;
tmp->sel_ = PEIdent::SEL_BIT;
delete $1;
/* The indexed_identifier rule matches simple identifiers as well as
indexed arrays. Part selects are handled below. */
| indexed_identifier
{ PEIdent*tmp = $1;
$$ = tmp;
}
@ -996,34 +991,25 @@ expr_primary
place of the : in the basic part select, and the first expression
is not limited to constant values. */
| identifier '[' expression ':' expression ']'
{ PEIdent*tmp = new PEIdent(*$1);
tmp->set_file(@1.text);
tmp->set_lineno(@1.first_line);
| indexed_identifier '[' expression ':' expression ']'
{ PEIdent*tmp = $1;
tmp->msb_ = $3;
tmp->lsb_ = $5;
tmp->sel_ = PEIdent::SEL_PART;
delete $1;
$$ = tmp;
}
| identifier '[' expression K_PO_POS expression ']'
{ PEIdent*tmp = new PEIdent(*$1);
tmp->set_file(@1.text);
tmp->set_lineno(@1.first_line);
| indexed_identifier '[' expression K_PO_POS expression ']'
{ PEIdent*tmp = $1;
tmp->msb_ = $3;
tmp->lsb_ = $5;
tmp->sel_ = PEIdent::SEL_IDX_UP;
delete $1;
$$ = tmp;
}
| identifier '[' expression K_PO_NEG expression ']'
{ PEIdent*tmp = new PEIdent(*$1);
tmp->set_file(@1.text);
tmp->set_lineno(@1.first_line);
| indexed_identifier '[' expression K_PO_NEG expression ']'
{ PEIdent*tmp = $1;
tmp->msb_ = $3;
tmp->lsb_ = $5;
tmp->sel_ = PEIdent::SEL_IDX_DO;
delete $1;
$$ = tmp;
}
@ -1075,7 +1061,6 @@ expr_primary
}
;
/* A function_item is either a block item (i.e. a reg or integer
declaration) or an input declaration. There are no output or
inout ports. */
@ -1260,6 +1245,24 @@ identifier
}
;
/* An indexed_identifier is an identifier with a bit-select
expression. This bit select may be an array index or bit index,
to be sorted out later. */
indexed_identifier
: identifier
{ PEIdent*tmp = new PEIdent(*$1);
tmp->sel_ = PEIdent::SEL_NONE;
tmp->set_file(@1.text);
tmp->set_lineno(@1.first_line);
delete $1;
$$ = tmp;
}
| indexed_identifier '[' expression ']'
{ PEIdent*tmp = $1;
tmp->idx_.push_back($3);
$$ = tmp;
}
/* This is a list of identifiers. The result is a list of strings,
each one of the identifiers in the list. These are simple,
non-hierarchical names separated by ',' characters. */
@ -1436,80 +1439,33 @@ net_type_opt
signed_opt : K_signed { $$ = true; } | {$$ = false; } ;
/* An lavalue is the expression that can go on the left side of a
continuous assign statement. This checks (where it can) that the
expression meets the constraints of continuous assignments. */
lavalue
: identifier
{ PEIdent*tmp = new PEIdent(*$1);
tmp->set_file(@1.text);
tmp->set_lineno(@1.first_line);
delete $1;
$$ = tmp;
}
| identifier '[' expression ']'
{ PEIdent*tmp = new PEIdent(*$1);
PExpr*sel = $3;
if (! pform_expression_is_constant(sel)) {
yyerror(@2, "error: Bit select in lvalue must "
"contain a constant expression.");
delete sel;
} else {
tmp->msb_ = sel;
}
tmp->sel_ = PEIdent::SEL_BIT;
tmp->set_file(@1.text);
tmp->set_lineno(@1.first_line);
delete $1;
$$ = tmp;
}
| identifier range
{ PEIdent*tmp = new PEIdent(*$1);
assert($2->count() == 2);
tmp->msb_ = (*$2)[0];
tmp->lsb_ = (*$2)[1];
tmp->sel_ = PEIdent::SEL_PART;
tmp->set_file(@1.text);
tmp->set_lineno(@1.first_line);
delete $1;
delete $2;
$$ = tmp;
}
| '{' expression_list '}'
{ PEConcat*tmp = new PEConcat(*$2);
tmp->set_file(@1.text);
tmp->set_lineno(@1.first_line);
delete $2;
$$ = tmp;
}
;
/* An lpvalue is the expression that can go on the left side of a
procedural assignment. This rule handles only procedural assignments. */
procedural assignment. This rule handles only procedural
assignments. It is more limited then the general expr_primary
rule to reflect the rules for assignment l-values. */
lpvalue
: identifier
{ PEIdent*tmp = new PEIdent(*$1);
tmp->set_file(@1.text);
tmp->set_lineno(@1.first_line);
delete $1;
: indexed_identifier
{ PEIdent*tmp = $1;
$$ = tmp;
}
| identifier '[' expression ']'
{ PEIdent*tmp = new PEIdent(*$1);
tmp->msb_ = $3;
tmp->set_file(@1.text);
tmp->set_lineno(@1.first_line);
delete $1;
$$ = tmp;
}
| identifier '[' expression ':' expression ']'
{ PEIdent*tmp = new PEIdent(*$1);
| indexed_identifier '[' expression ':' expression ']'
{ PEIdent*tmp = $1;
tmp->msb_ = $3;
tmp->lsb_ = $5;
tmp->set_file(@1.text);
tmp->set_lineno(@1.first_line);
delete $1;
$$ = tmp;
}
| indexed_identifier '[' expression K_PO_POS expression ']'
{ PEIdent*tmp = $1;
tmp->msb_ = $3;
tmp->lsb_ = $5;
tmp->sel_ = PEIdent::SEL_IDX_UP;
$$ = tmp;
}
| indexed_identifier '[' expression K_PO_NEG expression ']'
{ PEIdent*tmp = $1;
tmp->msb_ = $3;
tmp->lsb_ = $5;
tmp->sel_ = PEIdent::SEL_IDX_DO;
$$ = tmp;
}
| '{' expression_list '}'
@ -1522,7 +1478,7 @@ lpvalue
;
assign
: lavalue '=' expression
: lpvalue '=' expression
{ svector<PExpr*>*tmp = new svector<PExpr*>(2);
(*tmp)[0] = $1;
(*tmp)[1] = $3;
@ -2595,14 +2551,14 @@ statement
off. This stronger then any other assign, but weaker then the
force assignments. */
: K_assign lavalue '=' expression ';'
: K_assign lpvalue '=' expression ';'
{ PCAssign*tmp = new PCAssign($2, $4);
tmp->set_file(@1.text);
tmp->set_lineno(@1.first_line);
$$ = tmp;
}
| K_deassign lavalue ';'
| K_deassign lpvalue ';'
{ PDeassign*tmp = new PDeassign($2);
tmp->set_file(@1.text);
tmp->set_lineno(@1.first_line);
@ -2613,13 +2569,13 @@ statement
/* Force and release statements are similar to assignments,
syntactically, but they will be elaborated differently. */
| K_force lavalue '=' expression ';'
| K_force lpvalue '=' expression ';'
{ PForce*tmp = new PForce($2, $4);
tmp->set_file(@1.text);
tmp->set_lineno(@1.first_line);
$$ = tmp;
}
| K_release lavalue ';'
| K_release lpvalue ';'
{ PRelease*tmp = new PRelease($2);
tmp->set_file(@1.text);
tmp->set_lineno(@1.first_line);
@ -2843,12 +2799,22 @@ statement
tmp->set_lineno(@1.first_line);
$$ = tmp;
}
| error '=' expression ';'
{ yyerror(@1, "Syntax in assignment statement l-value.");
yyerrok;
$$ = new PNoop;
}
| lpvalue K_LE expression ';'
{ PAssignNB*tmp = new PAssignNB($1,$3);
tmp->set_file(@1.text);
tmp->set_lineno(@1.first_line);
$$ = tmp;
}
| error K_LE expression ';'
{ yyerror(@1, "Syntax in assignment statement l-value.");
yyerrok;
$$ = new PNoop;
}
| lpvalue '=' delay1 expression ';'
{ assert($3->count() == 1);
PExpr*del = (*$3)[0];

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.132 2006/01/02 05:33:19 steve Exp $"
#ident "$Id: t-dll-api.cc,v 1.133 2006/02/02 02:43:59 steve Exp $"
#endif
# include "config.h"
@ -1217,10 +1217,10 @@ extern "C" ivl_memory_t ivl_lval_mem(ivl_lval_t net)
return 0x0;
}
extern "C" unsigned ivl_lval_part_off(ivl_lval_t net)
extern "C" ivl_expr_t ivl_lval_part_off(ivl_lval_t net)
{
assert(net);
return net->loff_;
return net->loff;
}
extern "C" unsigned ivl_lval_width(ivl_lval_t net)
@ -2033,6 +2033,9 @@ extern "C" ivl_statement_t ivl_stmt_sub_stmt(ivl_statement_t net)
/*
* $Log: t-dll-api.cc,v $
* Revision 1.133 2006/02/02 02:43:59 steve
* Allow part selects of memory words in l-values.
*
* Revision 1.132 2006/01/02 05:33:19 steve
* Node delays can be more general expressions in structural contexts.
*

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.67 2005/07/11 16:56:51 steve Exp $"
#ident "$Id: t-dll-proc.cc,v 1.68 2006/02/02 02:43:59 steve Exp $"
#endif
# include "config.h"
@ -154,9 +154,18 @@ void dll_target::make_assign_lvals_(const NetAssignBase*net)
for (unsigned idx = 0 ; idx < cnt ; idx += 1) {
struct ivl_lval_s*cur = stmt_cur_->u_.assign_.lval_ + idx;
const NetAssign_*asn = net->l_val(idx);
const NetExpr*loff = asn->get_base();
if (loff == 0) {
cur->loff = 0;
} else {
loff->expr_scan(this);
cur->loff = expr_;
expr_ = 0;
}
cur->width_ = asn->lwidth();
cur->loff_ = asn->get_loff();
if (asn->sig()) {
cur->type_ = IVL_LVAL_REG;
cur->n.sig = find_signal(des_, asn->sig());
@ -732,6 +741,9 @@ void dll_target::proc_while(const NetWhile*net)
/*
* $Log: t-dll-proc.cc,v $
* Revision 1.68 2006/02/02 02:43:59 steve
* Allow part selects of memory words in l-values.
*
* Revision 1.67 2005/07/11 16:56:51 steve
* Remove NetVariable and ivl_variable_t structures.
*

11
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.129 2006/01/02 05:33:19 steve Exp $"
#ident "$Id: t-dll.h,v 1.130 2006/02/02 02:43:59 steve Exp $"
#endif
# include "target.h"
@ -379,10 +379,10 @@ enum ivl_lval_type_t {
};
struct ivl_lval_s {
unsigned width_;
unsigned loff_;
unsigned type_ : 8;
ivl_expr_t loff;
ivl_expr_t idx;
unsigned width_;
unsigned type_ : 8;
union {
ivl_signal_t sig;
ivl_memory_t mem;
@ -671,6 +671,9 @@ struct ivl_statement_s {
/*
* $Log: t-dll.h,v $
* Revision 1.130 2006/02/02 02:43:59 steve
* Allow part selects of memory words in l-values.
*
* Revision 1.129 2006/01/02 05:33:19 steve
* Node delays can be more general expressions in structural contexts.
*

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.8 2005/11/20 15:58:53 steve Exp $"
#ident "$Id: statement.c,v 1.9 2006/02/02 02:43:59 steve Exp $"
#endif
# include "config.h"
@ -32,11 +32,18 @@ static unsigned show_assign_lval(ivl_lval_t lval, unsigned ind)
if ( (mem = ivl_lval_mem(lval)) ) {
ivl_scope_t scope = ivl_memory_scope(mem);
fprintf(out, "%*s{ %s . %s [\n", ind, "",
fprintf(out, "%*s{ %s.%s width=%u }\n", ind, "",
ivl_scope_name(scope),
ivl_memory_basename(mem));
show_expression(ivl_lval_idx(lval), ind+4);
fprintf(out, "%*s] width=%u }\n", ind, "", ivl_lval_width(lval));
ivl_memory_basename(mem),
ivl_lval_width(lval));
fprintf(out, "%*sAddress-0 expression:\n", ind+4, "");
show_expression(ivl_lval_idx(lval), ind+8);
if (ivl_lval_part_off(lval)) {
fprintf(out, "%*sPart select base:\n", ind+4, "");
show_expression(ivl_lval_part_off(lval), ind+8);
}
/* When the l-value is a memory word, the lval_width
must exactly match the word width. */
@ -50,16 +57,20 @@ static unsigned show_assign_lval(ivl_lval_t lval, unsigned ind)
} else {
ivl_signal_t sig = ivl_lval_sig(lval);
fprintf(out, "%*s{name=%s width=%u part_off=%u lvwidth=%u}\n",
fprintf(out, "%*s{name=%s width=%u lvwidth=%u}\n",
ind, "",
ivl_signal_name(sig),
ivl_signal_width(sig),
ivl_lval_part_off(lval),
ivl_lval_width(lval));
if (ivl_lval_mux(lval)) {
fprintf(out, "%*sBit select expression:\n", ind+4, "");
show_expression(ivl_lval_mux(lval), ind+8);
}
if (ivl_lval_part_off(lval)) {
fprintf(out, "%*sPart select base:\n", ind+4, "");
show_expression(ivl_lval_part_off(lval), ind+8);
}
wid = ivl_lval_width(lval);
}

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.129 2006/01/02 05:33:20 steve Exp $"
#ident "$Id: eval_expr.c,v 1.130 2006/02/02 02:43:59 steve Exp $"
#endif
# include "vvp_priv.h"
@ -101,6 +101,38 @@ unsigned long get_number_immediate(ivl_expr_t ex)
return imm;
}
/*
* This function, in addition to setting the value into index 0, sets
* bit 4 to 1 if the value is unknown.
*/
void draw_eval_expr_into_integer(ivl_expr_t expr, unsigned ix)
{
struct vector_info vec;
int word;
switch (ivl_expr_value(expr)) {
case IVL_VT_BOOL:
case IVL_VT_LOGIC:
vec = draw_eval_expr(expr, 0);
fprintf(vvp_out, " %%ix/get %u, %u, %u;\n",
ix, vec.base, vec.wid);
clr_vector(vec);
break;
case IVL_VT_REAL:
word = draw_eval_real(expr);
clr_word(word);
fprintf(vvp_out, " %%cvt/ir %u, %u;\n", ix, word);
break;
default:
fprintf(stderr, "XXXX ivl_expr_value == %d\n",
ivl_expr_value(expr));
assert(0);
}
}
/*
* The STUFF_OK_XZ bit is true if the output is going to be further
* processed so that x and z values are equivilent. This may allow for
@ -2177,6 +2209,9 @@ struct vector_info draw_eval_expr(ivl_expr_t exp, int stuff_ok_flag)
/*
* $Log: eval_expr.c,v $
* Revision 1.130 2006/02/02 02:43:59 steve
* Allow part selects of memory words in l-values.
*
* Revision 1.129 2006/01/02 05:33:20 steve
* Node delays can be more general expressions in structural contexts.
*

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.39 2005/10/12 17:26:17 steve Exp $"
#ident "$Id: vvp_priv.h,v 1.40 2006/02/02 02:43:59 steve Exp $"
#endif
# include "vvp_config.h"
@ -150,6 +150,13 @@ extern struct vector_info draw_eval_expr_wid(ivl_expr_t exp, unsigned w,
*/
extern void draw_memory_index_expr(ivl_memory_t mem, ivl_expr_t exp);
/*
* This evaluates an expression and leaves the result in the numbered
* integer index register. It also will set bit-4 to 1 if the value is
* not fully defined (i.e. contains x or z).
*/
extern void draw_eval_expr_into_integer(ivl_expr_t expr, unsigned ix);
/*
* These functions manage vector allocation in the thread register
* space. They presume that we work on one thread at a time, to
@ -245,6 +252,9 @@ extern unsigned thread_count;
/*
* $Log: vvp_priv.h,v $
* Revision 1.40 2006/02/02 02:43:59 steve
* Allow part selects of memory words in l-values.
*
* Revision 1.39 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: vvp_process.c,v 1.121 2005/11/26 17:23:17 steve Exp $"
#ident "$Id: vvp_process.c,v 1.122 2006/02/02 02:43:59 steve Exp $"
#endif
# include "vvp_priv.h"
@ -29,7 +29,6 @@
# include <stdlib.h>
static int show_statement(ivl_statement_t net, ivl_scope_t sscope);
static void draw_eval_expr_into_integer(ivl_expr_t expr, unsigned ix);
unsigned local_count = 0;
unsigned thread_count = 0;
@ -76,7 +75,15 @@ static void set_to_lvariable(ivl_lval_t lval,
unsigned bit, unsigned wid)
{
ivl_signal_t sig = ivl_lval_sig(lval);
unsigned part_off = ivl_lval_part_off(lval);
ivl_expr_t part_off_ex = ivl_lval_part_off(lval);
unsigned part_off;
if (part_off_ex == 0) {
part_off = 0;
} else {
assert(number_is_immediate(part_off_ex, 64));
part_off = get_number_immediate(part_off_ex);
}
if (ivl_lval_mux(lval)) {
unsigned skip_set = transient_id++;
@ -117,10 +124,26 @@ static void set_to_lvariable(ivl_lval_t lval,
* the memory, and bit is the base of the thread vector. The wid is
* the width of the vector to be written to the word.
*/
static void set_to_memory_word(ivl_memory_t mem, unsigned idx,
static void set_to_memory_word(ivl_lval_t lval, unsigned idx,
unsigned bit, unsigned wid)
{
unsigned skip_set = transient_id++;
ivl_memory_t mem = ivl_lval_mem(lval);
/* Calculate the word part select into index-1 */
if (ivl_lval_part_off(lval)) {
draw_eval_expr_into_integer(ivl_lval_part_off(lval), 1);
fprintf(vvp_out, " %%jmp/1 t_%u, 4;\n", skip_set);
} else {
fprintf(vvp_out, " %%ix/load 1, 0;\n");
}
/* Calculate the memory address into index-3 */
draw_memory_index_expr(mem, ivl_lval_idx(lval));
fprintf(vvp_out, " %%jmp/1 t_%u, 4;\n", skip_set);
fprintf(vvp_out, " %%set/mv M_%p, %u, %u;\n", mem, bit, wid);
fprintf(vvp_out, "t_%u ;\n", skip_set);
}
static void assign_to_lvector(ivl_lval_t lval, unsigned bit,
@ -128,8 +151,16 @@ static void assign_to_lvector(ivl_lval_t lval, unsigned bit,
unsigned width)
{
ivl_signal_t sig = ivl_lval_sig(lval);
unsigned part_off = ivl_lval_part_off(lval);
ivl_expr_t part_off_ex = ivl_lval_part_off(lval);
ivl_expr_t mux = ivl_lval_mux(lval);
unsigned part_off;
if (part_off_ex == 0) {
part_off = 0;
} else {
assert(number_is_immediate(part_off_ex, 64));
part_off = get_number_immediate(part_off_ex);
}
if (mux != 0) {
unsigned skip_assign = transient_id++;
@ -166,42 +197,31 @@ static void assign_to_lvector(ivl_lval_t lval, unsigned bit,
}
}
static void assign_to_memory_word(ivl_memory_t mem, unsigned bit,
static void assign_to_memory_word(ivl_lval_t lval, unsigned bit,
unsigned delay, unsigned wid)
{
assert(wid = ivl_memory_width(mem));
unsigned skip_set = transient_id++;
ivl_memory_t mem = ivl_lval_mem(lval);
//assert(wid == ivl_memory_width(mem));
/* Calculate the word part select into index-1 */
if (ivl_lval_part_off(lval)) {
draw_eval_expr_into_integer(ivl_lval_part_off(lval), 1);
fprintf(vvp_out, " %%jmp/1 t_%u, 4;\n", skip_set);
} else {
fprintf(vvp_out, " %%ix/load 1, 0;\n");
}
/* Calculate the memory address into index-3 */
draw_memory_index_expr(mem, ivl_lval_idx(lval));
fprintf(vvp_out, " %%jmp/1 t_%u, 4;\n", skip_set);
/* Load the word/part-select width into index-0 */
fprintf(vvp_out, " %%ix/load 0, %u;\n", wid);
fprintf(vvp_out, " %%assign/mv M_%p, %u, %u;\n", mem, delay, bit);
}
fprintf(vvp_out, "t_%u ;\n", skip_set);
/*
* This function, in addition to setting the value into index 0, sets
* bit 4 to 1 if the value is unknown.
*/
static void draw_eval_expr_into_integer(ivl_expr_t expr, unsigned ix)
{
struct vector_info vec;
int word;
switch (ivl_expr_value(expr)) {
case IVL_VT_VECTOR:
vec = draw_eval_expr(expr, 0);
fprintf(vvp_out, " %%ix/get %u, %u, %u;\n",
ix, vec.base, vec.wid);
clr_vector(vec);
break;
case IVL_VT_REAL:
word = draw_eval_real(expr);
clr_word(word);
fprintf(vvp_out, " %%cvt/ir %u, %u;\n", ix, word);
break;
default:
assert(0);
}
clear_expression_lookaside();
}
static void calculate_into_x1(ivl_expr_t expr)
@ -225,23 +245,12 @@ static void set_vec_to_lval(ivl_statement_t net, struct vector_info res)
unsigned cur_rbit = 0;
for (lidx = 0 ; lidx < ivl_stmt_lvals(net) ; lidx += 1) {
unsigned skip_set = transient_id++;
unsigned skip_set_flag = 0;
unsigned bidx;
unsigned bit_limit = wid - cur_rbit;
lval = ivl_stmt_lval(net, lidx);
mem = ivl_lval_mem(lval);
if (mem) {
/* If a memory, then the idx expression is the
memory index, and the ivl_lval_mux should be
absent. */
assert(! ivl_lval_mux(lval));
draw_memory_index_expr(mem, ivl_lval_idx(lval));
fprintf(vvp_out, " %%jmp/1 t_%u, 4;\n", skip_set);
skip_set_flag = 1;
}
/* Reduce bit_limit to the width of this l-value. */
if (bit_limit > ivl_lval_width(lval))
@ -252,7 +261,7 @@ static void set_vec_to_lval(ivl_statement_t net, struct vector_info res)
bidx = res.base < 4? res.base : (res.base+cur_rbit);
if (mem) {
set_to_memory_word(mem, 3, bidx, bit_limit);
set_to_memory_word(lval, 3, bidx, bit_limit);
} else {
set_to_lvariable(lval, bidx, bit_limit);
@ -261,11 +270,6 @@ static void set_vec_to_lval(ivl_statement_t net, struct vector_info res)
/* Now we've consumed this many r-value bits for the
current l-value. */
cur_rbit += bit_limit;
if (skip_set_flag) {
fprintf(vvp_out, "t_%u ;\n", skip_set);
clear_expression_lookaside();
}
}
}
@ -440,17 +444,10 @@ static int show_stmt_assign_nb(ivl_statement_t net)
calculate_into_x1(del);
for (lidx = 0 ; lidx < ivl_stmt_lvals(net) ; lidx += 1) {
unsigned skip_set = transient_id++;
unsigned skip_set_flag = 0;
unsigned bit_limit = wid - cur_rbit;
lval = ivl_stmt_lval(net, lidx);
mem = ivl_lval_mem(lval);
if (mem) {
draw_memory_index_expr(mem, ivl_lval_idx(lval));
fprintf(vvp_out, " %%jmp/1 t_%u, 4;\n", skip_set);
skip_set_flag = 1;
}
if (bit_limit > ivl_lval_width(lval))
bit_limit = ivl_lval_width(lval);
@ -464,21 +461,16 @@ static int show_stmt_assign_nb(ivl_statement_t net)
} else {
unsigned bidx;
assert(mem);
/* XXXX don't yet know what to do with a delay
in an index variable. */
/* XXXX don't yet know what to do with a
non-constant delay exprssion. */
assert(del == 0);
bidx = res.base < 4? res.base : (res.base+cur_rbit);
assign_to_memory_word(mem, bidx, delay, bit_limit);
assign_to_memory_word(lval, bidx, delay, bit_limit);
}
cur_rbit += bit_limit;
if (skip_set_flag) {
fprintf(vvp_out, "t_%u ;\n", skip_set);
clear_expression_lookaside();
}
}
if (res.base > 3)
@ -747,7 +739,15 @@ static void force_vector_to_lval(ivl_statement_t net, struct vector_info rvec)
ivl_signal_t lsig = ivl_lval_sig(lval);
unsigned use_wid = ivl_lval_width(lval);
unsigned part_off = ivl_lval_part_off(lval);
ivl_expr_t part_off_ex = ivl_lval_part_off(lval);
unsigned part_off;
if (part_off_ex == 0) {
part_off = 0;
} else {
assert(number_is_immediate(part_off_ex, 64));
part_off = get_number_immediate(part_off_ex);
}
/* L-Value must be a signal: reg or wire */
assert(lsig != 0);
@ -1479,6 +1479,9 @@ int draw_func_definition(ivl_scope_t scope)
/*
* $Log: vvp_process.c,v $
* Revision 1.122 2006/02/02 02:43:59 steve
* Allow part selects of memory words in l-values.
*
* Revision 1.121 2005/11/26 17:23:17 steve
* Handle indexed l-value to force.
*

View File

@ -19,7 +19,7 @@
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#ifdef HAVE_CVS_IDENT
#ident "$Id: codes.h,v 1.77 2005/11/26 17:16:05 steve Exp $"
#ident "$Id: codes.h,v 1.78 2006/02/02 02:44:00 steve Exp $"
#endif
@ -41,7 +41,6 @@ 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_D(vthread_t thr, vvp_code_t code);
extern bool of_ASSIGN_MEM(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);
extern bool of_ASSIGN_V0D(vthread_t thr, vvp_code_t code);
@ -179,6 +178,9 @@ extern vvp_code_t codespace_null(void);
/*
* $Log: codes.h,v $
* Revision 1.78 2006/02/02 02:44:00 steve
* Allow part selects of memory words in l-values.
*
* Revision 1.77 2005/11/26 17:16:05 steve
* Force instruction that can be indexed.
*

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.216 2006/01/02 05:32:06 steve Exp $"
#ident "$Id: compile.cc,v 1.217 2006/02/02 02:44:00 steve Exp $"
#endif
# include "arith.h"
@ -87,7 +87,6 @@ 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/m",of_ASSIGN_MEM,3,{OA_MEM_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} },
@ -1511,6 +1510,9 @@ void compile_param_string(char*label, char*name, char*str, char*value)
/*
* $Log: compile.cc,v $
* Revision 1.217 2006/02/02 02:44:00 steve
* Allow part selects of memory words in l-values.
*
* Revision 1.216 2006/01/02 05:32:06 steve
* Require explicit delay node from source.
*

View File

@ -19,7 +19,7 @@
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#ifdef HAVE_CVS_IDENT
#ident "$Id: memory.cc,v 1.27 2005/06/22 00:04:49 steve Exp $"
#ident "$Id: memory.cc,v 1.28 2006/02/02 02:44:00 steve Exp $"
#endif
#include "memory.h"
@ -185,9 +185,24 @@ void memory_init_word(vvp_memory_t mem, unsigned addr, vvp_vector4_t val)
mem->words[addr] = val;
}
void memory_set_word(vvp_memory_t mem, unsigned addr, vvp_vector4_t val)
void memory_set_word(vvp_memory_t mem, unsigned addr,
unsigned off, vvp_vector4_t val)
{
memory_init_word(mem, addr, val);
if (addr >= mem->word_count)
return;
if (off >= mem->width)
return;
if (off == 0 && val.size() == mem->width) {
mem->words[addr] = val;
} else {
if ((off + val.size()) > mem->width)
val = val.subvalue(0, mem->width - off);
mem->words[addr].set_vec(off, val);
}
for (vvp_fun_memport*cur = mem->port_list
; cur ; cur = cur->next_) {
@ -249,6 +264,9 @@ void vvp_fun_memport::check_word_change(unsigned long addr)
/*
* $Log: memory.cc,v $
* Revision 1.28 2006/02/02 02:44:00 steve
* Allow part selects of memory words in l-values.
*
* Revision 1.27 2005/06/22 00:04:49 steve
* Reduce vvp_vector4 copies by using const references.
*

View File

@ -20,7 +20,7 @@
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#ifdef HAVE_CVS_IDENT
#ident "$Id: memory.h,v 1.10 2005/06/22 00:04:49 steve Exp $"
#ident "$Id: memory.h,v 1.11 2006/02/02 02:44:00 steve Exp $"
#endif
#include "vvp_net.h"
@ -69,6 +69,7 @@ extern void memory_init_word(vvp_memory_t mem,
vvp_vector4_t val);
extern void memory_set_word(vvp_memory_t mem,
unsigned idx,
unsigned off,
vvp_vector4_t val);
/*
@ -129,7 +130,8 @@ class vvp_fun_memport : public vvp_net_fun_t {
private:
vvp_memory_t mem_;
friend void memory_set_word(vvp_memory_t, unsigned, vvp_vector4_t);
friend void memory_set_word(vvp_memory_t, unsigned,
unsigned, vvp_vector4_t);
void check_word_change(unsigned long address);
class vvp_fun_memport*next_;
@ -152,6 +154,9 @@ vvp_memory_t memory_create(char *label);
/*
* $Log: memory.h,v $
* Revision 1.11 2006/02/02 02:44:00 steve
* Allow part selects of memory words in l-values.
*
* Revision 1.10 2005/06/22 00:04:49 steve
* Reduce vvp_vector4 copies by using const references.
*

View File

@ -1,7 +1,7 @@
/*
* Copyright (c) 2001-2003 Stephen Williams (steve@icarus.com)
*
* $Id: opcodes.txt,v 1.69 2005/11/26 17:16:05 steve Exp $
* $Id: opcodes.txt,v 1.70 2006/02/02 02:44:00 steve Exp $
*/
@ -57,13 +57,6 @@ means the following:
1 and 1 --> 1
otherwise x
* %assign/m <memory-label>, <delay>, <bit> (OBSOLETE)
This instruction does a non-blocking assignment to a bit in a memory
from 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.
* %assign/mv <memory-label>, <delay>, <bit>
the %assign/mv instruction assigns a vector value to a word in the
@ -73,6 +66,8 @@ 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.
@ -540,8 +535,12 @@ signal.
This sets a thread vector to a memory word. The <memory-label>
addresses a memory device, and the <bit>,<wid> describe a vector to be
written. Index register 3 contains the address of the word within the
memory. The address (in canonical form) is precalculated and loaded
into index register 3.
memory.
The base of a part select is retrieved from index register 1.
The address (in canonical form) is precalculated and loaded into index
register 3.
* %set/wr <vpi-label>, <bit>

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.40 2005/09/20 18:34:02 steve Exp $"
#ident "$Id: schedule.cc,v 1.41 2006/02/02 02:44:00 steve Exp $"
#endif
# include "schedule.h"
@ -136,13 +136,14 @@ struct assign_memory_word_s : public event_s {
vvp_memory_t mem;
unsigned adr;
vvp_vector4_t val;
unsigned off;
void run_run(void);
};
void assign_memory_word_s::run_run(void)
{
count_assign_events += 1;
memory_set_word(mem, adr, val);
memory_set_word(mem, adr, off, val);
}
struct generic_event_s : public event_s {
@ -463,12 +464,14 @@ void schedule_assign_vector(vvp_net_ptr_t ptr,
void schedule_assign_memory_word(vvp_memory_t mem,
unsigned word_addr,
unsigned off,
vvp_vector4_t val,
vvp_time64_t delay)
{
struct assign_memory_word_s*cur = new struct assign_memory_word_s;
cur->mem = mem;
cur->adr = word_addr;
cur->off = off;
cur->val = val;
schedule_event_(cur, delay, SEQ_NBASSIGN);
}
@ -605,6 +608,9 @@ void schedule_simulate(void)
/*
* $Log: schedule.cc,v $
* Revision 1.41 2006/02/02 02:44:00 steve
* Allow part selects of memory words in l-values.
*
* Revision 1.40 2005/09/20 18:34:02 steve
* Clean up compiler warnings.
*

View File

@ -19,7 +19,7 @@
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#ifdef HAVE_CVS_IDENT
#ident "$Id: schedule.h,v 1.26 2005/09/20 18:34:02 steve Exp $"
#ident "$Id: schedule.h,v 1.27 2006/02/02 02:44:00 steve Exp $"
#endif
# include "vthread.h"
@ -56,6 +56,7 @@ extern void schedule_assign_vector(vvp_net_ptr_t ptr,
extern void schedule_assign_memory_word(vvp_memory_t mem,
unsigned word_address,
unsigned off,
vvp_vector4_t val,
vvp_time64_t delay);
/*
@ -133,6 +134,9 @@ extern unsigned long count_event_pool;
/*
* $Log: schedule.h,v $
* Revision 1.27 2006/02/02 02:44:00 steve
* Allow part selects of memory words in l-values.
*
* Revision 1.26 2005/09/20 18:34:02 steve
* Clean up compiler warnings.
*

View File

@ -18,7 +18,7 @@
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#ifdef HAVE_CVS_IDENT
#ident "$Id: vpi_memory.cc,v 1.27 2005/06/17 05:13:07 steve Exp $"
#ident "$Id: vpi_memory.cc,v 1.28 2006/02/02 02:44:00 steve Exp $"
#endif
# include "vpi_priv.h"
@ -346,7 +346,7 @@ static vpiHandle memory_word_put(vpiHandle ref, p_vpi_value val)
assert(0);
}
memory_set_word(rfp->mem->mem, word_addr, put_val);
memory_set_word(rfp->mem->mem, word_addr, 0, put_val);
return 0;
}
@ -557,6 +557,9 @@ vpiHandle vpip_make_memory(vvp_memory_t mem, const char*name)
/*
* $Log: vpi_memory.cc,v $
* Revision 1.28 2006/02/02 02:44:00 steve
* Allow part selects of memory words in l-values.
*
* Revision 1.27 2005/06/17 05:13:07 steve
* Support set of IntVal to memory words.
*

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.150 2005/11/26 17:16:05 steve Exp $"
#ident "$Id: vthread.cc,v 1.151 2006/02/02 02:44:00 steve Exp $"
#endif
# include "config.h"
@ -606,17 +606,6 @@ bool of_ASSIGN_X0(vthread_t thr, vvp_code_t cp)
return true;
}
bool of_ASSIGN_MEM(vthread_t thr, vvp_code_t cp)
{
#if 0
unsigned char bit_val = thr_get_bit(thr, cp->bit_idx[1]);
schedule_memory(cp->mem, thr->words[3].w_int, bit_val, cp->bit_idx[0]);
#else
fprintf(stderr, "XXXX %%assign/m is obsolete.\n");
#endif
return true;
}
/* %assign/mv <memory>, <delay>, <bit>
* This generates an assignment event to a memory. Index register 0
* contains the width of the vector (and the word) and index register
@ -625,6 +614,7 @@ bool of_ASSIGN_MEM(vthread_t thr, vvp_code_t cp)
bool of_ASSIGN_MV(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);
@ -634,7 +624,7 @@ bool of_ASSIGN_MV(vthread_t thr, vvp_code_t cp)
vvp_vector4_t value = vthread_bits_to_vector(thr, bit, wid);
schedule_assign_memory_word(cp->mem, adr, value, delay);
schedule_assign_memory_word(cp->mem, adr, off, value, delay);
return true;
}
@ -2789,12 +2779,13 @@ bool of_SET_MV(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);
memory_set_word(cp->mem, adr, value);
memory_set_word(cp->mem, adr, off, value);
return true;
}
@ -3228,6 +3219,9 @@ bool of_JOIN_UFUNC(vthread_t thr, vvp_code_t cp)
/*
* $Log: vthread.cc,v $
* Revision 1.151 2006/02/02 02:44:00 steve
* Allow part selects of memory words in l-values.
*
* Revision 1.150 2005/11/26 17:16:05 steve
* Force instruction that can be indexed.
*