mirror of
https://github.com/steveicarus/iverilog.git
synced 2026-08-24 06:46:52 +02:00
Compare commits
59
Commits
s19991103
...
version0_1
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
e67952240b | ||
|
|
22d89c5984 | ||
|
|
88193a369f | ||
|
|
cdb99e7638 | ||
|
|
99e145da48 | ||
|
|
b30b695ff0 | ||
|
|
998c039fd9 | ||
|
|
5ffac8adbf | ||
|
|
80b8ea95bb | ||
|
|
68a7ce3745 | ||
|
|
bb68753bd2 | ||
|
|
dab47610ed | ||
|
|
e96e8c62be | ||
|
|
fa088f8baa | ||
|
|
48b6726cf4 | ||
|
|
bf42be12de | ||
|
|
4cfa3e4047 | ||
|
|
ac25dc03a8 | ||
|
|
680c35a845 | ||
|
|
26288eeeb4 | ||
|
|
3a69ab8934 | ||
|
|
cd3ed1959e | ||
|
|
eb72a83e5f | ||
|
|
85ab6d160b | ||
|
|
b769c7781e | ||
|
|
7324673bd1 | ||
|
|
4cfa715092 | ||
|
|
b4aade1e4c | ||
|
|
a81dcd7955 | ||
|
|
fae40cf380 | ||
|
|
28149e73e3 | ||
|
|
8b81d6e416 | ||
|
|
fbf0bf1fb7 | ||
|
|
9d6392fda9 | ||
|
|
23ce3a9042 | ||
|
|
33946e188c | ||
|
|
477495c648 | ||
|
|
16f7268729 | ||
|
|
a4a0ba670d | ||
|
|
e98083af15 | ||
|
|
513ade9b95 | ||
|
|
1624afe1ba | ||
|
|
0eb6056ea6 | ||
|
|
2602505885 | ||
|
|
82f3f0f741 | ||
|
|
02f8099aa7 | ||
|
|
43ff33cd79 | ||
|
|
2d1ace1dbc | ||
|
|
8d806d538b | ||
|
|
3fe0344246 | ||
|
|
c688d95cb8 | ||
|
|
282c58040b | ||
|
|
c18ea61994 | ||
|
|
5171846d72 | ||
|
|
206b37e5de | ||
|
|
f7526c6c4b | ||
|
|
f827ad8625 | ||
|
|
93a1f4853b | ||
|
|
2cce0ce238 |
+8
-8
@@ -18,7 +18,7 @@
|
||||
# 59 Temple Place - Suite 330
|
||||
# Boston, MA 02111-1307, USA
|
||||
#
|
||||
#ident "$Id: Makefile.in,v 1.27 1999/11/02 04:55:34 steve Exp $"
|
||||
#ident "$Id: Makefile.in,v 1.24.2.1 1999/12/03 17:43:49 steve Exp $"
|
||||
#
|
||||
#
|
||||
SHELL = /bin/sh
|
||||
@@ -66,10 +66,10 @@ distclean: clean
|
||||
rm -f Makefile
|
||||
|
||||
TT = t-null.o t-verilog.o t-vvm.o t-xnf.o
|
||||
FF = nobufz.o propinit.o sigfold.o synth.o xnfio.o xnfsyn.o
|
||||
FF = nobufz.o propinit.o sigfold.o xnfio.o xnfsyn.o
|
||||
|
||||
O = main.o cprop.o design_dump.o elaborate.o elab_expr.o elab_net.o \
|
||||
emit.o eval.o eval_tree.o expr_synth.o functor.o \
|
||||
O = main.o cprop.o design_dump.o elaborate.o elab_expr.o emit.o eval.o \
|
||||
eval_tree.o functor.o \
|
||||
lexor.o lexor_keyword.o mangle.o netlist.o pad_to_width.o \
|
||||
parse.o parse_misc.o pform.o pform_dump.o \
|
||||
set_width.o \
|
||||
@@ -113,7 +113,7 @@ parse.h parse.cc: $(srcdir)/parse.y
|
||||
lexor.cc: $(srcdir)/lexor.lex
|
||||
flex -PVL -s -olexor.cc $(srcdir)/lexor.lex
|
||||
|
||||
install: all installdirs $(bindir)/verilog $(bindir)/ivl $(mandir)/man1/verilog.1
|
||||
install: all installdirs $(bindir)/verilog $(libdir)/ivl/ivl $(mandir)/man1/verilog.1
|
||||
cd vpi ; $(MAKE) install
|
||||
cd vvm ; $(MAKE) install
|
||||
cd ivlpp ; $(MAKE) install
|
||||
@@ -121,9 +121,9 @@ install: all installdirs $(bindir)/verilog $(bindir)/ivl $(mandir)/man1/verilog.
|
||||
$(bindir)/verilog: ./verilog
|
||||
$(INSTALL_PROGRAM) ./verilog $(bindir)/verilog
|
||||
|
||||
$(bindir)/ivl: ivl
|
||||
$(INSTALL_PROGRAM) ./ivl $(bindir)/ivl
|
||||
$(STRIP) $(bindir)/ivl
|
||||
$(libdir)/ivl/ivl: ivl
|
||||
$(INSTALL_PROGRAM) ./ivl $(libdir)/ivl/ivl
|
||||
$(STRIP) $(libdir)/ivl/ivl
|
||||
|
||||
$(mandir)/man1/verilog.1: $(srcdir)/verilog.1
|
||||
$(INSTALL_DATA) $(srcdir)/verilog.1 $(mandir)/man1/verilog.1
|
||||
|
||||
@@ -19,7 +19,7 @@
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
|
||||
*/
|
||||
#if !defined(WINNT)
|
||||
#ident "$Id: Module.h,v 1.9 1999/08/23 16:48:39 steve Exp $"
|
||||
#ident "$Id: Module.h,v 1.10 1999/11/27 19:07:57 steve Exp $"
|
||||
#endif
|
||||
|
||||
# include <list>
|
||||
@@ -33,6 +33,7 @@ class PFunction;
|
||||
class PWire;
|
||||
class PProcess;
|
||||
class Design;
|
||||
class NetScope;
|
||||
|
||||
/*
|
||||
* A module is a named container and scope. A module holds a bunch of
|
||||
@@ -93,7 +94,7 @@ class Module {
|
||||
const list<PProcess*>& get_behaviors() const { return behaviors_; }
|
||||
|
||||
void dump(ostream&out) const;
|
||||
bool elaborate(Design*, const string&path, svector<PExpr*>*overrides_) const;
|
||||
bool elaborate(Design*, NetScope*scope, svector<PExpr*>*overrides_) const;
|
||||
|
||||
private:
|
||||
const string name_;
|
||||
@@ -113,6 +114,9 @@ class Module {
|
||||
|
||||
/*
|
||||
* $Log: Module.h,v $
|
||||
* Revision 1.10 1999/11/27 19:07:57 steve
|
||||
* Support the creation of scopes.
|
||||
*
|
||||
* Revision 1.9 1999/08/23 16:48:39 steve
|
||||
* Parameter overrides support from Peter Monta
|
||||
* AND and XOR support wide expressions.
|
||||
|
||||
@@ -19,7 +19,7 @@
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
|
||||
*/
|
||||
#if !defined(WINNT)
|
||||
#ident "$Id: PExpr.h,v 1.22 1999/10/31 20:08:24 steve Exp $"
|
||||
#ident "$Id: PExpr.h,v 1.25 1999/11/21 00:13:08 steve Exp $"
|
||||
#endif
|
||||
|
||||
# include <string>
|
||||
@@ -159,6 +159,12 @@ class PEIdent : public PExpr {
|
||||
// If this is a reference to a memory, this is the index
|
||||
// expression.
|
||||
PExpr*idx_;
|
||||
|
||||
NetNet* elaborate_net_ram_(Design*des, const string&path,
|
||||
NetMemory*mem, unsigned lwidth,
|
||||
unsigned long rise,
|
||||
unsigned long fall,
|
||||
unsigned long decay) const;
|
||||
};
|
||||
|
||||
class PENumber : public PExpr {
|
||||
@@ -248,6 +254,16 @@ class PEBinary : public PExpr {
|
||||
unsigned long rise,
|
||||
unsigned long fall,
|
||||
unsigned long decay) const;
|
||||
NetNet* elaborate_net_cmp_(Design*des, const string&path,
|
||||
unsigned lwidth,
|
||||
unsigned long rise,
|
||||
unsigned long fall,
|
||||
unsigned long decay) const;
|
||||
NetNet* elaborate_net_shift_(Design*des, const string&path,
|
||||
unsigned lwidth,
|
||||
unsigned long rise,
|
||||
unsigned long fall,
|
||||
unsigned long decay) const;
|
||||
};
|
||||
|
||||
/*
|
||||
@@ -297,6 +313,16 @@ class PECallFunction : public PExpr {
|
||||
|
||||
/*
|
||||
* $Log: PExpr.h,v $
|
||||
* Revision 1.25 1999/11/21 00:13:08 steve
|
||||
* Support memories in continuous assignments.
|
||||
*
|
||||
* Revision 1.24 1999/11/14 20:24:28 steve
|
||||
* Add support for the LPM_CLSHIFT device.
|
||||
*
|
||||
* Revision 1.23 1999/11/05 21:45:19 steve
|
||||
* Fix NetConst being set to zero width, and clean
|
||||
* up elaborate_set_cmp_ for NetEBinary.
|
||||
*
|
||||
* Revision 1.22 1999/10/31 20:08:24 steve
|
||||
* Include subtraction in LPM_ADD_SUB device.
|
||||
*
|
||||
|
||||
@@ -19,7 +19,7 @@
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
|
||||
*/
|
||||
#if !defined(WINNT)
|
||||
#ident "$Id: PWire.h,v 1.5 1999/06/17 05:34:42 steve Exp $"
|
||||
#ident "$Id: PWire.h,v 1.6 1999/11/27 19:07:57 steve Exp $"
|
||||
#endif
|
||||
|
||||
# include "netlist.h"
|
||||
@@ -58,7 +58,7 @@ class PWire : public LineInfo {
|
||||
// Write myself to the specified stream.
|
||||
void dump(ostream&out) const;
|
||||
|
||||
void elaborate(Design*, const string&path) const;
|
||||
void elaborate(Design*, NetScope*scope) const;
|
||||
|
||||
private:
|
||||
string name_;
|
||||
@@ -82,6 +82,9 @@ class PWire : public LineInfo {
|
||||
|
||||
/*
|
||||
* $Log: PWire.h,v $
|
||||
* Revision 1.6 1999/11/27 19:07:57 steve
|
||||
* Support the creation of scopes.
|
||||
*
|
||||
* Revision 1.5 1999/06/17 05:34:42 steve
|
||||
* Clean up interface of the PWire class,
|
||||
* Properly match wire ranges.
|
||||
|
||||
@@ -327,6 +327,8 @@ current state of support for Verilog.
|
||||
reg [7:0] del;
|
||||
always #(reg) $display($time,,"del = %d", del); // sorry
|
||||
|
||||
- drive strengths are parsed, bug ignored.
|
||||
|
||||
Specify blocks are parsed but ignored in general.
|
||||
|
||||
|
||||
|
||||
@@ -5,6 +5,7 @@ dnl Checks for programs.
|
||||
AC_PROG_CC
|
||||
AC_PROG_CXX
|
||||
AC_CHECK_TOOL(STRIP, strip, true)
|
||||
AC_CHECK_HEADERS(getopt.h)
|
||||
AC_PROG_INSTALL
|
||||
|
||||
AC_OUTPUT(Makefile vpi/Makefile ivlpp/Makefile vvm/Makefile)
|
||||
|
||||
+76
-9
@@ -17,7 +17,7 @@
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
|
||||
*/
|
||||
#if !defined(WINNT)
|
||||
#ident "$Id: design_dump.cc,v 1.55 1999/11/04 03:53:26 steve Exp $"
|
||||
#ident "$Id: design_dump.cc,v 1.61 1999/11/28 23:42:02 steve Exp $"
|
||||
#endif
|
||||
|
||||
/*
|
||||
@@ -49,6 +49,8 @@ void NetNet::dump_net(ostream&o, unsigned ind) const
|
||||
pin_count() << "]";
|
||||
if (local_flag_)
|
||||
o << " (local)";
|
||||
if (scope_)
|
||||
o << " scope=" << scope_->name();
|
||||
o << " #(" << rise_time() << "," << fall_time() << "," <<
|
||||
decay_time() << ") init=";
|
||||
for (unsigned idx = pin_count() ; idx > 0 ; idx -= 1)
|
||||
@@ -130,6 +132,22 @@ void NetAddSub::dump_node(ostream&o, unsigned ind) const
|
||||
dump_obj_attr(o, ind+4);
|
||||
}
|
||||
|
||||
void NetCLShift::dump_node(ostream&o, unsigned ind) const
|
||||
{
|
||||
o << setw(ind) << "" << "Combinatorial shift (NetCLShift): " <<
|
||||
name() << endl;
|
||||
dump_node_pins(o, ind+4);
|
||||
dump_obj_attr(o, ind+4);
|
||||
}
|
||||
|
||||
void NetCompare::dump_node(ostream&o, unsigned ind) const
|
||||
{
|
||||
o << setw(ind) << "" << "LPM_COMPARE (NetCompare): " <<
|
||||
name() << endl;
|
||||
dump_node_pins(o, ind+4);
|
||||
dump_obj_attr(o, ind+4);
|
||||
}
|
||||
|
||||
void NetMux::dump_node(ostream&o, unsigned ind) const
|
||||
{
|
||||
o << setw(ind) << "" << "Multiplexer (NetMux): " << name() << endl;
|
||||
@@ -225,6 +243,14 @@ void NetLogic::dump_node(ostream&o, unsigned ind) const
|
||||
dump_obj_attr(o, ind+4);
|
||||
}
|
||||
|
||||
void NetRamDq::dump_node(ostream&o, unsigned ind) const
|
||||
{
|
||||
o << setw(ind) << "" << "LPM_RAM_DQ (" << mem_->name() << "): "
|
||||
<< name() << endl;
|
||||
dump_node_pins(o, ind+4);
|
||||
dump_obj_attr(o, ind+4);
|
||||
}
|
||||
|
||||
void NetTaskDef::dump(ostream&o, unsigned ind) const
|
||||
{
|
||||
o << setw(ind) << "" << "task " << name_ << ";" << endl;
|
||||
@@ -555,6 +581,23 @@ void NetRepeat::dump(ostream&o, unsigned ind) const
|
||||
statement_->dump(o, ind+2);
|
||||
}
|
||||
|
||||
void NetScope::dump(ostream&o) const
|
||||
{
|
||||
o << name_;
|
||||
switch (type_) {
|
||||
case BEGIN_END:
|
||||
o << " sequential block";
|
||||
break;
|
||||
case FORK_JOIN:
|
||||
o << " parallel block";
|
||||
break;
|
||||
case MODULE:
|
||||
o << " module";
|
||||
break;
|
||||
}
|
||||
o << endl;
|
||||
}
|
||||
|
||||
void NetSTask::dump(ostream&o, unsigned ind) const
|
||||
{
|
||||
o << setw(ind) << "" << name_;
|
||||
@@ -681,6 +724,11 @@ void NetEIdent::dump(ostream&o) const
|
||||
o << name_;
|
||||
}
|
||||
|
||||
void NetEScope::dump(ostream&o) const
|
||||
{
|
||||
o << "<scope=" << scope_->name() << ">";
|
||||
}
|
||||
|
||||
void NetESignal::dump(ostream&o) const
|
||||
{
|
||||
o << name();
|
||||
@@ -706,14 +754,6 @@ void NetEParam::dump(ostream&o) const
|
||||
o << "<" << path_ << "." << name_ << ">";
|
||||
}
|
||||
|
||||
void NetESignal::dump_node(ostream&o, unsigned ind) const
|
||||
{
|
||||
o << setw(ind) << "" << "Expression Node (NetESignal): " <<
|
||||
name() << endl;
|
||||
|
||||
dump_node_pins(o, ind+4);
|
||||
}
|
||||
|
||||
void NetETernary::dump(ostream&o) const
|
||||
{
|
||||
o << "(" << *cond_ << ") ? (" << *true_val_ << ") : (" <<
|
||||
@@ -749,6 +789,14 @@ void NetEUnary::dump(ostream&o) const
|
||||
|
||||
void Design::dump(ostream&o) const
|
||||
{
|
||||
o << "SCOPES:" << endl;
|
||||
{
|
||||
map<string,NetScope*>::const_iterator pp;
|
||||
for (pp = scopes_.begin()
|
||||
; pp != scopes_.end() ; pp ++)
|
||||
(*pp).second -> dump(o);
|
||||
}
|
||||
|
||||
o << "ELABORATED PARAMETERS:" << endl;
|
||||
{
|
||||
map<string,NetExpr*>::const_iterator pp;
|
||||
@@ -818,6 +866,25 @@ void Design::dump(ostream&o) const
|
||||
|
||||
/*
|
||||
* $Log: design_dump.cc,v $
|
||||
* Revision 1.61 1999/11/28 23:42:02 steve
|
||||
* NetESignal object no longer need to be NetNode
|
||||
* objects. Let them keep a pointer to NetNet objects.
|
||||
*
|
||||
* Revision 1.60 1999/11/27 19:07:57 steve
|
||||
* Support the creation of scopes.
|
||||
*
|
||||
* Revision 1.59 1999/11/24 04:01:58 steve
|
||||
* Detect and list scope names.
|
||||
*
|
||||
* Revision 1.58 1999/11/21 00:13:08 steve
|
||||
* Support memories in continuous assignments.
|
||||
*
|
||||
* Revision 1.57 1999/11/14 23:43:45 steve
|
||||
* Support combinatorial comparators.
|
||||
*
|
||||
* Revision 1.56 1999/11/14 20:24:28 steve
|
||||
* Add support for the LPM_CLSHIFT device.
|
||||
*
|
||||
* Revision 1.55 1999/11/04 03:53:26 steve
|
||||
* Patch to synthesize unary ~ and the ternary operator.
|
||||
* Thanks to Larry Doolittle <[email protected]>.
|
||||
|
||||
+38
@@ -0,0 +1,38 @@
|
||||
/*
|
||||
* Copyright (c) 1999 Stephen Williams ([email protected])
|
||||
*
|
||||
* This source code is free software; you can redistribute it
|
||||
* and/or modify it in source code form under the terms of the GNU
|
||||
* General Public License as published by the Free Software
|
||||
* Foundation; either version 2 of the License, or (at your option)
|
||||
* any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
|
||||
*/
|
||||
#if !defined(WINNT)
|
||||
#ident "$Id: dup_expr.cc,v 1.1 1999/11/27 19:07:57 steve Exp $"
|
||||
#endif
|
||||
|
||||
# include "netlist.h"
|
||||
# include <cassert>
|
||||
|
||||
NetEScope* NetEScope::dup_expr() const
|
||||
{
|
||||
assert(0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* $Log: dup_expr.cc,v $
|
||||
* Revision 1.1 1999/11/27 19:07:57 steve
|
||||
* Support the creation of scopes.
|
||||
*
|
||||
*/
|
||||
|
||||
+36
-12
@@ -17,7 +17,7 @@
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
|
||||
*/
|
||||
#if !defined(WINNT)
|
||||
#ident "$Id: elab_expr.cc,v 1.7 1999/10/18 00:02:21 steve Exp $"
|
||||
#ident "$Id: elab_expr.cc,v 1.12 1999/11/30 04:54:01 steve Exp $"
|
||||
#endif
|
||||
|
||||
|
||||
@@ -154,7 +154,6 @@ NetExpr* PECallFunction::elaborate_expr(Design*des, const string&path) const
|
||||
assert(res);
|
||||
NetESignal*eres = new NetESignal(res);
|
||||
assert(eres);
|
||||
des->add_node(eres);
|
||||
NetEUFunc*func = new NetEUFunc(def, eres, parms);
|
||||
return func;
|
||||
}
|
||||
@@ -209,15 +208,17 @@ NetExpr* PEIdent::elaborate_expr(Design*des, const string&path) const
|
||||
assert(net->sb_to_idx(msv) >= net->sb_to_idx(lsv));
|
||||
|
||||
string tname = des->local_symbol(path);
|
||||
NetESignal*tmp = new NetESignal(tname, wid);
|
||||
tmp->set_line(*this);
|
||||
NetTmp*tsig = new NetTmp(tname, wid);
|
||||
|
||||
// Connect the pins from the lsb up to the msb.
|
||||
unsigned off = net->sb_to_idx(lsv);
|
||||
for (unsigned idx = 0 ; idx < wid ; idx += 1)
|
||||
connect(tmp->pin(idx), net->pin(idx+off));
|
||||
connect(tsig->pin(idx), net->pin(idx+off));
|
||||
|
||||
des->add_node(tmp);
|
||||
NetESignal*tmp = new NetESignal(tsig);
|
||||
tmp->set_line(*this);
|
||||
|
||||
des->add_signal(tsig);
|
||||
return tmp;
|
||||
}
|
||||
|
||||
@@ -230,16 +231,16 @@ NetExpr* PEIdent::elaborate_expr(Design*des, const string&path) const
|
||||
unsigned long msv = msn->as_ulong();
|
||||
|
||||
string tname = des->local_symbol(path);
|
||||
NetESignal*tmp = new NetESignal(tname, 1);
|
||||
NetTmp*tsig = new NetTmp(tname);
|
||||
connect(tsig->pin(0), net->pin(msv));
|
||||
NetESignal*tmp = new NetESignal(tsig);
|
||||
tmp->set_line(*this);
|
||||
connect(tmp->pin(0), net->pin(msv));
|
||||
|
||||
des->add_node(tmp);
|
||||
des->add_signal(tsig);
|
||||
return tmp;
|
||||
}
|
||||
|
||||
NetESignal*node = new NetESignal(net);
|
||||
des->add_node(node);
|
||||
assert(idx_ == 0);
|
||||
|
||||
// Non-constant bit select? punt and make a subsignal
|
||||
@@ -260,7 +261,7 @@ NetExpr* PEIdent::elaborate_expr(Design*des, const string&path) const
|
||||
// If the identifier names a memory, then this is a
|
||||
// memory reference and I must generate a NetEMemory
|
||||
// object to handle it.
|
||||
if (NetMemory*mem = des->find_memory(name)) {
|
||||
if (NetMemory*mem = des->find_memory(path, text_)) {
|
||||
if (msb_ == 0) {
|
||||
cerr << get_line() << ": error: Memory ``" << name <<
|
||||
"'' referenced without an index expression." << endl;
|
||||
@@ -271,7 +272,7 @@ NetExpr* PEIdent::elaborate_expr(Design*des, const string&path) const
|
||||
assert(lsb_ == 0);
|
||||
assert(idx_ == 0);
|
||||
NetExpr*i = msb_->elaborate_expr(des, path);
|
||||
if (i == 0) {
|
||||
if (msb_ && i == 0) {
|
||||
cerr << get_line() << ": error: Unable to exaborate "
|
||||
"index expression `" << *msb_ << "'" << endl;
|
||||
des->errors += 1;
|
||||
@@ -283,6 +284,13 @@ NetExpr* PEIdent::elaborate_expr(Design*des, const string&path) const
|
||||
return node;
|
||||
}
|
||||
|
||||
// Finally, if this is a scope name, then return that.
|
||||
if (NetScope*nsc = des->find_scope(text_)) {
|
||||
NetEScope*tmp = new NetEScope(nsc);
|
||||
tmp->set_line(*this);
|
||||
return tmp;
|
||||
}
|
||||
|
||||
// I cannot interpret this identifier. Error message.
|
||||
cerr << get_line() << ": error: Unable to bind wire/reg/memory "
|
||||
"`" << path << "." << text_ << "'" << endl;
|
||||
@@ -324,6 +332,22 @@ NetExpr*PETernary::elaborate_expr(Design*des, const string&path) const
|
||||
|
||||
/*
|
||||
* $Log: elab_expr.cc,v $
|
||||
* Revision 1.12 1999/11/30 04:54:01 steve
|
||||
* Match scope names as last resort.
|
||||
*
|
||||
* Revision 1.11 1999/11/28 23:42:02 steve
|
||||
* NetESignal object no longer need to be NetNode
|
||||
* objects. Let them keep a pointer to NetNet objects.
|
||||
*
|
||||
* Revision 1.10 1999/11/27 19:07:57 steve
|
||||
* Support the creation of scopes.
|
||||
*
|
||||
* Revision 1.9 1999/11/21 17:35:37 steve
|
||||
* Memory name lookup handles scopes.
|
||||
*
|
||||
* Revision 1.8 1999/11/10 02:52:24 steve
|
||||
* Create the vpiMemory handle type.
|
||||
*
|
||||
* Revision 1.7 1999/10/18 00:02:21 steve
|
||||
* Catch unindexed memory reference.
|
||||
*
|
||||
|
||||
+640
-84
@@ -17,7 +17,7 @@
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
|
||||
*/
|
||||
#if !defined(WINNT)
|
||||
#ident "$Id: elab_net.cc,v 1.2 1999/11/04 03:53:26 steve Exp $"
|
||||
#ident "$Id: elab_net.cc,v 1.11 1999/12/02 04:08:10 steve Exp $"
|
||||
#endif
|
||||
|
||||
# include "PExpr.h"
|
||||
@@ -38,6 +38,17 @@ NetNet* PEBinary::elaborate_net(Design*des, const string&path,
|
||||
case '+':
|
||||
case '-':
|
||||
return elaborate_net_add_(des, path, width, rise, fall, decay);
|
||||
case 'E':
|
||||
case 'e':
|
||||
case 'n':
|
||||
case '<':
|
||||
case '>':
|
||||
case 'L': // <=
|
||||
case 'G': // >=
|
||||
return elaborate_net_cmp_(des, path, width, rise, fall, decay);
|
||||
case 'l': // <<
|
||||
case 'r': // >>
|
||||
return elaborate_net_shift_(des, path, width, rise, fall, decay);
|
||||
}
|
||||
|
||||
NetNet*lsig = left_->elaborate_net(des, path, width, 0, 0, 0),
|
||||
@@ -62,7 +73,7 @@ NetNet* PEBinary::elaborate_net(Design*des, const string&path,
|
||||
switch (op_) {
|
||||
case '^': // XOR
|
||||
assert(lsig->pin_count() == rsig->pin_count());
|
||||
osig = new NetNet(des->local_symbol(path), NetNet::WIRE,
|
||||
osig = new NetNet(0, des->local_symbol(path), NetNet::WIRE,
|
||||
lsig->pin_count());
|
||||
osig->local_flag(true);
|
||||
for (unsigned idx = 0 ; idx < lsig->pin_count() ; idx += 1) {
|
||||
@@ -81,7 +92,7 @@ NetNet* PEBinary::elaborate_net(Design*des, const string&path,
|
||||
|
||||
case '&': // AND
|
||||
assert(lsig->pin_count() == rsig->pin_count());
|
||||
osig = new NetNet(des->local_symbol(path), NetNet::WIRE,
|
||||
osig = new NetNet(0, des->local_symbol(path), NetNet::WIRE,
|
||||
lsig->pin_count());
|
||||
osig->local_flag(true);
|
||||
for (unsigned idx = 0 ; idx < lsig->pin_count() ; idx += 1) {
|
||||
@@ -100,7 +111,7 @@ NetNet* PEBinary::elaborate_net(Design*des, const string&path,
|
||||
|
||||
case '|': // Bitwise OR
|
||||
assert(lsig->pin_count() == rsig->pin_count());
|
||||
osig = new NetNet(des->local_symbol(path), NetNet::WIRE,
|
||||
osig = new NetNet(0, des->local_symbol(path), NetNet::WIRE,
|
||||
lsig->pin_count());
|
||||
osig->local_flag(true);
|
||||
for (unsigned idx = 0 ; idx < lsig->pin_count() ; idx += 1) {
|
||||
@@ -145,7 +156,7 @@ NetNet* PEBinary::elaborate_net(Design*des, const string&path,
|
||||
}
|
||||
|
||||
// The output is the AND of the two logic values.
|
||||
osig = new NetNet(des->local_symbol(path), NetNet::WIRE);
|
||||
osig = new NetNet(0, des->local_symbol(path), NetNet::WIRE);
|
||||
osig->local_flag(true);
|
||||
connect(gate->pin(0), osig->pin(0));
|
||||
des->add_signal(osig);
|
||||
@@ -156,81 +167,13 @@ NetNet* PEBinary::elaborate_net(Design*des, const string&path,
|
||||
break;
|
||||
|
||||
case 'E': // === (Case equals)
|
||||
|
||||
// The comparison generates gates to bitwise compare
|
||||
// each pair, and AND all the comparison results.
|
||||
assert(lsig->pin_count() == rsig->pin_count());
|
||||
osig = new NetNet(des->local_symbol(path), NetNet::WIRE);
|
||||
osig->local_flag(true);
|
||||
gate = new NetLogic(des->local_symbol(path),
|
||||
1+lsig->pin_count(),
|
||||
NetLogic::AND);
|
||||
connect(gate->pin(0), osig->pin(0));
|
||||
for (unsigned idx = 0 ; idx < lsig->pin_count() ; idx += 1) {
|
||||
gate_t = new NetCaseCmp(des->local_symbol(path));
|
||||
connect(gate_t->pin(1), lsig->pin(idx));
|
||||
connect(gate_t->pin(2), rsig->pin(idx));
|
||||
connect(gate_t->pin(0), gate->pin(idx+1));
|
||||
des->add_node(gate_t);
|
||||
|
||||
// Attach a label to this intermediate wire
|
||||
NetNet*tmp = new NetNet(des->local_symbol(path),
|
||||
NetNet::WIRE);
|
||||
tmp->local_flag(true);
|
||||
connect(gate_t->pin(0), tmp->pin(0));
|
||||
des->add_signal(tmp);
|
||||
}
|
||||
des->add_signal(osig);
|
||||
gate->rise_time(rise);
|
||||
gate->fall_time(fall);
|
||||
gate->decay_time(decay);
|
||||
des->add_node(gate);
|
||||
break;
|
||||
|
||||
case 'e': // ==
|
||||
assert(lsig->pin_count() == rsig->pin_count());
|
||||
osig = new NetNet(des->local_symbol(path), NetNet::WIRE);
|
||||
osig->local_flag(true);
|
||||
gate = new NetLogic(des->local_symbol(path),
|
||||
1+lsig->pin_count(),
|
||||
NetLogic::AND);
|
||||
connect(gate->pin(0), osig->pin(0));
|
||||
for (unsigned idx = 0 ; idx < lsig->pin_count() ; idx += 1) {
|
||||
gate_t = new NetLogic(des->local_symbol(path), 3,
|
||||
NetLogic::XNOR);
|
||||
connect(gate_t->pin(1), lsig->pin(idx));
|
||||
connect(gate_t->pin(2), rsig->pin(idx));
|
||||
connect(gate_t->pin(0), gate->pin(idx+1));
|
||||
des->add_node(gate_t);
|
||||
}
|
||||
des->add_signal(osig);
|
||||
gate->rise_time(rise);
|
||||
gate->fall_time(fall);
|
||||
gate->decay_time(decay);
|
||||
des->add_node(gate);
|
||||
break;
|
||||
|
||||
case 'n': // !=
|
||||
assert(lsig->pin_count() == rsig->pin_count());
|
||||
osig = new NetNet(des->local_symbol(path), NetNet::WIRE);
|
||||
osig->local_flag(true);
|
||||
gate = new NetLogic(des->local_symbol(path),
|
||||
1+lsig->pin_count(),
|
||||
NetLogic::OR);
|
||||
connect(gate->pin(0), osig->pin(0));
|
||||
for (unsigned idx = 0 ; idx < lsig->pin_count() ; idx += 1) {
|
||||
gate_t = new NetLogic(des->local_symbol(path), 3,
|
||||
NetLogic::XOR);
|
||||
connect(gate_t->pin(1), lsig->pin(idx));
|
||||
connect(gate_t->pin(2), rsig->pin(idx));
|
||||
connect(gate_t->pin(0), gate->pin(idx+1));
|
||||
des->add_node(gate_t);
|
||||
}
|
||||
des->add_signal(osig);
|
||||
gate->rise_time(rise);
|
||||
gate->fall_time(fall);
|
||||
gate->decay_time(decay);
|
||||
des->add_node(gate);
|
||||
case '<':
|
||||
case '>':
|
||||
case 'G': // >=
|
||||
case 'L': // <=
|
||||
assert(0);
|
||||
break;
|
||||
|
||||
case '+':
|
||||
@@ -239,10 +182,7 @@ NetNet* PEBinary::elaborate_net(Design*des, const string&path,
|
||||
|
||||
case 'l':
|
||||
case 'r':
|
||||
cerr << get_line() << ": sorry: combinational shift"
|
||||
" not supported here." << endl;
|
||||
des->errors += 1;
|
||||
osig = 0;
|
||||
assert(0);
|
||||
break;
|
||||
default:
|
||||
cerr << get_line() << ": internal error: unsupported"
|
||||
@@ -297,7 +237,7 @@ NetNet* PEBinary::elaborate_net_add_(Design*des, const string&path,
|
||||
width = rsig->pin_count();
|
||||
|
||||
// Make the adder as wide as the widest operand
|
||||
osig = new NetNet(des->local_symbol(path), NetNet::WIRE, width);
|
||||
osig = new NetNet(0, des->local_symbol(path), NetNet::WIRE, width);
|
||||
NetAddSub*adder = new NetAddSub(name, width);
|
||||
|
||||
// Connect the adder to the various parts.
|
||||
@@ -332,6 +272,589 @@ NetNet* PEBinary::elaborate_net_add_(Design*des, const string&path,
|
||||
return osig;
|
||||
}
|
||||
|
||||
/*
|
||||
* Elaborate the various binary comparison operators.
|
||||
*/
|
||||
NetNet* PEBinary::elaborate_net_cmp_(Design*des, const string&path,
|
||||
unsigned lwidth,
|
||||
unsigned long rise,
|
||||
unsigned long fall,
|
||||
unsigned long decay) const
|
||||
{
|
||||
NetNet*lsig = left_->elaborate_net(des, path, 0, 0, 0, 0),
|
||||
*rsig = right_->elaborate_net(des, path, 0, 0, 0, 0);
|
||||
if (lsig == 0) {
|
||||
cerr << get_line() << ": error: Cannot elaborate ";
|
||||
left_->dump(cerr);
|
||||
cerr << endl;
|
||||
return 0;
|
||||
}
|
||||
if (rsig == 0) {
|
||||
cerr << get_line() << ": error: Cannot elaborate ";
|
||||
right_->dump(cerr);
|
||||
cerr << endl;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (lsig->pin_count() != rsig->pin_count()) {
|
||||
cerr << get_line() << ": internal error: Cannot match "
|
||||
"structural net widths " << lsig->pin_count() <<
|
||||
" and " << rsig->pin_count() << "." << endl;
|
||||
delete lsig;
|
||||
delete rsig;
|
||||
des->errors += 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
NetNet*osig = new NetNet(0, des->local_symbol(path), NetNet::WIRE);
|
||||
osig->local_flag(true);
|
||||
|
||||
NetNode*gate;
|
||||
NetNode*gate_t;
|
||||
|
||||
switch (op_) {
|
||||
case '<':
|
||||
case '>':
|
||||
case 'L':
|
||||
case 'G': {
|
||||
NetCompare*cmp = new NetCompare(des->local_symbol(path),
|
||||
lsig->pin_count());
|
||||
for (unsigned idx = 0 ; idx < lsig->pin_count() ; idx += 1) {
|
||||
connect(cmp->pin_DataA(idx), lsig->pin(idx));
|
||||
connect(cmp->pin_DataB(idx), rsig->pin(idx));
|
||||
}
|
||||
switch (op_) {
|
||||
case '<':
|
||||
connect(cmp->pin_ALB(), osig->pin(0));
|
||||
break;
|
||||
case '>':
|
||||
connect(cmp->pin_AGB(), osig->pin(0));
|
||||
break;
|
||||
case 'L':
|
||||
connect(cmp->pin_ALEB(), osig->pin(0));
|
||||
break;
|
||||
case 'G':
|
||||
connect(cmp->pin_AGEB(), osig->pin(0));
|
||||
break;
|
||||
}
|
||||
gate = cmp;
|
||||
break;
|
||||
}
|
||||
|
||||
case 'E': // Case equals (===)
|
||||
// The comparison generates gates to bitwise compare
|
||||
// each pair, and AND all the comparison results.
|
||||
gate = new NetLogic(des->local_symbol(path),
|
||||
1+lsig->pin_count(),
|
||||
NetLogic::AND);
|
||||
connect(gate->pin(0), osig->pin(0));
|
||||
for (unsigned idx = 0 ; idx < lsig->pin_count() ; idx += 1) {
|
||||
gate_t = new NetCaseCmp(des->local_symbol(path));
|
||||
connect(gate_t->pin(1), lsig->pin(idx));
|
||||
connect(gate_t->pin(2), rsig->pin(idx));
|
||||
connect(gate_t->pin(0), gate->pin(idx+1));
|
||||
des->add_node(gate_t);
|
||||
|
||||
// Attach a label to this intermediate wire
|
||||
NetNet*tmp = new NetNet(0, des->local_symbol(path),
|
||||
NetNet::WIRE);
|
||||
tmp->local_flag(true);
|
||||
connect(gate_t->pin(0), tmp->pin(0));
|
||||
des->add_signal(tmp);
|
||||
}
|
||||
break;
|
||||
|
||||
|
||||
case 'e': // ==
|
||||
gate = new NetLogic(des->local_symbol(path),
|
||||
1+lsig->pin_count(),
|
||||
NetLogic::AND);
|
||||
connect(gate->pin(0), osig->pin(0));
|
||||
for (unsigned idx = 0 ; idx < lsig->pin_count() ; idx += 1) {
|
||||
gate_t = new NetLogic(des->local_symbol(path), 3,
|
||||
NetLogic::XNOR);
|
||||
connect(gate_t->pin(1), lsig->pin(idx));
|
||||
connect(gate_t->pin(2), rsig->pin(idx));
|
||||
connect(gate_t->pin(0), gate->pin(idx+1));
|
||||
des->add_node(gate_t);
|
||||
}
|
||||
break;
|
||||
|
||||
case 'n': // !=
|
||||
gate = new NetLogic(des->local_symbol(path),
|
||||
1+lsig->pin_count(),
|
||||
NetLogic::OR);
|
||||
connect(gate->pin(0), osig->pin(0));
|
||||
for (unsigned idx = 0 ; idx < lsig->pin_count() ; idx += 1) {
|
||||
gate_t = new NetLogic(des->local_symbol(path), 3,
|
||||
NetLogic::XOR);
|
||||
connect(gate_t->pin(1), lsig->pin(idx));
|
||||
connect(gate_t->pin(2), rsig->pin(idx));
|
||||
connect(gate_t->pin(0), gate->pin(idx+1));
|
||||
des->add_node(gate_t);
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
assert(0);
|
||||
}
|
||||
|
||||
des->add_signal(osig);
|
||||
gate->rise_time(rise);
|
||||
gate->fall_time(fall);
|
||||
gate->decay_time(decay);
|
||||
des->add_node(gate);
|
||||
|
||||
return osig;
|
||||
}
|
||||
|
||||
NetNet* PEBinary::elaborate_net_shift_(Design*des, const string&path,
|
||||
unsigned lwidth,
|
||||
unsigned long rise,
|
||||
unsigned long fall,
|
||||
unsigned long decay) const
|
||||
{
|
||||
NetNet*lsig = left_->elaborate_net(des, path, lwidth, 0, 0, 0);
|
||||
if (lsig == 0) return 0;
|
||||
|
||||
/* Handle the special case of a constant shift amount. There
|
||||
is no reason in this case to create a gate at all, just
|
||||
connect the lsig to the osig with the bit positions
|
||||
shifted. */
|
||||
if (verinum*rval = right_->eval_const(des, path)) {
|
||||
assert(rval->is_defined());
|
||||
unsigned dist = rval->as_ulong();
|
||||
if (dist > lsig->pin_count())
|
||||
dist = lsig->pin_count();
|
||||
|
||||
/* Very special case, constant 0 shift. */
|
||||
if (dist == 0) return lsig;
|
||||
|
||||
NetNet*osig = new NetNet(0, des->local_symbol(path), NetNet::WIRE,
|
||||
lsig->pin_count());
|
||||
osig->local_flag(true);
|
||||
|
||||
NetConst*zero = new NetConst(des->local_symbol(path), verinum::V0);
|
||||
des->add_node(zero);
|
||||
|
||||
if (op_ == 'l') {
|
||||
unsigned idx;
|
||||
for (idx = 0 ; idx < dist ; idx += 1)
|
||||
connect(osig->pin(idx), zero->pin(0));
|
||||
for (idx = dist ; idx < lsig->pin_count() ; idx += 1)
|
||||
connect(osig->pin(idx), lsig->pin(idx-dist));
|
||||
|
||||
} else {
|
||||
assert(op_ == 'r');
|
||||
unsigned idx;
|
||||
unsigned keep = lsig->pin_count()-dist;
|
||||
for (idx = 0 ; idx < keep ; idx += 1)
|
||||
connect(osig->pin(idx), lsig->pin(idx+dist));
|
||||
for (idx = keep ; idx < lsig->pin_count() ; idx += 1)
|
||||
connect(osig->pin(idx), zero->pin(0));
|
||||
}
|
||||
|
||||
des->add_signal(osig);
|
||||
return osig;
|
||||
}
|
||||
|
||||
unsigned dwid = 0;
|
||||
while ((1 << dwid) < lsig->pin_count())
|
||||
dwid += 1;
|
||||
|
||||
NetNet*rsig = right_->elaborate_net(des, path, dwid, 0, 0, 0);
|
||||
if (rsig == 0) return 0;
|
||||
|
||||
NetCLShift*gate = new NetCLShift(des->local_symbol(path),
|
||||
lsig->pin_count(),
|
||||
rsig->pin_count());
|
||||
|
||||
NetNet*osig = new NetNet(0, des->local_symbol(path), NetNet::WIRE,
|
||||
lsig->pin_count());
|
||||
osig->local_flag(true);
|
||||
|
||||
for (unsigned idx = 0 ; idx < osig->pin_count() ; idx += 1) {
|
||||
connect(osig->pin(idx), gate->pin_Result(idx));
|
||||
connect(lsig->pin(idx), gate->pin_Data(idx));
|
||||
}
|
||||
|
||||
for (unsigned idx = 0 ; idx < rsig->pin_count() ; idx += 1)
|
||||
connect(rsig->pin(idx), gate->pin_Distance(idx));
|
||||
|
||||
if (op_ == 'r') {
|
||||
NetConst*dir = new NetConst(des->local_symbol(path), verinum::V1);
|
||||
connect(dir->pin(0), gate->pin_Direction());
|
||||
des->add_node(dir);
|
||||
}
|
||||
|
||||
des->add_signal(osig);
|
||||
des->add_node(gate);
|
||||
|
||||
return osig;
|
||||
}
|
||||
|
||||
/*
|
||||
* The concatenation operator, as a net, is a wide signal that is
|
||||
* connected to all the pins of the elaborated expression nets.
|
||||
*/
|
||||
NetNet* PEConcat::elaborate_net(Design*des, const string&path,
|
||||
unsigned,
|
||||
unsigned long rise,
|
||||
unsigned long fall,
|
||||
unsigned long decay) const
|
||||
{
|
||||
svector<NetNet*>nets (parms_.count());
|
||||
unsigned pins = 0;
|
||||
unsigned errors = 0;
|
||||
|
||||
if (repeat_) {
|
||||
verinum*rep = repeat_->eval_const(des, path);
|
||||
if (rep == 0) {
|
||||
cerr << get_line() << ": internal error: Unable to "
|
||||
<< "evaluate constant repeat expression." << endl;
|
||||
des->errors += 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
unsigned long repeat = rep->as_ulong();
|
||||
|
||||
assert(parms_.count() == 1);
|
||||
NetNet*obj = parms_[0]->elaborate_net(des, path, 0, rise,
|
||||
fall, decay);
|
||||
NetTmp*tmp = new NetTmp(des->local_symbol(path),
|
||||
repeat * obj->pin_count());
|
||||
|
||||
for (unsigned idx = 0 ; idx < repeat ; idx += 1) {
|
||||
unsigned base = obj->pin_count() * idx;
|
||||
for (unsigned pin = 0 ; pin < obj->pin_count() ; pin += 1)
|
||||
connect(tmp->pin(base+pin), obj->pin(pin));
|
||||
}
|
||||
|
||||
des->add_signal(tmp);
|
||||
return tmp;
|
||||
}
|
||||
|
||||
/* Elaborate the operands of the concatenation. */
|
||||
for (unsigned idx = 0 ; idx < nets.count() ; idx += 1) {
|
||||
nets[idx] = parms_[idx]->elaborate_net(des, path, 0,
|
||||
rise,fall,decay);
|
||||
if (nets[idx] == 0)
|
||||
errors += 1;
|
||||
else
|
||||
pins += nets[idx]->pin_count();
|
||||
}
|
||||
|
||||
/* If any of the sub expressions failed to elaborate, then
|
||||
delete all those that did and abort myself. */
|
||||
if (errors) {
|
||||
for (unsigned idx = 0 ; idx < nets.count() ; idx += 1) {
|
||||
if (nets[idx]) delete nets[idx];
|
||||
}
|
||||
des->errors += 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Make the temporary signal that connects to all the
|
||||
operands, and connect it up. Scan the operands of the
|
||||
concat operator from least significant to most significant,
|
||||
which is opposite from how they are given in the list. */
|
||||
NetNet*osig = new NetNet(0, des->local_symbol(path),
|
||||
NetNet::IMPLICIT, pins);
|
||||
pins = 0;
|
||||
for (unsigned idx = nets.count() ; idx > 0 ; idx -= 1) {
|
||||
NetNet*cur = nets[idx-1];
|
||||
for (unsigned pin = 0 ; pin < cur->pin_count() ; pin += 1) {
|
||||
connect(osig->pin(pins), cur->pin(pin));
|
||||
pins += 1;
|
||||
}
|
||||
}
|
||||
|
||||
osig->local_flag(true);
|
||||
des->add_signal(osig);
|
||||
return osig;
|
||||
}
|
||||
|
||||
NetNet* PEIdent::elaborate_net(Design*des, const string&path,
|
||||
unsigned lwidth,
|
||||
unsigned long rise,
|
||||
unsigned long fall,
|
||||
unsigned long decay) const
|
||||
{
|
||||
NetScope*scope = des->find_scope(path);
|
||||
NetNet*sig = des->find_signal(path, text_);
|
||||
|
||||
if (sig == 0) {
|
||||
/* If the identifier is a memory instead of a signal,
|
||||
then handle it elsewhere. Create a RAM. */
|
||||
if (NetMemory*mem = des->find_memory(path, text_))
|
||||
return elaborate_net_ram_(des, path, mem, lwidth,
|
||||
rise, fall, decay);
|
||||
|
||||
|
||||
if (const NetExpr*pe = des->find_parameter(path, text_)) {
|
||||
|
||||
const NetEConst*pc = dynamic_cast<const NetEConst*>(pe);
|
||||
assert(pc);
|
||||
verinum pvalue = pc->value();
|
||||
sig = new NetNet(0, path+"."+text_, NetNet::IMPLICIT,
|
||||
pc->expr_width());
|
||||
for (unsigned idx = 0; idx < sig->pin_count(); idx += 1) {
|
||||
NetConst*cp = new NetConst(des->local_symbol(path),
|
||||
pvalue[idx]);
|
||||
connect(sig->pin(idx), cp->pin(0));
|
||||
des->add_node(cp);
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
sig = new NetNet(scope, path+"."+text_, NetNet::IMPLICIT, 1);
|
||||
des->add_signal(sig);
|
||||
cerr << get_line() << ": warning: Implicitly defining "
|
||||
"wire " << path << "." << text_ << "." << endl;
|
||||
}
|
||||
}
|
||||
|
||||
assert(sig);
|
||||
|
||||
if (msb_ && lsb_) {
|
||||
verinum*mval = msb_->eval_const(des, path);
|
||||
if (mval == 0) {
|
||||
cerr << msb_->get_line() << ": error: unable to "
|
||||
"evaluate constant expression: " << *msb_ <<
|
||||
endl;
|
||||
des->errors += 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
verinum*lval = lsb_->eval_const(des, path);
|
||||
if (lval == 0) {
|
||||
cerr << lsb_->get_line() << ": error: unable to "
|
||||
"evaluate constant expression: " << *lsb_ <<
|
||||
endl;
|
||||
delete mval;
|
||||
des->errors += 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
assert(mval);
|
||||
assert(lval);
|
||||
unsigned midx = sig->sb_to_idx(mval->as_long());
|
||||
unsigned lidx = sig->sb_to_idx(lval->as_long());
|
||||
|
||||
if (midx >= lidx) {
|
||||
NetTmp*tmp = new NetTmp(des->local_symbol(path),
|
||||
midx-lidx+1);
|
||||
des->add_signal(tmp);
|
||||
if (tmp->pin_count() > sig->pin_count()) {
|
||||
cerr << get_line() << ": bit select out of "
|
||||
<< "range for " << sig->name() << endl;
|
||||
return sig;
|
||||
}
|
||||
|
||||
for (unsigned idx = lidx ; idx <= midx ; idx += 1)
|
||||
connect(tmp->pin(idx-lidx), sig->pin(idx));
|
||||
|
||||
sig = tmp;
|
||||
|
||||
} else {
|
||||
NetTmp*tmp = new NetTmp(des->local_symbol(path),
|
||||
lidx-midx+1);
|
||||
des->add_signal(tmp);
|
||||
assert(tmp->pin_count() <= sig->pin_count());
|
||||
for (unsigned idx = lidx ; idx >= midx ; idx -= 1)
|
||||
connect(tmp->pin(idx-midx), sig->pin(idx));
|
||||
|
||||
sig = tmp;
|
||||
}
|
||||
|
||||
} else if (msb_) {
|
||||
verinum*mval = msb_->eval_const(des, path);
|
||||
if (mval == 0) {
|
||||
cerr << get_line() << ": index of " << text_ <<
|
||||
" needs to be constant in this context." <<
|
||||
endl;
|
||||
des->errors += 1;
|
||||
return 0;
|
||||
}
|
||||
assert(mval);
|
||||
unsigned idx = sig->sb_to_idx(mval->as_long());
|
||||
if (idx >= sig->pin_count()) {
|
||||
cerr << get_line() << "; index " << sig->name() <<
|
||||
"[" << mval->as_long() << "] out of range." << endl;
|
||||
des->errors += 1;
|
||||
idx = 0;
|
||||
}
|
||||
NetTmp*tmp = new NetTmp(des->local_symbol(path), 1);
|
||||
des->add_signal(tmp);
|
||||
connect(tmp->pin(0), sig->pin(idx));
|
||||
sig = tmp;
|
||||
}
|
||||
|
||||
return sig;
|
||||
}
|
||||
|
||||
/*
|
||||
* When I run into an identifier in an expression that referrs to a
|
||||
* memory, create a RAM port object.
|
||||
*/
|
||||
NetNet* PEIdent::elaborate_net_ram_(Design*des, const string&path,
|
||||
NetMemory*mem, unsigned lwidth,
|
||||
unsigned long rise,
|
||||
unsigned long fall,
|
||||
unsigned long decay) const
|
||||
{
|
||||
if (msb_ == 0) {
|
||||
cerr << get_line() << ": error: memory reference without"
|
||||
" the required index expression." << endl;
|
||||
des->errors += 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
NetNet*adr = msb_->elaborate_net(des, path, 0, 0, 0, 0);
|
||||
if (adr == 0)
|
||||
return 0;
|
||||
|
||||
|
||||
NetRamDq*ram = new NetRamDq(des->local_symbol(mem->name()),
|
||||
mem, adr->pin_count());
|
||||
des->add_node(ram);
|
||||
|
||||
for (unsigned idx = 0 ; idx < adr->pin_count() ; idx += 1)
|
||||
connect(ram->pin_Address(idx), adr->pin(idx));
|
||||
|
||||
NetNet*osig = new NetTmp(des->local_symbol(mem->name()), ram->width());
|
||||
des->add_signal(osig);
|
||||
|
||||
for (unsigned idx = 0 ; idx < osig->pin_count() ; idx += 1)
|
||||
connect(ram->pin_Q(idx), osig->pin(idx));
|
||||
|
||||
return osig;
|
||||
}
|
||||
|
||||
/*
|
||||
* Identifiers in continuous assignment l-values are limited to wires
|
||||
* and that ilk. Detect registers and memories here and report errors.
|
||||
*/
|
||||
NetNet* PEIdent::elaborate_lnet(Design*des, const string&path) const
|
||||
{
|
||||
NetNet*sig = des->find_signal(path, text_);
|
||||
if (sig == 0) {
|
||||
/* Don't allow memories here. Is it a memory? */
|
||||
if (des->find_memory(path, text_)) {
|
||||
cerr << get_line() << ": error: memories (" << text_
|
||||
<< ") cannot be l-values in continuous "
|
||||
<< "assignments." << endl;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Fine, create an implicit wire as an l-value. */
|
||||
sig = new NetNet(0, path+"."+text_, NetNet::IMPLICIT, 1);
|
||||
des->add_signal(sig);
|
||||
cerr << get_line() << ": warning: Implicitly defining "
|
||||
"wire " << path << "." << text_ << "." << endl;
|
||||
}
|
||||
|
||||
assert(sig);
|
||||
|
||||
/* Don't allow registers as assign l-values. */
|
||||
if (sig->type() == NetNet::REG) {
|
||||
cerr << get_line() << ": error: registers (" << sig->name()
|
||||
<< ") cannot be l-values in continuous"
|
||||
<< " assignments." << endl;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (msb_ && lsb_) {
|
||||
/* Detect a part select. Evaluate the bits and elaborate
|
||||
the l-value by creating a sub-net that links to just
|
||||
the right pins. */
|
||||
verinum*mval = msb_->eval_const(des, path);
|
||||
assert(mval);
|
||||
verinum*lval = lsb_->eval_const(des, path);
|
||||
assert(lval);
|
||||
unsigned midx = sig->sb_to_idx(mval->as_long());
|
||||
unsigned lidx = sig->sb_to_idx(lval->as_long());
|
||||
|
||||
if (midx >= lidx) {
|
||||
NetTmp*tmp = new NetTmp(des->local_symbol(path),
|
||||
midx-lidx+1);
|
||||
des->add_signal(tmp);
|
||||
if (tmp->pin_count() > sig->pin_count()) {
|
||||
cerr << get_line() << ": bit select out of "
|
||||
<< "range for " << sig->name() << endl;
|
||||
return sig;
|
||||
}
|
||||
|
||||
for (unsigned idx = lidx ; idx <= midx ; idx += 1)
|
||||
connect(tmp->pin(idx-lidx), sig->pin(idx));
|
||||
|
||||
sig = tmp;
|
||||
|
||||
} else {
|
||||
NetTmp*tmp = new NetTmp(des->local_symbol(path),
|
||||
lidx-midx+1);
|
||||
des->add_signal(tmp);
|
||||
assert(tmp->pin_count() <= sig->pin_count());
|
||||
for (unsigned idx = lidx ; idx >= midx ; idx -= 1)
|
||||
connect(tmp->pin(idx-midx), sig->pin(idx));
|
||||
|
||||
sig = tmp;
|
||||
}
|
||||
|
||||
} else if (msb_) {
|
||||
verinum*mval = msb_->eval_const(des, path);
|
||||
if (mval == 0) {
|
||||
cerr << get_line() << ": index of " << text_ <<
|
||||
" needs to be constant in this context." <<
|
||||
endl;
|
||||
des->errors += 1;
|
||||
return 0;
|
||||
}
|
||||
assert(mval);
|
||||
unsigned idx = sig->sb_to_idx(mval->as_long());
|
||||
if (idx >= sig->pin_count()) {
|
||||
cerr << get_line() << "; index " << sig->name() <<
|
||||
"[" << mval->as_long() << "] out of range." << endl;
|
||||
des->errors += 1;
|
||||
idx = 0;
|
||||
}
|
||||
NetTmp*tmp = new NetTmp(des->local_symbol(path), 1);
|
||||
des->add_signal(tmp);
|
||||
connect(tmp->pin(0), sig->pin(idx));
|
||||
sig = tmp;
|
||||
}
|
||||
|
||||
return sig;
|
||||
}
|
||||
|
||||
/*
|
||||
* Elaborate a number as a NetConst object.
|
||||
*/
|
||||
NetNet* PENumber::elaborate_net(Design*des, const string&path,
|
||||
unsigned lwidth,
|
||||
unsigned long rise,
|
||||
unsigned long fall,
|
||||
unsigned long decay) const
|
||||
{
|
||||
unsigned width = value_->len();
|
||||
if ((lwidth > 0) && (lwidth < width))
|
||||
width = lwidth;
|
||||
|
||||
NetNet*net = new NetNet(0, des->local_symbol(path),
|
||||
NetNet::IMPLICIT, width);
|
||||
net->local_flag(true);
|
||||
for (unsigned idx = 0 ; idx < width ; idx += 1) {
|
||||
NetConst*tmp = new NetConst(des->local_symbol(path),
|
||||
value_->get(idx));
|
||||
des->add_node(tmp);
|
||||
connect(net->pin(idx), tmp->pin(0));
|
||||
}
|
||||
|
||||
des->add_signal(net);
|
||||
return net;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Elaborate the ternary operator in a netlist by creating a LPM_MUX
|
||||
* with width matching the result, size == 2 and 1 select input.
|
||||
@@ -354,7 +877,7 @@ NetNet* PETernary::elaborate_net(Design*des, const string&path,
|
||||
assert(width == tru_sig->pin_count());
|
||||
assert(expr_sig->pin_count() == 1);
|
||||
|
||||
NetNet*sig = new NetNet(des->local_symbol(path), NetNet::WIRE,
|
||||
NetNet*sig = new NetNet(0, des->local_symbol(path), NetNet::WIRE,
|
||||
tru_sig->pin_count());
|
||||
sig->local_flag(true);
|
||||
|
||||
@@ -366,10 +889,43 @@ NetNet* PETernary::elaborate_net(Design*des, const string&path,
|
||||
connect(mux->pin_Data(idx,0), fal_sig->pin(idx));
|
||||
connect(mux->pin_Data(idx,1), tru_sig->pin(idx));
|
||||
}
|
||||
|
||||
des->add_signal(sig);
|
||||
des->add_node(mux);
|
||||
|
||||
return sig;
|
||||
}
|
||||
|
||||
/*
|
||||
* $Log: elab_net.cc,v $
|
||||
* Revision 1.11 1999/12/02 04:08:10 steve
|
||||
* Elaborate net repeat concatenations.
|
||||
*
|
||||
* Revision 1.10 1999/11/30 04:33:41 steve
|
||||
* Put implicitly defined signals in the scope.
|
||||
*
|
||||
* Revision 1.9 1999/11/27 19:07:57 steve
|
||||
* Support the creation of scopes.
|
||||
*
|
||||
* Revision 1.8 1999/11/21 17:35:37 steve
|
||||
* Memory name lookup handles scopes.
|
||||
*
|
||||
* Revision 1.7 1999/11/21 00:13:08 steve
|
||||
* Support memories in continuous assignments.
|
||||
*
|
||||
* Revision 1.6 1999/11/14 23:43:45 steve
|
||||
* Support combinatorial comparators.
|
||||
*
|
||||
* Revision 1.5 1999/11/14 20:24:28 steve
|
||||
* Add support for the LPM_CLSHIFT device.
|
||||
*
|
||||
* Revision 1.4 1999/11/05 23:36:31 steve
|
||||
* Forgot to return the mux for use after elaboration.
|
||||
*
|
||||
* Revision 1.3 1999/11/05 21:45:19 steve
|
||||
* Fix NetConst being set to zero width, and clean
|
||||
* up elaborate_set_cmp_ for NetEBinary.
|
||||
*
|
||||
* Revision 1.2 1999/11/04 03:53:26 steve
|
||||
* Patch to synthesize unary ~ and the ternary operator.
|
||||
* Thanks to Larry Doolittle <[email protected]>.
|
||||
|
||||
+84
-588
@@ -17,7 +17,7 @@
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
|
||||
*/
|
||||
#if !defined(WINNT)
|
||||
#ident "$Id: elaborate.cc,v 1.121 1999/11/04 03:53:26 steve Exp $"
|
||||
#ident "$Id: elaborate.cc,v 1.132 1999/12/02 04:08:10 steve Exp $"
|
||||
#endif
|
||||
|
||||
/*
|
||||
@@ -54,8 +54,9 @@ static const map<string,PUdp*>* udplist = 0;
|
||||
* elaboration this creates an object in the design that represent the
|
||||
* defined item.
|
||||
*/
|
||||
void PWire::elaborate(Design*des, const string&path) const
|
||||
void PWire::elaborate(Design*des, NetScope*scope) const
|
||||
{
|
||||
const string path = scope->name();
|
||||
NetNet::Type wtype = type_;
|
||||
if (wtype == NetNet::IMPLICIT)
|
||||
wtype = NetNet::WIRE;
|
||||
@@ -141,7 +142,7 @@ void PWire::elaborate(Design*des, const string&path) const
|
||||
|
||||
} else {
|
||||
|
||||
NetNet*sig = new NetNet(path + "." + name_, wtype, msb, lsb);
|
||||
NetNet*sig = new NetNet(scope, path + "." + name_, wtype, msb, lsb);
|
||||
sig->set_line(*this);
|
||||
sig->port_type(port_type_);
|
||||
sig->set_attributes(attributes);
|
||||
@@ -290,7 +291,7 @@ void PGBuiltin::elaborate(Design*des, const string&path) const
|
||||
else
|
||||
index = low - idx;
|
||||
|
||||
tmp << name << "<" << index << ">";
|
||||
tmp << name << "<" << index << ">" << ends;
|
||||
const string inm = tmp.str();
|
||||
|
||||
switch (type()) {
|
||||
@@ -376,7 +377,8 @@ void PGBuiltin::elaborate(Design*des, const string&path) const
|
||||
void PGModule::elaborate_mod_(Design*des, Module*rmod, const string&path) const
|
||||
{
|
||||
assert(get_name() != "");
|
||||
const string my_name = path + "." + get_name();
|
||||
NetScope*my_scope = des->make_scope(path, NetScope::MODULE, get_name());
|
||||
const string my_name = my_scope -> name();
|
||||
|
||||
const svector<PExpr*>*pins;
|
||||
|
||||
@@ -445,7 +447,7 @@ void PGModule::elaborate_mod_(Design*des, Module*rmod, const string&path) const
|
||||
// elaboration causes the module to generate a netlist with
|
||||
// the ports represented by NetNet objects. I will find them
|
||||
// later.
|
||||
rmod->elaborate(des, my_name, overrides_);
|
||||
rmod->elaborate(des, my_scope, overrides_);
|
||||
|
||||
// Now connect the ports of the newly elaborated designs to
|
||||
// the expressions that are the instantiation parameters. Scan
|
||||
@@ -591,66 +593,6 @@ void PGModule::elaborate(Design*des, const string&path) const
|
||||
cerr << get_line() << ": error: Unknown module: " << type_ << endl;
|
||||
}
|
||||
|
||||
/*
|
||||
* The concatenation operator, as a net, is a wide signal that is
|
||||
* connected to all the pins of the elaborated expression nets.
|
||||
*/
|
||||
NetNet* PEConcat::elaborate_net(Design*des, const string&path,
|
||||
unsigned,
|
||||
unsigned long rise,
|
||||
unsigned long fall,
|
||||
unsigned long decay) const
|
||||
{
|
||||
svector<NetNet*>nets (parms_.count());
|
||||
unsigned pins = 0;
|
||||
unsigned errors = 0;
|
||||
|
||||
if (repeat_) {
|
||||
cerr << get_line() << ": sorry: I do not know how to"
|
||||
" elaborate repeat concatenation nets." << endl;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Elaborate the operands of the concatenation. */
|
||||
for (unsigned idx = 0 ; idx < nets.count() ; idx += 1) {
|
||||
nets[idx] = parms_[idx]->elaborate_net(des, path, 0,
|
||||
rise,fall,decay);
|
||||
if (nets[idx] == 0)
|
||||
errors += 1;
|
||||
else
|
||||
pins += nets[idx]->pin_count();
|
||||
}
|
||||
|
||||
/* If any of the sub expressions failed to elaborate, then
|
||||
delete all those that did and abort myself. */
|
||||
if (errors) {
|
||||
for (unsigned idx = 0 ; idx < nets.count() ; idx += 1) {
|
||||
if (nets[idx]) delete nets[idx];
|
||||
}
|
||||
des->errors += 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Make the temporary signal that connects to all the
|
||||
operands, and connect it up. Scan the operands of the
|
||||
concat operator from least significant to most significant,
|
||||
which is opposite from how they are given in the list. */
|
||||
NetNet*osig = new NetNet(des->local_symbol(path),
|
||||
NetNet::IMPLICIT, pins);
|
||||
pins = 0;
|
||||
for (unsigned idx = nets.count() ; idx > 0 ; idx -= 1) {
|
||||
NetNet*cur = nets[idx-1];
|
||||
for (unsigned pin = 0 ; pin < cur->pin_count() ; pin += 1) {
|
||||
connect(osig->pin(pins), cur->pin(pin));
|
||||
pins += 1;
|
||||
}
|
||||
}
|
||||
|
||||
osig->local_flag(true);
|
||||
des->add_signal(osig);
|
||||
return osig;
|
||||
}
|
||||
|
||||
/*
|
||||
* The concatenation is also OK an an l-value. This method elaborates
|
||||
* it as a structural l-value.
|
||||
@@ -690,7 +632,7 @@ NetNet* PEConcat::elaborate_lnet(Design*des, const string&path) const
|
||||
operands, and connect it up. Scan the operands of the
|
||||
concat operator from least significant to most significant,
|
||||
which is opposite from how they are given in the list. */
|
||||
NetNet*osig = new NetNet(des->local_symbol(path),
|
||||
NetNet*osig = new NetNet(0, des->local_symbol(path),
|
||||
NetNet::IMPLICIT, pins);
|
||||
pins = 0;
|
||||
for (unsigned idx = nets.count() ; idx > 0 ; idx -= 1) {
|
||||
@@ -706,236 +648,6 @@ NetNet* PEConcat::elaborate_lnet(Design*des, const string&path) const
|
||||
return osig;
|
||||
}
|
||||
|
||||
NetNet* PEIdent::elaborate_net(Design*des, const string&path,
|
||||
unsigned lwidth,
|
||||
unsigned long rise,
|
||||
unsigned long fall,
|
||||
unsigned long decay) const
|
||||
{
|
||||
NetNet*sig = des->find_signal(path, text_);
|
||||
if (sig == 0) {
|
||||
if (des->find_memory(path+"."+text_)) {
|
||||
cerr << get_line() << ": sorry: memories not supported"
|
||||
" in this context." << endl;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (const NetExpr*pe = des->find_parameter(path, text_)) {
|
||||
|
||||
const NetEConst*pc = dynamic_cast<const NetEConst*>(pe);
|
||||
assert(pc);
|
||||
verinum pvalue = pc->value();
|
||||
sig = new NetNet(path+"."+text_, NetNet::IMPLICIT,
|
||||
pc->expr_width());
|
||||
for (unsigned idx = 0; idx < sig->pin_count(); idx += 1) {
|
||||
NetConst*cp = new NetConst(des->local_symbol(path),
|
||||
pvalue[idx]);
|
||||
connect(sig->pin(idx), cp->pin(0));
|
||||
des->add_node(cp);
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
sig = new NetNet(path+"."+text_, NetNet::IMPLICIT, 1);
|
||||
des->add_signal(sig);
|
||||
cerr << get_line() << ": warning: Implicitly defining "
|
||||
"wire " << path << "." << text_ << "." << endl;
|
||||
}
|
||||
}
|
||||
|
||||
assert(sig);
|
||||
|
||||
if (msb_ && lsb_) {
|
||||
verinum*mval = msb_->eval_const(des, path);
|
||||
if (mval == 0) {
|
||||
cerr << msb_->get_line() << ": error: unable to "
|
||||
"evaluate constant expression: " << *msb_ <<
|
||||
endl;
|
||||
des->errors += 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
verinum*lval = lsb_->eval_const(des, path);
|
||||
if (lval == 0) {
|
||||
cerr << lsb_->get_line() << ": error: unable to "
|
||||
"evaluate constant expression: " << *lsb_ <<
|
||||
endl;
|
||||
delete mval;
|
||||
des->errors += 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
assert(mval);
|
||||
assert(lval);
|
||||
unsigned midx = sig->sb_to_idx(mval->as_long());
|
||||
unsigned lidx = sig->sb_to_idx(lval->as_long());
|
||||
|
||||
if (midx >= lidx) {
|
||||
NetTmp*tmp = new NetTmp(midx-lidx+1);
|
||||
if (tmp->pin_count() > sig->pin_count()) {
|
||||
cerr << get_line() << ": bit select out of "
|
||||
<< "range for " << sig->name() << endl;
|
||||
return sig;
|
||||
}
|
||||
|
||||
for (unsigned idx = lidx ; idx <= midx ; idx += 1)
|
||||
connect(tmp->pin(idx-lidx), sig->pin(idx));
|
||||
|
||||
sig = tmp;
|
||||
|
||||
} else {
|
||||
NetTmp*tmp = new NetTmp(lidx-midx+1);
|
||||
assert(tmp->pin_count() <= sig->pin_count());
|
||||
for (unsigned idx = lidx ; idx >= midx ; idx -= 1)
|
||||
connect(tmp->pin(idx-midx), sig->pin(idx));
|
||||
|
||||
sig = tmp;
|
||||
}
|
||||
|
||||
} else if (msb_) {
|
||||
verinum*mval = msb_->eval_const(des, path);
|
||||
if (mval == 0) {
|
||||
cerr << get_line() << ": index of " << text_ <<
|
||||
" needs to be constant in this context." <<
|
||||
endl;
|
||||
des->errors += 1;
|
||||
return 0;
|
||||
}
|
||||
assert(mval);
|
||||
unsigned idx = sig->sb_to_idx(mval->as_long());
|
||||
if (idx >= sig->pin_count()) {
|
||||
cerr << get_line() << "; index " << sig->name() <<
|
||||
"[" << mval->as_long() << "] out of range." << endl;
|
||||
des->errors += 1;
|
||||
idx = 0;
|
||||
}
|
||||
NetTmp*tmp = new NetTmp(1);
|
||||
connect(tmp->pin(0), sig->pin(idx));
|
||||
sig = tmp;
|
||||
}
|
||||
|
||||
return sig;
|
||||
}
|
||||
|
||||
/*
|
||||
* Identifiers in continuous assignment l-values are limited to wires
|
||||
* and that ilk. Detect registers and memories here and report errors.
|
||||
*/
|
||||
NetNet* PEIdent::elaborate_lnet(Design*des, const string&path) const
|
||||
{
|
||||
NetNet*sig = des->find_signal(path, text_);
|
||||
if (sig == 0) {
|
||||
/* Don't allow memories here. Is it a memory? */
|
||||
if (des->find_memory(path+"."+text_)) {
|
||||
cerr << get_line() << ": error: memories (" << text_
|
||||
<< ") cannot be l-values in continuous "
|
||||
<< "assignments." << endl;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Fine, create an implicit wire as an l-value. */
|
||||
sig = new NetNet(path+"."+text_, NetNet::IMPLICIT, 1);
|
||||
des->add_signal(sig);
|
||||
cerr << get_line() << ": warning: Implicitly defining "
|
||||
"wire " << path << "." << text_ << "." << endl;
|
||||
}
|
||||
|
||||
assert(sig);
|
||||
|
||||
/* Don't allow registers as assign l-values. */
|
||||
if (sig->type() == NetNet::REG) {
|
||||
cerr << get_line() << ": error: registers (" << sig->name()
|
||||
<< ") cannot be l-values in continuous"
|
||||
<< " assignments." << endl;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (msb_ && lsb_) {
|
||||
/* Detect a part select. Evaluate the bits and elaborate
|
||||
the l-value by creating a sub-net that links to just
|
||||
the right pins. */
|
||||
verinum*mval = msb_->eval_const(des, path);
|
||||
assert(mval);
|
||||
verinum*lval = lsb_->eval_const(des, path);
|
||||
assert(lval);
|
||||
unsigned midx = sig->sb_to_idx(mval->as_long());
|
||||
unsigned lidx = sig->sb_to_idx(lval->as_long());
|
||||
|
||||
if (midx >= lidx) {
|
||||
NetTmp*tmp = new NetTmp(midx-lidx+1);
|
||||
if (tmp->pin_count() > sig->pin_count()) {
|
||||
cerr << get_line() << ": bit select out of "
|
||||
<< "range for " << sig->name() << endl;
|
||||
return sig;
|
||||
}
|
||||
|
||||
for (unsigned idx = lidx ; idx <= midx ; idx += 1)
|
||||
connect(tmp->pin(idx-lidx), sig->pin(idx));
|
||||
|
||||
sig = tmp;
|
||||
|
||||
} else {
|
||||
NetTmp*tmp = new NetTmp(lidx-midx+1);
|
||||
assert(tmp->pin_count() <= sig->pin_count());
|
||||
for (unsigned idx = lidx ; idx >= midx ; idx -= 1)
|
||||
connect(tmp->pin(idx-midx), sig->pin(idx));
|
||||
|
||||
sig = tmp;
|
||||
}
|
||||
|
||||
} else if (msb_) {
|
||||
verinum*mval = msb_->eval_const(des, path);
|
||||
if (mval == 0) {
|
||||
cerr << get_line() << ": index of " << text_ <<
|
||||
" needs to be constant in this context." <<
|
||||
endl;
|
||||
des->errors += 1;
|
||||
return 0;
|
||||
}
|
||||
assert(mval);
|
||||
unsigned idx = sig->sb_to_idx(mval->as_long());
|
||||
if (idx >= sig->pin_count()) {
|
||||
cerr << get_line() << "; index " << sig->name() <<
|
||||
"[" << mval->as_long() << "] out of range." << endl;
|
||||
des->errors += 1;
|
||||
idx = 0;
|
||||
}
|
||||
NetTmp*tmp = new NetTmp(1);
|
||||
connect(tmp->pin(0), sig->pin(idx));
|
||||
sig = tmp;
|
||||
}
|
||||
|
||||
return sig;
|
||||
}
|
||||
|
||||
/*
|
||||
* Elaborate a number as a NetConst object.
|
||||
*/
|
||||
NetNet* PENumber::elaborate_net(Design*des, const string&path,
|
||||
unsigned lwidth,
|
||||
unsigned long rise,
|
||||
unsigned long fall,
|
||||
unsigned long decay) const
|
||||
{
|
||||
unsigned width = value_->len();
|
||||
if (lwidth < width)
|
||||
width = lwidth;
|
||||
|
||||
NetNet*net = new NetNet(des->local_symbol(path),
|
||||
NetNet::IMPLICIT, width);
|
||||
net->local_flag(true);
|
||||
for (unsigned idx = 0 ; idx < width ; idx += 1) {
|
||||
NetConst*tmp = new NetConst(des->local_symbol(path),
|
||||
value_->get(idx));
|
||||
des->add_node(tmp);
|
||||
connect(net->pin(idx), tmp->pin(0));
|
||||
}
|
||||
|
||||
des->add_signal(net);
|
||||
return net;
|
||||
}
|
||||
|
||||
|
||||
NetNet* PEUnary::elaborate_net(Design*des, const string&path,
|
||||
unsigned width,
|
||||
unsigned long rise,
|
||||
@@ -954,7 +666,7 @@ NetNet* PEUnary::elaborate_net(Design*des, const string&path,
|
||||
NetLogic*gate;
|
||||
switch (op_) {
|
||||
case '~': // Bitwise NOT
|
||||
sig = new NetNet(des->local_symbol(path), NetNet::WIRE,
|
||||
sig = new NetNet(0, des->local_symbol(path), NetNet::WIRE,
|
||||
sub_sig->pin_count());
|
||||
sig->local_flag(true);
|
||||
for (unsigned idx = 0 ; idx < sub_sig->pin_count() ; idx += 1) {
|
||||
@@ -972,7 +684,7 @@ NetNet* PEUnary::elaborate_net(Design*des, const string&path,
|
||||
|
||||
case 'N': // Reduction NOR
|
||||
case '!': // Reduction NOT
|
||||
sig = new NetNet(des->local_symbol(path), NetNet::WIRE);
|
||||
sig = new NetNet(0, des->local_symbol(path), NetNet::WIRE);
|
||||
sig->local_flag(true);
|
||||
gate = new NetLogic(des->local_symbol(path),
|
||||
1+sub_sig->pin_count(),
|
||||
@@ -989,7 +701,7 @@ NetNet* PEUnary::elaborate_net(Design*des, const string&path,
|
||||
break;
|
||||
|
||||
case '&': // Reduction AND
|
||||
sig = new NetNet(des->local_symbol(path), NetNet::WIRE);
|
||||
sig = new NetNet(0, des->local_symbol(path), NetNet::WIRE);
|
||||
sig->local_flag(true);
|
||||
gate = new NetLogic(des->local_symbol(path),
|
||||
1+sub_sig->pin_count(),
|
||||
@@ -1006,7 +718,7 @@ NetNet* PEUnary::elaborate_net(Design*des, const string&path,
|
||||
break;
|
||||
|
||||
case '|': // Reduction OR
|
||||
sig = new NetNet(des->local_symbol(path), NetNet::WIRE);
|
||||
sig = new NetNet(0, des->local_symbol(path), NetNet::WIRE);
|
||||
sig->local_flag(true);
|
||||
gate = new NetLogic(des->local_symbol(path),
|
||||
1+sub_sig->pin_count(),
|
||||
@@ -1023,7 +735,7 @@ NetNet* PEUnary::elaborate_net(Design*des, const string&path,
|
||||
break;
|
||||
|
||||
case '^': // Reduction XOR
|
||||
sig = new NetNet(des->local_symbol(path), NetNet::WIRE);
|
||||
sig = new NetNet(0, des->local_symbol(path), NetNet::WIRE);
|
||||
sig->local_flag(true);
|
||||
gate = new NetLogic(des->local_symbol(path),
|
||||
1+sub_sig->pin_count(),
|
||||
@@ -1277,7 +989,7 @@ NetProc* PAssign::elaborate(Design*des, const string&path) const
|
||||
const PEIdent*id = dynamic_cast<const PEIdent*>(lval());
|
||||
if (id == 0) break;
|
||||
|
||||
if (NetMemory*mem = des->find_memory(path+"."+id->name()))
|
||||
if (NetMemory*mem = des->find_memory(path, id->name()))
|
||||
return assign_to_memory_(mem, id->msb_, des, path);
|
||||
|
||||
} while(0);
|
||||
@@ -1297,9 +1009,21 @@ NetProc* PAssign::elaborate(Design*des, const string&path) const
|
||||
|
||||
/* Elaborate the r-value expression. */
|
||||
assert(rval());
|
||||
NetExpr*rv = rval()->elaborate_expr(des, path);
|
||||
if (rv == 0)
|
||||
|
||||
NetExpr*rv;
|
||||
|
||||
if (verinum*val = rval()->eval_const(des,path)) {
|
||||
rv = new NetEConst(*val);
|
||||
delete val;
|
||||
|
||||
} else if (rv = rval()->elaborate_expr(des, path)) {
|
||||
|
||||
/* OK, go on. */
|
||||
|
||||
} else {
|
||||
/* Unable to elaborate expression. Retreat. */
|
||||
return 0;
|
||||
}
|
||||
|
||||
assert(rv);
|
||||
|
||||
@@ -1342,7 +1066,7 @@ NetProc* PAssign::elaborate(Design*des, const string&path) const
|
||||
return 0;
|
||||
}
|
||||
|
||||
NetNet*tmp = new NetNet(n, NetNet::REG, wid);
|
||||
NetNet*tmp = new NetNet(0, n, NetNet::REG, wid);
|
||||
tmp->set_line(*this);
|
||||
des->add_signal(tmp);
|
||||
|
||||
@@ -1358,7 +1082,6 @@ NetProc* PAssign::elaborate(Design*des, const string&path) const
|
||||
/* Generate an assignment of the temporary to the r-value... */
|
||||
n = des->local_symbol(path);
|
||||
NetESignal*sig = new NetESignal(tmp);
|
||||
des->add_node(sig);
|
||||
NetAssign*a2 = new NetAssign(n, des, wid, sig);
|
||||
a2->set_line(*this);
|
||||
des->add_node(a2);
|
||||
@@ -1473,7 +1196,7 @@ NetProc* PAssignNB::elaborate(Design*des, const string&path) const
|
||||
const PEIdent*id = dynamic_cast<const PEIdent*>(lval());
|
||||
if (id == 0) break;
|
||||
|
||||
if (NetMemory*mem = des->find_memory(path+"."+id->name()))
|
||||
if (NetMemory*mem = des->find_memory(path, id->name()))
|
||||
return assign_to_memory_(mem, id->msb_, des, path);
|
||||
|
||||
} while(0);
|
||||
@@ -1540,7 +1263,9 @@ NetProc* PBlock::elaborate(Design*des, const string&path) const
|
||||
NetBlock*cur = new NetBlock(type);
|
||||
bool fail_flag = false;
|
||||
|
||||
string npath = name_.length()? (path+"."+name_) : path;
|
||||
string npath = name_.length()
|
||||
? des->make_scope(path, NetScope::BEGIN_END, name_) -> name()
|
||||
: path;
|
||||
|
||||
// Handle the special case that the block contains only one
|
||||
// statement. There is no need to keep the block node.
|
||||
@@ -1699,6 +1424,11 @@ NetProc* PCallTask::elaborate(Design*des, const string&path) const
|
||||
/*
|
||||
* A call to a system task involves elaborating all the parameters,
|
||||
* then passing the list to the NetSTask object.
|
||||
*XXXX
|
||||
* There is a single special in the call to a system task. Normally,
|
||||
* an expression cannot take an unindexed memory. However, it is
|
||||
* possible to take a system task parameter a memory if the expression
|
||||
* is trivial.
|
||||
*/
|
||||
NetProc* PCallTask::elaborate_sys(Design*des, const string&path) const
|
||||
{
|
||||
@@ -1706,6 +1436,7 @@ NetProc* PCallTask::elaborate_sys(Design*des, const string&path) const
|
||||
|
||||
for (unsigned idx = 0 ; idx < nparms() ; idx += 1) {
|
||||
PExpr*ex = parm(idx);
|
||||
|
||||
eparms[idx] = ex? ex->elaborate_expr(des, path) : 0;
|
||||
}
|
||||
|
||||
@@ -1836,7 +1567,6 @@ NetProc* PCallTask::elaborate_usr(Design*des, const string&path) const
|
||||
for (unsigned pi = 0 ; pi < val->pin_count() ; pi += 1)
|
||||
connect(val->pin(pi), ass->pin(pi));
|
||||
|
||||
des->add_node(sig);
|
||||
des->add_node(ass);
|
||||
block->append(ass);
|
||||
}
|
||||
@@ -2161,8 +1891,9 @@ NetProc* PWhile::elaborate(Design*des, const string&path) const
|
||||
return loop;
|
||||
}
|
||||
|
||||
bool Module::elaborate(Design*des, const string&path, svector<PExpr*>*overrides_) const
|
||||
bool Module::elaborate(Design*des, NetScope*scope, svector<PExpr*>*overrides_) const
|
||||
{
|
||||
const string path = scope->name();
|
||||
bool result_flag = true;
|
||||
|
||||
// Generate all the parameters that this instance of this
|
||||
@@ -2247,7 +1978,7 @@ bool Module::elaborate(Design*des, const string&path, svector<PExpr*>*overrides_
|
||||
; wt != wl.end()
|
||||
; wt ++ ) {
|
||||
|
||||
(*wt)->elaborate(des, path);
|
||||
(*wt)->elaborate(des, scope);
|
||||
}
|
||||
|
||||
// Elaborate functions.
|
||||
@@ -2341,9 +2072,11 @@ Design* elaborate(const map<string,Module*>&modules,
|
||||
// module and elaborate what I find.
|
||||
Design*des = new Design;
|
||||
|
||||
NetScope*scope = des->make_root_scope(root);
|
||||
|
||||
modlist = &modules;
|
||||
udplist = &primitives;
|
||||
bool rc = rmod->elaborate(des, root, (svector<PExpr*>*)0);
|
||||
bool rc = rmod->elaborate(des, scope, (svector<PExpr*>*)0);
|
||||
modlist = 0;
|
||||
udplist = 0;
|
||||
|
||||
@@ -2357,6 +2090,44 @@ Design* elaborate(const map<string,Module*>&modules,
|
||||
|
||||
/*
|
||||
* $Log: elaborate.cc,v $
|
||||
* Revision 1.132 1999/12/02 04:08:10 steve
|
||||
* Elaborate net repeat concatenations.
|
||||
*
|
||||
* Revision 1.131 1999/11/28 23:42:02 steve
|
||||
* NetESignal object no longer need to be NetNode
|
||||
* objects. Let them keep a pointer to NetNet objects.
|
||||
*
|
||||
* Revision 1.130 1999/11/27 19:07:57 steve
|
||||
* Support the creation of scopes.
|
||||
*
|
||||
* Revision 1.129 1999/11/24 04:01:58 steve
|
||||
* Detect and list scope names.
|
||||
*
|
||||
* Revision 1.128 1999/11/21 20:03:24 steve
|
||||
* Handle multiply in constant expressions.
|
||||
*
|
||||
* Revision 1.127 1999/11/21 17:35:37 steve
|
||||
* Memory name lookup handles scopes.
|
||||
*
|
||||
* Revision 1.126 1999/11/21 01:16:51 steve
|
||||
* Fix coding errors handling names of logic devices,
|
||||
* and add support for buf device in vvm.
|
||||
*
|
||||
* Revision 1.125 1999/11/21 00:13:08 steve
|
||||
* Support memories in continuous assignments.
|
||||
*
|
||||
* Revision 1.124 1999/11/18 03:52:19 steve
|
||||
* Turn NetTmp objects into normal local NetNet objects,
|
||||
* and add the nodangle functor to clean up the local
|
||||
* symbols generated by elaboration and other steps.
|
||||
*
|
||||
* Revision 1.123 1999/11/10 02:52:24 steve
|
||||
* Create the vpiMemory handle type.
|
||||
*
|
||||
* Revision 1.122 1999/11/05 21:45:19 steve
|
||||
* Fix NetConst being set to zero width, and clean
|
||||
* up elaborate_set_cmp_ for NetEBinary.
|
||||
*
|
||||
* Revision 1.121 1999/11/04 03:53:26 steve
|
||||
* Patch to synthesize unary ~ and the ternary operator.
|
||||
* Thanks to Larry Doolittle <[email protected]>.
|
||||
@@ -2434,280 +2205,5 @@ Design* elaborate(const map<string,Module*>&modules,
|
||||
* Allow expanding of additive operators.
|
||||
*
|
||||
* Revision 1.100 1999/09/25 02:57:30 steve
|
||||
* Parse system function calls.
|
||||
*
|
||||
* Revision 1.99 1999/09/23 03:56:57 steve
|
||||
* Support shift operators.
|
||||
*
|
||||
* Revision 1.98 1999/09/23 02:28:27 steve
|
||||
* internal error message for funky comparison width.
|
||||
*
|
||||
* Revision 1.97 1999/09/23 00:21:54 steve
|
||||
* Move set_width methods into a single file,
|
||||
* Add the NetEBLogic class for logic expressions,
|
||||
* Fix error setting with of && in if statements.
|
||||
*
|
||||
* Revision 1.96 1999/09/22 21:25:42 steve
|
||||
* Expand bits in delayed assignments.
|
||||
*
|
||||
* Revision 1.95 1999/09/22 04:30:04 steve
|
||||
* Parse and elaborate named for/join blocks.
|
||||
*
|
||||
* Revision 1.94 1999/09/22 02:00:48 steve
|
||||
* assignment with blocking event delay.
|
||||
*
|
||||
* Revision 1.93 1999/09/20 02:21:10 steve
|
||||
* Elaborate parameters in phases.
|
||||
*
|
||||
* Revision 1.92 1999/09/18 22:23:50 steve
|
||||
* Match bit widths comming out of task output ports.
|
||||
*
|
||||
* Revision 1.91 1999/09/18 02:51:35 steve
|
||||
* report non-constant part select expressions.
|
||||
*
|
||||
* Revision 1.90 1999/09/18 01:53:08 steve
|
||||
* Detect constant lessthen-equal expressions.
|
||||
*
|
||||
* Revision 1.89 1999/09/17 02:06:25 steve
|
||||
* Handle unconnected module ports.
|
||||
*
|
||||
* Revision 1.88 1999/09/16 04:18:15 steve
|
||||
* elaborate concatenation repeats.
|
||||
*
|
||||
* Revision 1.87 1999/09/16 00:33:45 steve
|
||||
* Handle implicit !=0 in if statements.
|
||||
*
|
||||
* Revision 1.86 1999/09/15 04:17:52 steve
|
||||
* separate assign lval elaboration for error checking.
|
||||
*
|
||||
* Revision 1.85 1999/09/15 01:55:06 steve
|
||||
* Elaborate non-blocking assignment to memories.
|
||||
*
|
||||
* Revision 1.84 1999/09/14 01:50:52 steve
|
||||
* implicitly declare wires if needed.
|
||||
*
|
||||
* Revision 1.83 1999/09/13 03:10:59 steve
|
||||
* Clarify msb/lsb in context of netlist. Properly
|
||||
* handle part selects in lval and rval of expressions,
|
||||
* and document where the least significant bit goes
|
||||
* in NetNet objects.
|
||||
*
|
||||
* Revision 1.82 1999/09/12 01:16:51 steve
|
||||
* Pad r-values in certain assignments.
|
||||
*
|
||||
* Revision 1.81 1999/09/10 04:04:06 steve
|
||||
* Add ternary elaboration.
|
||||
*
|
||||
* Revision 1.80 1999/09/08 04:05:30 steve
|
||||
* Allow assign to not match rvalue width.
|
||||
*
|
||||
* Revision 1.79 1999/09/08 02:24:39 steve
|
||||
* Empty conditionals ([email protected])
|
||||
*
|
||||
* Revision 1.78 1999/09/04 19:11:46 steve
|
||||
* Add support for delayed non-blocking assignments.
|
||||
*
|
||||
* Revision 1.77 1999/09/03 04:28:38 steve
|
||||
* elaborate the binary plus operator.
|
||||
*
|
||||
* Revision 1.76 1999/09/02 01:59:27 steve
|
||||
* Parse non-blocking assignment delays.
|
||||
*
|
||||
* Revision 1.75 1999/09/01 20:46:19 steve
|
||||
* Handle recursive functions and arbitrary function
|
||||
* references to other functions, properly pass
|
||||
* function parameters and save function results.
|
||||
*
|
||||
* Revision 1.74 1999/08/31 22:38:29 steve
|
||||
* Elaborate and emit to vvm procedural functions.
|
||||
*
|
||||
* Revision 1.73 1999/08/25 22:22:41 steve
|
||||
* elaborate some aspects of functions.
|
||||
*
|
||||
* Revision 1.72 1999/08/23 16:48:39 steve
|
||||
* Parameter overrides support from Peter Monta
|
||||
* AND and XOR support wide expressions.
|
||||
*
|
||||
* Revision 1.71 1999/08/18 04:00:02 steve
|
||||
* Fixup spelling and some error messages. <[email protected]>
|
||||
*
|
||||
* Revision 1.70 1999/08/08 20:06:06 steve
|
||||
* Uninitialized low and high indices for single gate syntax
|
||||
*
|
||||
* Revision 1.69 1999/08/06 04:05:28 steve
|
||||
* Handle scope of parameters.
|
||||
*
|
||||
* Revision 1.68 1999/08/05 04:58:57 steve
|
||||
* Allow integers as register lvalues.
|
||||
*
|
||||
* Revision 1.67 1999/08/04 02:13:02 steve
|
||||
* Elaborate module ports that are concatenations of
|
||||
* module signals.
|
||||
*
|
||||
* Revision 1.66 1999/08/03 04:14:49 steve
|
||||
* Parse into pform arbitrarily complex module
|
||||
* port declarations.
|
||||
*
|
||||
* Revision 1.65 1999/08/01 21:48:11 steve
|
||||
* set width of procedural r-values when then
|
||||
* l-value is a memory word.
|
||||
*
|
||||
* Revision 1.64 1999/08/01 21:18:55 steve
|
||||
* elaborate rise/fall/decay for continuous assign.
|
||||
*
|
||||
* Revision 1.63 1999/08/01 16:34:50 steve
|
||||
* Parse and elaborate rise/fall/decay times
|
||||
* for gates, and handle the rules for partial
|
||||
* lists of times.
|
||||
*
|
||||
* Revision 1.62 1999/07/31 03:16:54 steve
|
||||
* move binary operators to derived classes.
|
||||
*
|
||||
* Revision 1.61 1999/07/28 03:46:57 steve
|
||||
* Handle no ports at all for tasks.
|
||||
*
|
||||
* Revision 1.60 1999/07/24 19:19:06 steve
|
||||
* Add support for task output and inout ports.
|
||||
*
|
||||
* Revision 1.59 1999/07/24 02:11:20 steve
|
||||
* Elaborate task input ports.
|
||||
*
|
||||
* Revision 1.58 1999/07/18 21:17:50 steve
|
||||
* Add support for CE input to XNF DFF, and do
|
||||
* complete cleanup of replaced design nodes.
|
||||
*
|
||||
* Revision 1.57 1999/07/17 19:50:59 steve
|
||||
* netlist support for ternary operator.
|
||||
*
|
||||
* Revision 1.56 1999/07/17 18:06:02 steve
|
||||
* Better handling of bit width of + operators.
|
||||
*
|
||||
* Revision 1.55 1999/07/17 03:08:31 steve
|
||||
* part select in expressions.
|
||||
*
|
||||
* Revision 1.54 1999/07/13 04:08:26 steve
|
||||
* Construct delayed assignment as an equivalent block.
|
||||
*
|
||||
* Revision 1.53 1999/07/12 00:59:36 steve
|
||||
* procedural blocking assignment delays.
|
||||
*
|
||||
* Revision 1.52 1999/07/10 03:00:05 steve
|
||||
* Proper initialization of registers.
|
||||
*
|
||||
* Revision 1.51 1999/07/10 02:19:26 steve
|
||||
* Support concatenate in l-values.
|
||||
*
|
||||
* Revision 1.50 1999/07/03 02:12:51 steve
|
||||
* Elaborate user defined tasks.
|
||||
*
|
||||
* Revision 1.49 1999/06/24 04:45:29 steve
|
||||
* Elaborate wide structoral bitwise OR.
|
||||
*
|
||||
* Revision 1.48 1999/06/24 04:24:18 steve
|
||||
* Handle expression widths for EEE and NEE operators,
|
||||
* add named blocks and scope handling,
|
||||
* add registers declared in named blocks.
|
||||
*
|
||||
* Revision 1.47 1999/06/19 21:06:16 steve
|
||||
* Elaborate and supprort to vvm the forever
|
||||
* and repeat statements.
|
||||
*
|
||||
* Revision 1.46 1999/06/17 05:34:42 steve
|
||||
* Clean up interface of the PWire class,
|
||||
* Properly match wire ranges.
|
||||
*
|
||||
* Revision 1.45 1999/06/15 05:38:39 steve
|
||||
* Support case expression lists.
|
||||
*
|
||||
* Revision 1.44 1999/06/15 03:44:53 steve
|
||||
* Get rid of the STL vector template.
|
||||
*
|
||||
* Revision 1.43 1999/06/13 23:51:16 steve
|
||||
* l-value part select for procedural assignments.
|
||||
*
|
||||
* Revision 1.42 1999/06/13 16:30:06 steve
|
||||
* Unify the NetAssign constructors a bit.
|
||||
*
|
||||
* Revision 1.41 1999/06/13 04:46:54 steve
|
||||
* Add part select lvalues to AssignNB.
|
||||
*
|
||||
* Revision 1.40 1999/06/12 23:16:37 steve
|
||||
* Handle part selects as l-values to continuous assign.
|
||||
*
|
||||
* Revision 1.39 1999/06/10 04:03:53 steve
|
||||
* Add support for the Ternary operator,
|
||||
* Add support for repeat concatenation,
|
||||
* Correct some seg faults cause by elaboration
|
||||
* errors,
|
||||
* Parse the casex anc casez statements.
|
||||
*
|
||||
* Revision 1.38 1999/06/09 03:00:06 steve
|
||||
* Add support for procedural concatenation expression.
|
||||
*
|
||||
* Revision 1.37 1999/06/09 00:58:06 steve
|
||||
* Support for binary | (Stephen Tell)
|
||||
*
|
||||
* Revision 1.36 1999/06/07 02:23:31 steve
|
||||
* Support non-blocking assignment down to vvm.
|
||||
*
|
||||
* Revision 1.35 1999/06/06 23:07:43 steve
|
||||
* Drop degenerate blocks.
|
||||
*
|
||||
* Revision 1.34 1999/06/06 20:45:38 steve
|
||||
* Add parse and elaboration of non-blocking assignments,
|
||||
* Replace list<PCase::Item*> with an svector version,
|
||||
* Add integer support.
|
||||
*
|
||||
* Revision 1.33 1999/06/03 05:16:25 steve
|
||||
* Compile time evalutation of constant expressions.
|
||||
*
|
||||
* Revision 1.32 1999/06/02 15:38:46 steve
|
||||
* Line information with nets.
|
||||
*
|
||||
* Revision 1.31 1999/05/31 15:45:35 steve
|
||||
* Fix error message.
|
||||
*
|
||||
* Revision 1.30 1999/05/30 01:11:46 steve
|
||||
* Exressions are trees that can duplicate, and not DAGS.
|
||||
*
|
||||
* Revision 1.29 1999/05/29 02:36:17 steve
|
||||
* module parameter bind by name.
|
||||
*
|
||||
* Revision 1.28 1999/05/27 04:13:08 steve
|
||||
* Handle expression bit widths with non-fatal errors.
|
||||
*
|
||||
* Revision 1.27 1999/05/20 04:31:45 steve
|
||||
* Much expression parsing work,
|
||||
* mark continuous assigns with source line info,
|
||||
* replace some assertion failures with Sorry messages.
|
||||
*
|
||||
* Revision 1.26 1999/05/16 05:08:42 steve
|
||||
* Redo constant expression detection to happen
|
||||
* after parsing.
|
||||
*
|
||||
* Parse more operators and expressions.
|
||||
*
|
||||
* Revision 1.25 1999/05/10 00:16:58 steve
|
||||
* Parse and elaborate the concatenate operator
|
||||
* in structural contexts, Replace vector<PExpr*>
|
||||
* and list<PExpr*> with svector<PExpr*>, evaluate
|
||||
* constant expressions with parameters, handle
|
||||
* memories as lvalues.
|
||||
*
|
||||
* Parse task declarations, integer types.
|
||||
*
|
||||
* Revision 1.24 1999/05/05 03:04:46 steve
|
||||
* Fix handling of null delay statements.
|
||||
*
|
||||
* Revision 1.23 1999/05/01 20:43:55 steve
|
||||
* Handle wide events, such as @(a) where a has
|
||||
* many bits in it.
|
||||
*
|
||||
* Add to vvm the binary ^ and unary & operators.
|
||||
*
|
||||
* Dump events a bit more completely.
|
||||
*
|
||||
* Revision 1.22 1999/05/01 02:57:53 steve
|
||||
* Handle much more complex event expressions.
|
||||
*/
|
||||
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
|
||||
*/
|
||||
#if !defined(WINNT)
|
||||
#ident "$Id: emit.cc,v 1.26 1999/11/04 03:53:26 steve Exp $"
|
||||
#ident "$Id: emit.cc,v 1.31 1999/11/28 23:42:02 steve Exp $"
|
||||
#endif
|
||||
|
||||
/*
|
||||
@@ -65,6 +65,16 @@ void NetCaseCmp::emit_node(ostream&o, struct target_t*tgt) const
|
||||
tgt->net_case_cmp(o, this);
|
||||
}
|
||||
|
||||
void NetCLShift::emit_node(ostream&o, struct target_t*tgt) const
|
||||
{
|
||||
tgt->lpm_clshift(o, this);
|
||||
}
|
||||
|
||||
void NetCompare::emit_node(ostream&o, struct target_t*tgt) const
|
||||
{
|
||||
tgt->lpm_compare(o, this);
|
||||
}
|
||||
|
||||
void NetConst::emit_node(ostream&o, struct target_t*tgt) const
|
||||
{
|
||||
tgt->net_const(o, this);
|
||||
@@ -80,6 +90,11 @@ void NetMux::emit_node(ostream&o, struct target_t*tgt) const
|
||||
tgt->lpm_mux(o, this);
|
||||
}
|
||||
|
||||
void NetRamDq::emit_node(ostream&o, struct target_t*tgt) const
|
||||
{
|
||||
tgt->lpm_ram_dq(o, this);
|
||||
}
|
||||
|
||||
void NetNEvent::emit_node(ostream&o, struct target_t*tgt) const
|
||||
{
|
||||
tgt->net_event(o, this);
|
||||
@@ -240,6 +255,13 @@ bool Design::emit(ostream&o, struct target_t*tgt) const
|
||||
bool rc = true;
|
||||
tgt->start_design(o, this);
|
||||
|
||||
// enumerate the scopes
|
||||
{ map<string,NetScope*>::const_iterator sc;
|
||||
for (sc = scopes_.begin() ; sc != scopes_.end() ; sc++) {
|
||||
tgt->scope(o, (*sc).second);
|
||||
}
|
||||
}
|
||||
|
||||
// emit signals
|
||||
if (signals_) {
|
||||
NetNet*cur = signals_->sig_next_;
|
||||
@@ -324,6 +346,11 @@ void NetEParam::expr_scan(struct expr_scan_t*tgt) const
|
||||
<< endl;
|
||||
}
|
||||
|
||||
void NetEScope::expr_scan(struct expr_scan_t*tgt) const
|
||||
{
|
||||
tgt->expr_scope(this);
|
||||
}
|
||||
|
||||
void NetEUFunc::expr_scan(struct expr_scan_t*tgt) const
|
||||
{
|
||||
tgt->expr_ufunc(this);
|
||||
@@ -334,11 +361,6 @@ void NetESignal::expr_scan(struct expr_scan_t*tgt) const
|
||||
tgt->expr_signal(this);
|
||||
}
|
||||
|
||||
void NetESignal::emit_node(ostream&o, struct target_t*tgt) const
|
||||
{
|
||||
tgt->net_esignal(o, this);
|
||||
}
|
||||
|
||||
void NetESubSignal::expr_scan(struct expr_scan_t*tgt) const
|
||||
{
|
||||
tgt->expr_subsignal(this);
|
||||
@@ -367,6 +389,22 @@ bool emit(ostream&o, const Design*des, const char*type)
|
||||
|
||||
/*
|
||||
* $Log: emit.cc,v $
|
||||
* Revision 1.31 1999/11/28 23:42:02 steve
|
||||
* NetESignal object no longer need to be NetNode
|
||||
* objects. Let them keep a pointer to NetNet objects.
|
||||
*
|
||||
* Revision 1.30 1999/11/27 19:07:57 steve
|
||||
* Support the creation of scopes.
|
||||
*
|
||||
* Revision 1.29 1999/11/21 00:13:08 steve
|
||||
* Support memories in continuous assignments.
|
||||
*
|
||||
* Revision 1.28 1999/11/14 23:43:45 steve
|
||||
* Support combinatorial comparators.
|
||||
*
|
||||
* Revision 1.27 1999/11/14 20:24:28 steve
|
||||
* Add support for the LPM_CLSHIFT device.
|
||||
*
|
||||
* Revision 1.26 1999/11/04 03:53:26 steve
|
||||
* Patch to synthesize unary ~ and the ternary operator.
|
||||
* Thanks to Larry Doolittle <[email protected]>.
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
|
||||
*/
|
||||
#if !defined(WINNT)
|
||||
#ident "$Id: eval.cc,v 1.9 1999/10/08 17:48:09 steve Exp $"
|
||||
#ident "$Id: eval.cc,v 1.12 1999/11/30 04:48:17 steve Exp $"
|
||||
#endif
|
||||
|
||||
# include "PExpr.h"
|
||||
@@ -42,17 +42,45 @@ verinum* PEBinary::eval_const(const Design*des, const string&path) const
|
||||
|
||||
switch (op_) {
|
||||
case '+': {
|
||||
assert(l->is_defined());
|
||||
assert(r->is_defined());
|
||||
long lv = l->as_long();
|
||||
long rv = r->as_long();
|
||||
res = new verinum(lv+rv, l->len());
|
||||
break;
|
||||
}
|
||||
case '-': {
|
||||
assert(l->is_defined());
|
||||
assert(r->is_defined());
|
||||
long lv = l->as_long();
|
||||
long rv = r->as_long();
|
||||
res = new verinum(lv-rv, l->len());
|
||||
break;
|
||||
}
|
||||
case '*': {
|
||||
assert(l->is_defined());
|
||||
assert(r->is_defined());
|
||||
long lv = l->as_long();
|
||||
long rv = r->as_long();
|
||||
res = new verinum(lv * rv, l->len());
|
||||
break;
|
||||
}
|
||||
case '/': {
|
||||
assert(l->is_defined());
|
||||
assert(r->is_defined());
|
||||
long lv = l->as_long();
|
||||
long rv = r->as_long();
|
||||
res = new verinum(lv / rv, l->len());
|
||||
break;
|
||||
}
|
||||
case '%': {
|
||||
assert(l->is_defined());
|
||||
assert(r->is_defined());
|
||||
long lv = l->as_long();
|
||||
long rv = r->as_long();
|
||||
res = new verinum(lv % rv, l->len());
|
||||
break;
|
||||
}
|
||||
default:
|
||||
delete l;
|
||||
delete r;
|
||||
@@ -68,12 +96,13 @@ verinum* PEBinary::eval_const(const Design*des, const string&path) const
|
||||
*/
|
||||
verinum* PEIdent::eval_const(const Design*des, const string&path) const
|
||||
{
|
||||
assert(msb_ == 0);
|
||||
const NetExpr*expr = des->find_parameter(path, text_);
|
||||
|
||||
if (expr == 0)
|
||||
return 0;
|
||||
|
||||
assert(msb_ == 0);
|
||||
|
||||
if (dynamic_cast<const NetEParam*>(expr)) {
|
||||
cerr << get_line() << ": sorry: I cannot evaluate ``" <<
|
||||
text_ << "'' in this context." << endl;
|
||||
@@ -90,14 +119,39 @@ verinum* PENumber::eval_const(const Design*, const string&) const
|
||||
return new verinum(value());
|
||||
}
|
||||
|
||||
verinum* PETernary::eval_const(const Design*, const string&) const
|
||||
verinum* PETernary::eval_const(const Design*des, const string&path) const
|
||||
{
|
||||
assert(0);
|
||||
verinum*test = expr_->eval_const(des, path);
|
||||
if (test == 0)
|
||||
return 0;
|
||||
|
||||
verinum::V bit = test->get(0);
|
||||
delete test;
|
||||
switch (bit) {
|
||||
case verinum::V0:
|
||||
return fal_->eval_const(des, path);
|
||||
case verinum::V1:
|
||||
return tru_->eval_const(des, path);
|
||||
default:
|
||||
return 0;
|
||||
// XXXX It is possible to handle this case if both fal_
|
||||
// and tru_ are constant. Someday...
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* $Log: eval.cc,v $
|
||||
* Revision 1.12 1999/11/30 04:48:17 steve
|
||||
* Handle evaluation of ternary during elaboration.
|
||||
*
|
||||
* Revision 1.11 1999/11/28 23:42:02 steve
|
||||
* NetESignal object no longer need to be NetNode
|
||||
* objects. Let them keep a pointer to NetNet objects.
|
||||
*
|
||||
* Revision 1.10 1999/11/21 20:03:24 steve
|
||||
* Handle multiply in constant expressions.
|
||||
*
|
||||
* Revision 1.9 1999/10/08 17:48:09 steve
|
||||
* Support + in constant expressions.
|
||||
*
|
||||
|
||||
+78
-9
@@ -17,7 +17,7 @@
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
|
||||
*/
|
||||
#if !defined(WINNT)
|
||||
#ident "$Id: expr_synth.cc,v 1.2 1999/11/04 03:53:26 steve Exp $"
|
||||
#ident "$Id: expr_synth.cc,v 1.6 1999/11/28 23:42:02 steve Exp $"
|
||||
#endif
|
||||
|
||||
# include "netlist.h"
|
||||
@@ -31,6 +31,44 @@ NetNet* NetExpr::synthesize(Design*des)
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Make an LPM_ADD_SUB device from addition operators.
|
||||
*/
|
||||
NetNet* NetEBAdd::synthesize(Design*des)
|
||||
{
|
||||
assert((op()=='+') || (op()=='-'));
|
||||
|
||||
string path = des->local_symbol("SYNTH");
|
||||
NetNet*lsig = left_->synthesize(des);
|
||||
NetNet*rsig = right_->synthesize(des);
|
||||
|
||||
assert(lsig->pin_count() == rsig->pin_count());
|
||||
unsigned width=lsig->pin_count();
|
||||
|
||||
NetNet*osig = new NetNet(0, path, NetNet::IMPLICIT, width);
|
||||
|
||||
string oname = des->local_symbol(path);
|
||||
NetAddSub *adder = new NetAddSub(oname, width);
|
||||
for (unsigned idx = 0 ; idx < width; idx += 1) {
|
||||
connect(lsig->pin(idx), adder->pin_DataA(idx));
|
||||
connect(rsig->pin(idx), adder->pin_DataB(idx));
|
||||
connect(osig->pin(idx), adder->pin_Result(idx));
|
||||
}
|
||||
des->add_node(adder);
|
||||
des->add_signal(osig);
|
||||
|
||||
switch (op()) {
|
||||
case '+':
|
||||
adder->attribute("LPM_Direction", "ADD");
|
||||
break;
|
||||
case '-':
|
||||
adder->attribute("LPM_Direction", "SUB");
|
||||
break;
|
||||
}
|
||||
|
||||
return osig;
|
||||
}
|
||||
|
||||
/*
|
||||
* The bitwise logic operators are turned into discrete gates pretty
|
||||
* easily. Synthesize the left and right sub-expressions to get
|
||||
@@ -44,7 +82,7 @@ NetNet* NetEBBits::synthesize(Design*des)
|
||||
NetNet*rsig = right_->synthesize(des);
|
||||
|
||||
assert(lsig->pin_count() == rsig->pin_count());
|
||||
NetNet*osig = new NetNet(path, NetNet::IMPLICIT, lsig->pin_count());
|
||||
NetNet*osig = new NetNet(0, path, NetNet::IMPLICIT, lsig->pin_count());
|
||||
|
||||
for (unsigned idx = 0 ; idx < osig->pin_count() ; idx += 1) {
|
||||
string oname = des->local_symbol(path);
|
||||
@@ -81,6 +119,22 @@ NetNet* NetEBBits::synthesize(Design*des)
|
||||
return osig;
|
||||
}
|
||||
|
||||
NetNet* NetEConst::synthesize(Design*des)
|
||||
{
|
||||
string path = des->local_symbol("SYNTH");
|
||||
unsigned width=expr_width();
|
||||
|
||||
NetNet*osig = new NetNet(0, path, NetNet::IMPLICIT, width);
|
||||
for (unsigned idx = 0 ; idx < width; idx += 1) {
|
||||
string oname = des->local_symbol(path);
|
||||
NetConst *c = new NetConst(oname, value().get(idx));
|
||||
connect(osig->pin(idx), c->pin(0));
|
||||
des->add_node(c);
|
||||
}
|
||||
des->add_signal(osig);
|
||||
return osig;
|
||||
}
|
||||
|
||||
/*
|
||||
* The bitwise unary logic operator (there is only one) is turned
|
||||
* into discrete gates just as easily as the binary ones above.
|
||||
@@ -90,7 +144,7 @@ NetNet* NetEUBits::synthesize(Design*des)
|
||||
string path = des->local_symbol("SYNTH");
|
||||
NetNet*isig = expr_->synthesize(des);
|
||||
|
||||
NetNet*osig = new NetNet(path, NetNet::IMPLICIT, isig->pin_count());
|
||||
NetNet*osig = new NetNet(0, path, NetNet::IMPLICIT, isig->pin_count());
|
||||
|
||||
for (unsigned idx = 0 ; idx < osig->pin_count() ; idx += 1) {
|
||||
string oname = des->local_symbol(path);
|
||||
@@ -124,7 +178,7 @@ NetNet* NetETernary::synthesize(Design *des)
|
||||
assert(csig->pin_count() == 1);
|
||||
assert(tsig->pin_count() == fsig->pin_count());
|
||||
unsigned width=tsig->pin_count();
|
||||
NetNet*osig = new NetNet(path, NetNet::IMPLICIT, width);
|
||||
NetNet*osig = new NetNet(0, path, NetNet::IMPLICIT, width);
|
||||
|
||||
string oname = des->local_symbol(path);
|
||||
NetMux *mux = new NetMux(oname, width, 2, 1);
|
||||
@@ -141,15 +195,30 @@ NetNet* NetETernary::synthesize(Design *des)
|
||||
|
||||
NetNet* NetESignal::synthesize(Design*des)
|
||||
{
|
||||
NetNet*sig = new NetNet(name(), NetNet::WIRE, pin_count());
|
||||
for (unsigned idx = 0 ; idx < pin_count() ; idx += 1)
|
||||
connect(sig->pin(idx), pin(idx));
|
||||
des->add_signal(sig);
|
||||
return sig;
|
||||
return net_;
|
||||
}
|
||||
|
||||
/*
|
||||
* $Log: expr_synth.cc,v $
|
||||
* Revision 1.6 1999/11/28 23:42:02 steve
|
||||
* NetESignal object no longer need to be NetNode
|
||||
* objects. Let them keep a pointer to NetNet objects.
|
||||
*
|
||||
* Revision 1.5 1999/11/27 19:07:57 steve
|
||||
* Support the creation of scopes.
|
||||
*
|
||||
* Revision 1.4 1999/11/19 03:00:59 steve
|
||||
* Whoops, created a signal with a duplicate name.
|
||||
*
|
||||
* Revision 1.3 1999/11/05 04:40:40 steve
|
||||
* Patch to synthesize LPM_ADD_SUB from expressions,
|
||||
* Thanks to Larry Doolittle. Also handle constants
|
||||
* in expressions.
|
||||
*
|
||||
* Synthesize adders in XNF, based on a patch from
|
||||
* Larry. Accept synthesis of constants from Larry
|
||||
* as is.
|
||||
*
|
||||
* Revision 1.2 1999/11/04 03:53:26 steve
|
||||
* Patch to synthesize unary ~ and the ternary operator.
|
||||
* Thanks to Larry Doolittle <[email protected]>.
|
||||
|
||||
+50
-2
@@ -17,7 +17,7 @@
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
|
||||
*/
|
||||
#if !defined(WINNT)
|
||||
#ident "$Id: functor.cc,v 1.3 1999/11/01 02:07:40 steve Exp $"
|
||||
#ident "$Id: functor.cc,v 1.5 1999/12/01 06:06:16 steve Exp $"
|
||||
#endif
|
||||
|
||||
# include "functor.h"
|
||||
@@ -45,8 +45,9 @@ void Design::functor(functor_t*fun)
|
||||
if (signals_) {
|
||||
NetNet*cur = signals_->sig_next_;
|
||||
do {
|
||||
NetNet*tmp = cur->sig_next_;
|
||||
fun->signal(this, cur);
|
||||
cur = cur->sig_next_;
|
||||
cur = tmp;
|
||||
} while (cur != signals_->sig_next_);
|
||||
}
|
||||
|
||||
@@ -79,8 +80,55 @@ void NetFF::functor_node(Design*des, functor_t*fun)
|
||||
fun->lpm_ff(des, this);
|
||||
}
|
||||
|
||||
proc_match_t::~proc_match_t()
|
||||
{
|
||||
}
|
||||
|
||||
int NetProc::match_proc(proc_match_t*that)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
int proc_match_t::assign(NetAssign*)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
int NetAssign::match_proc(proc_match_t*that)
|
||||
{
|
||||
return that->assign(this);
|
||||
}
|
||||
|
||||
int proc_match_t::condit(NetCondit*)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
int NetCondit::match_proc(proc_match_t*that)
|
||||
{
|
||||
return that->condit(this);
|
||||
}
|
||||
|
||||
int proc_match_t::pevent(NetPEvent*)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
int NetPEvent::match_proc(proc_match_t*that)
|
||||
{
|
||||
return that->pevent(this);
|
||||
}
|
||||
|
||||
/*
|
||||
* $Log: functor.cc,v $
|
||||
* Revision 1.5 1999/12/01 06:06:16 steve
|
||||
* Redo synth to use match_proc_t scanner.
|
||||
*
|
||||
* Revision 1.4 1999/11/18 03:52:19 steve
|
||||
* Turn NetTmp objects into normal local NetNet objects,
|
||||
* and add the nodangle functor to clean up the local
|
||||
* symbols generated by elaboration and other steps.
|
||||
*
|
||||
* Revision 1.3 1999/11/01 02:07:40 steve
|
||||
* Add the synth functor to do generic synthesis
|
||||
* and add the LPM_FF device to handle rows of
|
||||
|
||||
@@ -19,7 +19,7 @@
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
|
||||
*/
|
||||
#if !defined(WINNT)
|
||||
#ident "$Id: functor.h,v 1.2 1999/11/01 02:07:40 steve Exp $"
|
||||
#ident "$Id: functor.h,v 1.3 1999/12/01 06:06:16 steve Exp $"
|
||||
#endif
|
||||
|
||||
/*
|
||||
@@ -46,8 +46,20 @@ struct functor_t {
|
||||
virtual void lpm_ff(class Design*des, class NetFF*);
|
||||
};
|
||||
|
||||
struct proc_match_t {
|
||||
virtual ~proc_match_t();
|
||||
|
||||
virtual int assign(class NetAssign*);
|
||||
virtual int condit(class NetCondit*);
|
||||
virtual int pevent(class NetPEvent*);
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
* $Log: functor.h,v $
|
||||
* Revision 1.3 1999/12/01 06:06:16 steve
|
||||
* Redo synth to use match_proc_t scanner.
|
||||
*
|
||||
* Revision 1.2 1999/11/01 02:07:40 steve
|
||||
* Add the synth functor to do generic synthesis
|
||||
* and add the LPM_FF device to handle rows of
|
||||
|
||||
+5
-4
@@ -18,7 +18,7 @@
|
||||
# 59 Temple Place - Suite 330
|
||||
# Boston, MA 02111-1307, USA
|
||||
#
|
||||
#ident "$Id: Makefile.in,v 1.6 1999/10/16 20:48:15 steve Exp $"
|
||||
#ident "$Id: Makefile.in,v 1.6.2.1 1999/12/03 17:43:49 steve Exp $"
|
||||
#
|
||||
#
|
||||
SHELL = /bin/sh
|
||||
@@ -33,6 +33,7 @@ VPATH = $(srcdir)
|
||||
|
||||
bindir = $(exec_prefix)/bin
|
||||
libdir = $(exec_prefix)/lib
|
||||
libexecdir = $(libdir)/ivl
|
||||
includedir = $(prefix)/include
|
||||
|
||||
CC = @CC@
|
||||
@@ -60,10 +61,10 @@ lexor.c: lexor.lex
|
||||
parse.h parse.c: parse.y
|
||||
bison --verbose -t -d parse.y -o parse.c
|
||||
|
||||
install: all installdirs $(bindir)/ivlpp
|
||||
install: all installdirs $(libexecdir)/ivlpp
|
||||
|
||||
$(bindir)/ivlpp: ivlpp
|
||||
$(INSTALL_PROGRAM) ./ivlpp $(bindir)/ivlpp
|
||||
$(libexecdir)/ivlpp: ivlpp
|
||||
$(INSTALL_PROGRAM) ./ivlpp $(libexecdir)/ivlpp
|
||||
|
||||
installdirs: ../mkinstalldirs
|
||||
$(srcdir)/../mkinstalldirs $(bindir)
|
||||
|
||||
+7
-1
@@ -17,7 +17,7 @@ const char COPYRIGHT[] =
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
|
||||
*/
|
||||
#if !defined(WINNT)
|
||||
#ident "$Id: main.c,v 1.3 1999/09/05 22:33:18 steve Exp $"
|
||||
#ident "$Id: main.c,v 1.4 1999/11/29 17:02:21 steve Exp $"
|
||||
#endif
|
||||
|
||||
const char NOTICE[] =
|
||||
@@ -42,6 +42,9 @@ const char VERSION[] = "$Name: $ $State: Exp $";
|
||||
# include <malloc.h>
|
||||
# include <unistd.h>
|
||||
# include <string.h>
|
||||
#if defined(HAVE_GETOPT_H)
|
||||
# include <getopt.h>
|
||||
#endif
|
||||
# include "globals.h"
|
||||
|
||||
char**include_dir = 0;
|
||||
@@ -140,6 +143,9 @@ int main(int argc, char*argv[])
|
||||
|
||||
/*
|
||||
* $Log: main.c,v $
|
||||
* Revision 1.4 1999/11/29 17:02:21 steve
|
||||
* include getopt if present.
|
||||
*
|
||||
* Revision 1.3 1999/09/05 22:33:18 steve
|
||||
* Take multiple source files on the command line.
|
||||
*
|
||||
|
||||
@@ -19,7 +19,7 @@
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
|
||||
*/
|
||||
#if !defined(WINNT)
|
||||
#ident "$Id: lexor.lex,v 1.36 1999/09/30 04:51:14 steve Exp $"
|
||||
#ident "$Id: lexor.lex,v 1.38 1999/11/23 02:49:04 steve Exp $"
|
||||
#endif
|
||||
|
||||
//# define YYSTYPE lexval
|
||||
@@ -40,6 +40,7 @@ extern YYLTYPE yylloc;
|
||||
|
||||
static void reset_lexor();
|
||||
static void line_directive();
|
||||
static void line_directive2();
|
||||
|
||||
extern int check_identifier(const char*str, int len);
|
||||
static verinum*make_sized_binary(const char*txt);
|
||||
@@ -66,6 +67,7 @@ W [ \t\b\f\r]+
|
||||
%%
|
||||
|
||||
^"#line"[ ]+\"[^\"]*\"[ ]+[0-9]+.* { line_directive(); }
|
||||
^"`line"[ ]+[0-9]+[ ]+\"[^\"]*\".* { line_directive2(); }
|
||||
|
||||
[ \t\b\f\r] { ; }
|
||||
\n { yylloc.first_line += 1; }
|
||||
@@ -157,7 +159,7 @@ W [ \t\b\f\r]+
|
||||
yylval.text = strdup(cp);
|
||||
return PORTNAME; }
|
||||
|
||||
[0-9][0-9_]*[ \t]*\'d[ \t]*[0-9][0-9_]* {
|
||||
[0-9][0-9_]*[ \t]*\'[dD][ \t]*[0-9][0-9_]* {
|
||||
yylval.number = make_sized_dec(yytext);
|
||||
return NUMBER; }
|
||||
[0-9][0-9_]*[ \t]*\'[bB][ \t]*[0-1xzXZ_\?]+ {
|
||||
@@ -778,6 +780,31 @@ static void line_directive()
|
||||
yylloc.first_line = strtoul(qt2,0,0);
|
||||
}
|
||||
|
||||
static void line_directive2()
|
||||
{
|
||||
assert(strncmp(yytext,"`line",5) == 0);
|
||||
char*cp = yytext + strlen("`line");
|
||||
cp += strspn(cp, " ");
|
||||
yylloc.first_line = strtoul(cp,&cp,10);
|
||||
|
||||
cp += strspn(cp, " ");
|
||||
if (*cp == 0) return;
|
||||
|
||||
char*qt1 = strchr(yytext, '"');
|
||||
assert(qt1);
|
||||
qt1 += 1;
|
||||
|
||||
char*qt2 = strchr(qt1, '"');
|
||||
assert(qt2);
|
||||
|
||||
char*buf = new char[qt2-qt1+1];
|
||||
strncpy(buf, qt1, qt2-qt1);
|
||||
buf[qt2-qt1] = 0;
|
||||
|
||||
delete[]yylloc.text;
|
||||
yylloc.text = buf;
|
||||
}
|
||||
|
||||
static void reset_lexor()
|
||||
{
|
||||
yyrestart(vl_input);
|
||||
|
||||
@@ -19,7 +19,7 @@ const char COPYRIGHT[] =
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
|
||||
*/
|
||||
#if !defined(WINNT)
|
||||
#ident "$Id: main.cc,v 1.24 1999/11/01 02:07:40 steve Exp $"
|
||||
#ident "$Id: main.cc,v 1.26 1999/11/29 17:02:21 steve Exp $"
|
||||
#endif
|
||||
|
||||
const char NOTICE[] =
|
||||
@@ -44,6 +44,9 @@ const char NOTICE[] =
|
||||
# include <queue>
|
||||
# include <map>
|
||||
# include <unistd.h>
|
||||
#if defined(HAVE_GETOPT_H)
|
||||
# include <getopt.h>
|
||||
#endif
|
||||
# include "pform.h"
|
||||
# include "netlist.h"
|
||||
# include "target.h"
|
||||
@@ -81,6 +84,7 @@ extern void propinit(Design*des);
|
||||
extern void sigfold(Design*des);
|
||||
extern void synth(Design*des);
|
||||
extern void nobufz(Design*des);
|
||||
extern void nodangle(Design*des);
|
||||
extern void xnfio(Design*des);
|
||||
extern void xnfsyn(Design*des);
|
||||
|
||||
@@ -91,7 +95,8 @@ static struct net_func_map {
|
||||
} func_table[] = {
|
||||
{ "cprop", &cprop },
|
||||
{ "nobufz", &nobufz },
|
||||
{ "propinit", &propinit },
|
||||
{ "nodangle",&nodangle },
|
||||
{ "propinit",&propinit },
|
||||
{ "sigfold", &sigfold },
|
||||
{ "synth", &synth },
|
||||
{ "xnfio", &xnfio },
|
||||
@@ -279,6 +284,14 @@ int main(int argc, char*argv[])
|
||||
|
||||
/*
|
||||
* $Log: main.cc,v $
|
||||
* Revision 1.26 1999/11/29 17:02:21 steve
|
||||
* include getopt if present.
|
||||
*
|
||||
* Revision 1.25 1999/11/18 03:52:19 steve
|
||||
* Turn NetTmp objects into normal local NetNet objects,
|
||||
* and add the nodangle functor to clean up the local
|
||||
* symbols generated by elaboration and other steps.
|
||||
*
|
||||
* Revision 1.24 1999/11/01 02:07:40 steve
|
||||
* Add the synth functor to do generic synthesis
|
||||
* and add the LPM_FF device to handle rows of
|
||||
|
||||
+639
-105
@@ -17,7 +17,7 @@
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
|
||||
*/
|
||||
#if !defined(WINNT)
|
||||
#ident "$Id: netlist.cc,v 1.82 1999/11/04 03:53:26 steve Exp $"
|
||||
#ident "$Id: netlist.cc,v 1.97 1999/12/02 16:58:58 steve Exp $"
|
||||
#endif
|
||||
|
||||
# include <cassert>
|
||||
@@ -77,9 +77,20 @@ ostream& operator<< (ostream&o, NetNet::Type t)
|
||||
|
||||
void connect(NetObj::Link&l, NetObj::Link&r)
|
||||
{
|
||||
assert(&l != &r);
|
||||
assert(l.next_->prev_ == &l);
|
||||
assert(l.prev_->next_ == &l);
|
||||
assert(r.next_->prev_ == &r);
|
||||
assert(r.prev_->next_ == &r);
|
||||
|
||||
NetObj::Link* cur = &l;
|
||||
do {
|
||||
NetObj::Link*tmp = cur->next_;
|
||||
|
||||
// If I stumble on r in the nexus, then stop now because
|
||||
// we are already connected.
|
||||
if (tmp == &r) break;
|
||||
|
||||
// Pull cur out of left list...
|
||||
cur->prev_->next_ = cur->next_;
|
||||
cur->next_->prev_ = cur->prev_;
|
||||
@@ -93,6 +104,11 @@ void connect(NetObj::Link&l, NetObj::Link&r)
|
||||
// Go to the next item in the left list.
|
||||
cur = tmp;
|
||||
} while (cur != &l);
|
||||
|
||||
assert(l.next_->prev_ == &l);
|
||||
assert(l.prev_->next_ == &l);
|
||||
assert(r.next_->prev_ == &r);
|
||||
assert(r.prev_->next_ == &r);
|
||||
}
|
||||
|
||||
NetObj::Link::Link()
|
||||
@@ -135,6 +151,36 @@ bool NetObj::Link::is_linked(const NetObj::Link&that) const
|
||||
return false;
|
||||
}
|
||||
|
||||
void NetObj::Link::next_link(NetObj*&net, unsigned&pin)
|
||||
{
|
||||
assert(next_->prev_ == this);
|
||||
assert(prev_->next_ == this);
|
||||
net = next_->node_;
|
||||
pin = next_->pin_;
|
||||
}
|
||||
|
||||
void NetObj::Link::next_link(const NetObj*&net, unsigned&pin) const
|
||||
{
|
||||
assert(next_->prev_ == this);
|
||||
assert(prev_->next_ == this);
|
||||
net = next_->node_;
|
||||
pin = next_->pin_;
|
||||
}
|
||||
|
||||
NetObj::Link* NetObj::Link::next_link()
|
||||
{
|
||||
assert(next_->prev_ == this);
|
||||
assert(prev_->next_ == this);
|
||||
return next_;
|
||||
}
|
||||
|
||||
const NetObj::Link* NetObj::Link::next_link() const
|
||||
{
|
||||
assert(next_->prev_ == this);
|
||||
assert(prev_->next_ == this);
|
||||
return next_;
|
||||
}
|
||||
|
||||
const NetObj*NetObj::Link::get_obj() const
|
||||
{
|
||||
return node_;
|
||||
@@ -242,6 +288,16 @@ const NetNet* find_link_signal(const NetObj*net, unsigned pin, unsigned&bidx)
|
||||
return 0;
|
||||
}
|
||||
|
||||
NetObj::Link* find_next_output(NetObj::Link*lnk)
|
||||
{
|
||||
for (NetObj::Link*cur = lnk->next_link()
|
||||
; cur != lnk ; cur = cur->next_link())
|
||||
if (cur->get_dir() == NetObj::Link::OUTPUT)
|
||||
return cur;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
NetObj::NetObj(const string&n, unsigned np)
|
||||
: name_(n), npins_(np), delay1_(0), delay2_(0), delay3_(0), mark_(false)
|
||||
{
|
||||
@@ -312,32 +368,48 @@ NetNode::~NetNode()
|
||||
design_->del_node(this);
|
||||
}
|
||||
|
||||
NetNet::NetNet(const string&n, Type t, unsigned npins)
|
||||
: NetObj(n, npins), sig_next_(0), sig_prev_(0), design_(0),
|
||||
NetNet::NetNet(NetScope*s, const string&n, Type t, unsigned npins)
|
||||
: NetObj(n, npins), sig_next_(0), sig_prev_(0), design_(0), scope_(s),
|
||||
type_(t), port_type_(NOT_A_PORT), msb_(npins-1), lsb_(0),
|
||||
local_flag_(false)
|
||||
local_flag_(false), eref_count_(0)
|
||||
{
|
||||
ivalue_ = new verinum::V[npins];
|
||||
for (unsigned idx = 0 ; idx < npins ; idx += 1)
|
||||
for (unsigned idx = 0 ; idx < npins ; idx += 1) {
|
||||
pin(idx).set_name("P", idx);
|
||||
ivalue_[idx] = verinum::Vz;
|
||||
}
|
||||
}
|
||||
|
||||
NetNet::NetNet(const string&n, Type t, long ms, long ls)
|
||||
NetNet::NetNet(NetScope*s, const string&n, Type t, long ms, long ls)
|
||||
: NetObj(n, ((ms>ls)?ms-ls:ls-ms) + 1), sig_next_(0),
|
||||
sig_prev_(0), design_(0), type_(t), port_type_(NOT_A_PORT),
|
||||
msb_(ms), lsb_(ls), local_flag_(false)
|
||||
sig_prev_(0), design_(0), scope_(s), type_(t),
|
||||
port_type_(NOT_A_PORT), msb_(ms), lsb_(ls), local_flag_(false),
|
||||
eref_count_(0)
|
||||
{
|
||||
ivalue_ = new verinum::V[pin_count()];
|
||||
for (unsigned idx = 0 ; idx < pin_count() ; idx += 1)
|
||||
for (unsigned idx = 0 ; idx < pin_count() ; idx += 1) {
|
||||
pin(idx).set_name("P", idx);
|
||||
ivalue_[idx] = verinum::Vz;
|
||||
}
|
||||
}
|
||||
|
||||
NetNet::~NetNet()
|
||||
{
|
||||
assert(eref_count_ == 0);
|
||||
if (design_)
|
||||
design_->del_signal(this);
|
||||
}
|
||||
|
||||
NetScope* NetNet::scope()
|
||||
{
|
||||
return scope_;
|
||||
}
|
||||
|
||||
const NetScope* NetNet::scope() const
|
||||
{
|
||||
return scope_;
|
||||
}
|
||||
|
||||
unsigned NetNet::sb_to_idx(long sb) const
|
||||
{
|
||||
if (msb_ >= lsb_)
|
||||
@@ -346,6 +418,28 @@ unsigned NetNet::sb_to_idx(long sb) const
|
||||
return lsb_ - sb;
|
||||
}
|
||||
|
||||
void NetNet::incr_eref()
|
||||
{
|
||||
eref_count_ += 1;
|
||||
}
|
||||
|
||||
void NetNet::decr_eref()
|
||||
{
|
||||
assert(eref_count_ > 0);
|
||||
eref_count_ -= 1;
|
||||
}
|
||||
|
||||
unsigned NetNet::get_eref() const
|
||||
{
|
||||
return eref_count_;
|
||||
}
|
||||
|
||||
NetTmp::NetTmp(const string&name, unsigned npins)
|
||||
: NetNet(0, name, IMPLICIT, npins)
|
||||
{
|
||||
local_flag(true);
|
||||
}
|
||||
|
||||
NetProc::NetProc()
|
||||
: next_(0)
|
||||
{
|
||||
@@ -555,6 +649,13 @@ NetObj::Link& NetAddSub::pin_DataA(unsigned idx)
|
||||
return pin(idx);
|
||||
}
|
||||
|
||||
const NetObj::Link& NetAddSub::pin_DataA(unsigned idx) const
|
||||
{
|
||||
idx = 6 + idx*3;
|
||||
assert(idx < pin_count());
|
||||
return pin(idx);
|
||||
}
|
||||
|
||||
NetObj::Link& NetAddSub::pin_DataB(unsigned idx)
|
||||
{
|
||||
idx = 7 + idx*3;
|
||||
@@ -562,6 +663,13 @@ NetObj::Link& NetAddSub::pin_DataB(unsigned idx)
|
||||
return pin(idx);
|
||||
}
|
||||
|
||||
const NetObj::Link& NetAddSub::pin_DataB(unsigned idx) const
|
||||
{
|
||||
idx = 7 + idx*3;
|
||||
assert(idx < pin_count());
|
||||
return pin(idx);
|
||||
}
|
||||
|
||||
NetObj::Link& NetAddSub::pin_Result(unsigned idx)
|
||||
{
|
||||
idx = 8 + idx*3;
|
||||
@@ -576,6 +684,244 @@ const NetObj::Link& NetAddSub::pin_Result(unsigned idx) const
|
||||
return pin(idx);
|
||||
}
|
||||
|
||||
/*
|
||||
* The pinout for the NetCLShift is:
|
||||
* 0 -- Direction
|
||||
* 1 -- Underflow
|
||||
* 2 -- Overflow
|
||||
* 3 -- Data(0)
|
||||
* 3+W -- Result(0)
|
||||
* 3+2W -- Distance(0)
|
||||
*/
|
||||
NetCLShift::NetCLShift(const string&n, unsigned width, unsigned width_dist)
|
||||
: NetNode(n, 3+2*width+width_dist), width_(width), width_dist_(width_dist)
|
||||
{
|
||||
pin(0).set_dir(NetObj::Link::INPUT); pin(0).set_name("Direction", 0);
|
||||
pin(1).set_dir(NetObj::Link::OUTPUT); pin(1).set_name("Underflow", 0);
|
||||
pin(2).set_dir(NetObj::Link::OUTPUT); pin(2).set_name("Overflow", 0);
|
||||
|
||||
for (unsigned idx = 0 ; idx < width_ ; idx += 1) {
|
||||
pin(3+idx).set_dir(NetObj::Link::INPUT);
|
||||
pin(3+idx).set_name("Data", idx);
|
||||
|
||||
pin(3+width_+idx).set_dir(NetObj::Link::OUTPUT);
|
||||
pin(3+width_+idx).set_name("Result", idx);
|
||||
}
|
||||
|
||||
for (unsigned idx = 0 ; idx < width_dist_ ; idx += 1) {
|
||||
pin(3+2*width_+idx).set_dir(NetObj::Link::INPUT);
|
||||
pin(3+2*width_+idx).set_name("Distance", idx);
|
||||
}
|
||||
}
|
||||
|
||||
NetCLShift::~NetCLShift()
|
||||
{
|
||||
}
|
||||
|
||||
unsigned NetCLShift::width() const
|
||||
{
|
||||
return width_;
|
||||
}
|
||||
|
||||
unsigned NetCLShift::width_dist() const
|
||||
{
|
||||
return width_dist_;
|
||||
}
|
||||
|
||||
NetObj::Link& NetCLShift::pin_Direction()
|
||||
{
|
||||
return pin(0);
|
||||
}
|
||||
|
||||
const NetObj::Link& NetCLShift::pin_Direction() const
|
||||
{
|
||||
return pin(0);
|
||||
}
|
||||
|
||||
NetObj::Link& NetCLShift::pin_Underflow()
|
||||
{
|
||||
return pin(1);
|
||||
}
|
||||
|
||||
const NetObj::Link& NetCLShift::pin_Underflow() const
|
||||
{
|
||||
return pin(1);
|
||||
}
|
||||
|
||||
NetObj::Link& NetCLShift::pin_Overflow()
|
||||
{
|
||||
return pin(2);
|
||||
}
|
||||
|
||||
const NetObj::Link& NetCLShift::pin_Overflow() const
|
||||
{
|
||||
return pin(2);
|
||||
}
|
||||
|
||||
NetObj::Link& NetCLShift::pin_Data(unsigned idx)
|
||||
{
|
||||
assert(idx < width_);
|
||||
return pin(3+idx);
|
||||
}
|
||||
|
||||
const NetObj::Link& NetCLShift::pin_Data(unsigned idx) const
|
||||
{
|
||||
assert(idx < width_);
|
||||
return pin(3+idx);
|
||||
}
|
||||
|
||||
NetObj::Link& NetCLShift::pin_Result(unsigned idx)
|
||||
{
|
||||
assert(idx < width_);
|
||||
return pin(3+width_+idx);
|
||||
}
|
||||
|
||||
const NetObj::Link& NetCLShift::pin_Result(unsigned idx) const
|
||||
{
|
||||
assert(idx < width_);
|
||||
return pin(3+width_+idx);
|
||||
}
|
||||
|
||||
NetObj::Link& NetCLShift::pin_Distance(unsigned idx)
|
||||
{
|
||||
assert(idx < width_dist_);
|
||||
return pin(3+2*width_+idx);
|
||||
}
|
||||
|
||||
const NetObj::Link& NetCLShift::pin_Distance(unsigned idx) const
|
||||
{
|
||||
assert(idx < width_dist_);
|
||||
return pin(3+2*width_+idx);
|
||||
}
|
||||
|
||||
NetCompare::NetCompare(const string&n, unsigned wi)
|
||||
: NetNode(n, 8+2*wi), width_(wi)
|
||||
{
|
||||
pin(0).set_dir(NetObj::Link::INPUT); pin(0).set_name("Aclr");
|
||||
pin(1).set_dir(NetObj::Link::INPUT); pin(1).set_name("Clock");
|
||||
pin(2).set_dir(NetObj::Link::OUTPUT); pin(2).set_name("AGB");
|
||||
pin(3).set_dir(NetObj::Link::OUTPUT); pin(3).set_name("AGEB");
|
||||
pin(4).set_dir(NetObj::Link::OUTPUT); pin(4).set_name("AEB");
|
||||
pin(5).set_dir(NetObj::Link::OUTPUT); pin(5).set_name("ANEB");
|
||||
pin(6).set_dir(NetObj::Link::OUTPUT); pin(6).set_name("ALB");
|
||||
pin(7).set_dir(NetObj::Link::OUTPUT); pin(7).set_name("ALEB");
|
||||
for (unsigned idx = 0 ; idx < width_ ; idx += 1) {
|
||||
pin(8+idx).set_dir(NetObj::Link::INPUT);
|
||||
pin(8+idx).set_name("DataA", idx);
|
||||
pin(8+width_+idx).set_dir(NetObj::Link::INPUT);
|
||||
pin(8+width_+idx).set_name("DataB", idx);
|
||||
}
|
||||
}
|
||||
|
||||
NetCompare::~NetCompare()
|
||||
{
|
||||
}
|
||||
|
||||
unsigned NetCompare::width() const
|
||||
{
|
||||
return width_;
|
||||
}
|
||||
|
||||
NetObj::Link& NetCompare::pin_Aclr()
|
||||
{
|
||||
return pin(0);
|
||||
}
|
||||
|
||||
const NetObj::Link& NetCompare::pin_Aclr() const
|
||||
{
|
||||
return pin(0);
|
||||
}
|
||||
|
||||
NetObj::Link& NetCompare::pin_Clock()
|
||||
{
|
||||
return pin(1);
|
||||
}
|
||||
|
||||
const NetObj::Link& NetCompare::pin_Clock() const
|
||||
{
|
||||
return pin(1);
|
||||
}
|
||||
|
||||
NetObj::Link& NetCompare::pin_AGB()
|
||||
{
|
||||
return pin(2);
|
||||
}
|
||||
|
||||
const NetObj::Link& NetCompare::pin_AGB() const
|
||||
{
|
||||
return pin(2);
|
||||
}
|
||||
|
||||
NetObj::Link& NetCompare::pin_AGEB()
|
||||
{
|
||||
return pin(3);
|
||||
}
|
||||
|
||||
const NetObj::Link& NetCompare::pin_AGEB() const
|
||||
{
|
||||
return pin(3);
|
||||
}
|
||||
|
||||
NetObj::Link& NetCompare::pin_AEB()
|
||||
{
|
||||
return pin(4);
|
||||
}
|
||||
|
||||
const NetObj::Link& NetCompare::pin_AEB() const
|
||||
{
|
||||
return pin(4);
|
||||
}
|
||||
|
||||
NetObj::Link& NetCompare::pin_ANEB()
|
||||
{
|
||||
return pin(5);
|
||||
}
|
||||
|
||||
const NetObj::Link& NetCompare::pin_ANEB() const
|
||||
{
|
||||
return pin(5);
|
||||
}
|
||||
|
||||
NetObj::Link& NetCompare::pin_ALB()
|
||||
{
|
||||
return pin(6);
|
||||
}
|
||||
|
||||
const NetObj::Link& NetCompare::pin_ALB() const
|
||||
{
|
||||
return pin(6);
|
||||
}
|
||||
|
||||
NetObj::Link& NetCompare::pin_ALEB()
|
||||
{
|
||||
return pin(7);
|
||||
}
|
||||
|
||||
const NetObj::Link& NetCompare::pin_ALEB() const
|
||||
{
|
||||
return pin(7);
|
||||
}
|
||||
|
||||
NetObj::Link& NetCompare::pin_DataA(unsigned idx)
|
||||
{
|
||||
return pin(8+idx);
|
||||
}
|
||||
|
||||
const NetObj::Link& NetCompare::pin_DataA(unsigned idx) const
|
||||
{
|
||||
return pin(8+idx);
|
||||
}
|
||||
|
||||
NetObj::Link& NetCompare::pin_DataB(unsigned idx)
|
||||
{
|
||||
return pin(8+width_+idx);
|
||||
}
|
||||
|
||||
const NetObj::Link& NetCompare::pin_DataB(unsigned idx) const
|
||||
{
|
||||
return pin(8+width_+idx);
|
||||
}
|
||||
|
||||
/*
|
||||
* The NetMux class represents an LPM_MUX device. The pinout is assigned
|
||||
* like so:
|
||||
@@ -589,7 +935,7 @@ NetMux::NetMux(const string&n, unsigned wi, unsigned si, unsigned sw)
|
||||
: NetNode(n, 2+wi+sw+wi*si), width_(wi), size_(si), swidth_(sw)
|
||||
{
|
||||
pin(0).set_dir(NetObj::Link::INPUT); pin(0).set_name("Aclr", 0);
|
||||
pin(1).set_dir(NetObj::Link::INPUT); pin(0).set_name("Clock", 0);
|
||||
pin(1).set_dir(NetObj::Link::INPUT); pin(1).set_name("Clock", 0);
|
||||
|
||||
for (unsigned idx = 0 ; idx < width_ ; idx += 1) {
|
||||
pin_Result(idx).set_dir(NetObj::Link::OUTPUT);
|
||||
@@ -602,7 +948,7 @@ NetMux::NetMux(const string&n, unsigned wi, unsigned si, unsigned sw)
|
||||
}
|
||||
|
||||
for (unsigned idx = 0 ; idx < swidth_ ; idx += 1) {
|
||||
pin_Sel(idx).set_dir(Link::OUTPUT);
|
||||
pin_Sel(idx).set_dir(Link::INPUT);
|
||||
pin_Sel(idx).set_name("Sel", idx);
|
||||
}
|
||||
}
|
||||
@@ -684,6 +1030,120 @@ const NetObj::Link& NetMux::pin_Data(unsigned w, unsigned s) const
|
||||
return pin(2+width_+swidth_+s*width_+w);
|
||||
}
|
||||
|
||||
|
||||
NetRamDq::NetRamDq(const string&n, NetMemory*mem, unsigned awid)
|
||||
: NetNode(n, 3+2*mem->width()+awid), mem_(mem), awidth_(awid)
|
||||
{
|
||||
pin(0).set_dir(NetObj::Link::INPUT); pin(0).set_name("InClock", 0);
|
||||
pin(1).set_dir(NetObj::Link::INPUT); pin(1).set_name("OutClock", 0);
|
||||
pin(2).set_dir(NetObj::Link::INPUT); pin(2).set_name("WE", 0);
|
||||
|
||||
for (unsigned idx = 0 ; idx < awidth_ ; idx += 1) {
|
||||
pin(3+idx).set_dir(NetObj::Link::INPUT);
|
||||
pin(3+idx).set_name("Address", idx);
|
||||
}
|
||||
|
||||
for (unsigned idx = 0 ; idx < width() ; idx += 1) {
|
||||
pin(3+awidth_+idx).set_dir(NetObj::Link::INPUT);
|
||||
pin(3+awidth_+idx).set_name("Data", idx);
|
||||
}
|
||||
|
||||
for (unsigned idx = 0 ; idx < width() ; idx += 1) {
|
||||
pin(3+awidth_+width()+idx).set_dir(NetObj::Link::OUTPUT);
|
||||
pin(3+awidth_+width()+idx).set_name("Q", idx);
|
||||
}
|
||||
}
|
||||
|
||||
NetRamDq::~NetRamDq()
|
||||
{
|
||||
}
|
||||
|
||||
unsigned NetRamDq::width() const
|
||||
{
|
||||
return mem_->width();
|
||||
}
|
||||
|
||||
unsigned NetRamDq::awidth() const
|
||||
{
|
||||
return awidth_;
|
||||
}
|
||||
|
||||
unsigned NetRamDq::size() const
|
||||
{
|
||||
return mem_->count();
|
||||
}
|
||||
|
||||
const NetMemory* NetRamDq::mem() const
|
||||
{
|
||||
return mem_;
|
||||
}
|
||||
|
||||
NetObj::Link& NetRamDq::pin_InClock()
|
||||
{
|
||||
return pin(0);
|
||||
}
|
||||
|
||||
const NetObj::Link& NetRamDq::pin_InClock() const
|
||||
{
|
||||
return pin(0);
|
||||
}
|
||||
|
||||
NetObj::Link& NetRamDq::pin_OutClock()
|
||||
{
|
||||
return pin(1);
|
||||
}
|
||||
|
||||
const NetObj::Link& NetRamDq::pin_OutClock() const
|
||||
{
|
||||
return pin(1);
|
||||
}
|
||||
|
||||
NetObj::Link& NetRamDq::pin_WE()
|
||||
{
|
||||
return pin(2);
|
||||
}
|
||||
|
||||
const NetObj::Link& NetRamDq::pin_WE() const
|
||||
{
|
||||
return pin(2);
|
||||
}
|
||||
|
||||
NetObj::Link& NetRamDq::pin_Address(unsigned idx)
|
||||
{
|
||||
assert(idx < awidth_);
|
||||
return pin(3+idx);
|
||||
}
|
||||
|
||||
const NetObj::Link& NetRamDq::pin_Address(unsigned idx) const
|
||||
{
|
||||
assert(idx < awidth_);
|
||||
return pin(3+idx);
|
||||
}
|
||||
|
||||
NetObj::Link& NetRamDq::pin_Data(unsigned idx)
|
||||
{
|
||||
assert(idx < width());
|
||||
return pin(3+awidth_+idx);
|
||||
}
|
||||
|
||||
const NetObj::Link& NetRamDq::pin_Data(unsigned idx) const
|
||||
{
|
||||
assert(idx < width());
|
||||
return pin(3+awidth_+idx);
|
||||
}
|
||||
|
||||
NetObj::Link& NetRamDq::pin_Q(unsigned idx)
|
||||
{
|
||||
assert(idx < width());
|
||||
return pin(3+awidth_+width()+idx);
|
||||
}
|
||||
|
||||
const NetObj::Link& NetRamDq::pin_Q(unsigned idx) const
|
||||
{
|
||||
assert(idx < width());
|
||||
return pin(3+awidth_+width()+idx);
|
||||
}
|
||||
|
||||
/*
|
||||
* NetAssign
|
||||
*/
|
||||
@@ -884,9 +1344,9 @@ void NetCase::set_case(unsigned idx, NetExpr*e, NetProc*p)
|
||||
NetCaseCmp::NetCaseCmp(const string&n)
|
||||
: NetNode(n, 3)
|
||||
{
|
||||
pin(0).set_dir(Link::OUTPUT);
|
||||
pin(1).set_dir(Link::INPUT);
|
||||
pin(2).set_dir(Link::INPUT);
|
||||
pin(0).set_dir(Link::OUTPUT); pin(0).set_name("O",0);
|
||||
pin(1).set_dir(Link::INPUT); pin(1).set_name("I",0);
|
||||
pin(2).set_dir(Link::INPUT); pin(2).set_name("I",1);
|
||||
}
|
||||
|
||||
NetCaseCmp::~NetCaseCmp()
|
||||
@@ -1288,7 +1748,7 @@ NetEIdent* NetEIdent::dup_expr() const
|
||||
}
|
||||
|
||||
NetEMemory::NetEMemory(NetMemory*m, NetExpr*i)
|
||||
: mem_(m), idx_(i)
|
||||
: NetExpr(m->width()), mem_(m), idx_(i)
|
||||
{
|
||||
}
|
||||
|
||||
@@ -1348,26 +1808,45 @@ NetEParam* NetEParam::dup_expr() const
|
||||
return 0;
|
||||
}
|
||||
|
||||
NetESignal::NetESignal(NetNet*n)
|
||||
: NetExpr(n->pin_count()), NetNode(n->name(), n->pin_count())
|
||||
NetEScope::NetEScope(NetScope*s)
|
||||
: scope_(s)
|
||||
{
|
||||
set_line(*n);
|
||||
for (unsigned idx = 0 ; idx < n->pin_count() ; idx += 1) {
|
||||
pin(idx).set_name("P", idx);
|
||||
connect(pin(idx), n->pin(idx));
|
||||
}
|
||||
}
|
||||
|
||||
NetESignal::NetESignal(const string&n, unsigned np)
|
||||
: NetExpr(np), NetNode(n, np)
|
||||
NetEScope::~NetEScope()
|
||||
{
|
||||
expr_width(pin_count());
|
||||
for(unsigned idx = 0 ; idx < np ; idx += 1)
|
||||
pin(idx).set_name("P", idx);
|
||||
}
|
||||
|
||||
const NetScope* NetEScope::scope() const
|
||||
{
|
||||
return scope_;
|
||||
}
|
||||
|
||||
NetESignal::NetESignal(NetNet*n)
|
||||
: NetExpr(n->pin_count()), net_(n)
|
||||
{
|
||||
net_->incr_eref();
|
||||
set_line(*n);
|
||||
}
|
||||
|
||||
NetESignal::~NetESignal()
|
||||
{
|
||||
net_->decr_eref();
|
||||
}
|
||||
|
||||
const string& NetESignal::name() const
|
||||
{
|
||||
return net_->name();
|
||||
}
|
||||
|
||||
unsigned NetESignal::pin_count() const
|
||||
{
|
||||
return net_->pin_count();
|
||||
}
|
||||
|
||||
NetObj::Link& NetESignal::pin(unsigned idx)
|
||||
{
|
||||
return net_->pin(idx);
|
||||
}
|
||||
|
||||
NetESignal* NetESignal::dup_expr() const
|
||||
@@ -1498,6 +1977,30 @@ const NetExpr* NetRepeat::expr() const
|
||||
return expr_;
|
||||
}
|
||||
|
||||
NetScope::NetScope(const string&n)
|
||||
: type_(NetScope::MODULE), name_(n)
|
||||
{
|
||||
}
|
||||
|
||||
NetScope::NetScope(const string&p, NetScope::TYPE t)
|
||||
: type_(t), name_(p)
|
||||
{
|
||||
}
|
||||
|
||||
NetScope::~NetScope()
|
||||
{
|
||||
}
|
||||
|
||||
NetScope::TYPE NetScope::type() const
|
||||
{
|
||||
return type_;
|
||||
}
|
||||
|
||||
string NetScope::name() const
|
||||
{
|
||||
return name_;
|
||||
}
|
||||
|
||||
NetTaskDef::NetTaskDef(const string&n, const svector<NetNet*>&po)
|
||||
: name_(n), proc_(0), ports_(po)
|
||||
{
|
||||
@@ -1790,6 +2293,41 @@ void NetUDP::set_initial(char val)
|
||||
init_ = val;
|
||||
}
|
||||
|
||||
Design:: Design()
|
||||
: errors(0), signals_(0), nodes_(0), procs_(0), lcounter_(0)
|
||||
{
|
||||
}
|
||||
|
||||
Design::~Design()
|
||||
{
|
||||
}
|
||||
|
||||
NetScope* Design::make_root_scope(const string&root)
|
||||
{
|
||||
NetScope*scope = new NetScope(root);
|
||||
scopes_[root] = scope;
|
||||
return scope;
|
||||
}
|
||||
|
||||
NetScope* Design::make_scope(const string&path,
|
||||
NetScope::TYPE t,
|
||||
const string&name)
|
||||
{
|
||||
string npath = path + "." + name;
|
||||
NetScope*scope = new NetScope(npath, t);
|
||||
scopes_[npath] = scope;
|
||||
return scope;
|
||||
}
|
||||
|
||||
NetScope* Design::find_scope(const string&key)
|
||||
{
|
||||
map<string,NetScope*>::const_iterator tmp = scopes_.find(key);
|
||||
if (tmp == scopes_.end())
|
||||
return 0;
|
||||
else
|
||||
return (*tmp).second;
|
||||
}
|
||||
|
||||
void Design::set_parameter(const string&key, NetExpr*expr)
|
||||
{
|
||||
parameters_[key] = expr;
|
||||
@@ -1898,13 +2436,26 @@ void Design::add_memory(NetMemory*mem)
|
||||
memories_[mem->name()] = mem;
|
||||
}
|
||||
|
||||
NetMemory* Design::find_memory(const string&key)
|
||||
NetMemory* Design::find_memory(const string&path, const string&name)
|
||||
{
|
||||
map<string,NetMemory*>::const_iterator cur = memories_.find(key);
|
||||
if (cur == memories_.end())
|
||||
return 0;
|
||||
string root = path;
|
||||
|
||||
return (*cur).second;
|
||||
for (;;) {
|
||||
string fulname = root + "." + name;
|
||||
map<string,NetMemory*>::const_iterator cur
|
||||
= memories_.find(fulname);
|
||||
|
||||
if (cur != memories_.end())
|
||||
return (*cur).second;
|
||||
|
||||
unsigned pos = root.rfind('.');
|
||||
if (pos > root.length())
|
||||
break;
|
||||
|
||||
root = root.substr(0, pos);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void Design::add_function(const string&key, NetFuncDef*def)
|
||||
@@ -2090,6 +2641,62 @@ NetNet* Design::find_signal(bool (*func)(const NetNet*))
|
||||
|
||||
/*
|
||||
* $Log: netlist.cc,v $
|
||||
* Revision 1.97 1999/12/02 16:58:58 steve
|
||||
* Update case comparison (Eric Aardoom).
|
||||
*
|
||||
* Revision 1.96 1999/11/28 23:42:02 steve
|
||||
* NetESignal object no longer need to be NetNode
|
||||
* objects. Let them keep a pointer to NetNet objects.
|
||||
*
|
||||
* Revision 1.95 1999/11/28 01:16:18 steve
|
||||
* gate outputs need to set signal values.
|
||||
*
|
||||
* Revision 1.94 1999/11/27 19:07:57 steve
|
||||
* Support the creation of scopes.
|
||||
*
|
||||
* Revision 1.93 1999/11/24 04:01:59 steve
|
||||
* Detect and list scope names.
|
||||
*
|
||||
* Revision 1.92 1999/11/21 18:03:35 steve
|
||||
* Fix expression width of memory references.
|
||||
*
|
||||
* Revision 1.91 1999/11/21 17:35:37 steve
|
||||
* Memory name lookup handles scopes.
|
||||
*
|
||||
* Revision 1.90 1999/11/21 00:13:08 steve
|
||||
* Support memories in continuous assignments.
|
||||
*
|
||||
* Revision 1.89 1999/11/19 05:02:37 steve
|
||||
* handle duplicate connect to a nexus.
|
||||
*
|
||||
* Revision 1.88 1999/11/19 03:02:25 steve
|
||||
* Detect flip-flops connected to opads and turn
|
||||
* them into OUTFF devices. Inprove support for
|
||||
* the XNF-LCA attribute in the process.
|
||||
*
|
||||
* Revision 1.87 1999/11/18 03:52:19 steve
|
||||
* Turn NetTmp objects into normal local NetNet objects,
|
||||
* and add the nodangle functor to clean up the local
|
||||
* symbols generated by elaboration and other steps.
|
||||
*
|
||||
* Revision 1.86 1999/11/14 23:43:45 steve
|
||||
* Support combinatorial comparators.
|
||||
*
|
||||
* Revision 1.85 1999/11/14 20:24:28 steve
|
||||
* Add support for the LPM_CLSHIFT device.
|
||||
*
|
||||
* Revision 1.84 1999/11/13 03:46:52 steve
|
||||
* Support the LPM_MUX in vvm.
|
||||
*
|
||||
* Revision 1.83 1999/11/05 04:40:40 steve
|
||||
* Patch to synthesize LPM_ADD_SUB from expressions,
|
||||
* Thanks to Larry Doolittle. Also handle constants
|
||||
* in expressions.
|
||||
*
|
||||
* Synthesize adders in XNF, based on a patch from
|
||||
* Larry. Accept synthesis of constants from Larry
|
||||
* as is.
|
||||
*
|
||||
* Revision 1.82 1999/11/04 03:53:26 steve
|
||||
* Patch to synthesize unary ~ and the ternary operator.
|
||||
* Thanks to Larry Doolittle <[email protected]>.
|
||||
@@ -2339,78 +2946,5 @@ NetNet* Design::find_signal(bool (*func)(const NetNet*))
|
||||
*
|
||||
* Revision 1.15 1999/02/03 04:20:11 steve
|
||||
* Parse and elaborate the Verilog CASE statement.
|
||||
*
|
||||
* Revision 1.14 1998/12/18 05:16:25 steve
|
||||
* Parse more UDP input edge descriptions.
|
||||
*
|
||||
* Revision 1.13 1998/12/17 23:54:58 steve
|
||||
* VVM support for small sequential UDP objects.
|
||||
*
|
||||
* Revision 1.12 1998/12/14 02:01:35 steve
|
||||
* Fully elaborate Sequential UDP behavior.
|
||||
*
|
||||
* Revision 1.11 1998/12/07 04:53:17 steve
|
||||
* Generate OBUF or IBUF attributes (and the gates
|
||||
* to garry them) where a wire is a pad. This involved
|
||||
* figuring out enough of the netlist to know when such
|
||||
* was needed, and to generate new gates and signales
|
||||
* to handle what's missing.
|
||||
*
|
||||
* Revision 1.10 1998/12/02 04:37:13 steve
|
||||
* Add the nobufz function to eliminate bufz objects,
|
||||
* Object links are marked with direction,
|
||||
* constant propagation is more careful will wide links,
|
||||
* Signal folding is aware of attributes, and
|
||||
* the XNF target can dump UDP objects based on LCA
|
||||
* attributes.
|
||||
*
|
||||
* Revision 1.9 1998/12/01 00:42:14 steve
|
||||
* Elaborate UDP devices,
|
||||
* Support UDP type attributes, and
|
||||
* pass those attributes to nodes that
|
||||
* are instantiated by elaboration,
|
||||
* Put modules into a map instead of
|
||||
* a simple list.
|
||||
*
|
||||
* Revision 1.8 1998/11/23 00:20:23 steve
|
||||
* NetAssign handles lvalues as pin links
|
||||
* instead of a signal pointer,
|
||||
* Wire attributes added,
|
||||
* Ability to parse UDP descriptions added,
|
||||
* XNF generates EXT records for signals with
|
||||
* the PAD attribute.
|
||||
*
|
||||
* Revision 1.7 1998/11/18 04:25:22 steve
|
||||
* Add -f flags for generic flag key/values.
|
||||
*
|
||||
* Revision 1.6 1998/11/16 05:03:53 steve
|
||||
* Add the sigfold function that unlinks excess
|
||||
* signal nodes, and add the XNF target.
|
||||
*
|
||||
* Revision 1.5 1998/11/13 06:23:17 steve
|
||||
* Introduce netlist optimizations with the
|
||||
* cprop function to do constant propogation.
|
||||
*
|
||||
* Revision 1.4 1998/11/09 18:55:34 steve
|
||||
* Add procedural while loops,
|
||||
* Parse procedural for loops,
|
||||
* Add procedural wait statements,
|
||||
* Add constant nodes,
|
||||
* Add XNOR logic gate,
|
||||
* Make vvm output look a bit prettier.
|
||||
*
|
||||
* Revision 1.3 1998/11/07 19:17:10 steve
|
||||
* Calculate expression widths at elaboration time.
|
||||
*
|
||||
* Revision 1.2 1998/11/07 17:05:05 steve
|
||||
* Handle procedural conditional, and some
|
||||
* of the conditional expressions.
|
||||
*
|
||||
* Elaborate signals and identifiers differently,
|
||||
* allowing the netlist to hold signal information.
|
||||
*
|
||||
* Revision 1.1 1998/11/03 23:29:00 steve
|
||||
* Introduce verilog to CVS.
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
@@ -19,7 +19,7 @@
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
|
||||
*/
|
||||
#if !defined(WINNT)
|
||||
#ident "$Id: netlist.h,v 1.85 1999/11/04 03:53:26 steve Exp $"
|
||||
#ident "$Id: netlist.h,v 1.97 1999/12/01 06:06:16 steve Exp $"
|
||||
#endif
|
||||
|
||||
/*
|
||||
@@ -39,6 +39,7 @@ class Design;
|
||||
class NetNode;
|
||||
class NetProc;
|
||||
class NetProcTop;
|
||||
class NetScope;
|
||||
class NetExpr;
|
||||
class NetESignal;
|
||||
class ostream;
|
||||
@@ -88,18 +89,11 @@ class NetObj {
|
||||
pin = pin_;
|
||||
}
|
||||
|
||||
void next_link(NetObj*&net, unsigned&pin)
|
||||
{ net = next_->node_;
|
||||
pin = next_->pin_;
|
||||
}
|
||||
void next_link(NetObj*&net, unsigned&pin);
|
||||
void next_link(const NetObj*&net, unsigned&pin) const;
|
||||
|
||||
void next_link(const NetObj*&net, unsigned&pin) const
|
||||
{ net = next_->node_;
|
||||
pin = next_->pin_;
|
||||
}
|
||||
|
||||
Link* next_link() { return next_; }
|
||||
const Link* next_link() const { return next_; }
|
||||
Link* next_link();
|
||||
const Link* next_link() const;
|
||||
|
||||
// Remove this link from the set of connected pins. The
|
||||
// destructor will automatically do this if needed.
|
||||
@@ -239,12 +233,14 @@ class NetNet : public NetObj, public LineInfo {
|
||||
|
||||
enum PortType { NOT_A_PORT, PIMPLICIT, PINPUT, POUTPUT, PINOUT };
|
||||
|
||||
explicit NetNet(const string&n, Type t, unsigned npins =1);
|
||||
explicit NetNet(NetScope*s, const string&n, Type t, unsigned npins =1);
|
||||
|
||||
explicit NetNet(const string&n, Type t, long ms, long ls);
|
||||
explicit NetNet(NetScope*s, const string&n, Type t, long ms, long ls);
|
||||
|
||||
virtual ~NetNet();
|
||||
|
||||
NetScope* scope();
|
||||
const NetScope* scope() const;
|
||||
|
||||
Type type() const { return type_; }
|
||||
void type(Type t) { type_ = t; }
|
||||
@@ -267,6 +263,12 @@ class NetNet : public NetObj, public LineInfo {
|
||||
bool local_flag() const { return local_flag_; }
|
||||
void local_flag(bool f) { local_flag_ = f; }
|
||||
|
||||
/* NetESignal objects may reference this object. Keep a
|
||||
reference count so that I keep track of them. */
|
||||
void incr_eref();
|
||||
void decr_eref();
|
||||
unsigned get_eref() const;
|
||||
|
||||
verinum::V get_ival(unsigned pin) const
|
||||
{ return ivalue_[pin]; }
|
||||
void set_ival(unsigned pin, verinum::V val)
|
||||
@@ -281,12 +283,14 @@ class NetNet : public NetObj, public LineInfo {
|
||||
Design*design_;
|
||||
|
||||
private:
|
||||
NetScope*scope_;
|
||||
Type type_;
|
||||
PortType port_type_;
|
||||
|
||||
long msb_, lsb_;
|
||||
|
||||
bool local_flag_;
|
||||
unsigned eref_count_;
|
||||
|
||||
verinum::V*ivalue_;
|
||||
};
|
||||
@@ -317,12 +321,94 @@ class NetAddSub : public NetNode {
|
||||
NetObj::Link& pin_DataB(unsigned idx);
|
||||
NetObj::Link& pin_Result(unsigned idx);
|
||||
|
||||
const NetObj::Link& pin_DataA(unsigned idx) const;
|
||||
const NetObj::Link& pin_DataB(unsigned idx) const;
|
||||
const NetObj::Link& pin_Result(unsigned idx) const;
|
||||
|
||||
virtual void dump_node(ostream&, unsigned ind) const;
|
||||
virtual void emit_node(ostream&, struct target_t*) const;
|
||||
};
|
||||
|
||||
/*
|
||||
* This type represents the LPM_CLSHIFT device.
|
||||
*/
|
||||
class NetCLShift : public NetNode {
|
||||
|
||||
public:
|
||||
NetCLShift(const string&n, unsigned width, unsigned width_dist);
|
||||
~NetCLShift();
|
||||
|
||||
unsigned width() const;
|
||||
unsigned width_dist() const;
|
||||
|
||||
NetObj::Link& pin_Direction();
|
||||
NetObj::Link& pin_Underflow();
|
||||
NetObj::Link& pin_Overflow();
|
||||
NetObj::Link& pin_Data(unsigned idx);
|
||||
NetObj::Link& pin_Result(unsigned idx);
|
||||
NetObj::Link& pin_Distance(unsigned idx);
|
||||
|
||||
const NetObj::Link& pin_Direction() const;
|
||||
const NetObj::Link& pin_Underflow() const;
|
||||
const NetObj::Link& pin_Overflow() const;
|
||||
const NetObj::Link& pin_Data(unsigned idx) const;
|
||||
const NetObj::Link& pin_Result(unsigned idx) const;
|
||||
const NetObj::Link& pin_Distance(unsigned idx) const;
|
||||
|
||||
virtual void dump_node(ostream&, unsigned ind) const;
|
||||
virtual void emit_node(ostream&, struct target_t*) const;
|
||||
|
||||
private:
|
||||
unsigned width_;
|
||||
unsigned width_dist_;
|
||||
};
|
||||
|
||||
/*
|
||||
* This class supports the LPM_COMPARE device.
|
||||
*
|
||||
* NOTE: This is not the same as the device used to support case
|
||||
* compare. Case comparisons handle Vx and Vz values, whereas this
|
||||
* device need not.
|
||||
*/
|
||||
class NetCompare : public NetNode {
|
||||
|
||||
public:
|
||||
NetCompare(const string&n, unsigned width);
|
||||
~NetCompare();
|
||||
|
||||
unsigned width() const;
|
||||
|
||||
NetObj::Link& pin_Aclr();
|
||||
NetObj::Link& pin_Clock();
|
||||
NetObj::Link& pin_AGB();
|
||||
NetObj::Link& pin_AGEB();
|
||||
NetObj::Link& pin_AEB();
|
||||
NetObj::Link& pin_ANEB();
|
||||
NetObj::Link& pin_ALB();
|
||||
NetObj::Link& pin_ALEB();
|
||||
|
||||
NetObj::Link& pin_DataA(unsigned idx);
|
||||
NetObj::Link& pin_DataB(unsigned idx);
|
||||
|
||||
const NetObj::Link& pin_Aclr() const;
|
||||
const NetObj::Link& pin_Clock() const;
|
||||
const NetObj::Link& pin_AGB() const;
|
||||
const NetObj::Link& pin_AGEB() const;
|
||||
const NetObj::Link& pin_AEB() const;
|
||||
const NetObj::Link& pin_ANEB() const;
|
||||
const NetObj::Link& pin_ALB() const;
|
||||
const NetObj::Link& pin_ALEB() const;
|
||||
|
||||
const NetObj::Link& pin_DataA(unsigned idx) const;
|
||||
const NetObj::Link& pin_DataB(unsigned idx) const;
|
||||
|
||||
virtual void dump_node(ostream&, unsigned ind) const;
|
||||
virtual void emit_node(ostream&, struct target_t*) const;
|
||||
|
||||
private:
|
||||
unsigned width_;
|
||||
};
|
||||
|
||||
/*
|
||||
* This class represents an LPM_FF device. There is no literal gate
|
||||
* type in Verilog that maps, but gates of this type can be inferred.
|
||||
@@ -439,6 +525,50 @@ class NetMux : public NetNode {
|
||||
unsigned swidth_;
|
||||
};
|
||||
|
||||
/*
|
||||
* This device represents an LPM_RAM_DQ device. The actual content is
|
||||
* represented by a NetMemory object allocated elsewhere, but that
|
||||
* object fixes the width and size of the device. The pin count of the
|
||||
* address input is given in the constructor.
|
||||
*/
|
||||
class NetRamDq : public NetNode {
|
||||
|
||||
public:
|
||||
NetRamDq(const string&name, NetMemory*mem, unsigned awid);
|
||||
~NetRamDq();
|
||||
|
||||
unsigned width() const;
|
||||
unsigned awidth() const;
|
||||
unsigned size() const;
|
||||
const NetMemory*mem() const;
|
||||
|
||||
NetObj::Link& pin_InClock();
|
||||
NetObj::Link& pin_OutClock();
|
||||
NetObj::Link& pin_WE();
|
||||
|
||||
NetObj::Link& pin_Address(unsigned idx);
|
||||
NetObj::Link& pin_Data(unsigned idx);
|
||||
NetObj::Link& pin_Q(unsigned idx);
|
||||
|
||||
const NetObj::Link& pin_InClock() const;
|
||||
const NetObj::Link& pin_OutClock() const;
|
||||
const NetObj::Link& pin_WE() const;
|
||||
|
||||
const NetObj::Link& pin_Address(unsigned idx) const;
|
||||
const NetObj::Link& pin_Data(unsigned idx) const;
|
||||
const NetObj::Link& pin_Q(unsigned idx) const;
|
||||
|
||||
virtual void dump_node(ostream&, unsigned ind) const;
|
||||
virtual void emit_node(ostream&, struct target_t*) const;
|
||||
|
||||
private:
|
||||
friend class NetMemory;
|
||||
NetMemory*mem_;
|
||||
NetRamDq*next_;
|
||||
unsigned awidth_;
|
||||
|
||||
};
|
||||
|
||||
/* =========
|
||||
* There are cases where expressions need to be represented. The
|
||||
* NetExpr class is the root of a heirarchy that serves that purpose.
|
||||
@@ -493,7 +623,7 @@ class NetExpr : public LineInfo {
|
||||
|
||||
/*
|
||||
* The expression constant is slightly special, and is sometimes
|
||||
* retured from other classes that can be evaluated at compile
|
||||
* returned from other classes that can be evaluated at compile
|
||||
* time. This class represents constant values in expressions.
|
||||
*/
|
||||
class NetEConst : public NetExpr {
|
||||
@@ -509,6 +639,7 @@ class NetEConst : public NetExpr {
|
||||
virtual void dump(ostream&) const;
|
||||
|
||||
virtual NetEConst* dup_expr() const;
|
||||
virtual NetNet*synthesize(Design*);
|
||||
|
||||
private:
|
||||
verinum value_;
|
||||
@@ -516,14 +647,13 @@ class NetEConst : public NetExpr {
|
||||
|
||||
/*
|
||||
* The NetTmp object is a network that is only used momentarily by
|
||||
* elaboration to carry links around. A completed netlist cannot have
|
||||
* any of these within. This is a kind of wire, so it is NetNet type.
|
||||
* elaboration to carry links around. A completed netlist should not
|
||||
* have any of these within. This is a kind of wire, so it is NetNet type.
|
||||
*/
|
||||
class NetTmp : public NetNet {
|
||||
|
||||
public:
|
||||
explicit NetTmp(unsigned npins =1)
|
||||
: NetNet("@", IMPLICIT, npins) { }
|
||||
explicit NetTmp(const string&name, unsigned npins =1);
|
||||
|
||||
};
|
||||
|
||||
@@ -733,6 +863,10 @@ class NetProc : public LineInfo {
|
||||
// target. The target returns true if OK, false for errors.
|
||||
virtual bool emit_proc(ostream&, struct target_t*) const;
|
||||
|
||||
// This method is called by functors that want to scan a
|
||||
// process in search of matchable patterns.
|
||||
virtual int match_proc(struct proc_match_t*);
|
||||
|
||||
virtual void dump(ostream&, unsigned ind) const;
|
||||
|
||||
private:
|
||||
@@ -788,6 +922,7 @@ class NetAssign : public NetAssign_ {
|
||||
|
||||
virtual bool emit_proc(ostream&, struct target_t*) const;
|
||||
virtual void emit_node(ostream&, struct target_t*) const;
|
||||
virtual int match_proc(struct proc_match_t*);
|
||||
virtual void dump(ostream&, unsigned ind) const;
|
||||
virtual void dump_node(ostream&, unsigned ind) const;
|
||||
|
||||
@@ -950,6 +1085,7 @@ class NetCondit : public NetProc {
|
||||
void emit_recurse_else(ostream&, struct target_t*) const;
|
||||
|
||||
virtual bool emit_proc(ostream&, struct target_t*) const;
|
||||
virtual int match_proc(struct proc_match_t*);
|
||||
virtual void dump(ostream&, unsigned ind) const;
|
||||
|
||||
private:
|
||||
@@ -1043,6 +1179,7 @@ class NetPEvent : public NetProc, public sref_back<NetPEvent,NetNEvent> {
|
||||
NetProc* statement();
|
||||
const NetProc* statement() const;
|
||||
|
||||
virtual int match_proc(struct proc_match_t*);
|
||||
virtual bool emit_proc(ostream&, struct target_t*) const;
|
||||
virtual void dump(ostream&, unsigned ind) const;
|
||||
|
||||
@@ -1339,6 +1476,7 @@ class NetEBAdd : public NetEBinary {
|
||||
virtual bool set_width(unsigned w);
|
||||
virtual NetEBAdd* dup_expr() const;
|
||||
virtual NetEConst* eval_tree();
|
||||
virtual NetNet* synthesize(Design*);
|
||||
};
|
||||
|
||||
/*
|
||||
@@ -1499,6 +1637,29 @@ class NetEParam : public NetExpr {
|
||||
string name_;
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
* This class is a special (and magical) expression node type that
|
||||
* represents scope names. These can only be found as parameters to
|
||||
* NetSTask objects.
|
||||
*/
|
||||
class NetEScope : public NetExpr {
|
||||
|
||||
public:
|
||||
NetEScope(NetScope*);
|
||||
~NetEScope();
|
||||
|
||||
const NetScope* scope() const;
|
||||
|
||||
virtual void expr_scan(struct expr_scan_t*) const;
|
||||
virtual NetEScope* dup_expr() const;
|
||||
|
||||
virtual void dump(ostream&os) const;
|
||||
|
||||
private:
|
||||
NetScope*scope_;
|
||||
};
|
||||
|
||||
/*
|
||||
* This node represents a system function call in an expression. The
|
||||
* object contains the name of the system function, which the backend
|
||||
@@ -1657,27 +1818,28 @@ class NetEMemory : public NetExpr {
|
||||
* A signal shows up as a node in the netlist so that structural
|
||||
* activity can invoke the expression.
|
||||
*/
|
||||
class NetESignal : public NetExpr, public NetNode {
|
||||
class NetESignal : public NetExpr {
|
||||
|
||||
public:
|
||||
NetESignal(NetNet*n);
|
||||
NetESignal(const string&name, unsigned npins);
|
||||
~NetESignal();
|
||||
|
||||
const string& name() const { return NetNode::name(); }
|
||||
|
||||
const string& name() const;
|
||||
virtual bool set_width(unsigned);
|
||||
|
||||
virtual NetESignal* dup_expr() const;
|
||||
|
||||
NetNet* synthesize(Design*des);
|
||||
|
||||
// These methods actually reference the properties of the
|
||||
// NetNet object that I point to.
|
||||
unsigned pin_count() const;
|
||||
NetObj::Link& pin(unsigned idx);
|
||||
|
||||
virtual void expr_scan(struct expr_scan_t*) const;
|
||||
virtual void emit_node(ostream&, struct target_t*) const;
|
||||
virtual void dump(ostream&) const;
|
||||
virtual void dump_node(ostream&, unsigned ind) const;
|
||||
|
||||
private:
|
||||
NetNet*net_;
|
||||
};
|
||||
|
||||
/*
|
||||
@@ -1710,6 +1872,30 @@ class NetESubSignal : public NetExpr {
|
||||
NetExpr* idx_;
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
* This object type is used to contain a logical scope within a
|
||||
* design. The scope doesn't represent any executable hardware, but is
|
||||
* just a handle that netlist processors can use to grab at the design.
|
||||
*/
|
||||
class NetScope {
|
||||
|
||||
public:
|
||||
enum TYPE { MODULE, BEGIN_END, FORK_JOIN };
|
||||
NetScope(const string&root);
|
||||
NetScope(const string&path, TYPE t);
|
||||
~NetScope();
|
||||
|
||||
TYPE type() const;
|
||||
string name() const;
|
||||
|
||||
void dump(ostream&) const;
|
||||
|
||||
private:
|
||||
TYPE type_;
|
||||
string name_;
|
||||
};
|
||||
|
||||
/*
|
||||
* This class contains an entire design. It includes processes and a
|
||||
* netlist, and can be passed around from function to function.
|
||||
@@ -1717,7 +1903,9 @@ class NetESubSignal : public NetExpr {
|
||||
class Design {
|
||||
|
||||
public:
|
||||
Design() : errors(0), signals_(0), nodes_(0), procs_(0), lcounter_(0) { }
|
||||
Design();
|
||||
~Design();
|
||||
|
||||
|
||||
/* The flags are a generic way of accepting command line
|
||||
parameters/flags and passing them to the processing steps
|
||||
@@ -1730,6 +1918,10 @@ class Design {
|
||||
|
||||
string get_flag(const string&key) const;
|
||||
|
||||
NetScope* make_root_scope(const string&name);
|
||||
NetScope* make_scope(const string&path, NetScope::TYPE t,
|
||||
const string&name);
|
||||
NetScope* find_scope(const string&path);
|
||||
|
||||
// PARAMETERS
|
||||
void set_parameter(const string&, NetExpr*);
|
||||
@@ -1742,7 +1934,7 @@ class Design {
|
||||
|
||||
// Memories
|
||||
void add_memory(NetMemory*);
|
||||
NetMemory* find_memory(const string&name);
|
||||
NetMemory* find_memory(const string&path, const string&name);
|
||||
|
||||
// Functions
|
||||
void add_function(const string&n, NetFuncDef*);
|
||||
@@ -1781,6 +1973,8 @@ class Design {
|
||||
string local_symbol(const string&path);
|
||||
|
||||
private:
|
||||
map<string,NetScope*> scopes_;
|
||||
|
||||
// List all the parameters in the design. This table includes
|
||||
// the parameters of instantiated modules in canonical names.
|
||||
map<string,NetExpr*> parameters_;
|
||||
@@ -1841,6 +2035,9 @@ extern unsigned count_inputs(const NetObj::Link&pin);
|
||||
extern unsigned count_outputs(const NetObj::Link&pin);
|
||||
extern unsigned count_signals(const NetObj::Link&pin);
|
||||
|
||||
/* Find the next link that is an output into the nexus. */
|
||||
extern NetObj::Link* find_next_output(NetObj::Link*lnk);
|
||||
|
||||
/* Find the signal connected to the given node pin. There should
|
||||
always be exactly one signal. The bidx parameter get filled with
|
||||
the signal index of the Net, in case it is a vector. */
|
||||
@@ -1854,6 +2051,53 @@ extern ostream& operator << (ostream&, NetNet::Type);
|
||||
|
||||
/*
|
||||
* $Log: netlist.h,v $
|
||||
* Revision 1.97 1999/12/01 06:06:16 steve
|
||||
* Redo synth to use match_proc_t scanner.
|
||||
*
|
||||
* Revision 1.96 1999/11/28 23:42:02 steve
|
||||
* NetESignal object no longer need to be NetNode
|
||||
* objects. Let them keep a pointer to NetNet objects.
|
||||
*
|
||||
* Revision 1.95 1999/11/27 19:07:58 steve
|
||||
* Support the creation of scopes.
|
||||
*
|
||||
* Revision 1.94 1999/11/24 04:01:59 steve
|
||||
* Detect and list scope names.
|
||||
*
|
||||
* Revision 1.93 1999/11/21 17:35:37 steve
|
||||
* Memory name lookup handles scopes.
|
||||
*
|
||||
* Revision 1.92 1999/11/21 00:13:09 steve
|
||||
* Support memories in continuous assignments.
|
||||
*
|
||||
* Revision 1.91 1999/11/19 05:02:37 steve
|
||||
* handle duplicate connect to a nexus.
|
||||
*
|
||||
* Revision 1.90 1999/11/19 03:02:25 steve
|
||||
* Detect flip-flops connected to opads and turn
|
||||
* them into OUTFF devices. Inprove support for
|
||||
* the XNF-LCA attribute in the process.
|
||||
*
|
||||
* Revision 1.89 1999/11/18 03:52:19 steve
|
||||
* Turn NetTmp objects into normal local NetNet objects,
|
||||
* and add the nodangle functor to clean up the local
|
||||
* symbols generated by elaboration and other steps.
|
||||
*
|
||||
* Revision 1.88 1999/11/14 23:43:45 steve
|
||||
* Support combinatorial comparators.
|
||||
*
|
||||
* Revision 1.87 1999/11/14 20:24:28 steve
|
||||
* Add support for the LPM_CLSHIFT device.
|
||||
*
|
||||
* Revision 1.86 1999/11/05 04:40:40 steve
|
||||
* Patch to synthesize LPM_ADD_SUB from expressions,
|
||||
* Thanks to Larry Doolittle. Also handle constants
|
||||
* in expressions.
|
||||
*
|
||||
* Synthesize adders in XNF, based on a patch from
|
||||
* Larry. Accept synthesis of constants from Larry
|
||||
* as is.
|
||||
*
|
||||
* Revision 1.85 1999/11/04 03:53:26 steve
|
||||
* Patch to synthesize unary ~ and the ternary operator.
|
||||
* Thanks to Larry Doolittle <LRDoolittle@lbl.gov>.
|
||||
|
||||
+40
-7
@@ -16,7 +16,7 @@
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
|
||||
*/
|
||||
#ident "$Id: netlist.txt,v 1.5 1999/11/02 04:55:34 steve Exp $"
|
||||
#ident "$Id: netlist.txt,v 1.7 1999/11/28 23:42:02 steve Exp $"
|
||||
|
||||
|
||||
Note that the netlist.h header contains detailed descriptions of how
|
||||
@@ -114,6 +114,35 @@ and a NetProc. The NetAssign_ node has pins that represent the l-value
|
||||
of the statement, and carries behavioral expressions that represent
|
||||
the r-value of the assignment.
|
||||
|
||||
MEMORIES
|
||||
|
||||
The netlist form includes the NetMemory type to hold the content of a
|
||||
memory. Instances of this type represent the declaration of a memory,
|
||||
and occur once for each memory. References to the memory are managed
|
||||
by the NetEMemory and NetAssignMem_ classes.
|
||||
|
||||
An instance of the NetEMemory class is created whenever a procedural
|
||||
expression references a memory element. The operand is the index to
|
||||
use to address (and read) the memory.
|
||||
|
||||
An instance of the NetAssignMem_ class is created when there is a
|
||||
procedural assignment to the memory. The NetAssignMem_ object
|
||||
represents the l-value reference (a write) to the memory. As with the
|
||||
NetEMemory class, this is a procedural reference only.
|
||||
|
||||
When a memory reference appears in structural context (i.e. continuous
|
||||
assignments) elaboration creates a NetRamDq. This is a LPM_RAM_DQ
|
||||
device. Elaboration leaves the write control and data input pins
|
||||
unconnected for now, because memories cannot appear is l-values of
|
||||
continuous assignments. However, the synthesis functor may connect
|
||||
signals to the write control lines to get a fully operational RAM.
|
||||
|
||||
By the time elaboration completes, there may be many NetAssignMem_,
|
||||
NetEMemory and NetRamDq objects referencing the same NetMemory
|
||||
object. Each represents a port into the memory. It is up to the
|
||||
synthesis steps (and the target code) to figure out what to do with
|
||||
these ports.
|
||||
|
||||
EXPRESSIONS
|
||||
|
||||
Expressions are represented as a tree of NetExpr nodes. The NetExpr
|
||||
@@ -175,13 +204,10 @@ INTERACTION OF EXPRESSIONS AND STRUCTURE: NetESignal
|
||||
The NetAssign_ class described above is the means for processes to
|
||||
manipulate the net, but values are read from the net by NetESignal
|
||||
objects. These objects are class NetExpr because they can appear in
|
||||
expressions (and have width) but are also class NetNode because they
|
||||
connect to and receive signals from the structural aspects of the
|
||||
design.
|
||||
expressions (and have width). They are not NetNode object, but hold
|
||||
pointers to a NetNet object, which is used to retrieve values with the
|
||||
expression is evaluated.
|
||||
|
||||
The pins of a NetESignal object are passive. The values at the pin are
|
||||
only sampled when the process evaluates the expression that includes
|
||||
the NetESignal object.
|
||||
|
||||
HIERARCHY IN NETLISTS
|
||||
|
||||
@@ -214,6 +240,13 @@ some task calls. C++ programmers recognize this as inlining a task.)
|
||||
|
||||
|
||||
$Log: netlist.txt,v $
|
||||
Revision 1.7 1999/11/28 23:42:02 steve
|
||||
NetESignal object no longer need to be NetNode
|
||||
objects. Let them keep a pointer to NetNet objects.
|
||||
|
||||
Revision 1.6 1999/11/21 00:13:09 steve
|
||||
Support memories in continuous assignments.
|
||||
|
||||
Revision 1.5 1999/11/02 04:55:34 steve
|
||||
Add the synthesize method to NetExpr to handle
|
||||
synthesis of expressions, and use that method
|
||||
|
||||
+86
@@ -0,0 +1,86 @@
|
||||
/*
|
||||
* Copyright (c) 1999Stephen Williams (steve@icarus.com)
|
||||
*
|
||||
* This source code is free software; you can redistribute it
|
||||
* and/or modify it in source code form under the terms of the GNU
|
||||
* General Public License as published by the Free Software
|
||||
* Foundation; either version 2 of the License, or (at your option)
|
||||
* any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
|
||||
*/
|
||||
#if !defined(WINNT)
|
||||
#ident "$Id: nodangle.cc,v 1.2 1999/11/28 23:42:02 steve Exp $"
|
||||
#endif
|
||||
|
||||
/*
|
||||
* This functor scans the design looking for dangling objects and
|
||||
* excess local signals. These deletions are not necessarily required
|
||||
* for proper functioning of anything, but they can clean up the
|
||||
* appearance of design files that are generated.
|
||||
*/
|
||||
# include "functor.h"
|
||||
# include "netlist.h"
|
||||
|
||||
class nodangle_f : public functor_t {
|
||||
public:
|
||||
void signal(Design*des, NetNet*sig);
|
||||
};
|
||||
|
||||
|
||||
void nodangle_f::signal(Design*des, NetNet*sig)
|
||||
{
|
||||
if (! sig->local_flag())
|
||||
return;
|
||||
if (sig->get_eref() > 0)
|
||||
return;
|
||||
|
||||
/* Check to see if there is some significant signal connected
|
||||
to every pin of this signal. */
|
||||
unsigned significant_flags = 0;
|
||||
for (unsigned idx = 0 ; idx < sig->pin_count() ; idx += 1) {
|
||||
NetObj::Link&lnk = sig->pin(idx);
|
||||
for (NetObj::Link*cur = lnk.next_link()
|
||||
; cur != &lnk ; cur = cur->next_link()) {
|
||||
NetNet*cursig = dynamic_cast<NetNet*>(cur->get_obj());
|
||||
if (cursig == 0)
|
||||
continue;
|
||||
if (cursig->local_flag())
|
||||
continue;
|
||||
significant_flags += 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* If every pin is connected to another significant signal,
|
||||
then I can delete this one. */
|
||||
if (significant_flags == sig->pin_count())
|
||||
delete sig;
|
||||
}
|
||||
|
||||
void nodangle(Design*des)
|
||||
{
|
||||
nodangle_f fun;
|
||||
des->functor(&fun);
|
||||
}
|
||||
|
||||
/*
|
||||
* $Log: nodangle.cc,v $
|
||||
* Revision 1.2 1999/11/28 23:42:02 steve
|
||||
* NetESignal object no longer need to be NetNode
|
||||
* objects. Let them keep a pointer to NetNet objects.
|
||||
*
|
||||
* Revision 1.1 1999/11/18 03:52:20 steve
|
||||
* Turn NetTmp objects into normal local NetNet objects,
|
||||
* and add the nodangle functor to clean up the local
|
||||
* symbols generated by elaboration and other steps.
|
||||
*
|
||||
*/
|
||||
|
||||
@@ -19,7 +19,7 @@
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
|
||||
*/
|
||||
#if !defined(WINNT)
|
||||
#ident "$Id: parse.y,v 1.74 1999/10/15 05:03:33 steve Exp $"
|
||||
#ident "$Id: parse.y,v 1.76 1999/11/15 04:43:52 steve Exp $"
|
||||
#endif
|
||||
|
||||
# include "parse_misc.h"
|
||||
@@ -336,6 +336,23 @@ description
|
||||
}
|
||||
;
|
||||
|
||||
drive_strength
|
||||
: '(' dr_strength0 ',' dr_strength1 ')'
|
||||
| '(' dr_strength1 ',' dr_strength0 ')'
|
||||
| '(' dr_strength0 ',' K_highz1 ')'
|
||||
| '(' dr_strength1 ',' K_highz0 ')'
|
||||
| '(' K_highz1 ',' dr_strength0 ')'
|
||||
| '(' K_highz0 ',' dr_strength1 ')'
|
||||
;
|
||||
|
||||
drive_strength_opt
|
||||
: drive_strength
|
||||
|
|
||||
;
|
||||
|
||||
dr_strength0 : K_supply0 | K_strong0 | K_pull0 | K_weak0 ;
|
||||
dr_strength1 : K_supply1 | K_strong1 | K_pull1 | K_weak1 ;
|
||||
|
||||
event_control
|
||||
: '@' IDENTIFIER
|
||||
{ yyerror(@1, "sorry: event control not supported.");
|
||||
@@ -857,8 +874,7 @@ identifier
|
||||
: IDENTIFIER
|
||||
{ $$ = $1; }
|
||||
| HIDENTIFIER
|
||||
{ yyerror(@1, "sorry: qualified identifiers not supported.");
|
||||
$$ = $1;
|
||||
{ $$ = $1;
|
||||
}
|
||||
;
|
||||
|
||||
@@ -1061,8 +1077,8 @@ module_item
|
||||
{ pform_make_modgates($1, $2, $3);
|
||||
delete $1;
|
||||
}
|
||||
| K_assign delay_opt assign_list ';'
|
||||
{ pform_make_pgassign_list($3, $2, @1.text, @1.first_line); }
|
||||
| K_assign drive_strength_opt delay_opt assign_list ';'
|
||||
{ pform_make_pgassign_list($4, $3, @1.text, @1.first_line); }
|
||||
| K_assign error '=' expression ';'
|
||||
| K_always statement
|
||||
{ PProcess*tmp = pform_make_behavior(PProcess::PR_ALWAYS, $2);
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
|
||||
*/
|
||||
#if !defined(WINNT)
|
||||
#ident "$Id: pform.cc,v 1.46 1999/09/30 01:22:37 steve Exp $"
|
||||
#ident "$Id: pform.cc,v 1.47 1999/11/23 01:04:57 steve Exp $"
|
||||
#endif
|
||||
|
||||
# include "compiler.h"
|
||||
@@ -693,7 +693,10 @@ int pform_parse(const char*path, map<string,Module*>&modules,
|
||||
map<string,PUdp*>&prim)
|
||||
{
|
||||
vl_file = path;
|
||||
vl_input = fopen(path, "r");
|
||||
if (strcmp(path, "-") == 0)
|
||||
vl_input = stdin;
|
||||
else
|
||||
vl_input = fopen(path, "r");
|
||||
if (vl_input == 0) {
|
||||
cerr << "Unable to open " <<vl_file << "." << endl;
|
||||
return 11;
|
||||
@@ -714,6 +717,9 @@ int pform_parse(const char*path, map<string,Module*>&modules,
|
||||
|
||||
/*
|
||||
* $Log: pform.cc,v $
|
||||
* Revision 1.47 1999/11/23 01:04:57 steve
|
||||
* A file name of - means standard input.
|
||||
*
|
||||
* Revision 1.46 1999/09/30 01:22:37 steve
|
||||
* Handle declaration of integers (including scope) in functions.
|
||||
*
|
||||
|
||||
+23
-2
@@ -17,7 +17,7 @@
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
|
||||
*/
|
||||
#if !defined(WINNT)
|
||||
#ident "$Id: sigfold.cc,v 1.2 1998/12/02 04:37:13 steve Exp $"
|
||||
#ident "$Id: sigfold.cc,v 1.3 1999/11/06 04:51:11 steve Exp $"
|
||||
#endif
|
||||
|
||||
# include "netlist.h"
|
||||
@@ -83,6 +83,24 @@ static void clear_extra_signals(NetNet*net, unsigned npin)
|
||||
continue;
|
||||
}
|
||||
|
||||
if (NetTmp*tmp = dynamic_cast<NetTmp*>(sig)) {
|
||||
cerr << "internal warning: sigfold found NetTmp--"
|
||||
"deleting it." << endl;
|
||||
|
||||
// save the next link, ...
|
||||
NetObj*nxt;
|
||||
unsigned pnxt;
|
||||
cur->pin(pin).next_link(nxt, pnxt);
|
||||
|
||||
// disconnect the target signal, ...
|
||||
sig->pin(pin).unlink();
|
||||
|
||||
// And onward.
|
||||
cur = nxt;
|
||||
pin = pnxt;
|
||||
continue;
|
||||
}
|
||||
|
||||
// Skip the node if it has incompatible attributes.
|
||||
if (! net->has_compat_attributes(*sig)) {
|
||||
|
||||
@@ -152,10 +170,13 @@ void sigfold(Design*des)
|
||||
|
||||
/*
|
||||
* $Log: sigfold.cc,v $
|
||||
* Revision 1.3 1999/11/06 04:51:11 steve
|
||||
* Catch NetTmp objects.
|
||||
*
|
||||
* Revision 1.2 1998/12/02 04:37:13 steve
|
||||
* Add the nobufz function to eliminate bufz objects,
|
||||
* Object links are marked with direction,
|
||||
* constant propagation is more careful will wide links,
|
||||
* constant propagation is more careful with wide links,
|
||||
* Signal folding is aware of attributes, and
|
||||
* the XNF target can dump UDP objects based on LCA
|
||||
* attributes.
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
|
||||
*/
|
||||
#if !defined(WINNT)
|
||||
#ident "$Id: synth.cc,v 1.2 1999/11/02 04:55:34 steve Exp $"
|
||||
#ident "$Id: synth.cc,v 1.3 1999/12/01 06:06:16 steve Exp $"
|
||||
#endif
|
||||
|
||||
/*
|
||||
@@ -26,8 +26,12 @@
|
||||
* is especially interesting for the sequential components such as
|
||||
* flip flops and latches. As threads are transformed into components,
|
||||
* the design is rewritten.
|
||||
*
|
||||
* Currently, this transform recognizes the following patterns:
|
||||
*/
|
||||
# include "functor.h"
|
||||
# include "netlist.h"
|
||||
|
||||
/*
|
||||
* This transform recognizes the following patterns:
|
||||
*
|
||||
* always @(posedge CLK) Q = D
|
||||
* always @(negedge CLK) Q = D
|
||||
@@ -39,8 +43,105 @@
|
||||
* registers) and the CE must be single-bit identifiers. The generated
|
||||
* device will be wide enough to accomodate Q and D.
|
||||
*/
|
||||
# include "functor.h"
|
||||
# include "netlist.h"
|
||||
class match_dff : public proc_match_t {
|
||||
|
||||
public:
|
||||
match_dff(Design*d, NetProcTop*t)
|
||||
: des_(d), top_(t), pclk_(0), nclk_(0), con_(0), ce_(0),
|
||||
asn_(0), d_(0)
|
||||
{ }
|
||||
|
||||
~match_dff() { }
|
||||
|
||||
void make_it();
|
||||
|
||||
private:
|
||||
virtual int assign(NetAssign*);
|
||||
virtual int condit(NetCondit*);
|
||||
virtual int pevent(NetPEvent*);
|
||||
|
||||
Design*des_;
|
||||
NetProcTop*top_;
|
||||
NetPEvent*pclk_;
|
||||
NetNEvent*nclk_;
|
||||
|
||||
NetCondit *con_;
|
||||
NetNet*ce_;
|
||||
NetAssign *asn_;
|
||||
|
||||
NetNet*d_;
|
||||
};
|
||||
|
||||
int match_dff::assign(NetAssign*as)
|
||||
{
|
||||
if (!pclk_)
|
||||
return 0;
|
||||
if (asn_)
|
||||
return 0;
|
||||
|
||||
asn_ = as;
|
||||
d_ = asn_->rval()->synthesize(des_);
|
||||
if (d_ == 0)
|
||||
return 0;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int match_dff::condit(NetCondit*co)
|
||||
{
|
||||
if (!pclk_)
|
||||
return 0;
|
||||
if (con_ || asn_)
|
||||
return 0;
|
||||
|
||||
con_ = co;
|
||||
if (con_->else_clause())
|
||||
return 0;
|
||||
ce_ = con_->expr()->synthesize(des_);
|
||||
if (ce_ == 0)
|
||||
return 0;
|
||||
|
||||
return con_->if_clause()->match_proc(this);
|
||||
}
|
||||
|
||||
int match_dff::pevent(NetPEvent*pe)
|
||||
{
|
||||
if (pclk_ || con_ || asn_)
|
||||
return 0;
|
||||
|
||||
pclk_ = pe;
|
||||
|
||||
// ... there must be a single event source, ...
|
||||
svector<class NetNEvent*>*neb = pclk_->back_list();
|
||||
if (neb == 0)
|
||||
return 0;
|
||||
if (neb->count() != 1) {
|
||||
delete neb;
|
||||
return 0;
|
||||
}
|
||||
nclk_ = (*neb)[0];
|
||||
delete neb;
|
||||
return pclk_->statement()->match_proc(this);
|
||||
}
|
||||
|
||||
void match_dff::make_it()
|
||||
{
|
||||
NetFF*ff = new NetFF(asn_->name(), asn_->pin_count());
|
||||
|
||||
for (unsigned idx = 0 ; idx < ff->width() ; idx += 1) {
|
||||
connect(ff->pin_Data(idx), d_->pin(idx));
|
||||
connect(ff->pin_Q(idx), asn_->pin(idx));
|
||||
}
|
||||
|
||||
connect(ff->pin_Clock(), nclk_->pin(0));
|
||||
if (ce_) connect(ff->pin_Enable(), ce_->pin(0));
|
||||
|
||||
ff->attribute("LPM_FFType", "DFF");
|
||||
if (nclk_->type() == NetNEvent::NEGEDGE)
|
||||
ff->attribute("Clock:LPM_Polarity", "INVERT");
|
||||
|
||||
des_->add_node(ff);
|
||||
}
|
||||
|
||||
class synth_f : public functor_t {
|
||||
|
||||
@@ -49,20 +150,8 @@ class synth_f : public functor_t {
|
||||
|
||||
private:
|
||||
void proc_always_(class Design*);
|
||||
void proc_casn_(class Design*);
|
||||
void proc_ccon_(class Design*);
|
||||
|
||||
// The matcher does something like a recursive descent search
|
||||
// for the templates. These variables are filled in as the
|
||||
// searcher finds them.
|
||||
|
||||
class NetProcTop*top_;
|
||||
|
||||
class NetPEvent *pclk_;
|
||||
class NetNEvent *nclk_;
|
||||
|
||||
class NetCondit *con_;
|
||||
class NetAssign *asn_;
|
||||
NetProcTop*top_;
|
||||
};
|
||||
|
||||
|
||||
@@ -85,141 +174,14 @@ void synth_f::process(class Design*des, class NetProcTop*top)
|
||||
*/
|
||||
void synth_f::proc_always_(class Design*des)
|
||||
{
|
||||
// The statement must be a NetPEvent, ...
|
||||
pclk_ = dynamic_cast<class NetPEvent*>(top_->statement());
|
||||
if (pclk_ == 0)
|
||||
return;
|
||||
|
||||
// ... there must be a single event source, ...
|
||||
svector<class NetNEvent*>*neb = pclk_->back_list();
|
||||
if (neb == 0)
|
||||
return;
|
||||
if (neb->count() != 1) {
|
||||
delete neb;
|
||||
return;
|
||||
}
|
||||
nclk_ = (*neb)[0];
|
||||
delete neb;
|
||||
|
||||
// ... the event must be an edge, ...
|
||||
switch (nclk_->type()) {
|
||||
case NetNEvent::POSEDGE:
|
||||
case NetNEvent::NEGEDGE:
|
||||
break;
|
||||
default:
|
||||
return;
|
||||
}
|
||||
|
||||
// Is this a clocked assignment?
|
||||
asn_ = dynamic_cast<NetAssign*>(pclk_->statement());
|
||||
if (asn_) {
|
||||
proc_casn_(des);
|
||||
return;
|
||||
}
|
||||
|
||||
con_ = dynamic_cast<NetCondit*>(pclk_->statement());
|
||||
if (con_) {
|
||||
proc_ccon_(des);
|
||||
match_dff dff_pat(des, top_);
|
||||
if (top_->statement()->match_proc(&dff_pat)) {
|
||||
dff_pat.make_it();
|
||||
des->delete_process(top_);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* The process so far has been matched as:
|
||||
*
|
||||
* always @(posedge nclk_) asn_ = <r>;
|
||||
* always @(negedge nclk_) asn_ = <r>;
|
||||
*/
|
||||
void synth_f::proc_casn_(class Design*des)
|
||||
{
|
||||
// Turn the r-value into gates.
|
||||
NetNet*sig = asn_->rval()->synthesize(des);
|
||||
assert(sig);
|
||||
|
||||
// The signal and the assignment must be the same width...
|
||||
assert(asn_->pin_count() == sig->pin_count());
|
||||
|
||||
NetFF*ff = new NetFF(asn_->name(), asn_->pin_count());
|
||||
ff->attribute("LPM_FFType", "DFF");
|
||||
|
||||
for (unsigned idx = 0 ; idx < ff->width() ; idx += 1) {
|
||||
connect(ff->pin_Data(idx), sig->pin(idx));
|
||||
connect(ff->pin_Q(idx), asn_->pin(idx));
|
||||
}
|
||||
|
||||
switch (nclk_->type()) {
|
||||
case NetNEvent::POSEDGE:
|
||||
connect(ff->pin_Clock(), nclk_->pin(0));
|
||||
break;
|
||||
|
||||
case NetNEvent::NEGEDGE:
|
||||
connect(ff->pin_Clock(), nclk_->pin(0));
|
||||
ff->attribute("Clock:LPM_Polarity", "INVERT");
|
||||
break;
|
||||
}
|
||||
|
||||
des->add_node(ff);
|
||||
|
||||
// This process is matched and replaced with a DFF. Get
|
||||
// rid of the now useless NetProcTop.
|
||||
des->delete_process(top_);
|
||||
}
|
||||
|
||||
/*
|
||||
* The process so far has been matched as:
|
||||
*
|
||||
* always @(posedge nclk_) if ...;
|
||||
* always @(negedge nclk_) if ...;
|
||||
*/
|
||||
void synth_f::proc_ccon_(class Design*des)
|
||||
{
|
||||
if (con_->else_clause())
|
||||
return;
|
||||
|
||||
asn_ = dynamic_cast<NetAssign*>(con_->if_clause());
|
||||
if (asn_ == 0)
|
||||
return;
|
||||
|
||||
NetNet*sig = asn_->rval()->synthesize(des);
|
||||
assert(sig);
|
||||
|
||||
// The signal and the assignment must be the same width...
|
||||
assert(asn_->pin_count() == sig->pin_count());
|
||||
|
||||
NetESignal*ce = dynamic_cast<NetESignal*>(con_->expr());
|
||||
if (ce == 0)
|
||||
return;
|
||||
if (ce->pin_count() != 1)
|
||||
return;
|
||||
|
||||
NetFF*ff = new NetFF(asn_->name(), asn_->pin_count());
|
||||
ff->attribute("LPM_FFType", "DFF");
|
||||
|
||||
for (unsigned idx = 0 ; idx < ff->width() ; idx += 1) {
|
||||
connect(ff->pin_Data(idx), sig->pin(idx));
|
||||
connect(ff->pin_Q(idx), asn_->pin(idx));
|
||||
}
|
||||
|
||||
switch (nclk_->type()) {
|
||||
case NetNEvent::POSEDGE:
|
||||
connect(ff->pin_Clock(), nclk_->pin(0));
|
||||
connect(ff->pin_Enable(), ce->pin(0));
|
||||
break;
|
||||
|
||||
case NetNEvent::NEGEDGE:
|
||||
connect(ff->pin_Clock(), nclk_->pin(0));
|
||||
connect(ff->pin_Enable(), ce->pin(0));
|
||||
ff->attribute("Clock:LPM_Polarity", "INVERT");
|
||||
break;
|
||||
}
|
||||
|
||||
des->add_node(ff);
|
||||
|
||||
|
||||
// This process is matched and replaced with a DFF. Get
|
||||
// rid of the now useless NetProcTop.
|
||||
des->delete_process(top_);
|
||||
}
|
||||
|
||||
void synth(Design*des)
|
||||
{
|
||||
@@ -229,6 +191,9 @@ void synth(Design*des)
|
||||
|
||||
/*
|
||||
* $Log: synth.cc,v $
|
||||
* Revision 1.3 1999/12/01 06:06:16 steve
|
||||
* Redo synth to use match_proc_t scanner.
|
||||
*
|
||||
* Revision 1.2 1999/11/02 04:55:34 steve
|
||||
* Add the synthesize method to NetExpr to handle
|
||||
* synthesis of expressions, and use that method
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
|
||||
*/
|
||||
#if !defined(WINNT)
|
||||
#ident "$Id: t-vvm.cc,v 1.71 1999/11/01 02:07:41 steve Exp $"
|
||||
#ident "$Id: t-vvm.cc,v 1.87 1999/12/02 16:58:58 steve Exp $"
|
||||
#endif
|
||||
|
||||
# include <iostream>
|
||||
@@ -30,6 +30,13 @@
|
||||
# include "netlist.h"
|
||||
# include "target.h"
|
||||
|
||||
// Comparison for use in sorting algorithms.
|
||||
|
||||
struct less_verinum {
|
||||
bool operator() (const verinum&left, const verinum&right)
|
||||
{ return left.is_before(right); }
|
||||
};
|
||||
|
||||
static string make_temp()
|
||||
{
|
||||
static unsigned counter = 0;
|
||||
@@ -47,13 +54,18 @@ class target_vvm : public target_t {
|
||||
target_vvm();
|
||||
|
||||
virtual void start_design(ostream&os, const Design*);
|
||||
virtual void scope(ostream&os, const NetScope*);
|
||||
virtual void signal(ostream&os, const NetNet*);
|
||||
virtual void memory(ostream&os, const NetMemory*);
|
||||
virtual void task_def(ostream&os, const NetTaskDef*);
|
||||
virtual void func_def(ostream&os, const NetFuncDef*);
|
||||
|
||||
virtual void lpm_add_sub(ostream&os, const NetAddSub*);
|
||||
virtual void lpm_clshift(ostream&os, const NetCLShift*);
|
||||
virtual void lpm_compare(ostream&os, const NetCompare*);
|
||||
virtual void lpm_ff(ostream&os, const NetFF*);
|
||||
virtual void lpm_mux(ostream&os, const NetMux*);
|
||||
virtual void lpm_ram_dq(ostream&os, const NetRamDq*);
|
||||
|
||||
virtual void logic(ostream&os, const NetLogic*);
|
||||
virtual void bufz(ostream&os, const NetBUFZ*);
|
||||
@@ -61,7 +73,6 @@ class target_vvm : public target_t {
|
||||
virtual void net_assign_nb(ostream&os, const NetAssignNB*);
|
||||
virtual void net_case_cmp(ostream&os, const NetCaseCmp*);
|
||||
virtual void net_const(ostream&os, const NetConst*);
|
||||
virtual void net_esignal(ostream&os, const NetESignal*);
|
||||
virtual void net_event(ostream&os, const NetNEvent*);
|
||||
virtual bool process(ostream&os, const NetProcTop*);
|
||||
virtual void proc_assign(ostream&os, const NetAssign*);
|
||||
@@ -115,6 +126,9 @@ class target_vvm : public target_t {
|
||||
// handle name mapped by this.
|
||||
map<string,unsigned>string_constants;
|
||||
unsigned string_counter;
|
||||
|
||||
map<verinum,unsigned,less_verinum>number_constants;
|
||||
unsigned number_counter;
|
||||
};
|
||||
|
||||
|
||||
@@ -144,15 +158,7 @@ class vvm_proc_rval : public expr_scan_t {
|
||||
virtual void expr_const(const NetEConst*);
|
||||
virtual void expr_concat(const NetEConcat*);
|
||||
virtual void expr_ident(const NetEIdent*);
|
||||
virtual void expr_memory(const NetEMemory*mem)
|
||||
{
|
||||
mem->index()->expr_scan(this);
|
||||
string idx = make_temp();
|
||||
os_ << setw(indent_) << "" << "const unsigned " <<
|
||||
idx << " = " << result << ".as_unsigned();" <<
|
||||
endl;
|
||||
result = mangle(mem->name()) + "[" + idx + "]";
|
||||
}
|
||||
virtual void expr_memory(const NetEMemory*mem);
|
||||
virtual void expr_signal(const NetESignal*);
|
||||
virtual void expr_subsignal(const NetESubSignal*sig);
|
||||
virtual void expr_ternary(const NetETernary*);
|
||||
@@ -233,6 +239,13 @@ void vvm_proc_rval::expr_ident(const NetEIdent*expr)
|
||||
result = mangle(expr->name());
|
||||
}
|
||||
|
||||
void vvm_proc_rval::expr_memory(const NetEMemory*mem)
|
||||
{
|
||||
const string mname = mangle(mem->name());
|
||||
mem->index()->expr_scan(this);
|
||||
result = mname + ".get_word(" + result + ".as_unsigned())";
|
||||
}
|
||||
|
||||
void vvm_proc_rval::expr_signal(const NetESignal*expr)
|
||||
{
|
||||
result = mangle(expr->name()) + "_bits";
|
||||
@@ -470,8 +483,10 @@ class vvm_parm_rval : public expr_scan_t {
|
||||
string result;
|
||||
|
||||
private:
|
||||
virtual void expr_const(const NetEConst*expr);
|
||||
virtual void expr_const(const NetEConst*);
|
||||
virtual void expr_ident(const NetEIdent*);
|
||||
virtual void expr_memory(const NetEMemory*);
|
||||
virtual void expr_scope(const NetEScope*);
|
||||
virtual void expr_signal(const NetESignal*);
|
||||
|
||||
private:
|
||||
@@ -498,33 +513,40 @@ void vvm_parm_rval::expr_const(const NetEConst*expr)
|
||||
return;
|
||||
}
|
||||
|
||||
string tname = make_temp();
|
||||
tgt_->defn << " vvm_bitset_t<" <<
|
||||
expr->expr_width() << "> " << tname << ";" << endl;
|
||||
for (unsigned idx = 0 ; idx < expr->expr_width() ; idx += 1) {
|
||||
tgt_->defn << " " << tname << "[" << idx << "] = ";
|
||||
switch (expr->value().get(idx)) {
|
||||
case verinum::V0:
|
||||
tgt_->defn << "V0";
|
||||
break;
|
||||
case verinum::V1:
|
||||
tgt_->defn << "V1";
|
||||
break;
|
||||
case verinum::Vx:
|
||||
tgt_->defn << "Vx";
|
||||
break;
|
||||
case verinum::Vz:
|
||||
tgt_->defn << "Vz";
|
||||
break;
|
||||
unsigned&res = tgt_->number_constants[expr->value()];
|
||||
if (res == 0) {
|
||||
res = tgt_->number_counter ++;
|
||||
unsigned width = expr->expr_width();
|
||||
tgt_->init_code << " { vpip_bit_t*bits = new vpip_bit_t["
|
||||
<< width << "];" << endl;
|
||||
|
||||
for (unsigned idx = 0 ; idx < width ; idx += 1) {
|
||||
tgt_->init_code << " bits[" << idx << "] = ";
|
||||
switch(expr->value().get(idx)) {
|
||||
case verinum::V0:
|
||||
tgt_->init_code << "V0;" << endl;
|
||||
break;
|
||||
case verinum::V1:
|
||||
tgt_->init_code << "V1;" << endl;
|
||||
break;
|
||||
case verinum::Vx:
|
||||
tgt_->init_code << "Vx;" << endl;
|
||||
break;
|
||||
case verinum::Vz:
|
||||
tgt_->init_code << "Vz;" << endl;
|
||||
break;
|
||||
}
|
||||
}
|
||||
tgt_->defn << ";" << endl;
|
||||
tgt_->init_code << " vpip_make_number_const("
|
||||
"&number_table[" << res << "], bits, " << width <<
|
||||
");" << endl;
|
||||
tgt_->init_code << " }" << endl;
|
||||
}
|
||||
|
||||
result = make_temp();
|
||||
tgt_->defn << " struct __vpiHandle " << result << ";" << endl;
|
||||
tgt_->defn << " vvm_make_vpi_parm(&" << result << ", &"
|
||||
<< tname << ");" << endl;
|
||||
result = "&" + result;
|
||||
ostrstream tmp;
|
||||
tmp << "&number_table[" << res << "].base" << ends;
|
||||
result = tmp.str();
|
||||
return;
|
||||
}
|
||||
|
||||
void vvm_parm_rval::expr_ident(const NetEIdent*expr)
|
||||
@@ -536,6 +558,17 @@ void vvm_parm_rval::expr_ident(const NetEIdent*expr)
|
||||
}
|
||||
}
|
||||
|
||||
void vvm_parm_rval::expr_memory(const NetEMemory*mem)
|
||||
{
|
||||
assert(mem->index() == 0);
|
||||
result = string("&") + mangle(mem->name()) + ".base";
|
||||
}
|
||||
|
||||
void vvm_parm_rval::expr_scope(const NetEScope*escope)
|
||||
{
|
||||
result = string("&") + mangle(escope->scope()->name()) + "_scope.base";
|
||||
}
|
||||
|
||||
void vvm_parm_rval::expr_signal(const NetESignal*expr)
|
||||
{
|
||||
string res = string("&") + mangle(expr->name()) + ".base";
|
||||
@@ -573,8 +606,10 @@ void target_vvm::start_design(ostream&os, const Design*mod)
|
||||
|
||||
process_counter = 0;
|
||||
string_counter = 1;
|
||||
number_counter = 1;
|
||||
|
||||
os << "static struct __vpiStringConst string_table[];" << endl;
|
||||
os << "static struct __vpiNumberConst number_table[];" << endl;
|
||||
|
||||
init_code << "static void design_init(vvm_simulation&sim)" << endl;
|
||||
init_code << "{" << endl;
|
||||
@@ -584,10 +619,35 @@ void target_vvm::start_design(ostream&os, const Design*mod)
|
||||
start_code << "{" << endl;
|
||||
}
|
||||
|
||||
void target_vvm::scope(ostream&os, const NetScope*scope)
|
||||
{
|
||||
string hname = mangle(scope->name()) + "_scope";
|
||||
os << "// SCOPE: " << scope->name() << endl;
|
||||
os << "static struct __vpiScope " << hname << ";" << endl;
|
||||
|
||||
string type_code;
|
||||
switch (scope->type()) {
|
||||
case NetScope::MODULE:
|
||||
type_code = "vpiModule";
|
||||
break;
|
||||
case NetScope::BEGIN_END:
|
||||
type_code = "vpiNamedBegin";
|
||||
break;
|
||||
case NetScope::FORK_JOIN:
|
||||
type_code = "vpiNamedFork";
|
||||
break;
|
||||
}
|
||||
|
||||
init_code << " vpip_make_scope(&" << hname << ", " <<
|
||||
type_code << ", \"" << scope->name() << "\");" << endl;
|
||||
}
|
||||
|
||||
void target_vvm::end_design(ostream&os, const Design*mod)
|
||||
{
|
||||
os << "static struct __vpiStringConst string_table[" <<
|
||||
string_counter+1 << "];" << endl;
|
||||
os << "static struct __vpiNumberConst number_table[" <<
|
||||
number_counter+1 << "];" << endl;
|
||||
|
||||
defn.close();
|
||||
os << "// **** Definition code" << endl;
|
||||
@@ -635,6 +695,10 @@ void target_vvm::end_design(ostream&os, const Design*mod)
|
||||
|
||||
|
||||
os << "main()" << endl << "{" << endl;
|
||||
string vpi_module_path = mod->get_flag("VPI_MODULE_PATH");
|
||||
if (vpi_module_path.length() > 0)
|
||||
os << " vvm_set_module_path(\"" << vpi_module_path <<
|
||||
"\");" << endl;
|
||||
os << " vvm_load_vpi_module(\"system.vpi\");" << endl;
|
||||
os << " vvm_simulation sim;" << endl;
|
||||
os << " design_init(sim);" << endl;
|
||||
@@ -658,6 +722,22 @@ bool target_vvm::process(ostream&os, const NetProcTop*top)
|
||||
|
||||
void target_vvm::signal(ostream&os, const NetNet*sig)
|
||||
{
|
||||
string net_name = mangle(sig->name());
|
||||
os << "static vvm_bitset_t<" << sig->pin_count() << "> " <<
|
||||
net_name<< "_bits; /* " << sig->name() <<
|
||||
" */" << endl;
|
||||
os << "static vvm_signal_t<" << sig->pin_count() << "> " <<
|
||||
net_name << "(&" << net_name << "_bits);" << endl;
|
||||
|
||||
init_code << " vpip_make_reg(&" << net_name <<
|
||||
", \"" << sig->name() << "\");" << endl;
|
||||
|
||||
if (const NetScope*scope = sig->scope()) {
|
||||
string sname = mangle(scope->name()) + "_scope";
|
||||
init_code << " vpip_attach_to_scope(&" << sname
|
||||
<< ", &" << net_name << ".base);" << endl;
|
||||
}
|
||||
|
||||
|
||||
/* Scan the signals of the vector, passing the initial value
|
||||
to the inputs of all the connected devices. */
|
||||
@@ -667,6 +747,10 @@ void target_vvm::signal(ostream&os, const NetNet*sig)
|
||||
|
||||
map<string,bool>written;
|
||||
|
||||
init_code << " " << mangle(sig->name()) << ".init_P("
|
||||
<< idx << ", V" << sig->get_ival(idx) << ");"
|
||||
<< endl;
|
||||
|
||||
for (const NetObj::Link*lnk = sig->pin(idx).next_link()
|
||||
; (*lnk) != sig->pin(idx) ; lnk = lnk->next_link()) {
|
||||
|
||||
@@ -696,9 +780,13 @@ void target_vvm::signal(ostream&os, const NetNet*sig)
|
||||
|
||||
void target_vvm::memory(ostream&os, const NetMemory*mem)
|
||||
{
|
||||
os << "static vvm_bitset_t<" << mem->width() << "> " <<
|
||||
mangle(mem->name()) << "[" << mem->count() << "]; " <<
|
||||
"/* " << mem->name() << " */" << endl;
|
||||
const string mname = mangle(mem->name());
|
||||
os << "static vvm_memory_t<" << mem->width() << ", " <<
|
||||
mem->count() << "> " << mname << ";"
|
||||
" /* " << mem->name() << " */" << endl;
|
||||
init_code << " vpip_make_memory(&" << mname << ", \"" <<
|
||||
mem->name() << "\", " << mem->width() << ", " <<
|
||||
mem->count() << ");" << endl;
|
||||
}
|
||||
|
||||
void target_vvm::task_def(ostream&os, const NetTaskDef*def)
|
||||
@@ -792,9 +880,7 @@ void target_vvm::emit_gate_outputfun_(const NetNode*gate, unsigned gpin)
|
||||
gate->pin(gpin).next_link(cur, pin);
|
||||
while (cur != gate) {
|
||||
|
||||
if (dynamic_cast<const NetNet*>(cur)) {
|
||||
// Skip signals
|
||||
} else if (cur->pin(pin).get_name() != "") {
|
||||
if (cur->pin(pin).get_name() != "") {
|
||||
|
||||
delayed << " " << mangle(cur->name()) << ".set_"
|
||||
<< cur->pin(pin).get_name() << "(sim, " <<
|
||||
@@ -836,6 +922,59 @@ void target_vvm::lpm_add_sub(ostream&os, const NetAddSub*gate)
|
||||
}
|
||||
}
|
||||
|
||||
void target_vvm::lpm_clshift(ostream&os, const NetCLShift*gate)
|
||||
{
|
||||
os << "static vvm_clshift<" << gate->width() << "," <<
|
||||
gate->width_dist() << "> " << mangle(gate->name()) << ";"
|
||||
<< endl;
|
||||
|
||||
for (unsigned idx = 0 ; idx < gate->width() ; idx += 1) {
|
||||
unsigned pin = gate->pin_Result(idx).get_pin();
|
||||
string outfun = defn_gate_outputfun_(os, gate, pin);
|
||||
init_code << " " << mangle(gate->name()) <<
|
||||
".config_rout(" << idx << ", &" << outfun << ");" << endl;
|
||||
emit_gate_outputfun_(gate, pin);
|
||||
}
|
||||
}
|
||||
|
||||
void target_vvm::lpm_compare(ostream&os, const NetCompare*gate)
|
||||
{
|
||||
os << "static vvm_compare<" << gate->width() << "> " <<
|
||||
mangle(gate->name()) << ";" << endl;
|
||||
|
||||
if (gate->pin_ALB().is_linked()) {
|
||||
unsigned pin = gate->pin_ALB().get_pin();
|
||||
string outfun = defn_gate_outputfun_(os,gate,pin);
|
||||
init_code << " " << mangle(gate->name()) <<
|
||||
".config_ALB_out(&" << outfun << ");" << endl;
|
||||
emit_gate_outputfun_(gate,pin);
|
||||
}
|
||||
|
||||
if (gate->pin_ALEB().is_linked()) {
|
||||
unsigned pin = gate->pin_ALEB().get_pin();
|
||||
string outfun = defn_gate_outputfun_(os, gate, pin);
|
||||
init_code << " " << mangle(gate->name()) <<
|
||||
".config_ALEB_out(&" << outfun << ");" << endl;
|
||||
emit_gate_outputfun_(gate, pin);
|
||||
}
|
||||
|
||||
if (gate->pin_AGB().is_linked()) {
|
||||
unsigned pin = gate->pin_AGB().get_pin();
|
||||
string outfun = defn_gate_outputfun_(os,gate,pin);
|
||||
init_code << " " << mangle(gate->name()) <<
|
||||
".config_AGB_out(&" << outfun << ");" << endl;
|
||||
emit_gate_outputfun_(gate,pin);
|
||||
}
|
||||
|
||||
if (gate->pin_AGEB().is_linked()) {
|
||||
unsigned pin = gate->pin_AGEB().get_pin();
|
||||
string outfun = defn_gate_outputfun_(os, gate, pin);
|
||||
init_code << " " << mangle(gate->name()) <<
|
||||
".config_AGEB_out(&" << outfun << ");" << endl;
|
||||
emit_gate_outputfun_(gate, pin);
|
||||
}
|
||||
}
|
||||
|
||||
void target_vvm::lpm_ff(ostream&os, const NetFF*gate)
|
||||
{
|
||||
string mname = mangle(gate->name());
|
||||
@@ -851,6 +990,37 @@ void target_vvm::lpm_ff(ostream&os, const NetFF*gate)
|
||||
}
|
||||
}
|
||||
|
||||
void target_vvm::lpm_mux(ostream&os, const NetMux*mux)
|
||||
{
|
||||
string mname = mangle(mux->name());
|
||||
os << "static vvm_mux<" << mux->width() << "," << mux->size() <<
|
||||
"," << mux->sel_width() << "> " << mname << ";" << endl;
|
||||
|
||||
for (unsigned idx = 0 ; idx < mux->width() ; idx += 1) {
|
||||
unsigned pin = mux->pin_Result(idx).get_pin();
|
||||
string outfun = defn_gate_outputfun_(os, mux, pin);
|
||||
init_code << " " << mangle(mux->name()) <<
|
||||
".config_rout(" << idx << ", &" << outfun << ");" << endl;
|
||||
emit_gate_outputfun_(mux, pin);
|
||||
}
|
||||
}
|
||||
|
||||
void target_vvm::lpm_ram_dq(ostream&os, const NetRamDq*ram)
|
||||
{
|
||||
string mname = mangle(ram->name());
|
||||
os << "static vvm_ram_dq<" << ram->width() << "," <<
|
||||
ram->awidth() << "," << ram->size() << "> " << mname <<
|
||||
"(&" << mangle(ram->mem()->name()) << ");" << endl;
|
||||
|
||||
for (unsigned idx = 0 ; idx < ram->width() ; idx += 1) {
|
||||
unsigned pin = ram->pin_Q(idx).get_pin();
|
||||
string outfun = defn_gate_outputfun_(os, ram, pin);
|
||||
init_code << " " << mangle(ram->name()) <<
|
||||
".config_rout(" << idx << ", &" << outfun << ");" << endl;
|
||||
emit_gate_outputfun_(ram, pin);
|
||||
}
|
||||
}
|
||||
|
||||
void target_vvm::logic(ostream&os, const NetLogic*gate)
|
||||
{
|
||||
string outfun = defn_gate_outputfun_(os, gate, 0);
|
||||
@@ -860,6 +1030,9 @@ void target_vvm::logic(ostream&os, const NetLogic*gate)
|
||||
os << "static vvm_and" << "<" << gate->pin_count()-1 <<
|
||||
"," << gate->rise_time() << "> ";
|
||||
break;
|
||||
case NetLogic::BUF:
|
||||
os << "static vvm_buf<" << gate->rise_time() << "> ";
|
||||
break;
|
||||
case NetLogic::BUFIF0:
|
||||
os << "static vvm_bufif0<" << gate->rise_time() << "> ";
|
||||
break;
|
||||
@@ -889,6 +1062,9 @@ void target_vvm::logic(ostream&os, const NetLogic*gate)
|
||||
os << "static vvm_xor" << "<" << gate->pin_count()-1 <<
|
||||
"," << gate->rise_time() << "> ";
|
||||
break;
|
||||
default:
|
||||
os << "#error \"internal ivl error:bad gate type for " <<
|
||||
gate->name() << "\"" << endl;
|
||||
}
|
||||
|
||||
os << mangle(gate->name()) << "(&" << outfun << ");" << endl;
|
||||
@@ -1042,11 +1218,6 @@ void target_vvm::net_assign_nb(ostream&os, const NetAssignNB*net)
|
||||
if (cur->pin(pin).get_dir() == NetObj::Link::OUTPUT)
|
||||
continue;
|
||||
|
||||
// Skip signals, I'll hit them when I handle the
|
||||
// NetESignal nodes.
|
||||
if (dynamic_cast<const NetNet*>(cur))
|
||||
continue;
|
||||
|
||||
delayed << " " << mangle(cur->name())
|
||||
<< ".set_" << lnk.get_name() << "sim_, "
|
||||
<< lnk.get_inst() << ", value_[0]);" << endl;
|
||||
@@ -1074,11 +1245,6 @@ void target_vvm::net_assign_nb(ostream&os, const NetAssignNB*net)
|
||||
if (cur->pin(pin).get_dir() == NetObj::Link::OUTPUT)
|
||||
continue;
|
||||
|
||||
// Skip signals, I'll hit them when I handle the
|
||||
// NetESignal nodes.
|
||||
if (dynamic_cast<const NetNet*>(cur))
|
||||
continue;
|
||||
|
||||
delayed << " " << mangle(cur->name()) <<
|
||||
".set_" << lnk.get_name() << "(sim_, "
|
||||
<< lnk.get_inst() << ", value_[" <<
|
||||
@@ -1091,13 +1257,16 @@ void target_vvm::net_assign_nb(ostream&os, const NetAssignNB*net)
|
||||
|
||||
void target_vvm::net_case_cmp(ostream&os, const NetCaseCmp*gate)
|
||||
{
|
||||
const NetObj::Link&lnk = gate->pin(0);
|
||||
|
||||
os << "static void " << mangle(gate->name()) <<
|
||||
"_output_fun(vvm_simulation*, vpip_bit_t);" << endl;
|
||||
"_output_" << lnk.get_name() << "_" << lnk.get_inst() <<
|
||||
"(vvm_simulation*, vpip_bit_t);" << endl;
|
||||
|
||||
assert(gate->pin_count() == 3);
|
||||
os << "static vvm_eeq" << "<" << gate->rise_time() << "> "
|
||||
<< mangle(gate->name()) << "(&" << mangle(gate->name()) <<
|
||||
"_output_fun);" << endl;
|
||||
"_output_" << lnk.get_name() << "_" << lnk.get_inst() << ");" << endl;
|
||||
|
||||
emit_gate_outputfun_(gate, 0);
|
||||
|
||||
@@ -1138,24 +1307,6 @@ void target_vvm::net_const(ostream&os, const NetConst*gate)
|
||||
emit_gate_outputfun_(gate, 0);
|
||||
}
|
||||
|
||||
void target_vvm::net_esignal(ostream&os, const NetESignal*net)
|
||||
{
|
||||
bool&flag = esignal_printed_flag[net->name()];
|
||||
if (flag)
|
||||
return;
|
||||
|
||||
flag = true;
|
||||
string net_name = mangle(net->name());
|
||||
os << "static vvm_bitset_t<" << net->pin_count() << "> " <<
|
||||
net_name<< "_bits; /* " << net->name() <<
|
||||
" */" << endl;
|
||||
os << "static vvm_signal_t<" << net->pin_count() << "> " <<
|
||||
net_name << "(&" << net_name << "_bits);" << endl;
|
||||
|
||||
init_code << " vpip_make_reg(&" << net_name <<
|
||||
", \"" << net->name() << "\");" << endl;
|
||||
}
|
||||
|
||||
/*
|
||||
* The net_event device is a synthetic device type--a fabrication of
|
||||
* the elaboration phase. An event device receives value changes from
|
||||
@@ -1255,11 +1406,6 @@ void target_vvm::proc_assign(ostream&os, const NetAssign*net)
|
||||
if (cur->pin(pin).get_dir() == NetObj::Link::OUTPUT)
|
||||
continue;
|
||||
|
||||
// Skip signals, I'll hit them when I handle the
|
||||
// NetESignal nodes.
|
||||
if (dynamic_cast<const NetNet*>(cur))
|
||||
continue;
|
||||
|
||||
// It is possible for a named device to show up
|
||||
// several times in a link. This is the classic
|
||||
// case with NetESignal objects, which are
|
||||
@@ -1296,11 +1442,6 @@ void target_vvm::proc_assign(ostream&os, const NetAssign*net)
|
||||
if (cur->pin(pin).get_dir() == NetObj::Link::OUTPUT)
|
||||
continue;
|
||||
|
||||
// Skip signals, I'll hit them when I handle the
|
||||
// NetESignal nodes.
|
||||
if (dynamic_cast<const NetNet*>(cur))
|
||||
continue;
|
||||
|
||||
// It is possible for a named device to show up
|
||||
// several times in a link. This is the classic
|
||||
// case with NetESignal objects, which are
|
||||
@@ -1331,9 +1472,9 @@ void target_vvm::proc_assign_mem(ostream&os, const NetAssignMem*amem)
|
||||
|
||||
defn << " /* " << amem->get_line() << " */" << endl;
|
||||
if (mem->width() == amem->rval()->expr_width()) {
|
||||
defn << " " << mangle(mem->name())
|
||||
<< "[" << index << ".as_unsigned()] = " << rval <<
|
||||
";" << endl;
|
||||
defn << " " << mangle(mem->name()) <<
|
||||
".set_word(sim_, " << index << ".as_unsigned(), " <<
|
||||
rval << ");" << endl;
|
||||
|
||||
} else {
|
||||
assert(mem->width() <= amem->rval()->expr_width());
|
||||
@@ -1344,9 +1485,8 @@ void target_vvm::proc_assign_mem(ostream&os, const NetAssignMem*amem)
|
||||
defn << " " << tmp << "[" << idx << "] = " <<
|
||||
rval << "[" << idx << "];" << endl;
|
||||
|
||||
defn << " " << mangle(mem->name())
|
||||
<< "[" << index << ".as_unsigned()] = " << tmp << ";"
|
||||
<< endl;
|
||||
defn << " " << mangle(mem->name()) << ".set_word(sim_, "
|
||||
<< index << ".as_unsigned(), " << tmp << ");" << endl;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1818,6 +1958,57 @@ extern const struct target tgt_vvm = {
|
||||
};
|
||||
/*
|
||||
* $Log: t-vvm.cc,v $
|
||||
* Revision 1.87 1999/12/02 16:58:58 steve
|
||||
* Update case comparison (Eric Aardoom).
|
||||
*
|
||||
* Revision 1.86 1999/11/29 00:38:27 steve
|
||||
* Properly initialize registers.
|
||||
*
|
||||
* Revision 1.85 1999/11/28 23:59:22 steve
|
||||
* Remove useless tests for NetESignal.
|
||||
*
|
||||
* Revision 1.84 1999/11/28 23:42:03 steve
|
||||
* NetESignal object no longer need to be NetNode
|
||||
* objects. Let them keep a pointer to NetNet objects.
|
||||
*
|
||||
* Revision 1.83 1999/11/28 18:05:37 steve
|
||||
* Set VPI_MODULE_PATH in the target code, if desired.
|
||||
*
|
||||
* Revision 1.82 1999/11/28 01:16:19 steve
|
||||
* gate outputs need to set signal values.
|
||||
*
|
||||
* Revision 1.81 1999/11/28 00:56:08 steve
|
||||
* Build up the lists in the scope of a module,
|
||||
* and get $dumpvars to scan the scope for items.
|
||||
*
|
||||
* Revision 1.80 1999/11/27 19:07:58 steve
|
||||
* Support the creation of scopes.
|
||||
*
|
||||
* Revision 1.79 1999/11/24 04:38:49 steve
|
||||
* LT and GT fixes from Eric Aardoom.
|
||||
*
|
||||
* Revision 1.78 1999/11/21 01:16:51 steve
|
||||
* Fix coding errors handling names of logic devices,
|
||||
* and add support for buf device in vvm.
|
||||
*
|
||||
* Revision 1.77 1999/11/21 00:13:09 steve
|
||||
* Support memories in continuous assignments.
|
||||
*
|
||||
* Revision 1.76 1999/11/14 23:43:45 steve
|
||||
* Support combinatorial comparators.
|
||||
*
|
||||
* Revision 1.75 1999/11/14 20:24:28 steve
|
||||
* Add support for the LPM_CLSHIFT device.
|
||||
*
|
||||
* Revision 1.74 1999/11/13 03:46:52 steve
|
||||
* Support the LPM_MUX in vvm.
|
||||
*
|
||||
* Revision 1.73 1999/11/10 02:52:24 steve
|
||||
* Create the vpiMemory handle type.
|
||||
*
|
||||
* Revision 1.72 1999/11/06 16:00:17 steve
|
||||
* Put number constants into a static table.
|
||||
*
|
||||
* Revision 1.71 1999/11/01 02:07:41 steve
|
||||
* Add the synth functor to do generic synthesis
|
||||
* and add the LPM_FF device to handle rows of
|
||||
@@ -1875,127 +2066,5 @@ extern const struct target tgt_vvm = {
|
||||
*
|
||||
* Revision 1.55 1999/10/01 03:58:37 steve
|
||||
* More resilient assignment to memory location.
|
||||
*
|
||||
* Revision 1.54 1999/10/01 03:15:00 steve
|
||||
* Rewrite vvm output to separateclass declarations
|
||||
* from method definitions. This is required to allow
|
||||
* for mutual referencing, for example by tasks.
|
||||
*
|
||||
* Revision 1.53 1999/09/30 21:26:59 steve
|
||||
* Remember to declare the calee_ member.
|
||||
*
|
||||
* Revision 1.52 1999/09/29 18:36:04 steve
|
||||
* Full case support
|
||||
*
|
||||
* Revision 1.51 1999/09/29 00:42:25 steve
|
||||
* Comment on where binary operator came from.
|
||||
*
|
||||
* Revision 1.50 1999/09/28 23:45:09 steve
|
||||
* Use files instead of strstreams for delayed output,
|
||||
* and fix a missing ends in case output code.
|
||||
*
|
||||
* Revision 1.49 1999/09/28 03:11:09 steve
|
||||
* save the thread class name so that behaviors in tasks have it.
|
||||
*
|
||||
* Revision 1.48 1999/09/28 01:53:37 steve
|
||||
* Generate code for repeat concatenations.
|
||||
*
|
||||
* Revision 1.47 1999/09/28 01:21:27 steve
|
||||
* Proper syntax for method pointers.
|
||||
*
|
||||
* Revision 1.46 1999/09/28 01:13:15 steve
|
||||
* Support in vvm > and >= behavioral operators.
|
||||
*
|
||||
* Revision 1.45 1999/09/23 03:56:57 steve
|
||||
* Support shift operators.
|
||||
*
|
||||
* Revision 1.44 1999/09/22 16:57:24 steve
|
||||
* Catch parallel blocks in vvm emit.
|
||||
*
|
||||
* Revision 1.43 1999/09/22 04:30:04 steve
|
||||
* Parse and elaborate named for/join blocks.
|
||||
*
|
||||
* Revision 1.42 1999/09/16 04:18:15 steve
|
||||
* elaborate concatenation repeats.
|
||||
*
|
||||
* Revision 1.41 1999/09/11 04:43:17 steve
|
||||
* Support ternary and <= operators in vvm.
|
||||
*
|
||||
* Revision 1.40 1999/09/08 02:24:39 steve
|
||||
* Empty conditionals (pmonta@imedia.com)
|
||||
*
|
||||
* Revision 1.39 1999/09/04 19:11:46 steve
|
||||
* Add support for delayed non-blocking assignments.
|
||||
*
|
||||
* Revision 1.38 1999/09/04 01:57:15 steve
|
||||
* Generate fake adder code in vvm.
|
||||
*
|
||||
* Revision 1.37 1999/09/01 20:46:19 steve
|
||||
* Handle recursive functions and arbitrary function
|
||||
* references to other functions, properly pass
|
||||
* function parameters and save function results.
|
||||
*
|
||||
* Revision 1.36 1999/08/31 22:38:29 steve
|
||||
* Elaborate and emit to vvm procedural functions.
|
||||
*
|
||||
* Revision 1.35 1999/08/15 01:23:56 steve
|
||||
* Convert vvm to implement system tasks with vpi.
|
||||
*
|
||||
* Revision 1.34 1999/08/02 00:19:16 steve
|
||||
* Get rid of excess set/init of NetESignal objects.
|
||||
*
|
||||
* Revision 1.33 1999/08/01 16:34:50 steve
|
||||
* Parse and elaborate rise/fall/decay times
|
||||
* for gates, and handle the rules for partial
|
||||
* lists of times.
|
||||
*
|
||||
* Revision 1.32 1999/07/18 21:17:51 steve
|
||||
* Add support for CE input to XNF DFF, and do
|
||||
* complete cleanup of replaced design nodes.
|
||||
*
|
||||
* Revision 1.31 1999/07/17 03:39:11 steve
|
||||
* simplified process scan for targets.
|
||||
*
|
||||
* Revision 1.30 1999/07/10 03:00:05 steve
|
||||
* Proper initialization of registers.
|
||||
*
|
||||
* Revision 1.29 1999/07/10 01:02:08 steve
|
||||
* Handle number constants as parameters.
|
||||
*
|
||||
* Revision 1.28 1999/07/07 04:20:57 steve
|
||||
* Emit vvm for user defined tasks.
|
||||
*
|
||||
* Revision 1.27 1999/07/03 02:12:52 steve
|
||||
* Elaborate user defined tasks.
|
||||
*
|
||||
* Revision 1.26 1999/06/24 04:21:45 steve
|
||||
* Add the === and !== binary operators.
|
||||
*
|
||||
* Revision 1.25 1999/06/19 21:06:16 steve
|
||||
* Elaborate and supprort to vvm the forever
|
||||
* and repeat statements.
|
||||
*
|
||||
* Revision 1.24 1999/06/10 04:03:43 steve
|
||||
* Do not bother trying to print lvalue name in comment.
|
||||
*
|
||||
* Revision 1.23 1999/06/09 03:00:06 steve
|
||||
* Add support for procedural concatenation expression.
|
||||
*
|
||||
* Revision 1.22 1999/06/07 02:23:31 steve
|
||||
* Support non-blocking assignment down to vvm.
|
||||
*
|
||||
* Revision 1.21 1999/05/12 04:03:19 steve
|
||||
* emit NetAssignMem objects in vvm target.
|
||||
*
|
||||
* Revision 1.20 1999/05/03 01:51:29 steve
|
||||
* Restore support for wait event control.
|
||||
*
|
||||
* Revision 1.19 1999/05/01 20:43:55 steve
|
||||
* Handle wide events, such as @(a) where a has
|
||||
* many bits in it.
|
||||
*
|
||||
* Add to vvm the binary ^ and unary & operators.
|
||||
*
|
||||
* Dump events a bit more completely.
|
||||
*/
|
||||
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
|
||||
*/
|
||||
#if !defined(WINNT)
|
||||
#ident "$Id: t-xnf.cc,v 1.11 1999/11/04 03:53:26 steve Exp $"
|
||||
#ident "$Id: t-xnf.cc,v 1.18 1999/11/19 03:02:25 steve Exp $"
|
||||
#endif
|
||||
|
||||
/* XNF BACKEND
|
||||
@@ -33,6 +33,12 @@
|
||||
* PART record. Valid types are defined by Xilinx or the
|
||||
* receiving tools.
|
||||
*
|
||||
* ncf=<path>
|
||||
* Specify the path to a NCF file. This is an OUTPUT file into
|
||||
* which the code generator will write netlist constraints that
|
||||
* relate to pin assignments, CLB placement, etc. If this flag is
|
||||
* not given, no NCF file will be written.
|
||||
*
|
||||
* WIRE ATTRIBUTES
|
||||
*
|
||||
* PAD = <io><n>
|
||||
@@ -63,6 +69,8 @@
|
||||
|
||||
# include "netlist.h"
|
||||
# include "target.h"
|
||||
# include <fstream>
|
||||
# include <strstream>
|
||||
|
||||
class target_xnf : public target_t {
|
||||
|
||||
@@ -71,19 +79,28 @@ class target_xnf : public target_t {
|
||||
void end_design(ostream&os, const Design*);
|
||||
void signal(ostream&os, const NetNet*);
|
||||
|
||||
void lpm_add_sub(ostream&os, const NetAddSub*);
|
||||
void lpm_ff(ostream&os, const NetFF*);
|
||||
void lpm_mux(ostream&os, const NetMux*);
|
||||
|
||||
void net_const(ostream&os, const NetConst*);
|
||||
void logic(ostream&os, const NetLogic*);
|
||||
void bufz(ostream&os, const NetBUFZ*);
|
||||
void udp(ostream&os, const NetUDP*);
|
||||
|
||||
private:
|
||||
static string mangle(const string&);
|
||||
static string choose_sig_name(const NetObj::Link*lnk);
|
||||
static void draw_pin(ostream&os, const string&name,
|
||||
const NetObj::Link&lnk);
|
||||
static void draw_sym_with_lcaname(ostream&os, string lca,
|
||||
const NetNode*net);
|
||||
static void draw_xor(ostream&os, const NetAddSub*, unsigned idx);
|
||||
enum adder_type {FORCE0, LOWER, UPPER, DOUBLE };
|
||||
static void draw_carry(ostream&os, const NetAddSub*, unsigned idx,
|
||||
enum adder_type);
|
||||
|
||||
ofstream ncf_;
|
||||
};
|
||||
|
||||
/*
|
||||
@@ -106,6 +123,58 @@ string target_xnf::mangle(const string&name)
|
||||
return result;
|
||||
}
|
||||
|
||||
/*
|
||||
* This method takes a signal and pin number as a nexus. Scan the
|
||||
* nexus to decide which name to use if there are lots of attached
|
||||
* signals.
|
||||
*/
|
||||
string target_xnf::choose_sig_name(const NetObj::Link*lnk)
|
||||
{
|
||||
const NetNet*sig = dynamic_cast<const NetNet*>(lnk->get_obj());
|
||||
unsigned pin = lnk->get_pin();
|
||||
|
||||
for (const NetObj::Link*cur = lnk->next_link()
|
||||
; cur != lnk ; cur = cur->next_link()) {
|
||||
|
||||
const NetNet*cursig = dynamic_cast<const NetNet*>(cur->get_obj());
|
||||
if (cursig == 0)
|
||||
continue;
|
||||
|
||||
if (sig == 0) {
|
||||
sig = cursig;
|
||||
pin = cur->get_pin();
|
||||
continue;
|
||||
}
|
||||
|
||||
if ((cursig->pin_count() == 1) && (sig->pin_count() > 1))
|
||||
continue;
|
||||
|
||||
if ((cursig->pin_count() > 1) && (sig->pin_count() == 1)) {
|
||||
sig = cursig;
|
||||
pin = cur->get_pin();
|
||||
continue;
|
||||
}
|
||||
|
||||
if (cursig->local_flag() && !sig->local_flag())
|
||||
continue;
|
||||
|
||||
if (cursig->name() < sig->name())
|
||||
continue;
|
||||
|
||||
sig = cursig;
|
||||
pin = cur->get_pin();
|
||||
}
|
||||
|
||||
assert(sig);
|
||||
ostrstream tmp;
|
||||
tmp << mangle(sig->name());
|
||||
if (sig->pin_count() > 1)
|
||||
tmp << "<" << pin << ">";
|
||||
tmp << ends;
|
||||
|
||||
return tmp.str();
|
||||
}
|
||||
|
||||
void target_xnf::draw_pin(ostream&os, const string&name,
|
||||
const NetObj::Link&lnk)
|
||||
{
|
||||
@@ -126,26 +195,11 @@ void target_xnf::draw_pin(ostream&os, const string&name,
|
||||
type = 'O';
|
||||
break;
|
||||
}
|
||||
|
||||
unsigned cpin;
|
||||
const NetObj*cur;
|
||||
for (lnk.next_link(cur, cpin)
|
||||
; cur->pin(cpin) != lnk
|
||||
; cur->pin(cpin).next_link(cur, cpin)) {
|
||||
|
||||
const NetNet*sig = dynamic_cast<const NetNet*>(cur);
|
||||
if (sig) {
|
||||
os << " PIN, " << use_name << ", " << type << ", "
|
||||
<< mangle(sig->name());
|
||||
if (sig->pin_count() > 1)
|
||||
os << "<" << cpin << ">";
|
||||
|
||||
if (inv)
|
||||
os << ",,INV";
|
||||
|
||||
os << endl;
|
||||
}
|
||||
}
|
||||
os << " PIN, " << use_name << ", " << type << ", " <<
|
||||
choose_sig_name(&lnk);
|
||||
if (inv) os << ",,INV";
|
||||
os << endl;
|
||||
}
|
||||
|
||||
static string scrape_pin_name(string&list)
|
||||
@@ -171,23 +225,35 @@ void target_xnf::draw_sym_with_lcaname(ostream&os, string lca,
|
||||
os << "SYM, " << mangle(net->name()) << ", " << lcaname
|
||||
<< ", LIBVER=2.0.0" << endl;
|
||||
|
||||
for (idx = 0 ; idx < net->pin_count() ; idx += 1)
|
||||
draw_pin(os, scrape_pin_name(lca), net->pin(idx));
|
||||
for (idx = 0 ; idx < net->pin_count() ; idx += 1) {
|
||||
string usename = scrape_pin_name(lca);
|
||||
if (usename == "") continue;
|
||||
draw_pin(os, usename, net->pin(idx));
|
||||
}
|
||||
|
||||
os << "END" << endl;
|
||||
}
|
||||
|
||||
void target_xnf::start_design(ostream&os, const Design*des)
|
||||
{
|
||||
string ncfpath = des->get_flag("ncf");
|
||||
if (ncfpath != "")
|
||||
ncf_.open(ncfpath.c_str());
|
||||
|
||||
os << "LCANET,6" << endl;
|
||||
os << "PROG,verilog,0.2PRE,\"Icarus Verilog\"" << endl;
|
||||
if (des->get_flag("part") != "")
|
||||
ncf_ << "# Generated by Icarus Verilog 0.2PRE" << endl;
|
||||
|
||||
if (des->get_flag("part") != "") {
|
||||
os << "PART," << des->get_flag("part") << endl;
|
||||
ncf_ << "CONFIG PART=" << des->get_flag("part") << ";" << endl;
|
||||
}
|
||||
}
|
||||
|
||||
void target_xnf::end_design(ostream&os, const Design*)
|
||||
{
|
||||
os << "EOF" << endl;
|
||||
ncf_.close();
|
||||
}
|
||||
|
||||
void scrape_pad_info(string str, char&dir, unsigned&num)
|
||||
@@ -257,6 +323,164 @@ void target_xnf::signal(ostream&os, const NetNet*net)
|
||||
scrape_pad_info(pad, dir, num);
|
||||
os << "EXT, " << mangle(net->name()) << ", " << dir
|
||||
<< ", " << num << endl;
|
||||
|
||||
ncf_ << "# Assignment to pin " << num << " (DIR=" << dir <<
|
||||
") by $attribute(" << net->name() << ", \"PAD\", \"" <<
|
||||
pad << "\")" << endl;
|
||||
ncf_ << "NET " << mangle(net->name()) << " LOC=P" << num << ";"
|
||||
<< endl;
|
||||
}
|
||||
|
||||
void target_xnf::draw_xor(ostream &os, const NetAddSub*gate, unsigned idx)
|
||||
{
|
||||
string name = mangle(gate->name());
|
||||
string name_add = name;
|
||||
string name_cout = name + "/COUT";
|
||||
|
||||
// We only need to pick up the
|
||||
// carry if we are not the 0 bit. (We know it is 0).
|
||||
os << "SYM, " << name_add << "<" << (idx+0) << ">, XOR, "
|
||||
"LIBVER=2.0.0" << endl;
|
||||
draw_pin(os, "O", gate->pin_Result(idx));
|
||||
draw_pin(os, "I0", gate->pin_DataA(idx));
|
||||
draw_pin(os, "I1", gate->pin_DataB(idx));
|
||||
if (idx > 0) {
|
||||
os << " PIN, I2, I, " << name_cout << "<" <<
|
||||
idx << ">" << endl;
|
||||
}
|
||||
os << "END" << endl;
|
||||
}
|
||||
|
||||
void target_xnf::draw_carry(ostream &os, const NetAddSub*gate, unsigned idx,
|
||||
enum adder_type type)
|
||||
{
|
||||
string name = mangle(gate->name());
|
||||
|
||||
string name_cy4 = name + "/CY";
|
||||
string name_cym = name + "/CM";
|
||||
string name_cout = name + "/COUT";
|
||||
|
||||
os << "SYM, " << name_cy4 << "<" << idx << ">, CY4, "
|
||||
"LIBVER=2.0.0" << endl;
|
||||
|
||||
// Less significant bit addends, if any
|
||||
if ( type == LOWER || type == DOUBLE ) {
|
||||
draw_pin(os, "A0", gate->pin_DataA(idx));
|
||||
draw_pin(os, "B0", gate->pin_DataB(idx));
|
||||
}
|
||||
|
||||
// More significant bit addends, if any
|
||||
if ( type == UPPER || type == DOUBLE ) {
|
||||
unsigned int i = (type==UPPER)?idx:(idx+1);
|
||||
draw_pin(os, "A1", gate->pin_DataA(i));
|
||||
draw_pin(os, "B1", gate->pin_DataB(i));
|
||||
}
|
||||
|
||||
// Carry input
|
||||
if ( type != FORCE0 && type != UPPER ) {
|
||||
os << " PIN, CIN, I, " << name_cout << "<" <<
|
||||
idx << ">" << endl;
|
||||
}
|
||||
|
||||
// Connect the Cout0 to a signal so that I can connect
|
||||
// it to the adder.
|
||||
if ( type == LOWER || type == DOUBLE ) {
|
||||
os << " PIN, COUT0, O, " << name_cout << "<" << (idx+1) <<
|
||||
">" << endl;
|
||||
}
|
||||
|
||||
// Connect the Cout, this will connect to the next Cin
|
||||
if ( type == FORCE0 || type == UPPER || type == DOUBLE ) {
|
||||
unsigned int to = (type==FORCE0)?(0):(idx+2);
|
||||
if (type==UPPER) to=idx+1;
|
||||
os << " PIN, COUT, O, " << name_cout << "<" << to <<
|
||||
">" << endl;
|
||||
}
|
||||
|
||||
// Carry In for mode UPPER comes from a strange place
|
||||
if ( type == UPPER ) {
|
||||
os << " PIN, A0, I, " << name_cout << "<dummy>" << endl;
|
||||
}
|
||||
|
||||
// These are the mode inputs from the CY_xx pseudo-device
|
||||
for (unsigned cn = 0 ; cn < 8 ; cn += 1) {
|
||||
os << " PIN, C" << cn << ", I, " << name << "/C"
|
||||
<< cn << "<" << (idx) << ">" << endl;
|
||||
}
|
||||
os << "END" << endl;
|
||||
|
||||
// Complete the dummy force used above
|
||||
if ( type == UPPER ) {
|
||||
os << "PWR, 0, " << name_cout << "<dummy>" << endl;
|
||||
}
|
||||
|
||||
// On to the CY_xx pseudo-device itself
|
||||
os << "SYM, " << name_cym << "<" << (idx) << ">, ";
|
||||
switch (type) {
|
||||
case FORCE0:
|
||||
os << "CY4_37, CYMODE=FORCE-0" << endl;
|
||||
break;
|
||||
case LOWER:
|
||||
os << "CY4_01, CYMODE=ADD-F-CI" << endl;
|
||||
break;
|
||||
case UPPER:
|
||||
os << "CY4_03, CYMODE=ADD-G-F1" << endl;
|
||||
break;
|
||||
case DOUBLE:
|
||||
os << "CY4_02, CYMODE=ADD-FG-CI" << endl;
|
||||
break;
|
||||
}
|
||||
for (unsigned cn = 0 ; cn < 8 ; cn += 1) {
|
||||
os << " PIN, C" << cn << ", O, " << name << "/C"
|
||||
<< cn << "<" << (idx) << ">" << endl;
|
||||
}
|
||||
os << "END" << endl;
|
||||
}
|
||||
|
||||
/*
|
||||
* This function makes an adder out of carry logic symbols. It makes
|
||||
* as many 2 bit adders as are possible, then the top bit is made into
|
||||
* a 1-bit adder (with carry in) in the F unit. The low carry is
|
||||
* initialized with the FORCE-0 configuration of a carry unit below
|
||||
* the 0 bit. This takes up the carry logic of the CLB below, but not
|
||||
* the G function.
|
||||
*
|
||||
* References:
|
||||
* XNF 6.1 Specification
|
||||
* Application note XAPP013
|
||||
* Xilinx Libraries Guide, Chapter 12
|
||||
*/
|
||||
void target_xnf::lpm_add_sub(ostream&os, const NetAddSub*gate)
|
||||
{
|
||||
unsigned width = gate->width();
|
||||
|
||||
// Don't handle carry output yet
|
||||
// assert (count_outputs(gate->pin_Cout())==0);
|
||||
unsigned carry_width = width-1;
|
||||
|
||||
/* Make the force-0 cary mode object to initialize the bottom
|
||||
bits of the carry chain. Label this with the width instead
|
||||
of the bit position so that symbols don't clash. */
|
||||
if (carry_width%2) {
|
||||
draw_carry(os, gate, width, FORCE0);
|
||||
} else {
|
||||
draw_carry(os, gate, 0, UPPER);
|
||||
}
|
||||
|
||||
/* Now make the 2 bit adders that chain from the cin
|
||||
initializer and up. Save the tail bit (if there is one) for
|
||||
later. */
|
||||
for (unsigned idx = 1-(carry_width%2) ; idx < carry_width-1 ; idx += 2) {
|
||||
draw_carry(os, gate, idx, DOUBLE);
|
||||
}
|
||||
|
||||
/* Always have a tail bit */
|
||||
draw_carry(os, gate, carry_width-1, LOWER);
|
||||
|
||||
for (unsigned idx = 0 ; idx < width ; ++idx) {
|
||||
draw_xor(os, gate, idx);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void target_xnf::lpm_ff(ostream&os, const NetFF*net)
|
||||
@@ -266,7 +490,13 @@ void target_xnf::lpm_ff(ostream&os, const NetFF*net)
|
||||
|
||||
// XXXX For now, only support DFF
|
||||
assert(type == "DFF");
|
||||
// XXXX For now, I do not now how to deal with XNF-LCA attributes.
|
||||
|
||||
string lcaname = net->attribute("XNF-LCA");
|
||||
if (lcaname != "") {
|
||||
draw_sym_with_lcaname(os, lcaname, net);
|
||||
return;
|
||||
}
|
||||
|
||||
assert(net->attribute("XNF-LCA") == "");
|
||||
|
||||
for (unsigned idx = 0 ; idx < net->width() ; idx += 1) {
|
||||
@@ -302,7 +532,7 @@ void target_xnf::lpm_mux(ostream&os, const NetMux*net)
|
||||
|
||||
for (unsigned idx = 0 ; idx < net->width() ; idx += 1) {
|
||||
|
||||
os << "SYM, " << mangle(net->name()) << "<" << idx << ">"
|
||||
os << "SYM, " << mangle(net->name()) << "<" << idx << ">,"
|
||||
<< " EQN, EQN=(I0 * I2) + (~I0 * I1)" << endl;
|
||||
|
||||
draw_pin(os, "I0", net->pin_Sel(0));
|
||||
@@ -315,6 +545,18 @@ void target_xnf::lpm_mux(ostream&os, const NetMux*net)
|
||||
|
||||
}
|
||||
|
||||
void target_xnf::net_const(ostream&os, const NetConst*c)
|
||||
{
|
||||
verinum::V v=c->value();
|
||||
assert(v==verinum::V0 || v==verinum::V1);
|
||||
const NetObj::Link& lnk = c->pin(0);
|
||||
// Code parallels draw_pin above, some smart c++ guru should
|
||||
// find a way to make a method out of this.
|
||||
unsigned cpin;
|
||||
const NetObj*cur;
|
||||
|
||||
os << " PWR, " << v << ", " << choose_sig_name(&lnk) << endl;
|
||||
}
|
||||
|
||||
/*
|
||||
* The logic gates I know so far can be translated directly into XNF
|
||||
@@ -411,6 +653,35 @@ extern const struct target tgt_xnf = { "xnf", &target_xnf_obj };
|
||||
|
||||
/*
|
||||
* $Log: t-xnf.cc,v $
|
||||
* Revision 1.18 1999/11/19 03:02:25 steve
|
||||
* Detect flip-flops connected to opads and turn
|
||||
* them into OUTFF devices. Inprove support for
|
||||
* the XNF-LCA attribute in the process.
|
||||
*
|
||||
* Revision 1.17 1999/11/17 18:52:09 steve
|
||||
* Add algorithm for choosing nexus name from attached signals.
|
||||
*
|
||||
* Revision 1.16 1999/11/17 01:31:28 steve
|
||||
* Clean up warnings that add_sub got from Alliance
|
||||
*
|
||||
* Revision 1.15 1999/11/06 04:51:42 steve
|
||||
* Support writing some XNF things into an NCF file.
|
||||
*
|
||||
* Revision 1.14 1999/11/05 18:43:12 steve
|
||||
* fix syntax of EQN record.
|
||||
*
|
||||
* Revision 1.13 1999/11/05 07:10:45 steve
|
||||
* Include the obvious XOR gates in the adders.
|
||||
*
|
||||
* Revision 1.12 1999/11/05 04:40:40 steve
|
||||
* Patch to synthesize LPM_ADD_SUB from expressions,
|
||||
* Thanks to Larry Doolittle. Also handle constants
|
||||
* in expressions.
|
||||
*
|
||||
* Synthesize adders in XNF, based on a patch from
|
||||
* Larry. Accept synthesis of constants from Larry
|
||||
* as is.
|
||||
*
|
||||
* Revision 1.11 1999/11/04 03:53:26 steve
|
||||
* Patch to synthesize unary ~ and the ternary operator.
|
||||
* Thanks to Larry Doolittle <LRDoolittle@lbl.gov>.
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
|
||||
*/
|
||||
#if !defined(WINNT)
|
||||
#ident "$Id: target.cc,v 1.23 1999/11/04 03:53:26 steve Exp $"
|
||||
#ident "$Id: target.cc,v 1.28 1999/11/28 23:42:03 steve Exp $"
|
||||
#endif
|
||||
|
||||
# include "target.h"
|
||||
@@ -31,6 +31,10 @@ void target_t::start_design(ostream&os, const Design*)
|
||||
{
|
||||
}
|
||||
|
||||
void target_t::scope(ostream&, const NetScope*)
|
||||
{
|
||||
}
|
||||
|
||||
void target_t::signal(ostream&os, const NetNet*)
|
||||
{
|
||||
}
|
||||
@@ -75,6 +79,18 @@ void target_t::lpm_add_sub(ostream&, const NetAddSub*)
|
||||
"Unhandled NetAddSub." << endl;
|
||||
}
|
||||
|
||||
void target_t::lpm_clshift(ostream&, const NetCLShift*)
|
||||
{
|
||||
cerr << "target (" << typeid(*this).name() << "): "
|
||||
"Unhandled NetCLShift." << endl;
|
||||
}
|
||||
|
||||
void target_t::lpm_compare(ostream&, const NetCompare*)
|
||||
{
|
||||
cerr << "target (" << typeid(*this).name() << "): "
|
||||
"Unhandled NetCompare." << endl;
|
||||
}
|
||||
|
||||
void target_t::lpm_ff(ostream&, const NetFF*)
|
||||
{
|
||||
cerr << "target (" << typeid(*this).name() << "): "
|
||||
@@ -87,6 +103,12 @@ void target_t::lpm_mux(ostream&, const NetMux*)
|
||||
"Unhandled NetMux." << endl;
|
||||
}
|
||||
|
||||
void target_t::lpm_ram_dq(ostream&, const NetRamDq*)
|
||||
{
|
||||
cerr << "target (" << typeid(*this).name() << "): "
|
||||
"Unhandled NetRamDq." << endl;
|
||||
}
|
||||
|
||||
void target_t::net_assign(ostream&os, const NetAssign*)
|
||||
{
|
||||
}
|
||||
@@ -109,13 +131,6 @@ void target_t::net_const(ostream&os, const NetConst*)
|
||||
"Unhandled CONSTANT node." << endl;
|
||||
}
|
||||
|
||||
void target_t::net_esignal(ostream&os, const NetESignal*net)
|
||||
{
|
||||
cerr << "target (" << typeid(*this).name() << "): "
|
||||
"Unhandled Expression Signal node." << endl;
|
||||
net->dump_node(cerr, 4);
|
||||
}
|
||||
|
||||
void target_t::net_event(ostream&os, const NetNEvent*net)
|
||||
{
|
||||
cerr << "target (" << typeid(*this).name() << "): "
|
||||
@@ -249,6 +264,12 @@ void expr_scan_t::expr_memory(const NetEMemory*)
|
||||
"unhandled expr_memory." << endl;
|
||||
}
|
||||
|
||||
void expr_scan_t::expr_scope(const NetEScope*)
|
||||
{
|
||||
cerr << "expr_scan_t (" << typeid(*this).name() << "): "
|
||||
"unhandled expr_scope." << endl;
|
||||
}
|
||||
|
||||
void expr_scan_t::expr_signal(const NetESignal*)
|
||||
{
|
||||
cerr << "expr_scan_t (" << typeid(*this).name() << "): "
|
||||
@@ -287,6 +308,22 @@ void expr_scan_t::expr_binary(const NetEBinary*ex)
|
||||
|
||||
/*
|
||||
* $Log: target.cc,v $
|
||||
* Revision 1.28 1999/11/28 23:42:03 steve
|
||||
* NetESignal object no longer need to be NetNode
|
||||
* objects. Let them keep a pointer to NetNet objects.
|
||||
*
|
||||
* Revision 1.27 1999/11/27 19:07:58 steve
|
||||
* Support the creation of scopes.
|
||||
*
|
||||
* Revision 1.26 1999/11/21 00:13:09 steve
|
||||
* Support memories in continuous assignments.
|
||||
*
|
||||
* Revision 1.25 1999/11/14 23:43:45 steve
|
||||
* Support combinatorial comparators.
|
||||
*
|
||||
* Revision 1.24 1999/11/14 20:24:28 steve
|
||||
* Add support for the LPM_CLSHIFT device.
|
||||
*
|
||||
* Revision 1.23 1999/11/04 03:53:26 steve
|
||||
* Patch to synthesize unary ~ and the ternary operator.
|
||||
* Thanks to Larry Doolittle <LRDoolittle@lbl.gov>.
|
||||
|
||||
@@ -19,7 +19,7 @@
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
|
||||
*/
|
||||
#if !defined(WINNT)
|
||||
#ident "$Id: target.h,v 1.22 1999/11/04 03:53:26 steve Exp $"
|
||||
#ident "$Id: target.h,v 1.27 1999/11/28 23:42:03 steve Exp $"
|
||||
#endif
|
||||
|
||||
# include "netlist.h"
|
||||
@@ -55,6 +55,10 @@ struct target_t {
|
||||
/* Start the design. */
|
||||
virtual void start_design(ostream&os, const Design*);
|
||||
|
||||
/* This is called once for each scope in the design, before
|
||||
anything else is called. */
|
||||
virtual void scope(ostream&os, const NetScope*);
|
||||
|
||||
/* Output a signal (called for each signal) */
|
||||
virtual void signal(ostream&os, const NetNet*);
|
||||
|
||||
@@ -67,8 +71,11 @@ struct target_t {
|
||||
|
||||
/* LPM style components are handled here. */
|
||||
virtual void lpm_add_sub(ostream&os, const NetAddSub*);
|
||||
virtual void lpm_clshift(ostream&os, const NetCLShift*);
|
||||
virtual void lpm_compare(ostream&os, const NetCompare*);
|
||||
virtual void lpm_ff(ostream&os, const NetFF*);
|
||||
virtual void lpm_mux(ostream&os, const NetMux*);
|
||||
virtual void lpm_ram_dq(ostream&os, const NetRamDq*);
|
||||
|
||||
/* Output a gate (called for each gate) */
|
||||
virtual void logic(ostream&os, const NetLogic*);
|
||||
@@ -78,7 +85,6 @@ struct target_t {
|
||||
virtual void net_assign_nb(ostream&os, const NetAssignNB*);
|
||||
virtual void net_case_cmp(ostream&os, const NetCaseCmp*);
|
||||
virtual void net_const(ostream&os, const NetConst*);
|
||||
virtual void net_esignal(ostream&os, const NetESignal*);
|
||||
virtual void net_event(ostream&os, const NetNEvent*);
|
||||
|
||||
/* Output a process (called for each process). It is up to the
|
||||
@@ -114,6 +120,7 @@ struct expr_scan_t {
|
||||
virtual void expr_concat(const NetEConcat*);
|
||||
virtual void expr_ident(const NetEIdent*);
|
||||
virtual void expr_memory(const NetEMemory*);
|
||||
virtual void expr_scope(const NetEScope*);
|
||||
virtual void expr_signal(const NetESignal*);
|
||||
virtual void expr_subsignal(const NetESubSignal*);
|
||||
virtual void expr_ternary(const NetETernary*);
|
||||
@@ -139,6 +146,22 @@ extern const struct target *target_table[];
|
||||
|
||||
/*
|
||||
* $Log: target.h,v $
|
||||
* Revision 1.27 1999/11/28 23:42:03 steve
|
||||
* NetESignal object no longer need to be NetNode
|
||||
* objects. Let them keep a pointer to NetNet objects.
|
||||
*
|
||||
* Revision 1.26 1999/11/27 19:07:58 steve
|
||||
* Support the creation of scopes.
|
||||
*
|
||||
* Revision 1.25 1999/11/21 00:13:09 steve
|
||||
* Support memories in continuous assignments.
|
||||
*
|
||||
* Revision 1.24 1999/11/14 23:43:46 steve
|
||||
* Support combinatorial comparators.
|
||||
*
|
||||
* Revision 1.23 1999/11/14 20:24:28 steve
|
||||
* Add support for the LPM_CLSHIFT device.
|
||||
*
|
||||
* Revision 1.22 1999/11/04 03:53:26 steve
|
||||
* Patch to synthesize unary ~ and the ternary operator.
|
||||
* Thanks to Larry Doolittle <LRDoolittle@lbl.gov>.
|
||||
|
||||
+4
-3
@@ -21,7 +21,7 @@
|
||||
# Added support for functors, especially for the XNF target. <[email protected]>
|
||||
|
||||
# Setup variables
|
||||
execPath=@bindir@
|
||||
execPath=@libdir@/ivl
|
||||
execIVLPP=${execPath}/ivlpp
|
||||
execIVL=${execPath}/ivl
|
||||
execCpp=@CXX@
|
||||
@@ -41,8 +41,9 @@ flags=""
|
||||
|
||||
# If VPI module path aren't set up, warn at least
|
||||
if test -z "${VPI_MODULE_PATH}" ; then
|
||||
echo "Missing environment variable VPI_MODULE_PATH.";
|
||||
echo "Warning: Missing environment variable VPI_MODULE_PATH.";
|
||||
echo "To be able to execute, set VPI_MODULE_PATH to ${VPIModulePath}";
|
||||
export VPI_MODULE_PATH=${VPIModulePath}
|
||||
fi
|
||||
|
||||
# Try to extract given parameters
|
||||
@@ -78,7 +79,7 @@ fi
|
||||
case "$target" in
|
||||
vvm) targetSuffix="" ;;
|
||||
xnf) targetSuffix=".xnf"
|
||||
functors="-Fsynth -Fsigfold -Fxnfio" ;;
|
||||
functors="-Fxnfsyn -Fsigfold -Fxnfio" ;;
|
||||
*) targetSuffix=".$target" ;;
|
||||
esac
|
||||
|
||||
|
||||
+16
-1
@@ -17,7 +17,7 @@
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
|
||||
*/
|
||||
#if !defined(WINNT)
|
||||
#ident "$Id: verinum.cc,v 1.11 1999/10/22 23:57:53 steve Exp $"
|
||||
#ident "$Id: verinum.cc,v 1.12 1999/11/06 16:00:17 steve Exp $"
|
||||
#endif
|
||||
|
||||
# include "verinum.h"
|
||||
@@ -213,6 +213,18 @@ string verinum::as_string() const
|
||||
return result;
|
||||
}
|
||||
|
||||
bool verinum::is_before(const verinum&that) const
|
||||
{
|
||||
if (that.nbits_ > nbits_) return true;
|
||||
if (that.nbits_ < nbits_) return false;
|
||||
|
||||
for (unsigned idx = nbits_ ; idx > 0 ; idx -= 1) {
|
||||
if (bits_[idx-1] < that.bits_[idx-1]) return true;
|
||||
if (bits_[idx-1] > that.bits_[idx-1]) return false;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool verinum::is_defined() const
|
||||
{
|
||||
for (unsigned idx = 0 ; idx < nbits_ ; idx += 1) {
|
||||
@@ -455,6 +467,9 @@ verinum operator - (const verinum&left, const verinum&r)
|
||||
|
||||
/*
|
||||
* $Log: verinum.cc,v $
|
||||
* Revision 1.12 1999/11/06 16:00:17 steve
|
||||
* Put number constants into a static table.
|
||||
*
|
||||
* Revision 1.11 1999/10/22 23:57:53 steve
|
||||
* do the <= in bits, not numbers.
|
||||
*
|
||||
|
||||
@@ -19,7 +19,7 @@
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
|
||||
*/
|
||||
#if !defined(WINNT)
|
||||
#ident "$Id: verinum.h,v 1.7 1999/10/22 23:57:53 steve Exp $"
|
||||
#ident "$Id: verinum.h,v 1.8 1999/11/06 16:00:17 steve Exp $"
|
||||
#endif
|
||||
|
||||
# include <string>
|
||||
@@ -63,6 +63,9 @@ class verinum {
|
||||
// an ascii description instead of a number value.
|
||||
bool is_string() const { return string_flag_; }
|
||||
|
||||
// Comparison for use in sorting algorithms.
|
||||
bool is_before(const verinum&that) const;
|
||||
|
||||
// Individual bits can be accessed with the get and set
|
||||
// methods.
|
||||
V get(unsigned idx) const;
|
||||
@@ -97,6 +100,9 @@ extern verinum operator - (const verinum&left, const verinum&right);
|
||||
|
||||
/*
|
||||
* $Log: verinum.h,v $
|
||||
* Revision 1.8 1999/11/06 16:00:17 steve
|
||||
* Put number constants into a static table.
|
||||
*
|
||||
* Revision 1.7 1999/10/22 23:57:53 steve
|
||||
* do the <= in bits, not numbers.
|
||||
*
|
||||
|
||||
+2
-2
@@ -18,7 +18,7 @@
|
||||
# 59 Temple Place - Suite 330
|
||||
# Boston, MA 02111-1307, USA
|
||||
#
|
||||
#ident "$Id: Makefile.in,v 1.6 1999/10/22 23:58:13 steve Exp $"
|
||||
#ident "$Id: Makefile.in,v 1.7 1999/11/07 20:33:30 steve Exp $"
|
||||
#
|
||||
#
|
||||
SHELL = /bin/sh
|
||||
@@ -52,7 +52,7 @@ all: system.vpi
|
||||
$(CC) -Wall $(CPPFLAGS) -I$(srcdir) -MD -c $< -o $*.o
|
||||
mv $*.d dep
|
||||
|
||||
O = sys_table.o sys_display.o sys_finish.o
|
||||
O = sys_table.o sys_display.o sys_finish.o sys_vcd.o
|
||||
|
||||
system.vpi: $O
|
||||
$(CC) -shared -o $@ $O
|
||||
|
||||
+189
-102
@@ -17,7 +17,7 @@
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
|
||||
*/
|
||||
#if !defined(WINNT)
|
||||
#ident "$Id: sys_display.c,v 1.6 1999/10/29 03:37:22 steve Exp $"
|
||||
#ident "$Id: sys_display.c,v 1.9 1999/11/07 02:25:07 steve Exp $"
|
||||
#endif
|
||||
|
||||
# include "vpi_user.h"
|
||||
@@ -26,68 +26,28 @@
|
||||
# include <ctype.h>
|
||||
# include <stdlib.h>
|
||||
|
||||
static void format_binary(vpiHandle argv, int fsize)
|
||||
{
|
||||
s_vpi_value value;
|
||||
vpiHandle item = vpi_scan(argv);
|
||||
if (item == 0) return;
|
||||
struct strobe_cb_info {
|
||||
char*name;
|
||||
vpiHandle*items;
|
||||
unsigned nitems;
|
||||
};
|
||||
|
||||
value.format = vpiBinStrVal;
|
||||
vpi_get_value(item, &value);
|
||||
vpi_printf("%s", value.value.str);
|
||||
static void array_from_iterator(struct strobe_cb_info*info, vpiHandle argv)
|
||||
{
|
||||
vpiHandle item;
|
||||
unsigned nitems = 1;
|
||||
vpiHandle*items = malloc(sizeof(vpiHandle));
|
||||
items[0] = vpi_scan(argv);
|
||||
for (item = vpi_scan(argv) ; item ; item = vpi_scan(argv)) {
|
||||
items = realloc(items, (nitems+1)*sizeof(vpiHandle));
|
||||
items[nitems] = item;
|
||||
nitems += 1;
|
||||
}
|
||||
|
||||
info->nitems = nitems;
|
||||
info->items = items;
|
||||
}
|
||||
|
||||
static void format_octal(vpiHandle argv, int fsize)
|
||||
{
|
||||
s_vpi_value value;
|
||||
vpiHandle item = vpi_scan(argv);
|
||||
if (item == 0) return;
|
||||
|
||||
value.format = vpiOctStrVal;
|
||||
vpi_get_value(item, &value);
|
||||
vpi_printf("%s", value.value.str);
|
||||
}
|
||||
|
||||
static void format_decimal(vpiHandle argv, int fsize)
|
||||
{
|
||||
s_vpi_value value;
|
||||
vpiHandle item = vpi_scan(argv);
|
||||
if (item == 0) return;
|
||||
|
||||
value.format = vpiDecStrVal;
|
||||
vpi_get_value(item, &value);
|
||||
vpi_printf("%s", value.value.str);
|
||||
}
|
||||
|
||||
static void format_hex(vpiHandle argv, int fsize)
|
||||
{
|
||||
s_vpi_value value;
|
||||
vpiHandle item = vpi_scan(argv);
|
||||
if (item == 0) return;
|
||||
|
||||
value.format = vpiHexStrVal;
|
||||
vpi_get_value(item, &value);
|
||||
vpi_printf("%s", value.value.str);
|
||||
}
|
||||
|
||||
static void format_m(vpiHandle argv, int fsize)
|
||||
{
|
||||
vpiHandle item = vpi_scan(argv);
|
||||
if (item == 0) return;
|
||||
|
||||
vpi_printf("%s", vpi_get_str(vpiFullName, item));
|
||||
}
|
||||
|
||||
static void format_time(vpiHandle argv, int fsize)
|
||||
{
|
||||
s_vpi_value value;
|
||||
vpiHandle item = vpi_scan(argv);
|
||||
if (item == 0) return;
|
||||
|
||||
value.format = vpiDecStrVal;
|
||||
vpi_get_value(item, &value);
|
||||
vpi_printf("%s", value.value.str);
|
||||
}
|
||||
|
||||
/*
|
||||
* If $display discovers a string as a parameter, this function is
|
||||
@@ -95,11 +55,16 @@ static void format_time(vpiHandle argv, int fsize)
|
||||
* well so that I can look for arguments as I move forward through the
|
||||
* string.
|
||||
*/
|
||||
static void format(s_vpi_value*fmt, vpiHandle argv)
|
||||
static int format_str(char*fmt, int argc, vpiHandle*argv)
|
||||
{
|
||||
s_vpi_value value;
|
||||
char buf[256];
|
||||
char*cp = fmt->value.str;
|
||||
assert(fmt->value.str);
|
||||
char*cp = fmt;
|
||||
int idx;
|
||||
|
||||
assert(fmt);
|
||||
|
||||
idx = 0;
|
||||
|
||||
while (*cp) {
|
||||
size_t cnt = strcspn(cp, "%\\");
|
||||
@@ -123,33 +88,44 @@ static void format(s_vpi_value*fmt, vpiHandle argv)
|
||||
break;
|
||||
case 'b':
|
||||
case 'B':
|
||||
format_binary(argv, fsize);
|
||||
value.format = vpiBinStrVal;
|
||||
vpi_get_value(argv[idx++], &value);
|
||||
vpi_printf("%s", value.value.str);
|
||||
cp += 1;
|
||||
break;
|
||||
case 'd':
|
||||
case 'D':
|
||||
format_decimal(argv, fsize);
|
||||
value.format = vpiDecStrVal;
|
||||
vpi_get_value(argv[idx++], &value);
|
||||
vpi_printf("%s", value.value.str);
|
||||
cp += 1;
|
||||
break;
|
||||
case 'h':
|
||||
case 'H':
|
||||
case 'x':
|
||||
case 'X':
|
||||
format_hex(argv, fsize);
|
||||
value.format = vpiHexStrVal;
|
||||
vpi_get_value(argv[idx++], &value);
|
||||
vpi_printf("%s", value.value.str);
|
||||
cp += 1;
|
||||
break;
|
||||
case 'm':
|
||||
format_m(argv, fsize);
|
||||
vpi_printf("%s", vpi_get_str(vpiFullName, argv[idx]));
|
||||
idx += 1;
|
||||
cp += 1;
|
||||
break;
|
||||
case 'o':
|
||||
case 'O':
|
||||
format_octal(argv, fsize);
|
||||
value.format = vpiOctStrVal;
|
||||
vpi_get_value(argv[idx++], &value);
|
||||
vpi_printf("%s", value.value.str);
|
||||
cp += 1;
|
||||
break;
|
||||
case 't':
|
||||
case 'T':
|
||||
format_time(argv, fsize);
|
||||
value.format = vpiDecStrVal;
|
||||
vpi_get_value(argv[idx++], &value);
|
||||
vpi_printf("%s", value.value.str);
|
||||
cp += 1;
|
||||
break;
|
||||
case '%':
|
||||
@@ -178,17 +154,17 @@ static void format(s_vpi_value*fmt, vpiHandle argv)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return idx;
|
||||
}
|
||||
|
||||
static int sys_display_calltf(char *name)
|
||||
static void do_display(struct strobe_cb_info*info)
|
||||
{
|
||||
s_vpi_value value;
|
||||
vpiHandle sys = vpi_handle(vpiSysTfCall, 0);
|
||||
int idx;
|
||||
|
||||
vpiHandle argv = vpi_iterate(vpiArgument, sys);
|
||||
vpiHandle item;
|
||||
|
||||
for (item = vpi_scan(argv) ; item ; item = vpi_scan(argv)) {
|
||||
for (idx = 0 ; idx < info->nitems ; idx += 1) {
|
||||
vpiHandle item = info->items[idx];
|
||||
|
||||
switch (vpi_get(vpiType, item)) {
|
||||
|
||||
@@ -197,17 +173,16 @@ static int sys_display_calltf(char *name)
|
||||
break;
|
||||
|
||||
case vpiConstant:
|
||||
value.format = vpiObjTypeVal;
|
||||
vpi_get_value(item, &value);
|
||||
switch (value.format) {
|
||||
case vpiStringVal:
|
||||
format(&value, argv);
|
||||
break;
|
||||
case vpiSuppressVal:
|
||||
break;
|
||||
default:
|
||||
vpi_printf("?");
|
||||
break;
|
||||
if (vpi_get(vpiConstType, item) == vpiStringConst) {
|
||||
value.format = vpiStringVal;
|
||||
vpi_get_value(item, &value);
|
||||
idx += format_str(value.value.str,
|
||||
info->nitems-idx-1,
|
||||
info->items+idx+1);
|
||||
} else {
|
||||
value.format = vpiBinStrVal;
|
||||
vpi_get_value(item, &value);
|
||||
vpi_printf("%s", value.value.str);
|
||||
}
|
||||
break;
|
||||
|
||||
@@ -229,6 +204,20 @@ static int sys_display_calltf(char *name)
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static int sys_display_calltf(char *name)
|
||||
{
|
||||
struct strobe_cb_info info;
|
||||
vpiHandle sys = vpi_handle(vpiSysTfCall, 0);
|
||||
|
||||
vpiHandle argv = vpi_iterate(vpiArgument, sys);
|
||||
|
||||
array_from_iterator(&info, argv);
|
||||
|
||||
do_display(&info);
|
||||
|
||||
free(info.items);
|
||||
|
||||
if (strcmp(name,"$display") == 0)
|
||||
vpi_printf("\n");
|
||||
@@ -236,9 +225,26 @@ static int sys_display_calltf(char *name)
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* The strobe implementation takes the parameter handles that are
|
||||
* passed to the calltf and puts them in to an array for safe
|
||||
* keeping. That array (and other bookkeeping) is passed, via the
|
||||
* struct_cb_info object, to the REadOnlySych function strobe_cb,
|
||||
* where it is use to perform the actual formatting and printing.
|
||||
*/
|
||||
|
||||
static int strobe_cb(p_cb_data cb)
|
||||
{
|
||||
vpi_printf("%s NOT IMPLEMENTED YET\n", cb->user_data);
|
||||
struct strobe_cb_info*info = (struct strobe_cb_info*)cb->user_data;
|
||||
|
||||
do_display(info);
|
||||
|
||||
vpi_printf("\n");
|
||||
|
||||
free(info->name);
|
||||
free(info->items);
|
||||
free(info);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -247,6 +253,15 @@ static int sys_strobe_calltf(char*name)
|
||||
struct t_cb_data cb;
|
||||
struct t_vpi_time time;
|
||||
|
||||
vpiHandle sys = vpi_handle(vpiSysTfCall, 0);
|
||||
|
||||
vpiHandle argv = vpi_iterate(vpiArgument, sys);
|
||||
|
||||
struct strobe_cb_info*info = calloc(1, sizeof(struct strobe_cb_info));
|
||||
|
||||
array_from_iterator(info, argv);
|
||||
info->name = strdup(name);
|
||||
|
||||
time.type = vpiSimTime;
|
||||
time.low = 0;
|
||||
time.high = 0;
|
||||
@@ -255,40 +270,103 @@ static int sys_strobe_calltf(char*name)
|
||||
cb.cb_rtn = strobe_cb;
|
||||
cb.time = &time;
|
||||
cb.obj = 0;
|
||||
cb.user_data = name;
|
||||
cb.user_data = (char*)info;
|
||||
vpi_register_cb(&cb);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* The $monitor system task works by managing these static variables,
|
||||
* and the cbValueChange callbacks associated with registers and
|
||||
* nets. Note that it is proper to keep the state in static variables
|
||||
* because there can only be one monitor at a time pending (even
|
||||
* though that monitor may be watching many variables).
|
||||
*/
|
||||
|
||||
static struct strobe_cb_info monitor_info = { 0, 0, 0 };
|
||||
static int monitor_scheduled = 0;
|
||||
static vpiHandle *monitor_callbacks = 0;
|
||||
|
||||
static int monitor_cb_2(p_cb_data cb)
|
||||
{
|
||||
do_display(&monitor_info);
|
||||
vpi_printf("\n");
|
||||
monitor_scheduled = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int monitor_cb_1(p_cb_data cause)
|
||||
{
|
||||
struct t_cb_data cb;
|
||||
struct t_vpi_time time;
|
||||
|
||||
/* Reschedule this event so that it happens for the next
|
||||
trigger on this variable. */
|
||||
cb = *cause;
|
||||
vpi_register_cb(&cb);
|
||||
|
||||
if (monitor_scheduled) return 0;
|
||||
|
||||
/* This this action caused the first trigger, then schedule
|
||||
the monitor to happen at the end of the time slice and mark
|
||||
it as scheduled. */
|
||||
monitor_scheduled += 1;
|
||||
time.type = vpiSimTime;
|
||||
time.low = 0;
|
||||
time.high = 0;
|
||||
|
||||
cb.reason = cbReadOnlySynch;
|
||||
cb.cb_rtn = monitor_cb_2;
|
||||
cb.time = &time;
|
||||
cb.obj = 0;
|
||||
vpi_register_cb(&cb);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int sys_monitor_calltf(char*name)
|
||||
{
|
||||
unsigned idx;
|
||||
struct t_cb_data cb;
|
||||
struct t_vpi_time time;
|
||||
|
||||
vpiHandle sys = vpi_handle(vpiSysTfCall, 0);
|
||||
vpiHandle argv = vpi_iterate(vpiArgument, sys);
|
||||
vpiHandle item;
|
||||
|
||||
if (monitor_callbacks) {
|
||||
for (idx = 0 ; idx < monitor_info.nitems ; idx += 1)
|
||||
if (monitor_callbacks[idx])
|
||||
vpi_remove_cb(monitor_callbacks[idx]);
|
||||
|
||||
free(monitor_callbacks);
|
||||
monitor_callbacks = 0;
|
||||
|
||||
free(monitor_info.items);
|
||||
free(monitor_info.name);
|
||||
monitor_info.items = 0;
|
||||
monitor_info.nitems = 0;
|
||||
monitor_info.name = 0;
|
||||
}
|
||||
|
||||
array_from_iterator(&monitor_info, argv);
|
||||
monitor_info.name = strdup(name);
|
||||
|
||||
monitor_callbacks = calloc(monitor_info.nitems, sizeof(vpiHandle));
|
||||
|
||||
time.type = vpiSuppressTime;
|
||||
cb.reason = cbValueChange;
|
||||
cb.cb_rtn = monitor_cb_1;
|
||||
cb.time = &time;
|
||||
for (idx = 0 ; idx < monitor_info.nitems ; idx += 1) {
|
||||
|
||||
for (item = vpi_scan(argv) ; item ; item = vpi_scan(argv)) {
|
||||
|
||||
switch (vpi_get(vpiType, item)) {
|
||||
|
||||
switch (vpi_get(vpiType, monitor_info.items[idx])) {
|
||||
case vpiNet:
|
||||
case vpiReg:
|
||||
cb.reason = cbValueChange;
|
||||
cb.cb_rtn = strobe_cb;
|
||||
cb.time = &time;
|
||||
cb.obj = item;
|
||||
cb.user_data = name;
|
||||
vpi_register_cb(&cb);
|
||||
cb.obj = monitor_info.items[idx];
|
||||
monitor_callbacks[idx] = vpi_register_cb(&cb);
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return 0;
|
||||
@@ -334,6 +412,15 @@ void sys_display_register()
|
||||
|
||||
/*
|
||||
* $Log: sys_display.c,v $
|
||||
* Revision 1.9 1999/11/07 02:25:07 steve
|
||||
* Add the $monitor implementation.
|
||||
*
|
||||
* Revision 1.8 1999/11/06 23:32:14 steve
|
||||
* Unify display and strobe format routines.
|
||||
*
|
||||
* Revision 1.7 1999/11/06 22:16:50 steve
|
||||
* Get the $strobe task working.
|
||||
*
|
||||
* Revision 1.6 1999/10/29 03:37:22 steve
|
||||
* Support vpiValueChance callbacks.
|
||||
*
|
||||
|
||||
+6
-1
@@ -17,21 +17,26 @@
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
|
||||
*/
|
||||
#if !defined(WINNT)
|
||||
#ident "$Id: sys_table.c,v 1.1 1999/08/15 01:23:56 steve Exp $"
|
||||
#ident "$Id: sys_table.c,v 1.2 1999/11/07 20:33:30 steve Exp $"
|
||||
#endif
|
||||
|
||||
extern void sys_finish_register();
|
||||
extern void sys_display_register();
|
||||
extern void sys_vcd_register();
|
||||
|
||||
void (*vlog_startup_routines[])() = {
|
||||
sys_finish_register,
|
||||
sys_display_register,
|
||||
sys_vcd_register,
|
||||
0
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
* $Log: sys_table.c,v $
|
||||
* Revision 1.2 1999/11/07 20:33:30 steve
|
||||
* Add VCD output and related system tasks.
|
||||
*
|
||||
* Revision 1.1 1999/08/15 01:23:56 steve
|
||||
* Convert vvm to implement system tasks with vpi.
|
||||
*
|
||||
|
||||
+237
@@ -0,0 +1,237 @@
|
||||
/*
|
||||
* Copyright (c) 1999 Stephen Williams (steve@icarus.com)
|
||||
*
|
||||
* This source code is free software; you can redistribute it
|
||||
* and/or modify it in source code form under the terms of the GNU
|
||||
* General Public License as published by the Free Software
|
||||
* Foundation; either version 2 of the License, or (at your option)
|
||||
* any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
|
||||
*/
|
||||
#if !defined(WINNT)
|
||||
#ident "$Id: sys_vcd.c,v 1.2 1999/11/28 00:56:08 steve Exp $"
|
||||
#endif
|
||||
|
||||
/*
|
||||
* This file contains the implementations of the VCD related
|
||||
* funcitons.
|
||||
*/
|
||||
|
||||
# include <vpi_user.h>
|
||||
# include <stdio.h>
|
||||
# include <stdlib.h>
|
||||
# include <string.h>
|
||||
# include <assert.h>
|
||||
|
||||
static FILE*dump_file = 0;
|
||||
|
||||
struct vcd_info {
|
||||
vpiHandle item;
|
||||
vpiHandle cb;
|
||||
struct t_vpi_time time;
|
||||
char*ident;
|
||||
struct vcd_info*next;
|
||||
};
|
||||
|
||||
static struct vcd_info*vcd_list = 0;
|
||||
unsigned long vcd_cur_time = 0;
|
||||
|
||||
static int variable_cb(p_cb_data cause)
|
||||
{
|
||||
unsigned long now = cause->time->low;
|
||||
s_vpi_value value;
|
||||
struct t_cb_data cb;
|
||||
struct vcd_info*info = (struct vcd_info*)cause->user_data;
|
||||
|
||||
/* Reschedule this event so that it happens for the next
|
||||
trigger on this variable. */
|
||||
cb = *cause;
|
||||
vpi_register_cb(&cb);
|
||||
|
||||
if (now != vcd_cur_time) {
|
||||
fprintf(dump_file, "#%lu\n", now);
|
||||
vcd_cur_time = now;
|
||||
}
|
||||
|
||||
if (vpi_get(vpiSize, info->item) == 1) {
|
||||
value.format = vpiBinStrVal;
|
||||
vpi_get_value(info->item, &value);
|
||||
fprintf(dump_file, "%s%s\n", value.value.str, info->ident);
|
||||
} else {
|
||||
value.format = vpiBinStrVal;
|
||||
vpi_get_value(info->item, &value);
|
||||
fprintf(dump_file, "b%s %s\n", value.value.str, info->ident);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int sys_dumpall_calltf(char*name)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int sys_dumpfile_calltf(char*name)
|
||||
{
|
||||
char*path;
|
||||
|
||||
vpiHandle sys = vpi_handle(vpiSysTfCall, 0);
|
||||
vpiHandle argv = vpi_iterate(vpiArgument, sys);
|
||||
vpiHandle item = vpi_scan(argv);
|
||||
|
||||
if (item) {
|
||||
s_vpi_value value;
|
||||
|
||||
if (vpi_get(vpiType, item) != vpiConstant) {
|
||||
vpi_printf("ERROR: %s parameter must be a constant\n", name);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (vpi_get(vpiConstType, item) != vpiStringConst) {
|
||||
vpi_printf("ERROR: %s parameter must be a constant\n", name);
|
||||
return 0;
|
||||
}
|
||||
|
||||
value.format = vpiStringVal;
|
||||
vpi_get_value(item, &value);
|
||||
path = strdup(value.value.str);
|
||||
|
||||
vpi_free_object(argv);
|
||||
|
||||
} else {
|
||||
path = strdup("dumpfile.vcd");
|
||||
}
|
||||
|
||||
assert(dump_file == 0);
|
||||
dump_file = fopen(path, "w");
|
||||
if (dump_file == 0) {
|
||||
vpi_printf("ERROR: Unable to open %s for output.\n", path);
|
||||
return 0;
|
||||
}
|
||||
|
||||
free(path);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void scan_scope(unsigned depth, vpiHandle argv)
|
||||
{
|
||||
struct t_cb_data cb;
|
||||
struct vcd_info*info;
|
||||
char ident[64];
|
||||
unsigned nident = 0;
|
||||
|
||||
vpiHandle item;
|
||||
vpiHandle sublist;
|
||||
|
||||
cb.reason = cbValueChange;
|
||||
cb.cb_rtn = variable_cb;
|
||||
|
||||
for (item = vpi_scan(argv) ; item ; item = vpi_scan(argv)) {
|
||||
const char*type;
|
||||
|
||||
switch (vpi_get(vpiType, item)) {
|
||||
case vpiNet:
|
||||
case vpiReg:
|
||||
type = "wire";
|
||||
if (vpi_get(vpiType, item) == vpiReg)
|
||||
type = "reg";
|
||||
|
||||
sprintf(ident, "<%u", nident++);
|
||||
info = malloc(sizeof(*info));
|
||||
info->time.type = vpiSimTime;
|
||||
cb.time = &info->time;
|
||||
cb.user_data = (char*)info;
|
||||
cb.obj = item;
|
||||
info->item = item;
|
||||
info->ident = strdup(ident);
|
||||
info->cb = vpi_register_cb(&cb);
|
||||
info->next = vcd_list;
|
||||
vcd_list = info;
|
||||
fprintf(dump_file, "$var %s %u %s %s $end\n",
|
||||
type, vpi_get(vpiSize, item), ident,
|
||||
vpi_get_str(vpiFullName, item));
|
||||
break;
|
||||
|
||||
case vpiModule:
|
||||
sublist = vpi_iterate(vpiInternalScope, item);
|
||||
if (sublist && (depth > 0))
|
||||
scan_scope(depth-1, sublist);
|
||||
break;
|
||||
|
||||
default:
|
||||
vpi_printf("ERROR: $dumpvars: Unsupported parameter type\n");
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
static int sys_dumpvars_calltf(char*name)
|
||||
{
|
||||
vpiHandle sys = vpi_handle(vpiSysTfCall, 0);
|
||||
vpiHandle argv = vpi_iterate(vpiArgument, sys);
|
||||
vpiHandle item = vpi_scan(argv);
|
||||
|
||||
if (item == 0) {
|
||||
vpi_printf("SORRY: %s requires arguments\n", name);
|
||||
return 0;
|
||||
}
|
||||
|
||||
assert(dump_file);
|
||||
|
||||
scan_scope(99, argv);
|
||||
|
||||
fprintf(dump_file, "$enddefinitions $end\n");
|
||||
fprintf(dump_file, "#0\n");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void sys_vcd_register()
|
||||
{
|
||||
s_vpi_systf_data tf_data;
|
||||
|
||||
tf_data.type = vpiSysTask;
|
||||
tf_data.tfname = "$dumpall";
|
||||
tf_data.calltf = sys_dumpall_calltf;
|
||||
tf_data.compiletf = 0;
|
||||
tf_data.sizetf = 0;
|
||||
tf_data.user_data = "$dumpall";
|
||||
vpi_register_systf(&tf_data);
|
||||
|
||||
tf_data.type = vpiSysTask;
|
||||
tf_data.tfname = "$dumpfile";
|
||||
tf_data.calltf = sys_dumpfile_calltf;
|
||||
tf_data.compiletf = 0;
|
||||
tf_data.sizetf = 0;
|
||||
tf_data.user_data = "$dumpfile";
|
||||
vpi_register_systf(&tf_data);
|
||||
|
||||
tf_data.type = vpiSysTask;
|
||||
tf_data.tfname = "$dumpvars";
|
||||
tf_data.calltf = sys_dumpvars_calltf;
|
||||
tf_data.compiletf = 0;
|
||||
tf_data.sizetf = 0;
|
||||
tf_data.user_data = "$dumpvars";
|
||||
vpi_register_systf(&tf_data);
|
||||
}
|
||||
|
||||
/*
|
||||
* $Log: sys_vcd.c,v $
|
||||
* Revision 1.2 1999/11/28 00:56:08 steve
|
||||
* Build up the lists in the scope of a module,
|
||||
* and get $dumpvars to scan the scope for items.
|
||||
*
|
||||
* Revision 1.1 1999/11/07 20:33:30 steve
|
||||
* Add VCD output and related system tasks.
|
||||
*
|
||||
*/
|
||||
|
||||
+25
-1
@@ -19,7 +19,7 @@
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
|
||||
*/
|
||||
#if !defined(WINNT)
|
||||
#ident "$Id: vpi_user.h,v 1.4 1999/10/28 00:47:25 steve Exp $"
|
||||
#ident "$Id: vpi_user.h,v 1.9 1999/11/28 00:56:08 steve Exp $"
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
@@ -96,12 +96,18 @@ typedef struct t_vpi_value {
|
||||
/* OBJECT CODES */
|
||||
#define vpiConstant 7
|
||||
#define vpiIterator 27
|
||||
#define vpiMemory 29
|
||||
#define vpiMemoryWord 30
|
||||
#define vpiModule 32
|
||||
#define vpiNamedBegin 33
|
||||
#define vpiNamedFork 35
|
||||
#define vpiNet 36
|
||||
#define vpiReg 48
|
||||
#define vpiSysTaskCall 57
|
||||
#define vpiTimeVar 63
|
||||
#define vpiSysTfCall 85
|
||||
#define vpiArgument 89
|
||||
#define vpiInternalScope 92
|
||||
|
||||
#define vpiCallback 1000
|
||||
|
||||
@@ -109,6 +115,7 @@ typedef struct t_vpi_value {
|
||||
#define vpiType 1
|
||||
#define vpiName 2
|
||||
#define vpiFullName 3
|
||||
#define vpiSize 4
|
||||
#define vpiConstType 43
|
||||
# define vpiDecConst 1
|
||||
# define vpiRealConst 2
|
||||
@@ -161,6 +168,7 @@ typedef struct t_cb_data {
|
||||
#define cbUnresolvedSystf 24
|
||||
|
||||
extern vpiHandle vpi_register_cb(p_cb_data data);
|
||||
extern int vpi_remove_cb(vpiHandle ref);
|
||||
|
||||
/*
|
||||
* This function allows a vpi application to control the simulation
|
||||
@@ -203,6 +211,22 @@ extern void (*vlog_startup_routines[])();
|
||||
|
||||
/*
|
||||
* $Log: vpi_user.h,v $
|
||||
* Revision 1.9 1999/11/28 00:56:08 steve
|
||||
* Build up the lists in the scope of a module,
|
||||
* and get $dumpvars to scan the scope for items.
|
||||
*
|
||||
* Revision 1.8 1999/11/27 19:07:58 steve
|
||||
* Support the creation of scopes.
|
||||
*
|
||||
* Revision 1.7 1999/11/10 02:52:24 steve
|
||||
* Create the vpiMemory handle type.
|
||||
*
|
||||
* Revision 1.6 1999/11/07 20:33:30 steve
|
||||
* Add VCD output and related system tasks.
|
||||
*
|
||||
* Revision 1.5 1999/11/07 02:25:08 steve
|
||||
* Add the $monitor implementation.
|
||||
*
|
||||
* Revision 1.4 1999/10/28 00:47:25 steve
|
||||
* Rewrite vvm VPI support to make objects more
|
||||
* persistent, rewrite the simulation scheduler
|
||||
|
||||
+5
-5
@@ -18,7 +18,7 @@
|
||||
# 59 Temple Place - Suite 330
|
||||
# Boston, MA 02111-1307, USA
|
||||
#
|
||||
#ident "$Id: Makefile.in,v 1.10 1999/10/28 21:36:00 steve Exp $"
|
||||
#ident "$Id: Makefile.in,v 1.14 1999/11/27 19:07:58 steve Exp $"
|
||||
#
|
||||
#
|
||||
SHELL = /bin/sh
|
||||
@@ -55,15 +55,15 @@ all: libvvm.a
|
||||
|
||||
%.o dep/%.d: %.c
|
||||
@[ -d dep ] || mkdir dep
|
||||
$(CC) -Wall -fno-exceptions $(CFLAGS) -MD -c $< -o $*.o
|
||||
$(CC) -Wall $(CFLAGS) -MD -c $< -o $*.o
|
||||
mv $*.d dep
|
||||
|
||||
O = vvm_bit.o vvm_calltf.o vvm_event.o vvm_pevent.o \
|
||||
O = vvm_bit.o vvm_calltf.o vvm_event.o vvm_gates.o vvm_pevent.o \
|
||||
vvm_simulation.o vvm_thread.o vpip.o
|
||||
|
||||
P = vpi_callback.o \
|
||||
vpi_const.o vpi_iter.o vpi_null.o \
|
||||
vpi_priv.o vpi_signal.o vpi_simulation.o vpi_systask.o vpi_time.o
|
||||
vpi_const.o vpi_iter.o vpi_memory.o vpi_null.o \
|
||||
vpi_priv.o vpi_scope.o vpi_signal.o vpi_simulation.o vpi_systask.o vpi_time.o
|
||||
|
||||
libvvm.a: $O
|
||||
rm -f $@
|
||||
|
||||
+18
-1
@@ -17,7 +17,7 @@
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
|
||||
*/
|
||||
#if !defined(WINNT)
|
||||
#ident "$Id: vpi_callback.c,v 1.3 1999/10/29 03:37:22 steve Exp $"
|
||||
#ident "$Id: vpi_callback.c,v 1.4 1999/11/07 20:33:30 steve Exp $"
|
||||
#endif
|
||||
|
||||
# include "vpi_priv.h"
|
||||
@@ -40,8 +40,22 @@ static struct __vpirt vpip_callback_rt = {
|
||||
*/
|
||||
static void vpip_call_callback(void*cp)
|
||||
{
|
||||
unsigned long now;
|
||||
struct __vpiCallback*rfp = (struct __vpiCallback*)cp;
|
||||
assert(rfp->base.vpi_type->type_code == vpiCallback);
|
||||
|
||||
switch (rfp->cb_data.time->type) {
|
||||
case vpiSuppressTime:
|
||||
case vpiScaledRealTime: // XXXX not supported
|
||||
break;
|
||||
|
||||
case vpiSimTime:
|
||||
now = ((struct __vpiTimeVar*)vpip_sim_time())->time;
|
||||
rfp->cb_data.time->low = now;
|
||||
rfp->cb_data.time->high = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
rfp->cb_data.cb_rtn(&rfp->cb_data);
|
||||
free(rfp);
|
||||
}
|
||||
@@ -155,6 +169,9 @@ int vpi_remove_cb(vpiHandle ref)
|
||||
|
||||
/*
|
||||
* $Log: vpi_callback.c,v $
|
||||
* Revision 1.4 1999/11/07 20:33:30 steve
|
||||
* Add VCD output and related system tasks.
|
||||
*
|
||||
* Revision 1.3 1999/10/29 03:37:22 steve
|
||||
* Support vpiValueChance callbacks.
|
||||
*
|
||||
|
||||
+268
-2
@@ -17,13 +17,229 @@
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
|
||||
*/
|
||||
#if !defined(WINNT)
|
||||
#ident "$Id: vpi_const.c,v 1.1 1999/10/28 00:47:25 steve Exp $"
|
||||
#ident "$Id: vpi_const.c,v 1.4 1999/11/06 22:16:50 steve Exp $"
|
||||
#endif
|
||||
|
||||
# include "vpi_priv.h"
|
||||
# include <assert.h>
|
||||
# include <string.h>
|
||||
# include <stdio.h>
|
||||
|
||||
|
||||
/*
|
||||
* This function is used in a couple places to interpret a bit string
|
||||
* as a value.
|
||||
*/
|
||||
void vpip_bits_get_value(enum vpip_bit_t*bits, unsigned nbits, s_vpi_value*vp)
|
||||
{
|
||||
static char buff[1024];
|
||||
char*cp;
|
||||
unsigned val;
|
||||
unsigned idx;
|
||||
|
||||
cp = buff;
|
||||
|
||||
switch (vp->format) {
|
||||
case vpiObjTypeVal:
|
||||
case vpiBinStrVal:
|
||||
for (idx = 0 ; idx < nbits ; idx += 1)
|
||||
switch (bits[nbits-idx-1]) {
|
||||
case V0:
|
||||
*cp++ = '0';
|
||||
break;
|
||||
case V1:
|
||||
*cp++ = '1';
|
||||
break;
|
||||
case Vx:
|
||||
*cp++ = 'x';
|
||||
break;
|
||||
case Vz:
|
||||
*cp++ = 'z';
|
||||
break;
|
||||
}
|
||||
vp->format = vpiBinStrVal;
|
||||
break;
|
||||
|
||||
case vpiDecStrVal:
|
||||
val = 0;
|
||||
for (idx = 0 ; idx < nbits ; idx += 1) {
|
||||
val *= 2;
|
||||
switch (bits[nbits-idx-1]) {
|
||||
case V0:
|
||||
case Vx:
|
||||
case Vz:
|
||||
break;
|
||||
case V1:
|
||||
val += 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
sprintf(cp, "%u", val);
|
||||
cp += strlen(cp);
|
||||
break;
|
||||
|
||||
case vpiOctStrVal:
|
||||
if (nbits%3) {
|
||||
unsigned x = 0;
|
||||
unsigned z = 0;
|
||||
unsigned v = 0;
|
||||
unsigned i;
|
||||
for (i = 0 ; i < nbits%3 ; i += 1) {
|
||||
v *= 2;
|
||||
switch (bits[nbits-i-1]) {
|
||||
case V0:
|
||||
break;
|
||||
case V1:
|
||||
v += 1;
|
||||
break;
|
||||
case Vx:
|
||||
x += 1;
|
||||
break;
|
||||
case Vz:
|
||||
z += 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (x == nbits%3)
|
||||
*cp++ = 'x';
|
||||
else if (x > 0)
|
||||
*cp++ = 'X';
|
||||
else if (z == nbits%3)
|
||||
*cp++ = 'z';
|
||||
else if (z > 0)
|
||||
*cp++ = 'Z';
|
||||
else
|
||||
*cp++ = "01234567"[v];
|
||||
}
|
||||
|
||||
for (idx = nbits%3 ; idx < nbits ; idx += 3) {
|
||||
unsigned x = 0;
|
||||
unsigned z = 0;
|
||||
unsigned v = 0;
|
||||
unsigned i;
|
||||
for (i = idx ; i < idx+3 ; i += 1) {
|
||||
v *= 2;
|
||||
switch (bits[nbits-i-1]) {
|
||||
case V0:
|
||||
break;
|
||||
case V1:
|
||||
v += 1;
|
||||
break;
|
||||
case Vx:
|
||||
x += 1;
|
||||
break;
|
||||
case Vz:
|
||||
z += 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (x == 3)
|
||||
*cp++ = 'x';
|
||||
else if (x > 0)
|
||||
*cp++ = 'X';
|
||||
else if (z == 3)
|
||||
*cp++ = 'z';
|
||||
else if (z > 0)
|
||||
*cp++ = 'Z';
|
||||
else
|
||||
*cp++ = "01234567"[v];
|
||||
}
|
||||
break;
|
||||
|
||||
case vpiHexStrVal:
|
||||
if (nbits%4) {
|
||||
unsigned x = 0;
|
||||
unsigned z = 0;
|
||||
unsigned v = 0;
|
||||
unsigned i;
|
||||
for (i = 0 ; i < nbits%4 ; i += 1) {
|
||||
v *= 2;
|
||||
switch (bits[nbits-i-1]) {
|
||||
case V0:
|
||||
break;
|
||||
case V1:
|
||||
v += 1;
|
||||
break;
|
||||
case Vx:
|
||||
x += 1;
|
||||
break;
|
||||
case Vz:
|
||||
z += 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (x == nbits%4)
|
||||
*cp++ = 'x';
|
||||
else if (x > 0)
|
||||
*cp++ = 'X';
|
||||
else if (z == nbits%4)
|
||||
*cp++ = 'z';
|
||||
else if (z > 0)
|
||||
*cp++ = 'Z';
|
||||
else
|
||||
*cp++ = "0123456789abcdef"[v];
|
||||
}
|
||||
|
||||
for (idx = nbits%4 ; idx < nbits ; idx += 4) {
|
||||
unsigned x = 0;
|
||||
unsigned z = 0;
|
||||
unsigned v = 0;
|
||||
unsigned i;
|
||||
for (i = idx ; i < idx+4 ; i += 1) {
|
||||
v *= 2;
|
||||
switch (bits[nbits-i-1]) {
|
||||
case V0:
|
||||
break;
|
||||
case V1:
|
||||
v += 1;
|
||||
break;
|
||||
case Vx:
|
||||
x += 1;
|
||||
break;
|
||||
case Vz:
|
||||
z += 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (x == 4)
|
||||
*cp++ = 'x';
|
||||
else if (x > 0)
|
||||
*cp++ = 'X';
|
||||
else if (z == 4)
|
||||
*cp++ = 'z';
|
||||
else if (z > 0)
|
||||
*cp++ = 'Z';
|
||||
else
|
||||
*cp++ = "0123456789abcdef"[v];
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
*cp++ = '(';
|
||||
*cp++ = '?';
|
||||
*cp++ = ')';
|
||||
break;
|
||||
}
|
||||
|
||||
*cp++ = 0;
|
||||
vp->value.str = buff;
|
||||
}
|
||||
|
||||
static int string_get(int code, vpiHandle ref)
|
||||
{
|
||||
struct __vpiStringConst*rfp = (struct __vpiStringConst*)ref;
|
||||
assert(ref->vpi_type->type_code == vpiConstant);
|
||||
|
||||
switch (code) {
|
||||
case vpiConstType:
|
||||
return vpiStringConst;
|
||||
|
||||
default:
|
||||
assert(0);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
static void string_value(vpiHandle ref, p_vpi_value vp)
|
||||
{
|
||||
struct __vpiStringConst*rfp = (struct __vpiStringConst*)ref;
|
||||
@@ -42,15 +258,46 @@ static void string_value(vpiHandle ref, p_vpi_value vp)
|
||||
}
|
||||
}
|
||||
|
||||
static int number_get(int code, vpiHandle ref)
|
||||
{
|
||||
struct __vpiNumberConst*rfp = (struct __vpiNumberConst*)ref;
|
||||
assert(ref->vpi_type->type_code == vpiConstant);
|
||||
|
||||
switch (code) {
|
||||
case vpiConstType:
|
||||
return vpiBinaryConst;
|
||||
|
||||
default:
|
||||
assert(0);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
static void number_value(vpiHandle ref, p_vpi_value vp)
|
||||
{
|
||||
struct __vpiNumberConst*rfp = (struct __vpiNumberConst*)ref;
|
||||
assert(ref->vpi_type->type_code == vpiConstant);
|
||||
vpip_bits_get_value(rfp->bits, rfp->nbits, vp);
|
||||
}
|
||||
|
||||
static const struct __vpirt vpip_string_rt = {
|
||||
vpiConstant,
|
||||
0,
|
||||
string_get,
|
||||
0,
|
||||
string_value,
|
||||
0,
|
||||
0
|
||||
};
|
||||
|
||||
static const struct __vpirt vpip_number_rt = {
|
||||
vpiConstant,
|
||||
number_get,
|
||||
0,
|
||||
number_value,
|
||||
0,
|
||||
0
|
||||
};
|
||||
|
||||
vpiHandle vpip_make_string_const(struct __vpiStringConst*ref, const char*val)
|
||||
{
|
||||
ref->base.vpi_type = &vpip_string_rt;
|
||||
@@ -58,8 +305,27 @@ vpiHandle vpip_make_string_const(struct __vpiStringConst*ref, const char*val)
|
||||
return &(ref->base);
|
||||
}
|
||||
|
||||
vpiHandle vpip_make_number_const(struct __vpiNumberConst*ref,
|
||||
const enum vpip_bit_t*bits,
|
||||
unsigned nbits)
|
||||
{
|
||||
ref->base.vpi_type = &vpip_number_rt;
|
||||
ref->bits = bits;
|
||||
ref->nbits = nbits;
|
||||
return &(ref->base);
|
||||
}
|
||||
|
||||
/*
|
||||
* $Log: vpi_const.c,v $
|
||||
* Revision 1.4 1999/11/06 22:16:50 steve
|
||||
* Get the $strobe task working.
|
||||
*
|
||||
* Revision 1.3 1999/11/06 16:52:16 steve
|
||||
* complete value retrieval for number constants.
|
||||
*
|
||||
* Revision 1.2 1999/11/06 16:00:18 steve
|
||||
* Put number constants into a static table.
|
||||
*
|
||||
* Revision 1.1 1999/10/28 00:47:25 steve
|
||||
* Rewrite vvm VPI support to make objects more
|
||||
* persistent, rewrite the simulation scheduler
|
||||
|
||||
@@ -0,0 +1,91 @@
|
||||
/*
|
||||
* Copyright (c) 1999 Picture Elements, Inc.
|
||||
* Stephen Williams (steve@picturel.com)
|
||||
*
|
||||
* This source code is free software; you can redistribute it
|
||||
* and/or modify it in source code form under the terms of the GNU
|
||||
* General Public License as published by the Free Software
|
||||
* Foundation; either version 2 of the License, or (at your option)
|
||||
* any later version. In order to redistribute the software in
|
||||
* binary form, you will need a Picture Elements Binary Software
|
||||
* License.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
|
||||
* ---
|
||||
* You should also have recieved a copy of the Picture Elements
|
||||
* Binary Software License offer along with the source. This offer
|
||||
* allows you to obtain the right to redistribute the software in
|
||||
* binary (compiled) form. If you have not received it, contact
|
||||
* Picture Elements, Inc., 777 Panoramic Way, Berkeley, CA 94704.
|
||||
*/
|
||||
#if !defined(WINNT)
|
||||
#ident "$Id: vpi_memory.c,v 1.1 1999/11/10 02:52:24 steve Exp $"
|
||||
#endif
|
||||
|
||||
# include "vpi_priv.h"
|
||||
# include <stdlib.h>
|
||||
# include <assert.h>
|
||||
|
||||
static int memory_get(int code, vpiHandle ref)
|
||||
{
|
||||
struct __vpiMemory*rfp = (struct __vpiMemory*)ref;
|
||||
|
||||
assert(ref->vpi_type->type_code==vpiMemory);
|
||||
|
||||
switch (code) {
|
||||
case vpiSize:
|
||||
return rfp->size;
|
||||
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
static char* memory_get_str(int code, vpiHandle ref)
|
||||
{
|
||||
struct __vpiMemory*rfp = (struct __vpiMemory*)ref;
|
||||
|
||||
assert(ref->vpi_type->type_code==vpiMemory);
|
||||
|
||||
switch (code) {
|
||||
|
||||
case vpiFullName:
|
||||
return (char*)rfp->name;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct __vpirt vpip_memory_rt = {
|
||||
vpiMemory,
|
||||
memory_get,
|
||||
memory_get_str,
|
||||
0,
|
||||
0,
|
||||
0
|
||||
};
|
||||
|
||||
vpiHandle vpip_make_memory(struct __vpiMemory*ref, const char*name,
|
||||
unsigned wid, unsigned siz)
|
||||
{
|
||||
ref->base.vpi_type = &vpip_memory_rt;
|
||||
ref->name = name;
|
||||
ref->bits = calloc(wid*siz, sizeof(enum vpip_bit_t));
|
||||
ref->width = wid;
|
||||
ref->size = siz;
|
||||
return &(ref->base);
|
||||
}
|
||||
/*
|
||||
* $Log: vpi_memory.c,v $
|
||||
* Revision 1.1 1999/11/10 02:52:24 steve
|
||||
* Create the vpiMemory handle type.
|
||||
*
|
||||
*/
|
||||
|
||||
+74
-10
@@ -19,7 +19,7 @@
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
|
||||
*/
|
||||
#if !defined(WINNT)
|
||||
#ident "$Id: vpi_priv.h,v 1.3 1999/10/29 03:37:22 steve Exp $"
|
||||
#ident "$Id: vpi_priv.h,v 1.8 1999/11/28 00:56:08 steve Exp $"
|
||||
#endif
|
||||
|
||||
/*
|
||||
@@ -37,6 +37,9 @@ extern "C" {
|
||||
struct __vpirt;
|
||||
enum vpip_bit_t { V0 = 0, V1, Vx, Vz };
|
||||
|
||||
extern void vpip_bits_get_value(enum vpip_bit_t*bits, unsigned nbits,
|
||||
s_vpi_value*vp);
|
||||
|
||||
/*
|
||||
* This structure is the very base of a vpiHandle. Every handle
|
||||
* structure starts with this structure, so that the library can
|
||||
@@ -76,15 +79,6 @@ struct __vpiCallback {
|
||||
struct __vpiCallback*next;
|
||||
};
|
||||
|
||||
/*
|
||||
* This type is occasionally useful. Really! And while we're at it,
|
||||
* create a single instance of the null object. (This is all we need.)
|
||||
*/
|
||||
struct __vpiNull {
|
||||
struct __vpiHandle base;
|
||||
};
|
||||
extern struct __vpiNull vpip_null;
|
||||
|
||||
/*
|
||||
* The vpiHandle for an iterator has this structure. The definition of
|
||||
* the methods lives in vpi_iter.c
|
||||
@@ -97,6 +91,45 @@ struct __vpiIterator {
|
||||
unsigned next;
|
||||
};
|
||||
|
||||
/*
|
||||
* Memory is an array of bits that is accessible in N-bit chunks, with
|
||||
* N being the width of a word.
|
||||
*/
|
||||
struct __vpiMemory {
|
||||
struct __vpiHandle base;
|
||||
/* The signal has a name (this points to static memory.) */
|
||||
const char*name;
|
||||
enum vpip_bit_t*bits;
|
||||
unsigned width;
|
||||
unsigned size;
|
||||
};
|
||||
|
||||
/*
|
||||
* This type is occasionally useful. Really! And while we're at it,
|
||||
* create a single instance of the null object. (This is all we need.)
|
||||
*/
|
||||
struct __vpiNull {
|
||||
struct __vpiHandle base;
|
||||
};
|
||||
extern struct __vpiNull vpip_null;
|
||||
|
||||
/*
|
||||
* This type represents the handle to a Verilog scope. These include
|
||||
* module instantiations and name begin-end blocks. The attach
|
||||
* function is used to attach handles to the scope by the runtime
|
||||
* initializaiton.
|
||||
*/
|
||||
struct __vpiScope {
|
||||
struct __vpiHandle base;
|
||||
/* The scope has a name. (this points to static memory.) */
|
||||
const char*name;
|
||||
/* Keep an array of internal scope items. */
|
||||
struct __vpiHandle**intern;
|
||||
unsigned nintern;
|
||||
};
|
||||
extern void vpip_attach_to_scope(struct __vpiScope*scope, vpiHandle obj);
|
||||
|
||||
|
||||
/*
|
||||
* This structure represents nets and registers. You can tell which by
|
||||
* the type_code in the base. The bits member points to the actual
|
||||
@@ -150,6 +183,13 @@ struct __vpiStringConst {
|
||||
const char*value;
|
||||
};
|
||||
|
||||
struct __vpiNumberConst {
|
||||
struct __vpiHandle base;
|
||||
|
||||
enum vpip_bit_t*bits;
|
||||
unsigned nbits;
|
||||
};
|
||||
|
||||
/*
|
||||
* These are methods to initialize specific handle types. Except for
|
||||
* vpip_make_iterator, all the vpi_make_* functions expect the caller
|
||||
@@ -158,8 +198,16 @@ struct __vpiStringConst {
|
||||
*/
|
||||
extern vpiHandle vpip_make_iterator(unsigned nargs, vpiHandle*args);
|
||||
extern vpiHandle vpip_make_net(struct __vpiSignal*ref, const char*name);
|
||||
extern vpiHandle vpip_make_scope(struct __vpiScope*ref,
|
||||
int type_code,
|
||||
const char*name);
|
||||
extern vpiHandle vpip_make_string_const(struct __vpiStringConst*ref,
|
||||
const char*val);
|
||||
extern vpiHandle vpip_make_number_const(struct __vpiNumberConst*ref,
|
||||
const enum vpip_bit_t*bits,
|
||||
unsigned nbits);
|
||||
extern vpiHandle vpip_make_memory(struct __vpiMemory*ref, const char*name,
|
||||
unsigned width, unsigned size);
|
||||
extern vpiHandle vpip_make_reg(struct __vpiSignal*ref, const char*name);
|
||||
extern vpiHandle vpip_make_time_var(struct __vpiTimeVar*ref,
|
||||
const char*val);
|
||||
@@ -226,6 +274,22 @@ extern int vpip_finished();
|
||||
|
||||
/*
|
||||
* $Log: vpi_priv.h,v $
|
||||
* Revision 1.8 1999/11/28 00:56:08 steve
|
||||
* Build up the lists in the scope of a module,
|
||||
* and get $dumpvars to scan the scope for items.
|
||||
*
|
||||
* Revision 1.7 1999/11/27 19:07:58 steve
|
||||
* Support the creation of scopes.
|
||||
*
|
||||
* Revision 1.6 1999/11/10 02:52:24 steve
|
||||
* Create the vpiMemory handle type.
|
||||
*
|
||||
* Revision 1.5 1999/11/06 16:52:16 steve
|
||||
* complete value retrieval for number constants.
|
||||
*
|
||||
* Revision 1.4 1999/11/06 16:00:18 steve
|
||||
* Put number constants into a static table.
|
||||
*
|
||||
* Revision 1.3 1999/10/29 03:37:22 steve
|
||||
* Support vpiValueChance callbacks.
|
||||
*
|
||||
|
||||
@@ -0,0 +1,86 @@
|
||||
/*
|
||||
* Copyright (c) 1999 Stephen Williams (steve@icarus.com)
|
||||
*
|
||||
* This source code is free software; you can redistribute it
|
||||
* and/or modify it in source code form under the terms of the GNU
|
||||
* General Public License as published by the Free Software
|
||||
* Foundation; either version 2 of the License, or (at your option)
|
||||
* any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
|
||||
*/
|
||||
#if !defined(WINNT)
|
||||
#ident "$Id: vpi_scope.c,v 1.2 1999/11/28 00:56:08 steve Exp $"
|
||||
#endif
|
||||
|
||||
# include "vpi_priv.h"
|
||||
# include <stdlib.h>
|
||||
# include <assert.h>
|
||||
|
||||
static vpiHandle module_iter(int code, vpiHandle obj)
|
||||
{
|
||||
struct __vpiScope*ref = (struct __vpiScope*)obj;
|
||||
assert(obj->vpi_type->type_code == vpiModule);
|
||||
|
||||
switch (code) {
|
||||
case vpiInternalScope:
|
||||
return vpip_make_iterator(ref->nintern, ref->intern);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct __vpirt vpip_module_rt = {
|
||||
vpiModule,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
module_iter
|
||||
};
|
||||
|
||||
vpiHandle vpip_make_scope(struct __vpiScope*ref, int type, const char*name)
|
||||
{
|
||||
ref->intern = 0;
|
||||
ref->nintern = 0;
|
||||
|
||||
switch (type) {
|
||||
case vpiModule:
|
||||
ref->base.vpi_type = &vpip_module_rt;
|
||||
break;
|
||||
default:
|
||||
assert(0);
|
||||
}
|
||||
|
||||
return &ref->base;
|
||||
}
|
||||
|
||||
void vpip_attach_to_scope(struct __vpiScope*ref, vpiHandle obj)
|
||||
{
|
||||
unsigned idx = ref->nintern++;
|
||||
|
||||
if (ref->intern == 0)
|
||||
ref->intern = malloc(sizeof(vpiHandle));
|
||||
else
|
||||
ref->intern = realloc(ref->intern, sizeof(vpiHandle)*ref->nintern);
|
||||
|
||||
ref->intern[idx] = obj;
|
||||
}
|
||||
|
||||
/*
|
||||
* $Log: vpi_scope.c,v $
|
||||
* Revision 1.2 1999/11/28 00:56:08 steve
|
||||
* Build up the lists in the scope of a module,
|
||||
* and get $dumpvars to scan the scope for items.
|
||||
*
|
||||
* Revision 1.1 1999/11/27 19:07:58 steve
|
||||
* Support the creation of scopes.
|
||||
*
|
||||
*/
|
||||
|
||||
+34
-202
@@ -17,19 +17,36 @@
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
|
||||
*/
|
||||
#if !defined(WINNT)
|
||||
#ident "$Id: vpi_signal.c,v 1.2 1999/10/29 03:37:22 steve Exp $"
|
||||
#ident "$Id: vpi_signal.c,v 1.5 1999/11/07 20:33:30 steve Exp $"
|
||||
#endif
|
||||
|
||||
# include "vpi_priv.h"
|
||||
# include <assert.h>
|
||||
# include <string.h>
|
||||
# include <stdio.h>
|
||||
|
||||
|
||||
static int signal_get(int code, vpiHandle ref)
|
||||
{
|
||||
struct __vpiSignal*rfp = (struct __vpiSignal*)ref;
|
||||
|
||||
assert((ref->vpi_type->type_code==vpiNet)
|
||||
|| (ref->vpi_type->type_code==vpiReg));
|
||||
|
||||
switch (code) {
|
||||
case vpiSize:
|
||||
return rfp->nbits;
|
||||
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
static char* signal_get_str(int code, vpiHandle ref)
|
||||
{
|
||||
struct __vpiSignal*rfp = (struct __vpiSignal*)ref;
|
||||
|
||||
assert((ref->vpi_type->type_code==vpiNet)
|
||||
|| (ref->vpi_type->type_code==vpiReg));
|
||||
|
||||
switch (code) {
|
||||
|
||||
case vpiFullName:
|
||||
@@ -39,212 +56,18 @@ static char* signal_get_str(int code, vpiHandle ref)
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* This function is a get_value_ method of a vpiHandle, that supports
|
||||
* reading bits as a string.
|
||||
*/
|
||||
static void signal_get_value(vpiHandle ref, s_vpi_value*vp)
|
||||
{
|
||||
static char buff[1024];
|
||||
char*cp;
|
||||
unsigned width;
|
||||
unsigned val;
|
||||
unsigned idx;
|
||||
struct __vpiSignal*rfp = (struct __vpiSignal*)ref;
|
||||
assert((ref->vpi_type->type_code==vpiNet)
|
||||
|| (ref->vpi_type->type_code==vpiReg));
|
||||
|
||||
assert(rfp->bits);
|
||||
width = rfp->nbits;
|
||||
cp = buff;
|
||||
|
||||
switch (vp->format) {
|
||||
case vpiObjTypeVal:
|
||||
case vpiBinStrVal:
|
||||
for (idx = 0 ; idx < width ; idx += 1)
|
||||
switch (rfp->bits[width-idx-1]) {
|
||||
case V0:
|
||||
*cp++ = '0';
|
||||
break;
|
||||
case V1:
|
||||
*cp++ = '1';
|
||||
break;
|
||||
case Vx:
|
||||
*cp++ = 'x';
|
||||
break;
|
||||
case Vz:
|
||||
*cp++ = 'z';
|
||||
break;
|
||||
}
|
||||
vp->format = vpiBinStrVal;
|
||||
break;
|
||||
|
||||
case vpiDecStrVal:
|
||||
val = 0;
|
||||
for (idx = 0 ; idx < width ; idx += 1) {
|
||||
val *= 2;
|
||||
switch (rfp->bits[width-idx-1]) {
|
||||
case V0:
|
||||
case Vx:
|
||||
case Vz:
|
||||
break;
|
||||
case V1:
|
||||
val += 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
sprintf(cp, "%u", val);
|
||||
cp += strlen(cp);
|
||||
break;
|
||||
|
||||
case vpiOctStrVal:
|
||||
if (width%3) {
|
||||
unsigned x = 0;
|
||||
unsigned z = 0;
|
||||
unsigned v = 0;
|
||||
unsigned i;
|
||||
for (i = 0 ; i < width%3 ; i += 1) {
|
||||
v *= 2;
|
||||
switch (rfp->bits[width-i-1]) {
|
||||
case V0:
|
||||
break;
|
||||
case V1:
|
||||
v += 1;
|
||||
break;
|
||||
case Vx:
|
||||
x += 1;
|
||||
break;
|
||||
case Vz:
|
||||
z += 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (x == width%3)
|
||||
*cp++ = 'x';
|
||||
else if (x > 0)
|
||||
*cp++ = 'X';
|
||||
else if (z == width%3)
|
||||
*cp++ = 'z';
|
||||
else if (z > 0)
|
||||
*cp++ = 'Z';
|
||||
else
|
||||
*cp++ = "01234567"[v];
|
||||
}
|
||||
|
||||
for (idx = width%3 ; idx < width ; idx += 3) {
|
||||
unsigned x = 0;
|
||||
unsigned z = 0;
|
||||
unsigned v = 0;
|
||||
unsigned i;
|
||||
for (i = idx ; i < idx+3 ; i += 1) {
|
||||
v *= 2;
|
||||
switch (rfp->bits[width-i-1]) {
|
||||
case V0:
|
||||
break;
|
||||
case V1:
|
||||
v += 1;
|
||||
break;
|
||||
case Vx:
|
||||
x += 1;
|
||||
break;
|
||||
case Vz:
|
||||
z += 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (x == 3)
|
||||
*cp++ = 'x';
|
||||
else if (x > 0)
|
||||
*cp++ = 'X';
|
||||
else if (z == 3)
|
||||
*cp++ = 'z';
|
||||
else if (z > 0)
|
||||
*cp++ = 'Z';
|
||||
else
|
||||
*cp++ = "01234567"[v];
|
||||
}
|
||||
break;
|
||||
|
||||
case vpiHexStrVal:
|
||||
if (width%4) {
|
||||
unsigned x = 0;
|
||||
unsigned z = 0;
|
||||
unsigned v = 0;
|
||||
unsigned i;
|
||||
for (i = 0 ; i < width%4 ; i += 1) {
|
||||
v *= 2;
|
||||
switch (rfp->bits[width-i-1]) {
|
||||
case V0:
|
||||
break;
|
||||
case V1:
|
||||
v += 1;
|
||||
break;
|
||||
case Vx:
|
||||
x += 1;
|
||||
break;
|
||||
case Vz:
|
||||
z += 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (x == width%4)
|
||||
*cp++ = 'x';
|
||||
else if (x > 0)
|
||||
*cp++ = 'X';
|
||||
else if (z == width%4)
|
||||
*cp++ = 'z';
|
||||
else if (z > 0)
|
||||
*cp++ = 'Z';
|
||||
else
|
||||
*cp++ = "0123456789abcdef"[v];
|
||||
}
|
||||
|
||||
for (idx = width%4 ; idx < width ; idx += 4) {
|
||||
unsigned x = 0;
|
||||
unsigned z = 0;
|
||||
unsigned v = 0;
|
||||
unsigned i;
|
||||
for (i = idx ; i < idx+4 ; i += 1) {
|
||||
v *= 2;
|
||||
switch (rfp->bits[width-i-1]) {
|
||||
case V0:
|
||||
break;
|
||||
case V1:
|
||||
v += 1;
|
||||
break;
|
||||
case Vx:
|
||||
x += 1;
|
||||
break;
|
||||
case Vz:
|
||||
z += 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (x == 4)
|
||||
*cp++ = 'x';
|
||||
else if (x > 0)
|
||||
*cp++ = 'X';
|
||||
else if (z == 4)
|
||||
*cp++ = 'z';
|
||||
else if (z > 0)
|
||||
*cp++ = 'Z';
|
||||
else
|
||||
*cp++ = "0123456789abcdef"[v];
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
*cp++ = '(';
|
||||
*cp++ = '?';
|
||||
*cp++ = ')';
|
||||
break;
|
||||
}
|
||||
|
||||
*cp++ = 0;
|
||||
vp->value.str = buff;
|
||||
vpip_bits_get_value(rfp->bits, rfp->nbits, vp);
|
||||
}
|
||||
|
||||
static const struct __vpirt vpip_net_rt = {
|
||||
vpiNet,
|
||||
0,
|
||||
signal_get,
|
||||
signal_get_str,
|
||||
signal_get_value,
|
||||
0,
|
||||
@@ -261,7 +84,7 @@ vpiHandle vpip_make_net(struct __vpiSignal*ref, const char*name)
|
||||
|
||||
static const struct __vpirt vpip_reg_rt = {
|
||||
vpiReg,
|
||||
0,
|
||||
signal_get,
|
||||
signal_get_str,
|
||||
signal_get_value,
|
||||
0,
|
||||
@@ -278,6 +101,15 @@ vpiHandle vpip_make_reg(struct __vpiSignal*ref, const char*name)
|
||||
|
||||
/*
|
||||
* $Log: vpi_signal.c,v $
|
||||
* Revision 1.5 1999/11/07 20:33:30 steve
|
||||
* Add VCD output and related system tasks.
|
||||
*
|
||||
* Revision 1.4 1999/11/07 02:25:08 steve
|
||||
* Add the $monitor implementation.
|
||||
*
|
||||
* Revision 1.3 1999/11/06 16:52:16 steve
|
||||
* complete value retrieval for number constants.
|
||||
*
|
||||
* Revision 1.2 1999/10/29 03:37:22 steve
|
||||
* Support vpiValueChance callbacks.
|
||||
*
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
#ifndef __vvm_H
|
||||
#define __vvm_H
|
||||
/*
|
||||
* Copyright (c) 1998 Stephen Williams (steve@icarus.com)
|
||||
* Copyright (c) 1998-1999 Stephen Williams (steve@icarus.com)
|
||||
*
|
||||
* This source code is free software; you can redistribute it
|
||||
* and/or modify it in source code form under the terms of the GNU
|
||||
@@ -19,11 +19,9 @@
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
|
||||
*/
|
||||
#if !defined(WINNT)
|
||||
#ident "$Id: vvm.h,v 1.20 1999/11/01 02:07:41 steve Exp $"
|
||||
#ident "$Id: vvm.h,v 1.24 1999/12/02 03:36:01 steve Exp $"
|
||||
#endif
|
||||
|
||||
# include <vector>
|
||||
# include <string>
|
||||
# include <cassert>
|
||||
# include "vpi_priv.h"
|
||||
|
||||
@@ -38,6 +36,7 @@ class vvm_event;
|
||||
class vvm_simulation;
|
||||
class vvm_simulation_cycle;
|
||||
class vvm_thread;
|
||||
class ostream;
|
||||
|
||||
|
||||
inline vpip_bit_t operator & (vpip_bit_t l, vpip_bit_t r)
|
||||
@@ -106,6 +105,8 @@ class vvm_bits_t {
|
||||
virtual ~vvm_bits_t() =0;
|
||||
virtual unsigned get_width() const =0;
|
||||
virtual vpip_bit_t get_bit(unsigned idx) const =0;
|
||||
|
||||
unsigned as_unsigned() const;
|
||||
};
|
||||
|
||||
extern ostream& operator << (ostream&os, vpip_bit_t);
|
||||
@@ -136,22 +137,15 @@ template <unsigned WIDTH> class vvm_bitset_t : public vvm_bits_t {
|
||||
}
|
||||
|
||||
|
||||
vvm_bitset_t(const vvm_bitset_t<WIDTH>&that)
|
||||
{ bits = that.bits; }
|
||||
|
||||
vpip_bit_t operator[] (unsigned idx) const { return bits[idx]; }
|
||||
vpip_bit_t&operator[] (unsigned idx) { return bits[idx]; }
|
||||
|
||||
unsigned get_width() const { return WIDTH; }
|
||||
vpip_bit_t get_bit(unsigned idx) const { return bits[idx]; }
|
||||
|
||||
unsigned as_unsigned() const
|
||||
{ unsigned result = 0;
|
||||
for (unsigned idx = WIDTH ; idx > 0 ; idx -= 1) {
|
||||
result <<= 1;
|
||||
if (bits[idx-1]) result |= 1;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
public:
|
||||
vpip_bit_t bits[WIDTH];
|
||||
};
|
||||
@@ -254,8 +248,64 @@ template <unsigned WIDTH> class vvm_signal_t : public __vpiSignal {
|
||||
}
|
||||
};
|
||||
|
||||
struct vvm_ram_callback {
|
||||
vvm_ram_callback();
|
||||
virtual ~vvm_ram_callback();
|
||||
virtual void handle_write(vvm_simulation*sim, unsigned idx) =0;
|
||||
vvm_ram_callback*next_;
|
||||
};
|
||||
|
||||
template <unsigned WIDTH, unsigned SIZE>
|
||||
class vvm_memory_t : public __vpiMemory {
|
||||
|
||||
public:
|
||||
vvm_memory_t()
|
||||
{ cb_list_ = 0;
|
||||
}
|
||||
|
||||
void set_word(vvm_simulation*sim, unsigned addr,
|
||||
const vvm_bitset_t<WIDTH>&val)
|
||||
{ unsigned base = WIDTH * addr;
|
||||
for (unsigned idx = 0 ; idx < WIDTH ; idx += 1)
|
||||
bits[base+idx] = val[idx];
|
||||
call_list_(sim, addr);
|
||||
}
|
||||
|
||||
vvm_bitset_t<WIDTH> get_word(unsigned addr) const
|
||||
{ vvm_bitset_t<WIDTH> val;
|
||||
unsigned base = WIDTH * addr;
|
||||
for (unsigned idx = 0 ; idx < WIDTH ; idx += 1)
|
||||
val[idx] = bits[base+idx];
|
||||
return val;
|
||||
}
|
||||
|
||||
void set_callback(vvm_ram_callback*ram)
|
||||
{ ram->next_ = cb_list_;
|
||||
cb_list_ = ram;
|
||||
}
|
||||
|
||||
private:
|
||||
vvm_ram_callback*cb_list_;
|
||||
void call_list_(vvm_simulation*sim, unsigned idx)
|
||||
{ for (vvm_ram_callback*cur = cb_list_; cur; cur = cur->next_)
|
||||
cur->handle_write(sim, idx);
|
||||
}
|
||||
};
|
||||
|
||||
/*
|
||||
* $Log: vvm.h,v $
|
||||
* Revision 1.24 1999/12/02 03:36:01 steve
|
||||
* shiftl and shiftr take unsized second parameter.
|
||||
*
|
||||
* Revision 1.23 1999/11/22 00:30:52 steve
|
||||
* Detemplate some and, or and nor methods.
|
||||
*
|
||||
* Revision 1.22 1999/11/21 00:13:09 steve
|
||||
* Support memories in continuous assignments.
|
||||
*
|
||||
* Revision 1.21 1999/11/10 02:52:24 steve
|
||||
* Create the vpiMemory handle type.
|
||||
*
|
||||
* Revision 1.20 1999/11/01 02:07:41 steve
|
||||
* Add the synth functor to do generic synthesis
|
||||
* and add the LPM_FF device to handle rows of
|
||||
|
||||
+38
-1
@@ -17,10 +17,11 @@
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
|
||||
*/
|
||||
#if !defined(WINNT)
|
||||
#ident "$Id: vvm_bit.cc,v 1.4 1999/11/01 02:07:41 steve Exp $"
|
||||
#ident "$Id: vvm_bit.cc,v 1.7 1999/12/02 03:36:01 steve Exp $"
|
||||
#endif
|
||||
|
||||
# include "vvm.h"
|
||||
# include <iostream>
|
||||
|
||||
ostream& operator << (ostream&os, vpip_bit_t bit)
|
||||
{
|
||||
@@ -68,6 +69,33 @@ vvm_bits_t::~vvm_bits_t()
|
||||
{
|
||||
}
|
||||
|
||||
unsigned vvm_bits_t::as_unsigned() const
|
||||
{
|
||||
unsigned result = 0;
|
||||
unsigned width = get_width();
|
||||
for (unsigned idx = width ; idx > 0 ; idx -= 1) {
|
||||
result <<= 1;
|
||||
switch (get_bit(idx-1)) {
|
||||
case V0:
|
||||
case Vx:
|
||||
case Vz:
|
||||
break;
|
||||
case V1:
|
||||
result |= 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
vvm_ram_callback::vvm_ram_callback()
|
||||
{
|
||||
}
|
||||
|
||||
vvm_ram_callback::~vvm_ram_callback()
|
||||
{
|
||||
}
|
||||
|
||||
vpip_bit_t add_with_carry(vpip_bit_t l, vpip_bit_t r, vpip_bit_t&carry)
|
||||
{
|
||||
unsigned li, ri, ci;
|
||||
@@ -114,6 +142,15 @@ vpip_bit_t add_with_carry(vpip_bit_t l, vpip_bit_t r, vpip_bit_t&carry)
|
||||
|
||||
/*
|
||||
* $Log: vvm_bit.cc,v $
|
||||
* Revision 1.7 1999/12/02 03:36:01 steve
|
||||
* shiftl and shiftr take unsized second parameter.
|
||||
*
|
||||
* Revision 1.6 1999/11/22 00:30:52 steve
|
||||
* Detemplate some and, or and nor methods.
|
||||
*
|
||||
* Revision 1.5 1999/11/21 00:13:09 steve
|
||||
* Support memories in continuous assignments.
|
||||
*
|
||||
* Revision 1.4 1999/11/01 02:07:41 steve
|
||||
* Add the synth functor to do generic synthesis
|
||||
* and add the LPM_FF device to handle rows of
|
||||
|
||||
+12
-1
@@ -17,7 +17,7 @@
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
|
||||
*/
|
||||
#if !defined(WINNT)
|
||||
#ident "$Id: vvm_calltf.cc,v 1.8 1999/10/28 00:47:25 steve Exp $"
|
||||
#ident "$Id: vvm_calltf.cc,v 1.9 1999/11/28 18:05:37 steve Exp $"
|
||||
#endif
|
||||
|
||||
# include "vvm_calltf.h"
|
||||
@@ -34,6 +34,13 @@
|
||||
|
||||
# define MAX_PATHLEN 1024
|
||||
|
||||
static char*module_path = 0;
|
||||
|
||||
void vvm_set_module_path(const char*path)
|
||||
{
|
||||
if (module_path) free(module_path);
|
||||
module_path = strdup(path);
|
||||
}
|
||||
|
||||
/*
|
||||
* The load_vpi_module function attempts to locate and load the named
|
||||
@@ -57,6 +64,7 @@ void vvm_load_vpi_module(const char*name)
|
||||
{
|
||||
void*mod = 0;
|
||||
const char*path = getenv("VPI_MODULE_PATH");
|
||||
if (path == 0) path = module_path;
|
||||
|
||||
if ((path == 0) || (strchr(name, '/'))) {
|
||||
mod = dlopen(name, RTLD_NOW);
|
||||
@@ -108,6 +116,9 @@ void vvm_load_vpi_module(const char*name)
|
||||
|
||||
/*
|
||||
* $Log: vvm_calltf.cc,v $
|
||||
* Revision 1.9 1999/11/28 18:05:37 steve
|
||||
* Set VPI_MODULE_PATH in the target code, if desired.
|
||||
*
|
||||
* Revision 1.8 1999/10/28 00:47:25 steve
|
||||
* Rewrite vvm VPI support to make objects more
|
||||
* persistent, rewrite the simulation scheduler
|
||||
|
||||
+5
-1
@@ -19,7 +19,7 @@
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
|
||||
*/
|
||||
#if !defined(WINNT)
|
||||
#ident "$Id: vvm_calltf.h,v 1.3 1999/10/28 00:47:25 steve Exp $"
|
||||
#ident "$Id: vvm_calltf.h,v 1.4 1999/11/28 18:05:37 steve Exp $"
|
||||
#endif
|
||||
|
||||
# include "vvm.h"
|
||||
@@ -29,11 +29,15 @@
|
||||
/*
|
||||
* This function loads a vpi module by name.
|
||||
*/
|
||||
extern void vvm_set_module_path(const char*path);
|
||||
extern void vvm_load_vpi_module(const char*path);
|
||||
|
||||
|
||||
/*
|
||||
* $Log: vvm_calltf.h,v $
|
||||
* Revision 1.4 1999/11/28 18:05:37 steve
|
||||
* Set VPI_MODULE_PATH in the target code, if desired.
|
||||
*
|
||||
* Revision 1.3 1999/10/28 00:47:25 steve
|
||||
* Rewrite vvm VPI support to make objects more
|
||||
* persistent, rewrite the simulation scheduler
|
||||
|
||||
+6
-3
@@ -19,7 +19,7 @@
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
|
||||
*/
|
||||
#if !defined(WINNT)
|
||||
#ident "$Id: vvm_func.h,v 1.15 1999/10/28 00:47:25 steve Exp $"
|
||||
#ident "$Id: vvm_func.h,v 1.16 1999/12/02 03:36:01 steve Exp $"
|
||||
#endif
|
||||
|
||||
# include "vvm.h"
|
||||
@@ -217,7 +217,7 @@ vvm_bitset_t<WIDTH> vvm_binop_xor(const vvm_bitset_t<WIDTH>&l,
|
||||
*/
|
||||
template <unsigned WIDTH>
|
||||
vvm_bitset_t<WIDTH> vvm_binop_shiftl(const vvm_bitset_t<WIDTH>&l,
|
||||
const vvm_bitset_t<32>&r)
|
||||
const vvm_bits_t&r)
|
||||
{
|
||||
vvm_bitset_t<WIDTH> result;
|
||||
vvm_u32 s = r.as_unsigned();
|
||||
@@ -234,7 +234,7 @@ vvm_bitset_t<WIDTH> vvm_binop_shiftl(const vvm_bitset_t<WIDTH>&l,
|
||||
*/
|
||||
template <unsigned WIDTH>
|
||||
vvm_bitset_t<WIDTH> vvm_binop_shiftr(const vvm_bitset_t<WIDTH>&l,
|
||||
const vvm_bitset_t<32>&r)
|
||||
const vvm_bits_t&r)
|
||||
{
|
||||
vvm_bitset_t<WIDTH> result;
|
||||
vvm_u32 s = r.as_unsigned();
|
||||
@@ -608,6 +608,9 @@ vvm_bitset_t<W> vvm_ternary(vpip_bit_t c, const vvm_bitset_t<W>&t,
|
||||
|
||||
/*
|
||||
* $Log: vvm_func.h,v $
|
||||
* Revision 1.16 1999/12/02 03:36:01 steve
|
||||
* shiftl and shiftr take unsized second parameter.
|
||||
*
|
||||
* Revision 1.15 1999/10/28 00:47:25 steve
|
||||
* Rewrite vvm VPI support to make objects more
|
||||
* persistent, rewrite the simulation scheduler
|
||||
|
||||
@@ -0,0 +1,159 @@
|
||||
/*
|
||||
* Copyright (c) 1999 Stephen Williams (steve@icarus.com)
|
||||
*
|
||||
* This source code is free software; you can redistribute it
|
||||
* and/or modify it in source code form under the terms of the GNU
|
||||
* General Public License as published by the Free Software
|
||||
* Foundation; either version 2 of the License, or (at your option)
|
||||
* any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
|
||||
* ---
|
||||
* You should also have recieved a copy of the Picture Elements
|
||||
* Binary Software License offer along with the source. This offer
|
||||
* allows you to obtain the right to redistribute the software in
|
||||
* binary (compiled) form. If you have not received it, contact
|
||||
* Picture Elements, Inc., 777 Panoramic Way, Berkeley, CA 94704.
|
||||
*/
|
||||
#if !defined(WINNT)
|
||||
#ident "$Id: vvm_gates.cc,v 1.3 1999/12/02 04:54:11 steve Exp $"
|
||||
#endif
|
||||
|
||||
# include "vvm_gates.h"
|
||||
|
||||
vvm_out_event::vvm_out_event(vvm_simulation*s, vpip_bit_t v, action_t o)
|
||||
: output_(o), sim_(s), val_(v)
|
||||
{
|
||||
}
|
||||
|
||||
vvm_out_event::~vvm_out_event()
|
||||
{
|
||||
}
|
||||
|
||||
void vvm_out_event::event_function()
|
||||
{
|
||||
output_(sim_, val_);
|
||||
}
|
||||
|
||||
vvm_1bit_out::vvm_1bit_out(vvm_out_event::action_t o, unsigned d)
|
||||
: output_(o), delay_(d)
|
||||
{
|
||||
}
|
||||
|
||||
vvm_1bit_out::~vvm_1bit_out()
|
||||
{
|
||||
}
|
||||
|
||||
void vvm_1bit_out::output(vvm_simulation*sim, vpip_bit_t val)
|
||||
{
|
||||
vvm_event*ev = new vvm_out_event(sim, val, output_);
|
||||
if (delay_ > 0)
|
||||
sim->insert_event(delay_, ev);
|
||||
else
|
||||
sim->active_event(ev);
|
||||
}
|
||||
|
||||
|
||||
vpip_bit_t compute_and(const vpip_bit_t*inp, unsigned count)
|
||||
{
|
||||
vpip_bit_t outval = inp[0];
|
||||
for (unsigned i = 1 ; i < count ; i += 1)
|
||||
outval = outval & inp[i];
|
||||
return outval;
|
||||
}
|
||||
|
||||
vpip_bit_t compute_or(const vpip_bit_t*inp, unsigned count)
|
||||
{
|
||||
vpip_bit_t outval = inp[0];
|
||||
for (unsigned i = 1 ; i < count ; i += 1)
|
||||
outval = outval | inp[i];
|
||||
return outval;
|
||||
}
|
||||
|
||||
vpip_bit_t compute_nor(const vpip_bit_t*inp, unsigned count)
|
||||
{
|
||||
vpip_bit_t outval = inp[0];
|
||||
for (unsigned i = 1 ; i < count ; i += 1)
|
||||
outval = outval | inp[i];
|
||||
return not(outval);
|
||||
}
|
||||
|
||||
vpip_bit_t compute_xor(const vpip_bit_t*inp, unsigned count)
|
||||
{
|
||||
vpip_bit_t outval = inp[0];
|
||||
for (unsigned i = 1; i < count; i++)
|
||||
outval = outval ^ inp[i];
|
||||
return outval;
|
||||
}
|
||||
|
||||
vpip_bit_t compute_nand(const vpip_bit_t*inp, unsigned count)
|
||||
{
|
||||
return not(compute_and(inp,count));
|
||||
}
|
||||
|
||||
vpip_bit_t compute_xnor(const vpip_bit_t*inp, unsigned count)
|
||||
{
|
||||
return not(compute_xor(inp,count));
|
||||
}
|
||||
|
||||
void compute_mux(vpip_bit_t*out, unsigned wid,
|
||||
const vpip_bit_t*sel, unsigned swid,
|
||||
const vpip_bit_t*dat, unsigned size)
|
||||
{
|
||||
unsigned tmp = 0;
|
||||
for (unsigned idx = 0 ; idx < swid ; idx += 1)
|
||||
switch (sel[idx]) {
|
||||
case V0:
|
||||
break;
|
||||
case V1:
|
||||
tmp |= (1<<idx);
|
||||
break;
|
||||
default:
|
||||
tmp = size;
|
||||
break;
|
||||
}
|
||||
|
||||
if (tmp >= size) {
|
||||
|
||||
if (swid > 1) {
|
||||
for (unsigned idx = 0; idx < wid ; idx += 1)
|
||||
out[idx] = Vx;
|
||||
} else {
|
||||
const unsigned b0 = 0;
|
||||
const unsigned b1 = wid;
|
||||
for (unsigned idx = 0 ; idx < wid ; idx += 1) {
|
||||
if (dat[idx+b0] == dat[idx+b1])
|
||||
out[idx] = dat[idx+b0];
|
||||
else
|
||||
out[idx] = Vx;
|
||||
}
|
||||
}
|
||||
|
||||
} else {
|
||||
unsigned b = tmp * wid;
|
||||
for (unsigned idx = 0; idx < wid ; idx += 1)
|
||||
out[idx] = dat[idx+b];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* $Log: vvm_gates.cc,v $
|
||||
* Revision 1.3 1999/12/02 04:54:11 steve
|
||||
* Handle mux sel of X, if inputs are equal.
|
||||
*
|
||||
* Revision 1.2 1999/11/24 04:38:49 steve
|
||||
* LT and GT fixes from Eric Aardoom.
|
||||
*
|
||||
* Revision 1.1 1999/11/22 00:30:52 steve
|
||||
* Detemplate some and, or and nor methods.
|
||||
*
|
||||
*/
|
||||
|
||||
+452
-231
@@ -19,12 +19,23 @@
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
|
||||
*/
|
||||
#if !defined(WINNT)
|
||||
#ident "$Id: vvm_gates.h,v 1.18 1999/11/01 02:07:41 steve Exp $"
|
||||
#ident "$Id: vvm_gates.h,v 1.30 1999/12/02 16:58:58 steve Exp $"
|
||||
#endif
|
||||
|
||||
# include "vvm.h"
|
||||
# include <assert.h>
|
||||
|
||||
extern vpip_bit_t compute_nand(const vpip_bit_t*inp, unsigned count);
|
||||
extern vpip_bit_t compute_and(const vpip_bit_t*inp, unsigned count);
|
||||
extern vpip_bit_t compute_nor(const vpip_bit_t*inp, unsigned count);
|
||||
extern vpip_bit_t compute_or(const vpip_bit_t*inp, unsigned count);
|
||||
extern vpip_bit_t compute_xor(const vpip_bit_t*inp, unsigned count);
|
||||
extern vpip_bit_t compute_xnor(const vpip_bit_t*inp, unsigned count);
|
||||
|
||||
extern void compute_mux(vpip_bit_t*out, unsigned wid,
|
||||
const vpip_bit_t*sel, unsigned swid,
|
||||
const vpip_bit_t*dat, unsigned size);
|
||||
|
||||
/*
|
||||
* A vvm gate is constructed with an input width and an output
|
||||
* function. The input width represents all the input signals that go
|
||||
@@ -37,11 +48,11 @@ class vvm_out_event : public vvm_event {
|
||||
|
||||
public:
|
||||
typedef void (*action_t)(vvm_simulation*, vpip_bit_t);
|
||||
vvm_out_event(vvm_simulation*s, vpip_bit_t v, action_t o)
|
||||
: output_(o), sim_(s), val_(v) { }
|
||||
|
||||
void event_function()
|
||||
{ output_(sim_, val_); }
|
||||
vvm_out_event(vvm_simulation*s, vpip_bit_t v, action_t o);
|
||||
~vvm_out_event();
|
||||
|
||||
void event_function();
|
||||
|
||||
private:
|
||||
const action_t output_;
|
||||
@@ -49,6 +60,18 @@ class vvm_out_event : public vvm_event {
|
||||
const vpip_bit_t val_;
|
||||
};
|
||||
|
||||
class vvm_1bit_out {
|
||||
|
||||
public:
|
||||
vvm_1bit_out(vvm_out_event::action_t, unsigned delay);
|
||||
~vvm_1bit_out();
|
||||
void output(vvm_simulation*sim, vpip_bit_t);
|
||||
|
||||
private:
|
||||
vvm_out_event::action_t output_;
|
||||
unsigned delay_;
|
||||
};
|
||||
|
||||
/*
|
||||
* This template implements the LPM_ADD_SUB device type. The width of
|
||||
* the device is a template parameter. The device handles addition and
|
||||
@@ -111,47 +134,220 @@ template <unsigned WIDTH> class vvm_add_sub {
|
||||
}
|
||||
};
|
||||
|
||||
template <unsigned WIDTH, unsigned long DELAY> class vvm_and {
|
||||
template <unsigned WIDTH, unsigned long DELAY>
|
||||
class vvm_and : private vvm_1bit_out {
|
||||
|
||||
public:
|
||||
explicit vvm_and(vvm_out_event::action_t o)
|
||||
: output_(o) { }
|
||||
: vvm_1bit_out(o, DELAY) { }
|
||||
|
||||
void init_I(unsigned idx, vpip_bit_t val)
|
||||
{ input_[idx] = val; }
|
||||
|
||||
void start(vvm_simulation*sim)
|
||||
{ vvm_event*ev = new vvm_out_event(sim, compute_(), output_);
|
||||
if (DELAY > 0)
|
||||
sim->insert_event(DELAY, ev);
|
||||
else
|
||||
sim->active_event(ev);
|
||||
}
|
||||
{ output(sim, compute_and(input_,WIDTH)); }
|
||||
|
||||
void set_I(vvm_simulation*sim, unsigned idx, vpip_bit_t val)
|
||||
{ if (input_[idx] == val)
|
||||
return;
|
||||
{ if (input_[idx] == val) return;
|
||||
input_[idx] = val;
|
||||
|
||||
vvm_event*ev = new vvm_out_event(sim, compute_(), output_);
|
||||
if (DELAY > 0)
|
||||
sim->insert_event(DELAY, ev);
|
||||
else
|
||||
sim->active_event(ev);
|
||||
output(sim, compute_and(input_,WIDTH));
|
||||
}
|
||||
|
||||
private:
|
||||
vpip_bit_t compute_() const
|
||||
{ vpip_bit_t outval = input_[0];
|
||||
for (unsigned i = 1 ; i < WIDTH ; i += 1)
|
||||
outval = outval & input_[i];
|
||||
return outval;
|
||||
vpip_bit_t input_[WIDTH];
|
||||
};
|
||||
|
||||
template <unsigned WIDTH, unsigned WDIST> class vvm_clshift {
|
||||
|
||||
public:
|
||||
explicit vvm_clshift()
|
||||
{ dir_ = V0;
|
||||
dist_val_ = WIDTH;
|
||||
for (unsigned idx = 0 ; idx < WIDTH ; idx += 1)
|
||||
data_[idx] = Vx;
|
||||
for (unsigned idx = 0 ; idx < WIDTH ; idx += 1)
|
||||
out_[idx] = 0;
|
||||
for (unsigned idx = 0 ; idx < WDIST ; idx += 1)
|
||||
dist_[idx] = Vx;
|
||||
}
|
||||
|
||||
vpip_bit_t input_[WIDTH];
|
||||
vvm_out_event::action_t output_;
|
||||
~vvm_clshift() { }
|
||||
|
||||
void init_Data(unsigned idx, vpip_bit_t val)
|
||||
{ data_[idx] = val;
|
||||
}
|
||||
void init_Distance(unsigned idx, vpip_bit_t val)
|
||||
{ dist_[idx] = val;
|
||||
calculate_dist_();
|
||||
}
|
||||
void init_Direction(vpip_bit_t val)
|
||||
{ dir_ = val; }
|
||||
|
||||
void set_Data(vvm_simulation*sim, unsigned idx, vpip_bit_t val)
|
||||
{ if (data_[idx] == val) return;
|
||||
data_[idx] = val;
|
||||
if ((dist_val_ + idx) >= WIDTH) return;
|
||||
if ((dist_val_ + idx) < 0) return;
|
||||
vvm_out_event::action_t out = out_[dist_val_+idx];
|
||||
if (out == 0) return;
|
||||
vvm_event*ev = new vvm_out_event(sim, val, out);
|
||||
sim->active_event(ev);
|
||||
}
|
||||
|
||||
void set_Distance(vvm_simulation*sim, unsigned idx, vpip_bit_t val)
|
||||
{ if (dist_[idx] == val) return;
|
||||
dist_[idx] = val;
|
||||
calculate_dist_();
|
||||
compute_(sim);
|
||||
}
|
||||
|
||||
void set_Direction(vvm_simulation*sim, unsigned, vpip_bit_t val)
|
||||
{ if (dir_ == val) return;
|
||||
dir_ = val;
|
||||
calculate_dist_();
|
||||
compute_(sim);
|
||||
}
|
||||
|
||||
void config_rout(unsigned idx, vvm_out_event::action_t o)
|
||||
{ out_[idx] = o;
|
||||
}
|
||||
|
||||
private:
|
||||
vpip_bit_t dir_;
|
||||
vpip_bit_t data_[WIDTH];
|
||||
vpip_bit_t dist_[WDIST];
|
||||
vvm_out_event::action_t out_[WIDTH];
|
||||
int dist_val_;
|
||||
|
||||
void calculate_dist_()
|
||||
{ int tmp = 0;
|
||||
for (unsigned idx = 0 ; idx < WDIST ; idx += 1)
|
||||
switch (dist_[idx]) {
|
||||
case V0:
|
||||
break;
|
||||
case V1:
|
||||
tmp |= 1<<idx;
|
||||
break;
|
||||
default:
|
||||
tmp = WIDTH;
|
||||
}
|
||||
if (tmp > WIDTH)
|
||||
tmp = WIDTH;
|
||||
else if (dir_ == V1)
|
||||
tmp = -tmp;
|
||||
dist_val_ = tmp;
|
||||
}
|
||||
|
||||
void compute_(vvm_simulation*sim)
|
||||
{ vvm_event*ev;
|
||||
if (dist_val_ == WIDTH) {
|
||||
for (unsigned idx = 0 ; idx < WIDTH ; idx += 1) {
|
||||
if (out_[idx] == 0) continue;
|
||||
ev = new vvm_out_event(sim, Vx, out_[idx]);
|
||||
sim->active_event(ev);
|
||||
}
|
||||
return;
|
||||
}
|
||||
for (int idx = 0 ; idx < WIDTH ; idx += 1) {
|
||||
if (out_[idx] == 0) continue;
|
||||
vpip_bit_t val;
|
||||
if ((idx-dist_val_) >= WIDTH) val = V0;
|
||||
else if ((idx-dist_val_) < 0) val = V0;
|
||||
else val = data_[idx-dist_val_];
|
||||
ev = new vvm_out_event(sim, val, out_[idx]);
|
||||
sim->active_event(ev);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
template <unsigned WIDTH> class vvm_compare {
|
||||
|
||||
public:
|
||||
explicit vvm_compare()
|
||||
{ out_lt_ = 0;
|
||||
out_le_ = 0;
|
||||
gt_ = Vx;
|
||||
lt_ = Vx;
|
||||
for (unsigned idx = 0 ; idx < WIDTH ; idx += 1) {
|
||||
a_[idx] = Vx;
|
||||
b_[idx] = Vx;
|
||||
}
|
||||
}
|
||||
~vvm_compare() { }
|
||||
|
||||
void init_DataA(unsigned idx, vpip_bit_t val)
|
||||
{ a_[idx] = val; }
|
||||
void init_DataB(unsigned idx, vpip_bit_t val)
|
||||
{ b_[idx] = val; }
|
||||
|
||||
void set_DataA(vvm_simulation*sim, unsigned idx, vpip_bit_t val)
|
||||
{ if (a_[idx] == val) return;
|
||||
a_[idx] = val;
|
||||
compute_(sim);
|
||||
}
|
||||
|
||||
void set_DataB(vvm_simulation*sim, unsigned idx, vpip_bit_t val)
|
||||
{ if (b_[idx] == val) return;
|
||||
b_[idx] = val;
|
||||
compute_(sim);
|
||||
}
|
||||
|
||||
void config_ALB_out(vvm_out_event::action_t o)
|
||||
{ out_lt_ = o; }
|
||||
|
||||
void config_ALEB_out(vvm_out_event::action_t o)
|
||||
{ out_le_ = o; }
|
||||
|
||||
void config_AGB_out(vvm_out_event::action_t o)
|
||||
{ out_gt_ = o; }
|
||||
|
||||
void config_AGEB_out(vvm_out_event::action_t o)
|
||||
{ out_ge_ = o; }
|
||||
|
||||
private:
|
||||
vpip_bit_t a_[WIDTH];
|
||||
vpip_bit_t b_[WIDTH];
|
||||
|
||||
vpip_bit_t gt_;
|
||||
vpip_bit_t lt_;
|
||||
|
||||
vvm_out_event::action_t out_lt_;
|
||||
vvm_out_event::action_t out_le_;
|
||||
vvm_out_event::action_t out_gt_;
|
||||
vvm_out_event::action_t out_ge_;
|
||||
|
||||
void compute_(vvm_simulation*sim)
|
||||
{ vpip_bit_t gt = V0;
|
||||
vpip_bit_t lt = V0;
|
||||
vvm_event*ev;
|
||||
for (unsigned idx = 0 ; idx < WIDTH ; idx += 1) {
|
||||
gt = greater_with_cascade(a_[idx], b_[idx], gt);
|
||||
lt = less_with_cascade(a_[idx], b_[idx], lt);
|
||||
}
|
||||
|
||||
if ((gt_ == gt) && (lt_ == lt)) return;
|
||||
gt_ = gt;
|
||||
lt_ = lt;
|
||||
if (out_lt_) {
|
||||
ev = new vvm_out_event(sim, lt_, out_lt_);
|
||||
sim->active_event(ev);
|
||||
}
|
||||
if (out_le_) {
|
||||
ev = new vvm_out_event(sim, not(gt_), out_le_);
|
||||
sim->active_event(ev);
|
||||
}
|
||||
if (out_gt_) {
|
||||
ev = new vvm_out_event(sim, gt_, out_gt_);
|
||||
sim->active_event(ev);
|
||||
}
|
||||
if (out_ge_) {
|
||||
ev = new vvm_out_event(sim, not(lt_), out_ge_);
|
||||
sim->active_event(ev);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
* This class simulates the LPM flip-flop device.
|
||||
* XXXX Inverted clock not yet supported.
|
||||
@@ -202,70 +398,182 @@ template <unsigned WIDTH> class vvm_ff {
|
||||
}
|
||||
};
|
||||
|
||||
template <unsigned WIDTH, unsigned long DELAY> class vvm_or {
|
||||
/*
|
||||
* This class supports mux devices. The width is the width of the data
|
||||
* (or bus) path, SIZE is the number of alternative inputs and SELWID
|
||||
* is the size (in bits) of the selector input.
|
||||
*/
|
||||
template <unsigned WIDTH, unsigned SIZE, unsigned SELWID> class vvm_mux {
|
||||
|
||||
public:
|
||||
explicit vvm_mux()
|
||||
{ unsigned idx;
|
||||
for (idx = 0 ; idx < WIDTH ; idx += 1) out_[idx] = 0;
|
||||
for (idx = 0 ; idx < WIDTH ; idx += 1) output_[idx] = Vx;
|
||||
for (idx = 0 ; idx < SELWID; idx += 1) sel_[idx] = Vx;
|
||||
for (idx = 0 ; idx < WIDTH*SIZE; idx += 1) input_[idx] = Vx;
|
||||
}
|
||||
|
||||
void init_Sel(unsigned idx, vpip_bit_t val)
|
||||
{ sel_[idx] = val; }
|
||||
|
||||
void init_Data(unsigned idx, vpip_bit_t val)
|
||||
{ input_[idx] = val; }
|
||||
|
||||
void set_Sel(vvm_simulation*sim, unsigned idx, vpip_bit_t val)
|
||||
{ if (sel_[idx] == val) return;
|
||||
sel_[idx] = val;
|
||||
evaluate_(sim);
|
||||
}
|
||||
|
||||
void set_Data(vvm_simulation*sim, unsigned idx, vpip_bit_t val)
|
||||
{ if (input_[idx] == val) return;
|
||||
input_[idx] = val;
|
||||
evaluate_(sim);
|
||||
}
|
||||
|
||||
void config_rout(unsigned idx, vvm_out_event::action_t o)
|
||||
{ out_[idx] = o; }
|
||||
|
||||
private:
|
||||
vpip_bit_t sel_[SELWID];
|
||||
vpip_bit_t input_[WIDTH * SIZE];
|
||||
vpip_bit_t output_[WIDTH];
|
||||
|
||||
vvm_out_event::action_t out_[WIDTH];
|
||||
|
||||
void evaluate_(vvm_simulation*sim)
|
||||
{ vpip_bit_t tmp[WIDTH];
|
||||
compute_mux(tmp, WIDTH, sel_, SELWID, input_, SIZE);
|
||||
for (unsigned idx = 0 ; idx < WIDTH ; idx += 1)
|
||||
if (tmp[idx] != output_[idx]) {
|
||||
output_[idx] = tmp[idx];
|
||||
vvm_event*ev = new vvm_out_event(sim,
|
||||
output_[idx],
|
||||
out_[idx]);
|
||||
sim->active_event(ev);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
template <unsigned WIDTH, unsigned long DELAY>
|
||||
class vvm_or : private vvm_1bit_out {
|
||||
|
||||
public:
|
||||
explicit vvm_or(vvm_out_event::action_t o)
|
||||
: output_(o) { }
|
||||
: vvm_1bit_out(o,DELAY) { }
|
||||
|
||||
void init_I(unsigned idx, vpip_bit_t val)
|
||||
{ input_[idx] = val; }
|
||||
|
||||
void start(vvm_simulation*sim)
|
||||
{ vvm_event*ev = new vvm_out_event(sim, compute_(), output_);
|
||||
if (DELAY > 0)
|
||||
sim->insert_event(DELAY, ev);
|
||||
else
|
||||
sim->active_event(ev);
|
||||
}
|
||||
{ output(sim, compute_or(input_,WIDTH)); }
|
||||
|
||||
void set_I(vvm_simulation*sim, unsigned idx, vpip_bit_t val)
|
||||
{ if (input_[idx] == val)
|
||||
return;
|
||||
input_[idx] = val;
|
||||
|
||||
vvm_event*ev = new vvm_out_event(sim, compute_(), output_);
|
||||
if (DELAY > 0)
|
||||
sim->insert_event(DELAY, ev);
|
||||
else
|
||||
sim->active_event(ev);
|
||||
output(sim, compute_or(input_,WIDTH));
|
||||
}
|
||||
|
||||
private:
|
||||
vpip_bit_t compute_() const
|
||||
{ vpip_bit_t outval = input_[0];
|
||||
for (unsigned i = 1 ; i < WIDTH ; i += 1)
|
||||
outval = outval | input_[i];
|
||||
return outval;
|
||||
}
|
||||
|
||||
vpip_bit_t input_[WIDTH];
|
||||
vvm_out_event::action_t output_;
|
||||
};
|
||||
|
||||
template <unsigned WIDTH, unsigned long DELAY> class vvm_nor {
|
||||
template <unsigned WIDTH, unsigned long DELAY>
|
||||
class vvm_nor : private vvm_1bit_out {
|
||||
|
||||
public:
|
||||
explicit vvm_nor(vvm_out_event::action_t o)
|
||||
: output_(o) { }
|
||||
: vvm_1bit_out(o, DELAY) { }
|
||||
|
||||
void init_I(unsigned idx, vpip_bit_t val)
|
||||
{ input_[idx] = val; }
|
||||
|
||||
void start(vvm_simulation*sim)
|
||||
{ vvm_event*ev = new vvm_out_event(sim, compute_(), output_);
|
||||
if (DELAY > 0)
|
||||
sim->insert_event(DELAY, ev);
|
||||
else
|
||||
sim->active_event(ev);
|
||||
}
|
||||
{ output(sim, compute_nor(input_,WIDTH)); }
|
||||
|
||||
void set_I(vvm_simulation*sim, unsigned idx, vpip_bit_t val)
|
||||
{ if (input_[idx] == val)
|
||||
return;
|
||||
input_[idx] = val;
|
||||
output(sim, compute_nor(input_,WIDTH));
|
||||
}
|
||||
|
||||
vvm_event*ev = new vvm_out_event(sim, compute_(), output_);
|
||||
private:
|
||||
vpip_bit_t input_[WIDTH];
|
||||
};
|
||||
|
||||
template <unsigned WIDTH, unsigned AWIDTH, unsigned SIZE>
|
||||
class vvm_ram_dq : protected vvm_ram_callback {
|
||||
|
||||
public:
|
||||
vvm_ram_dq(vvm_memory_t<WIDTH,SIZE>*mem)
|
||||
: mem_(mem)
|
||||
{ mem->set_callback(this);
|
||||
for (unsigned idx = 0 ; idx < WIDTH ; idx += 1)
|
||||
out_[idx] = 0;
|
||||
for (unsigned idx = 0 ; idx < AWIDTH ; idx += 1)
|
||||
addr_[idx] = Vx;
|
||||
}
|
||||
|
||||
void init_Address(unsigned idx, vpip_bit_t val)
|
||||
{ addr_[idx] = val; }
|
||||
|
||||
void set_Address(vvm_simulation*sim, unsigned idx, vpip_bit_t val)
|
||||
{ if (addr_[idx] == val) return;
|
||||
addr_[idx] = val;
|
||||
compute_();
|
||||
send_out_(sim);
|
||||
}
|
||||
|
||||
void handle_write(vvm_simulation*sim, unsigned idx)
|
||||
{ if (idx == addr_val_) send_out_(sim); }
|
||||
|
||||
void config_rout(unsigned idx, vvm_out_event::action_t o)
|
||||
{ out_[idx] = o; }
|
||||
|
||||
private:
|
||||
vvm_memory_t<WIDTH,SIZE>*mem_;
|
||||
vpip_bit_t addr_[AWIDTH];
|
||||
vvm_out_event::action_t out_[WIDTH];
|
||||
|
||||
unsigned long addr_val_;
|
||||
|
||||
void compute_()
|
||||
{ unsigned bit;
|
||||
unsigned mask;
|
||||
addr_val_ = 0;
|
||||
for (bit = 0, mask = 1 ; bit < AWIDTH ; bit += 1, mask <<= 1)
|
||||
if (addr_[bit] == V1) addr_val_ |= mask;
|
||||
}
|
||||
|
||||
void send_out_(vvm_simulation*sim)
|
||||
{ vvm_bitset_t<WIDTH>ov = mem_->get_word(addr_val_);
|
||||
for (unsigned bit = 0 ; bit < WIDTH ; bit += 1)
|
||||
if (out_[bit]) {
|
||||
vvm_event*ev = new vvm_out_event(sim,
|
||||
ov[bit],
|
||||
out_[bit]);
|
||||
sim->active_event(ev);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
template <unsigned long DELAY> class vvm_buf {
|
||||
|
||||
public:
|
||||
explicit vvm_buf(vvm_out_event::action_t o)
|
||||
: output_(o)
|
||||
{ }
|
||||
|
||||
void init_I(unsigned, vpip_bit_t) { }
|
||||
void start(vvm_simulation*) { }
|
||||
|
||||
void set_I(vvm_simulation*sim, unsigned, vpip_bit_t val)
|
||||
{ vpip_bit_t outval = val;
|
||||
if (val == Vz) val = Vx;
|
||||
vvm_event*ev = new vvm_out_event(sim, outval, output_);
|
||||
if (DELAY > 0)
|
||||
sim->insert_event(DELAY, ev);
|
||||
else
|
||||
@@ -273,14 +581,6 @@ template <unsigned WIDTH, unsigned long DELAY> class vvm_nor {
|
||||
}
|
||||
|
||||
private:
|
||||
vpip_bit_t compute_() const
|
||||
{ vpip_bit_t outval = input_[0];
|
||||
for (unsigned i = 1 ; i < WIDTH ; i += 1)
|
||||
outval = outval | input_[i];
|
||||
return not(outval);
|
||||
}
|
||||
|
||||
vpip_bit_t input_[WIDTH];
|
||||
vvm_out_event::action_t output_;
|
||||
};
|
||||
|
||||
@@ -319,112 +619,101 @@ template <unsigned long DELAY> class vvm_bufif1 {
|
||||
}
|
||||
};
|
||||
|
||||
template <unsigned WIDTH, unsigned long DELAY> class vvm_nand {
|
||||
template <unsigned WIDTH, unsigned long DELAY>
|
||||
class vvm_nand : private vvm_1bit_out {
|
||||
|
||||
public:
|
||||
explicit vvm_nand(vvm_out_event::action_t o)
|
||||
: output_(o)
|
||||
{ for (unsigned idx = 0 ; idx < WIDTH ; idx += 1)
|
||||
input_[idx] = V0;
|
||||
}
|
||||
: vvm_1bit_out(o, DELAY) { }
|
||||
|
||||
void init(unsigned idx, vpip_bit_t val) { input_[idx-1] = val; }
|
||||
void init_I(unsigned idx, vpip_bit_t val)
|
||||
{ input_[idx] = val; }
|
||||
|
||||
// Set an input of the NAND gate causes a new output value to
|
||||
// be calculated and an event generated to make the output
|
||||
// happen. The input pins are numbered from 1 - WIDTH.
|
||||
void set(vvm_simulation*sim, unsigned idx, vpip_bit_t val)
|
||||
{ if (input_[idx-1] == val)
|
||||
return;
|
||||
input_[idx-1] = val;
|
||||
vpip_bit_t outval = input_[0];
|
||||
for (unsigned i = 1 ; i < WIDTH ; i += 1)
|
||||
outval = outval & input_[i];
|
||||
void start(vvm_simulation*sim)
|
||||
{ output(sim, compute_nand(input_,WIDTH)); }
|
||||
|
||||
vvm_event*ev = new vvm_out_event(sim, not(outval), output_);
|
||||
if (DELAY > 0)
|
||||
sim->insert_event(DELAY, ev);
|
||||
else
|
||||
sim->active_event(ev);
|
||||
void set_I(vvm_simulation*sim, unsigned idx, vpip_bit_t val)
|
||||
{ if (input_[idx] == val) return;
|
||||
input_[idx] = val;
|
||||
output(sim, compute_nand(input_,WIDTH));
|
||||
}
|
||||
|
||||
private:
|
||||
vpip_bit_t input_[WIDTH];
|
||||
vvm_out_event::action_t output_;
|
||||
};
|
||||
|
||||
/*
|
||||
* Simple inverter buffer.
|
||||
*/
|
||||
template <unsigned long DELAY> class vvm_not {
|
||||
template <unsigned long DELAY> class vvm_not : private vvm_1bit_out {
|
||||
|
||||
public:
|
||||
explicit vvm_not(vvm_out_event::action_t o)
|
||||
: output_(o)
|
||||
{ }
|
||||
: vvm_1bit_out(o, DELAY) { }
|
||||
|
||||
void init_I(unsigned, vpip_bit_t) { }
|
||||
void start(vvm_simulation*) { }
|
||||
|
||||
void set_I(vvm_simulation*sim, unsigned, vpip_bit_t val)
|
||||
{ vpip_bit_t outval = not(val);
|
||||
vvm_event*ev = new vvm_out_event(sim, outval, output_);
|
||||
if (DELAY > 0)
|
||||
sim->insert_event(DELAY, ev);
|
||||
else
|
||||
sim->active_event(ev);
|
||||
}
|
||||
{ output(sim, not(val)); }
|
||||
|
||||
private:
|
||||
vvm_out_event::action_t output_;
|
||||
};
|
||||
|
||||
template <unsigned WIDTH, unsigned long DELAY> class vvm_xnor {
|
||||
template <unsigned WIDTH, unsigned long DELAY>
|
||||
class vvm_xnor : private vvm_1bit_out {
|
||||
|
||||
public:
|
||||
explicit vvm_xnor(vvm_out_event::action_t o)
|
||||
: output_(o) { }
|
||||
: vvm_1bit_out(o,DELAY) { }
|
||||
|
||||
void init_I(unsigned idx, vpip_bit_t val) { input_[idx] = val; }
|
||||
|
||||
void start(vvm_simulation*sim)
|
||||
{ vvm_event*ev = new vvm_out_event(sim, compute_(), output_);
|
||||
if (DELAY > 0)
|
||||
sim->insert_event(DELAY, ev);
|
||||
else
|
||||
sim->active_event(ev);
|
||||
}
|
||||
|
||||
|
||||
{ output(sim,compute_xnor(input_,WIDTH)); }
|
||||
|
||||
void set_I(vvm_simulation*sim, unsigned idx, vpip_bit_t val)
|
||||
{ if (input_[idx] == val)
|
||||
return;
|
||||
input_[idx] = val;
|
||||
vpip_bit_t outval = compute_();
|
||||
vvm_event*ev = new vvm_out_event(sim, outval, output_);
|
||||
if (DELAY > 0)
|
||||
sim->insert_event(DELAY, ev);
|
||||
else
|
||||
sim->active_event(ev);
|
||||
output(sim,compute_xnor(input_,WIDTH));
|
||||
}
|
||||
|
||||
private:
|
||||
vpip_bit_t compute_() const
|
||||
{ vpip_bit_t outval = input_[0];
|
||||
for (unsigned i = 1 ; i < WIDTH ; i += 1)
|
||||
outval = outval ^ input_[i];
|
||||
|
||||
outval = not(outval);
|
||||
return outval;
|
||||
}
|
||||
vpip_bit_t input_[WIDTH];
|
||||
vvm_out_event::action_t output_;
|
||||
};
|
||||
|
||||
template <unsigned WIDTH, unsigned long DELAY> class vvm_xor {
|
||||
template <unsigned WIDTH, unsigned long DELAY>
|
||||
class vvm_xor : private vvm_1bit_out {
|
||||
|
||||
public:
|
||||
explicit vvm_xor(vvm_out_event::action_t o)
|
||||
: vvm_1bit_out(o,DELAY) { }
|
||||
|
||||
void init_I(unsigned idx, vpip_bit_t val)
|
||||
{ input_[idx] = val; }
|
||||
|
||||
void start(vvm_simulation*sim)
|
||||
{ output(sim,compute_xor(input_,WIDTH)); }
|
||||
|
||||
void set_I(vvm_simulation*sim, unsigned idx, vpip_bit_t val)
|
||||
{ if (input_[idx] == val)
|
||||
return;
|
||||
input_[idx] = val;
|
||||
output(sim,compute_xor(input_,WIDTH)); }
|
||||
|
||||
private:
|
||||
vpip_bit_t input_[WIDTH];
|
||||
};
|
||||
|
||||
/*
|
||||
* This gate has only 3 pins, the output at pin 0 and two inputs. The
|
||||
* output is 1 or 0 if the two inputs are exactly equal or not.
|
||||
*/
|
||||
template <unsigned long DELAY> class vvm_eeq {
|
||||
|
||||
public:
|
||||
explicit vvm_eeq(vvm_out_event::action_t o)
|
||||
: output_(o) { }
|
||||
|
||||
void init_I(unsigned idx, vpip_bit_t val)
|
||||
@@ -445,47 +734,6 @@ template <unsigned WIDTH, unsigned long DELAY> class vvm_xor {
|
||||
start(sim);
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
vpip_bit_t compute_() const
|
||||
{ vpip_bit_t outval = input_[0];
|
||||
for (unsigned i = 1 ; i < WIDTH ; i += 1)
|
||||
outval = outval ^ input_[i];
|
||||
return outval;
|
||||
}
|
||||
|
||||
vpip_bit_t input_[WIDTH];
|
||||
vvm_out_event::action_t output_;
|
||||
};
|
||||
|
||||
/*
|
||||
* This gate has only 3 pins, the output at pin 0 and two inputs. The
|
||||
* output is 1 or 0 if the two inputs are exactly equal or not.
|
||||
*/
|
||||
template <unsigned long DELAY> class vvm_eeq {
|
||||
|
||||
public:
|
||||
explicit vvm_eeq(vvm_out_event::action_t o)
|
||||
: output_(o) { }
|
||||
|
||||
void init(unsigned idx, vpip_bit_t val)
|
||||
{ input_[idx-1] = val; }
|
||||
|
||||
void start(vvm_simulation*sim)
|
||||
{ vvm_event*ev = new vvm_out_event(sim, compute_(), output_);
|
||||
if (DELAY > 0)
|
||||
sim->insert_event(DELAY, ev);
|
||||
else
|
||||
sim->active_event(ev);
|
||||
}
|
||||
|
||||
void set(vvm_simulation*sim, unsigned idx, vpip_bit_t val)
|
||||
{ if (input_[idx-1] == val)
|
||||
return;
|
||||
input_[idx-1] = val;
|
||||
start(sim);
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
vpip_bit_t compute_() const
|
||||
@@ -649,73 +897,46 @@ template <unsigned WIDTH> class vvm_pevent {
|
||||
|
||||
/*
|
||||
* $Log: vvm_gates.h,v $
|
||||
* Revision 1.30 1999/12/02 16:58:58 steve
|
||||
* Update case comparison (Eric Aardoom).
|
||||
*
|
||||
* Revision 1.29 1999/12/02 04:54:11 steve
|
||||
* Handle mux sel of X, if inputs are equal.
|
||||
*
|
||||
* Revision 1.28 1999/11/25 01:34:04 steve
|
||||
* Reduce more gate templates to use vvm_1bit_out (Eric Aardoom)
|
||||
*
|
||||
* Revision 1.27 1999/11/24 04:38:49 steve
|
||||
* LT and GT fixes from Eric Aardoom.
|
||||
*
|
||||
* Revision 1.26 1999/11/22 00:30:52 steve
|
||||
* Detemplate some and, or and nor methods.
|
||||
*
|
||||
* Revision 1.25 1999/11/21 01:16:51 steve
|
||||
* Fix coding errors handling names of logic devices,
|
||||
* and add support for buf device in vvm.
|
||||
*
|
||||
* Revision 1.24 1999/11/21 00:13:09 steve
|
||||
* Support memories in continuous assignments.
|
||||
*
|
||||
* Revision 1.23 1999/11/15 00:42:31 steve
|
||||
* Fixup to include right shift support.
|
||||
*
|
||||
* Revision 1.22 1999/11/14 23:43:46 steve
|
||||
* Support combinatorial comparators.
|
||||
*
|
||||
* Revision 1.21 1999/11/14 20:24:28 steve
|
||||
* Add support for the LPM_CLSHIFT device.
|
||||
*
|
||||
* Revision 1.20 1999/11/14 18:22:12 steve
|
||||
* Fix NAND gate support to use named pins.
|
||||
*
|
||||
* Revision 1.19 1999/11/13 03:46:52 steve
|
||||
* Support the LPM_MUX in vvm.
|
||||
*
|
||||
* Revision 1.18 1999/11/01 02:07:41 steve
|
||||
* Add the synth functor to do generic synthesis
|
||||
* and add the LPM_FF device to handle rows of
|
||||
* flip-flops.
|
||||
*
|
||||
* Revision 1.17 1999/10/31 20:08:24 steve
|
||||
* Include subtraction in LPM_ADD_SUB device.
|
||||
*
|
||||
* Revision 1.16 1999/10/31 04:11:28 steve
|
||||
* Add to netlist links pin name and instance number,
|
||||
* and arrange in vvm for pin connections by name
|
||||
* and instance number.
|
||||
*
|
||||
* Revision 1.15 1999/10/28 00:47:25 steve
|
||||
* Rewrite vvm VPI support to make objects more
|
||||
* persistent, rewrite the simulation scheduler
|
||||
* in C (to interface with VPI) and add VPI support
|
||||
* for callbacks.
|
||||
*
|
||||
* Revision 1.14 1999/10/10 01:59:55 steve
|
||||
* Structural case equals device.
|
||||
*
|
||||
* Revision 1.13 1999/10/09 19:24:36 steve
|
||||
* NOR device.
|
||||
*
|
||||
* Revision 1.12 1999/07/17 03:07:27 steve
|
||||
* pevent objects have initial values.
|
||||
*
|
||||
* Revision 1.11 1999/06/09 00:58:29 steve
|
||||
* Support for binary | (Stephen Tell)
|
||||
*
|
||||
* Revision 1.10 1999/05/03 01:51:29 steve
|
||||
* Restore support for wait event control.
|
||||
*
|
||||
* Revision 1.9 1999/05/01 20:43:55 steve
|
||||
* Handle wide events, such as @(a) where a has
|
||||
* many bits in it.
|
||||
*
|
||||
* Add to vvm the binary ^ and unary & operators.
|
||||
*
|
||||
* Dump events a bit more completely.
|
||||
*
|
||||
* Revision 1.8 1999/05/01 02:57:53 steve
|
||||
* Handle much more complex event expressions.
|
||||
*
|
||||
* Revision 1.7 1999/02/15 05:52:50 steve
|
||||
* Mangle that handles device instance numbers.
|
||||
*
|
||||
* Revision 1.6 1999/01/31 18:15:55 steve
|
||||
* Missing start methods.
|
||||
*
|
||||
* Revision 1.5 1999/01/01 01:44:56 steve
|
||||
* Support the start() method.
|
||||
*
|
||||
* Revision 1.4 1998/12/20 02:05:41 steve
|
||||
* Function to calculate wire initial value.
|
||||
*
|
||||
* Revision 1.3 1998/12/17 23:54:58 steve
|
||||
* VVM support for small sequential UDP objects.
|
||||
*
|
||||
* Revision 1.2 1998/11/10 00:48:31 steve
|
||||
* Add support it vvm target for level-sensitive
|
||||
* triggers (i.e. the Verilog wait).
|
||||
* Fix display of $time is format strings.
|
||||
*
|
||||
* Revision 1.1 1998/11/09 23:44:11 steve
|
||||
* Add vvm library.
|
||||
*
|
||||
*/
|
||||
#endif
|
||||
|
||||
@@ -15,11 +15,12 @@ GENERATE XNF OUTPUT -- THE SHORT STORY
|
||||
The easiest way to compile for XNF output is with the "verilog"
|
||||
command (man verilog) and the -X switch:
|
||||
|
||||
% verilog -fpart=4010e -X prog.v
|
||||
% verilog -fpart=4010e -fncf=prog.ncf -X prog.v
|
||||
|
||||
This generates from the prog.v Verilog source file the prog.xnf
|
||||
output. The verilog program arranges to call the preprocessor and the
|
||||
ivl compiler with all the correct switches for generating XNF.
|
||||
This generates from the prog.v Verilog source file the prog.xnf output
|
||||
and the prog.ncf netlist constraints file. The verilog program
|
||||
arranges to call the preprocessor and the ivl compiler with all the
|
||||
correct switches for generating XNF.
|
||||
|
||||
XNF PADS IN VERILOG SOURCE
|
||||
|
||||
@@ -101,7 +102,7 @@ line. The code generator needs to know the type of part to generate
|
||||
code for, so the ``-fpart=<type>'' flag is also needed. For example,
|
||||
to generate code for the 4010E the command line might start out as:
|
||||
|
||||
ivl -txnf -fpart=4010e -Fsynth -Fsigfold -Fxnfio [...]
|
||||
ivl -txnf -fpart=4010e -Fsynth -Fnodangle -Fxnfio [...]
|
||||
|
||||
Icarus Verilog includes the functions ``synth'' and ``xnfio'' to
|
||||
perform transformations and optimizations on the design before code is
|
||||
@@ -109,6 +110,19 @@ generated. The ``synth'' function matches certain behavioral constructs
|
||||
to structural components, and the xnfio function generates pads and
|
||||
fills the IOBs.
|
||||
|
||||
SUPPORTED FLAGS
|
||||
|
||||
-fpart=<part>
|
||||
Specify the type of part to target. This string is written
|
||||
literally into the PART, record of the XNF, and may also be
|
||||
used to control synthesis and placement.
|
||||
|
||||
-fncf=<path>
|
||||
Cause the code generator to write into <path> the netlist
|
||||
constraints needed for controlling placement and timing. This
|
||||
switch is required if pin assignments are assigned in the
|
||||
Verilog source.
|
||||
|
||||
THE SYNTH FUNCTION
|
||||
|
||||
This function does synthesis transformations on the entered design,
|
||||
@@ -162,6 +176,14 @@ IBUF, NOT gates cannot be absorbed as in the OPAD case.
|
||||
|
||||
|
||||
$Log: xnf.txt,v $
|
||||
Revision 1.9 1999/11/18 03:52:20 steve
|
||||
Turn NetTmp objects into normal local NetNet objects,
|
||||
and add the nodangle functor to clean up the local
|
||||
symbols generated by elaboration and other steps.
|
||||
|
||||
Revision 1.8 1999/11/06 04:51:42 steve
|
||||
Support writing some XNF things into an NCF file.
|
||||
|
||||
Revision 1.7 1999/11/03 05:18:18 steve
|
||||
XNF synthesis now uses the synth functor.
|
||||
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
|
||||
*/
|
||||
#if !defined(WINNT)
|
||||
#ident "$Id: xnfio.cc,v 1.5 1999/11/02 04:55:01 steve Exp $"
|
||||
#ident "$Id: xnfio.cc,v 1.9 1999/11/27 19:07:58 steve Exp $"
|
||||
#endif
|
||||
|
||||
# include "functor.h"
|
||||
@@ -49,13 +49,19 @@ static bool is_a_pad(const NetNet*net)
|
||||
* really lame to not do the obvious optimization.
|
||||
*/
|
||||
|
||||
static void make_obuf(Design*des, NetNet*net)
|
||||
static NetLogic* make_obuf(Design*des, NetNet*net)
|
||||
{
|
||||
assert(net->pin_count() == 1);
|
||||
|
||||
/* FIXME: If there is nothing internally driving this PAD, I
|
||||
can connect the PAD to a pullup and disconnect it from the
|
||||
rest of the circuit. This would save routing resources. */
|
||||
if (count_outputs(net->pin(0)) <= 0) {
|
||||
cerr << net->get_line() << ":warning: No outputs to OPAD: "
|
||||
<< net->name() << endl;
|
||||
return 0;
|
||||
}
|
||||
|
||||
assert(count_outputs(net->pin(0)) > 0);
|
||||
|
||||
/* Look for an existing OBUF connected to this signal. If it
|
||||
@@ -73,7 +79,7 @@ static void make_obuf(Design*des, NetNet*net)
|
||||
&& (count_outputs(tmp->pin(0)) == 1)
|
||||
&& (idx->get_pin() == 0) ) {
|
||||
tmp->attribute("XNF-LCA", "OBUF:O,I");
|
||||
return;
|
||||
return tmp;
|
||||
}
|
||||
|
||||
// Try to use an existing INV as an OBUF. Certain
|
||||
@@ -86,7 +92,7 @@ static void make_obuf(Design*des, NetNet*net)
|
||||
&& (count_outputs(tmp->pin(0)) == 1)
|
||||
&& (idx->get_pin() == 0) ) {
|
||||
tmp->attribute("XNF-LCA", "OBUF:O,~I");
|
||||
return;
|
||||
return tmp;
|
||||
}
|
||||
|
||||
// Try to use an existing bufif1 as an OBUFT. Of course
|
||||
@@ -98,7 +104,7 @@ static void make_obuf(Design*des, NetNet*net)
|
||||
&& (count_outputs(tmp->pin(0)) == 1)
|
||||
&& (idx->get_pin() == 0) ) {
|
||||
tmp->attribute("XNF-LCA", "OBUFT:O,I,~T");
|
||||
return;
|
||||
return tmp;
|
||||
}
|
||||
|
||||
if ((tmp->type() == NetLogic::BUFIF0)
|
||||
@@ -106,7 +112,7 @@ static void make_obuf(Design*des, NetNet*net)
|
||||
&& (count_outputs(tmp->pin(0)) == 1)
|
||||
&& (idx->get_pin() == 0) ) {
|
||||
tmp->attribute("XNF-LCA", "OBUFT:O,I,T");
|
||||
return;
|
||||
return tmp;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -129,10 +135,64 @@ static void make_obuf(Design*des, NetNet*net)
|
||||
// of the netlist, to create a ring without a signal. Detect
|
||||
// this case and create a new signal.
|
||||
if (count_signals(buf->pin(1)) == 0) {
|
||||
NetNet*tmp = new NetNet(des->local_symbol("$"), NetNet::WIRE);
|
||||
NetNet*tmp = new NetNet(0, des->local_symbol("$"), NetNet::WIRE);
|
||||
tmp->local_flag(true);
|
||||
connect(buf->pin(1), tmp->pin(0));
|
||||
des->add_signal(tmp);
|
||||
}
|
||||
|
||||
return buf;
|
||||
}
|
||||
|
||||
static void absorb_OFF(Design*des, NetLogic*buf)
|
||||
{
|
||||
/* If the nexus connects is not a simple point-to-point link,
|
||||
then I can't drag it into the IOB. Give up. */
|
||||
if (count_outputs(buf->pin(1)) != 1)
|
||||
return;
|
||||
if (count_inputs(buf->pin(1)) != 1)
|
||||
return;
|
||||
/* For now, only support OUTFF. */
|
||||
if (buf->type() != NetLogic::BUF)
|
||||
return;
|
||||
|
||||
NetObj::Link*drv = find_next_output(&buf->pin(1));
|
||||
assert(drv);
|
||||
|
||||
/* Make sure the device is a FF with width 1. */
|
||||
NetFF*ff = dynamic_cast<NetFF*>(drv->get_obj());
|
||||
if (ff == 0)
|
||||
return;
|
||||
if (ff->width() != 1)
|
||||
return;
|
||||
if (ff->attribute("LPM_FFType") != "DFF")
|
||||
return;
|
||||
|
||||
/* Connect the flip-flop output to the buffer output and
|
||||
delete the buffer. The XNF OUTFF can buffer the pin. */
|
||||
connect(ff->pin_Q(0), buf->pin(0));
|
||||
delete buf;
|
||||
|
||||
/* Finally, build up an XNF-LCA value that defines this
|
||||
devices as an OUTFF and gives each pin an XNF name. */
|
||||
char**names = new char*[ff->pin_count()];
|
||||
for (unsigned idx = 0 ; idx < ff->pin_count() ; idx += 1)
|
||||
names[idx] = "";
|
||||
|
||||
if (ff->attribute("Clock:LPM_Polarity") == "INVERT")
|
||||
names[ff->pin_Clock().get_pin()] = "~C";
|
||||
else
|
||||
names[ff->pin_Clock().get_pin()] = "C";
|
||||
|
||||
names[ff->pin_Data(0).get_pin()] = "D";
|
||||
names[ff->pin_Q(0).get_pin()] = "Q";
|
||||
|
||||
string lname = string("OUTFF:") + names[0];
|
||||
for (unsigned idx = 1 ; idx < ff->pin_count() ; idx += 1)
|
||||
lname = lname + "," + names[idx];
|
||||
delete[]names;
|
||||
|
||||
ff->attribute("XNF-LCA", lname);
|
||||
}
|
||||
|
||||
static void make_ibuf(Design*des, NetNet*net)
|
||||
@@ -178,7 +238,7 @@ static void make_ibuf(Design*des, NetNet*net)
|
||||
// of the netlist, to create a ring without a signal. Detect
|
||||
// this case and create a new signal.
|
||||
if (count_signals(buf->pin(0)) == 0) {
|
||||
NetNet*tmp = new NetNet(des->local_symbol("$"), NetNet::WIRE);
|
||||
NetNet*tmp = new NetNet(0, des->local_symbol("$"), NetNet::WIRE);
|
||||
connect(buf->pin(0), tmp->pin(0));
|
||||
des->add_signal(tmp);
|
||||
}
|
||||
@@ -186,6 +246,7 @@ static void make_ibuf(Design*des, NetNet*net)
|
||||
|
||||
void xnfio_f::signal(Design*des, NetNet*net)
|
||||
{
|
||||
NetNode*buf;
|
||||
if (! is_a_pad(net))
|
||||
return;
|
||||
|
||||
@@ -198,9 +259,13 @@ void xnfio_f::signal(Design*des, NetNet*net)
|
||||
make_ibuf(des, net);
|
||||
break;
|
||||
case 'o':
|
||||
case 'O':
|
||||
make_obuf(des, net);
|
||||
break;
|
||||
case 'O': {
|
||||
NetLogic*buf = make_obuf(des, net);
|
||||
if (buf == 0) break;
|
||||
absorb_OFF(des, buf);
|
||||
break;
|
||||
}
|
||||
|
||||
// FIXME: Only IPAD and OPAD supported. Need to
|
||||
// add support for IOPAD.
|
||||
default:
|
||||
@@ -217,6 +282,20 @@ void xnfio(Design*des)
|
||||
|
||||
/*
|
||||
* $Log: xnfio.cc,v $
|
||||
* Revision 1.9 1999/11/27 19:07:58 steve
|
||||
* Support the creation of scopes.
|
||||
*
|
||||
* Revision 1.8 1999/11/19 05:02:15 steve
|
||||
* Handle inverted clock into OUTFF.
|
||||
*
|
||||
* Revision 1.7 1999/11/19 03:02:25 steve
|
||||
* Detect flip-flops connected to opads and turn
|
||||
* them into OUTFF devices. Inprove support for
|
||||
* the XNF-LCA attribute in the process.
|
||||
*
|
||||
* Revision 1.6 1999/11/18 02:58:37 steve
|
||||
* Handle (with a warning) unconnected opads.
|
||||
*
|
||||
* Revision 1.5 1999/11/02 04:55:01 steve
|
||||
* repair the sense of T from bufif01
|
||||
*
|
||||
|
||||
Reference in New Issue
Block a user