mirror of
https://github.com/steveicarus/iverilog.git
synced 2026-08-28 00:36:14 +02:00
Compare commits
74
Commits
s19991027
...
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 | ||
|
|
cb5fc54b5e | ||
|
|
50e47c4173 | ||
|
|
b3afc108cf | ||
|
|
b66e7b1713 | ||
|
|
73753f1337 | ||
|
|
7195d4e8f1 | ||
|
|
89881adece | ||
|
|
f80c4a309e | ||
|
|
e1bbbe5614 | ||
|
|
71ecf8c143 | ||
|
|
5a2015ee67 | ||
|
|
0721615345 | ||
|
|
2862178a6f | ||
|
|
162b895e1b | ||
|
|
bbf15778b8 |
+5
-5
@@ -18,7 +18,7 @@
|
||||
# 59 Temple Place - Suite 330
|
||||
# Boston, MA 02111-1307, USA
|
||||
#
|
||||
#ident "$Id: Makefile.in,v 1.24 1999/10/23 16:55:51 steve Exp $"
|
||||
#ident "$Id: Makefile.in,v 1.24.2.1 1999/12/03 17:43:49 steve Exp $"
|
||||
#
|
||||
#
|
||||
SHELL = /bin/sh
|
||||
@@ -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.
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
|
||||
*/
|
||||
#if !defined(WINNT)
|
||||
#ident "$Id: PExpr.cc,v 1.10 1999/09/25 02:57:29 steve Exp $"
|
||||
#ident "$Id: PExpr.cc,v 1.11 1999/10/31 04:11:27 steve Exp $"
|
||||
#endif
|
||||
|
||||
# include "PExpr.h"
|
||||
@@ -38,7 +38,7 @@ bool PExpr::is_constant(Module*) const
|
||||
return false;
|
||||
}
|
||||
|
||||
NetNet* PExpr::elaborate_net(Design*des, const string&path,
|
||||
NetNet* PExpr::elaborate_net(Design*des, const string&path, unsigned,
|
||||
unsigned long,
|
||||
unsigned long,
|
||||
unsigned long) const
|
||||
@@ -128,6 +128,11 @@ bool PETernary::is_constant(Module*) const
|
||||
|
||||
/*
|
||||
* $Log: PExpr.cc,v $
|
||||
* Revision 1.11 1999/10/31 04:11:27 steve
|
||||
* Add to netlist links pin name and instance number,
|
||||
* and arrange in vvm for pin connections by name
|
||||
* and instance number.
|
||||
*
|
||||
* Revision 1.10 1999/09/25 02:57:29 steve
|
||||
* Parse system function calls.
|
||||
*
|
||||
|
||||
@@ -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.20 1999/09/25 02:57:29 steve Exp $"
|
||||
#ident "$Id: PExpr.h,v 1.25 1999/11/21 00:13:08 steve Exp $"
|
||||
#endif
|
||||
|
||||
# include <string>
|
||||
@@ -52,11 +52,12 @@ class PExpr : public LineInfo {
|
||||
virtual NetExpr*elaborate_expr(Design*des, const string&path) const;
|
||||
|
||||
// This method elaborate the expression as gates, for use in a
|
||||
// continuous assign or other wholy structural context.
|
||||
// continuous assign or other wholly structural context.
|
||||
virtual NetNet* elaborate_net(Design*des, const string&path,
|
||||
unsigned long rise =0,
|
||||
unsigned long fall =0,
|
||||
unsigned long decay =0) const;
|
||||
unsigned lwidth,
|
||||
unsigned long rise,
|
||||
unsigned long fall,
|
||||
unsigned long decay) const;
|
||||
|
||||
// This method elaborates the expression as gates, but
|
||||
// restricted for use as l-values of continuous assignments.
|
||||
@@ -77,6 +78,7 @@ class PExpr : public LineInfo {
|
||||
// identifiers and any other module specific interpretations
|
||||
// of expresions.
|
||||
virtual bool is_constant(Module*) const;
|
||||
|
||||
};
|
||||
|
||||
ostream& operator << (ostream&, const PExpr&);
|
||||
@@ -91,9 +93,10 @@ class PEConcat : public PExpr {
|
||||
virtual void dump(ostream&) const;
|
||||
virtual NetNet* elaborate_lnet(Design*des, const string&path) const;
|
||||
virtual NetNet* elaborate_net(Design*des, const string&path,
|
||||
unsigned long rise =0,
|
||||
unsigned long fall =0,
|
||||
unsigned long decay =0) const;
|
||||
unsigned width,
|
||||
unsigned long rise,
|
||||
unsigned long fall,
|
||||
unsigned long decay) const;
|
||||
virtual NetExpr*elaborate_expr(Design*des, const string&path) const;
|
||||
virtual bool is_constant(Module*) const;
|
||||
|
||||
@@ -132,9 +135,10 @@ class PEIdent : public PExpr {
|
||||
|
||||
// Structural r-values are OK.
|
||||
virtual NetNet* elaborate_net(Design*des, const string&path,
|
||||
unsigned long rise =0,
|
||||
unsigned long fall =0,
|
||||
unsigned long decay =0) const;
|
||||
unsigned lwidth,
|
||||
unsigned long rise,
|
||||
unsigned long fall,
|
||||
unsigned long decay) const;
|
||||
|
||||
virtual NetExpr*elaborate_expr(Design*des, const string&path) const;
|
||||
|
||||
@@ -155,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 {
|
||||
@@ -168,9 +178,10 @@ class PENumber : public PExpr {
|
||||
|
||||
virtual void dump(ostream&) const;
|
||||
virtual NetNet* elaborate_net(Design*des, const string&path,
|
||||
unsigned long rise =0,
|
||||
unsigned long fall =0,
|
||||
unsigned long decay =0) const;
|
||||
unsigned lwidth,
|
||||
unsigned long rise,
|
||||
unsigned long fall,
|
||||
unsigned long decay) const;
|
||||
virtual NetExpr*elaborate_expr(Design*des, const string&path) const;
|
||||
virtual verinum* eval_const(const Design*des, const string&path) const;
|
||||
|
||||
@@ -205,9 +216,10 @@ class PEUnary : public PExpr {
|
||||
|
||||
virtual void dump(ostream&out) const;
|
||||
virtual NetNet* elaborate_net(Design*des, const string&path,
|
||||
unsigned long rise =0,
|
||||
unsigned long fall =0,
|
||||
unsigned long decay =0) const;
|
||||
unsigned width,
|
||||
unsigned long rise,
|
||||
unsigned long fall,
|
||||
unsigned long decay) const;
|
||||
virtual NetExpr*elaborate_expr(Design*des, const string&path) const;
|
||||
|
||||
private:
|
||||
@@ -225,9 +237,10 @@ class PEBinary : public PExpr {
|
||||
|
||||
virtual void dump(ostream&out) const;
|
||||
virtual NetNet* elaborate_net(Design*des, const string&path,
|
||||
unsigned long rise =0,
|
||||
unsigned long fall =0,
|
||||
unsigned long decay =0) const;
|
||||
unsigned width,
|
||||
unsigned long rise,
|
||||
unsigned long fall,
|
||||
unsigned long decay) const;
|
||||
virtual NetExpr*elaborate_expr(Design*des, const string&path) const;
|
||||
virtual verinum* eval_const(const Design*des, const string&path) const;
|
||||
|
||||
@@ -235,6 +248,22 @@ class PEBinary : public PExpr {
|
||||
char op_;
|
||||
PExpr*left_;
|
||||
PExpr*right_;
|
||||
|
||||
NetNet* elaborate_net_add_(Design*des, const string&path,
|
||||
unsigned lwidth,
|
||||
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;
|
||||
};
|
||||
|
||||
/*
|
||||
@@ -251,6 +280,7 @@ class PETernary : public PExpr {
|
||||
|
||||
virtual void dump(ostream&out) const;
|
||||
virtual NetNet* elaborate_net(Design*des, const string&path,
|
||||
unsigned width,
|
||||
unsigned long rise =0,
|
||||
unsigned long fall =0,
|
||||
unsigned long decay =0) const;
|
||||
@@ -283,6 +313,24 @@ 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.
|
||||
*
|
||||
* Revision 1.21 1999/10/31 04:11:27 steve
|
||||
* Add to netlist links pin name and instance number,
|
||||
* and arrange in vvm for pin connections by name
|
||||
* and instance number.
|
||||
*
|
||||
* Revision 1.20 1999/09/25 02:57:29 steve
|
||||
* Parse system function calls.
|
||||
*
|
||||
|
||||
@@ -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.
|
||||
|
||||
+2
-7
@@ -295,13 +295,6 @@ current state of support for Verilog.
|
||||
|
||||
- fork/join is not supported in vvm runtime
|
||||
|
||||
- structural arithmetic operators are in general not supported.
|
||||
Procedural expressions are OK. Constant expressions are OK.
|
||||
|
||||
assign foo = a + b; // sorry
|
||||
always @(a or b) foo = a + b; // OK
|
||||
parameter foo = a + b; // OK
|
||||
|
||||
- Structural shift operators are in general not supported.
|
||||
Procedural expressions are OK. Constant expressions are OK.
|
||||
|
||||
@@ -334,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)
|
||||
|
||||
+130
-12
@@ -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.50 1999/10/10 01:59:54 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)
|
||||
@@ -84,7 +86,9 @@ void NetNode::dump_node(ostream&o, unsigned ind) const
|
||||
void NetObj::dump_node_pins(ostream&o, unsigned ind) const
|
||||
{
|
||||
for (unsigned idx = 0 ; idx < pin_count() ; idx += 1) {
|
||||
o << setw(ind) << "" << idx;
|
||||
o << setw(ind) << "" << idx << " " << pin(idx).get_name()
|
||||
<< "<" << pin(idx).get_inst() << ">";
|
||||
|
||||
switch (pin(idx).get_dir()) {
|
||||
case Link::PASSIVE:
|
||||
o << " p";
|
||||
@@ -125,6 +129,30 @@ void NetAddSub::dump_node(ostream&o, unsigned ind) const
|
||||
{
|
||||
o << setw(ind) << "" << "Adder (NetAddSub): " << name() << endl;
|
||||
dump_node_pins(o, ind+4);
|
||||
dump_obj_attr(o, ind+4);
|
||||
}
|
||||
|
||||
void NetCLShift::dump_node(ostream&o, unsigned ind) const
|
||||
{
|
||||
o << setw(ind) << "" << "Combinatorial shift (NetCLShift): " <<
|
||||
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;
|
||||
dump_node_pins(o, ind+4);
|
||||
dump_obj_attr(o, ind+4);
|
||||
}
|
||||
|
||||
void NetAssign::dump_node(ostream&o, unsigned ind) const
|
||||
@@ -165,6 +193,13 @@ void NetConst::dump_node(ostream&o, unsigned ind) const
|
||||
dump_node_pins(o, ind+4);
|
||||
}
|
||||
|
||||
void NetFF::dump_node(ostream&o, unsigned ind) const
|
||||
{
|
||||
o << setw(ind) << "" << "LPM_FF: " << name() << endl;
|
||||
dump_node_pins(o, ind+4);
|
||||
dump_obj_attr(o, ind+4);
|
||||
}
|
||||
|
||||
void NetLogic::dump_node(ostream&o, unsigned ind) const
|
||||
{
|
||||
o << setw(ind) << "" << "logic: ";
|
||||
@@ -208,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;
|
||||
@@ -288,6 +331,12 @@ void NetUDP::dump_comb_(ostream&o, unsigned ind) const
|
||||
o << " #(" << rise_time() << "," << fall_time() << "," << decay_time() <<
|
||||
") " << name() << endl;
|
||||
|
||||
for (CM_::const_iterator ent = cm_.begin()
|
||||
; ent != cm_.end() ; ent++) {
|
||||
o << setw(ind+6) << "" << (*ent).first << " --> " <<
|
||||
(*ent).second << endl;
|
||||
}
|
||||
|
||||
dump_node_pins(o, ind+4);
|
||||
dump_obj_attr(o, ind+4);
|
||||
}
|
||||
@@ -532,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_;
|
||||
@@ -658,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();
|
||||
@@ -683,18 +754,10 @@ 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_ << ") : (" <<
|
||||
false_val_ << ")";
|
||||
o << "(" << *cond_ << ") ? (" << *true_val_ << ") : (" <<
|
||||
*false_val_ << ")";
|
||||
}
|
||||
|
||||
void NetEUFunc::dump(ostream&o) const
|
||||
@@ -726,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;
|
||||
@@ -795,6 +866,53 @@ 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]>.
|
||||
*
|
||||
* Add the LPM_MUX device, and integrate it with the
|
||||
* ternary synthesis from Larry. Replace the lpm_mux
|
||||
* generator in t-xnf.cc to use XNF EQU devices to
|
||||
* put muxs into function units.
|
||||
*
|
||||
* Rewrite elaborate_net for the PETernary class to
|
||||
* also use the LPM_MUX device.
|
||||
*
|
||||
* Revision 1.54 1999/11/04 01:12:41 steve
|
||||
* Elaborate combinational UDP devices.
|
||||
*
|
||||
* Revision 1.53 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
|
||||
* flip-flops.
|
||||
*
|
||||
* Revision 1.52 1999/10/31 20:08:24 steve
|
||||
* Include subtraction in LPM_ADD_SUB device.
|
||||
*
|
||||
* Revision 1.51 1999/10/31 04:11:27 steve
|
||||
* Add to netlist links pin name and instance number,
|
||||
* and arrange in vvm for pin connections by name
|
||||
* and instance number.
|
||||
*
|
||||
* Revision 1.50 1999/10/10 01:59:54 steve
|
||||
* Structural case equals device.
|
||||
*
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 1998 Stephen Williams (steve@picturel.com)
|
||||
* 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
|
||||
@@ -17,39 +17,22 @@
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
|
||||
*/
|
||||
#if !defined(WINNT)
|
||||
#ident "$Id: vvm_monitor.cc,v 1.3 1999/10/28 00:47:25 steve Exp $"
|
||||
#ident "$Id: dup_expr.cc,v 1.1 1999/11/27 19:07:57 steve Exp $"
|
||||
#endif
|
||||
|
||||
# include "vvm.h"
|
||||
# include "netlist.h"
|
||||
# include <cassert>
|
||||
|
||||
vvm_monitor_t::vvm_monitor_t(const char*n)
|
||||
: name_(n)
|
||||
NetEScope* NetEScope::dup_expr() const
|
||||
{
|
||||
assert(0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
vvm_monitor_t::~vvm_monitor_t()
|
||||
{
|
||||
}
|
||||
|
||||
const char*vvm_monitor_t::name() const
|
||||
{
|
||||
return name_;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* $Log: vvm_monitor.cc,v $
|
||||
* Revision 1.3 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.2 1999/08/15 01:23:56 steve
|
||||
* Convert vvm to implement system tasks with vpi.
|
||||
*
|
||||
* Revision 1.1 1998/11/09 23:44:11 steve
|
||||
* Add vvm library.
|
||||
* $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.
|
||||
*
|
||||
|
||||
+945
@@ -0,0 +1,945 @@
|
||||
/*
|
||||
* 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: elab_net.cc,v 1.11 1999/12/02 04:08:10 steve Exp $"
|
||||
#endif
|
||||
|
||||
# include "PExpr.h"
|
||||
# include "netlist.h"
|
||||
|
||||
/*
|
||||
* Elaborating binary operations generally involves elaborating the
|
||||
* left and right expressions, then making an output wire and
|
||||
* connecting the lot together with the right kind of gate.
|
||||
*/
|
||||
NetNet* PEBinary::elaborate_net(Design*des, const string&path,
|
||||
unsigned width,
|
||||
unsigned long rise,
|
||||
unsigned long fall,
|
||||
unsigned long decay) const
|
||||
{
|
||||
switch (op_) {
|
||||
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),
|
||||
*rsig = right_->elaborate_net(des, path, width, 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;
|
||||
}
|
||||
|
||||
NetNet*osig;
|
||||
NetNode*gate;
|
||||
NetNode*gate_t;
|
||||
|
||||
switch (op_) {
|
||||
case '^': // XOR
|
||||
assert(lsig->pin_count() == rsig->pin_count());
|
||||
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) {
|
||||
gate = new NetLogic(des->local_symbol(path), 3,
|
||||
NetLogic::XOR);
|
||||
connect(gate->pin(1), lsig->pin(idx));
|
||||
connect(gate->pin(2), rsig->pin(idx));
|
||||
connect(gate->pin(0), osig->pin(idx));
|
||||
gate->rise_time(rise);
|
||||
gate->fall_time(fall);
|
||||
gate->decay_time(decay);
|
||||
des->add_node(gate);
|
||||
}
|
||||
des->add_signal(osig);
|
||||
break;
|
||||
|
||||
case '&': // AND
|
||||
assert(lsig->pin_count() == rsig->pin_count());
|
||||
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) {
|
||||
gate = new NetLogic(des->local_symbol(path), 3,
|
||||
NetLogic::AND);
|
||||
connect(gate->pin(1), lsig->pin(idx));
|
||||
connect(gate->pin(2), rsig->pin(idx));
|
||||
connect(gate->pin(0), osig->pin(idx));
|
||||
gate->rise_time(rise);
|
||||
gate->fall_time(fall);
|
||||
gate->decay_time(decay);
|
||||
des->add_node(gate);
|
||||
}
|
||||
des->add_signal(osig);
|
||||
break;
|
||||
|
||||
case '|': // Bitwise OR
|
||||
assert(lsig->pin_count() == rsig->pin_count());
|
||||
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) {
|
||||
gate = new NetLogic(des->local_symbol(path), 3,
|
||||
NetLogic::OR);
|
||||
connect(gate->pin(1), lsig->pin(idx));
|
||||
connect(gate->pin(2), rsig->pin(idx));
|
||||
connect(gate->pin(0), osig->pin(idx));
|
||||
gate->rise_time(rise);
|
||||
gate->fall_time(fall);
|
||||
gate->decay_time(decay);
|
||||
des->add_node(gate);
|
||||
}
|
||||
des->add_signal(osig);
|
||||
break;
|
||||
|
||||
case 'a': // && (logical AND)
|
||||
gate = new NetLogic(des->local_symbol(path), 3, NetLogic::AND);
|
||||
|
||||
// The first OR gate returns 1 if the left value is true...
|
||||
if (lsig->pin_count() > 1) {
|
||||
gate_t = new NetLogic(des->local_symbol(path),
|
||||
1+lsig->pin_count(), NetLogic::OR);
|
||||
for (unsigned idx = 0 ; idx < lsig->pin_count() ; idx += 1)
|
||||
connect(gate_t->pin(idx+1), lsig->pin(idx));
|
||||
connect(gate->pin(1), gate_t->pin(0));
|
||||
des->add_node(gate_t);
|
||||
} else {
|
||||
connect(gate->pin(1), lsig->pin(0));
|
||||
}
|
||||
|
||||
// The second OR gate returns 1 if the right value is true...
|
||||
if (rsig->pin_count() > 1) {
|
||||
gate_t = new NetLogic(des->local_symbol(path),
|
||||
1+rsig->pin_count(), NetLogic::OR);
|
||||
for (unsigned idx = 0 ; idx < rsig->pin_count() ; idx += 1)
|
||||
connect(gate_t->pin(idx+1), rsig->pin(idx));
|
||||
connect(gate->pin(2), gate_t->pin(0));
|
||||
des->add_node(gate_t);
|
||||
} else {
|
||||
connect(gate->pin(2), rsig->pin(0));
|
||||
}
|
||||
|
||||
// The output is the AND of the two logic values.
|
||||
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);
|
||||
gate->rise_time(rise);
|
||||
gate->fall_time(fall);
|
||||
gate->decay_time(decay);
|
||||
des->add_node(gate);
|
||||
break;
|
||||
|
||||
case 'E': // === (Case equals)
|
||||
case 'e': // ==
|
||||
case 'n': // !=
|
||||
case '<':
|
||||
case '>':
|
||||
case 'G': // >=
|
||||
case 'L': // <=
|
||||
assert(0);
|
||||
break;
|
||||
|
||||
case '+':
|
||||
assert(0);
|
||||
break;
|
||||
|
||||
case 'l':
|
||||
case 'r':
|
||||
assert(0);
|
||||
break;
|
||||
default:
|
||||
cerr << get_line() << ": internal error: unsupported"
|
||||
" combinational operator (" << op_ << ")." << endl;
|
||||
des->errors += 1;
|
||||
osig = 0;
|
||||
}
|
||||
|
||||
if (NetTmp*tmp = dynamic_cast<NetTmp*>(lsig))
|
||||
delete tmp;
|
||||
if (NetTmp*tmp = dynamic_cast<NetTmp*>(rsig))
|
||||
delete tmp;
|
||||
|
||||
return osig;
|
||||
}
|
||||
|
||||
/*
|
||||
* Elaborate the structural +/- as an AddSub object. Connect DataA and
|
||||
* DataB to the parameters, and connect the output signal to the
|
||||
* Result. In this context, the device is a combinational adder with
|
||||
* fixed direction, so leave Add_Sub unconnected and set the
|
||||
* LPM_Direction property.
|
||||
*/
|
||||
NetNet* PEBinary::elaborate_net_add_(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),
|
||||
*rsig = right_->elaborate_net(des, path, lwidth, 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;
|
||||
}
|
||||
|
||||
NetNet*osig;
|
||||
NetNode*gate;
|
||||
NetNode*gate_t;
|
||||
|
||||
string name = des->local_symbol(path);
|
||||
unsigned width = lsig->pin_count();
|
||||
if (rsig->pin_count() > lsig->pin_count())
|
||||
width = rsig->pin_count();
|
||||
|
||||
// Make the adder as wide as the widest operand
|
||||
osig = new NetNet(0, des->local_symbol(path), NetNet::WIRE, width);
|
||||
NetAddSub*adder = new NetAddSub(name, width);
|
||||
|
||||
// Connect the adder to the various parts.
|
||||
for (unsigned idx = 0 ; idx < lsig->pin_count() ; idx += 1)
|
||||
connect(lsig->pin(idx), adder->pin_DataA(idx));
|
||||
for (unsigned idx = 0 ; idx < rsig->pin_count() ; idx += 1)
|
||||
connect(rsig->pin(idx), adder->pin_DataB(idx));
|
||||
for (unsigned idx = 0 ; idx < osig->pin_count() ; idx += 1)
|
||||
connect(osig->pin(idx), adder->pin_Result(idx));
|
||||
|
||||
gate = adder;
|
||||
des->add_signal(osig);
|
||||
gate->rise_time(rise);
|
||||
gate->fall_time(fall);
|
||||
gate->decay_time(decay);
|
||||
des->add_node(gate);
|
||||
|
||||
switch (op_) {
|
||||
case '+':
|
||||
gate->attribute("LPM_Direction", "ADD");
|
||||
break;
|
||||
case '-':
|
||||
gate->attribute("LPM_Direction", "SUB");
|
||||
break;
|
||||
}
|
||||
|
||||
if (NetTmp*tmp = dynamic_cast<NetTmp*>(lsig))
|
||||
delete tmp;
|
||||
if (NetTmp*tmp = dynamic_cast<NetTmp*>(rsig))
|
||||
delete tmp;
|
||||
|
||||
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.
|
||||
*/
|
||||
NetNet* PETernary::elaborate_net(Design*des, const string&path,
|
||||
unsigned width,
|
||||
unsigned long rise,
|
||||
unsigned long fall,
|
||||
unsigned long decay) const
|
||||
{
|
||||
NetNet* expr_sig = expr_->elaborate_net(des, path, 0, 0, 0, 0);
|
||||
NetNet* tru_sig = tru_->elaborate_net(des, path, width, 0, 0, 0);
|
||||
NetNet* fal_sig = fal_->elaborate_net(des, path, width, 0, 0, 0);
|
||||
if (expr_sig == 0 || tru_sig == 0 || fal_sig == 0) {
|
||||
des->errors += 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
assert(tru_sig->pin_count() == fal_sig->pin_count());
|
||||
assert(width == tru_sig->pin_count());
|
||||
assert(expr_sig->pin_count() == 1);
|
||||
|
||||
NetNet*sig = new NetNet(0, des->local_symbol(path), NetNet::WIRE,
|
||||
tru_sig->pin_count());
|
||||
sig->local_flag(true);
|
||||
|
||||
NetMux*mux = new NetMux(des->local_symbol(path), width, 2, 1);
|
||||
connect(mux->pin_Sel(0), expr_sig->pin(0));
|
||||
|
||||
for (unsigned idx = 0 ; idx < width ; idx += 1) {
|
||||
connect(mux->pin_Result(idx), sig->pin(idx));
|
||||
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]>.
|
||||
*
|
||||
* Add the LPM_MUX device, and integrate it with the
|
||||
* ternary synthesis from Larry. Replace the lpm_mux
|
||||
* generator in t-xnf.cc to use XNF EQU devices to
|
||||
* put muxs into function units.
|
||||
*
|
||||
* Rewrite elaborate_net for the PETernary class to
|
||||
* also use the LPM_MUX device.
|
||||
*
|
||||
* Revision 1.1 1999/10/31 20:08:24 steve
|
||||
* Include subtraction in LPM_ADD_SUB device.
|
||||
*
|
||||
*/
|
||||
|
||||
+147
-917
File diff suppressed because it is too large
Load Diff
@@ -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.24 1999/10/10 01:59:54 steve Exp $"
|
||||
#ident "$Id: emit.cc,v 1.31 1999/11/28 23:42:02 steve Exp $"
|
||||
#endif
|
||||
|
||||
/*
|
||||
@@ -65,11 +65,36 @@ 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);
|
||||
}
|
||||
|
||||
void NetFF::emit_node(ostream&o, struct target_t*tgt) const
|
||||
{
|
||||
tgt->lpm_ff(o, this);
|
||||
}
|
||||
|
||||
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);
|
||||
@@ -230,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_;
|
||||
@@ -314,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);
|
||||
@@ -324,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);
|
||||
@@ -357,6 +389,39 @@ 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 <LRDoolittle@lbl.gov>.
|
||||
*
|
||||
* Add the LPM_MUX device, and integrate it with the
|
||||
* ternary synthesis from Larry. Replace the lpm_mux
|
||||
* generator in t-xnf.cc to use XNF EQU devices to
|
||||
* put muxs into function units.
|
||||
*
|
||||
* Rewrite elaborate_net for the PETernary class to
|
||||
* also use the LPM_MUX device.
|
||||
*
|
||||
* Revision 1.25 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
|
||||
* flip-flops.
|
||||
*
|
||||
* Revision 1.24 1999/10/10 01:59:54 steve
|
||||
* Structural case equals device.
|
||||
*
|
||||
|
||||
@@ -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.
|
||||
*
|
||||
|
||||
+242
@@ -0,0 +1,242 @@
|
||||
/*
|
||||
* 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: expr_synth.cc,v 1.6 1999/11/28 23:42:02 steve Exp $"
|
||||
#endif
|
||||
|
||||
# include "netlist.h"
|
||||
|
||||
|
||||
NetNet* NetExpr::synthesize(Design*des)
|
||||
{
|
||||
cerr << get_line() << ": internal error: cannot synthesize expression: "
|
||||
<< *this << endl;
|
||||
des->errors += 1;
|
||||
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
|
||||
* signals, then just connect a single gate to each bit of the vector
|
||||
* of the expression.
|
||||
*/
|
||||
NetNet* NetEBBits::synthesize(Design*des)
|
||||
{
|
||||
string path = des->local_symbol("SYNTH");
|
||||
NetNet*lsig = left_->synthesize(des);
|
||||
NetNet*rsig = right_->synthesize(des);
|
||||
|
||||
assert(lsig->pin_count() == rsig->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);
|
||||
NetLogic*gate;
|
||||
|
||||
switch (op()) {
|
||||
case '&':
|
||||
gate = new NetLogic(oname, 3, NetLogic::AND);
|
||||
break;
|
||||
case '|':
|
||||
gate = new NetLogic(oname, 3, NetLogic::OR);
|
||||
break;
|
||||
case '^':
|
||||
gate = new NetLogic(oname, 3, NetLogic::XOR);
|
||||
break;
|
||||
case 'O':
|
||||
gate = new NetLogic(oname, 3, NetLogic::NOR);
|
||||
break;
|
||||
case 'X':
|
||||
gate = new NetLogic(oname, 3, NetLogic::XNOR);
|
||||
break;
|
||||
default:
|
||||
assert(0);
|
||||
}
|
||||
|
||||
connect(osig->pin(idx), gate->pin(0));
|
||||
connect(lsig->pin(idx), gate->pin(1));
|
||||
connect(rsig->pin(idx), gate->pin(2));
|
||||
|
||||
des->add_node(gate);
|
||||
}
|
||||
|
||||
des->add_signal(osig);
|
||||
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.
|
||||
*/
|
||||
NetNet* NetEUBits::synthesize(Design*des)
|
||||
{
|
||||
string path = des->local_symbol("SYNTH");
|
||||
NetNet*isig = expr_->synthesize(des);
|
||||
|
||||
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);
|
||||
NetLogic*gate;
|
||||
|
||||
switch (op()) {
|
||||
case '~':
|
||||
gate = new NetLogic(oname, 2, NetLogic::NOT);
|
||||
break;
|
||||
default:
|
||||
assert(0);
|
||||
}
|
||||
|
||||
connect(osig->pin(idx), gate->pin(0));
|
||||
connect(isig->pin(idx), gate->pin(1));
|
||||
|
||||
des->add_node(gate);
|
||||
}
|
||||
des->add_signal(osig);
|
||||
return osig;
|
||||
}
|
||||
|
||||
|
||||
NetNet* NetETernary::synthesize(Design *des)
|
||||
{
|
||||
string path = des->local_symbol("SYNTH");
|
||||
NetNet*csig = cond_->synthesize(des);
|
||||
NetNet*tsig = true_val_->synthesize(des);
|
||||
NetNet*fsig = false_val_->synthesize(des);
|
||||
|
||||
assert(csig->pin_count() == 1);
|
||||
assert(tsig->pin_count() == fsig->pin_count());
|
||||
unsigned width=tsig->pin_count();
|
||||
NetNet*osig = new NetNet(0, path, NetNet::IMPLICIT, width);
|
||||
|
||||
string oname = des->local_symbol(path);
|
||||
NetMux *mux = new NetMux(oname, width, 2, 1);
|
||||
for (unsigned idx = 0 ; idx < width; idx += 1) {
|
||||
connect(tsig->pin(idx), mux->pin_Data(idx, 1));
|
||||
connect(fsig->pin(idx), mux->pin_Data(idx, 0));
|
||||
connect(osig->pin(idx), mux->pin_Result(idx));
|
||||
}
|
||||
des->add_node(mux);
|
||||
connect(csig->pin(0), mux->pin_Sel(0));
|
||||
des->add_signal(osig);
|
||||
return osig;
|
||||
}
|
||||
|
||||
NetNet* NetESignal::synthesize(Design*des)
|
||||
{
|
||||
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 <LRDoolittle@lbl.gov>.
|
||||
*
|
||||
* Add the LPM_MUX device, and integrate it with the
|
||||
* ternary synthesis from Larry. Replace the lpm_mux
|
||||
* generator in t-xnf.cc to use XNF EQU devices to
|
||||
* put muxs into function units.
|
||||
*
|
||||
* Rewrite elaborate_net for the PETernary class to
|
||||
* also use the LPM_MUX device.
|
||||
*
|
||||
* Revision 1.1 1999/11/02 04:55:34 steve
|
||||
* Add the synthesize method to NetExpr to handle
|
||||
* synthesis of expressions, and use that method
|
||||
* to improve r-value handling of LPM_FF synthesis.
|
||||
*
|
||||
* Modify the XNF target to handle LPM_FF objects.
|
||||
*
|
||||
*/
|
||||
|
||||
+79
-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.2 1999/07/18 05:52:46 steve Exp $"
|
||||
#ident "$Id: functor.cc,v 1.5 1999/12/01 06:06:16 steve Exp $"
|
||||
#endif
|
||||
|
||||
# include "functor.h"
|
||||
@@ -35,14 +35,19 @@ void functor_t::process(class Design*, class NetProcTop*)
|
||||
{
|
||||
}
|
||||
|
||||
void functor_t::lpm_ff(class Design*, class NetFF*)
|
||||
{
|
||||
}
|
||||
|
||||
void Design::functor(functor_t*fun)
|
||||
{
|
||||
// apply to signals
|
||||
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_);
|
||||
}
|
||||
|
||||
@@ -53,10 +58,82 @@ void Design::functor(functor_t*fun)
|
||||
procs_idx_ = idx->next_;
|
||||
fun->process(this, idx);
|
||||
}
|
||||
|
||||
// apply to nodes
|
||||
if (nodes_) {
|
||||
NetNode*cur = nodes_->node_next_;
|
||||
do {
|
||||
NetNode*tmp = cur->node_next_;
|
||||
cur->functor_node(this, fun);
|
||||
cur = tmp;
|
||||
} while (cur != nodes_->node_next_);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void NetNode::functor_node(Design*, functor_t*)
|
||||
{
|
||||
}
|
||||
|
||||
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
|
||||
* flip-flops.
|
||||
*
|
||||
* Revision 1.2 1999/07/18 05:52:46 steve
|
||||
* xnfsyn generates DFF objects for XNF output, and
|
||||
* properly rewrites the Design netlist in the process.
|
||||
|
||||
@@ -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.1 1999/07/17 22:01:13 steve Exp $"
|
||||
#ident "$Id: functor.h,v 1.3 1999/12/01 06:06:16 steve Exp $"
|
||||
#endif
|
||||
|
||||
/*
|
||||
@@ -42,10 +42,29 @@ struct functor_t {
|
||||
/* This method is called for each process in the design. */
|
||||
virtual void process(class Design*des, class NetProcTop*);
|
||||
|
||||
/* This method is called for each FF in the design. */
|
||||
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
|
||||
* flip-flops.
|
||||
*
|
||||
* Revision 1.1 1999/07/17 22:01:13 steve
|
||||
* Add the functor interface for functor transforms.
|
||||
*
|
||||
|
||||
+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);
|
||||
|
||||
@@ -0,0 +1,26 @@
|
||||
|
||||
WHAT IS LPM
|
||||
|
||||
LPM (Library of Paramaterized Modules) is EIS-IS standard 103-A. It is
|
||||
a standard library of abstract devices that are designed to be close
|
||||
enough to the target hardware to be easily translated, yet abstract
|
||||
enough to support a variety of target technologies without excessive
|
||||
constraints. Icarus Verilog uses LPM internally to represent idealized
|
||||
hardware, especially when doing target neutral synthesis.
|
||||
|
||||
In general, the user does not even see the LPM that Icarus Verilog
|
||||
generates, because the LPM devices are translated into technology
|
||||
specific devices by the final code generator or target specific
|
||||
optimizers.
|
||||
|
||||
INTERNAL USES OF LPM
|
||||
|
||||
Internally, Icarus Verilog uses LPM devices to represent the design in
|
||||
abstract, especially when synthesizing such functions as addition,
|
||||
flip-flops, etc. The ``synth'' functor generates LPM modules when
|
||||
interpreting procedural constructs. The functor generates the LPM
|
||||
objects needed to replace a behavioral description, and uses
|
||||
attributes to tag the devices with LPM properties.
|
||||
|
||||
Code generators need to understand the supported LPM devices so that
|
||||
they can translate the devices into technology specific devices.
|
||||
@@ -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.23 1999/09/22 16:57:23 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"
|
||||
@@ -79,7 +82,9 @@ extern Design* elaborate(const map<string,Module*>&modules,
|
||||
extern void cprop(Design*des);
|
||||
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);
|
||||
|
||||
@@ -90,8 +95,10 @@ static struct net_func_map {
|
||||
} func_table[] = {
|
||||
{ "cprop", &cprop },
|
||||
{ "nobufz", &nobufz },
|
||||
{ "propinit", &propinit },
|
||||
{ "nodangle",&nodangle },
|
||||
{ "propinit",&propinit },
|
||||
{ "sigfold", &sigfold },
|
||||
{ "synth", &synth },
|
||||
{ "xnfio", &xnfio },
|
||||
{ "xnfsyn", &xnfsyn },
|
||||
{ 0, 0 }
|
||||
@@ -277,6 +284,19 @@ 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
|
||||
* flip-flops.
|
||||
*
|
||||
* Revision 1.23 1999/09/22 16:57:23 steve
|
||||
* Catch parallel blocks in vvm emit.
|
||||
*
|
||||
|
||||
+1019
-152
File diff suppressed because it is too large
Load Diff
@@ -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.80 1999/10/10 23:29:37 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;
|
||||
@@ -76,8 +77,8 @@ class NetObj {
|
||||
|
||||
public:
|
||||
enum DIR { PASSIVE, INPUT, OUTPUT };
|
||||
Link() : dir_(PASSIVE), next_(this), prev_(this) { }
|
||||
~Link() { unlink(); }
|
||||
Link();
|
||||
~Link();
|
||||
|
||||
// Manipulate the link direction.
|
||||
void set_dir(DIR d) { dir_ = d; }
|
||||
@@ -88,29 +89,18 @@ 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.
|
||||
void unlink()
|
||||
{ next_->prev_ = prev_;
|
||||
prev_->next_ = next_;
|
||||
next_ = prev_ = this;
|
||||
}
|
||||
void unlink();
|
||||
|
||||
// Return true if this link is connected to anything else.
|
||||
bool is_linked() const { return next_ != this; }
|
||||
bool is_linked() const;
|
||||
|
||||
// Return true if these pins are connected.
|
||||
bool is_linked(const NetObj::Link&that) const;
|
||||
@@ -123,9 +113,13 @@ class NetObj {
|
||||
|
||||
// Return information about the object that this link is
|
||||
// a part of.
|
||||
const NetObj*get_obj() const { return node_; }
|
||||
NetObj*get_obj() { return node_; }
|
||||
unsigned get_pin() const { return pin_; }
|
||||
const NetObj*get_obj() const;
|
||||
NetObj*get_obj();
|
||||
unsigned get_pin() const;
|
||||
|
||||
void set_name(const string&, unsigned inst =0);
|
||||
const string& get_name() const;
|
||||
unsigned get_inst() const;
|
||||
|
||||
private:
|
||||
// The NetNode manages these. They point back to the
|
||||
@@ -134,6 +128,12 @@ class NetObj {
|
||||
unsigned pin_;
|
||||
DIR dir_;
|
||||
|
||||
// These members name the pin of the link. If the name
|
||||
// has width, then the ninst_ member is the index of the
|
||||
// pin.
|
||||
string name_;
|
||||
unsigned inst_;
|
||||
|
||||
private:
|
||||
Link *next_;
|
||||
Link *prev_;
|
||||
@@ -205,6 +205,8 @@ class NetNode : public NetObj {
|
||||
virtual void emit_node(ostream&, struct target_t*) const;
|
||||
virtual void dump_node(ostream&, unsigned) const;
|
||||
|
||||
virtual void functor_node(Design*, functor_t*);
|
||||
|
||||
private:
|
||||
friend class Design;
|
||||
NetNode*node_next_, *node_prev_;
|
||||
@@ -231,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; }
|
||||
@@ -259,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)
|
||||
@@ -273,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_;
|
||||
};
|
||||
@@ -309,10 +321,129 @@ 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.
|
||||
*/
|
||||
class NetFF : public NetNode {
|
||||
|
||||
public:
|
||||
NetFF(const string&n, unsigned width);
|
||||
~NetFF();
|
||||
|
||||
unsigned width() const;
|
||||
|
||||
NetObj::Link& pin_Clock();
|
||||
NetObj::Link& pin_Enable();
|
||||
NetObj::Link& pin_Aload();
|
||||
NetObj::Link& pin_Aset();
|
||||
NetObj::Link& pin_Aclr();
|
||||
NetObj::Link& pin_Sload();
|
||||
NetObj::Link& pin_Sset();
|
||||
NetObj::Link& pin_Sclr();
|
||||
|
||||
NetObj::Link& pin_Data(unsigned);
|
||||
NetObj::Link& pin_Q(unsigned);
|
||||
|
||||
const NetObj::Link& pin_Clock() const;
|
||||
const NetObj::Link& pin_Enable() const;
|
||||
const NetObj::Link& pin_Data(unsigned) const;
|
||||
const NetObj::Link& pin_Q(unsigned) const;
|
||||
|
||||
virtual void dump_node(ostream&, unsigned ind) const;
|
||||
virtual void emit_node(ostream&, struct target_t*) const;
|
||||
virtual void functor_node(Design*des, functor_t*fun);
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
* This class represents the declared memory object. The parser
|
||||
* creates one of these for each declared memory in the elaborated
|
||||
@@ -351,6 +482,93 @@ class NetMemory {
|
||||
map<string,string> attributes_;
|
||||
};
|
||||
|
||||
/*
|
||||
* This class represents an LPM_MUX device. This device has some
|
||||
* number of Result points (the width of the device) and some number
|
||||
* of input choices. There is also a selector of some width. The
|
||||
* parameters are:
|
||||
*
|
||||
* width -- Width of the result and each possible Data input
|
||||
* size -- Number of Data input (each of width)
|
||||
* selw -- Width in bits of the select input
|
||||
*/
|
||||
class NetMux : public NetNode {
|
||||
|
||||
public:
|
||||
NetMux(const string&n, unsigned width, unsigned size, unsigned selw);
|
||||
~NetMux();
|
||||
|
||||
unsigned width() const;
|
||||
unsigned size() const;
|
||||
unsigned sel_width() const;
|
||||
|
||||
NetObj::Link& pin_Aclr();
|
||||
NetObj::Link& pin_Clock();
|
||||
|
||||
NetObj::Link& pin_Result(unsigned);
|
||||
NetObj::Link& pin_Data(unsigned wi, unsigned si);
|
||||
NetObj::Link& pin_Sel(unsigned);
|
||||
|
||||
const NetObj::Link& pin_Aclr() const;
|
||||
const NetObj::Link& pin_Clock() const;
|
||||
|
||||
const NetObj::Link& pin_Result(unsigned) const;
|
||||
const NetObj::Link& pin_Data(unsigned, unsigned) const;
|
||||
const NetObj::Link& pin_Sel(unsigned) const;
|
||||
|
||||
virtual void dump_node(ostream&, unsigned ind) const;
|
||||
virtual void emit_node(ostream&, struct target_t*) const;
|
||||
|
||||
private:
|
||||
unsigned width_;
|
||||
unsigned size_;
|
||||
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.
|
||||
@@ -387,6 +605,11 @@ class NetExpr : public LineInfo {
|
||||
// any. This is a deep copy operation.
|
||||
virtual NetExpr*dup_expr() const =0;
|
||||
|
||||
// Return a version of myself that is structural. This is used
|
||||
// for converting expressions to gates.
|
||||
virtual NetNet*synthesize(Design*);
|
||||
|
||||
|
||||
protected:
|
||||
void expr_width(unsigned w) { width_ = w; }
|
||||
|
||||
@@ -400,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 {
|
||||
@@ -416,6 +639,7 @@ class NetEConst : public NetExpr {
|
||||
virtual void dump(ostream&) const;
|
||||
|
||||
virtual NetEConst* dup_expr() const;
|
||||
virtual NetNet*synthesize(Design*);
|
||||
|
||||
private:
|
||||
verinum value_;
|
||||
@@ -423,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);
|
||||
|
||||
};
|
||||
|
||||
@@ -444,11 +667,8 @@ class NetTmp : public NetNet {
|
||||
class NetBUFZ : public NetNode {
|
||||
|
||||
public:
|
||||
explicit NetBUFZ(const string&n)
|
||||
: NetNode(n, 2)
|
||||
{ pin(0).set_dir(Link::OUTPUT);
|
||||
pin(1).set_dir(Link::INPUT);
|
||||
}
|
||||
explicit NetBUFZ(const string&n);
|
||||
~NetBUFZ();
|
||||
|
||||
virtual void dump_node(ostream&, unsigned ind) const;
|
||||
virtual void emit_node(ostream&, struct target_t*) const;
|
||||
@@ -523,7 +743,7 @@ class NetLogic : public NetNode {
|
||||
* In any case, pin 0 is an output, and all the remaining pins are
|
||||
* inputs.
|
||||
*
|
||||
* The truth table is canonically represented as a finite state
|
||||
* The sequential truth table is canonically represented as a finite state
|
||||
* machine with the current state representing the inputs and the
|
||||
* current output, and the next state carrying the new output value to
|
||||
* use. All the outgoing transitions from a state represent a single
|
||||
@@ -552,6 +772,12 @@ class NetLogic : public NetNode {
|
||||
* _ -- 10 or x0 (Note that this is not the output '-'.)
|
||||
* % -- 0x or 1x
|
||||
*
|
||||
* SEQUENTIAL
|
||||
* These objects have a single bit of memory. The logic table includes
|
||||
* an entry for the current value, and allows edges on the inputs. In
|
||||
* canonical form, inly then entries that generate 0, 1 or - (no change)
|
||||
* are listed.
|
||||
*
|
||||
* COMBINATIONAL
|
||||
* The logic table is a map between the input levels and the
|
||||
* output. Each input pin can have the value 0, 1 or x and the output
|
||||
@@ -559,12 +785,6 @@ class NetLogic : public NetNode {
|
||||
* output is x. In canonical form, only the entries that generate 0 or
|
||||
* 1 are listed.
|
||||
*
|
||||
* SEQUENTIAL
|
||||
* These objects have a single bit of memory. The logic table includes
|
||||
* an entry for the current value, and allows edges on the inputs. In
|
||||
* canonical form, inly then entries that generate 0, 1 or - (no change)
|
||||
* are listed.
|
||||
*
|
||||
*/
|
||||
class NetUDP : public NetNode {
|
||||
|
||||
@@ -590,7 +810,7 @@ class NetUDP : public NetNode {
|
||||
bool is_sequential() const { return sequential_; }
|
||||
|
||||
private:
|
||||
const bool sequential_;
|
||||
bool sequential_;
|
||||
char init_;
|
||||
|
||||
struct state_t_;
|
||||
@@ -617,6 +837,11 @@ class NetUDP : public NetNode {
|
||||
|
||||
state_t_*find_state_(const string&);
|
||||
|
||||
// A combinational primitive is more simply represented as a
|
||||
// simple map of input signals to a single output.
|
||||
typedef map<string,char> CM_;
|
||||
CM_ cm_;
|
||||
|
||||
void dump_sequ_(ostream&o, unsigned ind) const;
|
||||
void dump_comb_(ostream&o, unsigned ind) const;
|
||||
};
|
||||
@@ -638,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:
|
||||
@@ -693,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;
|
||||
|
||||
@@ -855,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:
|
||||
@@ -948,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;
|
||||
|
||||
@@ -1244,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*);
|
||||
};
|
||||
|
||||
/*
|
||||
@@ -1268,6 +1501,8 @@ class NetEBBits : public NetEBinary {
|
||||
|
||||
virtual bool set_width(unsigned w);
|
||||
virtual NetEBBits* dup_expr() const;
|
||||
|
||||
virtual NetNet* synthesize(Design*);
|
||||
};
|
||||
|
||||
/*
|
||||
@@ -1402,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
|
||||
@@ -1456,6 +1714,7 @@ class NetETernary : public NetExpr {
|
||||
|
||||
virtual void expr_scan(struct expr_scan_t*) const;
|
||||
virtual void dump(ostream&) const;
|
||||
virtual NetNet*synthesize(Design*);
|
||||
|
||||
private:
|
||||
NetExpr*cond_;
|
||||
@@ -1474,9 +1733,9 @@ class NetETernary : public NetExpr {
|
||||
* ^ -- Reduction XOR
|
||||
* + --
|
||||
* - --
|
||||
* A -- Reduciton NAND (~&)
|
||||
* N -- Reduciton NOR (~|)
|
||||
* X -- Reduciton NXOR (~^ or ^~)
|
||||
* A -- Reduction NAND (~&)
|
||||
* N -- Reduction NOR (~|)
|
||||
* X -- Reduction NXOR (~^ or ^~)
|
||||
*/
|
||||
class NetEUnary : public NetExpr {
|
||||
|
||||
@@ -1494,11 +1753,21 @@ class NetEUnary : public NetExpr {
|
||||
virtual void expr_scan(struct expr_scan_t*) const;
|
||||
virtual void dump(ostream&) const;
|
||||
|
||||
private:
|
||||
protected:
|
||||
char op_;
|
||||
NetExpr* expr_;
|
||||
};
|
||||
|
||||
class NetEUBits : public NetEUnary {
|
||||
|
||||
public:
|
||||
NetEUBits(char op, NetExpr*ex);
|
||||
~NetEUBits();
|
||||
|
||||
virtual NetNet* synthesize(Design*);
|
||||
|
||||
};
|
||||
|
||||
/* System identifiers are represented here. */
|
||||
class NetEIdent : public NetExpr {
|
||||
|
||||
@@ -1549,25 +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_;
|
||||
};
|
||||
|
||||
/*
|
||||
@@ -1600,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.
|
||||
@@ -1607,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
|
||||
@@ -1620,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*);
|
||||
@@ -1632,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*);
|
||||
@@ -1671,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_;
|
||||
@@ -1731,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. */
|
||||
@@ -1744,6 +2051,85 @@ 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>.
|
||||
*
|
||||
* Add the LPM_MUX device, and integrate it with the
|
||||
* ternary synthesis from Larry. Replace the lpm_mux
|
||||
* generator in t-xnf.cc to use XNF EQU devices to
|
||||
* put muxs into function units.
|
||||
*
|
||||
* Rewrite elaborate_net for the PETernary class to
|
||||
* also use the LPM_MUX device.
|
||||
*
|
||||
* Revision 1.84 1999/11/04 01:12:42 steve
|
||||
* Elaborate combinational UDP devices.
|
||||
*
|
||||
* Revision 1.83 1999/11/02 04:55:34 steve
|
||||
* Add the synthesize method to NetExpr to handle
|
||||
* synthesis of expressions, and use that method
|
||||
* to improve r-value handling of LPM_FF synthesis.
|
||||
*
|
||||
* Modify the XNF target to handle LPM_FF objects.
|
||||
*
|
||||
* Revision 1.82 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
|
||||
* flip-flops.
|
||||
*
|
||||
* Revision 1.81 1999/10/31 04:11:27 steve
|
||||
* Add to netlist links pin name and instance number,
|
||||
* and arrange in vvm for pin connections by name
|
||||
* and instance number.
|
||||
*
|
||||
* Revision 1.80 1999/10/10 23:29:37 steve
|
||||
* Support evaluating + operator at compile time.
|
||||
*
|
||||
|
||||
+72
-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.4 1999/09/29 00:03:27 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
|
||||
@@ -57,6 +57,31 @@ destructors for nets and nodes automatically arrange for pins to be
|
||||
disconnected when the item is deleted, so that the netlist can be
|
||||
changed during processing.
|
||||
|
||||
STRUCTURAL LINKS
|
||||
|
||||
The NetNode and NetNet classes contain arrays of Link objects, one
|
||||
object per pin. Each pin is a single bit. The Link objects link
|
||||
circularly to all the NetNode and NetNet objects' links that are
|
||||
connected together in the design. This way, code that examines a node
|
||||
of the design can discover what is connected to each pin.
|
||||
|
||||
See the NetObj::Link class definition for a description of the link
|
||||
methods.
|
||||
|
||||
Currently, a link has 3 possible direction properties:
|
||||
|
||||
PASSIVE -- These pins are sampled by the object that holds the
|
||||
pin based on some external event. These are used,
|
||||
for example, by NetESignal objects that read a
|
||||
point for a procedural expression.
|
||||
|
||||
INPUT -- These pins potentially react to the setting of its
|
||||
input.
|
||||
|
||||
OUTPUT -- These pins potentially drive the node. (They may be
|
||||
three-state.)
|
||||
|
||||
|
||||
BEHAVIORAL ITEMS: NetProcTop, NetProc and derived classes
|
||||
|
||||
Behavioral items are not in general linked to the netlist. Instead,
|
||||
@@ -89,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
|
||||
@@ -150,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
|
||||
|
||||
@@ -189,6 +240,20 @@ 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
|
||||
to improve r-value handling of LPM_FF synthesis.
|
||||
|
||||
Modify the XNF target to handle LPM_FF objects.
|
||||
|
||||
Revision 1.4 1999/09/29 00:03:27 steve
|
||||
Spelling fixes from Larry.
|
||||
|
||||
|
||||
+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.
|
||||
|
||||
@@ -0,0 +1,210 @@
|
||||
/*
|
||||
* 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: synth.cc,v 1.3 1999/12/01 06:06:16 steve Exp $"
|
||||
#endif
|
||||
|
||||
/*
|
||||
* The synth function searches the behavioral description for
|
||||
* patterns that are known to represent LPM library components. This
|
||||
* is especially interesting for the sequential components such as
|
||||
* flip flops and latches. As threads are transformed into components,
|
||||
* the design is rewritten.
|
||||
*/
|
||||
# include "functor.h"
|
||||
# include "netlist.h"
|
||||
|
||||
/*
|
||||
* This transform recognizes the following patterns:
|
||||
*
|
||||
* always @(posedge CLK) Q = D
|
||||
* always @(negedge CLK) Q = D
|
||||
*
|
||||
* always @(posedge CLK) if (CE) Q = D;
|
||||
* always @(negedge CLK) if (CE) Q = D;
|
||||
*
|
||||
* The r-value of the assignments must be identifiers (i.e. wires or
|
||||
* registers) and the CE must be single-bit identifiers. The generated
|
||||
* device will be wide enough to accomodate Q and D.
|
||||
*/
|
||||
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 {
|
||||
|
||||
public:
|
||||
void process(class Design*, class NetProcTop*);
|
||||
|
||||
private:
|
||||
void proc_always_(class Design*);
|
||||
|
||||
NetProcTop*top_;
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
* Look at a process, and divide the problem into always and initial
|
||||
* threads.
|
||||
*/
|
||||
void synth_f::process(class Design*des, class NetProcTop*top)
|
||||
{
|
||||
switch (top->type()) {
|
||||
case NetProcTop::KALWAYS:
|
||||
top_ = top;
|
||||
proc_always_(des);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* An "always ..." statement has been found.
|
||||
*/
|
||||
void synth_f::proc_always_(class Design*des)
|
||||
{
|
||||
match_dff dff_pat(des, top_);
|
||||
if (top_->statement()->match_proc(&dff_pat)) {
|
||||
dff_pat.make_it();
|
||||
des->delete_process(top_);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void synth(Design*des)
|
||||
{
|
||||
synth_f synth_obj;
|
||||
des->functor(&synth_obj);
|
||||
}
|
||||
|
||||
/*
|
||||
* $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
|
||||
* to improve r-value handling of LPM_FF synthesis.
|
||||
*
|
||||
* Modify the XNF target to handle LPM_FF objects.
|
||||
*
|
||||
* Revision 1.1 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.
|
||||
*
|
||||
*/
|
||||
|
||||
@@ -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.65 1999/10/28 00:47:24 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,12 +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*);
|
||||
@@ -60,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*);
|
||||
@@ -82,7 +94,8 @@ class target_vvm : public target_t {
|
||||
void end_process(ostream&os, const NetProcTop*);
|
||||
|
||||
private:
|
||||
void emit_gate_outputfun_(const NetNode*);
|
||||
void emit_gate_outputfun_(const NetNode*, unsigned);
|
||||
string defn_gate_outputfun_(ostream&os, const NetNode*, unsigned);
|
||||
|
||||
// This is the name of the thread (process or task) that is
|
||||
// being generated.
|
||||
@@ -111,7 +124,11 @@ class target_vvm : public target_t {
|
||||
|
||||
// String constants that are made into vpiHandles have th
|
||||
// handle name mapped by this.
|
||||
map<string,string>string_constants;
|
||||
map<string,unsigned>string_constants;
|
||||
unsigned string_counter;
|
||||
|
||||
map<verinum,unsigned,less_verinum>number_constants;
|
||||
unsigned number_counter;
|
||||
};
|
||||
|
||||
|
||||
@@ -141,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*);
|
||||
@@ -230,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";
|
||||
@@ -467,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:
|
||||
@@ -480,51 +498,55 @@ void vvm_parm_rval::expr_const(const NetEConst*expr)
|
||||
{
|
||||
if (expr->value().is_string()) {
|
||||
|
||||
string& res = tgt_->string_constants[expr->value().as_string()];
|
||||
if (res != "") {
|
||||
result = "&" + res + ".base";
|
||||
return;
|
||||
unsigned& res = tgt_->string_constants[expr->value().as_string()];
|
||||
|
||||
if (res == 0) {
|
||||
res = tgt_->string_counter ++;
|
||||
tgt_->init_code << " vpip_make_string_const("
|
||||
"&string_table[" << res << "], \"" <<
|
||||
expr->value().as_string() << "\");" << endl;
|
||||
}
|
||||
|
||||
res = make_temp();
|
||||
tgt_->delayed << "struct __vpiStringConst " << res
|
||||
<< ";" << endl;
|
||||
tgt_->init_code << " vpip_make_string_const(&" << res
|
||||
<< ", \"" << expr->value().as_string()
|
||||
<< "\");" << endl;
|
||||
tgt_->defn << " extern struct __vpiStringConst " << res
|
||||
<< ";" << endl;
|
||||
result = "&" + res + ".base";
|
||||
ostrstream tmp;
|
||||
tmp << "&string_table[" << res << "].base" << ends;
|
||||
result = tmp.str();
|
||||
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,9 +558,20 @@ 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()) + "_vpi.base";
|
||||
string res = string("&") + mangle(expr->name()) + ".base";
|
||||
result = res;
|
||||
}
|
||||
|
||||
@@ -572,6 +605,11 @@ void target_vvm::start_design(ostream&os, const Design*mod)
|
||||
os << "# include \"vpi_priv.h\"" << endl;
|
||||
|
||||
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;
|
||||
@@ -581,8 +619,36 @@ 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;
|
||||
{ ifstream rdefn (defn_name);
|
||||
@@ -629,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;
|
||||
@@ -652,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. */
|
||||
@@ -661,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()) {
|
||||
|
||||
@@ -677,11 +767,11 @@ void target_vvm::signal(ostream&os, const NetNet*sig)
|
||||
written[lnk->get_obj()->name()] = true;
|
||||
|
||||
|
||||
const NetNode*net;
|
||||
if ((net = dynamic_cast<const NetNode*>(lnk->get_obj()))) {
|
||||
if (dynamic_cast<const NetNode*>(lnk->get_obj())) {
|
||||
init_code << " " <<
|
||||
mangle(lnk->get_obj()->name()) <<
|
||||
".init(" << lnk->get_pin() << ", V" <<
|
||||
".init_" << lnk->get_name() << "(" <<
|
||||
lnk->get_inst() << ", V" <<
|
||||
sig->get_ival(idx) << ");" << endl;
|
||||
}
|
||||
}
|
||||
@@ -690,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)
|
||||
@@ -748,28 +842,50 @@ void target_vvm::func_def(ostream&os, const NetFuncDef*def)
|
||||
defn << "}" << endl;
|
||||
}
|
||||
|
||||
string target_vvm::defn_gate_outputfun_(ostream&os,
|
||||
const NetNode*gate,
|
||||
unsigned gpin)
|
||||
{
|
||||
const NetObj::Link&lnk = gate->pin(gpin);
|
||||
|
||||
ostrstream tmp;
|
||||
tmp << mangle(gate->name()) << "_output_" << lnk.get_name() <<
|
||||
"_" << lnk.get_inst() << ends;
|
||||
string name = tmp.str();
|
||||
|
||||
os << "static void " << name << "(vvm_simulation*, vpip_bit_t);" << endl;
|
||||
return name;
|
||||
}
|
||||
|
||||
/*
|
||||
* This method handles writing output functions for gates that have a
|
||||
* single output (at pin 0). This writes the output_fun method into
|
||||
* the delayed stream to be emitted to the output file later.
|
||||
*/
|
||||
void target_vvm::emit_gate_outputfun_(const NetNode*gate)
|
||||
void target_vvm::emit_gate_outputfun_(const NetNode*gate, unsigned gpin)
|
||||
{
|
||||
const NetObj::Link&lnk = gate->pin(gpin);
|
||||
|
||||
delayed << "static void " << mangle(gate->name()) <<
|
||||
"_output_fun(vvm_simulation*sim, vvm_bit_t val)" <<
|
||||
"_output_" << lnk.get_name() << "_" << lnk.get_inst() <<
|
||||
"(vvm_simulation*sim, vpip_bit_t val)" <<
|
||||
endl << "{" << endl;
|
||||
|
||||
/* The output function connects to pin 0 of the netlist part
|
||||
/* The output function connects to gpin of the netlist part
|
||||
and causes the inputs that it is connected to to be set
|
||||
with the new value. */
|
||||
|
||||
const NetObj*cur;
|
||||
unsigned pin;
|
||||
gate->pin(0).next_link(cur, pin);
|
||||
gate->pin(gpin).next_link(cur, pin);
|
||||
while (cur != gate) {
|
||||
|
||||
if (dynamic_cast<const NetNet*>(cur)) {
|
||||
// Skip signals
|
||||
if (cur->pin(pin).get_name() != "") {
|
||||
|
||||
delayed << " " << mangle(cur->name()) << ".set_"
|
||||
<< cur->pin(pin).get_name() << "(sim, " <<
|
||||
cur->pin(pin).get_inst() << ", val);" << endl;
|
||||
|
||||
} else {
|
||||
|
||||
delayed << " " << mangle(cur->name()) << ".set(sim, "
|
||||
@@ -784,21 +900,139 @@ void target_vvm::emit_gate_outputfun_(const NetNode*gate)
|
||||
|
||||
void target_vvm::lpm_add_sub(ostream&os, const NetAddSub*gate)
|
||||
{
|
||||
os << "#error \"adders not yet supported in vvm.\"" << endl;
|
||||
os << "static vvm_add_sub<" << gate->width() << "> " <<
|
||||
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);
|
||||
}
|
||||
|
||||
if (gate->attribute("LPM_Direction") == "ADD") {
|
||||
init_code << " " << mangle(gate->name()) <<
|
||||
".init_Add_Sub(0, V1);" << endl;
|
||||
|
||||
} else if (gate->attribute("LPM_Direction") == "SUB") {
|
||||
init_code << " " << mangle(gate->name()) <<
|
||||
".init_Add_Sub(0, V0);" << endl;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
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());
|
||||
os << "static vvm_ff<" << gate->width() << "> " << mname << ";"
|
||||
<< endl;
|
||||
|
||||
for (unsigned idx = 0 ; idx < gate->width() ; idx += 1) {
|
||||
unsigned pin = gate->pin_Q(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_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)
|
||||
{
|
||||
os << "static void " << mangle(gate->name()) <<
|
||||
"_output_fun(vvm_simulation*, vvm_bit_t);" << endl;
|
||||
string outfun = defn_gate_outputfun_(os, gate, 0);
|
||||
|
||||
switch (gate->type()) {
|
||||
case NetLogic::AND:
|
||||
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;
|
||||
@@ -828,12 +1062,14 @@ 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()) << "(&" <<
|
||||
mangle(gate->name()) << "_output_fun);" << endl;
|
||||
os << mangle(gate->name()) << "(&" << outfun << ");" << endl;
|
||||
|
||||
emit_gate_outputfun_(gate);
|
||||
emit_gate_outputfun_(gate, 0);
|
||||
|
||||
start_code << " " << mangle(gate->name()) <<
|
||||
".start(&sim);" << endl;
|
||||
@@ -841,13 +1077,12 @@ void target_vvm::logic(ostream&os, const NetLogic*gate)
|
||||
|
||||
void target_vvm::bufz(ostream&os, const NetBUFZ*gate)
|
||||
{
|
||||
os << "static void " << mangle(gate->name()) <<
|
||||
"_output_fun(vvm_simulation*, vvm_bit_t);" << endl;
|
||||
string outfun = defn_gate_outputfun_(os, gate, 0);
|
||||
|
||||
os << "static vvm_bufz " << mangle(gate->name()) << "(&" <<
|
||||
mangle(gate->name()) << "_output_fun);" << endl;
|
||||
outfun << ");" << endl;
|
||||
|
||||
emit_gate_outputfun_(gate);
|
||||
emit_gate_outputfun_(gate, 0);
|
||||
}
|
||||
|
||||
static string state_to_string(unsigned state, unsigned npins)
|
||||
@@ -908,17 +1143,16 @@ void target_vvm::udp(ostream&os, const NetUDP*gate)
|
||||
}
|
||||
os << "};" << dec << setfill(' ') << endl;
|
||||
|
||||
os << "static void " << mangle(gate->name()) <<
|
||||
"_output_fun(vvm_simulation*, vvm_bit_t);" << endl;
|
||||
string outfun = defn_gate_outputfun_(os, gate, 0);
|
||||
|
||||
os << "static vvm_udp_ssequ<" << gate->pin_count()-1 << "> " <<
|
||||
mangle(gate->name()) << "(&" << mangle(gate->name()) <<
|
||||
"_output_fun, V" << gate->get_initial() << ", " <<
|
||||
mangle(gate->name()) << "_table);" << endl;
|
||||
mangle(gate->name()) << "(&" << outfun << ", V" <<
|
||||
gate->get_initial() << ", " << mangle(gate->name()) <<
|
||||
"_table);" << endl;
|
||||
|
||||
/* The UDP output function is much like other logic gates. Use
|
||||
this general method to output the output function. */
|
||||
emit_gate_outputfun_(gate);
|
||||
emit_gate_outputfun_(gate, 0);
|
||||
|
||||
}
|
||||
|
||||
@@ -978,17 +1212,15 @@ void target_vvm::net_assign_nb(ostream&os, const NetAssignNB*net)
|
||||
; net->pin(idx) != cur->pin(pin)
|
||||
; cur->pin(pin).next_link(cur, pin)) {
|
||||
|
||||
const NetObj::Link&lnk = cur->pin(pin);
|
||||
|
||||
// Skip output only pins.
|
||||
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(sim_, " << pin << ", value_[0]);" << endl;
|
||||
delayed << " " << mangle(cur->name())
|
||||
<< ".set_" << lnk.get_name() << "sim_, "
|
||||
<< lnk.get_inst() << ", value_[0]);" << endl;
|
||||
}
|
||||
|
||||
delayed << " break;" << endl;
|
||||
@@ -1007,17 +1239,15 @@ void target_vvm::net_assign_nb(ostream&os, const NetAssignNB*net)
|
||||
; net->pin(idx) != cur->pin(pin)
|
||||
; cur->pin(pin).next_link(cur, pin)) {
|
||||
|
||||
const NetObj::Link&lnk = cur->pin(pin);
|
||||
|
||||
// Skip output only pins.
|
||||
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(sim_, " << pin << ", value_[" <<
|
||||
".set_" << lnk.get_name() << "(sim_, "
|
||||
<< lnk.get_inst() << ", value_[" <<
|
||||
idx << "]);" << endl;
|
||||
}
|
||||
}
|
||||
@@ -1027,15 +1257,18 @@ 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*, vvm_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);
|
||||
emit_gate_outputfun_(gate, 0);
|
||||
|
||||
start_code << " " << mangle(gate->name()) <<
|
||||
".start(&sim);" << endl;
|
||||
@@ -1049,11 +1282,10 @@ void target_vvm::net_case_cmp(ostream&os, const NetCaseCmp*gate)
|
||||
*/
|
||||
void target_vvm::net_const(ostream&os, const NetConst*gate)
|
||||
{
|
||||
os << "static void " << mangle(gate->name()) <<
|
||||
"_output_fun(vvm_simulation*, vvm_bit_t);" << endl;
|
||||
string outfun = defn_gate_outputfun_(os, gate, 0);
|
||||
|
||||
os << "static vvm_bufz " << mangle(gate->name()) << "(&" <<
|
||||
mangle(gate->name()) << "_output_fun);" << endl;
|
||||
outfun << ");" << endl;
|
||||
|
||||
init_code << " " << mangle(gate->name()) << ".set(&sim, 1, ";
|
||||
switch (gate->value()) {
|
||||
@@ -1072,34 +1304,7 @@ void target_vvm::net_const(ostream&os, const NetConst*gate)
|
||||
}
|
||||
init_code << ");" << endl;
|
||||
|
||||
|
||||
emit_gate_outputfun_(gate);
|
||||
}
|
||||
|
||||
void target_vvm::net_esignal(ostream&os, const NetESignal*net)
|
||||
{
|
||||
bool&flag = esignal_printed_flag[net->name()];
|
||||
if (flag)
|
||||
return;
|
||||
|
||||
flag = true;
|
||||
os << "static vvm_bitset_t<" << net->pin_count() << "> " <<
|
||||
mangle(net->name()) << "_bits; /* " << net->name() <<
|
||||
" */" << endl;
|
||||
os << "static vvm_signal_t<" << net->pin_count() << "> " <<
|
||||
mangle(net->name()) << "(\"" << net->name() << "\", &" <<
|
||||
mangle(net->name()) << "_bits);" << endl;
|
||||
|
||||
os << "static struct __vpiSignal " << mangle(net->name()) <<
|
||||
"_vpi;" << endl;
|
||||
|
||||
string vpi_name = mangle(net->name()) + "_vpi";
|
||||
init_code << " vpip_make_reg(&" << vpi_name << ", \"" <<
|
||||
net->name() << "\");" << endl;
|
||||
init_code << " " << vpi_name << ".bits = " <<
|
||||
mangle(net->name()) << "_bits.bits;" << endl;
|
||||
init_code << " " << vpi_name << ".nbits = " <<
|
||||
net->pin_count() << ";" << endl;
|
||||
emit_gate_outputfun_(gate, 0);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -1201,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
|
||||
@@ -1215,8 +1415,9 @@ void target_vvm::proc_assign(ostream&os, const NetAssign*net)
|
||||
|
||||
written[cur->name()] = true;
|
||||
defn << " " << mangle(cur->name()) <<
|
||||
".set(sim_, " << pin << ", " <<
|
||||
rval << "[0]);" << endl;
|
||||
".set_" << cur->pin(pin).get_name() <<
|
||||
"(sim_, " << cur->pin(pin).get_inst() <<
|
||||
", " << rval << "[0]);" << endl;
|
||||
}
|
||||
|
||||
defn << " break;" << endl;
|
||||
@@ -1241,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
|
||||
@@ -1255,8 +1451,9 @@ void target_vvm::proc_assign(ostream&os, const NetAssign*net)
|
||||
|
||||
written[cur->name()] = true;
|
||||
defn << " " << mangle(cur->name()) <<
|
||||
".set(sim_, " << pin << ", " <<
|
||||
rval << "[" << idx << "]);" << endl;
|
||||
".set_" << cur->pin(pin).get_name() <<
|
||||
"(sim_, " << cur->pin(pin).get_inst() <<
|
||||
", " << rval << "[" << idx << "]);" << endl;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1275,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());
|
||||
@@ -1288,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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1762,6 +1958,79 @@ 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
|
||||
* flip-flops.
|
||||
*
|
||||
* Revision 1.70 1999/10/31 20:08:24 steve
|
||||
* Include subtraction in LPM_ADD_SUB device.
|
||||
*
|
||||
* Revision 1.69 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.68 1999/10/28 21:51:21 steve
|
||||
* gate output pins use vpip_bit_t (Eric Aardoom)
|
||||
*
|
||||
* Revision 1.67 1999/10/28 21:36:00 steve
|
||||
* Get rid of monitor_t and fold __vpiSignal into signal.
|
||||
*
|
||||
* Revision 1.66 1999/10/28 04:48:29 steve
|
||||
* Put strings into a single string table.
|
||||
*
|
||||
* Revision 1.65 1999/10/28 00:47:24 steve
|
||||
* Rewrite vvm VPI support to make objects more
|
||||
* persistent, rewrite the simulation scheduler
|
||||
@@ -1797,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.9 1999/08/25 22:22:08 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 {
|
||||
|
||||
@@ -70,16 +78,29 @@ class target_xnf : public target_t {
|
||||
void start_design(ostream&os, const Design*);
|
||||
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_;
|
||||
};
|
||||
|
||||
/*
|
||||
@@ -102,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)
|
||||
{
|
||||
@@ -122,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)
|
||||
@@ -167,22 +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.0,\"Icarus Verilog\"" << endl;
|
||||
os << "PART," << des->get_flag("part") << endl;
|
||||
os << "PROG,verilog,0.2PRE,\"Icarus Verilog\"" << endl;
|
||||
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)
|
||||
@@ -252,6 +323,239 @@ 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)
|
||||
{
|
||||
string type = net->attribute("LPM_FFType");
|
||||
if (type == "") type = "DFF";
|
||||
|
||||
// XXXX For now, only support DFF
|
||||
assert(type == "DFF");
|
||||
|
||||
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) {
|
||||
|
||||
os << "SYM, " << mangle(net->name()) << "<" << idx
|
||||
<< ">, DFF, LIBVER=2.0.0" << endl;
|
||||
draw_pin(os, "Q", net->pin_Q(idx));
|
||||
draw_pin(os, "D", net->pin_Data(idx));
|
||||
|
||||
if (net->attribute("Clock:LPM_Polarity") == "INVERT")
|
||||
draw_pin(os, "~C", net->pin_Clock());
|
||||
else
|
||||
draw_pin(os, "C", net->pin_Clock());
|
||||
|
||||
if (count_outputs(net->pin_Enable()) > 0)
|
||||
draw_pin(os, "CE", net->pin_Enable());
|
||||
|
||||
os << "END" << endl;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Generate an LPM_MUX.
|
||||
*
|
||||
* XXXX NOTE: For now, this only supports combinational LPM_MUX
|
||||
* devices that have a single select input. These are typically
|
||||
* generated from ?: expressions.
|
||||
*/
|
||||
void target_xnf::lpm_mux(ostream&os, const NetMux*net)
|
||||
{
|
||||
assert(net->sel_width() == 1);
|
||||
assert(net->size() == 2);
|
||||
|
||||
for (unsigned idx = 0 ; idx < net->width() ; idx += 1) {
|
||||
|
||||
os << "SYM, " << mangle(net->name()) << "<" << idx << ">,"
|
||||
<< " EQN, EQN=(I0 * I2) + (~I0 * I1)" << endl;
|
||||
|
||||
draw_pin(os, "I0", net->pin_Sel(0));
|
||||
draw_pin(os, "I1", net->pin_Data(idx,0));
|
||||
draw_pin(os, "I2", net->pin_Data(idx,1));
|
||||
draw_pin(os, "O", net->pin_Result(idx));
|
||||
|
||||
os << "END" << endl;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -349,6 +653,54 @@ 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>.
|
||||
*
|
||||
* Add the LPM_MUX device, and integrate it with the
|
||||
* ternary synthesis from Larry. Replace the lpm_mux
|
||||
* generator in t-xnf.cc to use XNF EQU devices to
|
||||
* put muxs into function units.
|
||||
*
|
||||
* Rewrite elaborate_net for the PETernary class to
|
||||
* also use the LPM_MUX device.
|
||||
*
|
||||
* Revision 1.10 1999/11/02 04:55:34 steve
|
||||
* Add the synthesize method to NetExpr to handle
|
||||
* synthesis of expressions, and use that method
|
||||
* to improve r-value handling of LPM_FF synthesis.
|
||||
*
|
||||
* Modify the XNF target to handle LPM_FF objects.
|
||||
*
|
||||
* Revision 1.9 1999/08/25 22:22:08 steve
|
||||
* handle bufz in XNF backend.
|
||||
*
|
||||
|
||||
@@ -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.21 1999/10/10 01:59:55 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,36 @@ 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() << "): "
|
||||
"Unhandled NetFF." << endl;
|
||||
}
|
||||
|
||||
void target_t::lpm_mux(ostream&, const NetMux*)
|
||||
{
|
||||
cerr << "target (" << typeid(*this).name() << "): "
|
||||
"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*)
|
||||
{
|
||||
}
|
||||
@@ -97,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() << "): "
|
||||
@@ -237,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() << "): "
|
||||
@@ -275,6 +308,39 @@ 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>.
|
||||
*
|
||||
* Add the LPM_MUX device, and integrate it with the
|
||||
* ternary synthesis from Larry. Replace the lpm_mux
|
||||
* generator in t-xnf.cc to use XNF EQU devices to
|
||||
* put muxs into function units.
|
||||
*
|
||||
* Rewrite elaborate_net for the PETernary class to
|
||||
* also use the LPM_MUX device.
|
||||
*
|
||||
* Revision 1.22 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.21 1999/10/10 01:59:55 steve
|
||||
* Structural case equals device.
|
||||
*
|
||||
|
||||
@@ -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.20 1999/10/10 01:59:55 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,6 +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*);
|
||||
@@ -76,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
|
||||
@@ -112,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*);
|
||||
@@ -137,6 +146,39 @@ 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>.
|
||||
*
|
||||
* Add the LPM_MUX device, and integrate it with the
|
||||
* ternary synthesis from Larry. Replace the lpm_mux
|
||||
* generator in t-xnf.cc to use XNF EQU devices to
|
||||
* put muxs into function units.
|
||||
*
|
||||
* Rewrite elaborate_net for the PETernary class to
|
||||
* also use the LPM_MUX device.
|
||||
*
|
||||
* Revision 1.21 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.20 1999/10/10 01:59:55 steve
|
||||
* Structural case equals device.
|
||||
*
|
||||
|
||||
+3
-2
@@ -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
|
||||
|
||||
+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
|
||||
|
||||
+220
-88
@@ -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.5 1999/10/28 00:47:25 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,11 +270,108 @@ 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);
|
||||
|
||||
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) {
|
||||
|
||||
switch (vpi_get(vpiType, monitor_info.items[idx])) {
|
||||
case vpiNet:
|
||||
case vpiReg:
|
||||
cb.obj = monitor_info.items[idx];
|
||||
monitor_callbacks[idx] = vpi_register_cb(&cb);
|
||||
break;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void sys_display_register()
|
||||
{
|
||||
s_vpi_systf_data tf_data;
|
||||
@@ -287,11 +399,31 @@ void sys_display_register()
|
||||
tf_data.sizetf = 0;
|
||||
tf_data.user_data = "$strobe";
|
||||
vpi_register_systf(&tf_data);
|
||||
|
||||
tf_data.type = vpiSysTask;
|
||||
tf_data.tfname = "$monitor";
|
||||
tf_data.calltf = sys_monitor_calltf;
|
||||
tf_data.compiletf = 0;
|
||||
tf_data.sizetf = 0;
|
||||
tf_data.user_data = "$monitor";
|
||||
vpi_register_systf(&tf_data);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* $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.
|
||||
*
|
||||
* Revision 1.5 1999/10/28 00:47:25 steve
|
||||
* Rewrite vvm VPI support to make objects more
|
||||
* persistent, rewrite the simulation scheduler
|
||||
|
||||
+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.9 1999/10/28 00:47:25 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_monitor.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 $@
|
||||
|
||||
+108
-10
@@ -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.1 1999/10/28 00:47:25 steve Exp $"
|
||||
#ident "$Id: vpi_callback.c,v 1.4 1999/11/07 20:33:30 steve Exp $"
|
||||
#endif
|
||||
|
||||
# include "vpi_priv.h"
|
||||
@@ -33,18 +33,99 @@ static struct __vpirt vpip_callback_rt = {
|
||||
0
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
* This function is called by the scheduler to execute an event of
|
||||
* some sort. The parameter is a vpiHandle of the callback that is to
|
||||
* be executed.
|
||||
*/
|
||||
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);
|
||||
}
|
||||
|
||||
/*
|
||||
* XXXX This currently does not support (or pay any attention to) the
|
||||
* delay parameter. Yikes!
|
||||
* This function is called by the product when it changes the value of
|
||||
* a signal. It arranges for all the value chance callbacks to be
|
||||
* called.
|
||||
*/
|
||||
void vpip_run_value_changes(struct __vpiSignal*sig)
|
||||
{
|
||||
struct __vpiCallback*cur;
|
||||
if (sig->monitor == 0) return;
|
||||
|
||||
while (sig->monitor->next != sig->monitor) {
|
||||
cur = sig->monitor->next;
|
||||
sig->monitor->next = cur->next;
|
||||
|
||||
cur->next = 0;
|
||||
cur->ev = vpip_sim_insert_event(0, cur, vpip_call_callback, 0);
|
||||
}
|
||||
|
||||
cur = sig->monitor;
|
||||
sig->monitor = 0;
|
||||
cur->next = 0;
|
||||
cur->ev = vpip_sim_insert_event(0, cur, vpip_call_callback, 0);
|
||||
}
|
||||
|
||||
/*
|
||||
* Handle read-only synch events. This causes the callback to be
|
||||
* scheduled for a moment at the end of the time period. This method
|
||||
* handles scheduling with itme delays.
|
||||
*/
|
||||
static void go_readonly_synch(struct __vpiCallback*rfp)
|
||||
{
|
||||
unsigned long tim;
|
||||
assert(rfp->cb_data.time);
|
||||
assert(rfp->cb_data.time->type == vpiSimTime);
|
||||
assert(rfp->cb_data.time->high == 0);
|
||||
tim = rfp->cb_data.time->low;
|
||||
rfp->ev = vpip_sim_insert_event(tim, rfp, vpip_call_callback, 1);
|
||||
}
|
||||
|
||||
/*
|
||||
* To schedule a value change, attach the callback to the signal to me
|
||||
* monitored. I'll be inserted as an event later.
|
||||
*/
|
||||
static void go_value_change(struct __vpiCallback*rfp)
|
||||
{
|
||||
struct __vpiSignal*sig = (struct __vpiSignal*)rfp->cb_data.obj;
|
||||
assert((sig->base.vpi_type->type_code == vpiReg)
|
||||
|| (sig->base.vpi_type->type_code == vpiNet));
|
||||
|
||||
/* If there are no monitor events, start the list. */
|
||||
if (sig->monitor == 0) {
|
||||
rfp->next = rfp;
|
||||
sig->monitor = rfp;
|
||||
return;
|
||||
}
|
||||
|
||||
/* Put me at the end of the list. Remember that the monitor
|
||||
points to the *last* item in the list. */
|
||||
rfp->next = sig->monitor->next;
|
||||
sig->monitor->next = rfp;
|
||||
sig->monitor = rfp;
|
||||
}
|
||||
|
||||
/*
|
||||
* Register callbacks. This supports a variety of callback reasons,
|
||||
* mostly by dispatching them to a type specific handler.
|
||||
*/
|
||||
vpiHandle vpi_register_cb(p_cb_data data)
|
||||
{
|
||||
@@ -54,11 +135,11 @@ vpiHandle vpi_register_cb(p_cb_data data)
|
||||
|
||||
switch (data->reason) {
|
||||
case cbReadOnlySynch:
|
||||
assert(data->time);
|
||||
assert(data->time->type == vpiSimTime);
|
||||
assert(data->time->low == 0);
|
||||
assert(data->time->high == 0);
|
||||
rfp->ev = vpip_sim_insert_event(0, rfp, vpip_call_callback, 1);
|
||||
go_readonly_synch(rfp);
|
||||
break;
|
||||
|
||||
case cbValueChange:
|
||||
go_value_change(rfp);
|
||||
break;
|
||||
|
||||
default:
|
||||
@@ -73,13 +154,30 @@ int vpi_remove_cb(vpiHandle ref)
|
||||
{
|
||||
struct __vpiCallback*rfp = (struct __vpiCallback*)ref;
|
||||
assert(ref->vpi_type->type_code == vpiCallback);
|
||||
vpip_sim_cancel_event(rfp->ev);
|
||||
|
||||
if (rfp->ev) {
|
||||
/* callbacks attached to events are easy. */
|
||||
vpip_sim_cancel_event(rfp->ev);
|
||||
|
||||
} else {
|
||||
assert(0);
|
||||
}
|
||||
|
||||
free(rfp);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* $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.
|
||||
*
|
||||
* Revision 1.2 1999/10/28 04:47:57 steve
|
||||
* Support delay in constSync callback.
|
||||
*
|
||||
* Revision 1.1 1999/10/28 00:47:25 steve
|
||||
* Rewrite vvm VPI support to make objects more
|
||||
* persistent, rewrite the simulation scheduler
|
||||
|
||||
+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.
|
||||
*
|
||||
*/
|
||||
|
||||
+84
-11
@@ -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.2 1999/10/28 00:47:25 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
|
||||
@@ -71,17 +74,10 @@ struct __vpirt {
|
||||
struct __vpiCallback {
|
||||
struct __vpiHandle base;
|
||||
struct t_cb_data cb_data;
|
||||
struct vpip_event*ev;
|
||||
};
|
||||
|
||||
/*
|
||||
* 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;
|
||||
struct vpip_event*ev;
|
||||
struct __vpiCallback*next;
|
||||
};
|
||||
extern struct __vpiNull vpip_null;
|
||||
|
||||
/*
|
||||
* The vpiHandle for an iterator has this structure. The definition of
|
||||
@@ -95,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
|
||||
@@ -103,10 +138,13 @@ struct __vpiIterator {
|
||||
*/
|
||||
struct __vpiSignal {
|
||||
struct __vpiHandle base;
|
||||
|
||||
/* The signal has a name (this points to static memory.) */
|
||||
const char*name;
|
||||
/* The signal has a value and dimension. */
|
||||
enum vpip_bit_t*bits;
|
||||
unsigned nbits;
|
||||
/* monitors are added here. */
|
||||
struct __vpiCallback*monitor;
|
||||
};
|
||||
|
||||
|
||||
@@ -145,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
|
||||
@@ -153,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);
|
||||
@@ -162,6 +215,7 @@ extern vpiHandle vpip_make_time_var(struct __vpiTimeVar*ref,
|
||||
/* Use this function to call a registered task. */
|
||||
extern void vpip_calltask(const char*name, unsigned nparms, vpiHandle*parms);
|
||||
|
||||
extern void vpip_run_value_changes(struct __vpiSignal*sig);
|
||||
|
||||
/*
|
||||
* The simulation object holds the current state of the
|
||||
@@ -220,6 +274,25 @@ 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.
|
||||
*
|
||||
* Revision 1.2 1999/10/28 00:47:25 steve
|
||||
* Rewrite vvm VPI support to make objects more
|
||||
* persistent, rewrite the simulation scheduler
|
||||
|
||||
@@ -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.
|
||||
*
|
||||
*/
|
||||
|
||||
+39
-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.1 1999/10/28 00:47:25 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,
|
||||
@@ -255,12 +78,13 @@ vpiHandle vpip_make_net(struct __vpiSignal*ref, const char*name)
|
||||
{
|
||||
ref->base.vpi_type = &vpip_net_rt;
|
||||
ref->name = name;
|
||||
ref->monitor = 0;
|
||||
return &(ref->base);
|
||||
}
|
||||
|
||||
static const struct __vpirt vpip_reg_rt = {
|
||||
vpiReg,
|
||||
0,
|
||||
signal_get,
|
||||
signal_get_str,
|
||||
signal_get_value,
|
||||
0,
|
||||
@@ -271,11 +95,24 @@ vpiHandle vpip_make_reg(struct __vpiSignal*ref, const char*name)
|
||||
{
|
||||
ref->base.vpi_type = &vpip_reg_rt;
|
||||
ref->name = name;
|
||||
ref->monitor = 0;
|
||||
return &(ref->base);
|
||||
}
|
||||
|
||||
/*
|
||||
* $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.
|
||||
*
|
||||
* Revision 1.1 1999/10/28 00:47:25 steve
|
||||
* Rewrite vvm VPI support to make objects more
|
||||
* persistent, rewrite the simulation scheduler
|
||||
|
||||
@@ -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.16 1999/10/28 00:47:25 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)
|
||||
@@ -98,11 +97,16 @@ inline vpip_bit_t not(vpip_bit_t l)
|
||||
}
|
||||
}
|
||||
|
||||
extern bool posedge(vpip_bit_t from, vpip_bit_t to);
|
||||
|
||||
|
||||
class vvm_bits_t {
|
||||
public:
|
||||
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);
|
||||
@@ -133,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];
|
||||
};
|
||||
@@ -224,52 +221,107 @@ class vvm_simulation {
|
||||
};
|
||||
|
||||
/*
|
||||
* The vvm_monitor_t is a way of attaching a name to the signal, for
|
||||
* use by the vpi_ functions. I need to make a base type so that I can
|
||||
* avoid the casting problems with the vvm_signal_t template below.
|
||||
*
|
||||
* The vvm_signal_t template is the real object that handles the
|
||||
* receiving of assignments and doing whatever is done.
|
||||
* receiving of assignments and doing whatever is done. It also
|
||||
* connects VPI to the C++/vvm design.
|
||||
*/
|
||||
class vvm_monitor_t {
|
||||
public:
|
||||
vvm_monitor_t(const char*);
|
||||
~vvm_monitor_t();
|
||||
const char* name() const;
|
||||
private:
|
||||
const char* name_;
|
||||
|
||||
private: // not implemented
|
||||
vvm_monitor_t(const vvm_monitor_t&);
|
||||
vvm_monitor_t& operator= (const vvm_monitor_t&);
|
||||
};
|
||||
|
||||
template <unsigned WIDTH> class vvm_signal_t : public vvm_monitor_t {
|
||||
template <unsigned WIDTH> class vvm_signal_t : public __vpiSignal {
|
||||
|
||||
public:
|
||||
vvm_signal_t(const char*n, vvm_bitset_t<WIDTH>*b)
|
||||
: vvm_monitor_t(n), bits_(b) { }
|
||||
|
||||
vvm_signal_t(vvm_bitset_t<WIDTH>*b)
|
||||
{ bits = b->bits;
|
||||
nbits = WIDTH;
|
||||
}
|
||||
~vvm_signal_t() { }
|
||||
|
||||
void init(unsigned idx, vpip_bit_t val)
|
||||
{ (*bits_)[idx] = val; }
|
||||
void init_P(unsigned idx, vpip_bit_t val)
|
||||
{ bits[idx] = val; }
|
||||
|
||||
void set(vvm_simulation*sim, unsigned idx, vpip_bit_t val)
|
||||
{ (*bits_)[idx] = val;
|
||||
void set_P(vvm_simulation*sim, unsigned idx, vpip_bit_t val)
|
||||
{ bits[idx] = val;
|
||||
vpip_run_value_changes(this);
|
||||
}
|
||||
|
||||
void set(vvm_simulation*sim, const vvm_bitset_t<WIDTH>&val)
|
||||
void set_P(vvm_simulation*sim, const vvm_bitset_t<WIDTH>&val)
|
||||
{ for (unsigned idx = 0 ; idx < WIDTH ; idx += 1)
|
||||
set(sim, idx, val[idx]);
|
||||
}
|
||||
};
|
||||
|
||||
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_bitset_t<WIDTH>*bits_;
|
||||
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
|
||||
* flip-flops.
|
||||
*
|
||||
* Revision 1.19 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.18 1999/10/29 03:37:22 steve
|
||||
* Support vpiValueChance callbacks.
|
||||
*
|
||||
* Revision 1.17 1999/10/28 21:36:00 steve
|
||||
* Get rid of monitor_t and fold __vpiSignal into signal.
|
||||
*
|
||||
* Revision 1.16 1999/10/28 00:47:25 steve
|
||||
* Rewrite vvm VPI support to make objects more
|
||||
* persistent, rewrite the simulation scheduler
|
||||
|
||||
+57
-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.3 1999/10/28 00:47:25 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)
|
||||
{
|
||||
@@ -41,6 +42,20 @@ ostream& operator << (ostream&os, vpip_bit_t bit)
|
||||
return os;
|
||||
}
|
||||
|
||||
bool posedge(vpip_bit_t from, vpip_bit_t to)
|
||||
{
|
||||
switch (from) {
|
||||
case V1:
|
||||
return false;
|
||||
case V0:
|
||||
return from != to;
|
||||
case Vx:
|
||||
case Vz:
|
||||
return to == V1;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
ostream& operator << (ostream&os, const vvm_bits_t&str)
|
||||
{
|
||||
os << str.get_width() << "b'";
|
||||
@@ -54,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;
|
||||
@@ -100,6 +142,20 @@ 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
|
||||
* flip-flops.
|
||||
*
|
||||
* Revision 1.3 1999/10/28 00:47:25 steve
|
||||
* Rewrite vvm VPI support to make objects more
|
||||
* persistent, rewrite the simulation scheduler
|
||||
|
||||
+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.
|
||||
*
|
||||
*/
|
||||
|
||||
+566
-220
@@ -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.15 1999/10/28 00:47:25 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,111 +60,520 @@ class vvm_out_event : public vvm_event {
|
||||
const vpip_bit_t val_;
|
||||
};
|
||||
|
||||
template <unsigned WIDTH, unsigned long DELAY> class vvm_and {
|
||||
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
|
||||
* subtraction, selectable by the Add_Sub input. When configured as a
|
||||
* subtractor, the device works by adding the 2s complement of
|
||||
* DataB.
|
||||
*/
|
||||
template <unsigned WIDTH> class vvm_add_sub {
|
||||
|
||||
public:
|
||||
vvm_add_sub() : ndir_(V0) { }
|
||||
|
||||
void config_rout(unsigned idx, vvm_out_event::action_t a)
|
||||
{ o_[idx] = a;
|
||||
}
|
||||
|
||||
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 init_Add_Sub(unsigned, vpip_bit_t val)
|
||||
{ ndir_ = not(val);
|
||||
}
|
||||
|
||||
void set_DataA(vvm_simulation*sim, unsigned idx, vpip_bit_t val)
|
||||
{ a_[idx] = val;
|
||||
compute_(sim);
|
||||
}
|
||||
void set_DataB(vvm_simulation*sim, unsigned idx, vpip_bit_t val)
|
||||
{ b_[idx] = val;
|
||||
compute_(sim);
|
||||
}
|
||||
|
||||
private:
|
||||
vpip_bit_t a_[WIDTH];
|
||||
vpip_bit_t b_[WIDTH];
|
||||
vpip_bit_t r_[WIDTH];
|
||||
|
||||
// this is the inverse of the Add_Sub port. It is 0 for add,
|
||||
// and 1 for subtract.
|
||||
vpip_bit_t ndir_;
|
||||
|
||||
vvm_out_event::action_t o_[WIDTH];
|
||||
|
||||
void compute_(vvm_simulation*sim)
|
||||
{ vpip_bit_t carry = ndir_;
|
||||
for (unsigned idx = 0 ; idx < WIDTH ; idx += 1) {
|
||||
vpip_bit_t val;
|
||||
val = add_with_carry(a_[idx], b_[idx] ^ ndir_, carry);
|
||||
if (val == r_[idx]) continue;
|
||||
r_[idx] = val;
|
||||
if (o_[idx] == 0) continue;
|
||||
vvm_event*ev = new vvm_out_event(sim, val, o_[idx]);
|
||||
sim->insert_event(0, ev);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
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(unsigned idx, vpip_bit_t val)
|
||||
{ input_[idx-1] = val; }
|
||||
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(vvm_simulation*sim, unsigned idx, vpip_bit_t val)
|
||||
{ if (input_[idx-1] == val)
|
||||
return;
|
||||
input_[idx-1] = val;
|
||||
|
||||
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_I(vvm_simulation*sim, unsigned idx, vpip_bit_t val)
|
||||
{ if (input_[idx] == val) return;
|
||||
input_[idx] = val;
|
||||
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];
|
||||
vvm_out_event::action_t output_;
|
||||
};
|
||||
|
||||
template <unsigned WIDTH, unsigned long DELAY> class vvm_or {
|
||||
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;
|
||||
}
|
||||
|
||||
~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.
|
||||
*/
|
||||
template <unsigned WIDTH> class vvm_ff {
|
||||
|
||||
public:
|
||||
explicit vvm_ff()
|
||||
{ clk_ = Vx;
|
||||
for (unsigned idx = 0 ; idx < WIDTH ; idx += 1)
|
||||
q_[idx] = Vx;
|
||||
}
|
||||
~vvm_ff() { }
|
||||
|
||||
void init_Data(unsigned idx, vpip_bit_t val) { d_[idx] = val; }
|
||||
void init_Clock(unsigned, vpip_bit_t val) { clk_ = val; }
|
||||
|
||||
void set_Clock(vvm_simulation*sim, unsigned, vpip_bit_t val)
|
||||
{ if (val == clk_) return;
|
||||
bool flag = posedge(clk_, val);
|
||||
clk_ = val;
|
||||
if (flag) latch_(sim);
|
||||
}
|
||||
|
||||
void set_Data(vvm_simulation*sim, unsigned idx, vpip_bit_t val)
|
||||
{ d_[idx] = val;
|
||||
}
|
||||
|
||||
void config_rout(unsigned idx, vvm_out_event::action_t o)
|
||||
{ out_[idx] = o;
|
||||
}
|
||||
|
||||
private:
|
||||
vpip_bit_t d_[WIDTH];
|
||||
vpip_bit_t q_[WIDTH];
|
||||
vpip_bit_t clk_;
|
||||
|
||||
vvm_out_event::action_t out_[WIDTH];
|
||||
|
||||
void latch_(vvm_simulation*sim)
|
||||
{ q_ = d_;
|
||||
for (unsigned idx = 0 ; idx < WIDTH ; idx += 1)
|
||||
if (out_[idx]) {
|
||||
vvm_event*ev = new vvm_out_event(sim, q_[idx],
|
||||
out_[idx]);
|
||||
sim->active_event(ev);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
/*
|
||||
* 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(unsigned idx, vpip_bit_t val)
|
||||
{ input_[idx-1] = val; }
|
||||
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(vvm_simulation*sim, unsigned idx, vpip_bit_t val)
|
||||
{ if (input_[idx-1] == val)
|
||||
void set_I(vvm_simulation*sim, unsigned idx, vpip_bit_t val)
|
||||
{ if (input_[idx] == val)
|
||||
return;
|
||||
input_[idx-1] = val;
|
||||
|
||||
vvm_event*ev = new vvm_out_event(sim, compute_(), output_);
|
||||
if (DELAY > 0)
|
||||
sim->insert_event(DELAY, ev);
|
||||
else
|
||||
sim->active_event(ev);
|
||||
input_[idx] = val;
|
||||
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(unsigned idx, vpip_bit_t val)
|
||||
{ input_[idx-1] = val; }
|
||||
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));
|
||||
}
|
||||
|
||||
void set(vvm_simulation*sim, unsigned idx, vpip_bit_t val)
|
||||
{ if (input_[idx-1] == val)
|
||||
return;
|
||||
input_[idx-1] = val;
|
||||
private:
|
||||
vpip_bit_t input_[WIDTH];
|
||||
};
|
||||
|
||||
vvm_event*ev = new vvm_out_event(sim, compute_(), output_);
|
||||
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
|
||||
@@ -161,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_;
|
||||
};
|
||||
|
||||
@@ -207,143 +619,91 @@ 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(unsigned, vpip_bit_t) { }
|
||||
void init_I(unsigned, vpip_bit_t) { }
|
||||
void start(vvm_simulation*) { }
|
||||
|
||||
void set(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);
|
||||
}
|
||||
void set_I(vvm_simulation*sim, unsigned, vpip_bit_t val)
|
||||
{ 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 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);
|
||||
}
|
||||
{ output(sim,compute_xnor(input_,WIDTH)); }
|
||||
|
||||
|
||||
|
||||
void set(vvm_simulation*sim, unsigned idx, vpip_bit_t val)
|
||||
{ if (input_[idx-1] == val)
|
||||
void set_I(vvm_simulation*sim, unsigned idx, vpip_bit_t val)
|
||||
{ if (input_[idx] == val)
|
||||
return;
|
||||
input_[idx-1] = 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);
|
||||
input_[idx] = val;
|
||||
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)
|
||||
: output_(o) { }
|
||||
: 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; }
|
||||
|
||||
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_xor(input_,WIDTH)); }
|
||||
|
||||
void set(vvm_simulation*sim, unsigned idx, vpip_bit_t val)
|
||||
{ if (input_[idx-1] == val)
|
||||
void set_I(vvm_simulation*sim, unsigned idx, vpip_bit_t val)
|
||||
{ if (input_[idx] == val)
|
||||
return;
|
||||
input_[idx-1] = val;
|
||||
start(sim);
|
||||
}
|
||||
input_[idx] = val;
|
||||
output(sim,compute_xor(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_;
|
||||
};
|
||||
|
||||
/*
|
||||
@@ -356,8 +716,8 @@ template <unsigned long DELAY> class vvm_eeq {
|
||||
explicit vvm_eeq(vvm_out_event::action_t o)
|
||||
: output_(o) { }
|
||||
|
||||
void init(unsigned idx, vpip_bit_t val)
|
||||
{ input_[idx-1] = val; }
|
||||
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_);
|
||||
@@ -367,10 +727,10 @@ template <unsigned long DELAY> class vvm_eeq {
|
||||
sim->active_event(ev);
|
||||
}
|
||||
|
||||
void set(vvm_simulation*sim, unsigned idx, vpip_bit_t val)
|
||||
{ if (input_[idx-1] == val)
|
||||
void set_I(vvm_simulation*sim, unsigned idx, vpip_bit_t val)
|
||||
{ if (input_[idx] == val)
|
||||
return;
|
||||
input_[idx-1] = val;
|
||||
input_[idx] = val;
|
||||
start(sim);
|
||||
}
|
||||
|
||||
@@ -502,7 +862,7 @@ template <unsigned WIDTH> class vvm_pevent {
|
||||
|
||||
vvm_bitset_t<WIDTH> get() const { return value_; }
|
||||
|
||||
void set(vvm_simulation*sim, unsigned idx, vpip_bit_t val)
|
||||
void set_P(vvm_simulation*sim, unsigned idx, vpip_bit_t val)
|
||||
{ if (value_[idx] == val) return;
|
||||
switch (edge_) {
|
||||
case ANYEDGE:
|
||||
@@ -520,7 +880,7 @@ template <unsigned WIDTH> class vvm_pevent {
|
||||
value_[idx] = val;
|
||||
}
|
||||
|
||||
void init(int idx, vpip_bit_t val)
|
||||
void init_P(int idx, vpip_bit_t val)
|
||||
{ assert(idx < WIDTH);
|
||||
value_[idx] = val;
|
||||
}
|
||||
@@ -537,60 +897,46 @@ template <unsigned WIDTH> class vvm_pevent {
|
||||
|
||||
/*
|
||||
* $Log: vvm_gates.h,v $
|
||||
* 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.30 1999/12/02 16:58:58 steve
|
||||
* Update case comparison (Eric Aardoom).
|
||||
*
|
||||
* Revision 1.14 1999/10/10 01:59:55 steve
|
||||
* Structural case equals device.
|
||||
* Revision 1.29 1999/12/02 04:54:11 steve
|
||||
* Handle mux sel of X, if inputs are equal.
|
||||
*
|
||||
* Revision 1.13 1999/10/09 19:24:36 steve
|
||||
* NOR device.
|
||||
* Revision 1.28 1999/11/25 01:34:04 steve
|
||||
* Reduce more gate templates to use vvm_1bit_out (Eric Aardoom)
|
||||
*
|
||||
* Revision 1.12 1999/07/17 03:07:27 steve
|
||||
* pevent objects have initial values.
|
||||
* Revision 1.27 1999/11/24 04:38:49 steve
|
||||
* LT and GT fixes from Eric Aardoom.
|
||||
*
|
||||
* Revision 1.11 1999/06/09 00:58:29 steve
|
||||
* Support for binary | (Stephen Tell)
|
||||
* Revision 1.26 1999/11/22 00:30:52 steve
|
||||
* Detemplate some and, or and nor methods.
|
||||
*
|
||||
* Revision 1.10 1999/05/03 01:51:29 steve
|
||||
* Restore support for wait event control.
|
||||
* 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.9 1999/05/01 20:43:55 steve
|
||||
* Handle wide events, such as @(a) where a has
|
||||
* many bits in it.
|
||||
* Revision 1.24 1999/11/21 00:13:09 steve
|
||||
* Support memories in continuous assignments.
|
||||
*
|
||||
* Add to vvm the binary ^ and unary & operators.
|
||||
* Revision 1.23 1999/11/15 00:42:31 steve
|
||||
* Fixup to include right shift support.
|
||||
*
|
||||
* Dump events a bit more completely.
|
||||
* Revision 1.22 1999/11/14 23:43:46 steve
|
||||
* Support combinatorial comparators.
|
||||
*
|
||||
* Revision 1.8 1999/05/01 02:57:53 steve
|
||||
* Handle much more complex event expressions.
|
||||
* Revision 1.21 1999/11/14 20:24:28 steve
|
||||
* Add support for the LPM_CLSHIFT device.
|
||||
*
|
||||
* Revision 1.7 1999/02/15 05:52:50 steve
|
||||
* Mangle that handles device instance numbers.
|
||||
* Revision 1.20 1999/11/14 18:22:12 steve
|
||||
* Fix NAND gate support to use named pins.
|
||||
*
|
||||
* 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.
|
||||
* 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.
|
||||
*/
|
||||
#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
|
||||
|
||||
@@ -48,11 +49,22 @@ device. Also:
|
||||
|
||||
bufif1 bt (bar, value, en);
|
||||
|
||||
connects to pad bar so will automaticall be converted into an OBUFT
|
||||
connects to pad bar so will automatically be converted into an OBUFT
|
||||
device. Icarus Verilog understands OBUF, IBUF and OBUFT (with optionally
|
||||
inverted enable) devices and will convert Verilog devices from the
|
||||
source, or generate missing devices.
|
||||
|
||||
In addition, the Verilog programmer may explicitly declare a device as
|
||||
an I/OBUF by attaching an attribute to the device, like so:
|
||||
|
||||
buf b1 (sig, foo);
|
||||
$attribute(b1, "XNF-LCA", "OBUF:O,I");
|
||||
|
||||
This latter feature is not entirely recomended as it expects that the
|
||||
programmer really knows how the pins of the XNF device are to be
|
||||
connected. It also bypasses the efforts of the compiler, so is not
|
||||
checked for correctness.
|
||||
|
||||
XNF SPECIAL DEVICES
|
||||
|
||||
There are certain special devices in XNF that Verilog does not
|
||||
@@ -73,7 +85,7 @@ buffer:
|
||||
|
||||
The above statements cause the buffer BUFG to be emitted in the XNF
|
||||
output as a BUFG device with the first signal called "O" and the
|
||||
second called "O". The rest of this example connects the input of the
|
||||
second called "I". The rest of this example connects the input of the
|
||||
BUFG to a signal from the input pin #1 and connects the output to the
|
||||
internal wire "clk". Incidentally, this example will cause an IBUF to
|
||||
be generated to connect the iclk signal to input pin #1.
|
||||
@@ -90,15 +102,28 @@ 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 -Fxnfsyn -Fsigfold -Fxnfio [...]
|
||||
ivl -txnf -fpart=4010e -Fsynth -Fnodangle -Fxnfio [...]
|
||||
|
||||
Icarus Verilog includes the functions ``xnfsyn'' and ``xnfio'' to
|
||||
Icarus Verilog includes the functions ``synth'' and ``xnfio'' to
|
||||
perform transformations and optimizations on the design before code is
|
||||
generated. The xnfsyn function matches certain behavioral constructs
|
||||
to XNF components, and the xnfio function generates pads and fills the
|
||||
IOBs.
|
||||
generated. The ``synth'' function matches certain behavioral constructs
|
||||
to structural components, and the xnfio function generates pads and
|
||||
fills the IOBs.
|
||||
|
||||
XNFSYN FUNCTION
|
||||
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,
|
||||
making it possible to generate XNF netlist components from certain
|
||||
@@ -106,13 +131,13 @@ behavioral constructs. This is needed in Verilog for example to model
|
||||
some of the synchronous components of the XNF library.
|
||||
|
||||
It is a bit much to expect a Verilog compiler in general to generate
|
||||
components from arbitrary behavioral descriptions, so the xnfsyn
|
||||
components from arbitrary behavioral descriptions, so the synth
|
||||
function works by matching statements that have some documented
|
||||
structure, and substituting them for the equivalent XNF component. A
|
||||
fully synthesize-able design, then, is one where the behavioral
|
||||
statements can all be matched and substituted by the xnfsyn function.
|
||||
statements can all be matched and substituted by the synth function.
|
||||
|
||||
XNFIO FUNCTION
|
||||
THE XNFIO FUNCTION
|
||||
|
||||
The "xnfio" function transforms the netlist where the IOBs are
|
||||
concerned. The signals with PAD attributes are checked, and
|
||||
@@ -151,6 +176,20 @@ 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.
|
||||
|
||||
Revision 1.6 1999/11/02 01:43:55 steve
|
||||
Fix iobuf and iobufif handling.
|
||||
|
||||
Revision 1.5 1999/10/09 17:52:27 steve
|
||||
support XNF OBUFT devices.
|
||||
|
||||
|
||||
@@ -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.3 1999/10/09 17:52:27 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
|
||||
@@ -68,11 +74,12 @@ static void make_obuf(Design*des, NetNet*net)
|
||||
|
||||
// Try to use an existing BUF as an OBUF. This moves the
|
||||
// BUF into the IOB.
|
||||
if ((tmp->type() == NetLogic::BUF) &&
|
||||
(count_inputs(tmp->pin(0)) == 0) &&
|
||||
(count_outputs(tmp->pin(0)) == 1)) {
|
||||
if ((tmp->type() == NetLogic::BUF)
|
||||
&& (count_inputs(tmp->pin(0)) == 0)
|
||||
&& (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
|
||||
@@ -80,11 +87,12 @@ static void make_obuf(Design*des, NetNet*net)
|
||||
// which looks just like an inverter. This uses the
|
||||
// available resources of an IOB to optimize away an
|
||||
// otherwise expensive inverter.
|
||||
if ((tmp->type() == NetLogic::NOT) &&
|
||||
(count_inputs(tmp->pin(0)) == 0) &&
|
||||
(count_outputs(tmp->pin(0)) == 1)) {
|
||||
if ((tmp->type() == NetLogic::NOT)
|
||||
&& (count_inputs(tmp->pin(0)) == 0)
|
||||
&& (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
|
||||
@@ -93,16 +101,18 @@ static void make_obuf(Design*des, NetNet*net)
|
||||
// way, but the T input is inverted.
|
||||
if ((tmp->type() == NetLogic::BUFIF1)
|
||||
&& (count_inputs(tmp->pin(0)) == 0)
|
||||
&& (count_outputs(tmp->pin(0)) == 1)) {
|
||||
tmp->attribute("XNF-LCA", "OBUFT:O,I,T");
|
||||
return;
|
||||
&& (count_outputs(tmp->pin(0)) == 1)
|
||||
&& (idx->get_pin() == 0) ) {
|
||||
tmp->attribute("XNF-LCA", "OBUFT:O,I,~T");
|
||||
return tmp;
|
||||
}
|
||||
|
||||
if ((tmp->type() == NetLogic::BUFIF1)
|
||||
if ((tmp->type() == NetLogic::BUFIF0)
|
||||
&& (count_inputs(tmp->pin(0)) == 0)
|
||||
&& (count_outputs(tmp->pin(0)) == 1)) {
|
||||
tmp->attribute("XNF-LCA", "OBUFT:O,I,~T");
|
||||
return;
|
||||
&& (count_outputs(tmp->pin(0)) == 1)
|
||||
&& (idx->get_pin() == 0) ) {
|
||||
tmp->attribute("XNF-LCA", "OBUFT:O,I,T");
|
||||
return tmp;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -125,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)
|
||||
@@ -174,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);
|
||||
}
|
||||
@@ -182,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;
|
||||
|
||||
@@ -194,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:
|
||||
@@ -213,6 +282,26 @@ 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
|
||||
*
|
||||
* Revision 1.4 1999/11/02 01:43:55 steve
|
||||
* Fix iobuf and iobufif handling.
|
||||
*
|
||||
* Revision 1.3 1999/10/09 17:52:27 steve
|
||||
* support XNF OBUFT devices.
|
||||
*
|
||||
|
||||
Reference in New Issue
Block a user