mirror of
https://github.com/steveicarus/iverilog.git
synced 2026-08-23 14:27:01 +02:00
Compare commits
107
Commits
s19991007
...
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 | ||
|
|
d6450599d6 | ||
|
|
8bad04a020 | ||
|
|
409c8ff47d | ||
|
|
59e85dcffc | ||
|
|
2c774bfe75 | ||
|
|
2e40152ff2 | ||
|
|
8ab03fa90f | ||
|
|
07e2b2b828 | ||
|
|
08175f5ebc | ||
|
|
2e15006dc0 | ||
|
|
b24fa87de6 | ||
|
|
a4143f8788 | ||
|
|
2fb754cd54 | ||
|
|
bcbab34543 | ||
|
|
475dd5760a | ||
|
|
8f2a369588 | ||
|
|
19b8615363 | ||
|
|
564f972aef | ||
|
|
86a2bf1961 | ||
|
|
70a1236626 | ||
|
|
7201865554 | ||
|
|
a4298df776 | ||
|
|
aa11f57b57 | ||
|
|
a4f3fa8997 | ||
|
|
9f860e319a | ||
|
|
29abc5a69e | ||
|
|
0f919ab5f3 | ||
|
|
eb0103deb5 | ||
|
|
5b7d783979 | ||
|
|
32e5eb6681 | ||
|
|
213d02c4e5 | ||
|
|
6997971884 | ||
|
|
11eccfc033 |
+38
-24
@@ -18,7 +18,7 @@
|
||||
# 59 Temple Place - Suite 330
|
||||
# Boston, MA 02111-1307, USA
|
||||
#
|
||||
#ident "$Id: Makefile.in,v 1.20 1999/09/29 01:50:35 steve Exp $"
|
||||
#ident "$Id: Makefile.in,v 1.24.2.1 1999/12/03 17:43:49 steve Exp $"
|
||||
#
|
||||
#
|
||||
SHELL = /bin/sh
|
||||
@@ -41,21 +41,29 @@ CXX = @CXX@
|
||||
INSTALL = @INSTALL@
|
||||
INSTALL_PROGRAM = @INSTALL_PROGRAM@
|
||||
INSTALL_DATA = @INSTALL_DATA@
|
||||
STRIP = @STRIP@
|
||||
|
||||
CPPFLAGS = @CPPFLAGS@ @DEFS@
|
||||
CXXFLAGS = @CXXFLAGS@
|
||||
CXXFLAGS = @CXXFLAGS@ -I$(srcdir)
|
||||
LDFLAGS = @LDFLAGS@
|
||||
|
||||
all: ivl verilog
|
||||
cd vpi ; make all
|
||||
cd vvm ; make all
|
||||
cd ivlpp ; make all
|
||||
cd vpi ; $(MAKE) all
|
||||
cd vvm ; $(MAKE) all
|
||||
cd ivlpp ; $(MAKE) all
|
||||
|
||||
clean:
|
||||
rm *.o parse.cc parse.cc.output parse.h dep/*.d lexor.cc
|
||||
cd vpi ; make clean
|
||||
cd vvm ; make clean
|
||||
cd ivlpp ; make clean
|
||||
rm -f *.o parse.cc parse.cc.output parse.h dep/*.d lexor.cc verilog
|
||||
cd vpi ; $(MAKE) clean
|
||||
cd vvm ; $(MAKE) clean
|
||||
cd ivlpp ; $(MAKE) clean
|
||||
|
||||
distclean: clean
|
||||
rm -f vpi/Makefile
|
||||
rm -f vvm/Makefile
|
||||
rm -f ivlpp/Makefile
|
||||
rm -f config.status config.cache config.log
|
||||
rm -f Makefile
|
||||
|
||||
TT = t-null.o t-verilog.o t-vvm.o t-xnf.o
|
||||
FF = nobufz.o propinit.o sigfold.o xnfio.o xnfsyn.o
|
||||
@@ -77,8 +85,13 @@ Makefile: Makefile.in config.status
|
||||
# the configured copy.
|
||||
tmp1 = bindir
|
||||
tmp2 = libdir
|
||||
tmp3 = includedir
|
||||
tmp4 = CXX
|
||||
verilog: $(srcdir)/verilog.sh
|
||||
sed -e 's;@$(tmp1)@;@bindir@;' -e 's;@$(tmp2)@;@libdir@;' < $< > $@
|
||||
sed -e 's;@$(tmp1)@;@bindir@;' \
|
||||
-e 's;@$(tmp2)@;@libdir@;' \
|
||||
-e 's;@$(tmp3)@;@includedir@;' \
|
||||
-e 's;@$(tmp4)@;@CXX@;' < $< > $@
|
||||
|
||||
ivl: $O
|
||||
$(CXX) $(CXXFLAGS) -o ivl $O
|
||||
@@ -93,37 +106,38 @@ lexor.o dep/lexor.d: lexor.cc parse.h
|
||||
|
||||
parse.o dep/parse.d: parse.cc
|
||||
|
||||
parse.h parse.cc: parse.y
|
||||
bison --verbose -t -p VL -d parse.y -o parse.cc
|
||||
parse.h parse.cc: $(srcdir)/parse.y
|
||||
bison --verbose -t -p VL -d $(srcdir)/parse.y -o parse.cc
|
||||
mv parse.cc.h parse.h
|
||||
|
||||
lexor.cc: lexor.lex
|
||||
flex -PVL -s -olexor.cc lexor.lex
|
||||
lexor.cc: $(srcdir)/lexor.lex
|
||||
flex -PVL -s -olexor.cc $(srcdir)/lexor.lex
|
||||
|
||||
install: all installdirs $(bindir)/verilog $(bindir)/ivl $(mandir)/man1/verilog.1
|
||||
cd vpi ; make install
|
||||
cd vvm ; make install
|
||||
cd ivlpp ; make install
|
||||
install: all installdirs $(bindir)/verilog $(libdir)/ivl/ivl $(mandir)/man1/verilog.1
|
||||
cd vpi ; $(MAKE) install
|
||||
cd vvm ; $(MAKE) install
|
||||
cd ivlpp ; $(MAKE) install
|
||||
|
||||
$(bindir)/verilog: ./verilog
|
||||
$(INSTALL_PROGRAM) ./verilog $(bindir)/verilog
|
||||
|
||||
$(bindir)/ivl: ivl
|
||||
$(INSTALL_PROGRAM) ./ivl $(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
|
||||
|
||||
installdirs: mkinstalldirs
|
||||
$(srcdir)/mkinstalldirs $(includedir) $(bindir)
|
||||
$(srcdir)/mkinstalldirs $(bindir) $(mandir)/man1
|
||||
|
||||
uninstall:
|
||||
rm -f $(bindir)/ivl
|
||||
rm -f $(bindir)/verilog
|
||||
rm -f $(mandir)/man1/verilog.1
|
||||
cd vpi ; make uninstall
|
||||
cd vvm ; make uninstall
|
||||
cd ivlpp ; make uninstall
|
||||
cd vpi ; $(MAKE) uninstall
|
||||
cd vvm ; $(MAKE) uninstall
|
||||
cd ivlpp ; $(MAKE) uninstall
|
||||
|
||||
|
||||
-include $(patsubst %.o, dep/%.d, $O)
|
||||
|
||||
@@ -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.
|
||||
|
||||
+62
-29
@@ -2,21 +2,65 @@
|
||||
September 18, 1999
|
||||
|
||||
|
||||
1.0 What is ICARUS Verilog(IVL)?
|
||||
1.0 What is ICARUS Verilog?
|
||||
|
||||
Icarus Verilog is intended to compile ALL of the Verilog HDL as described
|
||||
in the IEEE-1364 standard. Of course, it's not quite there yet. It does
|
||||
currently handle a mix of structural and behavioral constructs. For a
|
||||
view of the current state of Icarus Verilog, see its home page at
|
||||
<http://www.icarus.com/pub/verilog>.
|
||||
<http://www.icarus.com/eda/verilog>.
|
||||
|
||||
IVL is not aimed at being a simulator in the traditional sense, but a
|
||||
compiler that generates code employed by back-end tools. These back-
|
||||
end tools currently include a simulator written in C++ called VVM
|
||||
and an XNF (Xilinx Netlist Format) generator. See "vvm.txt" and
|
||||
"xnf.txt" for further details on these back-end processors.
|
||||
"xnf.txt" for further details on these back-end processors. In the
|
||||
future, backends are expected for EDIF/LPM, structural Verilog, etc.
|
||||
|
||||
2.0 How IVL Works
|
||||
2.0 Building/Installing IVL From Source
|
||||
|
||||
If you are starting from source, the build process is designed to be
|
||||
as simple as practical. Someone basically familiar with the target
|
||||
system and C/C++ compilation should be able to build the source
|
||||
distribution with little effort. Some actual programming skills are
|
||||
not required, but helpful in case of problems.
|
||||
|
||||
2.1 Compile Time Prerequisites
|
||||
|
||||
You need the following software to compile Icarus Verilog from source
|
||||
on a UNIX-like system:
|
||||
|
||||
- GNU Make
|
||||
The Makefiles use some GNU extensions to, so a basic POSIX
|
||||
make will not work. Linux systems typically come with a
|
||||
satisfactory make.
|
||||
|
||||
- ISO C++ Compiler
|
||||
The ivl program is written in C++ and makes use of templates
|
||||
and some of the standard C++ library. egcs compilers with
|
||||
the associated libstdc++ are known to work.
|
||||
|
||||
- bison
|
||||
|
||||
2.2 Compilation
|
||||
|
||||
Unpack the tar-ball and cd into the verilog-######### directory
|
||||
(presumably that is how you got to this README) and compile the source
|
||||
with the commands:
|
||||
|
||||
./configure
|
||||
make
|
||||
|
||||
2.3 Installation
|
||||
|
||||
Now install the files in an appropriate place. (The makefiles by
|
||||
default install in /usr/local unless you specify a different prefix
|
||||
with the --prefix=<path> flag to the configure command.) Do this as
|
||||
root.
|
||||
|
||||
make install
|
||||
|
||||
3.0 How IVL Works
|
||||
|
||||
This tool includes a parser which reads in Verilog (plus extensions)
|
||||
and generates an internal netlist. The netlist is passed to various
|
||||
@@ -25,7 +69,7 @@ forms, then is passed to a code generator for final output. The
|
||||
processing steps and the code generator are selected by command line
|
||||
switches.
|
||||
|
||||
2.1 Preprocessing
|
||||
3.1 Preprocessing
|
||||
|
||||
There is a separate program, ivlpp, that does the preprocessing. This
|
||||
program implements the `include and `define directives producing
|
||||
@@ -33,7 +77,7 @@ output that is equivalent but without the directives. The output is a
|
||||
single file with line number directives, so that the actual compiler
|
||||
only sees a single input file. See ivlpp/ivlpp.txt for details.
|
||||
|
||||
2.2 Parse
|
||||
3.2 Parse
|
||||
|
||||
The verilog compiler starts by parsing the verilog source file. The
|
||||
output of the parse in a list of Module objects in PFORM. The pform
|
||||
@@ -45,7 +89,7 @@ One can see a human readable version of the final PFORM by using the
|
||||
``-P <path>'' flag to the compiler. This will cause ivl to dump the
|
||||
PFORM into the file named <path>.
|
||||
|
||||
2.3 Elaboration
|
||||
3.3 Elaboration
|
||||
|
||||
This phase takes the pform and generates a netlist. The driver selects
|
||||
(by user request or lucky guess) the root module to elaborate,
|
||||
@@ -60,7 +104,7 @@ optimized netlist by using the ``-N <path>'' flag to the compiler. If
|
||||
elaboration succeeds, the final netlist (i.e. after optimizations but
|
||||
before code generation) will be dumped into the file named <path>.
|
||||
|
||||
2.4 Optimization
|
||||
3.4 Optimization
|
||||
|
||||
This is actually a collection of processing steps that perform
|
||||
optimizations that do not depend on the target technology. Examples of
|
||||
@@ -73,7 +117,7 @@ some useful transformations would be,
|
||||
The actual functions performed are specified on the command line by
|
||||
the -F flags (See below).
|
||||
|
||||
2.5 Code Generation
|
||||
3.5 Code Generation
|
||||
|
||||
This step takes the design netlist and uses it to drive the code
|
||||
generator. (See target.h.) This may require transforming the
|
||||
@@ -86,21 +130,6 @@ to generate actual output.
|
||||
The target code generator to used is given by the -t flag on the
|
||||
command line.
|
||||
|
||||
3.0 Building/Installing IVL
|
||||
|
||||
Unpack the tar-ball and cd into the verilog-######### directory, and
|
||||
compile the source with the commands:
|
||||
|
||||
./configure
|
||||
make
|
||||
|
||||
Now install the files in an appropriate place. (The makefiles by
|
||||
default install in /usr/local unless you specify a different prefix
|
||||
with the --prefix=<path> flag to the configure command.) Do this as
|
||||
root.
|
||||
|
||||
make install
|
||||
|
||||
4.0 Running Verilog
|
||||
|
||||
The preferred way to invoke the compiler with the verilog(1)
|
||||
@@ -266,11 +295,12 @@ 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.
|
||||
- Structural shift 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
|
||||
assign foo = a << b; // sorry
|
||||
always @(a or b) foo = a << b; // OK
|
||||
parameter foo = a << b; // OK
|
||||
|
||||
- Functions in structural contexts are not supported.
|
||||
|
||||
@@ -297,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.
|
||||
|
||||
|
||||
@@ -323,4 +355,5 @@ especially testing from many people, including (in alphabetical order):
|
||||
Steve Wilson <[email protected]>
|
||||
|
||||
and others. Testers in particular include a larger community of people
|
||||
interested in a GPL Verilog for Linux.
|
||||
interested in a GPL Verilog for Linux. Special thanks to Steve Wilson
|
||||
for collecting and organizing the test suite code for all those testers.
|
||||
|
||||
+912
@@ -0,0 +1,912 @@
|
||||
#! /bin/sh
|
||||
# Attempt to guess a canonical system name.
|
||||
# Copyright (C) 1992, 93, 94, 95, 96, 1997 Free Software Foundation, Inc.
|
||||
#
|
||||
# This file is free software; you can redistribute it and/or modify it
|
||||
# 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.
|
||||
#
|
||||
# As a special exception to the GNU General Public License, if you
|
||||
# distribute this file as part of a program that contains a
|
||||
# configuration script generated by Autoconf, you may include it under
|
||||
# the same distribution terms that you use for the rest of that program.
|
||||
|
||||
# Written by Per Bothner <[email protected]>.
|
||||
# The master version of this file is at the FSF in /home/gd/gnu/lib.
|
||||
#
|
||||
# This script attempts to guess a canonical system name similar to
|
||||
# config.sub. If it succeeds, it prints the system name on stdout, and
|
||||
# exits with 0. Otherwise, it exits with 1.
|
||||
#
|
||||
# The plan is that this can be called by configure scripts if you
|
||||
# don't specify an explicit system type (host/target name).
|
||||
#
|
||||
# Only a few systems have been added to this list; please add others
|
||||
# (but try to keep the structure clean).
|
||||
#
|
||||
|
||||
# This is needed to find uname on a Pyramid OSx when run in the BSD universe.
|
||||
# ([email protected] 8/24/94.)
|
||||
if (test -f /.attbin/uname) >/dev/null 2>&1 ; then
|
||||
PATH=$PATH:/.attbin ; export PATH
|
||||
fi
|
||||
|
||||
UNAME_MACHINE=`(uname -m) 2>/dev/null` || UNAME_MACHINE=unknown
|
||||
UNAME_RELEASE=`(uname -r) 2>/dev/null` || UNAME_RELEASE=unknown
|
||||
UNAME_SYSTEM=`(uname -s) 2>/dev/null` || UNAME_SYSTEM=unknown
|
||||
UNAME_VERSION=`(uname -v) 2>/dev/null` || UNAME_VERSION=unknown
|
||||
|
||||
trap 'rm -f dummy.c dummy.o dummy; exit 1' 1 2 15
|
||||
|
||||
# Note: order is significant - the case branches are not exclusive.
|
||||
|
||||
case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in
|
||||
alpha:OSF1:*:*)
|
||||
if test $UNAME_RELEASE = "V4.0"; then
|
||||
UNAME_RELEASE=`/usr/sbin/sizer -v | awk '{print $3}'`
|
||||
fi
|
||||
# A Vn.n version is a released version.
|
||||
# A Tn.n version is a released field test version.
|
||||
# A Xn.n version is an unreleased experimental baselevel.
|
||||
# 1.2 uses "1.2" for uname -r.
|
||||
cat <<EOF >dummy.s
|
||||
.globl main
|
||||
.ent main
|
||||
main:
|
||||
.frame \$30,0,\$26,0
|
||||
.prologue 0
|
||||
.long 0x47e03d80 # implver $0
|
||||
lda \$2,259
|
||||
.long 0x47e20c21 # amask $2,$1
|
||||
srl \$1,8,\$2
|
||||
sll \$2,2,\$2
|
||||
sll \$0,3,\$0
|
||||
addl \$1,\$0,\$0
|
||||
addl \$2,\$0,\$0
|
||||
ret \$31,(\$26),1
|
||||
.end main
|
||||
EOF
|
||||
${CC-cc} dummy.s -o dummy 2>/dev/null
|
||||
if test "$?" = 0 ; then
|
||||
./dummy
|
||||
case "$?" in
|
||||
7)
|
||||
UNAME_MACHINE="alpha"
|
||||
;;
|
||||
15)
|
||||
UNAME_MACHINE="alphaev5"
|
||||
;;
|
||||
14)
|
||||
UNAME_MACHINE="alphaev56"
|
||||
;;
|
||||
10)
|
||||
UNAME_MACHINE="alphapca56"
|
||||
;;
|
||||
16)
|
||||
UNAME_MACHINE="alphaev6"
|
||||
;;
|
||||
esac
|
||||
fi
|
||||
rm -f dummy.s dummy
|
||||
echo ${UNAME_MACHINE}-dec-osf`echo ${UNAME_RELEASE} | sed -e 's/^[VTX]//' | tr [[A-Z]] [[a-z]]`
|
||||
exit 0 ;;
|
||||
21064:Windows_NT:50:3)
|
||||
echo alpha-dec-winnt3.5
|
||||
exit 0 ;;
|
||||
Amiga*:UNIX_System_V:4.0:*)
|
||||
echo m68k-cbm-sysv4
|
||||
exit 0;;
|
||||
amiga:NetBSD:*:*)
|
||||
echo m68k-cbm-netbsd${UNAME_RELEASE}
|
||||
exit 0 ;;
|
||||
amiga:OpenBSD:*:*)
|
||||
echo m68k-unknown-openbsd${UNAME_RELEASE}
|
||||
exit 0 ;;
|
||||
arc64:OpenBSD:*:*)
|
||||
echo mips64el-unknown-openbsd${UNAME_RELEASE}
|
||||
exit 0 ;;
|
||||
arc:OpenBSD:*:*)
|
||||
echo mipsel-unknown-openbsd${UNAME_RELEASE}
|
||||
exit 0 ;;
|
||||
hkmips:OpenBSD:*:*)
|
||||
echo mips-unknown-openbsd${UNAME_RELEASE}
|
||||
exit 0 ;;
|
||||
pmax:OpenBSD:*:*)
|
||||
echo mipsel-unknown-openbsd${UNAME_RELEASE}
|
||||
exit 0 ;;
|
||||
sgi:OpenBSD:*:*)
|
||||
echo mips-unknown-openbsd${UNAME_RELEASE}
|
||||
exit 0 ;;
|
||||
wgrisc:OpenBSD:*:*)
|
||||
echo mipsel-unknown-openbsd${UNAME_RELEASE}
|
||||
exit 0 ;;
|
||||
arm:RISC*:1.[012]*:*|arm:riscix:1.[012]*:*)
|
||||
echo arm-acorn-riscix${UNAME_RELEASE}
|
||||
exit 0;;
|
||||
arm32:NetBSD:*:*)
|
||||
echo arm-unknown-netbsd`echo ${UNAME_RELEASE}|sed -e 's/[-_].*/\./'`
|
||||
exit 0 ;;
|
||||
SR2?01:HI-UX/MPP:*:*)
|
||||
echo hppa1.1-hitachi-hiuxmpp
|
||||
exit 0;;
|
||||
Pyramid*:OSx*:*:*|MIS*:OSx*:*:*)
|
||||
# [email protected] (Earle F. Ake) contributed MIS and NILE.
|
||||
if test "`(/bin/universe) 2>/dev/null`" = att ; then
|
||||
echo pyramid-pyramid-sysv3
|
||||
else
|
||||
echo pyramid-pyramid-bsd
|
||||
fi
|
||||
exit 0 ;;
|
||||
NILE:*:*:dcosx)
|
||||
echo pyramid-pyramid-svr4
|
||||
exit 0 ;;
|
||||
sun4*:SunOS:5.*:* | tadpole*:SunOS:5.*:*)
|
||||
echo sparc-sun-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
|
||||
exit 0 ;;
|
||||
i86pc:SunOS:5.*:*)
|
||||
echo i386-pc-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
|
||||
exit 0 ;;
|
||||
sun4*:SunOS:6*:*)
|
||||
# According to config.sub, this is the proper way to canonicalize
|
||||
# SunOS6. Hard to guess exactly what SunOS6 will be like, but
|
||||
# it's likely to be more like Solaris than SunOS4.
|
||||
echo sparc-sun-solaris3`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
|
||||
exit 0 ;;
|
||||
sun4*:SunOS:*:*)
|
||||
case "`/usr/bin/arch -k`" in
|
||||
Series*|S4*)
|
||||
UNAME_RELEASE=`uname -v`
|
||||
;;
|
||||
esac
|
||||
# Japanese Language versions have a version number like `4.1.3-JL'.
|
||||
echo sparc-sun-sunos`echo ${UNAME_RELEASE}|sed -e 's/-/_/'`
|
||||
exit 0 ;;
|
||||
sun3*:SunOS:*:*)
|
||||
echo m68k-sun-sunos${UNAME_RELEASE}
|
||||
exit 0 ;;
|
||||
sun*:*:4.2BSD:*)
|
||||
UNAME_RELEASE=`(head -1 /etc/motd | awk '{print substr($5,1,3)}') 2>/dev/null`
|
||||
test "x${UNAME_RELEASE}" = "x" && UNAME_RELEASE=3
|
||||
case "`/bin/arch`" in
|
||||
sun3)
|
||||
echo m68k-sun-sunos${UNAME_RELEASE}
|
||||
;;
|
||||
sun4)
|
||||
echo sparc-sun-sunos${UNAME_RELEASE}
|
||||
;;
|
||||
esac
|
||||
exit 0 ;;
|
||||
aushp:SunOS:*:*)
|
||||
echo sparc-auspex-sunos${UNAME_RELEASE}
|
||||
exit 0 ;;
|
||||
atari*:NetBSD:*:*)
|
||||
echo m68k-atari-netbsd${UNAME_RELEASE}
|
||||
exit 0 ;;
|
||||
atari*:OpenBSD:*:*)
|
||||
echo m68k-unknown-openbsd${UNAME_RELEASE}
|
||||
exit 0 ;;
|
||||
sun3*:NetBSD:*:*)
|
||||
echo m68k-sun-netbsd${UNAME_RELEASE}
|
||||
exit 0 ;;
|
||||
sun3*:OpenBSD:*:*)
|
||||
echo m68k-unknown-openbsd${UNAME_RELEASE}
|
||||
exit 0 ;;
|
||||
mac68k:NetBSD:*:*)
|
||||
echo m68k-apple-netbsd${UNAME_RELEASE}
|
||||
exit 0 ;;
|
||||
mac68k:OpenBSD:*:*)
|
||||
echo m68k-unknown-openbsd${UNAME_RELEASE}
|
||||
exit 0 ;;
|
||||
mvme68k:OpenBSD:*:*)
|
||||
echo m68k-unknown-openbsd${UNAME_RELEASE}
|
||||
exit 0 ;;
|
||||
mvme88k:OpenBSD:*:*)
|
||||
echo m88k-unknown-openbsd${UNAME_RELEASE}
|
||||
exit 0 ;;
|
||||
powerpc:machten:*:*)
|
||||
echo powerpc-apple-machten${UNAME_RELEASE}
|
||||
exit 0 ;;
|
||||
RISC*:Mach:*:*)
|
||||
echo mips-dec-mach_bsd4.3
|
||||
exit 0 ;;
|
||||
RISC*:ULTRIX:*:*)
|
||||
echo mips-dec-ultrix${UNAME_RELEASE}
|
||||
exit 0 ;;
|
||||
VAX*:ULTRIX*:*:*)
|
||||
echo vax-dec-ultrix${UNAME_RELEASE}
|
||||
exit 0 ;;
|
||||
2020:CLIX:*:*)
|
||||
echo clipper-intergraph-clix${UNAME_RELEASE}
|
||||
exit 0 ;;
|
||||
mips:*:*:UMIPS | mips:*:*:RISCos)
|
||||
sed 's/^ //' << EOF >dummy.c
|
||||
int main (argc, argv) int argc; char **argv; {
|
||||
#if defined (host_mips) && defined (MIPSEB)
|
||||
#if defined (SYSTYPE_SYSV)
|
||||
printf ("mips-mips-riscos%ssysv\n", argv[1]); exit (0);
|
||||
#endif
|
||||
#if defined (SYSTYPE_SVR4)
|
||||
printf ("mips-mips-riscos%ssvr4\n", argv[1]); exit (0);
|
||||
#endif
|
||||
#if defined (SYSTYPE_BSD43) || defined(SYSTYPE_BSD)
|
||||
printf ("mips-mips-riscos%sbsd\n", argv[1]); exit (0);
|
||||
#endif
|
||||
#endif
|
||||
exit (-1);
|
||||
}
|
||||
EOF
|
||||
${CC-cc} dummy.c -o dummy \
|
||||
&& ./dummy `echo "${UNAME_RELEASE}" | sed -n 's/\([0-9]*\).*/\1/p'` \
|
||||
&& rm dummy.c dummy && exit 0
|
||||
rm -f dummy.c dummy
|
||||
echo mips-mips-riscos${UNAME_RELEASE}
|
||||
exit 0 ;;
|
||||
Night_Hawk:Power_UNIX:*:*)
|
||||
echo powerpc-harris-powerunix
|
||||
exit 0 ;;
|
||||
m88k:CX/UX:7*:*)
|
||||
echo m88k-harris-cxux7
|
||||
exit 0 ;;
|
||||
m88k:*:4*:R4*)
|
||||
echo m88k-motorola-sysv4
|
||||
exit 0 ;;
|
||||
m88k:*:3*:R3*)
|
||||
echo m88k-motorola-sysv3
|
||||
exit 0 ;;
|
||||
AViiON:dgux:*:*)
|
||||
# DG/UX returns AViiON for all architectures
|
||||
UNAME_PROCESSOR=`/usr/bin/uname -p`
|
||||
if [ $UNAME_PROCESSOR = mc88100 -o $UNAME_PROCESSOR = mc88110 ] ; then
|
||||
if [ ${TARGET_BINARY_INTERFACE}x = m88kdguxelfx \
|
||||
-o ${TARGET_BINARY_INTERFACE}x = x ] ; then
|
||||
echo m88k-dg-dgux${UNAME_RELEASE}
|
||||
else
|
||||
echo m88k-dg-dguxbcs${UNAME_RELEASE}
|
||||
fi
|
||||
else echo i586-dg-dgux${UNAME_RELEASE}
|
||||
fi
|
||||
exit 0 ;;
|
||||
M88*:DolphinOS:*:*) # DolphinOS (SVR3)
|
||||
echo m88k-dolphin-sysv3
|
||||
exit 0 ;;
|
||||
M88*:*:R3*:*)
|
||||
# Delta 88k system running SVR3
|
||||
echo m88k-motorola-sysv3
|
||||
exit 0 ;;
|
||||
XD88*:*:*:*) # Tektronix XD88 system running UTekV (SVR3)
|
||||
echo m88k-tektronix-sysv3
|
||||
exit 0 ;;
|
||||
Tek43[0-9][0-9]:UTek:*:*) # Tektronix 4300 system running UTek (BSD)
|
||||
echo m68k-tektronix-bsd
|
||||
exit 0 ;;
|
||||
*:IRIX*:*:*)
|
||||
echo mips-sgi-irix`echo ${UNAME_RELEASE}|sed -e 's/-/_/g'`
|
||||
exit 0 ;;
|
||||
????????:AIX?:[12].1:2) # AIX 2.2.1 or AIX 2.1.1 is RT/PC AIX.
|
||||
echo romp-ibm-aix # uname -m gives an 8 hex-code CPU id
|
||||
exit 0 ;; # Note that: echo "'`uname -s`'" gives 'AIX '
|
||||
i?86:AIX:*:*)
|
||||
echo i386-ibm-aix
|
||||
exit 0 ;;
|
||||
*:AIX:2:3)
|
||||
if grep bos325 /usr/include/stdio.h >/dev/null 2>&1; then
|
||||
sed 's/^ //' << EOF >dummy.c
|
||||
#include <sys/systemcfg.h>
|
||||
|
||||
main()
|
||||
{
|
||||
if (!__power_pc())
|
||||
exit(1);
|
||||
puts("powerpc-ibm-aix3.2.5");
|
||||
exit(0);
|
||||
}
|
||||
EOF
|
||||
${CC-cc} dummy.c -o dummy && ./dummy && rm dummy.c dummy && exit 0
|
||||
rm -f dummy.c dummy
|
||||
echo rs6000-ibm-aix3.2.5
|
||||
elif grep bos324 /usr/include/stdio.h >/dev/null 2>&1; then
|
||||
echo rs6000-ibm-aix3.2.4
|
||||
else
|
||||
echo rs6000-ibm-aix3.2
|
||||
fi
|
||||
exit 0 ;;
|
||||
*:AIX:*:4)
|
||||
if /usr/sbin/lsattr -EHl proc0 | grep POWER >/dev/null 2>&1; then
|
||||
IBM_ARCH=rs6000
|
||||
else
|
||||
IBM_ARCH=powerpc
|
||||
fi
|
||||
if [ -x /usr/bin/oslevel ] ; then
|
||||
IBM_REV=`/usr/bin/oslevel`
|
||||
else
|
||||
IBM_REV=4.${UNAME_RELEASE}
|
||||
fi
|
||||
echo ${IBM_ARCH}-ibm-aix${IBM_REV}
|
||||
exit 0 ;;
|
||||
*:AIX:*:*)
|
||||
echo rs6000-ibm-aix
|
||||
exit 0 ;;
|
||||
ibmrt:4.4BSD:*|romp-ibm:BSD:*)
|
||||
echo romp-ibm-bsd4.4
|
||||
exit 0 ;;
|
||||
ibmrt:*BSD:*|romp-ibm:BSD:*) # covers RT/PC NetBSD and
|
||||
echo romp-ibm-bsd${UNAME_RELEASE} # 4.3 with uname added to
|
||||
exit 0 ;; # report: romp-ibm BSD 4.3
|
||||
*:BOSX:*:*)
|
||||
echo rs6000-bull-bosx
|
||||
exit 0 ;;
|
||||
DPX/2?00:B.O.S.:*:*)
|
||||
echo m68k-bull-sysv3
|
||||
exit 0 ;;
|
||||
9000/[34]??:4.3bsd:1.*:*)
|
||||
echo m68k-hp-bsd
|
||||
exit 0 ;;
|
||||
hp300:4.4BSD:*:* | 9000/[34]??:4.3bsd:2.*:*)
|
||||
echo m68k-hp-bsd4.4
|
||||
exit 0 ;;
|
||||
9000/[3478]??:HP-UX:*:*)
|
||||
case "${UNAME_MACHINE}" in
|
||||
9000/31? ) HP_ARCH=m68000 ;;
|
||||
9000/[34]?? ) HP_ARCH=m68k ;;
|
||||
9000/7?? | 9000/8?[1679] ) HP_ARCH=hppa1.1 ;;
|
||||
9000/8?? ) HP_ARCH=hppa1.0 ;;
|
||||
esac
|
||||
HPUX_REV=`echo ${UNAME_RELEASE}|sed -e 's/[^.]*.[0B]*//'`
|
||||
echo ${HP_ARCH}-hp-hpux${HPUX_REV}
|
||||
exit 0 ;;
|
||||
3050*:HI-UX:*:*)
|
||||
sed 's/^ //' << EOF >dummy.c
|
||||
#include <unistd.h>
|
||||
int
|
||||
main ()
|
||||
{
|
||||
long cpu = sysconf (_SC_CPU_VERSION);
|
||||
/* The order matters, because CPU_IS_HP_MC68K erroneously returns
|
||||
true for CPU_PA_RISC1_0. CPU_IS_PA_RISC returns correct
|
||||
results, however. */
|
||||
if (CPU_IS_PA_RISC (cpu))
|
||||
{
|
||||
switch (cpu)
|
||||
{
|
||||
case CPU_PA_RISC1_0: puts ("hppa1.0-hitachi-hiuxwe2"); break;
|
||||
case CPU_PA_RISC1_1: puts ("hppa1.1-hitachi-hiuxwe2"); break;
|
||||
case CPU_PA_RISC2_0: puts ("hppa2.0-hitachi-hiuxwe2"); break;
|
||||
default: puts ("hppa-hitachi-hiuxwe2"); break;
|
||||
}
|
||||
}
|
||||
else if (CPU_IS_HP_MC68K (cpu))
|
||||
puts ("m68k-hitachi-hiuxwe2");
|
||||
else puts ("unknown-hitachi-hiuxwe2");
|
||||
exit (0);
|
||||
}
|
||||
EOF
|
||||
${CC-cc} dummy.c -o dummy && ./dummy && rm dummy.c dummy && exit 0
|
||||
rm -f dummy.c dummy
|
||||
echo unknown-hitachi-hiuxwe2
|
||||
exit 0 ;;
|
||||
9000/7??:4.3bsd:*:* | 9000/8?[79]:4.3bsd:*:* )
|
||||
echo hppa1.1-hp-bsd
|
||||
exit 0 ;;
|
||||
9000/8??:4.3bsd:*:*)
|
||||
echo hppa1.0-hp-bsd
|
||||
exit 0 ;;
|
||||
hp7??:OSF1:*:* | hp8?[79]:OSF1:*:* )
|
||||
echo hppa1.1-hp-osf
|
||||
exit 0 ;;
|
||||
hp8??:OSF1:*:*)
|
||||
echo hppa1.0-hp-osf
|
||||
exit 0 ;;
|
||||
i?86:OSF1:*:*)
|
||||
if [ -x /usr/sbin/sysversion ] ; then
|
||||
echo ${UNAME_MACHINE}-unknown-osf1mk
|
||||
else
|
||||
echo ${UNAME_MACHINE}-unknown-osf1
|
||||
fi
|
||||
exit 0 ;;
|
||||
parisc*:Lites*:*:*)
|
||||
echo hppa1.1-hp-lites
|
||||
exit 0 ;;
|
||||
C1*:ConvexOS:*:* | convex:ConvexOS:C1*:*)
|
||||
echo c1-convex-bsd
|
||||
exit 0 ;;
|
||||
C2*:ConvexOS:*:* | convex:ConvexOS:C2*:*)
|
||||
if getsysinfo -f scalar_acc
|
||||
then echo c32-convex-bsd
|
||||
else echo c2-convex-bsd
|
||||
fi
|
||||
exit 0 ;;
|
||||
C34*:ConvexOS:*:* | convex:ConvexOS:C34*:*)
|
||||
echo c34-convex-bsd
|
||||
exit 0 ;;
|
||||
C38*:ConvexOS:*:* | convex:ConvexOS:C38*:*)
|
||||
echo c38-convex-bsd
|
||||
exit 0 ;;
|
||||
C4*:ConvexOS:*:* | convex:ConvexOS:C4*:*)
|
||||
echo c4-convex-bsd
|
||||
exit 0 ;;
|
||||
CRAY*X-MP:*:*:*)
|
||||
echo xmp-cray-unicos
|
||||
exit 0 ;;
|
||||
CRAY*Y-MP:*:*:*)
|
||||
echo ymp-cray-unicos${UNAME_RELEASE}
|
||||
exit 0 ;;
|
||||
CRAY*[A-Z]90:*:*:*)
|
||||
echo ${UNAME_MACHINE}-cray-unicos${UNAME_RELEASE} \
|
||||
| sed -e 's/CRAY.*\([A-Z]90\)/\1/' \
|
||||
-e y/ABCDEFGHIJKLMNOPQRSTUVWXYZ/abcdefghijklmnopqrstuvwxyz/
|
||||
exit 0 ;;
|
||||
CRAY*TS:*:*:*)
|
||||
echo t90-cray-unicos${UNAME_RELEASE}
|
||||
exit 0 ;;
|
||||
CRAY-2:*:*:*)
|
||||
echo cray2-cray-unicos
|
||||
exit 0 ;;
|
||||
F300:UNIX_System_V:*:*)
|
||||
FUJITSU_SYS=`uname -p | tr [A-Z] [a-z] | sed -e 's/\///'`
|
||||
FUJITSU_REL=`echo ${UNAME_RELEASE} | sed -e 's/ /_/'`
|
||||
echo "f300-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}"
|
||||
exit 0 ;;
|
||||
F301:UNIX_System_V:*:*)
|
||||
echo f301-fujitsu-uxpv`echo $UNAME_RELEASE | sed 's/ .*//'`
|
||||
exit 0 ;;
|
||||
hp3[0-9][05]:NetBSD:*:*)
|
||||
echo m68k-hp-netbsd${UNAME_RELEASE}
|
||||
exit 0 ;;
|
||||
hp300:OpenBSD:*:*)
|
||||
echo m68k-unknown-openbsd${UNAME_RELEASE}
|
||||
exit 0 ;;
|
||||
i?86:BSD/386:*:* | *:BSD/OS:*:*)
|
||||
echo ${UNAME_MACHINE}-pc-bsdi${UNAME_RELEASE}
|
||||
exit 0 ;;
|
||||
*:FreeBSD:*:*)
|
||||
echo ${UNAME_MACHINE}-unknown-freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'`
|
||||
exit 0 ;;
|
||||
*:NetBSD:*:*)
|
||||
echo ${UNAME_MACHINE}-unknown-netbsd`echo ${UNAME_RELEASE}|sed -e 's/[-_].*/\./'`
|
||||
exit 0 ;;
|
||||
*:OpenBSD:*:*)
|
||||
echo ${UNAME_MACHINE}-unknown-openbsd`echo ${UNAME_RELEASE}|sed -e 's/[-_].*/\./'`
|
||||
exit 0 ;;
|
||||
i*:CYGWIN*:*)
|
||||
echo i386-pc-cygwin32
|
||||
exit 0 ;;
|
||||
i*:MINGW*:*)
|
||||
echo i386-pc-mingw32
|
||||
exit 0 ;;
|
||||
p*:CYGWIN*:*)
|
||||
echo powerpcle-unknown-cygwin32
|
||||
exit 0 ;;
|
||||
prep*:SunOS:5.*:*)
|
||||
echo powerpcle-unknown-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
|
||||
exit 0 ;;
|
||||
*:GNU:*:*)
|
||||
echo `echo ${UNAME_MACHINE}|sed -e 's,[-/].*$,,'`-unknown-gnu`echo ${UNAME_RELEASE}|sed -e 's,/.*$,,'`
|
||||
exit 0 ;;
|
||||
*:Linux:*:*)
|
||||
# The BFD linker knows what the default object file format is, so
|
||||
# first see if it will tell us.
|
||||
ld_help_string=`ld --help 2>&1`
|
||||
ld_supported_emulations=`echo $ld_help_string \
|
||||
| sed -ne '/supported emulations:/!d
|
||||
s/[ ][ ]*/ /g
|
||||
s/.*supported emulations: *//
|
||||
s/ .*//
|
||||
p'`
|
||||
case "$ld_supported_emulations" in
|
||||
i?86linux) echo "${UNAME_MACHINE}-pc-linux-gnuaout" ; exit 0 ;;
|
||||
i?86coff) echo "${UNAME_MACHINE}-pc-linux-gnucoff" ; exit 0 ;;
|
||||
sparclinux) echo "${UNAME_MACHINE}-unknown-linux-gnuaout" ; exit 0 ;;
|
||||
m68klinux) echo "${UNAME_MACHINE}-unknown-linux-gnuaout" ; exit 0 ;;
|
||||
elf32ppc)
|
||||
# Determine Lib Version
|
||||
cat >dummy.c <<EOF
|
||||
#include <features.h>
|
||||
#if defined(__GLIBC__)
|
||||
extern char __libc_version[];
|
||||
extern char __libc_release[];
|
||||
#endif
|
||||
main(argc, argv)
|
||||
int argc;
|
||||
char *argv[];
|
||||
{
|
||||
#if defined(__GLIBC__)
|
||||
printf("%s %s\n", __libc_version, __libc_release);
|
||||
#else
|
||||
printf("unkown\n");
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
EOF
|
||||
LIBC=""
|
||||
${CC-cc} dummy.c -o dummy 2>/dev/null
|
||||
if test "$?" = 0 ; then
|
||||
./dummy | grep 1\.99 > /dev/null
|
||||
if test "$?" = 0 ; then
|
||||
LIBC="libc1"
|
||||
fi
|
||||
fi
|
||||
rm -f dummy.c dummy
|
||||
echo powerpc-unknown-linux-gnu${LIBC} ; exit 0 ;;
|
||||
esac
|
||||
|
||||
if test "${UNAME_MACHINE}" = "alpha" ; then
|
||||
sed 's/^ //' <<EOF >dummy.s
|
||||
.globl main
|
||||
.ent main
|
||||
main:
|
||||
.frame \$30,0,\$26,0
|
||||
.prologue 0
|
||||
.long 0x47e03d80 # implver $0
|
||||
lda \$2,259
|
||||
.long 0x47e20c21 # amask $2,$1
|
||||
srl \$1,8,\$2
|
||||
sll \$2,2,\$2
|
||||
sll \$0,3,\$0
|
||||
addl \$1,\$0,\$0
|
||||
addl \$2,\$0,\$0
|
||||
ret \$31,(\$26),1
|
||||
.end main
|
||||
EOF
|
||||
LIBC=""
|
||||
${CC-cc} dummy.s -o dummy 2>/dev/null
|
||||
if test "$?" = 0 ; then
|
||||
./dummy
|
||||
case "$?" in
|
||||
7)
|
||||
UNAME_MACHINE="alpha"
|
||||
;;
|
||||
15)
|
||||
UNAME_MACHINE="alphaev5"
|
||||
;;
|
||||
14)
|
||||
UNAME_MACHINE="alphaev56"
|
||||
;;
|
||||
10)
|
||||
UNAME_MACHINE="alphapca56"
|
||||
;;
|
||||
16)
|
||||
UNAME_MACHINE="alphaev6"
|
||||
;;
|
||||
esac
|
||||
|
||||
objdump --private-headers dummy | \
|
||||
grep ld.so.1 > /dev/null
|
||||
if test "$?" = 0 ; then
|
||||
LIBC="libc1"
|
||||
fi
|
||||
fi
|
||||
rm -f dummy.s dummy
|
||||
echo ${UNAME_MACHINE}-unknown-linux-gnu${LIBC} ; exit 0
|
||||
elif test "${UNAME_MACHINE}" = "mips" ; then
|
||||
cat >dummy.c <<EOF
|
||||
main(argc, argv)
|
||||
int argc;
|
||||
char *argv[];
|
||||
{
|
||||
#ifdef __MIPSEB__
|
||||
printf ("%s-unknown-linux-gnu\n", argv[1]);
|
||||
#endif
|
||||
#ifdef __MIPSEL__
|
||||
printf ("%sel-unknown-linux-gnu\n", argv[1]);
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
EOF
|
||||
${CC-cc} dummy.c -o dummy 2>/dev/null && ./dummy "${UNAME_MACHINE}" && rm dummy.c dummy && exit 0
|
||||
rm -f dummy.c dummy
|
||||
else
|
||||
# Either a pre-BFD a.out linker (linux-gnuoldld)
|
||||
# or one that does not give us useful --help.
|
||||
# GCC wants to distinguish between linux-gnuoldld and linux-gnuaout.
|
||||
# If ld does not provide *any* "supported emulations:"
|
||||
# that means it is gnuoldld.
|
||||
echo "$ld_help_string" | grep >/dev/null 2>&1 "supported emulations:"
|
||||
test $? != 0 && echo "${UNAME_MACHINE}-pc-linux-gnuoldld" && exit 0
|
||||
|
||||
case "${UNAME_MACHINE}" in
|
||||
i?86)
|
||||
VENDOR=pc;
|
||||
;;
|
||||
*)
|
||||
VENDOR=unknown;
|
||||
;;
|
||||
esac
|
||||
# Determine whether the default compiler is a.out or elf
|
||||
cat >dummy.c <<EOF
|
||||
#include <features.h>
|
||||
main(argc, argv)
|
||||
int argc;
|
||||
char *argv[];
|
||||
{
|
||||
#ifdef __ELF__
|
||||
# ifdef __GLIBC__
|
||||
# if __GLIBC__ >= 2
|
||||
printf ("%s-${VENDOR}-linux-gnu\n", argv[1]);
|
||||
# else
|
||||
printf ("%s-${VENDOR}-linux-gnulibc1\n", argv[1]);
|
||||
# endif
|
||||
# else
|
||||
printf ("%s-${VENDOR}-linux-gnulibc1\n", argv[1]);
|
||||
# endif
|
||||
#else
|
||||
printf ("%s-${VENDOR}-linux-gnuaout\n", argv[1]);
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
EOF
|
||||
${CC-cc} dummy.c -o dummy 2>/dev/null && ./dummy "${UNAME_MACHINE}" && rm dummy.c dummy && exit 0
|
||||
rm -f dummy.c dummy
|
||||
fi ;;
|
||||
# ptx 4.0 does uname -s correctly, with DYNIX/ptx in there. earlier versions
|
||||
# are messed up and put the nodename in both sysname and nodename.
|
||||
i?86:DYNIX/ptx:4*:*)
|
||||
echo i386-sequent-sysv4
|
||||
exit 0 ;;
|
||||
i?86:UNIX_SV:4.2MP:2.*)
|
||||
# Unixware is an offshoot of SVR4, but it has its own version
|
||||
# number series starting with 2...
|
||||
# I am not positive that other SVR4 systems won't match this,
|
||||
# I just have to hope. -- rms.
|
||||
# Use sysv4.2uw... so that sysv4* matches it.
|
||||
echo ${UNAME_MACHINE}-pc-sysv4.2uw${UNAME_VERSION}
|
||||
exit 0 ;;
|
||||
i?86:*:4.*:* | i?86:SYSTEM_V:4.*:*)
|
||||
if grep Novell /usr/include/link.h >/dev/null 2>/dev/null; then
|
||||
echo ${UNAME_MACHINE}-univel-sysv${UNAME_RELEASE}
|
||||
else
|
||||
echo ${UNAME_MACHINE}-pc-sysv${UNAME_RELEASE}
|
||||
fi
|
||||
exit 0 ;;
|
||||
i?86:*:3.2:*)
|
||||
if test -f /usr/options/cb.name; then
|
||||
UNAME_REL=`sed -n 's/.*Version //p' </usr/options/cb.name`
|
||||
echo ${UNAME_MACHINE}-pc-isc$UNAME_REL
|
||||
elif /bin/uname -X 2>/dev/null >/dev/null ; then
|
||||
UNAME_REL=`(/bin/uname -X|egrep Release|sed -e 's/.*= //')`
|
||||
(/bin/uname -X|egrep i80486 >/dev/null) && UNAME_MACHINE=i486
|
||||
(/bin/uname -X|egrep '^Machine.*Pentium' >/dev/null) \
|
||||
&& UNAME_MACHINE=i586
|
||||
echo ${UNAME_MACHINE}-pc-sco$UNAME_REL
|
||||
else
|
||||
echo ${UNAME_MACHINE}-pc-sysv32
|
||||
fi
|
||||
exit 0 ;;
|
||||
pc:*:*:*)
|
||||
# uname -m prints for DJGPP always 'pc', but it prints nothing about
|
||||
# the processor, so we play safe by assuming i386.
|
||||
echo i386-pc-msdosdjgpp
|
||||
exit 0 ;;
|
||||
Intel:Mach:3*:*)
|
||||
echo i386-pc-mach3
|
||||
exit 0 ;;
|
||||
paragon:*:*:*)
|
||||
echo i860-intel-osf1
|
||||
exit 0 ;;
|
||||
i860:*:4.*:*) # i860-SVR4
|
||||
if grep Stardent /usr/include/sys/uadmin.h >/dev/null 2>&1 ; then
|
||||
echo i860-stardent-sysv${UNAME_RELEASE} # Stardent Vistra i860-SVR4
|
||||
else # Add other i860-SVR4 vendors below as they are discovered.
|
||||
echo i860-unknown-sysv${UNAME_RELEASE} # Unknown i860-SVR4
|
||||
fi
|
||||
exit 0 ;;
|
||||
mini*:CTIX:SYS*5:*)
|
||||
# "miniframe"
|
||||
echo m68010-convergent-sysv
|
||||
exit 0 ;;
|
||||
M68*:*:R3V[567]*:*)
|
||||
test -r /sysV68 && echo 'm68k-motorola-sysv' && exit 0 ;;
|
||||
3[34]??:*:4.0:3.0 | 3[34]??,*:*:4.0:3.0 | 4850:*:4.0:3.0)
|
||||
OS_REL=''
|
||||
test -r /etc/.relid \
|
||||
&& OS_REL=.`sed -n 's/[^ ]* [^ ]* \([0-9][0-9]\).*/\1/p' < /etc/.relid`
|
||||
/bin/uname -p 2>/dev/null | grep 86 >/dev/null \
|
||||
&& echo i486-ncr-sysv4.3${OS_REL} && exit 0
|
||||
/bin/uname -p 2>/dev/null | /bin/grep entium >/dev/null \
|
||||
&& echo i586-ncr-sysv4.3${OS_REL} && exit 0 ;;
|
||||
3[34]??:*:4.0:* | 3[34]??,*:*:4.0:*)
|
||||
/bin/uname -p 2>/dev/null | grep 86 >/dev/null \
|
||||
&& echo i486-ncr-sysv4 && exit 0 ;;
|
||||
m68*:LynxOS:2.*:*)
|
||||
echo m68k-unknown-lynxos${UNAME_RELEASE}
|
||||
exit 0 ;;
|
||||
mc68030:UNIX_System_V:4.*:*)
|
||||
echo m68k-atari-sysv4
|
||||
exit 0 ;;
|
||||
i?86:LynxOS:2.*:*)
|
||||
echo i386-unknown-lynxos${UNAME_RELEASE}
|
||||
exit 0 ;;
|
||||
TSUNAMI:LynxOS:2.*:*)
|
||||
echo sparc-unknown-lynxos${UNAME_RELEASE}
|
||||
exit 0 ;;
|
||||
rs6000:LynxOS:2.*:* | PowerPC:LynxOS:2.*:*)
|
||||
echo rs6000-unknown-lynxos${UNAME_RELEASE}
|
||||
exit 0 ;;
|
||||
SM[BE]S:UNIX_SV:*:*)
|
||||
echo mips-dde-sysv${UNAME_RELEASE}
|
||||
exit 0 ;;
|
||||
RM*:SINIX-*:*:*)
|
||||
echo mips-sni-sysv4
|
||||
exit 0 ;;
|
||||
*:SINIX-*:*:*)
|
||||
if uname -p 2>/dev/null >/dev/null ; then
|
||||
UNAME_MACHINE=`(uname -p) 2>/dev/null`
|
||||
echo ${UNAME_MACHINE}-sni-sysv4
|
||||
else
|
||||
echo ns32k-sni-sysv
|
||||
fi
|
||||
exit 0 ;;
|
||||
PENTIUM:CPunix:4.0*:*) # Unisys `ClearPath HMP IX 4000' SVR4/MP effort
|
||||
# says <[email protected]>
|
||||
echo i586-unisys-sysv4
|
||||
exit 0 ;;
|
||||
*:UNIX_System_V:4*:FTX*)
|
||||
# From Gerald Hewes <[email protected]>.
|
||||
# How about differentiating between stratus architectures? -djm
|
||||
echo hppa1.1-stratus-sysv4
|
||||
exit 0 ;;
|
||||
*:*:*:FTX*)
|
||||
# From [email protected].
|
||||
echo i860-stratus-sysv4
|
||||
exit 0 ;;
|
||||
mc68*:A/UX:*:*)
|
||||
echo m68k-apple-aux${UNAME_RELEASE}
|
||||
exit 0 ;;
|
||||
news*:NEWS-OS:*:6*)
|
||||
echo mips-sony-newsos6
|
||||
exit 0 ;;
|
||||
R3000:*System_V*:*:* | R4000:UNIX_SYSV:*:*)
|
||||
if [ -d /usr/nec ]; then
|
||||
echo mips-nec-sysv${UNAME_RELEASE}
|
||||
else
|
||||
echo mips-unknown-sysv${UNAME_RELEASE}
|
||||
fi
|
||||
exit 0 ;;
|
||||
esac
|
||||
|
||||
#echo '(No uname command or uname output not recognized.)' 1>&2
|
||||
#echo "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" 1>&2
|
||||
|
||||
cat >dummy.c <<EOF
|
||||
#ifdef _SEQUENT_
|
||||
# include <sys/types.h>
|
||||
# include <sys/utsname.h>
|
||||
#endif
|
||||
main ()
|
||||
{
|
||||
#if defined (sony)
|
||||
#if defined (MIPSEB)
|
||||
/* BFD wants "bsd" instead of "newsos". Perhaps BFD should be changed,
|
||||
I don't know.... */
|
||||
printf ("mips-sony-bsd\n"); exit (0);
|
||||
#else
|
||||
#include <sys/param.h>
|
||||
printf ("m68k-sony-newsos%s\n",
|
||||
#ifdef NEWSOS4
|
||||
"4"
|
||||
#else
|
||||
""
|
||||
#endif
|
||||
); exit (0);
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if defined (__arm) && defined (__acorn) && defined (__unix)
|
||||
printf ("arm-acorn-riscix"); exit (0);
|
||||
#endif
|
||||
|
||||
#if defined (hp300) && !defined (hpux)
|
||||
printf ("m68k-hp-bsd\n"); exit (0);
|
||||
#endif
|
||||
|
||||
#if defined (NeXT)
|
||||
#if !defined (__ARCHITECTURE__)
|
||||
#define __ARCHITECTURE__ "m68k"
|
||||
#endif
|
||||
int version;
|
||||
version=`(hostinfo | sed -n 's/.*NeXT Mach \([0-9]*\).*/\1/p') 2>/dev/null`;
|
||||
printf ("%s-next-nextstep%d\n", __ARCHITECTURE__, version);
|
||||
exit (0);
|
||||
#endif
|
||||
|
||||
#if defined (MULTIMAX) || defined (n16)
|
||||
#if defined (UMAXV)
|
||||
printf ("ns32k-encore-sysv\n"); exit (0);
|
||||
#else
|
||||
#if defined (CMU)
|
||||
printf ("ns32k-encore-mach\n"); exit (0);
|
||||
#else
|
||||
printf ("ns32k-encore-bsd\n"); exit (0);
|
||||
#endif
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if defined (__386BSD__)
|
||||
printf ("i386-pc-bsd\n"); exit (0);
|
||||
#endif
|
||||
|
||||
#if defined (sequent)
|
||||
#if defined (i386)
|
||||
printf ("i386-sequent-dynix\n"); exit (0);
|
||||
#endif
|
||||
#if defined (ns32000)
|
||||
printf ("ns32k-sequent-dynix\n"); exit (0);
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if defined (_SEQUENT_)
|
||||
struct utsname un;
|
||||
|
||||
uname(&un);
|
||||
|
||||
if (strncmp(un.version, "V2", 2) == 0) {
|
||||
printf ("i386-sequent-ptx2\n"); exit (0);
|
||||
}
|
||||
if (strncmp(un.version, "V1", 2) == 0) { /* XXX is V1 correct? */
|
||||
printf ("i386-sequent-ptx1\n"); exit (0);
|
||||
}
|
||||
printf ("i386-sequent-ptx\n"); exit (0);
|
||||
|
||||
#endif
|
||||
|
||||
#if defined (vax)
|
||||
#if !defined (ultrix)
|
||||
printf ("vax-dec-bsd\n"); exit (0);
|
||||
#else
|
||||
printf ("vax-dec-ultrix\n"); exit (0);
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if defined (alliant) && defined (i860)
|
||||
printf ("i860-alliant-bsd\n"); exit (0);
|
||||
#endif
|
||||
|
||||
exit (1);
|
||||
}
|
||||
EOF
|
||||
|
||||
${CC-cc} dummy.c -o dummy 2>/dev/null && ./dummy && rm dummy.c dummy && exit 0
|
||||
rm -f dummy.c dummy
|
||||
|
||||
# Apollos put the system type in the environment.
|
||||
|
||||
test -d /usr/apollo && { echo ${ISP}-apollo-${SYSTYPE}; exit 0; }
|
||||
|
||||
# Convex versions that predate uname can use getsysinfo(1)
|
||||
|
||||
if [ -x /usr/convex/getsysinfo ]
|
||||
then
|
||||
case `getsysinfo -f cpu_type` in
|
||||
c1*)
|
||||
echo c1-convex-bsd
|
||||
exit 0 ;;
|
||||
c2*)
|
||||
if getsysinfo -f scalar_acc
|
||||
then echo c32-convex-bsd
|
||||
else echo c2-convex-bsd
|
||||
fi
|
||||
exit 0 ;;
|
||||
c34*)
|
||||
echo c34-convex-bsd
|
||||
exit 0 ;;
|
||||
c38*)
|
||||
echo c38-convex-bsd
|
||||
exit 0 ;;
|
||||
c4*)
|
||||
echo c4-convex-bsd
|
||||
exit 0 ;;
|
||||
esac
|
||||
fi
|
||||
|
||||
#echo '(Unable to guess system type)' 1>&2
|
||||
|
||||
exit 1
|
||||
+1178
File diff suppressed because it is too large
Load Diff
@@ -4,6 +4,8 @@ AC_INIT(netlist.h)
|
||||
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)
|
||||
|
||||
+145
-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.48 1999/10/07 05:25:33 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
|
||||
@@ -153,12 +181,25 @@ void NetBUFZ::dump_node(ostream&o, unsigned ind) const
|
||||
dump_node_pins(o, ind+4);
|
||||
}
|
||||
|
||||
void NetCaseCmp::dump_node(ostream&o, unsigned ind) const
|
||||
{
|
||||
o << setw(ind) << "" << "case compare === : " << name() << endl;
|
||||
dump_node_pins(o, ind+4);
|
||||
}
|
||||
|
||||
void NetConst::dump_node(ostream&o, unsigned ind) const
|
||||
{
|
||||
o << setw(ind) << "" << "constant " << value_ << ": " << name() << endl;
|
||||
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: ";
|
||||
@@ -202,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;
|
||||
@@ -282,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);
|
||||
}
|
||||
@@ -413,10 +468,13 @@ void NetCase::dump(ostream&o, unsigned ind) const
|
||||
switch (type_) {
|
||||
case EQ:
|
||||
o << setw(ind) << "" << "case (" << *expr_ << ")" << endl;
|
||||
break;
|
||||
case EQX:
|
||||
o << setw(ind) << "" << "casex (" << *expr_ << ")" << endl;
|
||||
break;
|
||||
case EQZ:
|
||||
o << setw(ind) << "" << "casez (" << *expr_ << ")" << endl;
|
||||
break;
|
||||
}
|
||||
|
||||
for (unsigned idx = 0 ; idx < nitems_ ; idx += 1) {
|
||||
@@ -523,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_;
|
||||
@@ -649,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();
|
||||
@@ -674,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
|
||||
@@ -717,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;
|
||||
@@ -786,6 +866,59 @@ 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.
|
||||
*
|
||||
* Revision 1.49 1999/10/08 02:00:35 steve
|
||||
* Fix dump of sase statements.
|
||||
*
|
||||
* Revision 1.48 1999/10/07 05:25:33 steve
|
||||
* Add non-const bit select in l-value of assignment.
|
||||
*
|
||||
|
||||
@@ -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,25 +17,22 @@
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
|
||||
*/
|
||||
#if !defined(WINNT)
|
||||
#ident "$Id: vvm_monitor.cc,v 1.2 1999/08/15 01:23:56 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;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* $Log: vvm_monitor.cc,v $
|
||||
* 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.
|
||||
*
|
||||
*/
|
||||
|
||||
+45
-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.6 1999/09/30 02:43:02 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,12 +261,18 @@ 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;
|
||||
des->errors += 1;
|
||||
return 0;
|
||||
}
|
||||
assert(msb_ != 0);
|
||||
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;
|
||||
@@ -277,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;
|
||||
@@ -318,6 +332,25 @@ 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.
|
||||
*
|
||||
* Revision 1.6 1999/09/30 02:43:02 steve
|
||||
* Elaborate ~^ and ~| operators.
|
||||
*
|
||||
|
||||
+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.
|
||||
*
|
||||
*/
|
||||
|
||||
+181
-842
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.23 1999/09/22 16:57:23 steve Exp $"
|
||||
#ident "$Id: emit.cc,v 1.31 1999/11/28 23:42:02 steve Exp $"
|
||||
#endif
|
||||
|
||||
/*
|
||||
@@ -60,11 +60,41 @@ void NetAssignNB::emit_node(ostream&o, struct target_t*tgt) const
|
||||
tgt->net_assign_nb(o, this);
|
||||
}
|
||||
|
||||
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);
|
||||
@@ -225,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_;
|
||||
@@ -309,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);
|
||||
@@ -319,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);
|
||||
@@ -352,6 +389,42 @@ bool emit(ostream&o, const Design*des, const char*type)
|
||||
|
||||
/*
|
||||
* $Log: emit.cc,v $
|
||||
* Revision 1.31 1999/11/28 23:42:02 steve
|
||||
* NetESignal object no longer need to be NetNode
|
||||
* objects. Let them keep a pointer to NetNet objects.
|
||||
*
|
||||
* Revision 1.30 1999/11/27 19:07:57 steve
|
||||
* Support the creation of scopes.
|
||||
*
|
||||
* Revision 1.29 1999/11/21 00:13:08 steve
|
||||
* Support memories in continuous assignments.
|
||||
*
|
||||
* Revision 1.28 1999/11/14 23:43:45 steve
|
||||
* Support combinatorial comparators.
|
||||
*
|
||||
* Revision 1.27 1999/11/14 20:24:28 steve
|
||||
* Add support for the LPM_CLSHIFT device.
|
||||
*
|
||||
* Revision 1.26 1999/11/04 03:53:26 steve
|
||||
* Patch to synthesize unary ~ and the ternary operator.
|
||||
* Thanks to Larry Doolittle <[email protected]>.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* Revision 1.23 1999/09/22 16:57:23 steve
|
||||
* Catch parallel blocks in vvm emit.
|
||||
*
|
||||
|
||||
@@ -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.8 1999/09/20 02:21:10 steve Exp $"
|
||||
#ident "$Id: eval.cc,v 1.12 1999/11/30 04:48:17 steve Exp $"
|
||||
#endif
|
||||
|
||||
# include "PExpr.h"
|
||||
@@ -41,12 +41,46 @@ verinum* PEBinary::eval_const(const Design*des, const string&path) const
|
||||
verinum*res;
|
||||
|
||||
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;
|
||||
@@ -62,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;
|
||||
@@ -84,14 +119,42 @@ 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.
|
||||
*
|
||||
* Revision 1.8 1999/09/20 02:21:10 steve
|
||||
* Elaborate parameters in phases.
|
||||
*
|
||||
|
||||
+41
-9
@@ -17,7 +17,7 @@
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
|
||||
*/
|
||||
#if !defined(WINNT)
|
||||
#ident "$Id: eval_tree.cc,v 1.4 1999/09/23 03:56:57 steve Exp $"
|
||||
#ident "$Id: eval_tree.cc,v 1.6 1999/10/22 23:57:53 steve Exp $"
|
||||
#endif
|
||||
|
||||
# include "netlist.h"
|
||||
@@ -26,8 +26,8 @@ NetExpr* NetExpr::eval_tree()
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
/*
|
||||
|
||||
/*
|
||||
* Some of the derived classes can be evaluated by the compiler, this
|
||||
* method provides the common aid of evaluating the parameter
|
||||
* expressions.
|
||||
@@ -46,8 +46,33 @@ void NetEBinary::eval_sub_tree_()
|
||||
}
|
||||
}
|
||||
|
||||
NetEConst* NetEBAdd::eval_tree()
|
||||
{
|
||||
eval_sub_tree_();
|
||||
NetEConst*lc = dynamic_cast<NetEConst*>(left_);
|
||||
if (lc == 0) return 0;
|
||||
NetEConst*rc = dynamic_cast<NetEConst*>(right_);
|
||||
if (rc == 0) return 0;
|
||||
|
||||
NetExpr* NetEBComp::eval_eqeq_()
|
||||
verinum lval = lc->value();
|
||||
verinum rval = rc->value();
|
||||
|
||||
verinum val;
|
||||
switch (op_) {
|
||||
case '+':
|
||||
val = lval + rval;
|
||||
break;
|
||||
case '-':
|
||||
val = lval - rval;
|
||||
break;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
|
||||
return new NetEConst(val);
|
||||
}
|
||||
|
||||
NetEConst* NetEBComp::eval_eqeq_()
|
||||
{
|
||||
NetEConst*l = dynamic_cast<NetEConst*>(left_);
|
||||
if (l == 0) return 0;
|
||||
@@ -70,7 +95,7 @@ NetExpr* NetEBComp::eval_eqeq_()
|
||||
}
|
||||
|
||||
|
||||
NetExpr* NetEBComp::eval_leeq_()
|
||||
NetEConst* NetEBComp::eval_leeq_()
|
||||
{
|
||||
NetEConst*r = dynamic_cast<NetEConst*>(right_);
|
||||
if (r == 0) return 0;
|
||||
@@ -80,8 +105,9 @@ NetExpr* NetEBComp::eval_leeq_()
|
||||
/* Detect the case where the right side is greater that or
|
||||
equal to the largest value the left side can possibly
|
||||
have. */
|
||||
unsigned long lv = (1 << left_->expr_width()) - 1;
|
||||
if (lv <= rv.as_ulong()) {
|
||||
assert(left_->expr_width() > 0);
|
||||
verinum lv (verinum::V1, left_->expr_width());
|
||||
if (lv <= rv) {
|
||||
verinum result(verinum::V1, 1);
|
||||
return new NetEConst(result);
|
||||
}
|
||||
@@ -90,7 +116,7 @@ NetExpr* NetEBComp::eval_leeq_()
|
||||
}
|
||||
|
||||
|
||||
NetExpr* NetEBComp::eval_tree()
|
||||
NetEConst* NetEBComp::eval_tree()
|
||||
{
|
||||
eval_sub_tree_();
|
||||
|
||||
@@ -106,7 +132,7 @@ NetExpr* NetEBComp::eval_tree()
|
||||
}
|
||||
}
|
||||
|
||||
NetExpr* NetEBLogic::eval_tree()
|
||||
NetEConst* NetEBLogic::eval_tree()
|
||||
{
|
||||
eval_sub_tree_();
|
||||
return 0;
|
||||
@@ -116,7 +142,7 @@ NetExpr* NetEBLogic::eval_tree()
|
||||
* Evaluate the shift operator if possible. For this to work, both
|
||||
* operands must be constant.
|
||||
*/
|
||||
NetExpr* NetEBShift::eval_tree()
|
||||
NetEConst* NetEBShift::eval_tree()
|
||||
{
|
||||
eval_sub_tree_();
|
||||
NetEConst*re = dynamic_cast<NetEConst*>(right_);
|
||||
@@ -236,6 +262,12 @@ NetExpr* NetEParam::eval_tree()
|
||||
|
||||
/*
|
||||
* $Log: eval_tree.cc,v $
|
||||
* Revision 1.6 1999/10/22 23:57:53 steve
|
||||
* do the <= in bits, not numbers.
|
||||
*
|
||||
* Revision 1.5 1999/10/10 23:29:37 steve
|
||||
* Support evaluating + operator at compile time.
|
||||
*
|
||||
* Revision 1.4 1999/09/23 03:56:57 steve
|
||||
* Support shift operators.
|
||||
*
|
||||
|
||||
+242
@@ -0,0 +1,242 @@
|
||||
/*
|
||||
* 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: 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 <[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/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.
|
||||
*
|
||||
|
||||
+6
-5
@@ -18,7 +18,7 @@
|
||||
# 59 Temple Place - Suite 330
|
||||
# Boston, MA 02111-1307, USA
|
||||
#
|
||||
#ident "$Id: Makefile.in,v 1.5 1999/07/30 00:42:33 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,13 +61,13 @@ 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 $(includedir) $(bindir)
|
||||
$(srcdir)/../mkinstalldirs $(bindir)
|
||||
|
||||
uninstall:
|
||||
rm -f $(bindir)/ivlpp
|
||||
|
||||
+6
-4
@@ -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.13 1999/09/16 00:49:05 steve Exp $"
|
||||
#ident "$Id: lexor.lex,v 1.14 1999/10/08 17:27:56 steve Exp $"
|
||||
#endif
|
||||
|
||||
# include <stdio.h>
|
||||
@@ -467,7 +467,8 @@ static void do_include()
|
||||
yy_switch_to_buffer(yy_new_buffer(istack->file, YY_BUF_SIZE));
|
||||
|
||||
if (line_direct_flag && istack->path)
|
||||
fprintf(yyout, "#line \"%s\" %u\n", istack->path, istack->lineno);
|
||||
fprintf(yyout, "\n#line \"%s\" %u\n",
|
||||
istack->path, istack->lineno);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -519,7 +520,7 @@ static int yywrap()
|
||||
}
|
||||
|
||||
if (line_direct_flag)
|
||||
fprintf(yyout, "#line \"%s\" 0\n", istack->path);
|
||||
fprintf(yyout, "\n#line \"%s\" 0\n", istack->path);
|
||||
|
||||
yyrestart(isp->file);
|
||||
return 0;
|
||||
@@ -532,7 +533,8 @@ static int yywrap()
|
||||
yy_switch_to_buffer(istack->yybs);
|
||||
|
||||
if (line_direct_flag && istack->path && !line_mask_flag)
|
||||
fprintf(yyout, "#line \"%s\" %u\n", istack->path, istack->lineno);
|
||||
fprintf(yyout, "\n#line \"%s\" %u\n",
|
||||
istack->path, istack->lineno);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
+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.
|
||||
*
|
||||
|
||||
+1079
-149
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.78 1999/10/07 05:25:34 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; }
|
||||
|
||||
@@ -398,16 +621,39 @@ class NetExpr : public LineInfo {
|
||||
NetExpr& operator=(const NetExpr&);
|
||||
};
|
||||
|
||||
/*
|
||||
* The expression constant is slightly special, and is sometimes
|
||||
* returned from other classes that can be evaluated at compile
|
||||
* time. This class represents constant values in expressions.
|
||||
*/
|
||||
class NetEConst : public NetExpr {
|
||||
|
||||
public:
|
||||
explicit NetEConst(const verinum&val);
|
||||
~NetEConst();
|
||||
|
||||
const verinum&value() const { return value_; }
|
||||
|
||||
virtual bool set_width(unsigned w);
|
||||
virtual void expr_scan(struct expr_scan_t*) const;
|
||||
virtual void dump(ostream&) const;
|
||||
|
||||
virtual NetEConst* dup_expr() const;
|
||||
virtual NetNet*synthesize(Design*);
|
||||
|
||||
private:
|
||||
verinum value_;
|
||||
};
|
||||
|
||||
/*
|
||||
* 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);
|
||||
|
||||
};
|
||||
|
||||
@@ -421,21 +667,40 @@ 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;
|
||||
};
|
||||
|
||||
/*
|
||||
* This node is used to represent case equality in combinational
|
||||
* logic. Although this is not normally synthesizeable, it makes sense
|
||||
* to support an abstract gate that can compare x and z.
|
||||
*
|
||||
* This pins are assigned as:
|
||||
*
|
||||
* 0 -- Output (always returns 0 or 1)
|
||||
* 1 -- Input
|
||||
* 2 -- Input
|
||||
*/
|
||||
class NetCaseCmp : public NetNode {
|
||||
|
||||
public:
|
||||
explicit NetCaseCmp(const string&n);
|
||||
~NetCaseCmp();
|
||||
|
||||
virtual void dump_node(ostream&, unsigned ind) const;
|
||||
virtual void emit_node(ostream&, struct target_t*) const;
|
||||
};
|
||||
|
||||
|
||||
class NetConst : public NetNode {
|
||||
|
||||
public:
|
||||
explicit NetConst(const string&n, verinum::V v)
|
||||
: NetNode(n, 1), value_(v) { pin(0).set_dir(Link::OUTPUT); }
|
||||
explicit NetConst(const string&n, verinum::V v);
|
||||
~NetConst();
|
||||
|
||||
verinum::V value() const { return value_; }
|
||||
|
||||
@@ -478,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
|
||||
@@ -507,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
|
||||
@@ -514,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 {
|
||||
|
||||
@@ -545,7 +810,7 @@ class NetUDP : public NetNode {
|
||||
bool is_sequential() const { return sequential_; }
|
||||
|
||||
private:
|
||||
const bool sequential_;
|
||||
bool sequential_;
|
||||
char init_;
|
||||
|
||||
struct state_t_;
|
||||
@@ -572,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;
|
||||
};
|
||||
@@ -593,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:
|
||||
@@ -648,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;
|
||||
|
||||
@@ -810,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:
|
||||
@@ -903,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;
|
||||
|
||||
@@ -1197,6 +1474,9 @@ class NetEBAdd : public NetEBinary {
|
||||
~NetEBAdd();
|
||||
|
||||
virtual bool set_width(unsigned w);
|
||||
virtual NetEBAdd* dup_expr() const;
|
||||
virtual NetEConst* eval_tree();
|
||||
virtual NetNet* synthesize(Design*);
|
||||
};
|
||||
|
||||
/*
|
||||
@@ -1220,6 +1500,9 @@ class NetEBBits : public NetEBinary {
|
||||
~NetEBBits();
|
||||
|
||||
virtual bool set_width(unsigned w);
|
||||
virtual NetEBBits* dup_expr() const;
|
||||
|
||||
virtual NetNet* synthesize(Design*);
|
||||
};
|
||||
|
||||
/*
|
||||
@@ -1243,11 +1526,12 @@ class NetEBComp : public NetEBinary {
|
||||
~NetEBComp();
|
||||
|
||||
virtual bool set_width(unsigned w);
|
||||
virtual NetExpr* eval_tree();
|
||||
virtual NetEBComp* dup_expr() const;
|
||||
virtual NetEConst* eval_tree();
|
||||
|
||||
private:
|
||||
NetExpr*eval_eqeq_();
|
||||
NetExpr*eval_leeq_();
|
||||
NetEConst*eval_eqeq_();
|
||||
NetEConst*eval_leeq_();
|
||||
|
||||
};
|
||||
|
||||
@@ -1264,7 +1548,8 @@ class NetEBLogic : public NetEBinary {
|
||||
~NetEBLogic();
|
||||
|
||||
virtual bool set_width(unsigned w);
|
||||
virtual NetExpr* eval_tree();
|
||||
virtual NetEBLogic* dup_expr() const;
|
||||
virtual NetEConst* eval_tree();
|
||||
|
||||
private:
|
||||
};
|
||||
@@ -1284,7 +1569,8 @@ class NetEBShift : public NetEBinary {
|
||||
~NetEBShift();
|
||||
|
||||
virtual bool set_width(unsigned w);
|
||||
virtual NetExpr* eval_tree();
|
||||
virtual NetEBShift* dup_expr() const;
|
||||
virtual NetEConst* eval_tree();
|
||||
|
||||
private:
|
||||
};
|
||||
@@ -1323,24 +1609,6 @@ class NetEConcat : public NetExpr {
|
||||
unsigned repeat_;
|
||||
};
|
||||
|
||||
class NetEConst : public NetExpr {
|
||||
|
||||
public:
|
||||
explicit NetEConst(const verinum&val);
|
||||
~NetEConst();
|
||||
|
||||
const verinum&value() const { return value_; }
|
||||
|
||||
virtual bool set_width(unsigned w);
|
||||
virtual void expr_scan(struct expr_scan_t*) const;
|
||||
virtual void dump(ostream&) const;
|
||||
|
||||
virtual NetEConst* dup_expr() const;
|
||||
|
||||
private:
|
||||
verinum value_;
|
||||
};
|
||||
|
||||
/*
|
||||
* This clas is a placeholder for a parameter expression. When
|
||||
* parameters are first created, an instance of this object is used to
|
||||
@@ -1369,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
|
||||
@@ -1423,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_;
|
||||
@@ -1441,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 {
|
||||
|
||||
@@ -1461,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 {
|
||||
|
||||
@@ -1516,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_;
|
||||
};
|
||||
|
||||
/*
|
||||
@@ -1567,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.
|
||||
@@ -1574,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
|
||||
@@ -1587,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*);
|
||||
@@ -1599,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*);
|
||||
@@ -1638,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_;
|
||||
@@ -1698,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. */
|
||||
@@ -1711,6 +2051,91 @@ 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.
|
||||
*
|
||||
* Revision 1.79 1999/10/10 01:59:55 steve
|
||||
* Structural case equals device.
|
||||
*
|
||||
* Revision 1.78 1999/10/07 05:25:34 steve
|
||||
* Add non-const bit select in l-value of assignment.
|
||||
*
|
||||
|
||||
+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.73 1999/09/30 02:43:02 steve Exp $"
|
||||
#ident "$Id: parse.y,v 1.76 1999/11/15 04:43:52 steve Exp $"
|
||||
#endif
|
||||
|
||||
# include "parse_misc.h"
|
||||
@@ -164,6 +164,9 @@ extern void lex_end_table();
|
||||
|
||||
%%
|
||||
|
||||
/* A degenerate source file can be completely empty. */
|
||||
main : source_file | ;
|
||||
|
||||
source_file
|
||||
: description
|
||||
| source_file description
|
||||
@@ -333,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.");
|
||||
@@ -854,8 +874,7 @@ identifier
|
||||
: IDENTIFIER
|
||||
{ $$ = $1; }
|
||||
| HIDENTIFIER
|
||||
{ yyerror(@1, "sorry: qualified identifiers not supported.");
|
||||
$$ = $1;
|
||||
{ $$ = $1;
|
||||
}
|
||||
;
|
||||
|
||||
@@ -1058,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.
|
||||
*
|
||||
|
||||
+7
-1
@@ -17,7 +17,7 @@
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
|
||||
*/
|
||||
#if !defined(WINNT)
|
||||
#ident "$Id: pform_dump.cc,v 1.44 1999/09/30 02:43:02 steve Exp $"
|
||||
#ident "$Id: pform_dump.cc,v 1.45 1999/10/10 01:59:55 steve Exp $"
|
||||
#endif
|
||||
|
||||
/*
|
||||
@@ -132,6 +132,9 @@ void PEBinary::dump(ostream&out) const
|
||||
{
|
||||
out << "(" << *left_ << ")";
|
||||
switch (op_) {
|
||||
case 'a':
|
||||
out << "&&";
|
||||
break;
|
||||
case 'e':
|
||||
out << "==";
|
||||
break;
|
||||
@@ -672,6 +675,9 @@ void PUdp::dump(ostream&out) const
|
||||
|
||||
/*
|
||||
* $Log: pform_dump.cc,v $
|
||||
* Revision 1.45 1999/10/10 01:59:55 steve
|
||||
* Structural case equals device.
|
||||
*
|
||||
* Revision 1.44 1999/09/30 02:43:02 steve
|
||||
* Elaborate ~^ and ~| operators.
|
||||
*
|
||||
|
||||
+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-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.20 1999/09/22 16:57:24 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*)
|
||||
{
|
||||
}
|
||||
@@ -85,19 +119,18 @@ void target_t::net_assign_nb(ostream&os, const NetAssignNB*)
|
||||
"Unhandled non-blocking assignment node." << endl;
|
||||
}
|
||||
|
||||
void target_t::net_case_cmp(ostream&os, const NetCaseCmp*)
|
||||
{
|
||||
cerr << "target (" << typeid(*this).name() << "): "
|
||||
"Unhandled case compare node." << endl;
|
||||
}
|
||||
|
||||
void target_t::net_const(ostream&os, const NetConst*)
|
||||
{
|
||||
cerr << "target (" << typeid(*this).name() << "): "
|
||||
"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() << "): "
|
||||
@@ -231,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() << "): "
|
||||
@@ -269,6 +308,42 @@ 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.
|
||||
*
|
||||
* Revision 1.20 1999/09/22 16:57:24 steve
|
||||
* Catch parallel blocks in vvm emit.
|
||||
*
|
||||
|
||||
@@ -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.19 1999/09/22 16:57:24 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*);
|
||||
@@ -74,8 +83,8 @@ struct target_t {
|
||||
virtual void udp(ostream&os, const NetUDP*);
|
||||
virtual void net_assign(ostream&os, const NetAssign*);
|
||||
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
|
||||
@@ -111,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*);
|
||||
@@ -136,6 +146,42 @@ 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.
|
||||
*
|
||||
* Revision 1.19 1999/09/22 16:57:24 steve
|
||||
* Catch parallel blocks in vvm emit.
|
||||
*
|
||||
|
||||
+32
-18
@@ -17,42 +17,48 @@
|
||||
# along with this program; if not, write to the Free Software
|
||||
# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
|
||||
# Added support for the -t flag, for odd-ball target types. <[email protected]>
|
||||
# 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=/usr/bin/g++
|
||||
|
||||
vvmTarget="-t vvm"
|
||||
xnfTarget="-t xnf"
|
||||
execCpp=@CXX@
|
||||
|
||||
tmpDir=/tmp
|
||||
tmpPPFile=${tmpDir}/ivl$$.pp
|
||||
tmpCCFile=${tmpDir}/ivl$$.cc
|
||||
|
||||
VPIModulePath=@libdir@/ivl:.
|
||||
includedir=@includedir@
|
||||
libdir=@libdir@
|
||||
VPIModulePath=@libdir@/ivl
|
||||
|
||||
target=${vvmTarget}
|
||||
target="vvm"
|
||||
targetSuffix=""
|
||||
functors=""
|
||||
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
|
||||
parameter=`getopt D:I:Xxo:s: "$@"`
|
||||
parameter=`getopt D:I:Xxf:o:s:t: "$@"`
|
||||
eval set -- "${parameter}"
|
||||
while true ; do
|
||||
|
||||
case "$1" in
|
||||
-D) extDefines="${extDefines} -D$2" ; shift 2 ;;
|
||||
-I) extIncPath="${extIncPath} -I $2" ; shift 2 ;;
|
||||
-X) targetSuffix=".xnf" ; target=${xnfTarget} ; shift ;;
|
||||
-X) target="xnf" ; shift ;;
|
||||
-f) flags="$flags -f$2" ; shift 2 ;;
|
||||
-o) outputFile=$2 ; shift 2 ;;
|
||||
-s) topModule="-s $2 " ; shift 2 ;;
|
||||
-t) target="$2" ; shift 2 ;;
|
||||
-x) execute="true"; shift ;;
|
||||
--) shift ; break ;;
|
||||
*) echo "Internal error! Arg is $1 " ; exit 1 ;;
|
||||
@@ -69,6 +75,14 @@ if test -z "${verilogFile}" ; then
|
||||
exit 1;
|
||||
fi
|
||||
|
||||
# Choose a target file suffix based on the target type.
|
||||
case "$target" in
|
||||
vvm) targetSuffix="" ;;
|
||||
xnf) targetSuffix=".xnf"
|
||||
functors="-Fxnfsyn -Fsigfold -Fxnfio" ;;
|
||||
*) targetSuffix=".$target" ;;
|
||||
esac
|
||||
|
||||
|
||||
# If no output file is given should we guess one or...?
|
||||
# Assumes a few silly things if several files are given
|
||||
@@ -87,7 +101,7 @@ fi
|
||||
|
||||
|
||||
# Compile preprocessed verilog file
|
||||
${execIVL} ${target} -o ${tmpCCFile} ${topModule} ${tmpPPFile}
|
||||
${execIVL} -t ${target} -o ${tmpCCFile} ${topModule} ${functors} ${flags} ${tmpPPFile}
|
||||
if test $? -ne 0 ; then
|
||||
echo "Verilog compilation failed. Terminating compilation."
|
||||
rm -f ${tmpCCFile}
|
||||
@@ -96,19 +110,19 @@ fi
|
||||
rm -f ${tmpPPFile}
|
||||
|
||||
|
||||
case "${targetSuffix}" in
|
||||
case "${target}" in
|
||||
|
||||
.xnf) mv ${tmpCCFile} ${outputFile} ;;
|
||||
"xnf") mv ${tmpCCFile} ${outputFile} ;;
|
||||
|
||||
"") ${execCpp} -rdynamic ${tmpCCFile} -o ${outputFile} -lvvm -ldl ;
|
||||
if test $? -ne 0 ; then
|
||||
"vvm") ${execCpp} -rdynamic -I${includedir} -L${libdir} ${tmpCCFile} -o ${outputFile} -lvvm -ldl ;
|
||||
if test $? -ne 0 ; then
|
||||
echo "C++ compilation failed. Terminating compilation."
|
||||
rm -f ${tmpCCFile}
|
||||
exit 1
|
||||
fi
|
||||
rm -f ${tmpCCFile} ;;
|
||||
fi
|
||||
rm -f ${tmpCCFile} ;;
|
||||
|
||||
*) echo "Internal error in target compilation." ; exit 1
|
||||
*) mv ${tmpCCFile} ${outputFile} ;;
|
||||
|
||||
esac
|
||||
|
||||
|
||||
+171
-5
@@ -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.9 1999/07/20 05:12:22 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) {
|
||||
@@ -296,20 +308,174 @@ ostream& operator<< (ostream&o, const verinum&v)
|
||||
return o;
|
||||
}
|
||||
|
||||
bool operator == (const verinum&left, const verinum&right)
|
||||
verinum::V operator == (const verinum&left, const verinum&right)
|
||||
{
|
||||
if (left.len() != right.len())
|
||||
return false;
|
||||
return verinum::V0;
|
||||
|
||||
for (unsigned idx = 0 ; idx < left.len() ; idx += 1)
|
||||
if (left[idx] != right[idx])
|
||||
return false;
|
||||
return verinum::V0;
|
||||
|
||||
return true;
|
||||
return verinum::V1;
|
||||
}
|
||||
|
||||
verinum::V operator <= (const verinum&left, const verinum&right)
|
||||
{
|
||||
unsigned idx;
|
||||
for (idx = left.len() ; idx > right.len() ; idx -= 1) {
|
||||
if (left[idx-1] != verinum::V0) return verinum::V0;
|
||||
}
|
||||
|
||||
for (idx = right.len() ; idx > left.len() ; idx -= 1) {
|
||||
if (right[idx-1] != verinum::V0) return verinum::V0;
|
||||
}
|
||||
|
||||
while (idx > 0) {
|
||||
if (left[idx-1] == verinum::Vx) return verinum::Vx;
|
||||
if (left[idx-1] == verinum::Vz) return verinum::Vx;
|
||||
if (right[idx-1] == verinum::Vx) return verinum::Vx;
|
||||
if (right[idx-1] == verinum::Vz) return verinum::Vx;
|
||||
if (left[idx-1] > right[idx-1]) return verinum::V0;
|
||||
idx -= 1;
|
||||
}
|
||||
|
||||
return verinum::V1;
|
||||
}
|
||||
|
||||
static verinum::V add_with_carry(verinum::V l, verinum::V r, verinum::V&c)
|
||||
{
|
||||
unsigned sum = 0;
|
||||
switch (c) {
|
||||
case verinum::Vx:
|
||||
case verinum::Vz:
|
||||
c = verinum::Vx;
|
||||
return verinum::Vx;
|
||||
case verinum::V0:
|
||||
break;
|
||||
case verinum::V1:
|
||||
sum += 1;
|
||||
}
|
||||
|
||||
switch (l) {
|
||||
case verinum::Vx:
|
||||
case verinum::Vz:
|
||||
c = verinum::Vx;
|
||||
return verinum::Vx;
|
||||
case verinum::V0:
|
||||
break;
|
||||
case verinum::V1:
|
||||
sum += 1;
|
||||
break;
|
||||
}
|
||||
|
||||
switch (r) {
|
||||
case verinum::Vx:
|
||||
case verinum::Vz:
|
||||
c = verinum::Vx;
|
||||
return verinum::Vx;
|
||||
case verinum::V0:
|
||||
break;
|
||||
case verinum::V1:
|
||||
sum += 1;
|
||||
break;
|
||||
}
|
||||
|
||||
if (sum & 2)
|
||||
c = verinum::V1;
|
||||
else
|
||||
c = verinum::V0;
|
||||
if (sum & 1)
|
||||
return verinum::V1;
|
||||
else
|
||||
return verinum::V0;
|
||||
}
|
||||
|
||||
verinum not(const verinum&left)
|
||||
{
|
||||
verinum val = left;
|
||||
for (unsigned idx = 0 ; idx < val.len() ; idx += 1)
|
||||
switch (val[idx]) {
|
||||
case verinum::V0:
|
||||
val.set(idx, verinum::V1);
|
||||
break;
|
||||
case verinum::V1:
|
||||
val.set(idx, verinum::V0);
|
||||
break;
|
||||
default:
|
||||
val.set(idx, verinum::Vx);
|
||||
break;
|
||||
}
|
||||
|
||||
return val;
|
||||
}
|
||||
|
||||
/*
|
||||
* Addition works a bit at a time, from the least significant up to
|
||||
* the most significant.
|
||||
*/
|
||||
verinum operator + (const verinum&left, const verinum&right)
|
||||
{
|
||||
unsigned min = left.len();
|
||||
if (right.len() < min) min = right.len();
|
||||
|
||||
unsigned max = left.len();
|
||||
if (right.len() > max) max = right.len();
|
||||
|
||||
verinum val (verinum::V0, max);
|
||||
|
||||
verinum::V carry = verinum::V0;
|
||||
for (unsigned idx = 0 ; idx < min ; idx += 1)
|
||||
val.set(idx, add_with_carry(left[idx], right[idx], carry));
|
||||
|
||||
if (left.len() > right.len()) {
|
||||
for (unsigned idx = min ; idx < max ; idx += 1)
|
||||
val.set(idx,add_with_carry(left[idx], verinum::V0, carry));
|
||||
} else {
|
||||
for (unsigned idx = min ; idx < max ; idx += 1)
|
||||
val.set(idx, add_with_carry(verinum::V0, right[idx], carry));
|
||||
}
|
||||
|
||||
return val;
|
||||
}
|
||||
|
||||
verinum operator - (const verinum&left, const verinum&r)
|
||||
{
|
||||
verinum right = not(r);
|
||||
unsigned min = left.len();
|
||||
if (right.len() < min) min = right.len();
|
||||
|
||||
unsigned max = left.len();
|
||||
if (right.len() > max) max = right.len();
|
||||
|
||||
verinum val (verinum::V0, max);
|
||||
|
||||
verinum::V carry = verinum::V1;
|
||||
for (unsigned idx = 0 ; idx < min ; idx += 1)
|
||||
val.set(idx, add_with_carry(left[idx], right[idx], carry));
|
||||
|
||||
if (left.len() > right.len()) {
|
||||
for (unsigned idx = min ; idx < max ; idx += 1)
|
||||
val.set(idx,add_with_carry(left[idx], verinum::V0, carry));
|
||||
} else {
|
||||
for (unsigned idx = min ; idx < max ; idx += 1)
|
||||
val.set(idx, add_with_carry(verinum::V0, right[idx], carry));
|
||||
}
|
||||
|
||||
return val;
|
||||
}
|
||||
|
||||
/*
|
||||
* $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.
|
||||
*
|
||||
* Revision 1.10 1999/10/10 23:29:37 steve
|
||||
* Support evaluating + operator at compile time.
|
||||
*
|
||||
* Revision 1.9 1999/07/20 05:12:22 steve
|
||||
* Implement the set method.
|
||||
*
|
||||
|
||||
@@ -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.5 1999/05/13 04:02:09 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;
|
||||
@@ -90,10 +93,22 @@ class ostream;
|
||||
extern ostream& operator<< (ostream&, const verinum&);
|
||||
extern ostream& operator<< (ostream&, verinum::V);
|
||||
|
||||
extern bool operator == (const verinum&left, const verinum&right);
|
||||
extern verinum::V operator == (const verinum&left, const verinum&right);
|
||||
extern verinum::V operator <= (const verinum&left, const verinum&right);
|
||||
extern verinum operator + (const verinum&left, const verinum&right);
|
||||
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.
|
||||
*
|
||||
* Revision 1.6 1999/10/10 23:29:37 steve
|
||||
* Support evaluating + operator at compile time.
|
||||
*
|
||||
* Revision 1.5 1999/05/13 04:02:09 steve
|
||||
* More precise handling of verinum bit lengths.
|
||||
*
|
||||
|
||||
+4
-4
@@ -18,7 +18,7 @@
|
||||
# 59 Temple Place - Suite 330
|
||||
# Boston, MA 02111-1307, USA
|
||||
#
|
||||
#ident "$Id: Makefile.in,v 1.4 1999/08/31 23:00:08 steve Exp $"
|
||||
#ident "$Id: Makefile.in,v 1.7 1999/11/07 20:33:30 steve Exp $"
|
||||
#
|
||||
#
|
||||
SHELL = /bin/sh
|
||||
@@ -41,7 +41,7 @@ INSTALL = @INSTALL@
|
||||
INSTALL_PROGRAM = @INSTALL_PROGRAM@
|
||||
INSTALL_DATA = @INSTALL_DATA@
|
||||
|
||||
CPPFLAGS = @CPPFLAGS@ @DEFS@
|
||||
CPPFLAGS = @CPPFLAGS@ @DEFS@ -fpic
|
||||
CXXFLAGS = @CXXFLAGS@
|
||||
LDFLAGS = @LDFLAGS@
|
||||
|
||||
@@ -49,10 +49,10 @@ all: system.vpi
|
||||
|
||||
%.o dep/%.d: %.c
|
||||
@[ -d dep ] || mkdir dep
|
||||
$(CC) -Wall $(CPPFLAGS) -MD -c $< -o $*.o
|
||||
$(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
|
||||
|
||||
+270
-62
@@ -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.2 1999/09/29 01:41:18 steve Exp $"
|
||||
#ident "$Id: sys_display.c,v 1.9 1999/11/07 02:25:07 steve Exp $"
|
||||
#endif
|
||||
|
||||
# include "vpi_user.h"
|
||||
@@ -26,46 +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_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));
|
||||
}
|
||||
|
||||
/*
|
||||
* If $display discovers a string as a parameter, this function is
|
||||
@@ -73,11 +55,16 @@ static void format_m(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, "%\\");
|
||||
@@ -101,23 +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':
|
||||
value.format = vpiOctStrVal;
|
||||
vpi_get_value(argv[idx++], &value);
|
||||
vpi_printf("%s", value.value.str);
|
||||
cp += 1;
|
||||
break;
|
||||
case 't':
|
||||
case 'T':
|
||||
value.format = vpiDecStrVal;
|
||||
vpi_get_value(argv[idx++], &value);
|
||||
vpi_printf("%s", value.value.str);
|
||||
cp += 1;
|
||||
break;
|
||||
case '%':
|
||||
@@ -146,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)) {
|
||||
|
||||
@@ -165,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;
|
||||
|
||||
@@ -197,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");
|
||||
@@ -204,6 +225,153 @@ 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)
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
cb.reason = cbReadOnlySynch;
|
||||
cb.cb_rtn = strobe_cb;
|
||||
cb.time = &time;
|
||||
cb.obj = 0;
|
||||
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;
|
||||
@@ -223,11 +391,51 @@ void sys_display_register()
|
||||
tf_data.sizetf = 0;
|
||||
tf_data.user_data = "$write";
|
||||
vpi_register_systf(&tf_data);
|
||||
|
||||
tf_data.type = vpiSysTask;
|
||||
tf_data.tfname = "$strobe";
|
||||
tf_data.calltf = sys_strobe_calltf;
|
||||
tf_data.compiletf = 0;
|
||||
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
|
||||
* in C (to interface with VPI) and add VPI support
|
||||
* for callbacks.
|
||||
*
|
||||
* Revision 1.4 1999/10/10 14:50:50 steve
|
||||
* Add Octal dump format.
|
||||
*
|
||||
* Revision 1.3 1999/10/08 17:47:49 steve
|
||||
* Add the %t formatting escape.
|
||||
*
|
||||
* Revision 1.2 1999/09/29 01:41:18 steve
|
||||
* Support the $write system task, and have the
|
||||
* vpi_scan function free iterators as needed.
|
||||
|
||||
+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.
|
||||
*
|
||||
*/
|
||||
|
||||
+73
-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.3 1999/08/19 02:51:03 steve Exp $"
|
||||
#ident "$Id: vpi_user.h,v 1.9 1999/11/28 00:56:08 steve Exp $"
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
@@ -95,18 +95,27 @@ 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
|
||||
|
||||
/* PROPERTIES */
|
||||
#define vpiType 1
|
||||
#define vpiName 2
|
||||
#define vpiFullName 3
|
||||
#define vpiSize 4
|
||||
#define vpiConstType 43
|
||||
# define vpiDecConst 1
|
||||
# define vpiRealConst 2
|
||||
@@ -120,6 +129,47 @@ typedef struct t_vpi_value {
|
||||
extern void vpi_register_systf(const struct t_vpi_systf_data*ss);
|
||||
extern void vpi_printf(const char*fmt, ...);
|
||||
|
||||
/*
|
||||
* support for VPI callback functions.
|
||||
*/
|
||||
typedef struct t_cb_data {
|
||||
int reason;
|
||||
int (*cb_rtn)(struct t_cb_data*cb);
|
||||
vpiHandle obj;
|
||||
p_vpi_time time;
|
||||
p_vpi_value value;
|
||||
int index;
|
||||
char*user_data;
|
||||
} s_cb_data, *p_cb_data;
|
||||
|
||||
#define cbValueChange 1
|
||||
#define cbStmt 2
|
||||
#define cbForce 3
|
||||
#define cbRelease 4
|
||||
#define cbAtStartOfSimTime 5
|
||||
#define cbReadWriteSynch 6
|
||||
#define cbReadOnlySynch 7
|
||||
#define cbNextSimTime 8
|
||||
#define cbAfterDelay 9
|
||||
#define cbEndOfCompile 10
|
||||
#define cbStartOfSimulation 11
|
||||
#define cbEndOfSimulation 12
|
||||
#define cbError 13
|
||||
#define cbTchkViolation 14
|
||||
#define cbStartOfSave 15
|
||||
#define cbEndOfSave 16
|
||||
#define cbStartOfRestart 17
|
||||
#define cbEndOfRestart 18
|
||||
#define cbStartOfReset 19
|
||||
#define cbEndOfReset 20
|
||||
#define cbEnterInteractive 21
|
||||
#define cbExitInteractive 22
|
||||
#define cbInteractiveScopeChange 23
|
||||
#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
|
||||
* engine. The operation parameter specifies the function to
|
||||
@@ -161,6 +211,28 @@ 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
|
||||
* in C (to interface with VPI) and add VPI support
|
||||
* for callbacks.
|
||||
*
|
||||
* Revision 1.3 1999/08/19 02:51:03 steve
|
||||
* Add vpi_sim_control
|
||||
*
|
||||
|
||||
+20
-7
@@ -18,7 +18,7 @@
|
||||
# 59 Temple Place - Suite 330
|
||||
# Boston, MA 02111-1307, USA
|
||||
#
|
||||
#ident "$Id: Makefile.in,v 1.5 1999/08/28 02:10:57 steve Exp $"
|
||||
#ident "$Id: Makefile.in,v 1.14 1999/11/27 19:07:58 steve Exp $"
|
||||
#
|
||||
#
|
||||
SHELL = /bin/sh
|
||||
@@ -35,14 +35,15 @@ bindir = $(exec_prefix)/bin
|
||||
libdir = $(exec_prefix)/lib
|
||||
includedir = $(prefix)/include
|
||||
|
||||
CC = @CC@
|
||||
CXX = @CXX@ -I../vpi
|
||||
CC = @CC@ -I$(srcdir) -I$(srcdir)/../vpi
|
||||
CXX = @CXX@ -I$(srcdir) -I$(srcdir)/../vpi
|
||||
INSTALL = @INSTALL@
|
||||
INSTALL_PROGRAM = @INSTALL_PROGRAM@
|
||||
INSTALL_DATA = @INSTALL_DATA@
|
||||
|
||||
CPPFLAGS = @CPPFLAGS@ @DEFS@
|
||||
CXXFLAGS = @CXXFLAGS@
|
||||
CFLAGS = @CFLAGS@
|
||||
LDFLAGS = @LDFLAGS@
|
||||
|
||||
all: libvvm.a
|
||||
@@ -52,12 +53,24 @@ all: libvvm.a
|
||||
$(CXX) -Wall -fno-exceptions $(CXXFLAGS) -MD -c $< -o $*.o
|
||||
mv $*.d dep
|
||||
|
||||
O = vvm_bit.o vvm_calltf.o vvm_event.o vvm_monitor.o vvm_pevent.o \
|
||||
vvm_simulation.o vvm_thread.o
|
||||
%.o dep/%.d: %.c
|
||||
@[ -d dep ] || mkdir dep
|
||||
$(CC) -Wall $(CFLAGS) -MD -c $< -o $*.o
|
||||
mv $*.d dep
|
||||
|
||||
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_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 $@
|
||||
ar cvqf $@ $O
|
||||
ar cvq $@ $O
|
||||
|
||||
vpip.o: $P
|
||||
$(LD) -r -o vpip.o $P
|
||||
|
||||
clean:
|
||||
rm -f *.o dep/*.d
|
||||
@@ -92,7 +105,7 @@ $(includedir)/vpi_priv.h: $(srcdir)/vpi_priv.h
|
||||
$(INSTALL_DATA) $(srcdir)/vpi_priv.h $(includedir)/vpi_priv.h
|
||||
|
||||
installdirs: mkinstalldirs
|
||||
$(srcdir)/mkinstalldirs $(includedir) $(bindir)
|
||||
$(srcdir)/mkinstalldirs $(includedir) $(libdir)
|
||||
|
||||
uninstall:
|
||||
rm -f $(libdir)/libvvm.a
|
||||
|
||||
@@ -0,0 +1,188 @@
|
||||
/*
|
||||
* 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_callback.c,v 1.4 1999/11/07 20:33:30 steve Exp $"
|
||||
#endif
|
||||
|
||||
# include "vpi_priv.h"
|
||||
# include <stdlib.h>
|
||||
# include <assert.h>
|
||||
|
||||
static struct __vpirt vpip_callback_rt = {
|
||||
vpiCallback,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
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);
|
||||
}
|
||||
|
||||
/*
|
||||
* 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)
|
||||
{
|
||||
struct __vpiCallback*rfp = calloc(1, sizeof(struct __vpiCallback));
|
||||
rfp->base.vpi_type = &vpip_callback_rt;
|
||||
rfp->cb_data = *data;
|
||||
|
||||
switch (data->reason) {
|
||||
case cbReadOnlySynch:
|
||||
go_readonly_synch(rfp);
|
||||
break;
|
||||
|
||||
case cbValueChange:
|
||||
go_value_change(rfp);
|
||||
break;
|
||||
|
||||
default:
|
||||
assert(0);
|
||||
}
|
||||
|
||||
return &(rfp->base);
|
||||
}
|
||||
|
||||
|
||||
int vpi_remove_cb(vpiHandle ref)
|
||||
{
|
||||
struct __vpiCallback*rfp = (struct __vpiCallback*)ref;
|
||||
assert(ref->vpi_type->type_code == vpiCallback);
|
||||
|
||||
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
|
||||
* in C (to interface with VPI) and add VPI support
|
||||
* for callbacks.
|
||||
*
|
||||
*/
|
||||
|
||||
+336
@@ -0,0 +1,336 @@
|
||||
/*
|
||||
* 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_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;
|
||||
assert(ref->vpi_type->type_code == vpiConstant);
|
||||
|
||||
switch (vp->format) {
|
||||
case vpiObjTypeVal:
|
||||
case vpiStringVal:
|
||||
vp->value.str = rfp->value;
|
||||
vp->format = vpiStringVal;
|
||||
break;
|
||||
|
||||
default:
|
||||
vp->format = vpiSuppressVal;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
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,
|
||||
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;
|
||||
ref->value = 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
|
||||
* in C (to interface with VPI) and add VPI support
|
||||
* for callbacks.
|
||||
*
|
||||
*/
|
||||
|
||||
@@ -0,0 +1,77 @@
|
||||
/*
|
||||
* 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_iter.c,v 1.1 1999/10/28 00:47:25 steve Exp $"
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Find here the methods functions in support of iterator objects.
|
||||
*/
|
||||
|
||||
# include "vpi_priv.h"
|
||||
# include <stdlib.h>
|
||||
# include <assert.h>
|
||||
|
||||
static const struct __vpirt vpip_iterator_rt = {
|
||||
vpiIterator,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0
|
||||
};
|
||||
|
||||
vpiHandle vpip_make_iterator(unsigned nargs, vpiHandle*args)
|
||||
{
|
||||
struct __vpiIterator*res = calloc(1, sizeof(struct __vpiIterator));
|
||||
res->base.vpi_type = &vpip_iterator_rt;
|
||||
res->args = args;
|
||||
res->nargs = nargs;
|
||||
res->next = 0;
|
||||
|
||||
return &(res->base);
|
||||
}
|
||||
|
||||
/*
|
||||
* The vpi_scan function only applies to iterators. It returns the
|
||||
* next vpiHandle in the iterated list.
|
||||
*/
|
||||
vpiHandle vpi_scan(vpiHandle ref)
|
||||
{
|
||||
struct __vpiIterator*hp = (struct __vpiIterator*)ref;
|
||||
assert(ref->vpi_type->type_code == vpiIterator);
|
||||
|
||||
if (hp->next == hp->nargs) {
|
||||
vpi_free_object(ref);
|
||||
return 0;
|
||||
}
|
||||
|
||||
return hp->args[hp->next++];
|
||||
}
|
||||
|
||||
/*
|
||||
* $Log: vpi_iter.c,v $
|
||||
* Revision 1.1 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.
|
||||
*
|
||||
*/
|
||||
|
||||
@@ -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.
|
||||
*
|
||||
*/
|
||||
|
||||
@@ -0,0 +1,47 @@
|
||||
/*
|
||||
* 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_null.c,v 1.1 1999/10/28 00:47:25 steve Exp $"
|
||||
#endif
|
||||
|
||||
# include "vpi_priv.h"
|
||||
|
||||
static const struct __vpirt vpip_null_rt = {
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0
|
||||
};
|
||||
|
||||
struct __vpiNull vpip_null = {
|
||||
{ &vpip_null_rt }
|
||||
};
|
||||
|
||||
/*
|
||||
* $Log: vpi_null.c,v $
|
||||
* Revision 1.1 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.
|
||||
*
|
||||
*/
|
||||
|
||||
+160
@@ -0,0 +1,160 @@
|
||||
/*
|
||||
* 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_priv.c,v 1.1 1999/10/28 00:47:25 steve Exp $"
|
||||
#endif
|
||||
|
||||
# include "vpi_priv.h"
|
||||
# include <assert.h>
|
||||
# include <stdarg.h>
|
||||
# include <stdio.h>
|
||||
# include <stdlib.h>
|
||||
# include <string.h>
|
||||
|
||||
/*
|
||||
* Keep a list of vpi_systf_data structures. This list is searched
|
||||
* forward whenever a function is invoked by name, and items are
|
||||
* pushed in front of the list whenever they are registered. This
|
||||
* allows entries to override older entries.
|
||||
*/
|
||||
struct systf_entry {
|
||||
struct systf_entry* next;
|
||||
s_vpi_systf_data systf_data;
|
||||
};
|
||||
|
||||
static struct systf_entry*systf_list = 0;
|
||||
|
||||
/* This is the handle of the task currently being called. */
|
||||
static struct __vpiSysTaskCall*vpip_cur_task;
|
||||
|
||||
|
||||
void vpip_calltask(const char*fname, unsigned nparms, vpiHandle*parms)
|
||||
{
|
||||
struct systf_entry*idx;
|
||||
struct __vpiSysTaskCall cur_task;
|
||||
cur_task.base.vpi_type = &vpip_systask_rt;
|
||||
cur_task.args = parms;
|
||||
cur_task.nargs = nparms;
|
||||
|
||||
vpip_cur_task = &cur_task;
|
||||
|
||||
/* Look for a systf function to invoke. */
|
||||
for (idx = systf_list ; idx ; idx = idx->next)
|
||||
if (strcmp(fname, idx->systf_data.tfname) == 0) {
|
||||
cur_task.info = &idx->systf_data;
|
||||
idx->systf_data.calltf(idx->systf_data.user_data);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
/* Finally, if nothing is found then something is not
|
||||
right. Print out the function name all the parameters
|
||||
passed, so that someone can deal with it. */
|
||||
vpi_printf("Call %s\n", fname);
|
||||
}
|
||||
|
||||
|
||||
int vpi_free_object(vpiHandle ref)
|
||||
{
|
||||
free(ref);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int vpi_get(int property, vpiHandle ref)
|
||||
{
|
||||
if (property == vpiType)
|
||||
return ref->vpi_type->type_code;
|
||||
|
||||
if (ref->vpi_type->vpi_get_ == 0)
|
||||
return -1;
|
||||
|
||||
return (ref->vpi_type->vpi_get_)(property, ref);
|
||||
}
|
||||
|
||||
char* vpi_get_str(int property, vpiHandle ref)
|
||||
{
|
||||
if (ref->vpi_type->vpi_get_str_ == 0)
|
||||
return 0;
|
||||
|
||||
return (ref->vpi_type->vpi_get_str_)(property, ref);
|
||||
}
|
||||
|
||||
void vpi_get_value(vpiHandle expr, s_vpi_value*vp)
|
||||
{
|
||||
if (expr->vpi_type->vpi_get_value_) {
|
||||
(expr->vpi_type->vpi_get_value_)(expr, vp);
|
||||
return;
|
||||
}
|
||||
|
||||
vp->format = vpiSuppressVal;
|
||||
}
|
||||
|
||||
vpiHandle vpi_handle(int type, vpiHandle ref)
|
||||
{
|
||||
if (type == vpiSysTfCall) {
|
||||
assert(ref == 0);
|
||||
return &vpip_cur_task->base;
|
||||
}
|
||||
|
||||
assert(ref->vpi_type->handle_);
|
||||
return (ref->vpi_type->handle_)(type, ref);
|
||||
}
|
||||
|
||||
/*
|
||||
* This function asks the object to return an iterator for
|
||||
* the specified reference. It is up to the iterate_ method to
|
||||
* allocate a properly formed iterator.
|
||||
*/
|
||||
vpiHandle vpi_iterate(int type, vpiHandle ref)
|
||||
{
|
||||
assert(ref->vpi_type->iterate_);
|
||||
return (ref->vpi_type->iterate_)(type, ref);
|
||||
}
|
||||
|
||||
void vpi_printf(const char*fmt, ...)
|
||||
{
|
||||
va_list ap;
|
||||
va_start(ap, fmt);
|
||||
vprintf(fmt, ap);
|
||||
va_end(ap);
|
||||
}
|
||||
|
||||
/*
|
||||
* This function adds the information that the user supplies to a list
|
||||
* that I keep.
|
||||
*/
|
||||
void vpi_register_systf(const struct t_vpi_systf_data*systf)
|
||||
{
|
||||
struct systf_entry*cur = calloc(1, sizeof(struct systf_entry));
|
||||
cur->systf_data = *systf;
|
||||
cur->systf_data.tfname = strdup(systf->tfname);
|
||||
cur->next = systf_list;
|
||||
systf_list = cur;
|
||||
}
|
||||
|
||||
/*
|
||||
* $Log: vpi_priv.c,v $
|
||||
* Revision 1.1 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.
|
||||
*
|
||||
*/
|
||||
|
||||
+254
-45
@@ -19,70 +19,254 @@
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
|
||||
*/
|
||||
#if !defined(WINNT)
|
||||
#ident "$Id: vpi_priv.h,v 1.1 1999/08/15 01:23:56 steve Exp $"
|
||||
#ident "$Id: vpi_priv.h,v 1.8 1999/11/28 00:56:08 steve Exp $"
|
||||
#endif
|
||||
|
||||
/*
|
||||
* This header file describes the "back side" of the VPI
|
||||
* interface. The product that offers the VPI interface uses types and
|
||||
* methods declared here to manage the VPI structures and provide the
|
||||
* needed behaviors.
|
||||
*/
|
||||
# include <vpi_user.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
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 is the most basic type in the vpi implementation. A handle can
|
||||
* exist to refer to most any of the supported vpi objects. The
|
||||
* interpretation of the parts depends in general on the type of the
|
||||
* object.
|
||||
* This structure is the very base of a vpiHandle. Every handle
|
||||
* structure starts with this structure, so that the library can
|
||||
* internally pass the derived types as pointers to one of these.
|
||||
*/
|
||||
struct __vpiHandle {
|
||||
int type;
|
||||
int subtype;
|
||||
const struct __vpirt *vpi_type;
|
||||
};
|
||||
|
||||
/* These are property values. */
|
||||
char*full_name;
|
||||
/*
|
||||
* Objects with this structure are used to represent a type of
|
||||
* vpiHandle. A specific object becomes of this type by holding a
|
||||
* pointer to an instance of this structure.
|
||||
*/
|
||||
struct __vpirt {
|
||||
int type_code;
|
||||
|
||||
/* This pointer is used for to-one references. */
|
||||
struct __vpiHandle*referent;
|
||||
/* These methods extract information from the handle. */
|
||||
int (*vpi_get_)(int, vpiHandle);
|
||||
char* (*vpi_get_str_)(int, vpiHandle);
|
||||
void (*vpi_get_value_)(vpiHandle, p_vpi_value);
|
||||
|
||||
/* This pointer table is used for to-many refrences to
|
||||
arguments, and is used by the vpiArgument iterator. */
|
||||
struct __vpiHandle**arguments;
|
||||
unsigned narguments;
|
||||
/* These methods follow references. */
|
||||
vpiHandle (*handle_)(int, vpiHandle);
|
||||
vpiHandle (*iterate_)(int, vpiHandle);
|
||||
};
|
||||
|
||||
/* These methods support the various vpi_get() functions. */
|
||||
int (*get_)(int property, vpiHandle ref);
|
||||
char* (*get_str_)(int property, vpiHandle ref);
|
||||
/*
|
||||
* This is a private handle type that doesn't seem to be well defined
|
||||
* by the VPI standard.
|
||||
*/
|
||||
struct __vpiCallback {
|
||||
struct __vpiHandle base;
|
||||
struct t_cb_data cb_data;
|
||||
|
||||
/* This method is used to get a value. */
|
||||
void (*get_value_)(struct __vpiHandle*expr, s_vpi_value*vp);
|
||||
struct vpip_event*ev;
|
||||
struct __vpiCallback*next;
|
||||
};
|
||||
|
||||
/* This is a value union, that reflect state or the value of a
|
||||
handle. */
|
||||
union {
|
||||
unsigned unum;
|
||||
struct vvm_bits_t*bits;
|
||||
struct t_vpi_time time;
|
||||
} val;
|
||||
/*
|
||||
* The vpiHandle for an iterator has this structure. The definition of
|
||||
* the methods lives in vpi_iter.c
|
||||
*/
|
||||
struct __vpiIterator {
|
||||
struct __vpiHandle base;
|
||||
|
||||
vpiHandle *args;
|
||||
unsigned nargs;
|
||||
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
|
||||
* array of bits that the environment provides. The bits must persist
|
||||
* as long as this object persists.
|
||||
*/
|
||||
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;
|
||||
};
|
||||
|
||||
|
||||
/* TYPE MEANINGS:
|
||||
*
|
||||
* vpiArgument
|
||||
* This type of handle contains a single referent, the item that has
|
||||
* many arguments. It is an iterator.
|
||||
*
|
||||
* vpiConstant
|
||||
* Constant values, such as strings and numbers, are this type.
|
||||
*
|
||||
* vpiSysTaskCall
|
||||
* This handle type represents a call to a system task. It has a
|
||||
* to-many reference to argument expressions, and a to-one reference
|
||||
* to a vpiUserSystf object.
|
||||
*
|
||||
* vpiTimeVar
|
||||
* This type is a special kind of variable, that holds a time. The
|
||||
* time value is a more complex structure then a single number. The
|
||||
* type really seems to exist to implement the $time system variable.
|
||||
extern const struct __vpirt vpip_systask_rt;
|
||||
struct __vpiSysTaskCall {
|
||||
struct __vpiHandle base;
|
||||
|
||||
s_vpi_systf_data*info;
|
||||
vpiHandle*args;
|
||||
unsigned nargs;
|
||||
|
||||
const char*file;
|
||||
unsigned lineno;
|
||||
int subtype;
|
||||
};
|
||||
|
||||
/*
|
||||
* Represent a TimeVar variable. The actual time is stored in the
|
||||
* "time" member for fast manipulation by various bits of the
|
||||
* simulation engine. The time_obj member is used as persistent
|
||||
* storage of the time value when get_value is used (on the opaque
|
||||
* handle) to the get time.
|
||||
*/
|
||||
struct __vpiTimeVar {
|
||||
struct __vpiHandle base;
|
||||
|
||||
const char*name;
|
||||
unsigned long time;
|
||||
struct t_vpi_time time_obj;
|
||||
};
|
||||
|
||||
|
||||
struct __vpiStringConst {
|
||||
struct __vpiHandle base;
|
||||
|
||||
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
|
||||
* to allocate the memory for the handle. The result is the vpiHandle
|
||||
* of the constructed object.
|
||||
*/
|
||||
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);
|
||||
|
||||
/* 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
|
||||
* simulation. There is a single global variable that is the
|
||||
* simulation.
|
||||
*/
|
||||
|
||||
struct vpip_simulation_cycle;
|
||||
struct vpip_event;
|
||||
struct vpip_simulation {
|
||||
/* Current simulation time. */
|
||||
struct __vpiTimeVar sim_time;
|
||||
|
||||
/* List of cbReadOnlySynch callbacks. */
|
||||
struct __vpiCallback*read_sync_list;
|
||||
|
||||
/* List of simulation cycles, starting with the next time. */
|
||||
struct vpip_simulation_cycle*sim;
|
||||
int going_flag;
|
||||
};
|
||||
|
||||
extern struct vpip_simulation vpip_simulation_obj;
|
||||
|
||||
extern void vpip_init_simulation();
|
||||
extern void vpip_simulation_run();
|
||||
|
||||
/*
|
||||
* Schedule an event to be run sometime in the future. The d parmater
|
||||
* is the delay in simulation units before the event is processed. If
|
||||
* the non-block flag is set, the event is scheduled to happen at the
|
||||
* end of the time step.
|
||||
*
|
||||
* The return value from the insert method is a cookie that can be
|
||||
* used to manipulate the event before it is executed.
|
||||
*/
|
||||
extern struct vpip_event* vpip_sim_insert_event(unsigned long d,
|
||||
void*user_data,
|
||||
void (*sim_fun)(void*),
|
||||
int nonblock_flag);
|
||||
extern void vpip_sim_cancel_event(struct vpip_event*cookie);
|
||||
|
||||
/*
|
||||
* This function returns a handle to the vpiTimeVar that is th main
|
||||
* simulation time clock.
|
||||
*/
|
||||
extern vpiHandle vpip_sim_time();
|
||||
|
||||
/*
|
||||
* Return true if the going_flag is false.
|
||||
*/
|
||||
extern int vpip_finished();
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
@@ -90,6 +274,31 @@ struct __vpiHandle {
|
||||
|
||||
/*
|
||||
* $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
|
||||
* in C (to interface with VPI) and add VPI support
|
||||
* for callbacks.
|
||||
*
|
||||
* Revision 1.1 1999/08/15 01:23:56 steve
|
||||
* Convert vvm to implement system tasks with vpi.
|
||||
*
|
||||
|
||||
@@ -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.
|
||||
*
|
||||
*/
|
||||
|
||||
@@ -0,0 +1,123 @@
|
||||
/*
|
||||
* 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_signal.c,v 1.5 1999/11/07 20:33:30 steve Exp $"
|
||||
#endif
|
||||
|
||||
# include "vpi_priv.h"
|
||||
# include <assert.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:
|
||||
return (char*)rfp->name;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void signal_get_value(vpiHandle ref, s_vpi_value*vp)
|
||||
{
|
||||
struct __vpiSignal*rfp = (struct __vpiSignal*)ref;
|
||||
assert((ref->vpi_type->type_code==vpiNet)
|
||||
|| (ref->vpi_type->type_code==vpiReg));
|
||||
|
||||
vpip_bits_get_value(rfp->bits, rfp->nbits, vp);
|
||||
}
|
||||
|
||||
static const struct __vpirt vpip_net_rt = {
|
||||
vpiNet,
|
||||
signal_get,
|
||||
signal_get_str,
|
||||
signal_get_value,
|
||||
0,
|
||||
0
|
||||
};
|
||||
|
||||
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,
|
||||
signal_get,
|
||||
signal_get_str,
|
||||
signal_get_value,
|
||||
0,
|
||||
0
|
||||
};
|
||||
|
||||
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
|
||||
* in C (to interface with VPI) and add VPI support
|
||||
* for callbacks.
|
||||
*
|
||||
*/
|
||||
|
||||
@@ -0,0 +1,205 @@
|
||||
/*
|
||||
* 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_simulation.c,v 1.1 1999/10/28 00:47:25 steve Exp $"
|
||||
#endif
|
||||
|
||||
# include "vpi_priv.h"
|
||||
# include <stdlib.h>
|
||||
# include <assert.h>
|
||||
|
||||
struct vpip_event {
|
||||
void*user_data;
|
||||
void (*sim_fun)(void*);
|
||||
struct vpip_event*next;
|
||||
};
|
||||
|
||||
struct vpip_simulation vpip_simulation_obj;
|
||||
|
||||
void vpi_sim_control(int func, ...)
|
||||
{
|
||||
switch (func) {
|
||||
case vpiFinish:
|
||||
vpip_simulation_obj.going_flag = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* The simulation event queue is a list of simulation cycles that in
|
||||
* turn contain lists of simulation events. The simulation cycle
|
||||
* represents the happening at some simulation time.
|
||||
*/
|
||||
struct vpip_simulation_cycle {
|
||||
unsigned long delay;
|
||||
|
||||
struct vpip_simulation_cycle*next;
|
||||
struct vpip_simulation_cycle*prev;
|
||||
|
||||
struct vpip_event*event_list;
|
||||
struct vpip_event*event_last;
|
||||
struct vpip_event*nonblock_list;
|
||||
struct vpip_event*nonblock_last;
|
||||
};
|
||||
|
||||
void vpip_init_simulation()
|
||||
{
|
||||
struct vpip_simulation_cycle*cur;
|
||||
|
||||
vpip_make_time_var(&vpip_simulation_obj.sim_time, "$time");
|
||||
vpip_simulation_obj.read_sync_list = 0;
|
||||
|
||||
/* Allocate a header cell for the simulation event list. */
|
||||
cur = calloc(1, sizeof(struct vpip_simulation_cycle));
|
||||
cur->delay = 0;
|
||||
cur->next = cur->prev = cur;
|
||||
vpip_simulation_obj.sim = cur;
|
||||
}
|
||||
|
||||
vpiHandle vpip_sim_time()
|
||||
{
|
||||
return &vpip_simulation_obj.sim_time.base;
|
||||
}
|
||||
|
||||
struct vpip_event* vpip_sim_insert_event(unsigned long delay,
|
||||
void*user_data,
|
||||
void (*sim_fun)(void*),
|
||||
int nonblock_flag)
|
||||
{
|
||||
struct vpip_event*event;
|
||||
struct vpip_simulation_cycle*cur;
|
||||
|
||||
event = calloc(1, sizeof(struct vpip_event));
|
||||
event->user_data = user_data;
|
||||
event->sim_fun = sim_fun;
|
||||
|
||||
cur = vpip_simulation_obj.sim->next;
|
||||
while ((cur != vpip_simulation_obj.sim) && (cur->delay < delay)) {
|
||||
delay -= cur->delay;
|
||||
cur = cur->next;
|
||||
}
|
||||
|
||||
/* If there is no cycle cell for the specified time, create one. */
|
||||
if ((cur == vpip_simulation_obj.sim) || (cur->delay > delay)) {
|
||||
struct vpip_simulation_cycle*cell
|
||||
= calloc(1,sizeof(struct vpip_simulation_cycle));
|
||||
cell->delay = delay;
|
||||
if (cur != vpip_simulation_obj.sim)
|
||||
cur->delay -= delay;
|
||||
cell->next = cur;
|
||||
cell->prev = cur->prev;
|
||||
cell->next->prev = cell;
|
||||
cell->prev->next = cell;
|
||||
cur = cell;
|
||||
}
|
||||
|
||||
/* Put the event into the end of the cycle list. */
|
||||
event->next = 0;
|
||||
if (nonblock_flag) {
|
||||
if (cur->nonblock_list == 0) {
|
||||
cur->nonblock_list = cur->nonblock_last = event;
|
||||
|
||||
} else {
|
||||
cur->nonblock_last->next = event;
|
||||
cur->nonblock_last = event;
|
||||
}
|
||||
} else {
|
||||
if (cur->event_list == 0) {
|
||||
cur->event_list = cur->event_last = event;
|
||||
|
||||
} else {
|
||||
cur->event_last->next = event;
|
||||
cur->event_last = event;
|
||||
}
|
||||
}
|
||||
|
||||
return event;
|
||||
}
|
||||
|
||||
void vpip_sim_cancel_event(struct vpip_event*ev)
|
||||
{
|
||||
assert(0);
|
||||
}
|
||||
|
||||
int vpip_finished()
|
||||
{
|
||||
return ! vpip_simulation_obj.going_flag;
|
||||
}
|
||||
|
||||
void vpip_simulation_run()
|
||||
{
|
||||
vpip_simulation_obj.sim_time.time = 0;
|
||||
vpip_simulation_obj.going_flag = !0;
|
||||
|
||||
while (vpip_simulation_obj.going_flag) {
|
||||
struct vpip_simulation_cycle*sim = vpip_simulation_obj.sim;
|
||||
|
||||
/* Step the time forward to the next time cycle. */
|
||||
vpip_simulation_obj.sim_time.time += sim->delay;
|
||||
sim->delay = 0;
|
||||
|
||||
while (vpip_simulation_obj.going_flag) {
|
||||
struct vpip_event*active = sim->event_list;
|
||||
sim->event_list = 0;
|
||||
sim->event_last = 0;
|
||||
|
||||
if (active == 0) {
|
||||
active = sim->nonblock_list;
|
||||
sim->nonblock_list = 0;
|
||||
sim->nonblock_last = 0;
|
||||
}
|
||||
|
||||
if (active == 0)
|
||||
break;
|
||||
|
||||
while (active && vpip_simulation_obj.going_flag) {
|
||||
struct vpip_event*cur = active;
|
||||
active = cur->next;
|
||||
(cur->sim_fun)(cur->user_data);
|
||||
free(cur);
|
||||
}
|
||||
}
|
||||
|
||||
if (! vpip_simulation_obj.going_flag)
|
||||
break;
|
||||
|
||||
{ struct vpip_simulation_cycle*next = sim->next;
|
||||
if (next == sim) {
|
||||
vpip_simulation_obj.going_flag = 0;
|
||||
break;
|
||||
}
|
||||
sim->next->prev = sim->prev;
|
||||
sim->prev->next = sim->next;
|
||||
free(sim);
|
||||
vpip_simulation_obj.sim = next;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* $Log: vpi_simulation.c,v $
|
||||
* Revision 1.1 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.
|
||||
*
|
||||
*/
|
||||
|
||||
@@ -0,0 +1,56 @@
|
||||
/*
|
||||
* 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_systask.c,v 1.1 1999/10/28 00:47:25 steve Exp $"
|
||||
#endif
|
||||
|
||||
# include "vpi_priv.h"
|
||||
# include <stdlib.h>
|
||||
# include <assert.h>
|
||||
|
||||
static vpiHandle systask_iter(int type, vpiHandle ref)
|
||||
{
|
||||
struct __vpiSysTaskCall*rfp = (struct __vpiSysTaskCall*)ref;
|
||||
assert(ref->vpi_type->type_code == vpiSysTaskCall);
|
||||
|
||||
if (rfp->nargs == 0)
|
||||
return 0;
|
||||
|
||||
return vpip_make_iterator(rfp->nargs, rfp->args);
|
||||
}
|
||||
|
||||
const struct __vpirt vpip_systask_rt = {
|
||||
vpiSysTaskCall,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
systask_iter
|
||||
};
|
||||
|
||||
/*
|
||||
* $Log: vpi_systask.c,v $
|
||||
* Revision 1.1 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.
|
||||
*
|
||||
*/
|
||||
|
||||
@@ -0,0 +1,84 @@
|
||||
/*
|
||||
* 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_time.c,v 1.1 1999/10/28 00:47:25 steve Exp $"
|
||||
#endif
|
||||
|
||||
# include "vpi_priv.h"
|
||||
# include <assert.h>
|
||||
# include <stdio.h>
|
||||
|
||||
/*
|
||||
* IEEE-1364 VPI pretty much mandates the existance of this sort of
|
||||
* thing. (Either this or a huge memory leak.) Sorry.
|
||||
*/
|
||||
static char buf_obj[128];
|
||||
|
||||
static void timevar_get_value(vpiHandle ref, s_vpi_value*vp)
|
||||
{
|
||||
struct __vpiTimeVar*rfp = (struct __vpiTimeVar*)ref;
|
||||
assert(ref->vpi_type->type_code == vpiTimeVar);
|
||||
|
||||
switch (vp->format) {
|
||||
case vpiObjTypeVal:
|
||||
case vpiTimeVal:
|
||||
rfp->time_obj.low = rfp->time;
|
||||
vp->value.time = &rfp->time_obj;
|
||||
vp->format = vpiTimeVal;
|
||||
break;
|
||||
|
||||
case vpiDecStrVal:
|
||||
sprintf(buf_obj, "%lu", rfp->time);
|
||||
vp->value.str = buf_obj;
|
||||
break;
|
||||
|
||||
default:
|
||||
vp->format = vpiSuppressVal;
|
||||
vp->value.str = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static const struct __vpirt vpip_time_var_rt = {
|
||||
vpiTimeVar,
|
||||
0,
|
||||
0,
|
||||
timevar_get_value,
|
||||
0,
|
||||
0
|
||||
};
|
||||
|
||||
vpiHandle vpip_make_time_var(struct __vpiTimeVar*ref, const char*val)
|
||||
{
|
||||
ref->base.vpi_type = &vpip_time_var_rt;
|
||||
ref->name = val;
|
||||
return &(ref->base);
|
||||
}
|
||||
|
||||
/*
|
||||
* $Log: vpi_time.c,v $
|
||||
* Revision 1.1 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.
|
||||
*
|
||||
*/
|
||||
|
||||
@@ -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,12 +19,11 @@
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
|
||||
*/
|
||||
#if !defined(WINNT)
|
||||
#ident "$Id: vvm.h,v 1.14 1999/10/06 01:28:18 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"
|
||||
|
||||
/*
|
||||
* The Verilog Virtual Machine are definitions for the virtual machine
|
||||
@@ -37,15 +36,10 @@ class vvm_event;
|
||||
class vvm_simulation;
|
||||
class vvm_simulation_cycle;
|
||||
class vvm_thread;
|
||||
|
||||
/* The vvm_bit_t is the basic unit of value for a scalar signal in
|
||||
Verilog. It represents all the possible values. The vvm_bitstring_t
|
||||
is a vector of vvm_bit_t and is used when variable-length bit
|
||||
arrays are needed. */
|
||||
enum vvm_bit_t { V0 = 0, V1, Vx, Vz };
|
||||
class ostream;
|
||||
|
||||
|
||||
inline vvm_bit_t operator & (vvm_bit_t l, vvm_bit_t r)
|
||||
inline vpip_bit_t operator & (vpip_bit_t l, vpip_bit_t r)
|
||||
{
|
||||
if (l == V0) return V0;
|
||||
if (r == V0) return V0;
|
||||
@@ -53,7 +47,7 @@ inline vvm_bit_t operator & (vvm_bit_t l, vvm_bit_t r)
|
||||
return Vx;
|
||||
}
|
||||
|
||||
inline vvm_bit_t operator | (vvm_bit_t l, vvm_bit_t r)
|
||||
inline vpip_bit_t operator | (vpip_bit_t l, vpip_bit_t r)
|
||||
{
|
||||
if (l == V1) return V1;
|
||||
if (r == V1) return V1;
|
||||
@@ -61,7 +55,7 @@ inline vvm_bit_t operator | (vvm_bit_t l, vvm_bit_t r)
|
||||
return Vx;
|
||||
}
|
||||
|
||||
inline vvm_bit_t operator ^ (vvm_bit_t l, vvm_bit_t r)
|
||||
inline vpip_bit_t operator ^ (vpip_bit_t l, vpip_bit_t r)
|
||||
{
|
||||
if (l == Vx) return Vx;
|
||||
if (l == Vz) return Vx;
|
||||
@@ -71,7 +65,7 @@ inline vvm_bit_t operator ^ (vvm_bit_t l, vvm_bit_t r)
|
||||
return (r == V0)? V1 : V0;
|
||||
}
|
||||
|
||||
inline vvm_bit_t less_with_cascade(vvm_bit_t l, vvm_bit_t r, vvm_bit_t c)
|
||||
inline vpip_bit_t less_with_cascade(vpip_bit_t l, vpip_bit_t r, vpip_bit_t c)
|
||||
{
|
||||
if (l == Vx) return Vx;
|
||||
if (r == Vx) return Vx;
|
||||
@@ -80,7 +74,7 @@ inline vvm_bit_t less_with_cascade(vvm_bit_t l, vvm_bit_t r, vvm_bit_t c)
|
||||
return c;
|
||||
}
|
||||
|
||||
inline vvm_bit_t greater_with_cascade(vvm_bit_t l, vvm_bit_t r, vvm_bit_t c)
|
||||
inline vpip_bit_t greater_with_cascade(vpip_bit_t l, vpip_bit_t r, vpip_bit_t c)
|
||||
{
|
||||
if (l == Vx) return Vx;
|
||||
if (r == Vx) return Vx;
|
||||
@@ -89,9 +83,9 @@ inline vvm_bit_t greater_with_cascade(vvm_bit_t l, vvm_bit_t r, vvm_bit_t c)
|
||||
return c;
|
||||
}
|
||||
|
||||
extern vvm_bit_t add_with_carry(vvm_bit_t l, vvm_bit_t r, vvm_bit_t&carry);
|
||||
extern vpip_bit_t add_with_carry(vpip_bit_t l, vpip_bit_t r, vpip_bit_t&carry);
|
||||
|
||||
inline vvm_bit_t not(vvm_bit_t l)
|
||||
inline vpip_bit_t not(vpip_bit_t l)
|
||||
{
|
||||
switch (l) {
|
||||
case V0:
|
||||
@@ -103,18 +97,23 @@ inline vvm_bit_t not(vvm_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 vvm_bit_t get_bit(unsigned idx) const =0;
|
||||
virtual vpip_bit_t get_bit(unsigned idx) const =0;
|
||||
|
||||
unsigned as_unsigned() const;
|
||||
};
|
||||
|
||||
extern ostream& operator << (ostream&os, vvm_bit_t);
|
||||
extern ostream& operator << (ostream&os, vpip_bit_t);
|
||||
extern ostream& operator << (ostream&os, const vvm_bits_t&str);
|
||||
|
||||
/*
|
||||
* The vvm_bitset_t is a fixed width array-like set of vvm_bit_t
|
||||
* The vvm_bitset_t is a fixed width array-like set of vpip_bit_t
|
||||
* items. A number is often times made up of bit sets instead of
|
||||
* single bits. The fixed array is used when possible because of the
|
||||
* more thorough type checking and (hopefully) better optimization.
|
||||
@@ -124,44 +123,31 @@ template <unsigned WIDTH> class vvm_bitset_t : public vvm_bits_t {
|
||||
public:
|
||||
vvm_bitset_t()
|
||||
{ for (unsigned idx = 0 ; idx < WIDTH ; idx += 1)
|
||||
bits_[idx] = Vz;
|
||||
bits[idx] = Vz;
|
||||
}
|
||||
vvm_bitset_t(const vvm_bitset_t<WIDTH>&that)
|
||||
{ bits_ = that.bits_; }
|
||||
|
||||
vvm_bitset_t(const vvm_bits_t&that)
|
||||
{ unsigned wid = WIDTH;
|
||||
if (that.get_width() < WIDTH)
|
||||
wid = that.get_width();
|
||||
for (unsigned idx = 0 ; idx < wid ; idx += 1)
|
||||
bits_[idx] = that.get_bit(idx);
|
||||
bits[idx] = that.get_bit(idx);
|
||||
for (unsigned idx = wid ; idx < WIDTH ; idx += 1)
|
||||
bits_[idx] = V0;
|
||||
bits[idx] = V0;
|
||||
}
|
||||
|
||||
|
||||
vvm_bit_t operator[] (unsigned idx) const { return bits_[idx]; }
|
||||
vvm_bit_t&operator[] (unsigned idx) { return bits_[idx]; }
|
||||
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; }
|
||||
vvm_bit_t get_bit(unsigned idx) const { return bits_[idx]; }
|
||||
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;
|
||||
}
|
||||
|
||||
vvm_bitset_t<WIDTH>& operator= (const vvm_bitset_t<WIDTH>&that)
|
||||
{ if (this == &that) return *this;
|
||||
bits_ = that.bits_;
|
||||
return *this;
|
||||
}
|
||||
|
||||
private:
|
||||
vvm_bit_t bits_[WIDTH];
|
||||
public:
|
||||
vpip_bit_t bits[WIDTH];
|
||||
};
|
||||
|
||||
/*
|
||||
@@ -174,12 +160,14 @@ class vvm_event {
|
||||
friend class vvm_simulation;
|
||||
|
||||
public:
|
||||
vvm_event() { }
|
||||
vvm_event();
|
||||
virtual ~vvm_event() =0;
|
||||
virtual void event_function() =0;
|
||||
|
||||
static void callback_(void*);
|
||||
|
||||
private:
|
||||
vvm_event*next_;
|
||||
struct vpip_event*event_;
|
||||
|
||||
private: // not implemented
|
||||
vvm_event(const vvm_event&);
|
||||
@@ -225,85 +213,124 @@ class vvm_simulation {
|
||||
// only one event can be a monitor.
|
||||
void monitor_event(vvm_event*);
|
||||
|
||||
unsigned long get_sim_time() const { return time_; }
|
||||
|
||||
// The s_finish() method marks the simulation as finished and
|
||||
// prevents more events being executed. The finished() method
|
||||
// returns true if the s_finish() method has been called.
|
||||
void s_finish();
|
||||
bool finished() const;
|
||||
|
||||
private:
|
||||
bool going_;
|
||||
vvm_simulation_cycle*sim_;
|
||||
|
||||
// Triggered monitor event.
|
||||
vvm_event*mon_;
|
||||
|
||||
unsigned long time_;
|
||||
|
||||
private: // not implemented
|
||||
vvm_simulation(const vvm_simulation&);
|
||||
vvm_simulation& operator= (const vvm_simulation&);
|
||||
};
|
||||
|
||||
/*
|
||||
* The vvm_monitor_t is usually associated with a vvm_bitset_t that
|
||||
* represents a signal. The VVM code generator generates calls to the
|
||||
* trigger method whenever an assignment or output value is set on
|
||||
* the associated signal. The trigger, if enabled, then causes the
|
||||
* monitor event to be scheduled in the simulation.
|
||||
*
|
||||
* This object also carries the canonical signal name, for the use of
|
||||
* %m display patterns.
|
||||
* The vvm_signal_t template is the real object that handles the
|
||||
* 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*);
|
||||
|
||||
void trigger(vvm_simulation*sim)
|
||||
{ if (event_) sim->monitor_event(event_); }
|
||||
|
||||
const char* name() const { return name_; }
|
||||
|
||||
void enable(vvm_event*e) { event_ = e; }
|
||||
|
||||
private:
|
||||
const char* name_;
|
||||
vvm_event*event_;
|
||||
|
||||
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, vvm_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, vvm_bit_t val)
|
||||
{ (*bits_)[idx] = val;
|
||||
trigger(sim);
|
||||
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
|
||||
* in C (to interface with VPI) and add VPI support
|
||||
* for callbacks.
|
||||
*
|
||||
* Revision 1.15 1999/10/13 03:15:51 steve
|
||||
* Remove useless operator=.
|
||||
*
|
||||
* Revision 1.14 1999/10/06 01:28:18 steve
|
||||
* The $finish task should work immediately.
|
||||
*
|
||||
|
||||
+65
-3
@@ -17,12 +17,13 @@
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
|
||||
*/
|
||||
#if !defined(WINNT)
|
||||
#ident "$Id: vvm_bit.cc,v 1.2 1998/11/10 00:48:31 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, vvm_bit_t bit)
|
||||
ostream& operator << (ostream&os, vpip_bit_t bit)
|
||||
{
|
||||
switch (bit) {
|
||||
case V0:
|
||||
@@ -41,6 +42,20 @@ ostream& operator << (ostream&os, vvm_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,7 +69,34 @@ vvm_bits_t::~vvm_bits_t()
|
||||
{
|
||||
}
|
||||
|
||||
vvm_bit_t add_with_carry(vvm_bit_t l, vvm_bit_t r, vvm_bit_t&carry)
|
||||
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;
|
||||
switch (l) {
|
||||
@@ -100,6 +142,26 @@ vvm_bit_t add_with_carry(vvm_bit_t l, vvm_bit_t r, vvm_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
|
||||
* in C (to interface with VPI) and add VPI support
|
||||
* for callbacks.
|
||||
*
|
||||
* Revision 1.2 1998/11/10 00:48:31 steve
|
||||
* Add support it vvm target for level-sensitive
|
||||
* triggers (i.e. the Verilog wait).
|
||||
|
||||
+18
-393
@@ -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.6 1999/09/29 01:41:18 steve Exp $"
|
||||
#ident "$Id: vvm_calltf.cc,v 1.9 1999/11/28 18:05:37 steve Exp $"
|
||||
#endif
|
||||
|
||||
# include "vvm_calltf.h"
|
||||
@@ -34,330 +34,12 @@
|
||||
|
||||
# define MAX_PATHLEN 1024
|
||||
|
||||
/* This simulation pointer is used by vpi functions to get back to the
|
||||
simulation. */
|
||||
static vvm_simulation*vpi_sim;
|
||||
static char*module_path = 0;
|
||||
|
||||
static vpiHandle vvm_vpi_cur_task;
|
||||
|
||||
/*
|
||||
* Keep a list of vpi_systf_data structures. This list is searched
|
||||
* forward whenever a function is invoked by name, and items are
|
||||
* pushed in front of the list whenever they are registered. This
|
||||
* allows entries to override older entries.
|
||||
*/
|
||||
struct systf_entry {
|
||||
struct systf_entry* next;
|
||||
s_vpi_systf_data systf_data;
|
||||
};
|
||||
|
||||
static struct systf_entry*systf_list = 0;
|
||||
|
||||
extern "C" void vpi_register_systf(const struct t_vpi_systf_data*systf)
|
||||
void vvm_set_module_path(const char*path)
|
||||
{
|
||||
struct systf_entry*cur = new struct systf_entry;
|
||||
cur->systf_data = *systf;
|
||||
cur->systf_data.tfname = strdup(systf->tfname);
|
||||
cur->next = systf_list;
|
||||
systf_list = cur;
|
||||
}
|
||||
|
||||
extern "C" void vpi_printf(const char*fmt, ...)
|
||||
{
|
||||
va_list ap;
|
||||
va_start(ap, fmt);
|
||||
vprintf(fmt, ap);
|
||||
va_end(ap);
|
||||
}
|
||||
|
||||
extern "C" void vpi_sim_control(int func, ...)
|
||||
{
|
||||
switch (func) {
|
||||
case vpiFinish:
|
||||
vpi_sim->s_finish();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
extern "C" vpiHandle vpi_handle(int type, vpiHandle ref)
|
||||
{
|
||||
switch (type) {
|
||||
case vpiSysTfCall:
|
||||
return vvm_vpi_cur_task;
|
||||
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
extern "C" vpiHandle vpi_iterate(int type, vpiHandle ref)
|
||||
{
|
||||
vpiHandle res = (vpiHandle)calloc(1, sizeof (struct __vpiHandle));
|
||||
res->type = type;
|
||||
res->referent = ref;
|
||||
res->val.unum = 0;
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
extern "C" vpiHandle vpi_scan(vpiHandle ref)
|
||||
{
|
||||
assert(ref->type == vpiArgument);
|
||||
if (ref->val.unum >= ref->referent->narguments) {
|
||||
vpi_free_object(ref);
|
||||
return 0;
|
||||
}
|
||||
|
||||
return ref->referent->arguments[ref->val.unum++];
|
||||
}
|
||||
|
||||
extern "C" int vpi_get(int property, vpiHandle ref)
|
||||
{
|
||||
if (property == vpiType)
|
||||
return ref->type;
|
||||
|
||||
if (ref->get_ == 0)
|
||||
return -1;
|
||||
|
||||
return (ref->get_)(property, ref);
|
||||
}
|
||||
|
||||
extern "C" char* vpi_get_str(int property, vpiHandle ref)
|
||||
{
|
||||
if (property == vpiFullName)
|
||||
return ref->full_name;
|
||||
|
||||
if (ref->get_str_ == 0)
|
||||
return 0;
|
||||
|
||||
return (ref->get_str_)(property, ref);
|
||||
|
||||
switch (property) {
|
||||
case vpiName:
|
||||
return ref->full_name;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
extern "C" void vpi_get_value(vpiHandle expr, s_vpi_value*vp)
|
||||
{
|
||||
if (expr->get_value_) {
|
||||
expr->get_value_(expr, vp);
|
||||
return;
|
||||
}
|
||||
|
||||
vp->format = vpiSuppressVal;
|
||||
}
|
||||
|
||||
extern "C" int vpi_free_object(vpiHandle ref)
|
||||
{
|
||||
free(ref);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* This function is a get_value_ method of a vpiHandle, that supports
|
||||
* reading bits as a string.
|
||||
*/
|
||||
static void get_value_bits(vpiHandle ref, s_vpi_value*vp)
|
||||
{
|
||||
static char buff[1024];
|
||||
char*cp;
|
||||
unsigned width, bytes;
|
||||
unsigned val;
|
||||
assert(ref->val.bits);
|
||||
width = ref->val.bits->get_width();
|
||||
cp = buff;
|
||||
|
||||
switch (vp->format) {
|
||||
case vpiObjTypeVal:
|
||||
case vpiBinStrVal:
|
||||
for (unsigned idx = 0 ; idx < width ; idx += 1)
|
||||
switch (ref->val.bits->get_bit(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 (unsigned idx = 0 ; idx < width ; idx += 1) {
|
||||
val *= 2;
|
||||
switch (ref->val.bits->get_bit(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:
|
||||
bytes = width%3;
|
||||
if (bytes) {
|
||||
*cp++ = '?';
|
||||
}
|
||||
for (unsigned idx = bytes ; idx < width ; idx += 3) {
|
||||
unsigned x = 0;
|
||||
unsigned z = 0;
|
||||
unsigned v = 0;
|
||||
for (unsigned i = idx ; i < idx+3 ; i += 1) {
|
||||
v *= 2;
|
||||
switch (ref->val.bits->get_bit(width-idx-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;
|
||||
for (unsigned i = 0 ; i < width%4 ; i += 1) {
|
||||
v *= 2;
|
||||
switch (ref->val.bits->get_bit(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 (unsigned idx = width%4 ; idx < width ; idx += 4) {
|
||||
unsigned x = 0;
|
||||
unsigned z = 0;
|
||||
unsigned v = 0;
|
||||
for (unsigned i = idx ; i < idx+4 ; i += 1) {
|
||||
v *= 2;
|
||||
switch (ref->val.bits->get_bit(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;
|
||||
}
|
||||
|
||||
static void get_value_strconst(vpiHandle ref, s_vpi_value*vp)
|
||||
{
|
||||
switch (vp->format) {
|
||||
case vpiObjTypeVal:
|
||||
case vpiStringVal:
|
||||
vp->value.str = ref->full_name;
|
||||
vp->format = vpiStringVal;
|
||||
break;
|
||||
|
||||
default:
|
||||
vp->format = vpiSuppressVal;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void get_value_timevar(vpiHandle ref, s_vpi_value*vp)
|
||||
{
|
||||
static char buf[128];
|
||||
switch (vp->format) {
|
||||
case vpiObjTypeVal:
|
||||
case vpiTimeVal:
|
||||
vp->value.time = &ref->val.time;
|
||||
vp->format = vpiTimeVal;
|
||||
break;
|
||||
|
||||
case vpiDecStrVal:
|
||||
sprintf(buf, "%u", ref->val.time.low);
|
||||
vp->value.str = buf;
|
||||
break;
|
||||
|
||||
default:
|
||||
vp->format = vpiSuppressVal;
|
||||
vp->value.str = 0;
|
||||
break;
|
||||
}
|
||||
if (module_path) free(module_path);
|
||||
module_path = strdup(path);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -382,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);
|
||||
@@ -429,80 +112,22 @@ void vvm_load_vpi_module(const char*name)
|
||||
(routines[idx])();
|
||||
}
|
||||
|
||||
void vvm_make_vpi_parm(vpiHandle ref, const char*val)
|
||||
{
|
||||
memset(ref, 0, sizeof*ref);
|
||||
ref->type = vpiConstant;
|
||||
ref->subtype = vpiStringConst;
|
||||
ref->full_name = const_cast<char*>(val);
|
||||
ref->get_value_ = &get_value_strconst;
|
||||
}
|
||||
|
||||
void vvm_make_vpi_parm(vpiHandle ref, vvm_bits_t*val)
|
||||
{
|
||||
memset(ref, 0, sizeof*ref);
|
||||
ref->type = vpiConstant;
|
||||
ref->subtype = vpiBinaryConst;
|
||||
ref->full_name = "";
|
||||
ref->val.bits = val;
|
||||
ref->get_value_ = &get_value_bits;
|
||||
}
|
||||
|
||||
void vvm_init_vpi_handle(vpiHandle ref, vvm_bits_t*bits, vvm_monitor_t*mon)
|
||||
{
|
||||
memset(ref, 0, sizeof*ref);
|
||||
ref->type = vpiReg;
|
||||
ref->full_name = const_cast<char*>(mon->name());
|
||||
ref->val.bits = bits;
|
||||
ref->get_value_ = &get_value_bits;
|
||||
}
|
||||
|
||||
void vvm_init_vpi_timevar(vpiHandle ref, const char*name)
|
||||
{
|
||||
memset(ref, 0, sizeof*ref);
|
||||
ref->type = vpiTimeVar;
|
||||
ref->full_name = const_cast<char*>(name);
|
||||
ref->get_value_ = &get_value_timevar;
|
||||
}
|
||||
|
||||
void vvm_make_vpi_parm(vpiHandle ref)
|
||||
{
|
||||
memset(ref, 0, sizeof*ref);
|
||||
ref->type = 0;
|
||||
}
|
||||
|
||||
void vvm_calltask(vvm_simulation*sim, const string&fname,
|
||||
unsigned nparms, vpiHandle*parms)
|
||||
{
|
||||
vpi_sim = sim;
|
||||
|
||||
struct __vpiHandle cur_task;
|
||||
cur_task.type = vpiSysTaskCall;
|
||||
cur_task.full_name = 0;
|
||||
cur_task.referent = 0;
|
||||
cur_task.arguments = parms;
|
||||
cur_task.narguments = nparms;
|
||||
|
||||
vvm_vpi_cur_task = &cur_task;
|
||||
|
||||
/* Look for a systf function to invoke. */
|
||||
for (systf_entry*idx = systf_list ; idx ; idx = idx->next)
|
||||
if (fname == idx->systf_data.tfname) {
|
||||
cur_task.full_name = idx->systf_data.tfname;
|
||||
idx->systf_data.calltf(idx->systf_data.user_data);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
/* Finally, if nothing is found then something is not
|
||||
right. Print out the function name all the parameters
|
||||
passed, so that someone can deal with it. */
|
||||
cout << "Call " << fname << endl;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* $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
|
||||
* in C (to interface with VPI) and add VPI support
|
||||
* for callbacks.
|
||||
*
|
||||
* Revision 1.7 1999/10/10 14:57:38 steve
|
||||
* Handle display of odd octal/hex widths (Eric Ardoom)
|
||||
*
|
||||
* Revision 1.6 1999/09/29 01:41:18 steve
|
||||
* Support the $write system task, and have the
|
||||
* vpi_scan function free iterators as needed.
|
||||
|
||||
+11
-28
@@ -19,48 +19,31 @@
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
|
||||
*/
|
||||
#if !defined(WINNT)
|
||||
#ident "$Id: vvm_calltf.h,v 1.2 1999/08/15 01:23:56 steve Exp $"
|
||||
#ident "$Id: vvm_calltf.h,v 1.4 1999/11/28 18:05:37 steve Exp $"
|
||||
#endif
|
||||
|
||||
# include "vvm.h"
|
||||
# include <string>
|
||||
|
||||
typedef struct __vpiHandle*vpiHandle;
|
||||
|
||||
/*
|
||||
* 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);
|
||||
|
||||
|
||||
/*
|
||||
* The vvm_init_vpi_handle functions initialize statis VPI handles
|
||||
* that may be used many places within the program.
|
||||
*/
|
||||
extern void vvm_init_vpi_handle(vpiHandle, vvm_bits_t*, vvm_monitor_t*);
|
||||
extern void vvm_init_vpi_timevar(vpiHandle, const char*name);
|
||||
|
||||
/*
|
||||
* The vvm_make_vpi_parm functions initialize the vpiHandles to
|
||||
* represent objects suitable for use as vvm_calltask parameters.
|
||||
*/
|
||||
extern void vvm_make_vpi_parm(vpiHandle ref, const char*val);
|
||||
extern void vvm_make_vpi_parm(vpiHandle ref, vvm_bits_t*val);
|
||||
extern void vvm_make_vpi_parm(vpiHandle ref);
|
||||
|
||||
/*
|
||||
* The vvm environment supports external calls to C++ by
|
||||
* vvm_calltask. The code generator generates calls to vvm_calltask
|
||||
* that corresponds to the system call in the Verilog source. The
|
||||
* vvm_calltask in turn locates the vpi implementation (by name) and
|
||||
* calls the VPI that implements the task.
|
||||
*/
|
||||
|
||||
extern void vvm_calltask(vvm_simulation*sim, const string&name,
|
||||
unsigned nparms, vpiHandle*parms);
|
||||
|
||||
/*
|
||||
* $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
|
||||
* 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.
|
||||
*
|
||||
|
||||
+19
-1
@@ -17,18 +17,36 @@
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
|
||||
*/
|
||||
#if !defined(WINNT)
|
||||
#ident "$Id: vvm_event.cc,v 1.1 1998/11/09 23:44:11 steve Exp $"
|
||||
#ident "$Id: vvm_event.cc,v 1.2 1999/10/28 00:47:25 steve Exp $"
|
||||
#endif
|
||||
|
||||
# include "vvm.h"
|
||||
# include <assert.h>
|
||||
|
||||
vvm_event::vvm_event()
|
||||
{
|
||||
event_ = 0;
|
||||
}
|
||||
|
||||
vvm_event::~vvm_event()
|
||||
{
|
||||
}
|
||||
|
||||
void vvm_event::callback_(void*cbd)
|
||||
{
|
||||
vvm_event*obj = reinterpret_cast<vvm_event*>(cbd);
|
||||
obj->event_function();
|
||||
delete obj;
|
||||
}
|
||||
|
||||
/*
|
||||
* $Log: vvm_event.cc,v $
|
||||
* Revision 1.2 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.1 1998/11/09 23:44:11 steve
|
||||
* Add vvm library.
|
||||
*
|
||||
|
||||
+16
-7
@@ -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.14 1999/10/05 06:19:47 steve Exp $"
|
||||
#ident "$Id: vvm_func.h,v 1.16 1999/12/02 03:36:01 steve Exp $"
|
||||
#endif
|
||||
|
||||
# include "vvm.h"
|
||||
@@ -123,7 +123,7 @@ vvm_bitset_t<WIDTH> vvm_unop_uminus(const vvm_bitset_t<WIDTH>&l)
|
||||
{
|
||||
vvm_bitset_t<WIDTH> res;
|
||||
res = vvm_unop_not(l);
|
||||
vvm_bit_t carry = V1;
|
||||
vpip_bit_t carry = V1;
|
||||
for (int i = 0; i < WIDTH; i++)
|
||||
res[i] = add_with_carry(res[i], V0, carry);
|
||||
|
||||
@@ -170,7 +170,7 @@ vvm_bitset_t<WIDTH> vvm_binop_plus(const vvm_bitset_t<WIDTH>&l,
|
||||
const vvm_bitset_t<WIDTH>&r)
|
||||
{
|
||||
vvm_bitset_t<WIDTH> result;
|
||||
vvm_bit_t carry = V0;
|
||||
vpip_bit_t carry = V0;
|
||||
for (unsigned idx = 0 ; idx < WIDTH ; idx += 1)
|
||||
result[idx] = add_with_carry(l[idx], r[idx], carry);
|
||||
|
||||
@@ -188,7 +188,7 @@ vvm_bitset_t<WIDTH> vvm_binop_minus(const vvm_bitset_t<WIDTH>&l,
|
||||
{
|
||||
vvm_bitset_t<WIDTH> res;
|
||||
res = vvm_unop_not(r);
|
||||
vvm_bit_t carry = V1;
|
||||
vpip_bit_t carry = V1;
|
||||
for (unsigned idx = 0 ; idx < WIDTH ; idx += 1)
|
||||
res[idx] = add_with_carry(l[idx], res[idx], carry);
|
||||
|
||||
@@ -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();
|
||||
@@ -593,7 +593,7 @@ vvm_bitset_t<1> vvm_binop_lor(const vvm_bitset_t<LW>&l,
|
||||
}
|
||||
|
||||
template <unsigned W>
|
||||
vvm_bitset_t<W> vvm_ternary(vvm_bit_t c, const vvm_bitset_t<W>&t,
|
||||
vvm_bitset_t<W> vvm_ternary(vpip_bit_t c, const vvm_bitset_t<W>&t,
|
||||
const vvm_bitset_t<W>&f)
|
||||
{
|
||||
switch (c) {
|
||||
@@ -608,6 +608,15 @@ vvm_bitset_t<W> vvm_ternary(vvm_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
|
||||
* in C (to interface with VPI) and add VPI support
|
||||
* for callbacks.
|
||||
*
|
||||
* Revision 1.14 1999/10/05 06:19:47 steve
|
||||
* Add support for reduction NOR.
|
||||
*
|
||||
|
||||
@@ -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.
|
||||
*
|
||||
*/
|
||||
|
||||
+619
-179
@@ -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.12 1999/07/17 03:07:27 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
|
||||
@@ -36,83 +47,533 @@
|
||||
class vvm_out_event : public vvm_event {
|
||||
|
||||
public:
|
||||
typedef void (*action_t)(vvm_simulation*, vvm_bit_t);
|
||||
vvm_out_event(vvm_simulation*s, vvm_bit_t v, action_t o)
|
||||
: output_(o), sim_(s), val_(v) { }
|
||||
typedef void (*action_t)(vvm_simulation*, vpip_bit_t);
|
||||
|
||||
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_;
|
||||
vvm_simulation*const sim_;
|
||||
const vvm_bit_t val_;
|
||||
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, vvm_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, vvm_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:
|
||||
vvm_bit_t compute_() const
|
||||
{ vvm_bit_t outval = input_[0];
|
||||
for (unsigned i = 1 ; i < WIDTH ; i += 1)
|
||||
outval = outval & input_[i];
|
||||
return outval;
|
||||
}
|
||||
|
||||
vvm_bit_t input_[WIDTH];
|
||||
vvm_out_event::action_t output_;
|
||||
vpip_bit_t input_[WIDTH];
|
||||
};
|
||||
|
||||
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, vvm_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_I(vvm_simulation*sim, unsigned idx, vpip_bit_t val)
|
||||
{ if (input_[idx] == val)
|
||||
return;
|
||||
input_[idx] = val;
|
||||
output(sim, compute_or(input_,WIDTH));
|
||||
}
|
||||
|
||||
void set(vvm_simulation*sim, unsigned idx, vvm_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 long DELAY>
|
||||
class vvm_nor : private vvm_1bit_out {
|
||||
|
||||
public:
|
||||
explicit vvm_nor(vvm_out_event::action_t o)
|
||||
: vvm_1bit_out(o, DELAY) { }
|
||||
|
||||
void init_I(unsigned idx, vpip_bit_t val)
|
||||
{ input_[idx] = val; }
|
||||
|
||||
void start(vvm_simulation*sim)
|
||||
{ output(sim, compute_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));
|
||||
}
|
||||
|
||||
private:
|
||||
vpip_bit_t input_[WIDTH];
|
||||
};
|
||||
|
||||
template <unsigned WIDTH, unsigned AWIDTH, unsigned SIZE>
|
||||
class vvm_ram_dq : protected vvm_ram_callback {
|
||||
|
||||
public:
|
||||
vvm_ram_dq(vvm_memory_t<WIDTH,SIZE>*mem)
|
||||
: mem_(mem)
|
||||
{ mem->set_callback(this);
|
||||
for (unsigned idx = 0 ; idx < WIDTH ; idx += 1)
|
||||
out_[idx] = 0;
|
||||
for (unsigned idx = 0 ; idx < AWIDTH ; idx += 1)
|
||||
addr_[idx] = Vx;
|
||||
}
|
||||
|
||||
void init_Address(unsigned idx, vpip_bit_t val)
|
||||
{ addr_[idx] = val; }
|
||||
|
||||
void set_Address(vvm_simulation*sim, unsigned idx, vpip_bit_t val)
|
||||
{ if (addr_[idx] == val) return;
|
||||
addr_[idx] = val;
|
||||
compute_();
|
||||
send_out_(sim);
|
||||
}
|
||||
|
||||
void handle_write(vvm_simulation*sim, unsigned idx)
|
||||
{ if (idx == addr_val_) send_out_(sim); }
|
||||
|
||||
void config_rout(unsigned idx, vvm_out_event::action_t o)
|
||||
{ out_[idx] = o; }
|
||||
|
||||
private:
|
||||
vvm_memory_t<WIDTH,SIZE>*mem_;
|
||||
vpip_bit_t addr_[AWIDTH];
|
||||
vvm_out_event::action_t out_[WIDTH];
|
||||
|
||||
unsigned long addr_val_;
|
||||
|
||||
void compute_()
|
||||
{ unsigned bit;
|
||||
unsigned mask;
|
||||
addr_val_ = 0;
|
||||
for (bit = 0, mask = 1 ; bit < AWIDTH ; bit += 1, mask <<= 1)
|
||||
if (addr_[bit] == V1) addr_val_ |= mask;
|
||||
}
|
||||
|
||||
void send_out_(vvm_simulation*sim)
|
||||
{ vvm_bitset_t<WIDTH>ov = mem_->get_word(addr_val_);
|
||||
for (unsigned bit = 0 ; bit < WIDTH ; bit += 1)
|
||||
if (out_[bit]) {
|
||||
vvm_event*ev = new vvm_out_event(sim,
|
||||
ov[bit],
|
||||
out_[bit]);
|
||||
sim->active_event(ev);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
template <unsigned long DELAY> class vvm_buf {
|
||||
|
||||
public:
|
||||
explicit vvm_buf(vvm_out_event::action_t o)
|
||||
: output_(o)
|
||||
{ }
|
||||
|
||||
void init_I(unsigned, vpip_bit_t) { }
|
||||
void start(vvm_simulation*) { }
|
||||
|
||||
void set_I(vvm_simulation*sim, unsigned, vpip_bit_t val)
|
||||
{ vpip_bit_t outval = val;
|
||||
if (val == Vz) val = Vx;
|
||||
vvm_event*ev = new vvm_out_event(sim, outval, output_);
|
||||
if (DELAY > 0)
|
||||
sim->insert_event(DELAY, ev);
|
||||
else
|
||||
@@ -120,14 +581,6 @@ template <unsigned WIDTH, unsigned long DELAY> class vvm_or {
|
||||
}
|
||||
|
||||
private:
|
||||
vvm_bit_t compute_() const
|
||||
{ vvm_bit_t outval = input_[0];
|
||||
for (unsigned i = 1 ; i < WIDTH ; i += 1)
|
||||
outval = outval | input_[i];
|
||||
return outval;
|
||||
}
|
||||
|
||||
vvm_bit_t input_[WIDTH];
|
||||
vvm_out_event::action_t output_;
|
||||
};
|
||||
|
||||
@@ -140,7 +593,7 @@ template <unsigned long DELAY> class vvm_bufif1 {
|
||||
input_[1] = Vx;
|
||||
}
|
||||
|
||||
void set(vvm_simulation*sim, unsigned idx, vvm_bit_t val)
|
||||
void set(vvm_simulation*sim, unsigned idx, vpip_bit_t val)
|
||||
{ if (input_[idx-1] == val)
|
||||
return;
|
||||
input_[idx-1] = val;
|
||||
@@ -156,126 +609,115 @@ template <unsigned long DELAY> class vvm_bufif1 {
|
||||
}
|
||||
|
||||
private:
|
||||
vvm_bit_t input_[2];
|
||||
vpip_bit_t input_[2];
|
||||
vvm_out_event::action_t output_;
|
||||
|
||||
vvm_bit_t compute_() const
|
||||
vpip_bit_t compute_() const
|
||||
{ if (input_[1] != V1) return Vz;
|
||||
if (input_[0] == Vz) return Vx;
|
||||
return input_[0];
|
||||
}
|
||||
};
|
||||
|
||||
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, vvm_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, vvm_bit_t val)
|
||||
{ if (input_[idx-1] == val)
|
||||
return;
|
||||
input_[idx-1] = val;
|
||||
vvm_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:
|
||||
vvm_bit_t input_[WIDTH];
|
||||
vvm_out_event::action_t output_;
|
||||
vpip_bit_t input_[WIDTH];
|
||||
};
|
||||
|
||||
/*
|
||||
* 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, vvm_bit_t) { }
|
||||
void init_I(unsigned, vpip_bit_t) { }
|
||||
void start(vvm_simulation*) { }
|
||||
|
||||
void set(vvm_simulation*sim, unsigned, vvm_bit_t val)
|
||||
{ vvm_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, vvm_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, vvm_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_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:
|
||||
vvm_bit_t compute_() const
|
||||
{ vvm_bit_t outval = input_[0];
|
||||
for (unsigned i = 1 ; i < WIDTH ; i += 1)
|
||||
outval = outval ^ input_[i];
|
||||
|
||||
outval = not(outval);
|
||||
return outval;
|
||||
}
|
||||
vvm_bit_t input_[WIDTH];
|
||||
vvm_out_event::action_t output_;
|
||||
vpip_bit_t input_[WIDTH];
|
||||
};
|
||||
|
||||
template <unsigned WIDTH, unsigned long DELAY> class vvm_xor {
|
||||
template <unsigned WIDTH, unsigned long DELAY>
|
||||
class vvm_xor : private vvm_1bit_out {
|
||||
|
||||
public:
|
||||
explicit vvm_xor(vvm_out_event::action_t o)
|
||||
: vvm_1bit_out(o,DELAY) { }
|
||||
|
||||
void init_I(unsigned idx, vpip_bit_t val)
|
||||
{ input_[idx] = val; }
|
||||
|
||||
void start(vvm_simulation*sim)
|
||||
{ output(sim,compute_xor(input_,WIDTH)); }
|
||||
|
||||
void set_I(vvm_simulation*sim, unsigned idx, vpip_bit_t val)
|
||||
{ if (input_[idx] == val)
|
||||
return;
|
||||
input_[idx] = val;
|
||||
output(sim,compute_xor(input_,WIDTH)); }
|
||||
|
||||
private:
|
||||
vpip_bit_t input_[WIDTH];
|
||||
};
|
||||
|
||||
/*
|
||||
* This gate has only 3 pins, the output at pin 0 and two inputs. The
|
||||
* output is 1 or 0 if the two inputs are exactly equal or not.
|
||||
*/
|
||||
template <unsigned long DELAY> class vvm_eeq {
|
||||
|
||||
public:
|
||||
explicit vvm_eeq(vvm_out_event::action_t o)
|
||||
: output_(o) { }
|
||||
|
||||
void init(unsigned idx, vvm_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_);
|
||||
@@ -285,23 +727,23 @@ template <unsigned WIDTH, unsigned long DELAY> class vvm_xor {
|
||||
sim->active_event(ev);
|
||||
}
|
||||
|
||||
void set(vvm_simulation*sim, unsigned idx, vvm_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);
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
vvm_bit_t compute_() const
|
||||
{ vvm_bit_t outval = input_[0];
|
||||
for (unsigned i = 1 ; i < WIDTH ; i += 1)
|
||||
outval = outval ^ input_[i];
|
||||
vpip_bit_t compute_() const
|
||||
{ vpip_bit_t outval = V0;
|
||||
if (input_[0] == input_[1])
|
||||
outval = V1;
|
||||
return outval;
|
||||
}
|
||||
|
||||
vvm_bit_t input_[WIDTH];
|
||||
vpip_bit_t input_[2];
|
||||
vvm_out_event::action_t output_;
|
||||
};
|
||||
|
||||
@@ -315,7 +757,7 @@ template <unsigned WIDTH, unsigned long DELAY> class vvm_xor {
|
||||
template <unsigned WIDTH> class vvm_udp_ssequ {
|
||||
|
||||
public:
|
||||
explicit vvm_udp_ssequ(vvm_out_event::action_t o, vvm_bit_t i,
|
||||
explicit vvm_udp_ssequ(vvm_out_event::action_t o, vpip_bit_t i,
|
||||
const vvm_u32*tab)
|
||||
: output_(o), table_(tab)
|
||||
{ state_[0] = i;
|
||||
@@ -323,10 +765,10 @@ template <unsigned WIDTH> class vvm_udp_ssequ {
|
||||
state_[idx] = Vx;
|
||||
}
|
||||
|
||||
void init(unsigned pin, vvm_bit_t val)
|
||||
void init(unsigned pin, vpip_bit_t val)
|
||||
{ state_[pin] = val; }
|
||||
|
||||
void set(vvm_simulation*sim, unsigned pin, vvm_bit_t val)
|
||||
void set(vvm_simulation*sim, unsigned pin, vpip_bit_t val)
|
||||
{ assert(pin > 0);
|
||||
assert(pin < WIDTH+1);
|
||||
if (val == Vz) val = Vx;
|
||||
@@ -353,8 +795,8 @@ template <unsigned WIDTH> class vvm_udp_ssequ {
|
||||
code &= 3;
|
||||
break;
|
||||
}
|
||||
// Convert the code to a vvm_bit_t and run with it.
|
||||
vvm_bit_t outval = (code == 0)? V0 : (code == 1)? V1 : Vx;
|
||||
// Convert the code to a vpip_bit_t and run with it.
|
||||
vpip_bit_t outval = (code == 0)? V0 : (code == 1)? V1 : Vx;
|
||||
state_[0] = outval;
|
||||
state_[pin] = val;
|
||||
vvm_event*ev = new vvm_out_event(sim, outval, output_);
|
||||
@@ -364,7 +806,7 @@ template <unsigned WIDTH> class vvm_udp_ssequ {
|
||||
private:
|
||||
vvm_out_event::action_t output_;
|
||||
const vvm_u32*const table_;
|
||||
vvm_bit_t state_[WIDTH+1];
|
||||
vpip_bit_t state_[WIDTH+1];
|
||||
};
|
||||
|
||||
class vvm_bufz {
|
||||
@@ -373,9 +815,9 @@ class vvm_bufz {
|
||||
: output_(o)
|
||||
{ }
|
||||
|
||||
void init(unsigned idx, vvm_bit_t val) { }
|
||||
void init(unsigned idx, vpip_bit_t val) { }
|
||||
|
||||
void set(vvm_simulation*sim, unsigned idx, vvm_bit_t val)
|
||||
void set(vvm_simulation*sim, unsigned idx, vpip_bit_t val)
|
||||
{ output_(sim, val); }
|
||||
|
||||
private:
|
||||
@@ -420,7 +862,7 @@ template <unsigned WIDTH> class vvm_pevent {
|
||||
|
||||
vvm_bitset_t<WIDTH> get() const { return value_; }
|
||||
|
||||
void set(vvm_simulation*sim, unsigned idx, vvm_bit_t val)
|
||||
void set_P(vvm_simulation*sim, unsigned idx, vpip_bit_t val)
|
||||
{ if (value_[idx] == val) return;
|
||||
switch (edge_) {
|
||||
case ANYEDGE:
|
||||
@@ -438,7 +880,7 @@ template <unsigned WIDTH> class vvm_pevent {
|
||||
value_[idx] = val;
|
||||
}
|
||||
|
||||
void init(int idx, vvm_bit_t val)
|
||||
void init_P(int idx, vpip_bit_t val)
|
||||
{ assert(idx < WIDTH);
|
||||
value_[idx] = val;
|
||||
}
|
||||
@@ -455,48 +897,46 @@ template <unsigned WIDTH> class vvm_pevent {
|
||||
|
||||
/*
|
||||
* $Log: vvm_gates.h,v $
|
||||
* Revision 1.12 1999/07/17 03:07:27 steve
|
||||
* pevent objects have initial values.
|
||||
* Revision 1.30 1999/12/02 16:58:58 steve
|
||||
* Update case comparison (Eric Aardoom).
|
||||
*
|
||||
* Revision 1.11 1999/06/09 00:58:29 steve
|
||||
* Support for binary | (Stephen Tell)
|
||||
* Revision 1.29 1999/12/02 04:54:11 steve
|
||||
* Handle mux sel of X, if inputs are equal.
|
||||
*
|
||||
* Revision 1.10 1999/05/03 01:51:29 steve
|
||||
* Restore support for wait event control.
|
||||
* Revision 1.28 1999/11/25 01:34:04 steve
|
||||
* Reduce more gate templates to use vvm_1bit_out (Eric Aardoom)
|
||||
*
|
||||
* 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.27 1999/11/24 04:38:49 steve
|
||||
* LT and GT fixes from Eric Aardoom.
|
||||
*
|
||||
* Add to vvm the binary ^ and unary & operators.
|
||||
* Revision 1.26 1999/11/22 00:30:52 steve
|
||||
* Detemplate some and, or and nor methods.
|
||||
*
|
||||
* Dump events a bit more completely.
|
||||
* 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.8 1999/05/01 02:57:53 steve
|
||||
* Handle much more complex event expressions.
|
||||
* Revision 1.24 1999/11/21 00:13:09 steve
|
||||
* Support memories in continuous assignments.
|
||||
*
|
||||
* Revision 1.7 1999/02/15 05:52:50 steve
|
||||
* Mangle that handles device instance numbers.
|
||||
* Revision 1.23 1999/11/15 00:42:31 steve
|
||||
* Fixup to include right shift support.
|
||||
*
|
||||
* Revision 1.6 1999/01/31 18:15:55 steve
|
||||
* Missing start methods.
|
||||
* Revision 1.22 1999/11/14 23:43:46 steve
|
||||
* Support combinatorial comparators.
|
||||
*
|
||||
* Revision 1.5 1999/01/01 01:44:56 steve
|
||||
* Support the start() method.
|
||||
* Revision 1.21 1999/11/14 20:24:28 steve
|
||||
* Add support for the LPM_CLSHIFT device.
|
||||
*
|
||||
* Revision 1.4 1998/12/20 02:05:41 steve
|
||||
* Function to calculate wire initial value.
|
||||
* Revision 1.20 1999/11/14 18:22:12 steve
|
||||
* Fix NAND gate support to use named pins.
|
||||
*
|
||||
* 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
|
||||
|
||||
+16
-144
@@ -17,101 +17,37 @@
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
|
||||
*/
|
||||
#if !defined(WINNT)
|
||||
#ident "$Id: vvm_simulation.cc,v 1.6 1999/10/06 01:28:18 steve Exp $"
|
||||
#ident "$Id: vvm_simulation.cc,v 1.7 1999/10/28 00:47:25 steve Exp $"
|
||||
#endif
|
||||
|
||||
# include "vvm.h"
|
||||
# include "vvm_thread.h"
|
||||
# include "vpi_priv.h"
|
||||
# include <assert.h>
|
||||
|
||||
/*
|
||||
* The state of the simulation is stored as a list of simulation
|
||||
* times. Each simulation time contains the delay to get to it, and
|
||||
* also a list of events that are to execute here.
|
||||
*
|
||||
* The "events" member points to a list of inactive events to be made
|
||||
* active as a group. Update events go into this list.
|
||||
*
|
||||
* The "nonblock" member points to a list of events to be executed
|
||||
* only after ordinary events run out. This is intended to support the
|
||||
* semantics of nonblocking assignment.
|
||||
*/
|
||||
struct vvm_simulation_cycle {
|
||||
unsigned long delay;
|
||||
|
||||
struct vvm_simulation_cycle*next;
|
||||
struct vvm_simulation_cycle*prev;
|
||||
|
||||
struct vvm_event*event_list;
|
||||
struct vvm_event*event_last;
|
||||
struct vvm_event*nonblock_list;
|
||||
struct vvm_event*nonblock_last;
|
||||
|
||||
vvm_simulation_cycle()
|
||||
: event_list(0), event_last(0), nonblock_list(0),
|
||||
nonblock_last(0)
|
||||
{ }
|
||||
};
|
||||
|
||||
vvm_simulation::vvm_simulation()
|
||||
{
|
||||
sim_ = new vvm_simulation_cycle;
|
||||
sim_->delay = 0;
|
||||
sim_->next = sim_->prev = sim_;
|
||||
mon_ = 0;
|
||||
}
|
||||
|
||||
vvm_simulation::~vvm_simulation()
|
||||
{
|
||||
}
|
||||
|
||||
void vvm_simulation::insert_event(unsigned long delay, vvm_event*event)
|
||||
void vvm_simulation::monitor_event(vvm_event*)
|
||||
{
|
||||
vvm_simulation_cycle*cur = sim_->next;
|
||||
|
||||
while ((cur != sim_) && (cur->delay < delay)) {
|
||||
delay -= cur->delay;
|
||||
cur = cur->next;
|
||||
}
|
||||
|
||||
|
||||
if ((cur == sim_) || (cur->delay > delay)) {
|
||||
vvm_simulation_cycle*cell = new vvm_simulation_cycle;
|
||||
cell->delay = delay;
|
||||
if (cur != sim_)
|
||||
cur->delay -= delay;
|
||||
cell->next = cur;
|
||||
cell->prev = cur->prev;
|
||||
cell->next->prev = cell;
|
||||
cell->prev->next = cell;
|
||||
cur = cell;
|
||||
}
|
||||
|
||||
event->next_ = 0;
|
||||
if (cur->event_list == 0) {
|
||||
cur->event_list = cur->event_last = event;
|
||||
|
||||
} else {
|
||||
cur->event_last->next_ = event;
|
||||
cur->event_last = event;
|
||||
}
|
||||
assert(0);
|
||||
}
|
||||
|
||||
void vvm_simulation::monitor_event(vvm_event*event)
|
||||
void vvm_simulation::insert_event(unsigned long delay, vvm_event*event)
|
||||
{
|
||||
mon_ = event;
|
||||
event->event_ = vpip_sim_insert_event(delay, event,
|
||||
vvm_event::callback_, 0);
|
||||
}
|
||||
|
||||
void vvm_simulation::active_event(vvm_event*event)
|
||||
{
|
||||
event->next_ = 0;
|
||||
if (sim_->event_list == 0) {
|
||||
sim_->event_list = sim_->event_last = event;
|
||||
|
||||
} else {
|
||||
sim_->event_last->next_ = event;
|
||||
sim_->event_last = event;
|
||||
}
|
||||
event->event_ = vpip_sim_insert_event(0, event,
|
||||
vvm_event::callback_, 0);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -121,68 +57,7 @@ void vvm_simulation::active_event(vvm_event*event)
|
||||
*/
|
||||
void vvm_simulation::run()
|
||||
{
|
||||
assert(sim_);
|
||||
time_ = 0;
|
||||
going_ = true;
|
||||
|
||||
while (going_) {
|
||||
|
||||
/* Step the time forward to the cycle I am about to
|
||||
execute. */
|
||||
time_ += sim_->delay;
|
||||
sim_->delay = 0;
|
||||
|
||||
while (going_) {
|
||||
/* Look for some events to make active. If the
|
||||
main event list is empty, then activate the
|
||||
nonblock list. */
|
||||
vvm_event*active = sim_->event_list;
|
||||
sim_->event_list = 0;
|
||||
sim_->event_last = 0;
|
||||
|
||||
if (active == 0) {
|
||||
active = sim_->nonblock_list;
|
||||
sim_->nonblock_list = 0;
|
||||
sim_->nonblock_last = 0;
|
||||
}
|
||||
|
||||
/* Oops, no events left. Break out of this time cycle. */
|
||||
if (active == 0)
|
||||
break;
|
||||
|
||||
while (active && going_) {
|
||||
vvm_event*cur = active;
|
||||
active = cur->next_;
|
||||
cur->event_function();
|
||||
delete cur;
|
||||
}
|
||||
}
|
||||
|
||||
/* If the simulation was stopped by one of the events,
|
||||
then break out of the loop before doing any monitor
|
||||
events, and before clearing the current time. */
|
||||
if (!going_)
|
||||
break;
|
||||
|
||||
/* XXXX Execute monitor events here. */
|
||||
if (mon_) {
|
||||
mon_->event_function();
|
||||
mon_ = 0;
|
||||
}
|
||||
|
||||
/* The time cycle is done, delete it from the list and
|
||||
step to the next time. */
|
||||
struct vvm_simulation_cycle*next = sim_->next;
|
||||
if (next == sim_) {
|
||||
going_ = false;
|
||||
break;
|
||||
}
|
||||
|
||||
sim_->next->prev = sim_->prev;
|
||||
sim_->prev->next = sim_->next;
|
||||
delete sim_;
|
||||
sim_ = next;
|
||||
}
|
||||
vpip_simulation_run();
|
||||
}
|
||||
|
||||
class delay_event : public vvm_event {
|
||||
@@ -194,15 +69,6 @@ class delay_event : public vvm_event {
|
||||
vvm_thread*thr_;
|
||||
};
|
||||
|
||||
void vvm_simulation::s_finish()
|
||||
{
|
||||
going_ = false;
|
||||
}
|
||||
|
||||
bool vvm_simulation::finished() const
|
||||
{
|
||||
return !going_;
|
||||
}
|
||||
|
||||
void vvm_simulation::thread_delay(unsigned long delay, vvm_thread*thr)
|
||||
{
|
||||
@@ -219,6 +85,12 @@ void vvm_simulation::thread_active(vvm_thread*thr)
|
||||
|
||||
/*
|
||||
* $Log: vvm_simulation.cc,v $
|
||||
* Revision 1.7 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.6 1999/10/06 01:28:18 steve
|
||||
* The $finish task should work immediately.
|
||||
*
|
||||
|
||||
@@ -10,7 +10,87 @@ may be useful even independent of Xilinx parts.
|
||||
Icarus Verilog supports XNF as specified by the Xilinx Netlist Format
|
||||
Specification, Version 6.1.
|
||||
|
||||
IVL SUPPORT FOR XNF
|
||||
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 -fncf=prog.ncf -X prog.v
|
||||
|
||||
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
|
||||
|
||||
You can assign wires to pads using the Icarus Verilog $attribute
|
||||
extension. Attach to a scaler signal (wire or register) the PAD
|
||||
attribute with the value that specifies the direction and pin
|
||||
number. For example:
|
||||
|
||||
wire foo, bar, bid;
|
||||
$attribute(foo, "PAD", "i1"); // Input pad on pin 1
|
||||
$attribute(bar, "PAD", "o2"); // Output pad on pin 2
|
||||
$attribute(bid, "PAD", "b3"); // Bi-directional pad on pin 3
|
||||
|
||||
The XNFIO function uses these attributes to locate signals that are
|
||||
connected to pads, and generates XNF I/O block devices to connect to
|
||||
the pad to do the FPGA pin buffering that is needed. So the Verilog
|
||||
programmer need not in general specify the IBUF/OBUF buffers.
|
||||
|
||||
If the programmer does connect buffers to pads, the compiler will
|
||||
notice them and convert them to I/OBUFs automatically. For example:
|
||||
|
||||
buf b1 (sig, foo);
|
||||
|
||||
connects to pad foo, so will be converted into an XNF IBUF
|
||||
device. Also:
|
||||
|
||||
bufif1 bt (bar, value, en);
|
||||
|
||||
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
|
||||
naturally represent, although there are similar more generic Verilog
|
||||
devices. The most obvious and useful example is the clock driver,
|
||||
otherwise known as the global buffer BUFG. As with pads, Icarus
|
||||
Verilog uses the $attribute extension to allow you to specify special
|
||||
devices.
|
||||
|
||||
The $attribute statement can be applied to devices much the same way
|
||||
one applies them to wires. For example, to turn a buffer into a clock
|
||||
buffer:
|
||||
|
||||
wire iclk, clk;
|
||||
buf BUFG (clk, iclk);
|
||||
$attribute(iclk, "PAD", "i1");
|
||||
$attribute(BUFG, "XNF-LCA", "BUFG:O,I");
|
||||
|
||||
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 "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.
|
||||
|
||||
SUMMARY OF IVL SUPPORT FOR XNF
|
||||
|
||||
Icarus Verilog has a code generator and synthesis functions that
|
||||
support generation of XNF netlists. The XNF modules also allow the
|
||||
@@ -22,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
|
||||
@@ -38,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
|
||||
@@ -83,6 +176,23 @@ 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.
|
||||
|
||||
Revision 1.4 1999/08/14 22:48:21 steve
|
||||
Mention the sigfold function.
|
||||
|
||||
|
||||
@@ -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.2 1999/07/17 22:01:14 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,32 @@ 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
|
||||
// this will only work if the output of the bufif1 is
|
||||
// connected only to the pad. Handle bufif0 the same
|
||||
// way, but the T input is inverted.
|
||||
if ((tmp->type() == NetLogic::BUFIF1)
|
||||
&& (count_inputs(tmp->pin(0)) == 0)
|
||||
&& (count_outputs(tmp->pin(0)) == 1)
|
||||
&& (idx->get_pin() == 0) ) {
|
||||
tmp->attribute("XNF-LCA", "OBUFT:O,I,~T");
|
||||
return tmp;
|
||||
}
|
||||
|
||||
if ((tmp->type() == NetLogic::BUFIF0)
|
||||
&& (count_inputs(tmp->pin(0)) == 0)
|
||||
&& (count_outputs(tmp->pin(0)) == 1)
|
||||
&& (idx->get_pin() == 0) ) {
|
||||
tmp->attribute("XNF-LCA", "OBUFT:O,I,T");
|
||||
return tmp;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -107,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)
|
||||
@@ -156,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);
|
||||
}
|
||||
@@ -164,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;
|
||||
|
||||
@@ -176,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:
|
||||
@@ -195,6 +282,29 @@ 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.
|
||||
*
|
||||
* Revision 1.2 1999/07/17 22:01:14 steve
|
||||
* Add the functor interface for functor transforms.
|
||||
*
|
||||
|
||||
Reference in New Issue
Block a user