Compare commits

...
107 Commits
Author SHA1 Message Date
steve e67952240b Installation fixes for Debian. 1999-12-03 17:43:49 +00:00
steve 22d89c5984 Update case comparison (Eric Aardoom). 1999-12-02 16:58:58 +00:00
steve 88193a369f Handle mux sel of X, if inputs are equal. 1999-12-02 04:54:11 +00:00
steve cdb99e7638 Elaborate net repeat concatenations. 1999-12-02 04:08:10 +00:00
steve 99e145da48 shiftl and shiftr take unsized second parameter. 1999-12-02 03:36:01 +00:00
steve b30b695ff0 Redo synth to use match_proc_t scanner. 1999-12-01 06:06:16 +00:00
steve 998c039fd9 Match scope names as last resort. 1999-11-30 04:54:01 +00:00
steve 5ffac8adbf Handle evaluation of ternary during elaboration. 1999-11-30 04:48:17 +00:00
steve 80b8ea95bb Put implicitly defined signals in the scope. 1999-11-30 04:33:41 +00:00
steve 68a7ce3745 include getopt if present. 1999-11-29 17:02:21 +00:00
steve bb68753bd2 Properly initialize registers. 1999-11-29 00:38:27 +00:00
steve dab47610ed Remove useless tests for NetESignal. 1999-11-28 23:59:22 +00:00
steve e96e8c62be NetESignal object no longer need to be NetNode
objects. Let them keep a pointer to NetNet objects.
1999-11-28 23:42:02 +00:00
steve fa088f8baa Set VPI_MODULE_PATH in the target code, if desired. 1999-11-28 18:05:37 +00:00
steve 48b6726cf4 gate outputs need to set signal values. 1999-11-28 01:16:18 +00:00
steve bf42be12de Build up the lists in the scope of a module,
and get $dumpvars to scan the scope for items.
1999-11-28 00:56:08 +00:00
steve 4cfa3e4047 Support the creation of scopes. 1999-11-27 19:07:57 +00:00
steve ac25dc03a8 Reduce more gate templates to use vvm_1bit_out (Eric Aardoom) 1999-11-25 01:34:04 +00:00
steve 680c35a845 LT and GT fixes from Eric Aardoom. 1999-11-24 04:38:49 +00:00
steve 26288eeeb4 Detect and list scope names. 1999-11-24 04:01:58 +00:00
steve 3a69ab8934 support line directives with the line keyword. 1999-11-23 02:49:04 +00:00
steve cd3ed1959e A file name of - means standard input. 1999-11-23 01:04:57 +00:00
steve eb72a83e5f Detemplate some and, or and nor methods. 1999-11-22 00:30:52 +00:00
steve 85ab6d160b Handle multiply in constant expressions. 1999-11-21 20:03:24 +00:00
steve b769c7781e no -fno-exceptions to the C compiler. 1999-11-21 20:02:37 +00:00
steve 7324673bd1 Fix expression width of memory references. 1999-11-21 18:03:35 +00:00
steve 4cfa715092 Memory name lookup handles scopes. 1999-11-21 17:35:37 +00:00
steve b4aade1e4c Fix coding errors handling names of logic devices,
and add support for buf device in vvm.
1999-11-21 01:16:51 +00:00
steve a81dcd7955 Support memories in continuous assignments. 1999-11-21 00:13:08 +00:00
steve fae40cf380 handle duplicate connect to a nexus. 1999-11-19 05:02:37 +00:00
steve 28149e73e3 Handle inverted clock into OUTFF. 1999-11-19 05:02:15 +00:00
steve 8b81d6e416 Detect flip-flops connected to opads and turn
them into OUTFF devices. Inprove support for
 the XNF-LCA attribute in the process.
1999-11-19 03:02:25 +00:00
steve fbf0bf1fb7 Whoops, created a signal with a duplicate name. 1999-11-19 03:00:59 +00:00
steve 9d6392fda9 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.
1999-11-18 03:52:19 +00:00
steve 23ce3a9042 Handle (with a warning) unconnected opads. 1999-11-18 02:58:37 +00:00
steve 33946e188c Add algorithm for choosing nexus name from attached signals. 1999-11-17 18:52:09 +00:00
steve 477495c648 Clean up warnings that add_sub got from Alliance 1999-11-17 01:31:28 +00:00
steve 16f7268729 notice d and D in numbers. 1999-11-17 00:50:06 +00:00
steve a4a0ba670d Allow qualified identifiers. They really do work. 1999-11-15 04:43:52 +00:00
steve e98083af15 Fixup to include right shift support. 1999-11-15 00:42:31 +00:00
steve 513ade9b95 Support combinatorial comparators. 1999-11-14 23:43:45 +00:00
steve 1624afe1ba Add support for the LPM_CLSHIFT device. 1999-11-14 20:24:28 +00:00
steve 0eb6056ea6 Fix NAND gate support to use named pins. 1999-11-14 18:22:12 +00:00
steve 2602505885 Support the LPM_MUX in vvm. 1999-11-13 03:46:52 +00:00
steve 82f3f0f741 Create the vpiMemory handle type. 1999-11-10 02:52:24 +00:00
steve 02f8099aa7 Add VCD output and related system tasks. 1999-11-07 20:33:30 +00:00
steve 43ff33cd79 Add the $monitor implementation. 1999-11-07 02:25:07 +00:00
steve 2d1ace1dbc Unify display and strobe format routines. 1999-11-06 23:32:14 +00:00
steve 8d806d538b Get the $strobe task working. 1999-11-06 22:16:50 +00:00
steve 3fe0344246 complete value retrieval for number constants. 1999-11-06 16:52:16 +00:00
steve c688d95cb8 Put number constants into a static table. 1999-11-06 16:00:17 +00:00
steve 282c58040b Support writing some XNF things into an NCF file. 1999-11-06 04:51:42 +00:00
steve c18ea61994 Catch NetTmp objects. 1999-11-06 04:51:11 +00:00
steve 5171846d72 Forgot to return the mux for use after elaboration. 1999-11-05 23:36:31 +00:00
steve 206b37e5de Fix NetConst being set to zero width, and clean
up elaborate_set_cmp_ for NetEBinary.
1999-11-05 21:45:19 +00:00
steve f7526c6c4b parse drive strengths. 1999-11-05 19:36:36 +00:00
steve f827ad8625 fix syntax of EQN record. 1999-11-05 18:43:12 +00:00
steve 93a1f4853b Include the obvious XOR gates in the adders. 1999-11-05 07:10:45 +00:00
steve 2cce0ce238 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.
1999-11-05 04:40:40 +00:00
steve cb5fc54b5e 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.
1999-11-04 03:53:26 +00:00
steve 50e47c4173 Elaborate combinational UDP devices. 1999-11-04 01:12:41 +00:00
steve b3afc108cf XNF synthesis now uses the synth functor. 1999-11-03 05:18:18 +00:00
steve b66e7b1713 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.
1999-11-02 04:55:34 +00:00
steve 73753f1337 repair the sense of T from bufif01 1999-11-02 04:55:01 +00:00
steve 7195d4e8f1 Fix iobuf and iobufif handling. 1999-11-02 01:43:55 +00:00
steve 89881adece Add the synth functor to do generic synthesis
and add the LPM_FF device to handle rows of
 flip-flops.
1999-11-01 02:07:40 +00:00
steve f80c4a309e The + and - operators now work. 1999-11-01 01:17:21 +00:00
steve e1bbbe5614 Include subtraction in LPM_ADD_SUB device. 1999-10-31 20:08:24 +00:00
steve 71ecf8c143 Add to netlist links pin name and instance number,
and arrange in vvm for pin connections by name
 and instance number.
1999-10-31 04:11:27 +00:00
steve 5a2015ee67 Support vpiValueChance callbacks. 1999-10-29 03:37:22 +00:00
steve 0721615345 gate output pins use vpip_bit_t (Eric Aardoom) 1999-10-28 21:51:21 +00:00
steve 2862178a6f Get rid of monitor_t and fold __vpiSignal into signal. 1999-10-28 21:36:00 +00:00
steve 162b895e1b Put strings into a single string table. 1999-10-28 04:48:29 +00:00
steve bbf15778b8 Support delay in constSync callback. 1999-10-28 04:47:57 +00:00
steve d6450599d6 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.
1999-10-28 00:47:24 +00:00
steve 8bad04a020 cannonical make targets, and strip on install. 1999-10-23 16:55:51 +00:00
steve 409c8ff47d assignment to bit select is aa single bit. 1999-10-23 16:27:53 +00:00
steve 59e85dcffc Support build in different directory. 1999-10-22 23:58:13 +00:00
steve 2c774bfe75 do the <= in bits, not numbers. 1999-10-22 23:57:53 +00:00
steve 2e40152ff2 Make generated code ISO legal. 1999-10-21 02:15:06 +00:00
steve 8ab03fa90f Catch unindexed memory reference. 1999-10-18 00:02:21 +00:00
steve 07e2b2b828 ar -f flag is useless and incompatible. 1999-10-17 20:14:23 +00:00
steve 08175f5ebc VPI modules must be position-independent. 1999-10-17 20:14:05 +00:00
steve 2e15006dc0 More build instructions. 1999-10-16 21:22:06 +00:00
steve b24fa87de6 installdirs targets for what each directory installes. 1999-10-16 20:48:15 +00:00
steve a4143f8788 autoconf the verilog script to run anywhere. 1999-10-16 17:03:49 +00:00
steve 2fb754cd54 Parse empty source files. 1999-10-15 05:03:33 +00:00
steve bcbab34543 Special credit. 1999-10-15 02:55:21 +00:00
steve 475dd5760a Remove commented out do_assign. 1999-10-13 03:16:36 +00:00
steve 8f2a369588 Remove useless operator=. 1999-10-13 03:15:51 +00:00
steve 19b8615363 Support evaluating + operator at compile time. 1999-10-10 23:29:37 +00:00
steve 564f972aef Handle display of odd octal/hex widths (Eric Ardoom) 1999-10-10 14:57:38 +00:00
steve 86a2bf1961 Add Octal dump format. 1999-10-10 14:50:50 +00:00
steve 70a1236626 Structural case equals device. 1999-10-10 01:59:54 +00:00
steve 7201865554 Support parameters in continuous assignments. 1999-10-09 21:30:16 +00:00
steve a4298df776 NOR device. 1999-10-09 19:24:36 +00:00
steve aa11f57b57 Better message for combinational operators. 1999-10-09 19:24:04 +00:00
steve a4f3fa8997 support XNF OBUFT devices. 1999-10-09 17:52:27 +00:00
steve 9f860e319a Proper support for XNF synthesis. 1999-10-09 17:51:23 +00:00
steve 29abc5a69e Support + in constant expressions. 1999-10-08 17:48:08 +00:00
steve 0f919ab5f3 Add the %t formatting escape. 1999-10-08 17:47:49 +00:00
steve eb0103deb5 Start line directives with newline. 1999-10-08 17:27:56 +00:00
steve 5b7d783979 Accept adder parameters with different widths,
and simplify continuous assign construction.
1999-10-08 17:27:23 +00:00
steve 32e5eb6681 Fix too many -t with -t flag. 1999-10-08 17:27:09 +00:00
steve 213d02c4e5 support the -t switch. 1999-10-08 03:57:19 +00:00
steve 6997971884 vvm supports unary | operator. 1999-10-08 02:00:48 +00:00
steve 11eccfc033 Fix dump of sase statements. 1999-10-08 02:00:35 +00:00
71 changed files with 11057 additions and 2572 deletions
+38 -24
View File
@@ -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)
+6 -2
View File
@@ -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.
+7 -2
View File
@@ -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.
*
+68 -20
View File
@@ -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.
*
+5 -2
View File
@@ -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
View File
@@ -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.
Vendored Executable
+912
View File
@@ -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
Vendored Executable
+1178
View File
File diff suppressed because it is too large Load Diff
+2
View File
@@ -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
View File
@@ -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.
*
+10 -13
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
File diff suppressed because it is too large Load Diff
+79 -6
View File
@@ -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.
*
+67 -4
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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.
+20 -1
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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.
*
+29 -2
View File
@@ -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);
+26
View File
@@ -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.
+22 -2
View File
@@ -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
View File
File diff suppressed because it is too large Load Diff
+504 -79
View File
@@ -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
View File
@@ -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
View File
@@ -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.
*
*/
+24 -5
View File
@@ -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);
+8 -2
View File
@@ -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
View File
@@ -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
View File
@@ -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.
+210
View File
@@ -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.
*
*/
+475 -272
View File
File diff suppressed because it is too large Load Diff
+376 -24
View File
@@ -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.
*
+83 -8
View File
@@ -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.
*
+48 -2
View File
@@ -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
View File
@@ -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
View File
@@ -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.
*
+17 -2
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
+188
View File
@@ -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
View File
@@ -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.
*
*/
+77
View File
@@ -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.
*
*/
+91
View File
@@ -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.
*
*/
+47
View File
@@ -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
View File
@@ -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
View File
@@ -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.
*
+86
View File
@@ -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.
*
*/
+123
View File
@@ -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.
*
*/
+205
View File
@@ -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.
*
*/
+56
View File
@@ -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.
*
*/
+84
View File
@@ -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.
*
*/
+129 -102
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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.
*
+159
View File
@@ -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
View File
@@ -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
View File
@@ -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.
*
+120 -10
View File
@@ -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.
+125 -15
View File
@@ -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.
*