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.
This commit is contained in:
steve 2004-12-29 23:55:43 +00:00
parent 83423c978b
commit 8f2d679c8a
14 changed files with 483 additions and 160 deletions

31
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.66 2004/10/04 01:10:51 steve Exp $"
#ident "$Id: PExpr.h,v 1.67 2004/12/29 23:55:43 steve Exp $"
#endif
# include <string>
@ -83,8 +83,13 @@ class PExpr : public LineInfo {
bool implicit_net_ok =false) const;
// Expressions that can be in the l-value of procedural
// assignments can be elaborated with this method.
virtual NetAssign_* elaborate_lval(Design*des, NetScope*scope) const;
// assignments can be elaborated with this method. If the
// is_force flag is true, then the set of valid l-value types
// is slightly modified to accomodate the Verilog force
// statement
virtual NetAssign_* elaborate_lval(Design*des,
NetScope*scope,
bool is_force) const;
// This attempts to evaluate a constant expression, and return
// a verinum as a result. If the expression cannot be
@ -133,7 +138,9 @@ class PEConcat : public PExpr {
virtual NetExpr*elaborate_expr(Design*des, NetScope*,
bool sys_task_arg =false) const;
virtual NetEConcat*elaborate_pexpr(Design*des, NetScope*) const;
virtual NetAssign_* elaborate_lval(Design*des, NetScope*scope) const;
virtual NetAssign_* elaborate_lval(Design*des,
NetScope*scope,
bool is_force) const;
virtual bool is_constant(Module*) const;
private:
@ -213,7 +220,9 @@ class PEIdent : public PExpr {
bool implicit_net_ok =false) const;
// Identifiers are also allowed as procedural assignment l-values.
virtual NetAssign_* elaborate_lval(Design*des, NetScope*scope) const;
virtual NetAssign_* elaborate_lval(Design*des,
NetScope*scope,
bool is_force) const;
// Structural r-values are OK.
virtual NetNet* elaborate_net(Design*des, NetScope*scope,
@ -288,7 +297,9 @@ class PENumber : public PExpr {
virtual NetEConst*elaborate_expr(Design*des, NetScope*,
bool sys_task_arg =false) const;
virtual NetExpr*elaborate_pexpr(Design*des, NetScope*sc) const;
virtual NetAssign_* elaborate_lval(Design*des, NetScope*scope) const;
virtual NetAssign_* elaborate_lval(Design*des,
NetScope*scope,
bool is_force) const;
virtual verinum* eval_const(const Design*des, const NetScope*sc) const;
@ -492,6 +503,14 @@ class PECallFunction : public PExpr {
/*
* $Log: PExpr.h,v $
* Revision 1.67 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.66 2004/10/04 01:10:51 steve
* Clean up spurious trailing white space.
*

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.150 2004/12/11 02:31:25 steve Exp $"
#ident "$Id: design_dump.cc,v 1.151 2004/12/29 23:55:43 steve Exp $"
#endif
# include "config.h"
@ -213,6 +213,16 @@ void NetCompare::dump_node(ostream&o, unsigned ind) const
dump_obj_attr(o, ind+4);
}
void NetConcat::dump_node(ostream&o, unsigned ind) const
{
o << setw(ind) << "" << "NetConcat: "
<< name()
<< " scope=" << (scope()? scope()->name() : "")
<< " width=" << width_ << endl;
dump_node_pins(o, ind+4);
dump_obj_attr(o, ind+4);
}
void NetDivide::dump_node(ostream&o, unsigned ind) const
{
o << setw(ind) << "" << "NET_DIVIDE (NetDivide): " << name() << endl;
@ -1087,6 +1097,14 @@ void Design::dump(ostream&o) const
/*
* $Log: design_dump.cc,v $
* Revision 1.151 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.150 2004/12/11 02:31:25 steve
* Rework of internals to carry vectors through nexus instead
* of single bits. Make the ivl, tgt-vvp and vvp initial changes

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.30 2004/12/11 02:31:25 steve Exp $"
#ident "$Id: elab_lval.cc,v 1.31 2004/12/29 23:55:43 steve Exp $"
#endif
# include "config.h"
@ -66,7 +66,9 @@
* is to try to make a net elaboration, and see if the result is
* suitable for assignment.
*/
NetAssign_* PExpr::elaborate_lval(Design*des, NetScope*scope) const
NetAssign_* PExpr::elaborate_lval(Design*des,
NetScope*scope,
bool is_force) const
{
NetNet*ll = 0;
if (ll == 0) {
@ -92,7 +94,9 @@ NetAssign_* PExpr::elaborate_lval(Design*des, NetScope*scope) const
* a is the MSB and b the LSB. Connect the LSB to the low pins of the
* NetAssign_ object.
*/
NetAssign_* PEConcat::elaborate_lval(Design*des, NetScope*scope) const
NetAssign_* PEConcat::elaborate_lval(Design*des,
NetScope*scope,
bool is_force) const
{
if (repeat_) {
cerr << get_line() << ": error: Repeat concatenations make "
@ -112,7 +116,7 @@ NetAssign_* PEConcat::elaborate_lval(Design*des, NetScope*scope) const
continue;
}
NetAssign_*tmp = parms_[idx]->elaborate_lval(des, scope);
NetAssign_*tmp = parms_[idx]->elaborate_lval(des, scope, is_force);
/* If the l-value doesn't elaborate, the error was
already detected and printed. We just skip it and let
@ -140,7 +144,9 @@ NetAssign_* PEConcat::elaborate_lval(Design*des, NetScope*scope) const
* Handle the ident as an l-value. This includes bit and part selects
* of that ident.
*/
NetAssign_* PEIdent::elaborate_lval(Design*des, NetScope*scope) const
NetAssign_* PEIdent::elaborate_lval(Design*des,
NetScope*scope,
bool is_force) const
{
NetNet* reg = 0;
NetMemory* mem = 0;
@ -151,6 +157,15 @@ NetAssign_* PEIdent::elaborate_lval(Design*des, NetScope*scope) const
symbol_search(des, scope, path_, reg, mem, var, 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);
}
@ -171,8 +186,9 @@ NetAssign_* PEIdent::elaborate_lval(Design*des, NetScope*scope) const
assert(reg);
/* Get the signal referenced by the identifier, and make sure
it is a register. (Wires are not allows in this context. */
if (reg->type() != NetNet::REG) {
it is a register. Wires are not allows in this context,
unless this is the l-value of a force. */
if ((reg->type() != NetNet::REG) && !is_force) {
cerr << get_line() << ": error: " << path_ <<
" is not a reg/integer/time in " << scope->name() <<
"." << endl;
@ -340,7 +356,7 @@ NetAssign_* PEIdent::elaborate_mem_lval_(Design*des, NetScope*scope,
return lv;
}
NetAssign_* PENumber::elaborate_lval(Design*des, NetScope*) const
NetAssign_* PENumber::elaborate_lval(Design*des, NetScope*, bool) const
{
cerr << get_line() << ": error: Constant values not allowed "
<< "in l-value expressions." << endl;
@ -350,6 +366,14 @@ NetAssign_* PENumber::elaborate_lval(Design*des, NetScope*) const
/*
* $Log: elab_lval.cc,v $
* Revision 1.31 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.30 2004/12/11 02:31:25 steve
* Rework of internals to carry vectors through nexus instead
* of single bits. Make the ivl, tgt-vvp and vvp initial changes
@ -363,95 +387,5 @@ NetAssign_* PENumber::elaborate_lval(Design*des, NetScope*) const
*
* Revision 1.27 2003/09/19 03:30:05 steve
* Fix name search in elab_lval.
*
* Revision 1.26 2003/01/27 05:09:17 steve
* Spelling fixes.
*
* Revision 1.25 2003/01/26 21:15:58 steve
* Rework expression parsing and elaboration to
* accommodate real/realtime values and expressions.
*
* Revision 1.24 2003/01/19 00:35:39 steve
* Detect null arguments to concatenation operator.
*
* Revision 1.23 2002/11/21 23:27:51 steve
* Precalculate indices to l-value arrays.
*
* Revision 1.22 2002/11/21 18:15:40 steve
* Fix const test of msb in assignment l-values.
*
* Revision 1.21 2002/11/02 01:10:49 steve
* Detect memories without work index in l-value.
*
* Revision 1.20 2002/08/12 01:34:58 steve
* conditional ident string using autoconfig.
*
* Revision 1.19 2002/06/04 05:38:44 steve
* Add support for memory words in l-value of
* blocking assignments, and remove the special
* NetAssignMem class.
*
* Revision 1.18 2002/03/09 04:02:26 steve
* Constant expressions are not l-values for task ports.
*
* Revision 1.17 2001/12/03 04:47:14 steve
* Parser and pform use hierarchical names as hname_t
* objects instead of encoded strings.
*
* Revision 1.16 2001/11/08 05:15:50 steve
* Remove string paths from PExpr elaboration.
*
* Revision 1.15 2001/11/07 04:01:59 steve
* eval_const uses scope instead of a string path.
*
* Revision 1.14 2001/08/25 23:50:02 steve
* Change the NetAssign_ class to refer to the signal
* instead of link into the netlist. This is faster
* and uses less space. Make the NetAssignNB carry
* the delays instead of the NetAssign_ lval objects.
*
* Change the vvp code generator to support multiple
* l-values, i.e. concatenations of part selects.
*
* Revision 1.13 2001/07/25 03:10:48 steve
* Create a config.h.in file to hold all the config
* junk, and support gcc 3.0. (Stephan Boettcher)
*
* Revision 1.12 2001/02/09 03:16:48 steve
* Report bit/part select out of range errors. (PR#133)
*
* Revision 1.11 2001/01/10 03:13:23 steve
* Build task outputs as lval instead of nets. (PR#98)
*
* Revision 1.10 2001/01/06 06:31:58 steve
* declaration initialization for time variables.
*
* Revision 1.9 2001/01/06 02:29:36 steve
* Support arrays of integers.
*
* Revision 1.8 2000/12/12 06:14:51 steve
* sorry for concatenated memories in l-values. (PR#76)
*
* Revision 1.7 2000/12/01 02:55:37 steve
* Detect part select errors on l-values.
*
* Revision 1.6 2000/10/31 17:49:02 steve
* Support time variables.
*
* Revision 1.5 2000/10/26 17:09:46 steve
* Fix handling of errors in behavioral lvalues. (PR#28)
*
* Revision 1.4 2000/09/10 15:43:59 steve
* Some error checking.
*
* Revision 1.3 2000/09/10 03:59:59 steve
* Agressively merge NetAssign_ within concatenations.
*
* Revision 1.2 2000/09/10 02:18:16 steve
* elaborate complex l-values
*
* Revision 1.1 2000/09/09 15:21:26 steve
* move lval elaboration to PExpr virtual methods.
*
*/

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.311 2004/12/15 17:09:11 steve Exp $"
#ident "$Id: elaborate.cc,v 1.312 2004/12/29 23:55:43 steve Exp $"
#endif
# include "config.h"
@ -246,6 +246,7 @@ void PGAssign::elaborate(Design*des, NetScope*scope) const
void PGBuiltin::elaborate(Design*des, NetScope*scope) const
{
unsigned count = 1;
unsigned instance_width = 1;
long low = 0, high = 0;
string name = string(get_name());
@ -289,8 +290,33 @@ void PGBuiltin::elaborate(Design*des, NetScope*scope) const
low = lsb.as_long();
high = msb.as_long();
if (debug_elaborate) {
cerr << get_line() << ": debug: PGBuiltin: Make arrray "
<< "[" << high << ":" << low << "]"
<< " of " << count << " gates for " << name << endl;
}
}
/* Now we have a gate count. Elaborate the output expression
only. We do it early so that we can see if we can make a
wide gate instead of an array of gates. */
NetNet*lval_sig = pin(0)->elaborate_lnet(des, scope, true);
assert(lval_sig);
/* Detect the special case that the l-value width exactly
matches the gate count. In this case, we will make a single
gate that has the desired vector width. */
if (lval_sig->vector_width() == (long)count) {
instance_width = count;
count = 1;
if (debug_elaborate)
cerr << get_line() << ": debug: PGBuiltin: "
"Collapsed gate array into single wide "
"(" << instance_width << ") instance." << endl;
}
/* Allocate all the netlist nodes for the gates. */
NetLogic**cur = new NetLogic*[count];
@ -334,75 +360,75 @@ void PGBuiltin::elaborate(Design*des, NetScope*scope) const
switch (type()) {
case AND:
cur[idx] = new NetLogic(scope, inm, pin_count(),
NetLogic::AND, 1);
NetLogic::AND, instance_width);
break;
case BUF:
cur[idx] = new NetLogic(scope, inm, pin_count(),
NetLogic::BUF, 1);
NetLogic::BUF, instance_width);
break;
case BUFIF0:
cur[idx] = new NetLogic(scope, inm, pin_count(),
NetLogic::BUFIF0, 1);
NetLogic::BUFIF0, instance_width);
break;
case BUFIF1:
cur[idx] = new NetLogic(scope, inm, pin_count(),
NetLogic::BUFIF1, 1);
NetLogic::BUFIF1, instance_width);
break;
case NAND:
cur[idx] = new NetLogic(scope, inm, pin_count(),
NetLogic::NAND, 1);
NetLogic::NAND, instance_width);
break;
case NMOS:
cur[idx] = new NetLogic(scope, inm, pin_count(),
NetLogic::NMOS, 1);
NetLogic::NMOS, instance_width);
break;
case NOR:
cur[idx] = new NetLogic(scope, inm, pin_count(),
NetLogic::NOR, 1);
NetLogic::NOR, instance_width);
break;
case NOT:
cur[idx] = new NetLogic(scope, inm, pin_count(),
NetLogic::NOT, 1);
NetLogic::NOT, instance_width);
break;
case NOTIF0:
cur[idx] = new NetLogic(scope, inm, pin_count(),
NetLogic::NOTIF0, 1);
NetLogic::NOTIF0, instance_width);
break;
case NOTIF1:
cur[idx] = new NetLogic(scope, inm, pin_count(),
NetLogic::NOTIF1, 1);
NetLogic::NOTIF1, instance_width);
break;
case OR:
cur[idx] = new NetLogic(scope, inm, pin_count(),
NetLogic::OR, 1);
NetLogic::OR, instance_width);
break;
case RNMOS:
cur[idx] = new NetLogic(scope, inm, pin_count(),
NetLogic::RNMOS, 1);
NetLogic::RNMOS, instance_width);
break;
case RPMOS:
cur[idx] = new NetLogic(scope, inm, pin_count(),
NetLogic::RPMOS, 1);
NetLogic::RPMOS, instance_width);
break;
case PMOS:
cur[idx] = new NetLogic(scope, inm, pin_count(),
NetLogic::PMOS, 1);
NetLogic::PMOS, instance_width);
break;
case PULLDOWN:
cur[idx] = new NetLogic(scope, inm, pin_count(),
NetLogic::PULLDOWN, 1);
NetLogic::PULLDOWN, instance_width);
break;
case PULLUP:
cur[idx] = new NetLogic(scope, inm, pin_count(),
NetLogic::PULLUP, 1);
NetLogic::PULLUP, instance_width);
break;
case XNOR:
cur[idx] = new NetLogic(scope, inm, pin_count(),
NetLogic::XNOR, 1);
NetLogic::XNOR, instance_width);
break;
case XOR:
cur[idx] = new NetLogic(scope, inm, pin_count(),
NetLogic::XOR, 1);
NetLogic::XOR, instance_width);
break;
default:
cerr << get_line() << ": internal error: unhandled "
@ -434,25 +460,67 @@ void PGBuiltin::elaborate(Design*des, NetScope*scope) const
for (unsigned idx = 0 ; idx < pin_count() ; idx += 1) {
const PExpr*ex = pin(idx);
NetNet*sig = (idx == 0)
? ex->elaborate_lnet(des, scope, true)
? lval_sig
: ex->elaborate_net(des, scope, 0, 0, 0, 0);
if (sig == 0)
continue;
assert(sig);
if (sig->pin_count() == 1)
if (count == 1) {
/* Handle the case where there is one gate that
carries the whole vector width. */
connect(cur[0]->pin(idx), sig->pin(0));
} else if (sig->vector_width() == 1) {
/* Handle the case where a single bit is connected
repetitively to all the instances. */
for (unsigned gdx = 0 ; gdx < count ; gdx += 1)
connect(cur[gdx]->pin(idx), sig->pin(0));
else if (sig->pin_count() == count)
for (unsigned gdx = 0 ; gdx < count ; gdx += 1)
connect(cur[gdx]->pin(idx), sig->pin(gdx));
} else if (sig->vector_width() == (long)count) {
else {
/* Handle the general case that each bit of the
value is connected to a different instance. In
this case, the output is handled slightly
different from the inputs. */
if (idx == 0) {
NetConcat*cc = new NetConcat(scope,
scope->local_symbol(),
sig->vector_width(),
count);
des->add_node(cc);
/* Connect the concat to the signal. */
connect(cc->pin(0), sig->pin(0));
/* Connect the outputs of the gates to the concat. */
for (unsigned gdx = 0 ; gdx < count ; gdx += 1) {
connect(cur[gdx]->pin(0), cc->pin(gdx+1));
NetNet*tmp2 = new NetNet(scope,
scope->local_symbol(),
NetNet::WIRE, 1);
connect(cc->pin(gdx+1), tmp2->pin(0));
}
} else for (unsigned gdx = 0 ; gdx < count ; gdx += 1) {
/* Use part selects to get the bits
connected to the inputs of out gate. */
NetPartSelect*tmp1 = new NetPartSelect(sig, gdx, 1);
tmp1->set_line(*this);
des->add_node(tmp1);
connect(tmp1->pin(1), sig->pin(0));
NetNet*tmp2 = new NetNet(scope, scope->local_symbol(),
NetNet::WIRE, 1);
connect(tmp1->pin(0), tmp2->pin(0));
connect(cur[gdx]->pin(idx), tmp1->pin(0));
}
} else {
cerr << get_line() << ": error: Gate count of " <<
count << " does not match net width of " <<
sig->pin_count() << " at pin " << idx << "."
sig->vector_width() << " at pin " << idx << "."
<< endl;
des->errors += 1;
}
@ -1031,7 +1099,7 @@ NetProc* Statement::elaborate(Design*des, NetScope*) const
NetAssign_* PAssign_::elaborate_lval(Design*des, NetScope*scope) const
{
assert(lval_);
return lval_->elaborate_lval(des, scope);
return lval_->elaborate_lval(des, scope, false);
}
/*
@ -1667,7 +1735,7 @@ NetProc* PCallTask::elaborate_usr(Design*des, NetScope*scope) const
detailed message. */
NetAssign_*lv;
if (parms_[idx]) {
lv = parms_[idx]->elaborate_lval(des, scope);
lv = parms_[idx]->elaborate_lval(des, scope, false);
if (lv == 0) {
cerr << parms_[idx]->get_line() << ": error: "
<< "I give up on task port " << (idx+1)
@ -1702,7 +1770,7 @@ NetCAssign* PCAssign::elaborate(Design*des, NetScope*scope) const
NetCAssign*dev = 0;
assert(scope);
NetAssign_*lval = lval_->elaborate_lval(des, scope);
NetAssign_*lval = lval_->elaborate_lval(des, scope, false);
if (lval == 0)
return 0;
@ -1733,7 +1801,7 @@ NetDeassign* PDeassign::elaborate(Design*des, NetScope*scope) const
{
assert(scope);
NetAssign_*lval = lval_->elaborate_lval(des, scope);
NetAssign_*lval = lval_->elaborate_lval(des, scope, false);
if (lval == 0)
return 0;
@ -2216,12 +2284,22 @@ NetProc* PForever::elaborate(Design*des, NetScope*scope) const
return proc;
}
/*
* Force is like a procedural assignment, most notably prodedural
* continuous assignment:
*
* force <lval> = <rval>
*
* The <lval> can be anything that a normal behavioral assignment can
* take, plus net signals. This is a little bit more lax then the
* other proceedural assignments.
*/
NetForce* PForce::elaborate(Design*des, NetScope*scope) const
{
NetForce*dev = 0;
assert(scope);
NetAssign_*lval = lval_->elaborate_lval(des, scope);
NetAssign_*lval = lval_->elaborate_lval(des, scope, true);
if (lval == 0)
return 0;
@ -2396,7 +2474,7 @@ NetProc* PRelease::elaborate(Design*des, NetScope*scope) const
{
assert(scope);
NetAssign_*lval = lval_->elaborate_lval(des, scope);
NetAssign_*lval = lval_->elaborate_lval(des, scope, true);
if (lval == 0)
return 0;
@ -2767,6 +2845,14 @@ Design* elaborate(list<perm_string>roots)
/*
* $Log: elaborate.cc,v $
* Revision 1.312 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.311 2004/12/15 17:09:11 steve
* Force r-value padded to width.
*

15
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.78 2004/12/11 02:31:26 steve Exp $"
#ident "$Id: emit.cc,v 1.79 2004/12/29 23:55:43 steve Exp $"
#endif
# include "config.h"
@ -75,6 +75,11 @@ bool NetCompare::emit_node(struct target_t*tgt) const
return true;
}
bool NetConcat::emit_node(struct target_t*tgt) const
{
return tgt->concat(this);
}
bool NetConst::emit_node(struct target_t*tgt) const
{
return tgt->net_const(this);
@ -504,6 +509,14 @@ bool emit(const Design*des, const char*type)
/*
* $Log: emit.cc,v $
* Revision 1.79 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.78 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

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.129 2004/12/18 18:56:18 steve Exp $"
#ident "$Id: ivl_target.h,v 1.130 2004/12/29 23:55:43 steve Exp $"
#endif
#ifdef __cplusplus
@ -222,6 +222,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_CONCAT = 16,
IVL_LPM_CMP_EQ = 10,
IVL_LPM_CMP_GE = 1,
IVL_LPM_CMP_GT = 2,
@ -627,6 +628,12 @@ extern ivl_memory_t ivl_expr_memory(ivl_expr_t net);
* These support iterating over logic attributes. The _cnt method
* returns the number of attributes attached to the gate, and the
* ivl_logic_attr_val returns the value of the attribute.
*
* SEMANTIC NOTES
* The ivl_logic_width and ivl_logic_pins are *not* related. A logic
* device has a number of pins that is the number of inputs to a logic
* array of identical gates, and the ivl_logic_width, is the width of
* the vector into each input pin and out of the output pin.
*/
extern const char* ivl_logic_name(ivl_net_logic_t net);
@ -637,6 +644,7 @@ extern ivl_nexus_t ivl_logic_pin(ivl_net_logic_t net, unsigned pin);
extern unsigned ivl_logic_pins(ivl_net_logic_t net);
extern ivl_udp_t ivl_logic_udp(ivl_net_logic_t net);
extern unsigned ivl_logic_delay(ivl_net_logic_t net, unsigned transition);
extern unsigned ivl_logic_width(ivl_net_logic_t net);
/* DEPRECATED */
extern const char* ivl_logic_attr(ivl_net_logic_t net, const char*key);
@ -659,7 +667,8 @@ extern const char* ivl_udp_name(ivl_udp_t net);
/* LPM
* These functions support access to the properties of LPM
* devices. LPM devices are a variety of devices that handle more
* complex structural semantics.
* complex structural semantics. They are based on EIA LPM standard
* devices, but vary to suite the technical situation.
*
* These are the functions that apply to all LPM devices:
*
@ -689,13 +698,12 @@ extern const char* ivl_udp_name(ivl_udp_t net);
* of the part select. The ivl_lpm_width is the size of the part.
*
* ivl_lpm_data
* Return the input data nexus for device types that have a single
* input vector. This is also used to the get nexa of the first
* vector for devices that have more inputs.
* Return the input data nexus for device types that have input
* vectors. The "idx" parameter selects which data input is selected.
*
* ivl_lpm_datab
* Return the input data nexus for device types that have a second
* input vector. For example, arithmetic devices are like this.
* ivl_lpm_datab (ANACHRONISM)
* This is the same as ivl_lpm_data(net,1), in other words the
* second data input. Use the ivl_lpm_data method instead.
*
* ivl_lpm_q
* Return the output data nexus for device types that have a single
@ -713,6 +721,18 @@ extern const char* ivl_udp_name(ivl_udp_t net);
* In addition to a width, some devices have a size. The size is
* often the number of inputs per out, i.e., the number of inputs
* per bit for a MUX.
*
* SEMANTIC NOTES
*
* - Concatenation (IVL_LPM_CONCAT)
* These devices take vectors in and combine them to form a single
* output the width specified by ivl_lpm_width.
*
* The ivl_lpm_q nexus is the output from the concatenation.
*
* The ivl_lpm_data function returns the connections for the inputs to
* the concatentation. The ivl_lpm_size function returns the number of
* inputs help by the device.
*/
extern const char* ivl_lpm_name(ivl_lpm_t net); /* (Obsolete) */
@ -737,8 +757,8 @@ extern ivl_nexus_t ivl_lpm_clk(ivl_lpm_t net);
extern ivl_scope_t ivl_lpm_define(ivl_lpm_t net);
/* IVL_LPM_FF IVL_LPM_RAM */
extern ivl_nexus_t ivl_lpm_enable(ivl_lpm_t net);
/* IVL_LPM_ADD IVL_LPM_FF IVL_LPM_PART IVL_LPM_MULT IVL_LPM_RAM
IVL_LPM_SUB */
/* IVL_LPM_ADD IVL_LPM_CONCAT IVL_LPM_FF IVL_LPM_PART IVL_LPM_MULT
IVL_LPM_RAM IVL_LPM_SUB */
extern ivl_nexus_t ivl_lpm_data(ivl_lpm_t net, unsigned idx);
/* IVL_LPM_ADD IVL_LPM_MULT IVL_LPM_SUB */
/* IVL_LPM_MUX IVL_LPM_UFUNC */
@ -753,7 +773,7 @@ extern ivl_nexus_t ivl_lpm_q(ivl_lpm_t net, unsigned idx);
extern unsigned ivl_lpm_selects(ivl_lpm_t net);
/* IVL_LPM_MUX IVL_LPM_RAM */
extern ivl_nexus_t ivl_lpm_select(ivl_lpm_t net, unsigned idx);
/* IVL_LPM_MUX */
/* IVL_LPM_CONCAT IVL_LPM_MUX */
extern unsigned ivl_lpm_size(ivl_lpm_t net);
/* IVL_LPM_RAM */
extern ivl_memory_t ivl_lpm_memory(ivl_lpm_t net);
@ -1260,7 +1280,9 @@ extern ivl_statement_type_t ivl_statement_type(ivl_statement_t net);
*
* - IVL_ST_FORCE
* This is very much like IVL_ST_CASSIGN, but adds that l-values can
* include nets (tri, wire, etc).
* include nets (tri, wire, etc). Memory words are restricted from
* force l-values, and also non-constant bit or part selects. The
* compiler will assure these constraints are met.
*
* - IVL_ST_TRIGGER
* This represents the "-> name" statement that sends a trigger to a
@ -1371,6 +1393,14 @@ _END_DECL
/*
* $Log: ivl_target.h,v $
* 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.
*

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.227 2004/12/11 02:31:26 steve Exp $"
#ident "$Id: netlist.cc,v 1.228 2004/12/29 23:55:43 steve Exp $"
#endif
# include "config.h"
@ -532,6 +532,26 @@ const NetScope* NetProcTop::scope() const
return scope_;
}
NetConcat::NetConcat(NetScope*scope, perm_string n, unsigned wid, unsigned cnt)
: NetNode(scope, n, cnt+1), width_(wid)
{
pin(0).set_dir(Link::OUTPUT);
pin(0).set_name(perm_string::literal("O"), 0);
for (unsigned idx = 1 ; idx < cnt+1 ; idx += 1) {
pin(idx).set_dir(Link::INPUT);
pin(idx).set_name(perm_string::literal("I"), idx-1);
}
}
NetConcat::~NetConcat()
{
}
unsigned NetConcat::width() const
{
return width_;
}
/*
* The NetFF class represents an LPM_FF device. The pinout is assigned
* like so:
@ -2306,6 +2326,14 @@ const NetProc*NetTaskDef::proc() const
/*
* $Log: netlist.cc,v $
* Revision 1.228 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.227 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

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.322 2004/12/11 02:31:27 steve Exp $"
#ident "$Id: netlist.h,v 1.323 2004/12/29 23:55:43 steve Exp $"
#endif
/*
@ -582,6 +582,32 @@ class NetCompare : public NetNode {
bool signed_flag_;
};
/*
* This node is a means to connect net inputs together to form a wider
* vector. The output (pin 0) is a concatenation of the input vectors,
* with pin-1 at the LSB, pin-2 next, and so on. This node is most
* like the NetLogic node, as it has one output at pin 0 and the
* remaining pins are the input that are combined to make the
* output. It is seperated out because it it generally a special case
* for the code generators.
*/
class NetConcat : public NetNode {
public:
NetConcat(NetScope*scope, perm_string n, unsigned wid, unsigned cnt);
~NetConcat();
unsigned width() const;
void dump_node(ostream&, unsigned ind) const;
bool emit_node(struct target_t*) const;
private:
unsigned width_;
};
/*
* This class represents a theoretical (though not necessarily
* practical) integer divider gate. This is not to represent any real
@ -1242,6 +1268,11 @@ class NetConst : public NetNode {
* The pullup and pulldown gates have no inputs at all, and pin0 is
* the output 1 or 0, depending on the gate type. It is the strength
* of that value that is important.
*
* All these devices process vectors bitwise, so each bit can be
* logically seperated. The exception is the CONCAT gate, which is
* really an abstract gate that takes the inputs and turns it into a
* vector of bits.
*/
class NetLogic : public NetNode {
@ -3349,6 +3380,14 @@ extern ostream& operator << (ostream&, NetNet::Type);
/*
* $Log: netlist.h,v $
* Revision 1.323 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.322 2004/12/11 02:31:27 steve
* Rework of internals to carry vectors through nexus instead
* of single bits. Make the ivl, tgt-vvp and vvp initial changes

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.111 2004/12/18 18:56:18 steve Exp $"
#ident "$Id: t-dll-api.cc,v 1.112 2004/12/29 23:55:43 steve Exp $"
#endif
# include "config.h"
@ -766,8 +766,11 @@ extern "C" ivl_nexus_t ivl_lpm_data(ivl_lpm_t net, unsigned idx)
case IVL_LPM_MOD:
case IVL_LPM_MULT:
case IVL_LPM_SUB:
assert(idx == 0);
return net->u_.arith.a;
assert(idx <= 1);
if (idx == 0)
return net->u_.arith.a;
else
return net->u_.arith.b;
case IVL_LPM_SHIFTL:
case IVL_LPM_SHIFTR:
@ -782,6 +785,10 @@ extern "C" ivl_nexus_t ivl_lpm_data(ivl_lpm_t net, unsigned idx)
else
return net->u_.ff.d.pins[idx];
case IVL_LPM_CONCAT:
assert(idx < net->u_.concat.inputs);
return net->u_.concat.pins[idx+1];
case IVL_LPM_PART:
assert(idx == 0);
return net->u_.part.a;
@ -794,6 +801,7 @@ extern "C" ivl_nexus_t ivl_lpm_data(ivl_lpm_t net, unsigned idx)
extern "C" ivl_nexus_t ivl_lpm_datab(ivl_lpm_t net, unsigned idx)
{
cerr << "ANACHRONISM: Call to anachronistic ivl_lpm_datab." << endl;
assert(net);
switch (net->type) {
@ -928,6 +936,9 @@ extern "C" ivl_nexus_t ivl_lpm_q(ivl_lpm_t net, unsigned idx)
assert(idx < net->u_.ufunc.port_wid[0]);
return net->u_.ufunc.pins[idx];
case IVL_LPM_CONCAT:
return net->u_.concat.pins[0];
case IVL_LPM_PART:
assert(idx == 0);
return net->u_.part.q;
@ -982,6 +993,8 @@ extern "C" unsigned ivl_lpm_selects(ivl_lpm_t net)
case IVL_LPM_SHIFTL:
case IVL_LPM_SHIFTR:
return net->u_.shift.select;
case IVL_LPM_CONCAT:
return net->u_.concat.inputs;
default:
assert(0);
return 0;
@ -1012,6 +1025,8 @@ extern "C" int ivl_lpm_signed(ivl_lpm_t net)
return 0;
case IVL_LPM_UFUNC:
return 0;
case IVL_LPM_CONCAT: // Concatenations are always unsigned
return 0;
case IVL_LPM_PART:
return net->u_.part.signed_flag;
default:
@ -1062,6 +1077,8 @@ extern "C" unsigned ivl_lpm_width(ivl_lpm_t net)
return net->u_.shift.width;
case IVL_LPM_UFUNC:
return net->u_.ufunc.port_wid[0];
case IVL_LPM_CONCAT:
return net->u_.concat.width;
case IVL_LPM_PART:
return net->u_.part.width;
default:
@ -1946,6 +1963,14 @@ extern "C" ivl_variable_type_t ivl_variable_type(ivl_variable_t net)
/*
* $Log: t-dll-api.cc,v $
* Revision 1.112 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.111 2004/12/18 18:56:18 steve
* Add ivl_event_scope, and better document ivl_event_X methods.
*

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.132 2004/12/11 02:31:28 steve Exp $"
#ident "$Id: t-dll.cc,v 1.133 2004/12/29 23:55:43 steve Exp $"
#endif
# include "config.h"
@ -1867,6 +1867,34 @@ void dll_target::lpm_mux(const NetMux*net)
}
bool dll_target::concat(const NetConcat*net)
{
ivl_lpm_t obj = new struct ivl_lpm_s;
obj->type = IVL_LPM_CONCAT;
obj->name = net->name(); // NetConcat names are permallocated
assert(net->scope());
obj->scope = find_scope(des_, net->scope());
assert(obj->scope);
obj->u_.concat.width = net->width();
obj->u_.concat.inputs = net->pin_count() - 1;
obj->u_.concat.pins = new ivl_nexus_t[obj->u_.concat.inputs+1];
for (unsigned idx = 0 ; idx < obj->u_.concat.inputs+1 ; idx += 1) {
ivl_drive_t dr = idx == 0? IVL_DR_STRONG : IVL_DR_HiZ;
const Nexus*nex = net->pin(idx).nexus();
assert(nex->t_cookie());
obj->u_.concat.pins[idx] = (ivl_nexus_t) nex->t_cookie();
nexus_lpm_add(obj->u_.concat.pins[idx], obj, 0, dr, dr);
}
scope_add_lpm(obj->scope, obj);
return true;
}
bool dll_target::part_select(const NetPartSelect*net)
{
ivl_lpm_t obj = new struct ivl_lpm_s;
@ -2179,6 +2207,14 @@ extern const struct target tgt_dll = { "dll", &dll_target_obj };
/*
* $Log: t-dll.cc,v $
* Revision 1.133 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.132 2004/12/11 02:31:28 steve
* Rework of internals to carry vectors through nexus instead
* of single bits. Make the ivl, tgt-vvp and vvp initial changes

17
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.116 2004/12/11 02:31:28 steve Exp $"
#ident "$Id: t-dll.h,v 1.117 2004/12/29 23:55:43 steve Exp $"
#endif
# include "target.h"
@ -82,6 +82,7 @@ struct dll_target : public target_t, public expr_scan_t {
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*);
void net_assign(const NetAssign_*);
bool net_function(const NetUserFunc*);
@ -347,6 +348,12 @@ struct ivl_lpm_s {
ivl_nexus_t q, a, b;
} arith;
struct ivl_concat_s {
unsigned width;
unsigned inputs;
ivl_nexus_t*pins;
} concat;
struct ivl_part_s {
unsigned width;
unsigned base;
@ -680,6 +687,14 @@ struct ivl_variable_s {
/*
* $Log: t-dll.h,v $
* Revision 1.117 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.116 2004/12/11 02:31:28 steve
* Rework of internals to carry vectors through nexus instead
* of single bits. Make the ivl, tgt-vvp and vvp initial changes

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.70 2004/12/11 02:31:28 steve Exp $"
#ident "$Id: target.cc,v 1.71 2004/12/29 23:55:43 steve Exp $"
#endif
# include "config.h"
@ -137,6 +137,13 @@ void target_t::lpm_ram_dq(const NetRamDq*)
"Unhandled NetRamDq." << endl;
}
bool target_t::concat(const NetConcat*)
{
cerr << "target (" << typeid(*this).name() << "): "
"Unhandled NetConcat." << endl;
return false;
}
bool target_t::part_select(const NetPartSelect*)
{
cerr << "target (" << typeid(*this).name() << "): "
@ -412,6 +419,14 @@ void expr_scan_t::expr_binary(const NetEBinary*ex)
/*
* $Log: target.cc,v $
* Revision 1.71 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.70 2004/12/11 02:31:28 steve
* Rework of internals to carry vectors through nexus instead
* of single bits. Make the ivl, tgt-vvp and vvp initial changes

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.66 2004/12/11 02:31:28 steve Exp $"
#ident "$Id: target.h,v 1.67 2004/12/29 23:55:43 steve Exp $"
#endif
# include "netlist.h"
@ -86,6 +86,7 @@ struct target_t {
virtual void lpm_mux(const NetMux*);
virtual void lpm_ram_dq(const NetRamDq*);
virtual bool concat(const NetConcat*);
virtual bool part_select(const NetPartSelect*);
/* Output a gate (called for each gate) */
@ -170,6 +171,14 @@ extern const struct target *target_table[];
/*
* $Log: target.h,v $
* Revision 1.67 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.66 2004/12/11 02:31:28 steve
* Rework of internals to carry vectors through nexus instead
* of single bits. Make the ivl, tgt-vvp and vvp initial changes

View File

@ -17,7 +17,7 @@
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#ifdef HAVE_CVS_IDENT
#ident "$Id: stub.c,v 1.93 2004/12/18 18:55:08 steve Exp $"
#ident "$Id: stub.c,v 1.94 2004/12/29 23:55:43 steve Exp $"
#endif
# include "config.h"
@ -179,6 +179,50 @@ void show_expression(ivl_expr_t net, unsigned ind)
}
}
/* IVL_LPM_CONCAT
* The concat device takes N inputs (N=ivl_lpm_selects) and generates
* a single output. The total output is known from the ivl_lpm_width
* function. The widths of all the inputs are inferred from the widths
* of the signals connected to the nexus of the inputs. The compiler
* makes sure the input widths add up to the output width.
*/
static void show_lpm_concat(ivl_lpm_t net)
{
unsigned idx;
unsigned width_sum = 0;
unsigned width = ivl_lpm_width(net);
fprintf(out, " LPM_CONCAT %s: <width=%u, inputs=%u>\n",
ivl_lpm_basename(net), width, ivl_lpm_selects(net));
fprintf(out, " O: %s\n", ivl_nexus_name(ivl_lpm_q(net,0)));
for (idx = 0 ; idx < ivl_lpm_selects(net) ; idx += 1) {
unsigned ndx;
unsigned signal_width = 0;
ivl_nexus_t nex = ivl_lpm_data(net, idx);
for (ndx = 0 ; ndx < ivl_nexus_ptrs(nex) ; ndx += 1) {
ivl_nexus_ptr_t ptr = ivl_nexus_ptr(nex, ndx);
ivl_signal_t sig = ivl_nexus_ptr_sig(ptr);
if (sig != 0) {
signal_width = ivl_signal_width(sig);
break;
}
}
fprintf(out, " I%u: %s (width=%u)\n", idx,
ivl_nexus_name(nex), signal_width);
width_sum += signal_width;
}
if (width_sum != width) {
fprintf(out, " ERROR! Got %u bits input, expecting %u!\n",
width_sum, width);
}
}
static void show_lpm(ivl_lpm_t net)
{
unsigned idx;
@ -235,6 +279,10 @@ static void show_lpm(ivl_lpm_t net)
break;
}
case IVL_LPM_CONCAT:
show_lpm_concat(net);
break;
case IVL_LPM_SHIFTL: {
fprintf(out, " LPM_SHIFTL %s: <width=%u, selects=%u %s>\n",
ivl_lpm_basename(net), width, ivl_lpm_selects(net),
@ -762,6 +810,14 @@ int target_design(ivl_design_t des)
/*
* $Log: stub.c,v $
* Revision 1.94 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.93 2004/12/18 18:55:08 steve
* Better detail on event trigger and wait statements.
*