mirror of
https://github.com/steveicarus/iverilog.git
synced 2026-08-24 06:46:52 +02:00
Compare commits
217
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
e67952240b | ||
|
|
22d89c5984 | ||
|
|
88193a369f | ||
|
|
cdb99e7638 | ||
|
|
99e145da48 | ||
|
|
b30b695ff0 | ||
|
|
998c039fd9 | ||
|
|
5ffac8adbf | ||
|
|
80b8ea95bb | ||
|
|
68a7ce3745 | ||
|
|
bb68753bd2 | ||
|
|
dab47610ed | ||
|
|
e96e8c62be | ||
|
|
fa088f8baa | ||
|
|
48b6726cf4 | ||
|
|
bf42be12de | ||
|
|
4cfa3e4047 | ||
|
|
ac25dc03a8 | ||
|
|
680c35a845 | ||
|
|
26288eeeb4 | ||
|
|
3a69ab8934 | ||
|
|
cd3ed1959e | ||
|
|
eb72a83e5f | ||
|
|
85ab6d160b | ||
|
|
b769c7781e | ||
|
|
7324673bd1 | ||
|
|
4cfa715092 | ||
|
|
b4aade1e4c | ||
|
|
a81dcd7955 | ||
|
|
fae40cf380 | ||
|
|
28149e73e3 | ||
|
|
8b81d6e416 | ||
|
|
fbf0bf1fb7 | ||
|
|
9d6392fda9 | ||
|
|
23ce3a9042 | ||
|
|
33946e188c | ||
|
|
477495c648 | ||
|
|
16f7268729 | ||
|
|
a4a0ba670d | ||
|
|
e98083af15 | ||
|
|
513ade9b95 | ||
|
|
1624afe1ba | ||
|
|
0eb6056ea6 | ||
|
|
2602505885 | ||
|
|
82f3f0f741 | ||
|
|
02f8099aa7 | ||
|
|
43ff33cd79 | ||
|
|
2d1ace1dbc | ||
|
|
8d806d538b | ||
|
|
3fe0344246 | ||
|
|
c688d95cb8 | ||
|
|
282c58040b | ||
|
|
c18ea61994 | ||
|
|
5171846d72 | ||
|
|
206b37e5de | ||
|
|
f7526c6c4b | ||
|
|
f827ad8625 | ||
|
|
93a1f4853b | ||
|
|
2cce0ce238 | ||
|
|
cb5fc54b5e | ||
|
|
50e47c4173 | ||
|
|
b3afc108cf | ||
|
|
b66e7b1713 | ||
|
|
73753f1337 | ||
|
|
7195d4e8f1 | ||
|
|
89881adece | ||
|
|
f80c4a309e | ||
|
|
e1bbbe5614 | ||
|
|
71ecf8c143 | ||
|
|
5a2015ee67 | ||
|
|
0721615345 | ||
|
|
2862178a6f | ||
|
|
162b895e1b | ||
|
|
bbf15778b8 | ||
|
|
d6450599d6 | ||
|
|
8bad04a020 | ||
|
|
409c8ff47d | ||
|
|
59e85dcffc | ||
|
|
2c774bfe75 | ||
|
|
2e40152ff2 | ||
|
|
8ab03fa90f | ||
|
|
07e2b2b828 | ||
|
|
08175f5ebc | ||
|
|
2e15006dc0 | ||
|
|
b24fa87de6 | ||
|
|
a4143f8788 | ||
|
|
2fb754cd54 | ||
|
|
bcbab34543 | ||
|
|
475dd5760a | ||
|
|
8f2a369588 | ||
|
|
19b8615363 | ||
|
|
564f972aef | ||
|
|
86a2bf1961 | ||
|
|
70a1236626 | ||
|
|
7201865554 | ||
|
|
a4298df776 | ||
|
|
aa11f57b57 | ||
|
|
a4f3fa8997 | ||
|
|
9f860e319a | ||
|
|
29abc5a69e | ||
|
|
0f919ab5f3 | ||
|
|
eb0103deb5 | ||
|
|
5b7d783979 | ||
|
|
32e5eb6681 | ||
|
|
213d02c4e5 | ||
|
|
6997971884 | ||
|
|
11eccfc033 | ||
|
|
f949f96df1 | ||
|
|
1d215998b2 | ||
|
|
492d76e71d | ||
|
|
1cc68f745a | ||
|
|
4d8c0c79d6 | ||
|
|
a7f48c86e2 | ||
|
|
35e84f15d4 | ||
|
|
d513cf8f60 | ||
|
|
efdc1769e6 | ||
|
|
e1c697a746 | ||
|
|
393c9ab108 | ||
|
|
efa5222c66 | ||
|
|
f068196272 | ||
|
|
8317d8707e | ||
|
|
ed9aeec591 | ||
|
|
0c1c826410 | ||
|
|
c63a3acf93 | ||
|
|
b37fcf3593 | ||
|
|
6e486e9bcf | ||
|
|
076cecb6cd | ||
|
|
42006ec5f1 | ||
|
|
db7044850a | ||
|
|
5ee7cfb854 | ||
|
|
93f05306e7 | ||
|
|
8e21f0f363 | ||
|
|
b2f7f533f7 | ||
|
|
2271fc9894 | ||
|
|
a64a33e65a | ||
|
|
3a415fb04c | ||
|
|
0c7722ce7e | ||
|
|
86a283b9bc | ||
|
|
0fb4ba7907 | ||
|
|
f274c9cade | ||
|
|
4882f04945 | ||
|
|
a8a2b3e8f3 | ||
|
|
900949ab56 | ||
|
|
9f30615a91 | ||
|
|
a964e0479b | ||
|
|
6d7ac5d67b | ||
|
|
470b0d3d34 | ||
|
|
bb38653654 | ||
|
|
fb678877d7 | ||
|
|
64cc38f0eb | ||
|
|
1a21d2fe9d | ||
|
|
095995f09c | ||
|
|
851daff66f | ||
|
|
1b7261a393 | ||
|
|
1c41f8ebd2 | ||
|
|
59b1b4c7b9 | ||
|
|
0955058fbe | ||
|
|
12b9071f49 | ||
|
|
357461b034 | ||
|
|
4a0e7d56bd | ||
|
|
da4a7ea80a | ||
|
|
fcfa9d004a | ||
|
|
349f9ae302 | ||
|
|
3a5e55b229 | ||
|
|
1f44822510 | ||
|
|
6df3febada | ||
|
|
5fde1b3e05 | ||
|
|
fbf104bf4d | ||
|
|
dab04c221d | ||
|
|
251eb4f38f | ||
|
|
424e6a750c | ||
|
|
4594ac1c2c | ||
|
|
d904aceb2c | ||
|
|
a890724b40 | ||
|
|
31bdb87c8f | ||
|
|
b04148b754 | ||
|
|
f36c511c2f | ||
|
|
39bc45ce67 | ||
|
|
3d78b558bc | ||
|
|
54d38ac057 | ||
|
|
7a211b9136 | ||
|
|
6847dac5c2 | ||
|
|
a3e9a7417d | ||
|
|
25d6912217 | ||
|
|
1c238f1948 | ||
|
|
287d21f300 | ||
|
|
a6c6ac2191 | ||
|
|
d6fbc30cd5 | ||
|
|
9d82d19d07 | ||
|
|
006a2cce83 | ||
|
|
8f68a07476 | ||
|
|
555d447180 | ||
|
|
41a1c6bb02 | ||
|
|
6fb7120158 | ||
|
|
9f7eb4a935 | ||
|
|
5ee83fce70 | ||
|
|
e69345b9fe | ||
|
|
1c11c864d5 | ||
|
|
58d05dfca2 | ||
|
|
7d71abaa05 | ||
|
|
6b3b6f3384 | ||
|
|
0fe25f68f9 | ||
|
|
3017636c05 | ||
|
|
23acca48ff | ||
|
|
648e4c68e4 | ||
|
|
9eae940ebd | ||
|
|
0175a4fce0 | ||
|
|
aba4a877db | ||
|
|
031d91f813 | ||
|
|
f1fdce78be | ||
|
|
b119613a8a | ||
|
|
567badc7af | ||
|
|
b62f094874 | ||
|
|
28c0691b5f | ||
|
|
2d0e11283d | ||
|
|
f1825c54a7 | ||
|
|
cf1abfe38c |
@@ -6,6 +6,7 @@ ivl
|
||||
dep
|
||||
configure
|
||||
Makefile
|
||||
verilog
|
||||
config.status
|
||||
config.log
|
||||
config.cache
|
||||
|
||||
+61
-21
@@ -18,7 +18,7 @@
|
||||
# 59 Temple Place - Suite 330
|
||||
# Boston, MA 02111-1307, USA
|
||||
#
|
||||
#ident "$Id: Makefile.in,v 1.11 1999/08/07 20:05:51 steve Exp $"
|
||||
#ident "$Id: Makefile.in,v 1.24.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
|
||||
mandir = @mandir@
|
||||
includedir = $(prefix)/include
|
||||
|
||||
CC = @CC@
|
||||
@@ -40,32 +41,58 @@ 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
|
||||
cd vvm ; make all
|
||||
cd ivlpp ; make all
|
||||
all: ivl verilog
|
||||
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 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
|
||||
|
||||
O = main.o cprop.o design_dump.o elaborate.o emit.o eval.o functor.o \
|
||||
lexor.o mangle.o netlist.o parse.o parse_misc.o pform.o pform_dump.o \
|
||||
verinum.o verireal.o target.o targets.o Module.o PExpr.o PGate.o \
|
||||
O = main.o cprop.o design_dump.o elaborate.o elab_expr.o emit.o eval.o \
|
||||
eval_tree.o functor.o \
|
||||
lexor.o lexor_keyword.o mangle.o netlist.o pad_to_width.o \
|
||||
parse.o parse_misc.o pform.o pform_dump.o \
|
||||
set_width.o \
|
||||
verinum.o verireal.o target.o targets.o Module.o PDelays.o PExpr.o PGate.o \
|
||||
PTask.o PFunction.o PWire.o Statement.o \
|
||||
$(FF) $(TT)
|
||||
|
||||
Makefile: Makefile.in config.status
|
||||
./config.status
|
||||
|
||||
# Make the actual verilog program from the script template. This
|
||||
# simply invloves editing the substitution strings in the script into
|
||||
# the configured copy.
|
||||
tmp1 = bindir
|
||||
tmp2 = libdir
|
||||
tmp3 = includedir
|
||||
tmp4 = CXX
|
||||
verilog: $(srcdir)/verilog.sh
|
||||
sed -e 's;@$(tmp1)@;@bindir@;' \
|
||||
-e 's;@$(tmp2)@;@libdir@;' \
|
||||
-e 's;@$(tmp3)@;@includedir@;' \
|
||||
-e 's;@$(tmp4)@;@CXX@;' < $< > $@
|
||||
|
||||
ivl: $O
|
||||
$(CXX) $(CXXFLAGS) -o ivl $O
|
||||
|
||||
@@ -79,25 +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)/ivl
|
||||
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)/ivl: ivl
|
||||
$(INSTALL_PROGRAM) ./ivl $(bindir)/ivl
|
||||
$(bindir)/verilog: ./verilog
|
||||
$(INSTALL_PROGRAM) ./verilog $(bindir)/verilog
|
||||
|
||||
$(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
|
||||
|
||||
|
||||
-include $(patsubst %.o, dep/%.d, $O)
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
|
||||
*/
|
||||
#if !defined(WINNT)
|
||||
#ident "$Id: Module.cc,v 1.6 1999/08/04 02:13:02 steve Exp $"
|
||||
#ident "$Id: Module.cc,v 1.7 1999/09/17 02:06:25 steve Exp $"
|
||||
#endif
|
||||
|
||||
# include "Module.h"
|
||||
@@ -30,6 +30,8 @@ Module::Module(const string&name, const svector<Module::port_t*>*pp)
|
||||
ports_ = *pp;
|
||||
for (unsigned idx = 0 ; idx < ports_.count() ; idx += 1) {
|
||||
port_t*cur = ports_[idx];
|
||||
if (cur == 0)
|
||||
continue;
|
||||
for (unsigned jdx = 0 ; jdx < cur->wires.count() ; jdx += 1)
|
||||
add_wire(cur->wires[jdx]);
|
||||
}
|
||||
@@ -99,6 +101,9 @@ PWire* Module::get_wire(const string&name)
|
||||
|
||||
/*
|
||||
* $Log: Module.cc,v $
|
||||
* Revision 1.7 1999/09/17 02:06:25 steve
|
||||
* Handle unconnected module ports.
|
||||
*
|
||||
* Revision 1.6 1999/08/04 02:13:02 steve
|
||||
* Elaborate module ports that are concatenations of
|
||||
* module signals.
|
||||
|
||||
@@ -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.8 1999/08/04 02:13:02 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
|
||||
@@ -64,6 +65,14 @@ class Module {
|
||||
into this map. */
|
||||
map<string,PExpr*>parameters;
|
||||
|
||||
/* Parameters may be overridden at instantiation time;
|
||||
the overrides do not contain explicit parameter names,
|
||||
but rather refer to parameters in the order they
|
||||
appear in the instantiated module. Therefore a
|
||||
list of names in module-order is needed to pass from
|
||||
a parameter-index to its name. */
|
||||
list<string> param_names;
|
||||
|
||||
const string&get_name() const { return name_; }
|
||||
|
||||
void add_gate(PGate*gate);
|
||||
@@ -85,7 +94,7 @@ class Module {
|
||||
const list<PProcess*>& get_behaviors() const { return behaviors_; }
|
||||
|
||||
void dump(ostream&out) const;
|
||||
bool elaborate(Design*, const string&path) const;
|
||||
bool elaborate(Design*, NetScope*scope, svector<PExpr*>*overrides_) const;
|
||||
|
||||
private:
|
||||
const string name_;
|
||||
@@ -105,6 +114,13 @@ 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.
|
||||
*
|
||||
* Revision 1.8 1999/08/04 02:13:02 steve
|
||||
* Elaborate module ports that are concatenations of
|
||||
* module signals.
|
||||
|
||||
+103
@@ -0,0 +1,103 @@
|
||||
/*
|
||||
* 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: PDelays.cc,v 1.1 1999/09/04 19:11:46 steve Exp $"
|
||||
#endif
|
||||
|
||||
# include "PDelays.h"
|
||||
# include "PExpr.h"
|
||||
# include "verinum.h"
|
||||
|
||||
PDelays::PDelays()
|
||||
{
|
||||
for (unsigned idx = 0 ; idx < 3 ; idx += 1)
|
||||
delay_[idx] = 0;
|
||||
}
|
||||
|
||||
PDelays::~PDelays()
|
||||
{
|
||||
for (unsigned idx = 0 ; idx < 3 ; idx += 1)
|
||||
delete delay_[idx];
|
||||
}
|
||||
|
||||
void PDelays::set_delay(PExpr*del)
|
||||
{
|
||||
assert(del);
|
||||
assert(delay_[0] == 0);
|
||||
delay_[0] = del;
|
||||
}
|
||||
|
||||
|
||||
void PDelays::set_delays(const svector<PExpr*>*del)
|
||||
{
|
||||
assert(del);
|
||||
assert(del->count() <= 3);
|
||||
for (unsigned idx = 0 ; idx < del->count() ; idx += 1)
|
||||
delay_[idx] = (*del)[idx];
|
||||
}
|
||||
|
||||
void PDelays::eval_delays(Design*des, const string&path,
|
||||
unsigned long&rise_time,
|
||||
unsigned long&fall_time,
|
||||
unsigned long&decay_time) const
|
||||
{
|
||||
verinum*dv;
|
||||
|
||||
if (delay_[0]) {
|
||||
dv = delay_[0]->eval_const(des, path);
|
||||
assert(dv);
|
||||
rise_time = dv->as_ulong();
|
||||
delete dv;
|
||||
|
||||
if (delay_[1]) {
|
||||
dv = delay_[1]->eval_const(des, path);
|
||||
assert(dv);
|
||||
fall_time = dv->as_ulong();
|
||||
delete dv;
|
||||
|
||||
if (delay_[2]) {
|
||||
dv = delay_[2]->eval_const(des, path);
|
||||
assert(dv);
|
||||
decay_time = dv->as_ulong();
|
||||
delete dv;
|
||||
} else {
|
||||
if (rise_time < fall_time)
|
||||
decay_time = rise_time;
|
||||
else
|
||||
decay_time = fall_time;
|
||||
}
|
||||
} else {
|
||||
assert(delay_[2] == 0);
|
||||
fall_time = rise_time;
|
||||
decay_time = rise_time;
|
||||
}
|
||||
} else {
|
||||
rise_time = 0;
|
||||
fall_time = 0;
|
||||
decay_time = 0;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* $Log: PDelays.cc,v $
|
||||
* Revision 1.1 1999/09/04 19:11:46 steve
|
||||
* Add support for delayed non-blocking assignments.
|
||||
*
|
||||
*/
|
||||
|
||||
@@ -0,0 +1,67 @@
|
||||
#ifndef __PDelays_H
|
||||
#define __PDelays_H
|
||||
/*
|
||||
* 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: PDelays.h,v 1.1 1999/09/04 19:11:46 steve Exp $"
|
||||
#endif
|
||||
|
||||
# include "svector.h"
|
||||
# include <string>
|
||||
class Design;
|
||||
class PExpr;
|
||||
class ostream;
|
||||
|
||||
/*
|
||||
* Various PForm objects can carry delays. These delays include rise,
|
||||
* fall and decay times. This class arranges to carry the triplet.
|
||||
*/
|
||||
class PDelays {
|
||||
|
||||
public:
|
||||
PDelays();
|
||||
~PDelays();
|
||||
|
||||
void set_delay(PExpr*);
|
||||
void set_delays(const svector<PExpr*>*del);
|
||||
|
||||
void eval_delays(Design*des, const string&path,
|
||||
unsigned long&rise_time,
|
||||
unsigned long&fall_time,
|
||||
unsigned long&decay_time) const;
|
||||
|
||||
void dump_delays(ostream&out) const;
|
||||
|
||||
private:
|
||||
PExpr* delay_[3];
|
||||
|
||||
private: // not implemented
|
||||
PDelays(const PDelays&);
|
||||
PDelays& operator= (const PDelays&);
|
||||
};
|
||||
|
||||
ostream& operator << (ostream&o, const PDelays&);
|
||||
|
||||
/*
|
||||
* $Log: PDelays.h,v $
|
||||
* Revision 1.1 1999/09/04 19:11:46 steve
|
||||
* Add support for delayed non-blocking assignments.
|
||||
*
|
||||
*/
|
||||
#endif
|
||||
@@ -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.7 1999/07/22 02:05:20 steve Exp $"
|
||||
#ident "$Id: PExpr.cc,v 1.11 1999/10/31 04:11:27 steve Exp $"
|
||||
#endif
|
||||
|
||||
# include "PExpr.h"
|
||||
@@ -38,14 +38,40 @@ bool PExpr::is_constant(Module*) const
|
||||
return false;
|
||||
}
|
||||
|
||||
NetNet* PExpr::elaborate_net(Design*des, const string&path, unsigned,
|
||||
unsigned long,
|
||||
unsigned long,
|
||||
unsigned long) const
|
||||
{
|
||||
cerr << "Don't know how to elaborate `" << *this
|
||||
<< "' as gates." << endl;
|
||||
return 0;
|
||||
}
|
||||
|
||||
NetNet* PExpr::elaborate_lnet(Design*des, const string&path) const
|
||||
{
|
||||
cerr << get_line() << ": expression not valid in assign l-value: "
|
||||
<< *this << endl;
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool PEBinary::is_constant(Module*mod) const
|
||||
{
|
||||
return left_->is_constant(mod) && right_->is_constant(mod);
|
||||
}
|
||||
|
||||
PECallFunction::PECallFunction(const string &n, const svector<PExpr *> &parms)
|
||||
: name_(n), parms_(parms)
|
||||
{
|
||||
}
|
||||
|
||||
PECallFunction::~PECallFunction()
|
||||
{
|
||||
}
|
||||
|
||||
bool PEConcat::is_constant(Module *mod) const
|
||||
{
|
||||
bool constant = repeat_->is_constant(mod);
|
||||
bool constant = repeat_? repeat_->is_constant(mod) : true;
|
||||
for (unsigned i = 0; constant && i < parms_.count(); ++i) {
|
||||
constant = constant && parms_[i]->is_constant(mod);
|
||||
}
|
||||
@@ -102,6 +128,20 @@ 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.
|
||||
*
|
||||
* Revision 1.9 1999/09/16 04:18:15 steve
|
||||
* elaborate concatenation repeats.
|
||||
*
|
||||
* Revision 1.8 1999/09/15 04:17:52 steve
|
||||
* separate assign lval elaboration for error checking.
|
||||
*
|
||||
* Revision 1.7 1999/07/22 02:05:20 steve
|
||||
* is_constant method for PEConcat.
|
||||
*
|
||||
|
||||
@@ -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.17 1999/08/01 21:18:55 steve Exp $"
|
||||
#ident "$Id: PExpr.h,v 1.25 1999/11/21 00:13:08 steve Exp $"
|
||||
#endif
|
||||
|
||||
# include <string>
|
||||
@@ -47,12 +47,22 @@ class PExpr : public LineInfo {
|
||||
virtual ~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;
|
||||
|
||||
// Procedural elaboration of the expression.
|
||||
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 wholly structural context.
|
||||
virtual NetNet* elaborate_net(Design*des, const string&path,
|
||||
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.
|
||||
virtual NetNet* elaborate_lnet(Design*des, const string&path) const;
|
||||
|
||||
// This attempts to evaluate a constant expression, and return
|
||||
// a verinum as a result. If the expression cannot be
|
||||
// evaluated, return 0.
|
||||
@@ -68,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&);
|
||||
@@ -80,10 +91,12 @@ class PEConcat : public PExpr {
|
||||
~PEConcat();
|
||||
|
||||
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;
|
||||
|
||||
@@ -116,11 +129,19 @@ class PEIdent : public PExpr {
|
||||
: text_(s), msb_(0), lsb_(0), idx_(0) { }
|
||||
|
||||
virtual void dump(ostream&) const;
|
||||
|
||||
// Identifiers are allowed (with restrictions) is assign l-values.
|
||||
virtual NetNet* elaborate_lnet(Design*des, const string&path) const;
|
||||
|
||||
// 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;
|
||||
|
||||
virtual bool is_constant(Module*) const;
|
||||
verinum* eval_const(const Design*des, const string&path) const;
|
||||
|
||||
@@ -138,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 {
|
||||
@@ -151,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;
|
||||
|
||||
@@ -188,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:
|
||||
@@ -208,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;
|
||||
|
||||
@@ -218,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;
|
||||
};
|
||||
|
||||
/*
|
||||
@@ -234,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;
|
||||
@@ -246,22 +293,53 @@ class PETernary : public PExpr {
|
||||
PExpr*fal_;
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
* This class represents a parsed call to a function.
|
||||
*/
|
||||
class PECallFunction : public PExpr {
|
||||
public:
|
||||
explicit PECallFunction(const string &n, const svector<PExpr *> &parms)
|
||||
: name_(n), parms_(parms) {}
|
||||
~PECallFunction() {}
|
||||
public:
|
||||
explicit PECallFunction(const string &n, const svector<PExpr *> &parms);
|
||||
~PECallFunction();
|
||||
|
||||
virtual void dump(ostream &) const;
|
||||
virtual NetExpr*elaborate_expr(Design*des, const string&path) const;
|
||||
|
||||
private:
|
||||
private:
|
||||
string name_;
|
||||
svector<PExpr *> parms_;
|
||||
|
||||
NetESFunc* elaborate_sfunc_(Design*des, const string&path) const;
|
||||
};
|
||||
|
||||
/*
|
||||
* $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.
|
||||
*
|
||||
* Revision 1.19 1999/09/15 04:17:52 steve
|
||||
* separate assign lval elaboration for error checking.
|
||||
*
|
||||
* Revision 1.18 1999/08/31 22:38:29 steve
|
||||
* Elaborate and emit to vvm procedural functions.
|
||||
*
|
||||
* Revision 1.17 1999/08/01 21:18:55 steve
|
||||
* elaborate rise/fall/decay for continuous assign.
|
||||
*
|
||||
|
||||
+36
-1
@@ -1,10 +1,45 @@
|
||||
/*
|
||||
* 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: PFunction.cc,v 1.2 1999/08/25 22:22:41 steve Exp $"
|
||||
#endif
|
||||
|
||||
#include "PTask.h"
|
||||
|
||||
PFunction::PFunction(svector<PWire*>*p, Statement*s)
|
||||
: ports_(p), statement_(s)
|
||||
: out_(0), ports_(p), statement_(s)
|
||||
{
|
||||
}
|
||||
|
||||
PFunction::~PFunction()
|
||||
{
|
||||
}
|
||||
|
||||
void PFunction::set_output(PWire*o)
|
||||
{
|
||||
assert(out_ == 0);
|
||||
out_ = o;
|
||||
}
|
||||
|
||||
/*
|
||||
* $Log: PFunction.cc,v $
|
||||
* Revision 1.2 1999/08/25 22:22:41 steve
|
||||
* elaborate some aspects of functions.
|
||||
*
|
||||
*/
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
|
||||
*/
|
||||
#if !defined(WINNT)
|
||||
#ident "$Id: PGate.cc,v 1.3 1999/08/01 21:18:55 steve Exp $"
|
||||
#ident "$Id: PGate.cc,v 1.5 1999/09/14 01:50:35 steve Exp $"
|
||||
#endif
|
||||
|
||||
# include "PGate.h"
|
||||
@@ -30,14 +30,7 @@ PGate::PGate(const string&name,
|
||||
const svector<PExpr*>*del)
|
||||
: name_(name), pins_(pins)
|
||||
{
|
||||
for (unsigned idx = 0 ; idx < 3 ; idx += 1)
|
||||
delay_[idx] = 0;
|
||||
|
||||
if (del) {
|
||||
assert(del->count() <= 3);
|
||||
for (unsigned idx = 0 ; idx < del->count() ; idx += 1)
|
||||
delay_[idx] = (*del)[idx];
|
||||
}
|
||||
if (del) delay_.set_delays(del);
|
||||
}
|
||||
|
||||
PGate::PGate(const string&name,
|
||||
@@ -45,23 +38,16 @@ PGate::PGate(const string&name,
|
||||
PExpr*del)
|
||||
: name_(name), pins_(pins)
|
||||
{
|
||||
delay_[0] = del;
|
||||
delay_[1] = 0;
|
||||
delay_[2] = 0;
|
||||
if (del) delay_.set_delay(del);
|
||||
}
|
||||
|
||||
PGate::PGate(const string&name, svector<PExpr*>*pins)
|
||||
: name_(name), pins_(pins)
|
||||
{
|
||||
delay_[0] = 0;
|
||||
delay_[1] = 0;
|
||||
delay_[2] = 0;
|
||||
}
|
||||
|
||||
PGate::~PGate()
|
||||
{
|
||||
for (unsigned idx = 0 ; idx < 3 ; idx += 1)
|
||||
delete delay_[idx];
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -77,41 +63,7 @@ void PGate::eval_delays(Design*des, const string&path,
|
||||
unsigned long&fall_time,
|
||||
unsigned long&decay_time) const
|
||||
{
|
||||
verinum*dv;
|
||||
|
||||
if (delay_[0]) {
|
||||
dv = delay_[0]->eval_const(des, path);
|
||||
assert(dv);
|
||||
rise_time = dv->as_ulong();
|
||||
delete dv;
|
||||
|
||||
if (delay_[1]) {
|
||||
dv = delay_[1]->eval_const(des, path);
|
||||
assert(dv);
|
||||
fall_time = dv->as_ulong();
|
||||
delete dv;
|
||||
|
||||
if (delay_[2]) {
|
||||
dv = delay_[2]->eval_const(des, path);
|
||||
assert(dv);
|
||||
decay_time = dv->as_ulong();
|
||||
delete dv;
|
||||
} else {
|
||||
if (rise_time < fall_time)
|
||||
decay_time = rise_time;
|
||||
else
|
||||
decay_time = fall_time;
|
||||
}
|
||||
} else {
|
||||
assert(delay_[2] == 0);
|
||||
fall_time = rise_time;
|
||||
decay_time = rise_time;
|
||||
}
|
||||
} else {
|
||||
rise_time = 0;
|
||||
fall_time = 0;
|
||||
decay_time = 0;
|
||||
}
|
||||
delay_.eval_delays(des, path, rise_time, fall_time, decay_time);
|
||||
}
|
||||
|
||||
PGAssign::PGAssign(svector<PExpr*>*pins)
|
||||
@@ -160,6 +112,12 @@ void PGBuiltin::set_range(PExpr*msb, PExpr*lsb)
|
||||
|
||||
/*
|
||||
* $Log: PGate.cc,v $
|
||||
* Revision 1.5 1999/09/14 01:50:35 steve
|
||||
* Handle gates without delays.
|
||||
*
|
||||
* Revision 1.4 1999/09/04 19:11:46 steve
|
||||
* Add support for delayed non-blocking assignments.
|
||||
*
|
||||
* Revision 1.3 1999/08/01 21:18:55 steve
|
||||
* elaborate rise/fall/decay for continuous assign.
|
||||
*
|
||||
|
||||
@@ -19,11 +19,12 @@
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
|
||||
*/
|
||||
#if !defined(WINNT)
|
||||
#ident "$Id: PGate.h,v 1.8 1999/08/01 21:18:55 steve Exp $"
|
||||
#ident "$Id: PGate.h,v 1.10 1999/09/04 19:11:46 steve Exp $"
|
||||
#endif
|
||||
|
||||
# include "svector.h"
|
||||
# include "LineInfo.h"
|
||||
# include "PDelays.h"
|
||||
class PExpr;
|
||||
class PUdp;
|
||||
class Design;
|
||||
@@ -72,7 +73,7 @@ class PGate : public LineInfo {
|
||||
|
||||
private:
|
||||
const string name_;
|
||||
PExpr* delay_[3];
|
||||
PDelays delay_;
|
||||
svector<PExpr*>*pins_;
|
||||
|
||||
private: // not implemented
|
||||
@@ -150,8 +151,8 @@ class PGModule : public PGate {
|
||||
// If the binding of ports is by position, this constructor
|
||||
// builds everything all at once.
|
||||
explicit PGModule(const string&type, const string&name,
|
||||
svector<PExpr*>*pins)
|
||||
: PGate(name, pins), type_(type), pins_(0), npins_(0) { }
|
||||
svector<PExpr*>*overrides, svector<PExpr*>*pins)
|
||||
: PGate(name, pins), type_(type), overrides_(overrides), pins_(0), npins_(0) { }
|
||||
|
||||
// If the binding of ports is by name, this constructor takes
|
||||
// the bindings and stores them for later elaboration.
|
||||
@@ -160,8 +161,8 @@ class PGModule : public PGate {
|
||||
PExpr* parm;
|
||||
};
|
||||
explicit PGModule(const string&type, const string&name,
|
||||
bind_t*pins, unsigned npins)
|
||||
: PGate(name, 0), type_(type), pins_(pins), npins_(npins) { }
|
||||
svector<PExpr*>*overrides, bind_t*pins, unsigned npins)
|
||||
: PGate(name, 0), type_(type), overrides_(overrides), pins_(pins), npins_(npins) { }
|
||||
|
||||
|
||||
virtual void dump(ostream&out) const;
|
||||
@@ -169,6 +170,7 @@ class PGModule : public PGate {
|
||||
|
||||
private:
|
||||
string type_;
|
||||
svector<PExpr*>*overrides_;
|
||||
bind_t*pins_;
|
||||
unsigned npins_;
|
||||
|
||||
@@ -178,6 +180,13 @@ class PGModule : public PGate {
|
||||
|
||||
/*
|
||||
* $Log: PGate.h,v $
|
||||
* Revision 1.10 1999/09/04 19:11:46 steve
|
||||
* Add support for delayed non-blocking assignments.
|
||||
*
|
||||
* Revision 1.9 1999/08/23 16:48:39 steve
|
||||
* Parameter overrides support from Peter Monta
|
||||
* AND and XOR support wide expressions.
|
||||
*
|
||||
* Revision 1.8 1999/08/01 21:18:55 steve
|
||||
* elaborate rise/fall/decay for continuous assign.
|
||||
*
|
||||
|
||||
@@ -19,7 +19,7 @@
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
|
||||
*/
|
||||
#if !defined(WINNT)
|
||||
#ident "$Id: PTask.h,v 1.3 1999/07/31 19:14:47 steve Exp $"
|
||||
#ident "$Id: PTask.h,v 1.6 1999/09/30 21:28:34 steve Exp $"
|
||||
#endif
|
||||
|
||||
# include "LineInfo.h"
|
||||
@@ -38,7 +38,9 @@ class PTask : public LineInfo {
|
||||
explicit PTask(svector<PWire*>*p, Statement*s);
|
||||
~PTask();
|
||||
|
||||
virtual void elaborate(Design*des, const string&path) const;
|
||||
void elaborate_1(Design*des, const string&path) const;
|
||||
void elaborate_2(Design*des, const string&path) const;
|
||||
|
||||
void dump(ostream&, unsigned) const;
|
||||
|
||||
private:
|
||||
@@ -50,21 +52,45 @@ class PTask : public LineInfo {
|
||||
PTask& operator=(const PTask&);
|
||||
};
|
||||
|
||||
/*
|
||||
* The function is similar to a task (in this context) but there is a
|
||||
* single output port and a set of input ports. The output port is the
|
||||
* function return value.
|
||||
*/
|
||||
class PFunction : public LineInfo {
|
||||
public:
|
||||
explicit PFunction(svector<PWire *> *p, Statement *s);
|
||||
|
||||
public:
|
||||
explicit PFunction(svector<PWire *>*p, Statement *s);
|
||||
~PFunction();
|
||||
|
||||
//virtual void elaborate(Design *des, const string &path) const {}
|
||||
void set_output(PWire*);
|
||||
|
||||
/* Functions are elaborated in 2 passes. */
|
||||
void elaborate_1(Design *des, const string &path) const;
|
||||
void elaborate_2(Design *des, const string &path) const;
|
||||
|
||||
void dump(ostream&, unsigned) const;
|
||||
|
||||
private:
|
||||
private:
|
||||
PWire*out_;
|
||||
svector<PWire *> *ports_;
|
||||
Statement *statement_;
|
||||
};
|
||||
|
||||
/*
|
||||
* $Log: PTask.h,v $
|
||||
* Revision 1.6 1999/09/30 21:28:34 steve
|
||||
* Handle mutual reference of tasks by elaborating
|
||||
* task definitions in two passes, like functions.
|
||||
*
|
||||
* Revision 1.5 1999/09/01 20:46:19 steve
|
||||
* Handle recursive functions and arbitrary function
|
||||
* references to other functions, properly pass
|
||||
* function parameters and save function results.
|
||||
*
|
||||
* Revision 1.4 1999/08/25 22:22:41 steve
|
||||
* elaborate some aspects of functions.
|
||||
*
|
||||
* Revision 1.3 1999/07/31 19:14:47 steve
|
||||
* Add functions up to elaboration (Ed Carter)
|
||||
*
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
|
||||
*/
|
||||
#if !defined(WINNT)
|
||||
#ident "$Id: PWire.cc,v 1.1 1999/06/17 05:34:42 steve Exp $"
|
||||
#ident "$Id: PWire.cc,v 1.2 1999/09/10 05:02:09 steve Exp $"
|
||||
#endif
|
||||
|
||||
# include "PWire.h"
|
||||
@@ -41,6 +41,10 @@ bool PWire::set_wire_type(NetNet::Type t)
|
||||
case NetNet::IMPLICIT:
|
||||
type_ = t;
|
||||
return true;
|
||||
case NetNet::IMPLICIT_REG:
|
||||
if (t == NetNet::REG) { type_ = t; return true; }
|
||||
if (t == NetNet::INTEGER) {type_ = t; return true; }
|
||||
return false;
|
||||
case NetNet::REG:
|
||||
if (t == NetNet::REG) return true;
|
||||
if (t == NetNet::INTEGER) {type_ = t; return true; }
|
||||
@@ -96,6 +100,9 @@ void PWire::set_memory_idx(PExpr*ldx, PExpr*rdx)
|
||||
|
||||
/*
|
||||
* $Log: PWire.cc,v $
|
||||
* Revision 1.2 1999/09/10 05:02:09 steve
|
||||
* Handle integers at task parameters.
|
||||
*
|
||||
* Revision 1.1 1999/06/17 05:34:42 steve
|
||||
* Clean up interface of the PWire class,
|
||||
* Properly match wire ranges.
|
||||
|
||||
@@ -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.
|
||||
|
||||
+139
-81
@@ -1,53 +1,101 @@
|
||||
THE ICARUS VERILOG COMPILATION SYSTEM
|
||||
July 7, 1999
|
||||
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.
|
||||
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/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
|
||||
processing steps that transform the design to more optimal/practical
|
||||
forms, then passed to a code generator for final output. The
|
||||
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
|
||||
output that is equivalent but without the directives. See
|
||||
ivlpp/ivlpp.txt for details.
|
||||
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
|
||||
(see pform.h) is mostly a direct reflection of the compilation
|
||||
unit. There may be dangling references, and it is not yet clear which
|
||||
step. There may be dangling references, and it is not yet clear which
|
||||
module is the root.
|
||||
|
||||
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,
|
||||
resolves references and expands the instantiations to form the design
|
||||
netlist. (See netlist.txt.)
|
||||
netlist. (See netlist.txt.) Final semantic checks are performed during
|
||||
elaboration, and some simple optimizations are performed.
|
||||
|
||||
The elaborate() function performs the elaboration.
|
||||
|
||||
@@ -56,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
|
||||
@@ -69,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
|
||||
@@ -82,25 +130,14 @@ 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
|
||||
4.0 Running Verilog
|
||||
|
||||
Unpack the tar-ball and cd into the verilog-######### directory.
|
||||
The preferred way to invoke the compiler with the verilog(1)
|
||||
command. This program invokes the preprocessor (ivlpp) and the
|
||||
compiler (ivl) with the proper command line options to get the job
|
||||
done in a friendly way. See the verilog(1) man page for usage details.
|
||||
|
||||
./configure
|
||||
make
|
||||
cd vvm
|
||||
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
|
||||
cd vvm
|
||||
make install
|
||||
|
||||
4.0 Running IVL
|
||||
4.1 Running IVL Directly
|
||||
|
||||
The ivl command is the compiler driver, that invokes the parser,
|
||||
optimization functions and the code generator.
|
||||
@@ -208,78 +245,92 @@ endmodule
|
||||
|
||||
--------------------------------------------------------------
|
||||
|
||||
Insure that "ivl" is on your search path, and the library
|
||||
libvvm.a is available.
|
||||
Insure that "verilog" is on your search path, and the vpi library
|
||||
is available.
|
||||
|
||||
For csh -
|
||||
|
||||
setenv PATH /usr/local/bin:$PATH
|
||||
setenv LD_LIBRARY_PATH /usr/local/lib:$LD_LIBRARY_PATH
|
||||
setenv PATH /usr/local/bin:$PATH
|
||||
setenv VPI_MODULE_PATH /usr/local/lib/ivl
|
||||
|
||||
ivl -t vvm -o hello.cc hello.vl
|
||||
g++ hello.cc -o hello -lvvm
|
||||
verilog hello.vl
|
||||
|
||||
(The above presumes that /usr/local/include and /usr/local/lib are
|
||||
part of the compiler search path, which is usually the case for egcs.)
|
||||
part of the compiler search path, which is usually the case for gcc.)
|
||||
|
||||
To run the program
|
||||
|
||||
./hello
|
||||
./hello
|
||||
|
||||
|
||||
5.0 Unsupported Constructs
|
||||
|
||||
IVL is in development - as such it still only supports a (growing) subset
|
||||
of verilog. Below is a description of some of the currently unsupported
|
||||
verilog features.
|
||||
|
||||
- The "?" operator. Example: count = val ? 1 : 0;
|
||||
|
||||
- Ranges within parameter definitions:
|
||||
Example: parameter [15:0] seed = 16'ha3;
|
||||
|
||||
[Note: IEEE Std: 1364-1995 does not allow the syntax.]
|
||||
|
||||
- The "&&" operator:
|
||||
Example: if (a && 0) do = 1;
|
||||
|
||||
- The "===" operator: Example: if( a === b) do = 1;
|
||||
|
||||
- The ">=" operator: Example: if ( a >= 0) do = 1;
|
||||
|
||||
- The ">" operator: Example: if ( a > 0) do = 1;
|
||||
|
||||
- The "<=" operator: Example: if ( a <= 0) do = 1;
|
||||
|
||||
- The "<<" shift operator: Example: a = 8'b0000_0010 << 1;
|
||||
verilog features. This list is not exhaustive, and does not account
|
||||
for errors in the compiler. See the Icarus Verilog web page for the
|
||||
current state of support for Verilog.
|
||||
|
||||
- Min/Typ/Max expressions: Example: a = (1 : 6 : 14);
|
||||
|
||||
- Expansion of a string into a larger variable:
|
||||
Example: reg [0:15] b; b = "b";
|
||||
- Memories work, but only in procedural code.
|
||||
|
||||
- Function declarations/calls.
|
||||
|
||||
- Non-scalar memories, i.e. other than registers.
|
||||
Example: reg [1:0] b [2:0];
|
||||
|
||||
- Delay list. Example: sample #(9,99) sample1(a,b);
|
||||
|
||||
- Bit ranges within IF. Example: if (a[2:3]) do = 1;
|
||||
|
||||
- Assignment timing delay: Example: a = #1 0; #1 a = #2 ~a;
|
||||
|
||||
- Bit Ranges within $write, $display.
|
||||
reg [1:0] b [2:0], bar;
|
||||
wire [1:0] foo;
|
||||
always foo = b[i]; // sorry
|
||||
always @(i) bar = b[i]; // OK
|
||||
|
||||
- `timescale directive
|
||||
|
||||
- Specify blocks
|
||||
- force/release/assign/deassign procedural assignments not
|
||||
supported.
|
||||
|
||||
- Named port parameters.
|
||||
Example: module foo(.x(r[0])) ; reg r[7:0]; endmodule
|
||||
- block disable not supported, i.e.:
|
||||
|
||||
begin : foo
|
||||
[...]
|
||||
disable foo; // sorry
|
||||
[...]
|
||||
end
|
||||
|
||||
- fork/join is not supported in vvm runtime
|
||||
|
||||
- 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
|
||||
parameter foo = a << b; // OK
|
||||
|
||||
- Functions in structural contexts are not supported.
|
||||
|
||||
assign foo = user_function(a,b); // sorry
|
||||
always @(a or b) foo = user_function(a,b); // OK
|
||||
|
||||
- multiplicative operators (*, /, %) are not supported.
|
||||
|
||||
assign foo = a * b; // sorry
|
||||
always @(a or b) foo = a * b; // sorry
|
||||
|
||||
- event data type is not supported.
|
||||
|
||||
- real data type not supported.
|
||||
|
||||
- system functions are not supported. (User defined functions are
|
||||
supported, and system tasks are supported.)
|
||||
|
||||
assign foo = $some_function(a,b); // sorry
|
||||
always @(a or b) foo = $some_function(a,b); // sorry
|
||||
|
||||
- non-constant delay expressions, i.e.:
|
||||
|
||||
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.
|
||||
|
||||
Note that binding to a port by name does work from the outside.
|
||||
i.e. ``foo foogate(.x(n[0]))'' is OK.
|
||||
|
||||
6.0 CREDITS
|
||||
|
||||
@@ -288,9 +339,15 @@ Williams. The proper notices are in the head of each file. However,
|
||||
I have received aid in the form of fixes, Verilog guidance, and
|
||||
especially testing from many people, including (in alphabetical order):
|
||||
|
||||
Eric Aardoom <[email protected]>
|
||||
Ed Carter <[email protected]>
|
||||
Larry Doolittle <[email protected]>
|
||||
Guy Hutchison <[email protected]>
|
||||
Ales Hvezda <[email protected]>
|
||||
James Lee <[email protected]>
|
||||
Peter Monta <[email protected]>
|
||||
Daniel H. Nelsen <[email protected]>
|
||||
Stefan Petersen <[email protected]>
|
||||
Jason Schonberg <[email protected]>
|
||||
Stuart Sutherland <[email protected]>
|
||||
Stephen Tell <[email protected]>
|
||||
@@ -298,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.
|
||||
|
||||
+39
-7
@@ -17,7 +17,7 @@
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
|
||||
*/
|
||||
#if !defined(WINNT)
|
||||
#ident "$Id: Statement.cc,v 1.12 1999/07/12 00:59:36 steve Exp $"
|
||||
#ident "$Id: Statement.cc,v 1.16 1999/09/29 18:36:02 steve Exp $"
|
||||
#endif
|
||||
|
||||
# include "Statement.h"
|
||||
@@ -27,20 +27,30 @@ Statement::~Statement()
|
||||
{
|
||||
}
|
||||
|
||||
PAssign_::PAssign_(PExpr*lval, PExpr*ex)
|
||||
: event_(0), lval_(lval), rval_(ex)
|
||||
{
|
||||
}
|
||||
|
||||
PAssign_::PAssign_(PExpr*lval, PExpr*de, PExpr*ex)
|
||||
: lval_(lval), delay_(de), rval_(ex)
|
||||
: event_(0), lval_(lval), rval_(ex)
|
||||
{
|
||||
if (de) delay_.set_delay(de);
|
||||
}
|
||||
|
||||
PAssign_::PAssign_(PExpr*lval, PEventStatement*ev, PExpr*ex)
|
||||
: event_(ev), lval_(lval), rval_(ex)
|
||||
{
|
||||
}
|
||||
|
||||
PAssign_::~PAssign_()
|
||||
{
|
||||
delete lval_;
|
||||
delete delay_;
|
||||
delete rval_;
|
||||
}
|
||||
|
||||
PAssign::PAssign(PExpr*lval, PExpr*ex)
|
||||
: PAssign_(lval, 0, ex)
|
||||
: PAssign_(lval, ex)
|
||||
{
|
||||
}
|
||||
|
||||
@@ -49,12 +59,22 @@ PAssign::PAssign(PExpr*lval, PExpr*d, PExpr*ex)
|
||||
{
|
||||
}
|
||||
|
||||
PAssign::PAssign(PExpr*lval, PEventStatement*d, PExpr*ex)
|
||||
: PAssign_(lval, d, ex)
|
||||
{
|
||||
}
|
||||
|
||||
PAssign::~PAssign()
|
||||
{
|
||||
}
|
||||
|
||||
PAssignNB::PAssignNB(PExpr*lval, PExpr*ex)
|
||||
: PAssign_(lval, 0, ex)
|
||||
: PAssign_(lval, ex)
|
||||
{
|
||||
}
|
||||
|
||||
PAssignNB::PAssignNB(PExpr*lval, PExpr*d, PExpr*ex)
|
||||
: PAssign_(lval, d, ex)
|
||||
{
|
||||
}
|
||||
|
||||
@@ -88,8 +108,8 @@ PCallTask::PCallTask(const string&n, const svector<PExpr*>&p)
|
||||
{
|
||||
}
|
||||
|
||||
PCase::PCase(PExpr*ex, svector<PCase::Item*>*l)
|
||||
: expr_(ex), items_(l)
|
||||
PCase::PCase(NetCase::TYPE t, PExpr*ex, svector<PCase::Item*>*l)
|
||||
: type_(t), expr_(ex), items_(l)
|
||||
{
|
||||
}
|
||||
|
||||
@@ -143,6 +163,18 @@ PWhile::~PWhile()
|
||||
|
||||
/*
|
||||
* $Log: Statement.cc,v $
|
||||
* Revision 1.16 1999/09/29 18:36:02 steve
|
||||
* Full case support
|
||||
*
|
||||
* Revision 1.15 1999/09/22 02:00:48 steve
|
||||
* assignment with blocking event delay.
|
||||
*
|
||||
* Revision 1.14 1999/09/04 19:11:46 steve
|
||||
* Add support for delayed non-blocking assignments.
|
||||
*
|
||||
* Revision 1.13 1999/09/02 01:59:27 steve
|
||||
* Parse non-blocking assignment delays.
|
||||
*
|
||||
* Revision 1.12 1999/07/12 00:59:36 steve
|
||||
* procedural blocking assignment delays.
|
||||
*
|
||||
|
||||
+33
-4
@@ -19,15 +19,17 @@
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
|
||||
*/
|
||||
#if !defined(WINNT)
|
||||
#ident "$Id: Statement.h,v 1.15 1999/07/12 00:59:36 steve Exp $"
|
||||
#ident "$Id: Statement.h,v 1.20 1999/09/29 18:36:02 steve Exp $"
|
||||
#endif
|
||||
|
||||
# include <string>
|
||||
# include "svector.h"
|
||||
# include "PDelays.h"
|
||||
# include "PExpr.h"
|
||||
# include "LineInfo.h"
|
||||
class PExpr;
|
||||
class Statement;
|
||||
class PEventStatement;
|
||||
|
||||
/*
|
||||
* The PProcess is the root of a behavioral process. Each process gets
|
||||
@@ -77,11 +79,12 @@ class Statement : public LineInfo {
|
||||
*/
|
||||
class PAssign_ : public Statement {
|
||||
public:
|
||||
explicit PAssign_(PExpr*lval, PExpr*ex);
|
||||
explicit PAssign_(PExpr*lval, PExpr*de, PExpr*ex);
|
||||
explicit PAssign_(PExpr*lval, PEventStatement*de, PExpr*ex);
|
||||
virtual ~PAssign_() =0;
|
||||
|
||||
const PExpr* lval() const { return lval_; }
|
||||
const PExpr* delay() const { return delay_; }
|
||||
const PExpr* rval() const { return rval_; }
|
||||
|
||||
protected:
|
||||
@@ -89,9 +92,11 @@ class PAssign_ : public Statement {
|
||||
unsigned&lsb, unsigned&msb,
|
||||
NetExpr*&mux) const;
|
||||
|
||||
PDelays delay_;
|
||||
PEventStatement*event_;
|
||||
|
||||
private:
|
||||
PExpr* lval_;
|
||||
PExpr* delay_;
|
||||
PExpr* rval_;
|
||||
};
|
||||
|
||||
@@ -100,6 +105,7 @@ class PAssign : public PAssign_ {
|
||||
public:
|
||||
explicit PAssign(PExpr*lval, PExpr*ex);
|
||||
explicit PAssign(PExpr*lval, PExpr*de, PExpr*ex);
|
||||
explicit PAssign(PExpr*lval, PEventStatement*de, PExpr*ex);
|
||||
~PAssign();
|
||||
|
||||
virtual void dump(ostream&out, unsigned ind) const;
|
||||
@@ -114,12 +120,15 @@ class PAssignNB : public PAssign_ {
|
||||
|
||||
public:
|
||||
explicit PAssignNB(PExpr*lval, PExpr*ex);
|
||||
explicit PAssignNB(PExpr*lval, PExpr*de, PExpr*ex);
|
||||
~PAssignNB();
|
||||
|
||||
virtual void dump(ostream&out, unsigned ind) const;
|
||||
virtual NetProc* elaborate(Design*des, const string&path) const;
|
||||
|
||||
private:
|
||||
NetProc*assign_to_memory_(class NetMemory*, PExpr*,
|
||||
Design*des, const string&path) const;
|
||||
};
|
||||
|
||||
/*
|
||||
@@ -191,13 +200,14 @@ class PCase : public Statement {
|
||||
Statement*stat;
|
||||
};
|
||||
|
||||
PCase(PExpr*ex, svector<Item*>*);
|
||||
PCase(NetCase::TYPE, PExpr*ex, svector<Item*>*);
|
||||
~PCase();
|
||||
|
||||
virtual NetProc* elaborate(Design*des, const string&path) const;
|
||||
virtual void dump(ostream&out, unsigned ind) const;
|
||||
|
||||
private:
|
||||
NetCase::TYPE type_;
|
||||
PExpr*expr_;
|
||||
|
||||
svector<Item*>*items_;
|
||||
@@ -256,6 +266,10 @@ class PEventStatement : public Statement {
|
||||
virtual void dump(ostream&out, unsigned ind) const;
|
||||
virtual NetProc* elaborate(Design*des, const string&path) const;
|
||||
|
||||
// This method is used to elaborate, but attach a previously
|
||||
// elaborated statement to the event.
|
||||
NetProc* elaborate_st(Design*des, const string&path, NetProc*st) const;
|
||||
|
||||
private:
|
||||
svector<PEEvent*>expr_;
|
||||
Statement*statement_;
|
||||
@@ -333,6 +347,21 @@ class PWhile : public Statement {
|
||||
|
||||
/*
|
||||
* $Log: Statement.h,v $
|
||||
* Revision 1.20 1999/09/29 18:36:02 steve
|
||||
* Full case support
|
||||
*
|
||||
* Revision 1.19 1999/09/22 02:00:48 steve
|
||||
* assignment with blocking event delay.
|
||||
*
|
||||
* Revision 1.18 1999/09/15 01:55:06 steve
|
||||
* Elaborate non-blocking assignment to memories.
|
||||
*
|
||||
* Revision 1.17 1999/09/04 19:11:46 steve
|
||||
* Add support for delayed non-blocking assignments.
|
||||
*
|
||||
* Revision 1.16 1999/09/02 01:59:27 steve
|
||||
* Parse non-blocking assignment delays.
|
||||
*
|
||||
* Revision 1.15 1999/07/12 00:59:36 steve
|
||||
* procedural blocking assignment delays.
|
||||
*
|
||||
|
||||
+912
@@ -0,0 +1,912 @@
|
||||
#! /bin/sh
|
||||
# Attempt to guess a canonical system name.
|
||||
# Copyright (C) 1992, 93, 94, 95, 96, 1997 Free Software Foundation, Inc.
|
||||
#
|
||||
# This file is free software; you can redistribute it and/or modify it
|
||||
# under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation; either version 2 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful, but
|
||||
# WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
# General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program; if not, write to the Free Software
|
||||
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
#
|
||||
# As a special exception to the GNU General Public License, if you
|
||||
# distribute this file as part of a program that contains a
|
||||
# configuration script generated by Autoconf, you may include it under
|
||||
# the same distribution terms that you use for the rest of that program.
|
||||
|
||||
# Written by Per Bothner <[email protected]>.
|
||||
# The master version of this file is at the FSF in /home/gd/gnu/lib.
|
||||
#
|
||||
# This script attempts to guess a canonical system name similar to
|
||||
# config.sub. If it succeeds, it prints the system name on stdout, and
|
||||
# exits with 0. Otherwise, it exits with 1.
|
||||
#
|
||||
# The plan is that this can be called by configure scripts if you
|
||||
# don't specify an explicit system type (host/target name).
|
||||
#
|
||||
# Only a few systems have been added to this list; please add others
|
||||
# (but try to keep the structure clean).
|
||||
#
|
||||
|
||||
# This is needed to find uname on a Pyramid OSx when run in the BSD universe.
|
||||
# ([email protected] 8/24/94.)
|
||||
if (test -f /.attbin/uname) >/dev/null 2>&1 ; then
|
||||
PATH=$PATH:/.attbin ; export PATH
|
||||
fi
|
||||
|
||||
UNAME_MACHINE=`(uname -m) 2>/dev/null` || UNAME_MACHINE=unknown
|
||||
UNAME_RELEASE=`(uname -r) 2>/dev/null` || UNAME_RELEASE=unknown
|
||||
UNAME_SYSTEM=`(uname -s) 2>/dev/null` || UNAME_SYSTEM=unknown
|
||||
UNAME_VERSION=`(uname -v) 2>/dev/null` || UNAME_VERSION=unknown
|
||||
|
||||
trap 'rm -f dummy.c dummy.o dummy; exit 1' 1 2 15
|
||||
|
||||
# Note: order is significant - the case branches are not exclusive.
|
||||
|
||||
case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in
|
||||
alpha:OSF1:*:*)
|
||||
if test $UNAME_RELEASE = "V4.0"; then
|
||||
UNAME_RELEASE=`/usr/sbin/sizer -v | awk '{print $3}'`
|
||||
fi
|
||||
# A Vn.n version is a released version.
|
||||
# A Tn.n version is a released field test version.
|
||||
# A Xn.n version is an unreleased experimental baselevel.
|
||||
# 1.2 uses "1.2" for uname -r.
|
||||
cat <<EOF >dummy.s
|
||||
.globl main
|
||||
.ent main
|
||||
main:
|
||||
.frame \$30,0,\$26,0
|
||||
.prologue 0
|
||||
.long 0x47e03d80 # implver $0
|
||||
lda \$2,259
|
||||
.long 0x47e20c21 # amask $2,$1
|
||||
srl \$1,8,\$2
|
||||
sll \$2,2,\$2
|
||||
sll \$0,3,\$0
|
||||
addl \$1,\$0,\$0
|
||||
addl \$2,\$0,\$0
|
||||
ret \$31,(\$26),1
|
||||
.end main
|
||||
EOF
|
||||
${CC-cc} dummy.s -o dummy 2>/dev/null
|
||||
if test "$?" = 0 ; then
|
||||
./dummy
|
||||
case "$?" in
|
||||
7)
|
||||
UNAME_MACHINE="alpha"
|
||||
;;
|
||||
15)
|
||||
UNAME_MACHINE="alphaev5"
|
||||
;;
|
||||
14)
|
||||
UNAME_MACHINE="alphaev56"
|
||||
;;
|
||||
10)
|
||||
UNAME_MACHINE="alphapca56"
|
||||
;;
|
||||
16)
|
||||
UNAME_MACHINE="alphaev6"
|
||||
;;
|
||||
esac
|
||||
fi
|
||||
rm -f dummy.s dummy
|
||||
echo ${UNAME_MACHINE}-dec-osf`echo ${UNAME_RELEASE} | sed -e 's/^[VTX]//' | tr [[A-Z]] [[a-z]]`
|
||||
exit 0 ;;
|
||||
21064:Windows_NT:50:3)
|
||||
echo alpha-dec-winnt3.5
|
||||
exit 0 ;;
|
||||
Amiga*:UNIX_System_V:4.0:*)
|
||||
echo m68k-cbm-sysv4
|
||||
exit 0;;
|
||||
amiga:NetBSD:*:*)
|
||||
echo m68k-cbm-netbsd${UNAME_RELEASE}
|
||||
exit 0 ;;
|
||||
amiga:OpenBSD:*:*)
|
||||
echo m68k-unknown-openbsd${UNAME_RELEASE}
|
||||
exit 0 ;;
|
||||
arc64:OpenBSD:*:*)
|
||||
echo mips64el-unknown-openbsd${UNAME_RELEASE}
|
||||
exit 0 ;;
|
||||
arc:OpenBSD:*:*)
|
||||
echo mipsel-unknown-openbsd${UNAME_RELEASE}
|
||||
exit 0 ;;
|
||||
hkmips:OpenBSD:*:*)
|
||||
echo mips-unknown-openbsd${UNAME_RELEASE}
|
||||
exit 0 ;;
|
||||
pmax:OpenBSD:*:*)
|
||||
echo mipsel-unknown-openbsd${UNAME_RELEASE}
|
||||
exit 0 ;;
|
||||
sgi:OpenBSD:*:*)
|
||||
echo mips-unknown-openbsd${UNAME_RELEASE}
|
||||
exit 0 ;;
|
||||
wgrisc:OpenBSD:*:*)
|
||||
echo mipsel-unknown-openbsd${UNAME_RELEASE}
|
||||
exit 0 ;;
|
||||
arm:RISC*:1.[012]*:*|arm:riscix:1.[012]*:*)
|
||||
echo arm-acorn-riscix${UNAME_RELEASE}
|
||||
exit 0;;
|
||||
arm32:NetBSD:*:*)
|
||||
echo arm-unknown-netbsd`echo ${UNAME_RELEASE}|sed -e 's/[-_].*/\./'`
|
||||
exit 0 ;;
|
||||
SR2?01:HI-UX/MPP:*:*)
|
||||
echo hppa1.1-hitachi-hiuxmpp
|
||||
exit 0;;
|
||||
Pyramid*:OSx*:*:*|MIS*:OSx*:*:*)
|
||||
# [email protected] (Earle F. Ake) contributed MIS and NILE.
|
||||
if test "`(/bin/universe) 2>/dev/null`" = att ; then
|
||||
echo pyramid-pyramid-sysv3
|
||||
else
|
||||
echo pyramid-pyramid-bsd
|
||||
fi
|
||||
exit 0 ;;
|
||||
NILE:*:*:dcosx)
|
||||
echo pyramid-pyramid-svr4
|
||||
exit 0 ;;
|
||||
sun4*:SunOS:5.*:* | tadpole*:SunOS:5.*:*)
|
||||
echo sparc-sun-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
|
||||
exit 0 ;;
|
||||
i86pc:SunOS:5.*:*)
|
||||
echo i386-pc-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
|
||||
exit 0 ;;
|
||||
sun4*:SunOS:6*:*)
|
||||
# According to config.sub, this is the proper way to canonicalize
|
||||
# SunOS6. Hard to guess exactly what SunOS6 will be like, but
|
||||
# it's likely to be more like Solaris than SunOS4.
|
||||
echo sparc-sun-solaris3`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
|
||||
exit 0 ;;
|
||||
sun4*:SunOS:*:*)
|
||||
case "`/usr/bin/arch -k`" in
|
||||
Series*|S4*)
|
||||
UNAME_RELEASE=`uname -v`
|
||||
;;
|
||||
esac
|
||||
# Japanese Language versions have a version number like `4.1.3-JL'.
|
||||
echo sparc-sun-sunos`echo ${UNAME_RELEASE}|sed -e 's/-/_/'`
|
||||
exit 0 ;;
|
||||
sun3*:SunOS:*:*)
|
||||
echo m68k-sun-sunos${UNAME_RELEASE}
|
||||
exit 0 ;;
|
||||
sun*:*:4.2BSD:*)
|
||||
UNAME_RELEASE=`(head -1 /etc/motd | awk '{print substr($5,1,3)}') 2>/dev/null`
|
||||
test "x${UNAME_RELEASE}" = "x" && UNAME_RELEASE=3
|
||||
case "`/bin/arch`" in
|
||||
sun3)
|
||||
echo m68k-sun-sunos${UNAME_RELEASE}
|
||||
;;
|
||||
sun4)
|
||||
echo sparc-sun-sunos${UNAME_RELEASE}
|
||||
;;
|
||||
esac
|
||||
exit 0 ;;
|
||||
aushp:SunOS:*:*)
|
||||
echo sparc-auspex-sunos${UNAME_RELEASE}
|
||||
exit 0 ;;
|
||||
atari*:NetBSD:*:*)
|
||||
echo m68k-atari-netbsd${UNAME_RELEASE}
|
||||
exit 0 ;;
|
||||
atari*:OpenBSD:*:*)
|
||||
echo m68k-unknown-openbsd${UNAME_RELEASE}
|
||||
exit 0 ;;
|
||||
sun3*:NetBSD:*:*)
|
||||
echo m68k-sun-netbsd${UNAME_RELEASE}
|
||||
exit 0 ;;
|
||||
sun3*:OpenBSD:*:*)
|
||||
echo m68k-unknown-openbsd${UNAME_RELEASE}
|
||||
exit 0 ;;
|
||||
mac68k:NetBSD:*:*)
|
||||
echo m68k-apple-netbsd${UNAME_RELEASE}
|
||||
exit 0 ;;
|
||||
mac68k:OpenBSD:*:*)
|
||||
echo m68k-unknown-openbsd${UNAME_RELEASE}
|
||||
exit 0 ;;
|
||||
mvme68k:OpenBSD:*:*)
|
||||
echo m68k-unknown-openbsd${UNAME_RELEASE}
|
||||
exit 0 ;;
|
||||
mvme88k:OpenBSD:*:*)
|
||||
echo m88k-unknown-openbsd${UNAME_RELEASE}
|
||||
exit 0 ;;
|
||||
powerpc:machten:*:*)
|
||||
echo powerpc-apple-machten${UNAME_RELEASE}
|
||||
exit 0 ;;
|
||||
RISC*:Mach:*:*)
|
||||
echo mips-dec-mach_bsd4.3
|
||||
exit 0 ;;
|
||||
RISC*:ULTRIX:*:*)
|
||||
echo mips-dec-ultrix${UNAME_RELEASE}
|
||||
exit 0 ;;
|
||||
VAX*:ULTRIX*:*:*)
|
||||
echo vax-dec-ultrix${UNAME_RELEASE}
|
||||
exit 0 ;;
|
||||
2020:CLIX:*:*)
|
||||
echo clipper-intergraph-clix${UNAME_RELEASE}
|
||||
exit 0 ;;
|
||||
mips:*:*:UMIPS | mips:*:*:RISCos)
|
||||
sed 's/^ //' << EOF >dummy.c
|
||||
int main (argc, argv) int argc; char **argv; {
|
||||
#if defined (host_mips) && defined (MIPSEB)
|
||||
#if defined (SYSTYPE_SYSV)
|
||||
printf ("mips-mips-riscos%ssysv\n", argv[1]); exit (0);
|
||||
#endif
|
||||
#if defined (SYSTYPE_SVR4)
|
||||
printf ("mips-mips-riscos%ssvr4\n", argv[1]); exit (0);
|
||||
#endif
|
||||
#if defined (SYSTYPE_BSD43) || defined(SYSTYPE_BSD)
|
||||
printf ("mips-mips-riscos%sbsd\n", argv[1]); exit (0);
|
||||
#endif
|
||||
#endif
|
||||
exit (-1);
|
||||
}
|
||||
EOF
|
||||
${CC-cc} dummy.c -o dummy \
|
||||
&& ./dummy `echo "${UNAME_RELEASE}" | sed -n 's/\([0-9]*\).*/\1/p'` \
|
||||
&& rm dummy.c dummy && exit 0
|
||||
rm -f dummy.c dummy
|
||||
echo mips-mips-riscos${UNAME_RELEASE}
|
||||
exit 0 ;;
|
||||
Night_Hawk:Power_UNIX:*:*)
|
||||
echo powerpc-harris-powerunix
|
||||
exit 0 ;;
|
||||
m88k:CX/UX:7*:*)
|
||||
echo m88k-harris-cxux7
|
||||
exit 0 ;;
|
||||
m88k:*:4*:R4*)
|
||||
echo m88k-motorola-sysv4
|
||||
exit 0 ;;
|
||||
m88k:*:3*:R3*)
|
||||
echo m88k-motorola-sysv3
|
||||
exit 0 ;;
|
||||
AViiON:dgux:*:*)
|
||||
# DG/UX returns AViiON for all architectures
|
||||
UNAME_PROCESSOR=`/usr/bin/uname -p`
|
||||
if [ $UNAME_PROCESSOR = mc88100 -o $UNAME_PROCESSOR = mc88110 ] ; then
|
||||
if [ ${TARGET_BINARY_INTERFACE}x = m88kdguxelfx \
|
||||
-o ${TARGET_BINARY_INTERFACE}x = x ] ; then
|
||||
echo m88k-dg-dgux${UNAME_RELEASE}
|
||||
else
|
||||
echo m88k-dg-dguxbcs${UNAME_RELEASE}
|
||||
fi
|
||||
else echo i586-dg-dgux${UNAME_RELEASE}
|
||||
fi
|
||||
exit 0 ;;
|
||||
M88*:DolphinOS:*:*) # DolphinOS (SVR3)
|
||||
echo m88k-dolphin-sysv3
|
||||
exit 0 ;;
|
||||
M88*:*:R3*:*)
|
||||
# Delta 88k system running SVR3
|
||||
echo m88k-motorola-sysv3
|
||||
exit 0 ;;
|
||||
XD88*:*:*:*) # Tektronix XD88 system running UTekV (SVR3)
|
||||
echo m88k-tektronix-sysv3
|
||||
exit 0 ;;
|
||||
Tek43[0-9][0-9]:UTek:*:*) # Tektronix 4300 system running UTek (BSD)
|
||||
echo m68k-tektronix-bsd
|
||||
exit 0 ;;
|
||||
*:IRIX*:*:*)
|
||||
echo mips-sgi-irix`echo ${UNAME_RELEASE}|sed -e 's/-/_/g'`
|
||||
exit 0 ;;
|
||||
????????:AIX?:[12].1:2) # AIX 2.2.1 or AIX 2.1.1 is RT/PC AIX.
|
||||
echo romp-ibm-aix # uname -m gives an 8 hex-code CPU id
|
||||
exit 0 ;; # Note that: echo "'`uname -s`'" gives 'AIX '
|
||||
i?86:AIX:*:*)
|
||||
echo i386-ibm-aix
|
||||
exit 0 ;;
|
||||
*:AIX:2:3)
|
||||
if grep bos325 /usr/include/stdio.h >/dev/null 2>&1; then
|
||||
sed 's/^ //' << EOF >dummy.c
|
||||
#include <sys/systemcfg.h>
|
||||
|
||||
main()
|
||||
{
|
||||
if (!__power_pc())
|
||||
exit(1);
|
||||
puts("powerpc-ibm-aix3.2.5");
|
||||
exit(0);
|
||||
}
|
||||
EOF
|
||||
${CC-cc} dummy.c -o dummy && ./dummy && rm dummy.c dummy && exit 0
|
||||
rm -f dummy.c dummy
|
||||
echo rs6000-ibm-aix3.2.5
|
||||
elif grep bos324 /usr/include/stdio.h >/dev/null 2>&1; then
|
||||
echo rs6000-ibm-aix3.2.4
|
||||
else
|
||||
echo rs6000-ibm-aix3.2
|
||||
fi
|
||||
exit 0 ;;
|
||||
*:AIX:*:4)
|
||||
if /usr/sbin/lsattr -EHl proc0 | grep POWER >/dev/null 2>&1; then
|
||||
IBM_ARCH=rs6000
|
||||
else
|
||||
IBM_ARCH=powerpc
|
||||
fi
|
||||
if [ -x /usr/bin/oslevel ] ; then
|
||||
IBM_REV=`/usr/bin/oslevel`
|
||||
else
|
||||
IBM_REV=4.${UNAME_RELEASE}
|
||||
fi
|
||||
echo ${IBM_ARCH}-ibm-aix${IBM_REV}
|
||||
exit 0 ;;
|
||||
*:AIX:*:*)
|
||||
echo rs6000-ibm-aix
|
||||
exit 0 ;;
|
||||
ibmrt:4.4BSD:*|romp-ibm:BSD:*)
|
||||
echo romp-ibm-bsd4.4
|
||||
exit 0 ;;
|
||||
ibmrt:*BSD:*|romp-ibm:BSD:*) # covers RT/PC NetBSD and
|
||||
echo romp-ibm-bsd${UNAME_RELEASE} # 4.3 with uname added to
|
||||
exit 0 ;; # report: romp-ibm BSD 4.3
|
||||
*:BOSX:*:*)
|
||||
echo rs6000-bull-bosx
|
||||
exit 0 ;;
|
||||
DPX/2?00:B.O.S.:*:*)
|
||||
echo m68k-bull-sysv3
|
||||
exit 0 ;;
|
||||
9000/[34]??:4.3bsd:1.*:*)
|
||||
echo m68k-hp-bsd
|
||||
exit 0 ;;
|
||||
hp300:4.4BSD:*:* | 9000/[34]??:4.3bsd:2.*:*)
|
||||
echo m68k-hp-bsd4.4
|
||||
exit 0 ;;
|
||||
9000/[3478]??:HP-UX:*:*)
|
||||
case "${UNAME_MACHINE}" in
|
||||
9000/31? ) HP_ARCH=m68000 ;;
|
||||
9000/[34]?? ) HP_ARCH=m68k ;;
|
||||
9000/7?? | 9000/8?[1679] ) HP_ARCH=hppa1.1 ;;
|
||||
9000/8?? ) HP_ARCH=hppa1.0 ;;
|
||||
esac
|
||||
HPUX_REV=`echo ${UNAME_RELEASE}|sed -e 's/[^.]*.[0B]*//'`
|
||||
echo ${HP_ARCH}-hp-hpux${HPUX_REV}
|
||||
exit 0 ;;
|
||||
3050*:HI-UX:*:*)
|
||||
sed 's/^ //' << EOF >dummy.c
|
||||
#include <unistd.h>
|
||||
int
|
||||
main ()
|
||||
{
|
||||
long cpu = sysconf (_SC_CPU_VERSION);
|
||||
/* The order matters, because CPU_IS_HP_MC68K erroneously returns
|
||||
true for CPU_PA_RISC1_0. CPU_IS_PA_RISC returns correct
|
||||
results, however. */
|
||||
if (CPU_IS_PA_RISC (cpu))
|
||||
{
|
||||
switch (cpu)
|
||||
{
|
||||
case CPU_PA_RISC1_0: puts ("hppa1.0-hitachi-hiuxwe2"); break;
|
||||
case CPU_PA_RISC1_1: puts ("hppa1.1-hitachi-hiuxwe2"); break;
|
||||
case CPU_PA_RISC2_0: puts ("hppa2.0-hitachi-hiuxwe2"); break;
|
||||
default: puts ("hppa-hitachi-hiuxwe2"); break;
|
||||
}
|
||||
}
|
||||
else if (CPU_IS_HP_MC68K (cpu))
|
||||
puts ("m68k-hitachi-hiuxwe2");
|
||||
else puts ("unknown-hitachi-hiuxwe2");
|
||||
exit (0);
|
||||
}
|
||||
EOF
|
||||
${CC-cc} dummy.c -o dummy && ./dummy && rm dummy.c dummy && exit 0
|
||||
rm -f dummy.c dummy
|
||||
echo unknown-hitachi-hiuxwe2
|
||||
exit 0 ;;
|
||||
9000/7??:4.3bsd:*:* | 9000/8?[79]:4.3bsd:*:* )
|
||||
echo hppa1.1-hp-bsd
|
||||
exit 0 ;;
|
||||
9000/8??:4.3bsd:*:*)
|
||||
echo hppa1.0-hp-bsd
|
||||
exit 0 ;;
|
||||
hp7??:OSF1:*:* | hp8?[79]:OSF1:*:* )
|
||||
echo hppa1.1-hp-osf
|
||||
exit 0 ;;
|
||||
hp8??:OSF1:*:*)
|
||||
echo hppa1.0-hp-osf
|
||||
exit 0 ;;
|
||||
i?86:OSF1:*:*)
|
||||
if [ -x /usr/sbin/sysversion ] ; then
|
||||
echo ${UNAME_MACHINE}-unknown-osf1mk
|
||||
else
|
||||
echo ${UNAME_MACHINE}-unknown-osf1
|
||||
fi
|
||||
exit 0 ;;
|
||||
parisc*:Lites*:*:*)
|
||||
echo hppa1.1-hp-lites
|
||||
exit 0 ;;
|
||||
C1*:ConvexOS:*:* | convex:ConvexOS:C1*:*)
|
||||
echo c1-convex-bsd
|
||||
exit 0 ;;
|
||||
C2*:ConvexOS:*:* | convex:ConvexOS:C2*:*)
|
||||
if getsysinfo -f scalar_acc
|
||||
then echo c32-convex-bsd
|
||||
else echo c2-convex-bsd
|
||||
fi
|
||||
exit 0 ;;
|
||||
C34*:ConvexOS:*:* | convex:ConvexOS:C34*:*)
|
||||
echo c34-convex-bsd
|
||||
exit 0 ;;
|
||||
C38*:ConvexOS:*:* | convex:ConvexOS:C38*:*)
|
||||
echo c38-convex-bsd
|
||||
exit 0 ;;
|
||||
C4*:ConvexOS:*:* | convex:ConvexOS:C4*:*)
|
||||
echo c4-convex-bsd
|
||||
exit 0 ;;
|
||||
CRAY*X-MP:*:*:*)
|
||||
echo xmp-cray-unicos
|
||||
exit 0 ;;
|
||||
CRAY*Y-MP:*:*:*)
|
||||
echo ymp-cray-unicos${UNAME_RELEASE}
|
||||
exit 0 ;;
|
||||
CRAY*[A-Z]90:*:*:*)
|
||||
echo ${UNAME_MACHINE}-cray-unicos${UNAME_RELEASE} \
|
||||
| sed -e 's/CRAY.*\([A-Z]90\)/\1/' \
|
||||
-e y/ABCDEFGHIJKLMNOPQRSTUVWXYZ/abcdefghijklmnopqrstuvwxyz/
|
||||
exit 0 ;;
|
||||
CRAY*TS:*:*:*)
|
||||
echo t90-cray-unicos${UNAME_RELEASE}
|
||||
exit 0 ;;
|
||||
CRAY-2:*:*:*)
|
||||
echo cray2-cray-unicos
|
||||
exit 0 ;;
|
||||
F300:UNIX_System_V:*:*)
|
||||
FUJITSU_SYS=`uname -p | tr [A-Z] [a-z] | sed -e 's/\///'`
|
||||
FUJITSU_REL=`echo ${UNAME_RELEASE} | sed -e 's/ /_/'`
|
||||
echo "f300-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}"
|
||||
exit 0 ;;
|
||||
F301:UNIX_System_V:*:*)
|
||||
echo f301-fujitsu-uxpv`echo $UNAME_RELEASE | sed 's/ .*//'`
|
||||
exit 0 ;;
|
||||
hp3[0-9][05]:NetBSD:*:*)
|
||||
echo m68k-hp-netbsd${UNAME_RELEASE}
|
||||
exit 0 ;;
|
||||
hp300:OpenBSD:*:*)
|
||||
echo m68k-unknown-openbsd${UNAME_RELEASE}
|
||||
exit 0 ;;
|
||||
i?86:BSD/386:*:* | *:BSD/OS:*:*)
|
||||
echo ${UNAME_MACHINE}-pc-bsdi${UNAME_RELEASE}
|
||||
exit 0 ;;
|
||||
*:FreeBSD:*:*)
|
||||
echo ${UNAME_MACHINE}-unknown-freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'`
|
||||
exit 0 ;;
|
||||
*:NetBSD:*:*)
|
||||
echo ${UNAME_MACHINE}-unknown-netbsd`echo ${UNAME_RELEASE}|sed -e 's/[-_].*/\./'`
|
||||
exit 0 ;;
|
||||
*:OpenBSD:*:*)
|
||||
echo ${UNAME_MACHINE}-unknown-openbsd`echo ${UNAME_RELEASE}|sed -e 's/[-_].*/\./'`
|
||||
exit 0 ;;
|
||||
i*:CYGWIN*:*)
|
||||
echo i386-pc-cygwin32
|
||||
exit 0 ;;
|
||||
i*:MINGW*:*)
|
||||
echo i386-pc-mingw32
|
||||
exit 0 ;;
|
||||
p*:CYGWIN*:*)
|
||||
echo powerpcle-unknown-cygwin32
|
||||
exit 0 ;;
|
||||
prep*:SunOS:5.*:*)
|
||||
echo powerpcle-unknown-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
|
||||
exit 0 ;;
|
||||
*:GNU:*:*)
|
||||
echo `echo ${UNAME_MACHINE}|sed -e 's,[-/].*$,,'`-unknown-gnu`echo ${UNAME_RELEASE}|sed -e 's,/.*$,,'`
|
||||
exit 0 ;;
|
||||
*:Linux:*:*)
|
||||
# The BFD linker knows what the default object file format is, so
|
||||
# first see if it will tell us.
|
||||
ld_help_string=`ld --help 2>&1`
|
||||
ld_supported_emulations=`echo $ld_help_string \
|
||||
| sed -ne '/supported emulations:/!d
|
||||
s/[ ][ ]*/ /g
|
||||
s/.*supported emulations: *//
|
||||
s/ .*//
|
||||
p'`
|
||||
case "$ld_supported_emulations" in
|
||||
i?86linux) echo "${UNAME_MACHINE}-pc-linux-gnuaout" ; exit 0 ;;
|
||||
i?86coff) echo "${UNAME_MACHINE}-pc-linux-gnucoff" ; exit 0 ;;
|
||||
sparclinux) echo "${UNAME_MACHINE}-unknown-linux-gnuaout" ; exit 0 ;;
|
||||
m68klinux) echo "${UNAME_MACHINE}-unknown-linux-gnuaout" ; exit 0 ;;
|
||||
elf32ppc)
|
||||
# Determine Lib Version
|
||||
cat >dummy.c <<EOF
|
||||
#include <features.h>
|
||||
#if defined(__GLIBC__)
|
||||
extern char __libc_version[];
|
||||
extern char __libc_release[];
|
||||
#endif
|
||||
main(argc, argv)
|
||||
int argc;
|
||||
char *argv[];
|
||||
{
|
||||
#if defined(__GLIBC__)
|
||||
printf("%s %s\n", __libc_version, __libc_release);
|
||||
#else
|
||||
printf("unkown\n");
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
EOF
|
||||
LIBC=""
|
||||
${CC-cc} dummy.c -o dummy 2>/dev/null
|
||||
if test "$?" = 0 ; then
|
||||
./dummy | grep 1\.99 > /dev/null
|
||||
if test "$?" = 0 ; then
|
||||
LIBC="libc1"
|
||||
fi
|
||||
fi
|
||||
rm -f dummy.c dummy
|
||||
echo powerpc-unknown-linux-gnu${LIBC} ; exit 0 ;;
|
||||
esac
|
||||
|
||||
if test "${UNAME_MACHINE}" = "alpha" ; then
|
||||
sed 's/^ //' <<EOF >dummy.s
|
||||
.globl main
|
||||
.ent main
|
||||
main:
|
||||
.frame \$30,0,\$26,0
|
||||
.prologue 0
|
||||
.long 0x47e03d80 # implver $0
|
||||
lda \$2,259
|
||||
.long 0x47e20c21 # amask $2,$1
|
||||
srl \$1,8,\$2
|
||||
sll \$2,2,\$2
|
||||
sll \$0,3,\$0
|
||||
addl \$1,\$0,\$0
|
||||
addl \$2,\$0,\$0
|
||||
ret \$31,(\$26),1
|
||||
.end main
|
||||
EOF
|
||||
LIBC=""
|
||||
${CC-cc} dummy.s -o dummy 2>/dev/null
|
||||
if test "$?" = 0 ; then
|
||||
./dummy
|
||||
case "$?" in
|
||||
7)
|
||||
UNAME_MACHINE="alpha"
|
||||
;;
|
||||
15)
|
||||
UNAME_MACHINE="alphaev5"
|
||||
;;
|
||||
14)
|
||||
UNAME_MACHINE="alphaev56"
|
||||
;;
|
||||
10)
|
||||
UNAME_MACHINE="alphapca56"
|
||||
;;
|
||||
16)
|
||||
UNAME_MACHINE="alphaev6"
|
||||
;;
|
||||
esac
|
||||
|
||||
objdump --private-headers dummy | \
|
||||
grep ld.so.1 > /dev/null
|
||||
if test "$?" = 0 ; then
|
||||
LIBC="libc1"
|
||||
fi
|
||||
fi
|
||||
rm -f dummy.s dummy
|
||||
echo ${UNAME_MACHINE}-unknown-linux-gnu${LIBC} ; exit 0
|
||||
elif test "${UNAME_MACHINE}" = "mips" ; then
|
||||
cat >dummy.c <<EOF
|
||||
main(argc, argv)
|
||||
int argc;
|
||||
char *argv[];
|
||||
{
|
||||
#ifdef __MIPSEB__
|
||||
printf ("%s-unknown-linux-gnu\n", argv[1]);
|
||||
#endif
|
||||
#ifdef __MIPSEL__
|
||||
printf ("%sel-unknown-linux-gnu\n", argv[1]);
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
EOF
|
||||
${CC-cc} dummy.c -o dummy 2>/dev/null && ./dummy "${UNAME_MACHINE}" && rm dummy.c dummy && exit 0
|
||||
rm -f dummy.c dummy
|
||||
else
|
||||
# Either a pre-BFD a.out linker (linux-gnuoldld)
|
||||
# or one that does not give us useful --help.
|
||||
# GCC wants to distinguish between linux-gnuoldld and linux-gnuaout.
|
||||
# If ld does not provide *any* "supported emulations:"
|
||||
# that means it is gnuoldld.
|
||||
echo "$ld_help_string" | grep >/dev/null 2>&1 "supported emulations:"
|
||||
test $? != 0 && echo "${UNAME_MACHINE}-pc-linux-gnuoldld" && exit 0
|
||||
|
||||
case "${UNAME_MACHINE}" in
|
||||
i?86)
|
||||
VENDOR=pc;
|
||||
;;
|
||||
*)
|
||||
VENDOR=unknown;
|
||||
;;
|
||||
esac
|
||||
# Determine whether the default compiler is a.out or elf
|
||||
cat >dummy.c <<EOF
|
||||
#include <features.h>
|
||||
main(argc, argv)
|
||||
int argc;
|
||||
char *argv[];
|
||||
{
|
||||
#ifdef __ELF__
|
||||
# ifdef __GLIBC__
|
||||
# if __GLIBC__ >= 2
|
||||
printf ("%s-${VENDOR}-linux-gnu\n", argv[1]);
|
||||
# else
|
||||
printf ("%s-${VENDOR}-linux-gnulibc1\n", argv[1]);
|
||||
# endif
|
||||
# else
|
||||
printf ("%s-${VENDOR}-linux-gnulibc1\n", argv[1]);
|
||||
# endif
|
||||
#else
|
||||
printf ("%s-${VENDOR}-linux-gnuaout\n", argv[1]);
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
EOF
|
||||
${CC-cc} dummy.c -o dummy 2>/dev/null && ./dummy "${UNAME_MACHINE}" && rm dummy.c dummy && exit 0
|
||||
rm -f dummy.c dummy
|
||||
fi ;;
|
||||
# ptx 4.0 does uname -s correctly, with DYNIX/ptx in there. earlier versions
|
||||
# are messed up and put the nodename in both sysname and nodename.
|
||||
i?86:DYNIX/ptx:4*:*)
|
||||
echo i386-sequent-sysv4
|
||||
exit 0 ;;
|
||||
i?86:UNIX_SV:4.2MP:2.*)
|
||||
# Unixware is an offshoot of SVR4, but it has its own version
|
||||
# number series starting with 2...
|
||||
# I am not positive that other SVR4 systems won't match this,
|
||||
# I just have to hope. -- rms.
|
||||
# Use sysv4.2uw... so that sysv4* matches it.
|
||||
echo ${UNAME_MACHINE}-pc-sysv4.2uw${UNAME_VERSION}
|
||||
exit 0 ;;
|
||||
i?86:*:4.*:* | i?86:SYSTEM_V:4.*:*)
|
||||
if grep Novell /usr/include/link.h >/dev/null 2>/dev/null; then
|
||||
echo ${UNAME_MACHINE}-univel-sysv${UNAME_RELEASE}
|
||||
else
|
||||
echo ${UNAME_MACHINE}-pc-sysv${UNAME_RELEASE}
|
||||
fi
|
||||
exit 0 ;;
|
||||
i?86:*:3.2:*)
|
||||
if test -f /usr/options/cb.name; then
|
||||
UNAME_REL=`sed -n 's/.*Version //p' </usr/options/cb.name`
|
||||
echo ${UNAME_MACHINE}-pc-isc$UNAME_REL
|
||||
elif /bin/uname -X 2>/dev/null >/dev/null ; then
|
||||
UNAME_REL=`(/bin/uname -X|egrep Release|sed -e 's/.*= //')`
|
||||
(/bin/uname -X|egrep i80486 >/dev/null) && UNAME_MACHINE=i486
|
||||
(/bin/uname -X|egrep '^Machine.*Pentium' >/dev/null) \
|
||||
&& UNAME_MACHINE=i586
|
||||
echo ${UNAME_MACHINE}-pc-sco$UNAME_REL
|
||||
else
|
||||
echo ${UNAME_MACHINE}-pc-sysv32
|
||||
fi
|
||||
exit 0 ;;
|
||||
pc:*:*:*)
|
||||
# uname -m prints for DJGPP always 'pc', but it prints nothing about
|
||||
# the processor, so we play safe by assuming i386.
|
||||
echo i386-pc-msdosdjgpp
|
||||
exit 0 ;;
|
||||
Intel:Mach:3*:*)
|
||||
echo i386-pc-mach3
|
||||
exit 0 ;;
|
||||
paragon:*:*:*)
|
||||
echo i860-intel-osf1
|
||||
exit 0 ;;
|
||||
i860:*:4.*:*) # i860-SVR4
|
||||
if grep Stardent /usr/include/sys/uadmin.h >/dev/null 2>&1 ; then
|
||||
echo i860-stardent-sysv${UNAME_RELEASE} # Stardent Vistra i860-SVR4
|
||||
else # Add other i860-SVR4 vendors below as they are discovered.
|
||||
echo i860-unknown-sysv${UNAME_RELEASE} # Unknown i860-SVR4
|
||||
fi
|
||||
exit 0 ;;
|
||||
mini*:CTIX:SYS*5:*)
|
||||
# "miniframe"
|
||||
echo m68010-convergent-sysv
|
||||
exit 0 ;;
|
||||
M68*:*:R3V[567]*:*)
|
||||
test -r /sysV68 && echo 'm68k-motorola-sysv' && exit 0 ;;
|
||||
3[34]??:*:4.0:3.0 | 3[34]??,*:*:4.0:3.0 | 4850:*:4.0:3.0)
|
||||
OS_REL=''
|
||||
test -r /etc/.relid \
|
||||
&& OS_REL=.`sed -n 's/[^ ]* [^ ]* \([0-9][0-9]\).*/\1/p' < /etc/.relid`
|
||||
/bin/uname -p 2>/dev/null | grep 86 >/dev/null \
|
||||
&& echo i486-ncr-sysv4.3${OS_REL} && exit 0
|
||||
/bin/uname -p 2>/dev/null | /bin/grep entium >/dev/null \
|
||||
&& echo i586-ncr-sysv4.3${OS_REL} && exit 0 ;;
|
||||
3[34]??:*:4.0:* | 3[34]??,*:*:4.0:*)
|
||||
/bin/uname -p 2>/dev/null | grep 86 >/dev/null \
|
||||
&& echo i486-ncr-sysv4 && exit 0 ;;
|
||||
m68*:LynxOS:2.*:*)
|
||||
echo m68k-unknown-lynxos${UNAME_RELEASE}
|
||||
exit 0 ;;
|
||||
mc68030:UNIX_System_V:4.*:*)
|
||||
echo m68k-atari-sysv4
|
||||
exit 0 ;;
|
||||
i?86:LynxOS:2.*:*)
|
||||
echo i386-unknown-lynxos${UNAME_RELEASE}
|
||||
exit 0 ;;
|
||||
TSUNAMI:LynxOS:2.*:*)
|
||||
echo sparc-unknown-lynxos${UNAME_RELEASE}
|
||||
exit 0 ;;
|
||||
rs6000:LynxOS:2.*:* | PowerPC:LynxOS:2.*:*)
|
||||
echo rs6000-unknown-lynxos${UNAME_RELEASE}
|
||||
exit 0 ;;
|
||||
SM[BE]S:UNIX_SV:*:*)
|
||||
echo mips-dde-sysv${UNAME_RELEASE}
|
||||
exit 0 ;;
|
||||
RM*:SINIX-*:*:*)
|
||||
echo mips-sni-sysv4
|
||||
exit 0 ;;
|
||||
*:SINIX-*:*:*)
|
||||
if uname -p 2>/dev/null >/dev/null ; then
|
||||
UNAME_MACHINE=`(uname -p) 2>/dev/null`
|
||||
echo ${UNAME_MACHINE}-sni-sysv4
|
||||
else
|
||||
echo ns32k-sni-sysv
|
||||
fi
|
||||
exit 0 ;;
|
||||
PENTIUM:CPunix:4.0*:*) # Unisys `ClearPath HMP IX 4000' SVR4/MP effort
|
||||
# says <[email protected]>
|
||||
echo i586-unisys-sysv4
|
||||
exit 0 ;;
|
||||
*:UNIX_System_V:4*:FTX*)
|
||||
# From Gerald Hewes <[email protected]>.
|
||||
# How about differentiating between stratus architectures? -djm
|
||||
echo hppa1.1-stratus-sysv4
|
||||
exit 0 ;;
|
||||
*:*:*:FTX*)
|
||||
# From [email protected].
|
||||
echo i860-stratus-sysv4
|
||||
exit 0 ;;
|
||||
mc68*:A/UX:*:*)
|
||||
echo m68k-apple-aux${UNAME_RELEASE}
|
||||
exit 0 ;;
|
||||
news*:NEWS-OS:*:6*)
|
||||
echo mips-sony-newsos6
|
||||
exit 0 ;;
|
||||
R3000:*System_V*:*:* | R4000:UNIX_SYSV:*:*)
|
||||
if [ -d /usr/nec ]; then
|
||||
echo mips-nec-sysv${UNAME_RELEASE}
|
||||
else
|
||||
echo mips-unknown-sysv${UNAME_RELEASE}
|
||||
fi
|
||||
exit 0 ;;
|
||||
esac
|
||||
|
||||
#echo '(No uname command or uname output not recognized.)' 1>&2
|
||||
#echo "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" 1>&2
|
||||
|
||||
cat >dummy.c <<EOF
|
||||
#ifdef _SEQUENT_
|
||||
# include <sys/types.h>
|
||||
# include <sys/utsname.h>
|
||||
#endif
|
||||
main ()
|
||||
{
|
||||
#if defined (sony)
|
||||
#if defined (MIPSEB)
|
||||
/* BFD wants "bsd" instead of "newsos". Perhaps BFD should be changed,
|
||||
I don't know.... */
|
||||
printf ("mips-sony-bsd\n"); exit (0);
|
||||
#else
|
||||
#include <sys/param.h>
|
||||
printf ("m68k-sony-newsos%s\n",
|
||||
#ifdef NEWSOS4
|
||||
"4"
|
||||
#else
|
||||
""
|
||||
#endif
|
||||
); exit (0);
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if defined (__arm) && defined (__acorn) && defined (__unix)
|
||||
printf ("arm-acorn-riscix"); exit (0);
|
||||
#endif
|
||||
|
||||
#if defined (hp300) && !defined (hpux)
|
||||
printf ("m68k-hp-bsd\n"); exit (0);
|
||||
#endif
|
||||
|
||||
#if defined (NeXT)
|
||||
#if !defined (__ARCHITECTURE__)
|
||||
#define __ARCHITECTURE__ "m68k"
|
||||
#endif
|
||||
int version;
|
||||
version=`(hostinfo | sed -n 's/.*NeXT Mach \([0-9]*\).*/\1/p') 2>/dev/null`;
|
||||
printf ("%s-next-nextstep%d\n", __ARCHITECTURE__, version);
|
||||
exit (0);
|
||||
#endif
|
||||
|
||||
#if defined (MULTIMAX) || defined (n16)
|
||||
#if defined (UMAXV)
|
||||
printf ("ns32k-encore-sysv\n"); exit (0);
|
||||
#else
|
||||
#if defined (CMU)
|
||||
printf ("ns32k-encore-mach\n"); exit (0);
|
||||
#else
|
||||
printf ("ns32k-encore-bsd\n"); exit (0);
|
||||
#endif
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if defined (__386BSD__)
|
||||
printf ("i386-pc-bsd\n"); exit (0);
|
||||
#endif
|
||||
|
||||
#if defined (sequent)
|
||||
#if defined (i386)
|
||||
printf ("i386-sequent-dynix\n"); exit (0);
|
||||
#endif
|
||||
#if defined (ns32000)
|
||||
printf ("ns32k-sequent-dynix\n"); exit (0);
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if defined (_SEQUENT_)
|
||||
struct utsname un;
|
||||
|
||||
uname(&un);
|
||||
|
||||
if (strncmp(un.version, "V2", 2) == 0) {
|
||||
printf ("i386-sequent-ptx2\n"); exit (0);
|
||||
}
|
||||
if (strncmp(un.version, "V1", 2) == 0) { /* XXX is V1 correct? */
|
||||
printf ("i386-sequent-ptx1\n"); exit (0);
|
||||
}
|
||||
printf ("i386-sequent-ptx\n"); exit (0);
|
||||
|
||||
#endif
|
||||
|
||||
#if defined (vax)
|
||||
#if !defined (ultrix)
|
||||
printf ("vax-dec-bsd\n"); exit (0);
|
||||
#else
|
||||
printf ("vax-dec-ultrix\n"); exit (0);
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if defined (alliant) && defined (i860)
|
||||
printf ("i860-alliant-bsd\n"); exit (0);
|
||||
#endif
|
||||
|
||||
exit (1);
|
||||
}
|
||||
EOF
|
||||
|
||||
${CC-cc} dummy.c -o dummy 2>/dev/null && ./dummy && rm dummy.c dummy && exit 0
|
||||
rm -f dummy.c dummy
|
||||
|
||||
# Apollos put the system type in the environment.
|
||||
|
||||
test -d /usr/apollo && { echo ${ISP}-apollo-${SYSTYPE}; exit 0; }
|
||||
|
||||
# Convex versions that predate uname can use getsysinfo(1)
|
||||
|
||||
if [ -x /usr/convex/getsysinfo ]
|
||||
then
|
||||
case `getsysinfo -f cpu_type` in
|
||||
c1*)
|
||||
echo c1-convex-bsd
|
||||
exit 0 ;;
|
||||
c2*)
|
||||
if getsysinfo -f scalar_acc
|
||||
then echo c32-convex-bsd
|
||||
else echo c2-convex-bsd
|
||||
fi
|
||||
exit 0 ;;
|
||||
c34*)
|
||||
echo c34-convex-bsd
|
||||
exit 0 ;;
|
||||
c38*)
|
||||
echo c38-convex-bsd
|
||||
exit 0 ;;
|
||||
c4*)
|
||||
echo c4-convex-bsd
|
||||
exit 0 ;;
|
||||
esac
|
||||
fi
|
||||
|
||||
#echo '(Unable to guess system type)' 1>&2
|
||||
|
||||
exit 1
|
||||
+1178
File diff suppressed because it is too large
Load Diff
+3
-1
@@ -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 ivlpp/Makefile vvm/Makefile)
|
||||
AC_OUTPUT(Makefile vpi/Makefile ivlpp/Makefile vvm/Makefile)
|
||||
|
||||
+310
-37
@@ -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.34 1999/08/01 16:34:50 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";
|
||||
@@ -121,26 +125,65 @@ void NetObj::dump_obj_attr(ostream&o, unsigned ind) const
|
||||
}
|
||||
}
|
||||
|
||||
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
|
||||
{
|
||||
o << setw(ind) << "" << "Procedural assign: " << *rval_ << endl;
|
||||
o << setw(ind) << "" << "Procedural assign (NetAssign): " << name();
|
||||
if (bmux())
|
||||
o << "[" << *bmux() << "]";
|
||||
o << " = " << *rval() << endl;
|
||||
dump_node_pins(o, ind+4);
|
||||
}
|
||||
|
||||
void NetAssignNB::dump_node(ostream&o, unsigned ind) const
|
||||
{
|
||||
if (bmux_)
|
||||
o << setw(ind) << "" << "Procedural NB assign: " << name()
|
||||
<< "[" << *bmux_ << "] <= " << *rval_ << endl;
|
||||
if (bmux())
|
||||
o << setw(ind) << "" << "Procedural NB assign (NetAssignNB): "
|
||||
<< name() << "[" << *bmux() << "] <= " << *rval() << endl;
|
||||
else
|
||||
o << setw(ind) << "" << "Procedural NB assign: " << name()
|
||||
<< " <= " << *rval_ << endl;
|
||||
o << setw(ind) << "" << "Procedural NB assign (NetAssignNB): "
|
||||
<< name() << " <= " << *rval() << endl;
|
||||
dump_node_pins(o, ind+4);
|
||||
}
|
||||
|
||||
void NetBUFZ::dump_node(ostream&o, unsigned ind) const
|
||||
{
|
||||
o << setw(ind) << "" << "BUFZ: " << name() << endl;
|
||||
o << setw(ind) << "" << "NetBUFZ: " << name() << endl;
|
||||
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);
|
||||
}
|
||||
|
||||
@@ -150,6 +193,13 @@ void NetConst::dump_node(ostream&o, unsigned ind) const
|
||||
dump_node_pins(o, ind+4);
|
||||
}
|
||||
|
||||
void NetFF::dump_node(ostream&o, unsigned ind) const
|
||||
{
|
||||
o << setw(ind) << "" << "LPM_FF: " << name() << endl;
|
||||
dump_node_pins(o, ind+4);
|
||||
dump_obj_attr(o, ind+4);
|
||||
}
|
||||
|
||||
void NetLogic::dump_node(ostream&o, unsigned ind) const
|
||||
{
|
||||
o << setw(ind) << "" << "logic: ";
|
||||
@@ -193,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;
|
||||
@@ -273,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);
|
||||
}
|
||||
@@ -327,28 +391,35 @@ void NetAssign::dump(ostream&o, unsigned ind) const
|
||||
{
|
||||
o << setw(ind) << "";
|
||||
|
||||
const NetNet*sig;
|
||||
unsigned msb, lsb;
|
||||
find_lval_range(sig, msb, lsb);
|
||||
o << sig->name() << "[" << msb;
|
||||
if (pin_count() > 1)
|
||||
o << ":" << lsb;
|
||||
o << "] = ";
|
||||
|
||||
rval_->dump(o);
|
||||
o << ";" << endl;
|
||||
if (bmux()) {
|
||||
o << name() << "[" << *bmux() << "] = ";
|
||||
if (rise_time())
|
||||
o << "#" << rise_time() << " ";
|
||||
o << *rval() << ";" << endl;
|
||||
|
||||
} else {
|
||||
o << name() << " = ";
|
||||
if (rise_time())
|
||||
o << "#" << rise_time() << " ";
|
||||
o << *rval() << ";" << endl;
|
||||
}
|
||||
}
|
||||
|
||||
void NetAssignNB::dump(ostream&o, unsigned ind) const
|
||||
{
|
||||
o << setw(ind) << "";
|
||||
|
||||
if (bmux_) {
|
||||
o << name() << "[" << *bmux_ << "] <= " << *rval_ << ";" <<
|
||||
endl;
|
||||
if (bmux()) {
|
||||
o << name() << "[" << *bmux() << "] <= ";
|
||||
if (rise_time())
|
||||
o << "#" << rise_time() << " ";
|
||||
o << *rval() << ";" << endl;
|
||||
|
||||
} else {
|
||||
o << name() << " <= " << *rval_ << ";" << endl;
|
||||
o << name() << " <= ";
|
||||
if (rise_time())
|
||||
o << "#" << rise_time() << " ";
|
||||
o << *rval() << ";" << endl;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -357,10 +428,22 @@ void NetAssignMem::dump(ostream&o, unsigned ind) const
|
||||
o << setw(ind) << "";
|
||||
o << "/* " << get_line() << " */" << endl;
|
||||
o << setw(ind) << "";
|
||||
o << mem_->name() << "[";
|
||||
index_->dump(o);
|
||||
o << memory()->name() << "[";
|
||||
index()->dump(o);
|
||||
o << "] = ";
|
||||
rval_->dump(o);
|
||||
rval()->dump(o);
|
||||
o << ";" << endl;
|
||||
}
|
||||
|
||||
void NetAssignMemNB::dump(ostream&o, unsigned ind) const
|
||||
{
|
||||
o << setw(ind) << "";
|
||||
o << "/* " << get_line() << " */" << endl;
|
||||
o << setw(ind) << "";
|
||||
o << memory()->name() << "[";
|
||||
index()->dump(o);
|
||||
o << "] <= ";
|
||||
rval()->dump(o);
|
||||
o << ";" << endl;
|
||||
}
|
||||
|
||||
@@ -382,7 +465,17 @@ void NetBlock::dump(ostream&o, unsigned ind) const
|
||||
|
||||
void NetCase::dump(ostream&o, unsigned ind) const
|
||||
{
|
||||
o << setw(ind) << "" << "case (" << *expr_ << ")" << endl;
|
||||
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) {
|
||||
o << setw(ind+2) << "";
|
||||
@@ -423,6 +516,15 @@ void NetForever::dump(ostream&o, unsigned ind) const
|
||||
statement_->dump(o, ind+2);
|
||||
}
|
||||
|
||||
void NetFuncDef::dump(ostream&o, unsigned ind) const
|
||||
{
|
||||
o << setw(ind) << "" << "function " << name_ << endl;
|
||||
if (statement_)
|
||||
statement_->dump(o, ind+2);
|
||||
else
|
||||
o << setw(ind+2) << "" << "// NO STATEMENT" << endl;
|
||||
}
|
||||
|
||||
void NetPDelay::dump(ostream&o, unsigned ind) const
|
||||
{
|
||||
o << setw(ind) << "" << "#" << delay_;
|
||||
@@ -479,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_;
|
||||
@@ -558,9 +677,15 @@ void NetEBinary::dump(ostream&o) const
|
||||
case 'o':
|
||||
o << "||";
|
||||
break;
|
||||
case 'O':
|
||||
o << "~|";
|
||||
break;
|
||||
case 'r':
|
||||
o << ">>";
|
||||
break;
|
||||
case 'X':
|
||||
o << "~^";
|
||||
break;
|
||||
}
|
||||
o << "(";
|
||||
right_->dump(o);
|
||||
@@ -569,9 +694,20 @@ void NetEBinary::dump(ostream&o) const
|
||||
|
||||
void NetEConcat::dump(ostream&o) const
|
||||
{
|
||||
o << "{" << *parms_[0];
|
||||
for (unsigned idx = 1 ; idx < parms_.count() ; idx += 1)
|
||||
o << ", " << *parms_[idx];
|
||||
if (repeat_ != 1)
|
||||
o << repeat_;
|
||||
|
||||
if (parms_[0])
|
||||
o << "{" << *parms_[0];
|
||||
else
|
||||
o << "{";
|
||||
|
||||
for (unsigned idx = 1 ; idx < parms_.count() ; idx += 1) {
|
||||
if (parms_[idx])
|
||||
o << ", " << *parms_[idx];
|
||||
else
|
||||
o << ", ";
|
||||
}
|
||||
o << "}";
|
||||
}
|
||||
|
||||
@@ -588,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();
|
||||
@@ -608,28 +749,54 @@ void NetEMemory::dump(ostream&o) const
|
||||
o << "]";
|
||||
}
|
||||
|
||||
void NetESignal::dump_node(ostream&o, unsigned ind) const
|
||||
void NetEParam::dump(ostream&o) const
|
||||
{
|
||||
o << setw(ind) << "" << "Expression Node: " << name() << endl;
|
||||
|
||||
dump_node_pins(o, ind+4);
|
||||
o << "<" << path_ << "." << name_ << ">";
|
||||
}
|
||||
|
||||
void NetETernary::dump(ostream&o) const
|
||||
{
|
||||
o << "(" << *cond_ << ")? (" << *true_val_ << ") : (" <<
|
||||
false_val_ << ")";
|
||||
o << "(" << *cond_ << ") ? (" << *true_val_ << ") : (" <<
|
||||
*false_val_ << ")";
|
||||
}
|
||||
|
||||
void NetEUFunc::dump(ostream&o) const
|
||||
{
|
||||
o << name() << "(";
|
||||
assert(parms_.count() > 0);
|
||||
parms_[0]->dump(o);
|
||||
for (unsigned idx = 1 ; idx < parms_.count() ; idx += 1) {
|
||||
o << ", ";
|
||||
parms_[idx]->dump(o);
|
||||
}
|
||||
o << ")";
|
||||
}
|
||||
|
||||
void NetEUnary::dump(ostream&o) const
|
||||
{
|
||||
o << op_ << "(";
|
||||
switch (op_) {
|
||||
case 'N':
|
||||
o << "~|";
|
||||
break;
|
||||
default:
|
||||
o << op_;
|
||||
break;
|
||||
}
|
||||
o << "(";
|
||||
expr_->dump(o);
|
||||
o << ")";
|
||||
}
|
||||
|
||||
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;
|
||||
@@ -660,6 +827,15 @@ void Design::dump(ostream&o) const
|
||||
}
|
||||
}
|
||||
|
||||
o << "ELABORATED FUNCTION DEFINITIONS:" << endl;
|
||||
{
|
||||
map<string,NetFuncDef*>::const_iterator pp;
|
||||
for (pp = funcs_.begin()
|
||||
; pp != funcs_.end() ; pp ++) {
|
||||
(*pp).second->dump(o, 0);
|
||||
}
|
||||
}
|
||||
|
||||
o << "ELABORATED TASK DEFINITIONS:" << endl;
|
||||
{
|
||||
map<string,NetTaskDef*>::const_iterator pp;
|
||||
@@ -690,6 +866,103 @@ 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.
|
||||
*
|
||||
* Revision 1.47 1999/10/06 05:06:16 steve
|
||||
* Move the rvalue into NetAssign_ common code.
|
||||
*
|
||||
* Revision 1.46 1999/10/05 06:19:46 steve
|
||||
* Add support for reduction NOR.
|
||||
*
|
||||
* Revision 1.45 1999/09/30 02:43:01 steve
|
||||
* Elaborate ~^ and ~| operators.
|
||||
*
|
||||
* Revision 1.44 1999/09/29 18:36:03 steve
|
||||
* Full case support
|
||||
*
|
||||
* Revision 1.43 1999/09/21 00:13:40 steve
|
||||
* Support parameters that reference other paramters.
|
||||
*
|
||||
* Revision 1.42 1999/09/20 02:21:10 steve
|
||||
* Elaborate parameters in phases.
|
||||
*
|
||||
* Revision 1.41 1999/09/19 01:06:36 steve
|
||||
* dump the repeat count, if applicable.
|
||||
*
|
||||
* Revision 1.40 1999/09/15 01:55:06 steve
|
||||
* Elaborate non-blocking assignment to memories.
|
||||
*
|
||||
* Revision 1.39 1999/09/04 19:11:46 steve
|
||||
* Add support for delayed non-blocking assignments.
|
||||
*
|
||||
* Revision 1.38 1999/09/03 04:28:38 steve
|
||||
* elaborate the binary plus operator.
|
||||
*
|
||||
* Revision 1.37 1999/09/01 20:46:19 steve
|
||||
* Handle recursive functions and arbitrary function
|
||||
* references to other functions, properly pass
|
||||
* function parameters and save function results.
|
||||
*
|
||||
* Revision 1.36 1999/08/31 22:38:29 steve
|
||||
* Elaborate and emit to vvm procedural functions.
|
||||
*
|
||||
* Revision 1.35 1999/08/25 22:22:41 steve
|
||||
* elaborate some aspects of functions.
|
||||
*
|
||||
* Revision 1.34 1999/08/01 16:34:50 steve
|
||||
* Parse and elaborate rise/fall/decay times
|
||||
* for gates, and handle the rules for partial
|
||||
|
||||
@@ -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,22 +17,22 @@
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
|
||||
*/
|
||||
#if !defined(WINNT)
|
||||
#ident "$Id: vvm_monitor.cc,v 1.1 1998/11/09 23:44:11 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 string&n)
|
||||
: name_(n)
|
||||
NetEScope* NetEScope::dup_expr() const
|
||||
{
|
||||
assert(0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* $Log: vvm_monitor.cc,v $
|
||||
* 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.
|
||||
*
|
||||
*/
|
||||
|
||||
+373
@@ -0,0 +1,373 @@
|
||||
/*
|
||||
* 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_expr.cc,v 1.12 1999/11/30 04:54:01 steve Exp $"
|
||||
#endif
|
||||
|
||||
|
||||
# include "pform.h"
|
||||
# include "netlist.h"
|
||||
|
||||
/*
|
||||
* Elaborate binary expressions. This involves elaborating the left
|
||||
* and right sides, and creating one of a variety of different NetExpr
|
||||
* types.
|
||||
*/
|
||||
NetExpr* PEBinary::elaborate_expr(Design*des, const string&path) const
|
||||
{
|
||||
bool flag;
|
||||
NetExpr*lp = left_->elaborate_expr(des, path);
|
||||
NetExpr*rp = right_->elaborate_expr(des, path);
|
||||
if ((lp == 0) || (rp == 0)) {
|
||||
delete lp;
|
||||
delete rp;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* If either expression can be evaluated ahead of time, then
|
||||
do so. This can prove helpful later. */
|
||||
{ NetExpr*tmp;
|
||||
tmp = lp->eval_tree();
|
||||
if (tmp) {
|
||||
delete lp;
|
||||
lp = tmp;
|
||||
}
|
||||
tmp = rp->eval_tree();
|
||||
if (tmp) {
|
||||
delete rp;
|
||||
rp = tmp;
|
||||
}
|
||||
}
|
||||
|
||||
NetEBinary*tmp;
|
||||
switch (op_) {
|
||||
default:
|
||||
tmp = new NetEBinary(op_, lp, rp);
|
||||
tmp->set_line(*this);
|
||||
break;
|
||||
|
||||
case 'a':
|
||||
case 'o':
|
||||
tmp = new NetEBLogic(op_, lp, rp);
|
||||
tmp->set_line(*this);
|
||||
break;
|
||||
|
||||
case 'l':
|
||||
case 'r':
|
||||
tmp = new NetEBShift(op_, lp, rp);
|
||||
tmp->set_line(*this);
|
||||
break;
|
||||
|
||||
case '^':
|
||||
case '&':
|
||||
case '|':
|
||||
case 'O':
|
||||
case 'X':
|
||||
tmp = new NetEBBits(op_, lp, rp);
|
||||
tmp->set_line(*this);
|
||||
break;
|
||||
|
||||
case '+':
|
||||
case '-':
|
||||
tmp = new NetEBAdd(op_, lp, rp);
|
||||
tmp->set_line(*this);
|
||||
break;
|
||||
|
||||
case 'e': /* == */
|
||||
case 'E': /* === */
|
||||
case 'n': /* != */
|
||||
case 'N': /* !== */
|
||||
case 'L': /* <= */
|
||||
case 'G': /* >= */
|
||||
case '<':
|
||||
case '>':
|
||||
tmp = new NetEBComp(op_, lp, rp);
|
||||
tmp->set_line(*this);
|
||||
flag = tmp->set_width(1);
|
||||
if (flag == false) {
|
||||
cerr << get_line() << ": internal error: "
|
||||
"expression bit width of comparison != 1." << endl;
|
||||
des->errors += 1;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
return tmp;
|
||||
}
|
||||
|
||||
NetESFunc* PECallFunction::elaborate_sfunc_(Design*des, const string&path) const
|
||||
{
|
||||
cerr << get_line() << ": sorry: system functions not supported."
|
||||
<< endl;
|
||||
des->errors += 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
NetExpr* PECallFunction::elaborate_expr(Design*des, const string&path) const
|
||||
{
|
||||
if (name_[0] == '$')
|
||||
return elaborate_sfunc_(des, path);
|
||||
|
||||
string myname = path+"."+name_;
|
||||
NetFuncDef*def = des->find_function(path, name_);
|
||||
if (def == 0) {
|
||||
cerr << get_line() << ": error: No function " << name_ <<
|
||||
" in this context (" << path << ")." << endl;
|
||||
des->errors += 1;
|
||||
return 0;
|
||||
}
|
||||
assert(def);
|
||||
svector<NetExpr*> parms (parms_.count());
|
||||
|
||||
for (unsigned idx = 0 ; idx < parms.count() ; idx += 1) {
|
||||
NetExpr*tmp = parms_[idx]->elaborate_expr(des, myname);
|
||||
parms[idx] = tmp;
|
||||
}
|
||||
|
||||
/* Look for the return value signal for the called function in
|
||||
the context of the function definition, not my context. */
|
||||
NetNet*res = des->find_signal(def->name(), name_);
|
||||
if (res == 0) {
|
||||
cerr << get_line() << ": internal error: Unable to locate "
|
||||
"function return value for " << name_ << " in " <<
|
||||
def->name() << "." << endl;
|
||||
des->errors += 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
assert(res);
|
||||
NetESignal*eres = new NetESignal(res);
|
||||
assert(eres);
|
||||
NetEUFunc*func = new NetEUFunc(def, eres, parms);
|
||||
return func;
|
||||
}
|
||||
|
||||
|
||||
NetExpr* PEIdent::elaborate_expr(Design*des, const string&path) const
|
||||
{
|
||||
// System identifiers show up in the netlist as identifiers.
|
||||
if (text_[0] == '$')
|
||||
return new NetEIdent(text_, 64);
|
||||
|
||||
string name = path+"."+text_;
|
||||
|
||||
// If the identifier name is a parameter name, then return
|
||||
// a reference to the parameter expression.
|
||||
if (const NetExpr*ex = des->find_parameter(path, text_)) {
|
||||
NetExpr*tmp;
|
||||
if (dynamic_cast<const NetExpr*>(ex))
|
||||
tmp = ex->dup_expr();
|
||||
else
|
||||
tmp = new NetEParam(des, path, text_);
|
||||
|
||||
tmp->set_line(*this);
|
||||
return tmp;
|
||||
}
|
||||
|
||||
// If the identifier names a signal (a register or wire)
|
||||
// then create a NetESignal node to handle it.
|
||||
if (NetNet*net = des->find_signal(path, text_)) {
|
||||
|
||||
// If this is a part select of a signal, then make a new
|
||||
// temporary signal that is connected to just the
|
||||
// selected bits.
|
||||
if (lsb_) {
|
||||
assert(msb_);
|
||||
verinum*lsn = lsb_->eval_const(des, path);
|
||||
verinum*msn = msb_->eval_const(des, path);
|
||||
if ((lsn == 0) || (msn == 0)) {
|
||||
cerr << get_line() << ": error: "
|
||||
"Part select expresions must be "
|
||||
"constant expressions." << endl;
|
||||
des->errors += 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
assert(lsn);
|
||||
assert(msn);
|
||||
unsigned long lsv = lsn->as_ulong();
|
||||
unsigned long msv = msn->as_ulong();
|
||||
unsigned long wid = 1 + ((msv>lsv)? (msv-lsv) : (lsv-msv));
|
||||
assert(wid <= net->pin_count());
|
||||
assert(net->sb_to_idx(msv) >= net->sb_to_idx(lsv));
|
||||
|
||||
string tname = des->local_symbol(path);
|
||||
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(tsig->pin(idx), net->pin(idx+off));
|
||||
|
||||
NetESignal*tmp = new NetESignal(tsig);
|
||||
tmp->set_line(*this);
|
||||
|
||||
des->add_signal(tsig);
|
||||
return tmp;
|
||||
}
|
||||
|
||||
// If the bit select is constant, then treat it similar
|
||||
// to the part select, so that I save the effort of
|
||||
// making a mux part in the netlist.
|
||||
verinum*msn;
|
||||
if (msb_ && (msn = msb_->eval_const(des, path))) {
|
||||
assert(idx_ == 0);
|
||||
unsigned long msv = msn->as_ulong();
|
||||
|
||||
string tname = des->local_symbol(path);
|
||||
NetTmp*tsig = new NetTmp(tname);
|
||||
connect(tsig->pin(0), net->pin(msv));
|
||||
NetESignal*tmp = new NetESignal(tsig);
|
||||
tmp->set_line(*this);
|
||||
|
||||
des->add_signal(tsig);
|
||||
return tmp;
|
||||
}
|
||||
|
||||
NetESignal*node = new NetESignal(net);
|
||||
assert(idx_ == 0);
|
||||
|
||||
// Non-constant bit select? punt and make a subsignal
|
||||
// device to mux the bit in the net.
|
||||
if (msb_) {
|
||||
NetExpr*ex = msb_->elaborate_expr(des, path);
|
||||
NetESubSignal*ss = new NetESubSignal(node, ex);
|
||||
ss->set_line(*this);
|
||||
return ss;
|
||||
}
|
||||
|
||||
// All else fails, return the signal itself as the
|
||||
// expression.
|
||||
assert(msb_ == 0);
|
||||
return node;
|
||||
}
|
||||
|
||||
// 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(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 (msb_ && i == 0) {
|
||||
cerr << get_line() << ": error: Unable to exaborate "
|
||||
"index expression `" << *msb_ << "'" << endl;
|
||||
des->errors += 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
NetEMemory*node = new NetEMemory(mem, i);
|
||||
node->set_line(*this);
|
||||
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;
|
||||
des->errors += 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Elaborate the Ternary operator. I know that the expressions were
|
||||
* parsed so I can presume that they exist, and call elaboration
|
||||
* methods. If any elaboration fails, then give up and return 0.
|
||||
*/
|
||||
NetExpr*PETernary::elaborate_expr(Design*des, const string&path) const
|
||||
{
|
||||
assert(expr_);
|
||||
assert(tru_);
|
||||
assert(fal_);
|
||||
|
||||
NetExpr*con = expr_->elaborate_expr(des, path);
|
||||
if (con == 0)
|
||||
return 0;
|
||||
|
||||
NetExpr*tru = tru_->elaborate_expr(des, path);
|
||||
if (tru == 0) {
|
||||
delete con;
|
||||
return 0;
|
||||
}
|
||||
|
||||
NetExpr*fal = fal_->elaborate_expr(des, path);
|
||||
if (fal == 0) {
|
||||
delete con;
|
||||
delete tru;
|
||||
return 0;
|
||||
}
|
||||
|
||||
NetETernary*res = new NetETernary(con, tru, fal);
|
||||
return res;
|
||||
}
|
||||
|
||||
/*
|
||||
* $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.
|
||||
*
|
||||
* Revision 1.5 1999/09/30 00:48:49 steve
|
||||
* Cope with errors during ternary operator elaboration.
|
||||
*
|
||||
* Revision 1.4 1999/09/29 22:57:10 steve
|
||||
* Move code to elab_expr.cc
|
||||
*
|
||||
* Revision 1.3 1999/09/25 02:57:30 steve
|
||||
* Parse system function calls.
|
||||
*
|
||||
* Revision 1.2 1999/09/21 00:13:40 steve
|
||||
* Support parameters that reference other paramters.
|
||||
*
|
||||
* Revision 1.1 1999/09/20 02:21:10 steve
|
||||
* Elaborate parameters in phases.
|
||||
*
|
||||
*/
|
||||
|
||||
+945
@@ -0,0 +1,945 @@
|
||||
/*
|
||||
* Copyright (c) 1999 Stephen Williams ([email protected])
|
||||
*
|
||||
* This source code is free software; you can redistribute it
|
||||
* and/or modify it in source code form under the terms of the GNU
|
||||
* General Public License as published by the Free Software
|
||||
* Foundation; either version 2 of the License, or (at your option)
|
||||
* any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
|
||||
*/
|
||||
#if !defined(WINNT)
|
||||
#ident "$Id: elab_net.cc,v 1.11 1999/12/02 04:08:10 steve Exp $"
|
||||
#endif
|
||||
|
||||
# include "PExpr.h"
|
||||
# include "netlist.h"
|
||||
|
||||
/*
|
||||
* Elaborating binary operations generally involves elaborating the
|
||||
* left and right expressions, then making an output wire and
|
||||
* connecting the lot together with the right kind of gate.
|
||||
*/
|
||||
NetNet* PEBinary::elaborate_net(Design*des, const string&path,
|
||||
unsigned width,
|
||||
unsigned long rise,
|
||||
unsigned long fall,
|
||||
unsigned long decay) const
|
||||
{
|
||||
switch (op_) {
|
||||
case '+':
|
||||
case '-':
|
||||
return elaborate_net_add_(des, path, width, rise, fall, decay);
|
||||
case 'E':
|
||||
case 'e':
|
||||
case 'n':
|
||||
case '<':
|
||||
case '>':
|
||||
case 'L': // <=
|
||||
case 'G': // >=
|
||||
return elaborate_net_cmp_(des, path, width, rise, fall, decay);
|
||||
case 'l': // <<
|
||||
case 'r': // >>
|
||||
return elaborate_net_shift_(des, path, width, rise, fall, decay);
|
||||
}
|
||||
|
||||
NetNet*lsig = left_->elaborate_net(des, path, width, 0, 0, 0),
|
||||
*rsig = right_->elaborate_net(des, path, width, 0, 0, 0);
|
||||
if (lsig == 0) {
|
||||
cerr << get_line() << ": error: Cannot elaborate ";
|
||||
left_->dump(cerr);
|
||||
cerr << endl;
|
||||
return 0;
|
||||
}
|
||||
if (rsig == 0) {
|
||||
cerr << get_line() << ": error: Cannot elaborate ";
|
||||
right_->dump(cerr);
|
||||
cerr << endl;
|
||||
return 0;
|
||||
}
|
||||
|
||||
NetNet*osig;
|
||||
NetNode*gate;
|
||||
NetNode*gate_t;
|
||||
|
||||
switch (op_) {
|
||||
case '^': // XOR
|
||||
assert(lsig->pin_count() == rsig->pin_count());
|
||||
osig = new NetNet(0, des->local_symbol(path), NetNet::WIRE,
|
||||
lsig->pin_count());
|
||||
osig->local_flag(true);
|
||||
for (unsigned idx = 0 ; idx < lsig->pin_count() ; idx += 1) {
|
||||
gate = new NetLogic(des->local_symbol(path), 3,
|
||||
NetLogic::XOR);
|
||||
connect(gate->pin(1), lsig->pin(idx));
|
||||
connect(gate->pin(2), rsig->pin(idx));
|
||||
connect(gate->pin(0), osig->pin(idx));
|
||||
gate->rise_time(rise);
|
||||
gate->fall_time(fall);
|
||||
gate->decay_time(decay);
|
||||
des->add_node(gate);
|
||||
}
|
||||
des->add_signal(osig);
|
||||
break;
|
||||
|
||||
case '&': // AND
|
||||
assert(lsig->pin_count() == rsig->pin_count());
|
||||
osig = new NetNet(0, des->local_symbol(path), NetNet::WIRE,
|
||||
lsig->pin_count());
|
||||
osig->local_flag(true);
|
||||
for (unsigned idx = 0 ; idx < lsig->pin_count() ; idx += 1) {
|
||||
gate = new NetLogic(des->local_symbol(path), 3,
|
||||
NetLogic::AND);
|
||||
connect(gate->pin(1), lsig->pin(idx));
|
||||
connect(gate->pin(2), rsig->pin(idx));
|
||||
connect(gate->pin(0), osig->pin(idx));
|
||||
gate->rise_time(rise);
|
||||
gate->fall_time(fall);
|
||||
gate->decay_time(decay);
|
||||
des->add_node(gate);
|
||||
}
|
||||
des->add_signal(osig);
|
||||
break;
|
||||
|
||||
case '|': // Bitwise OR
|
||||
assert(lsig->pin_count() == rsig->pin_count());
|
||||
osig = new NetNet(0, des->local_symbol(path), NetNet::WIRE,
|
||||
lsig->pin_count());
|
||||
osig->local_flag(true);
|
||||
for (unsigned idx = 0 ; idx < lsig->pin_count() ; idx += 1) {
|
||||
gate = new NetLogic(des->local_symbol(path), 3,
|
||||
NetLogic::OR);
|
||||
connect(gate->pin(1), lsig->pin(idx));
|
||||
connect(gate->pin(2), rsig->pin(idx));
|
||||
connect(gate->pin(0), osig->pin(idx));
|
||||
gate->rise_time(rise);
|
||||
gate->fall_time(fall);
|
||||
gate->decay_time(decay);
|
||||
des->add_node(gate);
|
||||
}
|
||||
des->add_signal(osig);
|
||||
break;
|
||||
|
||||
case 'a': // && (logical AND)
|
||||
gate = new NetLogic(des->local_symbol(path), 3, NetLogic::AND);
|
||||
|
||||
// The first OR gate returns 1 if the left value is true...
|
||||
if (lsig->pin_count() > 1) {
|
||||
gate_t = new NetLogic(des->local_symbol(path),
|
||||
1+lsig->pin_count(), NetLogic::OR);
|
||||
for (unsigned idx = 0 ; idx < lsig->pin_count() ; idx += 1)
|
||||
connect(gate_t->pin(idx+1), lsig->pin(idx));
|
||||
connect(gate->pin(1), gate_t->pin(0));
|
||||
des->add_node(gate_t);
|
||||
} else {
|
||||
connect(gate->pin(1), lsig->pin(0));
|
||||
}
|
||||
|
||||
// The second OR gate returns 1 if the right value is true...
|
||||
if (rsig->pin_count() > 1) {
|
||||
gate_t = new NetLogic(des->local_symbol(path),
|
||||
1+rsig->pin_count(), NetLogic::OR);
|
||||
for (unsigned idx = 0 ; idx < rsig->pin_count() ; idx += 1)
|
||||
connect(gate_t->pin(idx+1), rsig->pin(idx));
|
||||
connect(gate->pin(2), gate_t->pin(0));
|
||||
des->add_node(gate_t);
|
||||
} else {
|
||||
connect(gate->pin(2), rsig->pin(0));
|
||||
}
|
||||
|
||||
// The output is the AND of the two logic values.
|
||||
osig = new NetNet(0, des->local_symbol(path), NetNet::WIRE);
|
||||
osig->local_flag(true);
|
||||
connect(gate->pin(0), osig->pin(0));
|
||||
des->add_signal(osig);
|
||||
gate->rise_time(rise);
|
||||
gate->fall_time(fall);
|
||||
gate->decay_time(decay);
|
||||
des->add_node(gate);
|
||||
break;
|
||||
|
||||
case 'E': // === (Case equals)
|
||||
case 'e': // ==
|
||||
case 'n': // !=
|
||||
case '<':
|
||||
case '>':
|
||||
case 'G': // >=
|
||||
case 'L': // <=
|
||||
assert(0);
|
||||
break;
|
||||
|
||||
case '+':
|
||||
assert(0);
|
||||
break;
|
||||
|
||||
case 'l':
|
||||
case 'r':
|
||||
assert(0);
|
||||
break;
|
||||
default:
|
||||
cerr << get_line() << ": internal error: unsupported"
|
||||
" combinational operator (" << op_ << ")." << endl;
|
||||
des->errors += 1;
|
||||
osig = 0;
|
||||
}
|
||||
|
||||
if (NetTmp*tmp = dynamic_cast<NetTmp*>(lsig))
|
||||
delete tmp;
|
||||
if (NetTmp*tmp = dynamic_cast<NetTmp*>(rsig))
|
||||
delete tmp;
|
||||
|
||||
return osig;
|
||||
}
|
||||
|
||||
/*
|
||||
* Elaborate the structural +/- as an AddSub object. Connect DataA and
|
||||
* DataB to the parameters, and connect the output signal to the
|
||||
* Result. In this context, the device is a combinational adder with
|
||||
* fixed direction, so leave Add_Sub unconnected and set the
|
||||
* LPM_Direction property.
|
||||
*/
|
||||
NetNet* PEBinary::elaborate_net_add_(Design*des, const string&path,
|
||||
unsigned lwidth,
|
||||
unsigned long rise,
|
||||
unsigned long fall,
|
||||
unsigned long decay) const
|
||||
{
|
||||
NetNet*lsig = left_->elaborate_net(des, path, lwidth, 0, 0, 0),
|
||||
*rsig = right_->elaborate_net(des, path, lwidth, 0, 0, 0);
|
||||
if (lsig == 0) {
|
||||
cerr << get_line() << ": error: Cannot elaborate ";
|
||||
left_->dump(cerr);
|
||||
cerr << endl;
|
||||
return 0;
|
||||
}
|
||||
if (rsig == 0) {
|
||||
cerr << get_line() << ": error: Cannot elaborate ";
|
||||
right_->dump(cerr);
|
||||
cerr << endl;
|
||||
return 0;
|
||||
}
|
||||
|
||||
NetNet*osig;
|
||||
NetNode*gate;
|
||||
NetNode*gate_t;
|
||||
|
||||
string name = des->local_symbol(path);
|
||||
unsigned width = lsig->pin_count();
|
||||
if (rsig->pin_count() > lsig->pin_count())
|
||||
width = rsig->pin_count();
|
||||
|
||||
// Make the adder as wide as the widest operand
|
||||
osig = new NetNet(0, des->local_symbol(path), NetNet::WIRE, width);
|
||||
NetAddSub*adder = new NetAddSub(name, width);
|
||||
|
||||
// Connect the adder to the various parts.
|
||||
for (unsigned idx = 0 ; idx < lsig->pin_count() ; idx += 1)
|
||||
connect(lsig->pin(idx), adder->pin_DataA(idx));
|
||||
for (unsigned idx = 0 ; idx < rsig->pin_count() ; idx += 1)
|
||||
connect(rsig->pin(idx), adder->pin_DataB(idx));
|
||||
for (unsigned idx = 0 ; idx < osig->pin_count() ; idx += 1)
|
||||
connect(osig->pin(idx), adder->pin_Result(idx));
|
||||
|
||||
gate = adder;
|
||||
des->add_signal(osig);
|
||||
gate->rise_time(rise);
|
||||
gate->fall_time(fall);
|
||||
gate->decay_time(decay);
|
||||
des->add_node(gate);
|
||||
|
||||
switch (op_) {
|
||||
case '+':
|
||||
gate->attribute("LPM_Direction", "ADD");
|
||||
break;
|
||||
case '-':
|
||||
gate->attribute("LPM_Direction", "SUB");
|
||||
break;
|
||||
}
|
||||
|
||||
if (NetTmp*tmp = dynamic_cast<NetTmp*>(lsig))
|
||||
delete tmp;
|
||||
if (NetTmp*tmp = dynamic_cast<NetTmp*>(rsig))
|
||||
delete tmp;
|
||||
|
||||
return osig;
|
||||
}
|
||||
|
||||
/*
|
||||
* Elaborate the various binary comparison operators.
|
||||
*/
|
||||
NetNet* PEBinary::elaborate_net_cmp_(Design*des, const string&path,
|
||||
unsigned lwidth,
|
||||
unsigned long rise,
|
||||
unsigned long fall,
|
||||
unsigned long decay) const
|
||||
{
|
||||
NetNet*lsig = left_->elaborate_net(des, path, 0, 0, 0, 0),
|
||||
*rsig = right_->elaborate_net(des, path, 0, 0, 0, 0);
|
||||
if (lsig == 0) {
|
||||
cerr << get_line() << ": error: Cannot elaborate ";
|
||||
left_->dump(cerr);
|
||||
cerr << endl;
|
||||
return 0;
|
||||
}
|
||||
if (rsig == 0) {
|
||||
cerr << get_line() << ": error: Cannot elaborate ";
|
||||
right_->dump(cerr);
|
||||
cerr << endl;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (lsig->pin_count() != rsig->pin_count()) {
|
||||
cerr << get_line() << ": internal error: Cannot match "
|
||||
"structural net widths " << lsig->pin_count() <<
|
||||
" and " << rsig->pin_count() << "." << endl;
|
||||
delete lsig;
|
||||
delete rsig;
|
||||
des->errors += 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
NetNet*osig = new NetNet(0, des->local_symbol(path), NetNet::WIRE);
|
||||
osig->local_flag(true);
|
||||
|
||||
NetNode*gate;
|
||||
NetNode*gate_t;
|
||||
|
||||
switch (op_) {
|
||||
case '<':
|
||||
case '>':
|
||||
case 'L':
|
||||
case 'G': {
|
||||
NetCompare*cmp = new NetCompare(des->local_symbol(path),
|
||||
lsig->pin_count());
|
||||
for (unsigned idx = 0 ; idx < lsig->pin_count() ; idx += 1) {
|
||||
connect(cmp->pin_DataA(idx), lsig->pin(idx));
|
||||
connect(cmp->pin_DataB(idx), rsig->pin(idx));
|
||||
}
|
||||
switch (op_) {
|
||||
case '<':
|
||||
connect(cmp->pin_ALB(), osig->pin(0));
|
||||
break;
|
||||
case '>':
|
||||
connect(cmp->pin_AGB(), osig->pin(0));
|
||||
break;
|
||||
case 'L':
|
||||
connect(cmp->pin_ALEB(), osig->pin(0));
|
||||
break;
|
||||
case 'G':
|
||||
connect(cmp->pin_AGEB(), osig->pin(0));
|
||||
break;
|
||||
}
|
||||
gate = cmp;
|
||||
break;
|
||||
}
|
||||
|
||||
case 'E': // Case equals (===)
|
||||
// The comparison generates gates to bitwise compare
|
||||
// each pair, and AND all the comparison results.
|
||||
gate = new NetLogic(des->local_symbol(path),
|
||||
1+lsig->pin_count(),
|
||||
NetLogic::AND);
|
||||
connect(gate->pin(0), osig->pin(0));
|
||||
for (unsigned idx = 0 ; idx < lsig->pin_count() ; idx += 1) {
|
||||
gate_t = new NetCaseCmp(des->local_symbol(path));
|
||||
connect(gate_t->pin(1), lsig->pin(idx));
|
||||
connect(gate_t->pin(2), rsig->pin(idx));
|
||||
connect(gate_t->pin(0), gate->pin(idx+1));
|
||||
des->add_node(gate_t);
|
||||
|
||||
// Attach a label to this intermediate wire
|
||||
NetNet*tmp = new NetNet(0, des->local_symbol(path),
|
||||
NetNet::WIRE);
|
||||
tmp->local_flag(true);
|
||||
connect(gate_t->pin(0), tmp->pin(0));
|
||||
des->add_signal(tmp);
|
||||
}
|
||||
break;
|
||||
|
||||
|
||||
case 'e': // ==
|
||||
gate = new NetLogic(des->local_symbol(path),
|
||||
1+lsig->pin_count(),
|
||||
NetLogic::AND);
|
||||
connect(gate->pin(0), osig->pin(0));
|
||||
for (unsigned idx = 0 ; idx < lsig->pin_count() ; idx += 1) {
|
||||
gate_t = new NetLogic(des->local_symbol(path), 3,
|
||||
NetLogic::XNOR);
|
||||
connect(gate_t->pin(1), lsig->pin(idx));
|
||||
connect(gate_t->pin(2), rsig->pin(idx));
|
||||
connect(gate_t->pin(0), gate->pin(idx+1));
|
||||
des->add_node(gate_t);
|
||||
}
|
||||
break;
|
||||
|
||||
case 'n': // !=
|
||||
gate = new NetLogic(des->local_symbol(path),
|
||||
1+lsig->pin_count(),
|
||||
NetLogic::OR);
|
||||
connect(gate->pin(0), osig->pin(0));
|
||||
for (unsigned idx = 0 ; idx < lsig->pin_count() ; idx += 1) {
|
||||
gate_t = new NetLogic(des->local_symbol(path), 3,
|
||||
NetLogic::XOR);
|
||||
connect(gate_t->pin(1), lsig->pin(idx));
|
||||
connect(gate_t->pin(2), rsig->pin(idx));
|
||||
connect(gate_t->pin(0), gate->pin(idx+1));
|
||||
des->add_node(gate_t);
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
assert(0);
|
||||
}
|
||||
|
||||
des->add_signal(osig);
|
||||
gate->rise_time(rise);
|
||||
gate->fall_time(fall);
|
||||
gate->decay_time(decay);
|
||||
des->add_node(gate);
|
||||
|
||||
return osig;
|
||||
}
|
||||
|
||||
NetNet* PEBinary::elaborate_net_shift_(Design*des, const string&path,
|
||||
unsigned lwidth,
|
||||
unsigned long rise,
|
||||
unsigned long fall,
|
||||
unsigned long decay) const
|
||||
{
|
||||
NetNet*lsig = left_->elaborate_net(des, path, lwidth, 0, 0, 0);
|
||||
if (lsig == 0) return 0;
|
||||
|
||||
/* Handle the special case of a constant shift amount. There
|
||||
is no reason in this case to create a gate at all, just
|
||||
connect the lsig to the osig with the bit positions
|
||||
shifted. */
|
||||
if (verinum*rval = right_->eval_const(des, path)) {
|
||||
assert(rval->is_defined());
|
||||
unsigned dist = rval->as_ulong();
|
||||
if (dist > lsig->pin_count())
|
||||
dist = lsig->pin_count();
|
||||
|
||||
/* Very special case, constant 0 shift. */
|
||||
if (dist == 0) return lsig;
|
||||
|
||||
NetNet*osig = new NetNet(0, des->local_symbol(path), NetNet::WIRE,
|
||||
lsig->pin_count());
|
||||
osig->local_flag(true);
|
||||
|
||||
NetConst*zero = new NetConst(des->local_symbol(path), verinum::V0);
|
||||
des->add_node(zero);
|
||||
|
||||
if (op_ == 'l') {
|
||||
unsigned idx;
|
||||
for (idx = 0 ; idx < dist ; idx += 1)
|
||||
connect(osig->pin(idx), zero->pin(0));
|
||||
for (idx = dist ; idx < lsig->pin_count() ; idx += 1)
|
||||
connect(osig->pin(idx), lsig->pin(idx-dist));
|
||||
|
||||
} else {
|
||||
assert(op_ == 'r');
|
||||
unsigned idx;
|
||||
unsigned keep = lsig->pin_count()-dist;
|
||||
for (idx = 0 ; idx < keep ; idx += 1)
|
||||
connect(osig->pin(idx), lsig->pin(idx+dist));
|
||||
for (idx = keep ; idx < lsig->pin_count() ; idx += 1)
|
||||
connect(osig->pin(idx), zero->pin(0));
|
||||
}
|
||||
|
||||
des->add_signal(osig);
|
||||
return osig;
|
||||
}
|
||||
|
||||
unsigned dwid = 0;
|
||||
while ((1 << dwid) < lsig->pin_count())
|
||||
dwid += 1;
|
||||
|
||||
NetNet*rsig = right_->elaborate_net(des, path, dwid, 0, 0, 0);
|
||||
if (rsig == 0) return 0;
|
||||
|
||||
NetCLShift*gate = new NetCLShift(des->local_symbol(path),
|
||||
lsig->pin_count(),
|
||||
rsig->pin_count());
|
||||
|
||||
NetNet*osig = new NetNet(0, des->local_symbol(path), NetNet::WIRE,
|
||||
lsig->pin_count());
|
||||
osig->local_flag(true);
|
||||
|
||||
for (unsigned idx = 0 ; idx < osig->pin_count() ; idx += 1) {
|
||||
connect(osig->pin(idx), gate->pin_Result(idx));
|
||||
connect(lsig->pin(idx), gate->pin_Data(idx));
|
||||
}
|
||||
|
||||
for (unsigned idx = 0 ; idx < rsig->pin_count() ; idx += 1)
|
||||
connect(rsig->pin(idx), gate->pin_Distance(idx));
|
||||
|
||||
if (op_ == 'r') {
|
||||
NetConst*dir = new NetConst(des->local_symbol(path), verinum::V1);
|
||||
connect(dir->pin(0), gate->pin_Direction());
|
||||
des->add_node(dir);
|
||||
}
|
||||
|
||||
des->add_signal(osig);
|
||||
des->add_node(gate);
|
||||
|
||||
return osig;
|
||||
}
|
||||
|
||||
/*
|
||||
* The concatenation operator, as a net, is a wide signal that is
|
||||
* connected to all the pins of the elaborated expression nets.
|
||||
*/
|
||||
NetNet* PEConcat::elaborate_net(Design*des, const string&path,
|
||||
unsigned,
|
||||
unsigned long rise,
|
||||
unsigned long fall,
|
||||
unsigned long decay) const
|
||||
{
|
||||
svector<NetNet*>nets (parms_.count());
|
||||
unsigned pins = 0;
|
||||
unsigned errors = 0;
|
||||
|
||||
if (repeat_) {
|
||||
verinum*rep = repeat_->eval_const(des, path);
|
||||
if (rep == 0) {
|
||||
cerr << get_line() << ": internal error: Unable to "
|
||||
<< "evaluate constant repeat expression." << endl;
|
||||
des->errors += 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
unsigned long repeat = rep->as_ulong();
|
||||
|
||||
assert(parms_.count() == 1);
|
||||
NetNet*obj = parms_[0]->elaborate_net(des, path, 0, rise,
|
||||
fall, decay);
|
||||
NetTmp*tmp = new NetTmp(des->local_symbol(path),
|
||||
repeat * obj->pin_count());
|
||||
|
||||
for (unsigned idx = 0 ; idx < repeat ; idx += 1) {
|
||||
unsigned base = obj->pin_count() * idx;
|
||||
for (unsigned pin = 0 ; pin < obj->pin_count() ; pin += 1)
|
||||
connect(tmp->pin(base+pin), obj->pin(pin));
|
||||
}
|
||||
|
||||
des->add_signal(tmp);
|
||||
return tmp;
|
||||
}
|
||||
|
||||
/* Elaborate the operands of the concatenation. */
|
||||
for (unsigned idx = 0 ; idx < nets.count() ; idx += 1) {
|
||||
nets[idx] = parms_[idx]->elaborate_net(des, path, 0,
|
||||
rise,fall,decay);
|
||||
if (nets[idx] == 0)
|
||||
errors += 1;
|
||||
else
|
||||
pins += nets[idx]->pin_count();
|
||||
}
|
||||
|
||||
/* If any of the sub expressions failed to elaborate, then
|
||||
delete all those that did and abort myself. */
|
||||
if (errors) {
|
||||
for (unsigned idx = 0 ; idx < nets.count() ; idx += 1) {
|
||||
if (nets[idx]) delete nets[idx];
|
||||
}
|
||||
des->errors += 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Make the temporary signal that connects to all the
|
||||
operands, and connect it up. Scan the operands of the
|
||||
concat operator from least significant to most significant,
|
||||
which is opposite from how they are given in the list. */
|
||||
NetNet*osig = new NetNet(0, des->local_symbol(path),
|
||||
NetNet::IMPLICIT, pins);
|
||||
pins = 0;
|
||||
for (unsigned idx = nets.count() ; idx > 0 ; idx -= 1) {
|
||||
NetNet*cur = nets[idx-1];
|
||||
for (unsigned pin = 0 ; pin < cur->pin_count() ; pin += 1) {
|
||||
connect(osig->pin(pins), cur->pin(pin));
|
||||
pins += 1;
|
||||
}
|
||||
}
|
||||
|
||||
osig->local_flag(true);
|
||||
des->add_signal(osig);
|
||||
return osig;
|
||||
}
|
||||
|
||||
NetNet* PEIdent::elaborate_net(Design*des, const string&path,
|
||||
unsigned lwidth,
|
||||
unsigned long rise,
|
||||
unsigned long fall,
|
||||
unsigned long decay) const
|
||||
{
|
||||
NetScope*scope = des->find_scope(path);
|
||||
NetNet*sig = des->find_signal(path, text_);
|
||||
|
||||
if (sig == 0) {
|
||||
/* If the identifier is a memory instead of a signal,
|
||||
then handle it elsewhere. Create a RAM. */
|
||||
if (NetMemory*mem = des->find_memory(path, text_))
|
||||
return elaborate_net_ram_(des, path, mem, lwidth,
|
||||
rise, fall, decay);
|
||||
|
||||
|
||||
if (const NetExpr*pe = des->find_parameter(path, text_)) {
|
||||
|
||||
const NetEConst*pc = dynamic_cast<const NetEConst*>(pe);
|
||||
assert(pc);
|
||||
verinum pvalue = pc->value();
|
||||
sig = new NetNet(0, path+"."+text_, NetNet::IMPLICIT,
|
||||
pc->expr_width());
|
||||
for (unsigned idx = 0; idx < sig->pin_count(); idx += 1) {
|
||||
NetConst*cp = new NetConst(des->local_symbol(path),
|
||||
pvalue[idx]);
|
||||
connect(sig->pin(idx), cp->pin(0));
|
||||
des->add_node(cp);
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
sig = new NetNet(scope, path+"."+text_, NetNet::IMPLICIT, 1);
|
||||
des->add_signal(sig);
|
||||
cerr << get_line() << ": warning: Implicitly defining "
|
||||
"wire " << path << "." << text_ << "." << endl;
|
||||
}
|
||||
}
|
||||
|
||||
assert(sig);
|
||||
|
||||
if (msb_ && lsb_) {
|
||||
verinum*mval = msb_->eval_const(des, path);
|
||||
if (mval == 0) {
|
||||
cerr << msb_->get_line() << ": error: unable to "
|
||||
"evaluate constant expression: " << *msb_ <<
|
||||
endl;
|
||||
des->errors += 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
verinum*lval = lsb_->eval_const(des, path);
|
||||
if (lval == 0) {
|
||||
cerr << lsb_->get_line() << ": error: unable to "
|
||||
"evaluate constant expression: " << *lsb_ <<
|
||||
endl;
|
||||
delete mval;
|
||||
des->errors += 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
assert(mval);
|
||||
assert(lval);
|
||||
unsigned midx = sig->sb_to_idx(mval->as_long());
|
||||
unsigned lidx = sig->sb_to_idx(lval->as_long());
|
||||
|
||||
if (midx >= lidx) {
|
||||
NetTmp*tmp = new NetTmp(des->local_symbol(path),
|
||||
midx-lidx+1);
|
||||
des->add_signal(tmp);
|
||||
if (tmp->pin_count() > sig->pin_count()) {
|
||||
cerr << get_line() << ": bit select out of "
|
||||
<< "range for " << sig->name() << endl;
|
||||
return sig;
|
||||
}
|
||||
|
||||
for (unsigned idx = lidx ; idx <= midx ; idx += 1)
|
||||
connect(tmp->pin(idx-lidx), sig->pin(idx));
|
||||
|
||||
sig = tmp;
|
||||
|
||||
} else {
|
||||
NetTmp*tmp = new NetTmp(des->local_symbol(path),
|
||||
lidx-midx+1);
|
||||
des->add_signal(tmp);
|
||||
assert(tmp->pin_count() <= sig->pin_count());
|
||||
for (unsigned idx = lidx ; idx >= midx ; idx -= 1)
|
||||
connect(tmp->pin(idx-midx), sig->pin(idx));
|
||||
|
||||
sig = tmp;
|
||||
}
|
||||
|
||||
} else if (msb_) {
|
||||
verinum*mval = msb_->eval_const(des, path);
|
||||
if (mval == 0) {
|
||||
cerr << get_line() << ": index of " << text_ <<
|
||||
" needs to be constant in this context." <<
|
||||
endl;
|
||||
des->errors += 1;
|
||||
return 0;
|
||||
}
|
||||
assert(mval);
|
||||
unsigned idx = sig->sb_to_idx(mval->as_long());
|
||||
if (idx >= sig->pin_count()) {
|
||||
cerr << get_line() << "; index " << sig->name() <<
|
||||
"[" << mval->as_long() << "] out of range." << endl;
|
||||
des->errors += 1;
|
||||
idx = 0;
|
||||
}
|
||||
NetTmp*tmp = new NetTmp(des->local_symbol(path), 1);
|
||||
des->add_signal(tmp);
|
||||
connect(tmp->pin(0), sig->pin(idx));
|
||||
sig = tmp;
|
||||
}
|
||||
|
||||
return sig;
|
||||
}
|
||||
|
||||
/*
|
||||
* When I run into an identifier in an expression that referrs to a
|
||||
* memory, create a RAM port object.
|
||||
*/
|
||||
NetNet* PEIdent::elaborate_net_ram_(Design*des, const string&path,
|
||||
NetMemory*mem, unsigned lwidth,
|
||||
unsigned long rise,
|
||||
unsigned long fall,
|
||||
unsigned long decay) const
|
||||
{
|
||||
if (msb_ == 0) {
|
||||
cerr << get_line() << ": error: memory reference without"
|
||||
" the required index expression." << endl;
|
||||
des->errors += 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
NetNet*adr = msb_->elaborate_net(des, path, 0, 0, 0, 0);
|
||||
if (adr == 0)
|
||||
return 0;
|
||||
|
||||
|
||||
NetRamDq*ram = new NetRamDq(des->local_symbol(mem->name()),
|
||||
mem, adr->pin_count());
|
||||
des->add_node(ram);
|
||||
|
||||
for (unsigned idx = 0 ; idx < adr->pin_count() ; idx += 1)
|
||||
connect(ram->pin_Address(idx), adr->pin(idx));
|
||||
|
||||
NetNet*osig = new NetTmp(des->local_symbol(mem->name()), ram->width());
|
||||
des->add_signal(osig);
|
||||
|
||||
for (unsigned idx = 0 ; idx < osig->pin_count() ; idx += 1)
|
||||
connect(ram->pin_Q(idx), osig->pin(idx));
|
||||
|
||||
return osig;
|
||||
}
|
||||
|
||||
/*
|
||||
* Identifiers in continuous assignment l-values are limited to wires
|
||||
* and that ilk. Detect registers and memories here and report errors.
|
||||
*/
|
||||
NetNet* PEIdent::elaborate_lnet(Design*des, const string&path) const
|
||||
{
|
||||
NetNet*sig = des->find_signal(path, text_);
|
||||
if (sig == 0) {
|
||||
/* Don't allow memories here. Is it a memory? */
|
||||
if (des->find_memory(path, text_)) {
|
||||
cerr << get_line() << ": error: memories (" << text_
|
||||
<< ") cannot be l-values in continuous "
|
||||
<< "assignments." << endl;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Fine, create an implicit wire as an l-value. */
|
||||
sig = new NetNet(0, path+"."+text_, NetNet::IMPLICIT, 1);
|
||||
des->add_signal(sig);
|
||||
cerr << get_line() << ": warning: Implicitly defining "
|
||||
"wire " << path << "." << text_ << "." << endl;
|
||||
}
|
||||
|
||||
assert(sig);
|
||||
|
||||
/* Don't allow registers as assign l-values. */
|
||||
if (sig->type() == NetNet::REG) {
|
||||
cerr << get_line() << ": error: registers (" << sig->name()
|
||||
<< ") cannot be l-values in continuous"
|
||||
<< " assignments." << endl;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (msb_ && lsb_) {
|
||||
/* Detect a part select. Evaluate the bits and elaborate
|
||||
the l-value by creating a sub-net that links to just
|
||||
the right pins. */
|
||||
verinum*mval = msb_->eval_const(des, path);
|
||||
assert(mval);
|
||||
verinum*lval = lsb_->eval_const(des, path);
|
||||
assert(lval);
|
||||
unsigned midx = sig->sb_to_idx(mval->as_long());
|
||||
unsigned lidx = sig->sb_to_idx(lval->as_long());
|
||||
|
||||
if (midx >= lidx) {
|
||||
NetTmp*tmp = new NetTmp(des->local_symbol(path),
|
||||
midx-lidx+1);
|
||||
des->add_signal(tmp);
|
||||
if (tmp->pin_count() > sig->pin_count()) {
|
||||
cerr << get_line() << ": bit select out of "
|
||||
<< "range for " << sig->name() << endl;
|
||||
return sig;
|
||||
}
|
||||
|
||||
for (unsigned idx = lidx ; idx <= midx ; idx += 1)
|
||||
connect(tmp->pin(idx-lidx), sig->pin(idx));
|
||||
|
||||
sig = tmp;
|
||||
|
||||
} else {
|
||||
NetTmp*tmp = new NetTmp(des->local_symbol(path),
|
||||
lidx-midx+1);
|
||||
des->add_signal(tmp);
|
||||
assert(tmp->pin_count() <= sig->pin_count());
|
||||
for (unsigned idx = lidx ; idx >= midx ; idx -= 1)
|
||||
connect(tmp->pin(idx-midx), sig->pin(idx));
|
||||
|
||||
sig = tmp;
|
||||
}
|
||||
|
||||
} else if (msb_) {
|
||||
verinum*mval = msb_->eval_const(des, path);
|
||||
if (mval == 0) {
|
||||
cerr << get_line() << ": index of " << text_ <<
|
||||
" needs to be constant in this context." <<
|
||||
endl;
|
||||
des->errors += 1;
|
||||
return 0;
|
||||
}
|
||||
assert(mval);
|
||||
unsigned idx = sig->sb_to_idx(mval->as_long());
|
||||
if (idx >= sig->pin_count()) {
|
||||
cerr << get_line() << "; index " << sig->name() <<
|
||||
"[" << mval->as_long() << "] out of range." << endl;
|
||||
des->errors += 1;
|
||||
idx = 0;
|
||||
}
|
||||
NetTmp*tmp = new NetTmp(des->local_symbol(path), 1);
|
||||
des->add_signal(tmp);
|
||||
connect(tmp->pin(0), sig->pin(idx));
|
||||
sig = tmp;
|
||||
}
|
||||
|
||||
return sig;
|
||||
}
|
||||
|
||||
/*
|
||||
* Elaborate a number as a NetConst object.
|
||||
*/
|
||||
NetNet* PENumber::elaborate_net(Design*des, const string&path,
|
||||
unsigned lwidth,
|
||||
unsigned long rise,
|
||||
unsigned long fall,
|
||||
unsigned long decay) const
|
||||
{
|
||||
unsigned width = value_->len();
|
||||
if ((lwidth > 0) && (lwidth < width))
|
||||
width = lwidth;
|
||||
|
||||
NetNet*net = new NetNet(0, des->local_symbol(path),
|
||||
NetNet::IMPLICIT, width);
|
||||
net->local_flag(true);
|
||||
for (unsigned idx = 0 ; idx < width ; idx += 1) {
|
||||
NetConst*tmp = new NetConst(des->local_symbol(path),
|
||||
value_->get(idx));
|
||||
des->add_node(tmp);
|
||||
connect(net->pin(idx), tmp->pin(0));
|
||||
}
|
||||
|
||||
des->add_signal(net);
|
||||
return net;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Elaborate the ternary operator in a netlist by creating a LPM_MUX
|
||||
* with width matching the result, size == 2 and 1 select input.
|
||||
*/
|
||||
NetNet* PETernary::elaborate_net(Design*des, const string&path,
|
||||
unsigned width,
|
||||
unsigned long rise,
|
||||
unsigned long fall,
|
||||
unsigned long decay) const
|
||||
{
|
||||
NetNet* expr_sig = expr_->elaborate_net(des, path, 0, 0, 0, 0);
|
||||
NetNet* tru_sig = tru_->elaborate_net(des, path, width, 0, 0, 0);
|
||||
NetNet* fal_sig = fal_->elaborate_net(des, path, width, 0, 0, 0);
|
||||
if (expr_sig == 0 || tru_sig == 0 || fal_sig == 0) {
|
||||
des->errors += 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
assert(tru_sig->pin_count() == fal_sig->pin_count());
|
||||
assert(width == tru_sig->pin_count());
|
||||
assert(expr_sig->pin_count() == 1);
|
||||
|
||||
NetNet*sig = new NetNet(0, des->local_symbol(path), NetNet::WIRE,
|
||||
tru_sig->pin_count());
|
||||
sig->local_flag(true);
|
||||
|
||||
NetMux*mux = new NetMux(des->local_symbol(path), width, 2, 1);
|
||||
connect(mux->pin_Sel(0), expr_sig->pin(0));
|
||||
|
||||
for (unsigned idx = 0 ; idx < width ; idx += 1) {
|
||||
connect(mux->pin_Result(idx), sig->pin(idx));
|
||||
connect(mux->pin_Data(idx,0), fal_sig->pin(idx));
|
||||
connect(mux->pin_Data(idx,1), tru_sig->pin(idx));
|
||||
}
|
||||
|
||||
des->add_signal(sig);
|
||||
des->add_node(mux);
|
||||
|
||||
return sig;
|
||||
}
|
||||
|
||||
/*
|
||||
* $Log: elab_net.cc,v $
|
||||
* Revision 1.11 1999/12/02 04:08:10 steve
|
||||
* Elaborate net repeat concatenations.
|
||||
*
|
||||
* Revision 1.10 1999/11/30 04:33:41 steve
|
||||
* Put implicitly defined signals in the scope.
|
||||
*
|
||||
* Revision 1.9 1999/11/27 19:07:57 steve
|
||||
* Support the creation of scopes.
|
||||
*
|
||||
* Revision 1.8 1999/11/21 17:35:37 steve
|
||||
* Memory name lookup handles scopes.
|
||||
*
|
||||
* Revision 1.7 1999/11/21 00:13:08 steve
|
||||
* Support memories in continuous assignments.
|
||||
*
|
||||
* Revision 1.6 1999/11/14 23:43:45 steve
|
||||
* Support combinatorial comparators.
|
||||
*
|
||||
* Revision 1.5 1999/11/14 20:24:28 steve
|
||||
* Add support for the LPM_CLSHIFT device.
|
||||
*
|
||||
* Revision 1.4 1999/11/05 23:36:31 steve
|
||||
* Forgot to return the mux for use after elaboration.
|
||||
*
|
||||
* Revision 1.3 1999/11/05 21:45:19 steve
|
||||
* Fix NetConst being set to zero width, and clean
|
||||
* up elaborate_set_cmp_ for NetEBinary.
|
||||
*
|
||||
* Revision 1.2 1999/11/04 03:53:26 steve
|
||||
* Patch to synthesize unary ~ and the ternary operator.
|
||||
* Thanks to Larry Doolittle <[email protected]>.
|
||||
*
|
||||
* Add the LPM_MUX device, and integrate it with the
|
||||
* ternary synthesis from Larry. Replace the lpm_mux
|
||||
* generator in t-xnf.cc to use XNF EQU devices to
|
||||
* put muxs into function units.
|
||||
*
|
||||
* Rewrite elaborate_net for the PETernary class to
|
||||
* also use the LPM_MUX device.
|
||||
*
|
||||
* Revision 1.1 1999/10/31 20:08:24 steve
|
||||
* Include subtraction in LPM_ADD_SUB device.
|
||||
*
|
||||
*/
|
||||
|
||||
+737
-758
File diff suppressed because it is too large
Load Diff
@@ -17,7 +17,7 @@
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
|
||||
*/
|
||||
#if !defined(WINNT)
|
||||
#ident "$Id: emit.cc,v 1.18 1999/07/17 19:50:59 steve Exp $"
|
||||
#ident "$Id: emit.cc,v 1.31 1999/11/28 23:42:02 steve Exp $"
|
||||
#endif
|
||||
|
||||
/*
|
||||
@@ -45,6 +45,11 @@ void NetUDP::emit_node(ostream&o, struct target_t*tgt) const
|
||||
tgt->udp(o, this);
|
||||
}
|
||||
|
||||
void NetAddSub::emit_node(ostream&o, struct target_t*tgt) const
|
||||
{
|
||||
tgt->lpm_add_sub(o, this);
|
||||
}
|
||||
|
||||
void NetAssign::emit_node(ostream&o, struct target_t*tgt) const
|
||||
{
|
||||
tgt->net_assign(o, this);
|
||||
@@ -55,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);
|
||||
@@ -70,54 +105,68 @@ void NetBUFZ::emit_node(ostream&o, struct target_t*tgt) const
|
||||
tgt->bufz(o, this);
|
||||
}
|
||||
|
||||
void NetProcTop::emit(ostream&o, struct target_t*tgt) const
|
||||
bool NetProcTop::emit(ostream&o, struct target_t*tgt) const
|
||||
{
|
||||
tgt->process(o, this);
|
||||
return tgt->process(o, this);
|
||||
}
|
||||
|
||||
void NetProc::emit_proc(ostream&o, struct target_t*tgt) const
|
||||
bool NetProc::emit_proc(ostream&o, struct target_t*tgt) const
|
||||
{
|
||||
cerr << "EMIT: Proc type? " << typeid(*this).name() << endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
void NetAssign::emit_proc(ostream&o, struct target_t*tgt) const
|
||||
bool NetAssign::emit_proc(ostream&o, struct target_t*tgt) const
|
||||
{
|
||||
tgt->proc_assign(o, this);
|
||||
return true;
|
||||
}
|
||||
|
||||
void NetAssignNB::emit_proc(ostream&o, struct target_t*tgt) const
|
||||
bool NetAssignNB::emit_proc(ostream&o, struct target_t*tgt) const
|
||||
{
|
||||
tgt->proc_assign_nb(o, this);
|
||||
return true;
|
||||
}
|
||||
|
||||
void NetAssignMem::emit_proc(ostream&o, struct target_t*tgt) const
|
||||
bool NetAssignMem::emit_proc(ostream&o, struct target_t*tgt) const
|
||||
{
|
||||
tgt->proc_assign_mem(o, this);
|
||||
return true;
|
||||
}
|
||||
|
||||
void NetBlock::emit_proc(ostream&o, struct target_t*tgt) const
|
||||
bool NetAssignMemNB::emit_proc(ostream&o, struct target_t*tgt) const
|
||||
{
|
||||
tgt->proc_block(o, this);
|
||||
tgt->proc_assign_mem_nb(o, this);
|
||||
return true;
|
||||
}
|
||||
|
||||
void NetCase::emit_proc(ostream&o, struct target_t*tgt) const
|
||||
bool NetBlock::emit_proc(ostream&o, struct target_t*tgt) const
|
||||
{
|
||||
return tgt->proc_block(o, this);
|
||||
}
|
||||
|
||||
bool NetCase::emit_proc(ostream&o, struct target_t*tgt) const
|
||||
{
|
||||
tgt->proc_case(o, this);
|
||||
return true;
|
||||
}
|
||||
|
||||
void NetCondit::emit_proc(ostream&o, struct target_t*tgt) const
|
||||
bool NetCondit::emit_proc(ostream&o, struct target_t*tgt) const
|
||||
{
|
||||
tgt->proc_condit(o, this);
|
||||
return true;
|
||||
}
|
||||
|
||||
void NetForever::emit_proc(ostream&o, struct target_t*tgt) const
|
||||
bool NetForever::emit_proc(ostream&o, struct target_t*tgt) const
|
||||
{
|
||||
tgt->proc_forever(o, this);
|
||||
return true;
|
||||
}
|
||||
|
||||
void NetPDelay::emit_proc(ostream&o, struct target_t*tgt) const
|
||||
bool NetPDelay::emit_proc(ostream&o, struct target_t*tgt) const
|
||||
{
|
||||
tgt->proc_delay(o, this);
|
||||
return true;
|
||||
}
|
||||
|
||||
void NetPDelay::emit_proc_recurse(ostream&o, struct target_t*tgt) const
|
||||
@@ -125,9 +174,10 @@ void NetPDelay::emit_proc_recurse(ostream&o, struct target_t*tgt) const
|
||||
if (statement_) statement_->emit_proc(o, tgt);
|
||||
}
|
||||
|
||||
void NetPEvent::emit_proc(ostream&o, struct target_t*tgt) const
|
||||
bool NetPEvent::emit_proc(ostream&o, struct target_t*tgt) const
|
||||
{
|
||||
tgt->proc_event(o, this);
|
||||
return true;
|
||||
}
|
||||
|
||||
void NetPEvent::emit_proc_recurse(ostream&o, struct target_t*tgt) const
|
||||
@@ -135,24 +185,28 @@ void NetPEvent::emit_proc_recurse(ostream&o, struct target_t*tgt) const
|
||||
if (statement_) statement_->emit_proc(o, tgt);
|
||||
}
|
||||
|
||||
void NetRepeat::emit_proc(ostream&o, struct target_t*tgt) const
|
||||
bool NetRepeat::emit_proc(ostream&o, struct target_t*tgt) const
|
||||
{
|
||||
tgt->proc_repeat(o, this);
|
||||
return true;
|
||||
}
|
||||
|
||||
void NetSTask::emit_proc(ostream&o, struct target_t*tgt) const
|
||||
bool NetSTask::emit_proc(ostream&o, struct target_t*tgt) const
|
||||
{
|
||||
tgt->proc_stask(o, this);
|
||||
return true;
|
||||
}
|
||||
|
||||
void NetUTask::emit_proc(ostream&o, struct target_t*tgt) const
|
||||
bool NetUTask::emit_proc(ostream&o, struct target_t*tgt) const
|
||||
{
|
||||
tgt->proc_utask(o, this);
|
||||
return true;
|
||||
}
|
||||
|
||||
void NetWhile::emit_proc(ostream&o, struct target_t*tgt) const
|
||||
bool NetWhile::emit_proc(ostream&o, struct target_t*tgt) const
|
||||
{
|
||||
tgt->proc_while(o, this);
|
||||
return true;
|
||||
}
|
||||
|
||||
void NetBlock::emit_recurse(ostream&o, struct target_t*tgt) const
|
||||
@@ -196,10 +250,18 @@ void NetWhile::emit_proc_recurse(ostream&o, struct target_t*tgt) const
|
||||
proc_->emit_proc(o, tgt);
|
||||
}
|
||||
|
||||
void Design::emit(ostream&o, struct target_t*tgt) const
|
||||
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_;
|
||||
@@ -229,6 +291,14 @@ void Design::emit(ostream&o, struct target_t*tgt) const
|
||||
}
|
||||
|
||||
|
||||
// emit function definitions
|
||||
{
|
||||
map<string,NetFuncDef*>::const_iterator ta;
|
||||
for (ta = funcs_.begin() ; ta != funcs_.end() ; ta ++) {
|
||||
tgt->func_def(o, (*ta).second);
|
||||
}
|
||||
}
|
||||
|
||||
// emit task definitions
|
||||
{
|
||||
map<string,NetTaskDef*>::const_iterator ta;
|
||||
@@ -239,9 +309,10 @@ void Design::emit(ostream&o, struct target_t*tgt) const
|
||||
|
||||
// emit the processes
|
||||
for (const NetProcTop*idx = procs_ ; idx ; idx = idx->next_)
|
||||
idx->emit(o, tgt);
|
||||
rc = rc && idx->emit(o, tgt);
|
||||
|
||||
tgt->end_design(o, this);
|
||||
return rc;
|
||||
}
|
||||
|
||||
void NetEBinary::expr_scan(struct expr_scan_t*tgt) const
|
||||
@@ -269,16 +340,27 @@ void NetEMemory::expr_scan(struct expr_scan_t*tgt) const
|
||||
tgt->expr_memory(this);
|
||||
}
|
||||
|
||||
void NetEParam::expr_scan(struct expr_scan_t*tgt) const
|
||||
{
|
||||
cerr << get_line() << ":internal error: unexpected NetEParam."
|
||||
<< 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);
|
||||
}
|
||||
|
||||
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);
|
||||
@@ -294,20 +376,70 @@ void NetEUnary::expr_scan(struct expr_scan_t*tgt) const
|
||||
tgt->expr_unary(this);
|
||||
}
|
||||
|
||||
void emit(ostream&o, const Design*des, const char*type)
|
||||
bool emit(ostream&o, const Design*des, const char*type)
|
||||
{
|
||||
for (unsigned idx = 0 ; target_table[idx] ; idx += 1) {
|
||||
const struct target*tgt = target_table[idx];
|
||||
if (tgt->name == type) {
|
||||
des->emit(o, tgt->meth);
|
||||
return;
|
||||
}
|
||||
if (tgt->name == type)
|
||||
return des->emit(o, tgt->meth);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* $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.
|
||||
*
|
||||
* Revision 1.22 1999/09/20 02:21:10 steve
|
||||
* Elaborate parameters in phases.
|
||||
*
|
||||
* Revision 1.21 1999/09/15 01:55:06 steve
|
||||
* Elaborate non-blocking assignment to memories.
|
||||
*
|
||||
* Revision 1.20 1999/09/03 04:28:38 steve
|
||||
* elaborate the binary plus operator.
|
||||
*
|
||||
* Revision 1.19 1999/08/31 22:38:29 steve
|
||||
* Elaborate and emit to vvm procedural functions.
|
||||
*
|
||||
* Revision 1.18 1999/07/17 19:50:59 steve
|
||||
* netlist support for ternary operator.
|
||||
*
|
||||
|
||||
@@ -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.5 1999/08/06 04:05:28 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;
|
||||
@@ -56,11 +90,25 @@ verinum* PEBinary::eval_const(const Design*des, const string&path) const
|
||||
return res;
|
||||
}
|
||||
|
||||
/*
|
||||
* Evaluate an identifier as a constant expression. This is only
|
||||
* possible if the identifier is that of a parameter.
|
||||
*/
|
||||
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;
|
||||
|
||||
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;
|
||||
return 0;
|
||||
}
|
||||
|
||||
const NetEConst*eval = dynamic_cast<const NetEConst*>(expr);
|
||||
assert(eval);
|
||||
return new verinum(eval->value());
|
||||
@@ -71,14 +119,51 @@ 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.
|
||||
*
|
||||
* Revision 1.7 1999/09/18 01:52:48 steve
|
||||
* Remove spurious message.
|
||||
*
|
||||
* Revision 1.6 1999/09/16 04:18:15 steve
|
||||
* elaborate concatenation repeats.
|
||||
*
|
||||
* Revision 1.5 1999/08/06 04:05:28 steve
|
||||
* Handle scope of parameters.
|
||||
*
|
||||
|
||||
+286
@@ -0,0 +1,286 @@
|
||||
/*
|
||||
* 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: eval_tree.cc,v 1.6 1999/10/22 23:57:53 steve Exp $"
|
||||
#endif
|
||||
|
||||
# include "netlist.h"
|
||||
|
||||
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.
|
||||
*/
|
||||
void NetEBinary::eval_sub_tree_()
|
||||
{
|
||||
NetExpr*tmp = left_->eval_tree();
|
||||
if (tmp) {
|
||||
delete left_;
|
||||
left_ = tmp;
|
||||
}
|
||||
tmp = right_->eval_tree();
|
||||
if (tmp){
|
||||
delete right_;
|
||||
right_ = tmp;
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
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;
|
||||
NetEConst*r = dynamic_cast<NetEConst*>(right_);
|
||||
if (r == 0) return 0;
|
||||
|
||||
const verinum&lv = l->value();
|
||||
const verinum&rv = r->value();
|
||||
|
||||
if (lv.len() < rv.len())
|
||||
return 0;
|
||||
|
||||
verinum result(verinum::V1, 1);
|
||||
for (unsigned idx = 0 ; idx < lv.len(); idx += 1) {
|
||||
if (lv[idx] != rv[idx])
|
||||
result = verinum::V0;
|
||||
}
|
||||
|
||||
return new NetEConst(result);
|
||||
}
|
||||
|
||||
|
||||
NetEConst* NetEBComp::eval_leeq_()
|
||||
{
|
||||
NetEConst*r = dynamic_cast<NetEConst*>(right_);
|
||||
if (r == 0) return 0;
|
||||
|
||||
verinum rv = r->value();
|
||||
|
||||
/* Detect the case where the right side is greater that or
|
||||
equal to the largest value the left side can possibly
|
||||
have. */
|
||||
assert(left_->expr_width() > 0);
|
||||
verinum lv (verinum::V1, left_->expr_width());
|
||||
if (lv <= rv) {
|
||||
verinum result(verinum::V1, 1);
|
||||
return new NetEConst(result);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
NetEConst* NetEBComp::eval_tree()
|
||||
{
|
||||
eval_sub_tree_();
|
||||
|
||||
switch (op_) {
|
||||
case 'e':
|
||||
return eval_eqeq_();
|
||||
|
||||
case 'L':
|
||||
return eval_leeq_();
|
||||
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
NetEConst* NetEBLogic::eval_tree()
|
||||
{
|
||||
eval_sub_tree_();
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Evaluate the shift operator if possible. For this to work, both
|
||||
* operands must be constant.
|
||||
*/
|
||||
NetEConst* NetEBShift::eval_tree()
|
||||
{
|
||||
eval_sub_tree_();
|
||||
NetEConst*re = dynamic_cast<NetEConst*>(right_);
|
||||
if (re == 0)
|
||||
return 0;
|
||||
|
||||
NetEConst*le = dynamic_cast<NetEConst*>(left_);
|
||||
if (le == 0)
|
||||
return 0;
|
||||
|
||||
NetEConst*res;
|
||||
|
||||
verinum rv = re->value();
|
||||
verinum lv = le->value();
|
||||
if (rv.is_defined()) {
|
||||
|
||||
unsigned wid = expr_width();
|
||||
unsigned shift = rv.as_ulong();
|
||||
|
||||
verinum nv (verinum::V0, wid);
|
||||
|
||||
if (op() == 'r')
|
||||
for (unsigned idx = 0 ; idx < (wid-shift) ; idx += 1)
|
||||
nv.set(idx, lv[idx+shift]);
|
||||
|
||||
else
|
||||
for (unsigned idx = 0 ; idx < (wid-shift) ; idx += 1)
|
||||
nv.set(idx+shift, lv[idx]);
|
||||
|
||||
res = new NetEConst(nv);
|
||||
|
||||
} else {
|
||||
verinum nv (verinum::Vx, expr_width());
|
||||
res = new NetEConst(nv);
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
NetExpr* NetEConcat::eval_tree()
|
||||
{
|
||||
for (unsigned idx = 0 ; idx < parms_.count() ; idx += 1) {
|
||||
|
||||
// Parameter not here? This is an error, but presumably
|
||||
// already caught and we are here just to catch more.
|
||||
if (parms_[idx] == 0)
|
||||
continue;
|
||||
|
||||
// If this parameter is already a constant, all is well
|
||||
// so go on.
|
||||
if (dynamic_cast<NetEConst*>(parms_[idx]))
|
||||
continue;
|
||||
|
||||
// Finally, try to evaluate the parameter expression
|
||||
// that is here. If I succeed, reset the parameter to
|
||||
// the evaluated value.
|
||||
assert(parms_[idx]);
|
||||
NetExpr*expr = parms_[idx]->eval_tree();
|
||||
if (expr) {
|
||||
delete parms_[idx];
|
||||
parms_[idx] = expr;
|
||||
}
|
||||
}
|
||||
|
||||
unsigned gap = expr_width() / repeat_;
|
||||
verinum val (verinum::Vx, repeat_ * gap);
|
||||
|
||||
|
||||
// build up the result from least significant to most.
|
||||
|
||||
unsigned cur = 0;
|
||||
for (unsigned idx = parms_.count() ; idx > 0 ; idx -= 1) {
|
||||
NetEConst*expr = dynamic_cast<NetEConst*>(parms_[idx-1]);
|
||||
if (expr == 0)
|
||||
return 0;
|
||||
|
||||
verinum tmp = expr->value();
|
||||
for (unsigned bit = 0 ; bit < tmp.len() ; bit += 1, cur += 1)
|
||||
for (unsigned rep = 0 ; rep < repeat_ ; rep += 1)
|
||||
val.set(rep*gap+cur, tmp[bit]);
|
||||
}
|
||||
|
||||
NetEConst*res = new NetEConst(val);
|
||||
res->set_width(val.len());
|
||||
return res;
|
||||
}
|
||||
|
||||
NetExpr* NetEParam::eval_tree()
|
||||
{
|
||||
if (des_ == 0)
|
||||
return 0;
|
||||
|
||||
const NetExpr*expr = des_->find_parameter(path_, name_);
|
||||
assert(expr);
|
||||
|
||||
NetExpr*nexpr = expr->dup_expr();
|
||||
assert(nexpr);
|
||||
|
||||
// If the parameter that I refer to is already evaluated, then
|
||||
// return the constant value.
|
||||
if (dynamic_cast<NetEConst*>(nexpr))
|
||||
return nexpr;
|
||||
|
||||
// Try to evaluate the expression. If I cannot, then the
|
||||
// expression is not a constant expression and I fail here.
|
||||
NetExpr*res = nexpr->eval_tree();
|
||||
if (res == 0) {
|
||||
delete nexpr;
|
||||
return 0;
|
||||
}
|
||||
|
||||
// The result can be saved as the value of the parameter for
|
||||
// future reference, and return a copy to the caller.
|
||||
des_->set_parameter(path_+"."+name_, res);
|
||||
return res->dup_expr();
|
||||
}
|
||||
|
||||
/*
|
||||
* $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.
|
||||
*
|
||||
* Revision 1.3 1999/09/23 00:21:54 steve
|
||||
* Move set_width methods into a single file,
|
||||
* Add the NetEBLogic class for logic expressions,
|
||||
* Fix error setting with of && in if statements.
|
||||
*
|
||||
* Revision 1.2 1999/09/21 00:13:40 steve
|
||||
* Support parameters that reference other paramters.
|
||||
*
|
||||
* Revision 1.1 1999/09/20 02:21:10 steve
|
||||
* Elaborate parameters in phases.
|
||||
*
|
||||
*/
|
||||
|
||||
+242
@@ -0,0 +1,242 @@
|
||||
/*
|
||||
* Copyright (c) 1999 Stephen Williams ([email protected])
|
||||
*
|
||||
* This source code is free software; you can redistribute it
|
||||
* and/or modify it in source code form under the terms of the GNU
|
||||
* General Public License as published by the Free Software
|
||||
* Foundation; either version 2 of the License, or (at your option)
|
||||
* any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
|
||||
*/
|
||||
#if !defined(WINNT)
|
||||
#ident "$Id: expr_synth.cc,v 1.6 1999/11/28 23:42:02 steve Exp $"
|
||||
#endif
|
||||
|
||||
# include "netlist.h"
|
||||
|
||||
|
||||
NetNet* NetExpr::synthesize(Design*des)
|
||||
{
|
||||
cerr << get_line() << ": internal error: cannot synthesize expression: "
|
||||
<< *this << endl;
|
||||
des->errors += 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Make an LPM_ADD_SUB device from addition operators.
|
||||
*/
|
||||
NetNet* NetEBAdd::synthesize(Design*des)
|
||||
{
|
||||
assert((op()=='+') || (op()=='-'));
|
||||
|
||||
string path = des->local_symbol("SYNTH");
|
||||
NetNet*lsig = left_->synthesize(des);
|
||||
NetNet*rsig = right_->synthesize(des);
|
||||
|
||||
assert(lsig->pin_count() == rsig->pin_count());
|
||||
unsigned width=lsig->pin_count();
|
||||
|
||||
NetNet*osig = new NetNet(0, path, NetNet::IMPLICIT, width);
|
||||
|
||||
string oname = des->local_symbol(path);
|
||||
NetAddSub *adder = new NetAddSub(oname, width);
|
||||
for (unsigned idx = 0 ; idx < width; idx += 1) {
|
||||
connect(lsig->pin(idx), adder->pin_DataA(idx));
|
||||
connect(rsig->pin(idx), adder->pin_DataB(idx));
|
||||
connect(osig->pin(idx), adder->pin_Result(idx));
|
||||
}
|
||||
des->add_node(adder);
|
||||
des->add_signal(osig);
|
||||
|
||||
switch (op()) {
|
||||
case '+':
|
||||
adder->attribute("LPM_Direction", "ADD");
|
||||
break;
|
||||
case '-':
|
||||
adder->attribute("LPM_Direction", "SUB");
|
||||
break;
|
||||
}
|
||||
|
||||
return osig;
|
||||
}
|
||||
|
||||
/*
|
||||
* The bitwise logic operators are turned into discrete gates pretty
|
||||
* easily. Synthesize the left and right sub-expressions to get
|
||||
* signals, then just connect a single gate to each bit of the vector
|
||||
* of the expression.
|
||||
*/
|
||||
NetNet* NetEBBits::synthesize(Design*des)
|
||||
{
|
||||
string path = des->local_symbol("SYNTH");
|
||||
NetNet*lsig = left_->synthesize(des);
|
||||
NetNet*rsig = right_->synthesize(des);
|
||||
|
||||
assert(lsig->pin_count() == rsig->pin_count());
|
||||
NetNet*osig = new NetNet(0, path, NetNet::IMPLICIT, lsig->pin_count());
|
||||
|
||||
for (unsigned idx = 0 ; idx < osig->pin_count() ; idx += 1) {
|
||||
string oname = des->local_symbol(path);
|
||||
NetLogic*gate;
|
||||
|
||||
switch (op()) {
|
||||
case '&':
|
||||
gate = new NetLogic(oname, 3, NetLogic::AND);
|
||||
break;
|
||||
case '|':
|
||||
gate = new NetLogic(oname, 3, NetLogic::OR);
|
||||
break;
|
||||
case '^':
|
||||
gate = new NetLogic(oname, 3, NetLogic::XOR);
|
||||
break;
|
||||
case 'O':
|
||||
gate = new NetLogic(oname, 3, NetLogic::NOR);
|
||||
break;
|
||||
case 'X':
|
||||
gate = new NetLogic(oname, 3, NetLogic::XNOR);
|
||||
break;
|
||||
default:
|
||||
assert(0);
|
||||
}
|
||||
|
||||
connect(osig->pin(idx), gate->pin(0));
|
||||
connect(lsig->pin(idx), gate->pin(1));
|
||||
connect(rsig->pin(idx), gate->pin(2));
|
||||
|
||||
des->add_node(gate);
|
||||
}
|
||||
|
||||
des->add_signal(osig);
|
||||
return osig;
|
||||
}
|
||||
|
||||
NetNet* NetEConst::synthesize(Design*des)
|
||||
{
|
||||
string path = des->local_symbol("SYNTH");
|
||||
unsigned width=expr_width();
|
||||
|
||||
NetNet*osig = new NetNet(0, path, NetNet::IMPLICIT, width);
|
||||
for (unsigned idx = 0 ; idx < width; idx += 1) {
|
||||
string oname = des->local_symbol(path);
|
||||
NetConst *c = new NetConst(oname, value().get(idx));
|
||||
connect(osig->pin(idx), c->pin(0));
|
||||
des->add_node(c);
|
||||
}
|
||||
des->add_signal(osig);
|
||||
return osig;
|
||||
}
|
||||
|
||||
/*
|
||||
* The bitwise unary logic operator (there is only one) is turned
|
||||
* into discrete gates just as easily as the binary ones above.
|
||||
*/
|
||||
NetNet* NetEUBits::synthesize(Design*des)
|
||||
{
|
||||
string path = des->local_symbol("SYNTH");
|
||||
NetNet*isig = expr_->synthesize(des);
|
||||
|
||||
NetNet*osig = new NetNet(0, path, NetNet::IMPLICIT, isig->pin_count());
|
||||
|
||||
for (unsigned idx = 0 ; idx < osig->pin_count() ; idx += 1) {
|
||||
string oname = des->local_symbol(path);
|
||||
NetLogic*gate;
|
||||
|
||||
switch (op()) {
|
||||
case '~':
|
||||
gate = new NetLogic(oname, 2, NetLogic::NOT);
|
||||
break;
|
||||
default:
|
||||
assert(0);
|
||||
}
|
||||
|
||||
connect(osig->pin(idx), gate->pin(0));
|
||||
connect(isig->pin(idx), gate->pin(1));
|
||||
|
||||
des->add_node(gate);
|
||||
}
|
||||
des->add_signal(osig);
|
||||
return osig;
|
||||
}
|
||||
|
||||
|
||||
NetNet* NetETernary::synthesize(Design *des)
|
||||
{
|
||||
string path = des->local_symbol("SYNTH");
|
||||
NetNet*csig = cond_->synthesize(des);
|
||||
NetNet*tsig = true_val_->synthesize(des);
|
||||
NetNet*fsig = false_val_->synthesize(des);
|
||||
|
||||
assert(csig->pin_count() == 1);
|
||||
assert(tsig->pin_count() == fsig->pin_count());
|
||||
unsigned width=tsig->pin_count();
|
||||
NetNet*osig = new NetNet(0, path, NetNet::IMPLICIT, width);
|
||||
|
||||
string oname = des->local_symbol(path);
|
||||
NetMux *mux = new NetMux(oname, width, 2, 1);
|
||||
for (unsigned idx = 0 ; idx < width; idx += 1) {
|
||||
connect(tsig->pin(idx), mux->pin_Data(idx, 1));
|
||||
connect(fsig->pin(idx), mux->pin_Data(idx, 0));
|
||||
connect(osig->pin(idx), mux->pin_Result(idx));
|
||||
}
|
||||
des->add_node(mux);
|
||||
connect(csig->pin(0), mux->pin_Sel(0));
|
||||
des->add_signal(osig);
|
||||
return osig;
|
||||
}
|
||||
|
||||
NetNet* NetESignal::synthesize(Design*des)
|
||||
{
|
||||
return net_;
|
||||
}
|
||||
|
||||
/*
|
||||
* $Log: expr_synth.cc,v $
|
||||
* Revision 1.6 1999/11/28 23:42:02 steve
|
||||
* NetESignal object no longer need to be NetNode
|
||||
* objects. Let them keep a pointer to NetNet objects.
|
||||
*
|
||||
* Revision 1.5 1999/11/27 19:07:57 steve
|
||||
* Support the creation of scopes.
|
||||
*
|
||||
* Revision 1.4 1999/11/19 03:00:59 steve
|
||||
* Whoops, created a signal with a duplicate name.
|
||||
*
|
||||
* Revision 1.3 1999/11/05 04:40:40 steve
|
||||
* Patch to synthesize LPM_ADD_SUB from expressions,
|
||||
* Thanks to Larry Doolittle. Also handle constants
|
||||
* in expressions.
|
||||
*
|
||||
* Synthesize adders in XNF, based on a patch from
|
||||
* Larry. Accept synthesis of constants from Larry
|
||||
* as is.
|
||||
*
|
||||
* Revision 1.2 1999/11/04 03:53:26 steve
|
||||
* Patch to synthesize unary ~ and the ternary operator.
|
||||
* Thanks to Larry Doolittle <[email protected]>.
|
||||
*
|
||||
* Add the LPM_MUX device, and integrate it with the
|
||||
* ternary synthesis from Larry. Replace the lpm_mux
|
||||
* generator in t-xnf.cc to use XNF EQU devices to
|
||||
* put muxs into function units.
|
||||
*
|
||||
* Rewrite elaborate_net for the PETernary class to
|
||||
* also use the LPM_MUX device.
|
||||
*
|
||||
* Revision 1.1 1999/11/02 04:55:34 steve
|
||||
* Add the synthesize method to NetExpr to handle
|
||||
* synthesis of expressions, and use that method
|
||||
* to improve r-value handling of LPM_FF synthesis.
|
||||
*
|
||||
* Modify the XNF target to handle LPM_FF objects.
|
||||
*
|
||||
*/
|
||||
|
||||
+79
-2
@@ -17,7 +17,7 @@
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
|
||||
*/
|
||||
#if !defined(WINNT)
|
||||
#ident "$Id: functor.cc,v 1.2 1999/07/18 05:52:46 steve Exp $"
|
||||
#ident "$Id: functor.cc,v 1.5 1999/12/01 06:06:16 steve Exp $"
|
||||
#endif
|
||||
|
||||
# include "functor.h"
|
||||
@@ -35,14 +35,19 @@ void functor_t::process(class Design*, class NetProcTop*)
|
||||
{
|
||||
}
|
||||
|
||||
void functor_t::lpm_ff(class Design*, class NetFF*)
|
||||
{
|
||||
}
|
||||
|
||||
void Design::functor(functor_t*fun)
|
||||
{
|
||||
// apply to signals
|
||||
if (signals_) {
|
||||
NetNet*cur = signals_->sig_next_;
|
||||
do {
|
||||
NetNet*tmp = cur->sig_next_;
|
||||
fun->signal(this, cur);
|
||||
cur = cur->sig_next_;
|
||||
cur = tmp;
|
||||
} while (cur != signals_->sig_next_);
|
||||
}
|
||||
|
||||
@@ -53,10 +58,82 @@ void Design::functor(functor_t*fun)
|
||||
procs_idx_ = idx->next_;
|
||||
fun->process(this, idx);
|
||||
}
|
||||
|
||||
// apply to nodes
|
||||
if (nodes_) {
|
||||
NetNode*cur = nodes_->node_next_;
|
||||
do {
|
||||
NetNode*tmp = cur->node_next_;
|
||||
cur->functor_node(this, fun);
|
||||
cur = tmp;
|
||||
} while (cur != nodes_->node_next_);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void NetNode::functor_node(Design*, functor_t*)
|
||||
{
|
||||
}
|
||||
|
||||
void NetFF::functor_node(Design*des, functor_t*fun)
|
||||
{
|
||||
fun->lpm_ff(des, this);
|
||||
}
|
||||
|
||||
proc_match_t::~proc_match_t()
|
||||
{
|
||||
}
|
||||
|
||||
int NetProc::match_proc(proc_match_t*that)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
int proc_match_t::assign(NetAssign*)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
int NetAssign::match_proc(proc_match_t*that)
|
||||
{
|
||||
return that->assign(this);
|
||||
}
|
||||
|
||||
int proc_match_t::condit(NetCondit*)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
int NetCondit::match_proc(proc_match_t*that)
|
||||
{
|
||||
return that->condit(this);
|
||||
}
|
||||
|
||||
int proc_match_t::pevent(NetPEvent*)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
int NetPEvent::match_proc(proc_match_t*that)
|
||||
{
|
||||
return that->pevent(this);
|
||||
}
|
||||
|
||||
/*
|
||||
* $Log: functor.cc,v $
|
||||
* Revision 1.5 1999/12/01 06:06:16 steve
|
||||
* Redo synth to use match_proc_t scanner.
|
||||
*
|
||||
* Revision 1.4 1999/11/18 03:52:19 steve
|
||||
* Turn NetTmp objects into normal local NetNet objects,
|
||||
* and add the nodangle functor to clean up the local
|
||||
* symbols generated by elaboration and other steps.
|
||||
*
|
||||
* Revision 1.3 1999/11/01 02:07:40 steve
|
||||
* Add the synth functor to do generic synthesis
|
||||
* and add the LPM_FF device to handle rows of
|
||||
* flip-flops.
|
||||
*
|
||||
* Revision 1.2 1999/07/18 05:52:46 steve
|
||||
* xnfsyn generates DFF objects for XNF output, and
|
||||
* properly rewrites the Design netlist in the process.
|
||||
|
||||
@@ -19,7 +19,7 @@
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
|
||||
*/
|
||||
#if !defined(WINNT)
|
||||
#ident "$Id: functor.h,v 1.1 1999/07/17 22:01:13 steve Exp $"
|
||||
#ident "$Id: functor.h,v 1.3 1999/12/01 06:06:16 steve Exp $"
|
||||
#endif
|
||||
|
||||
/*
|
||||
@@ -42,10 +42,29 @@ struct functor_t {
|
||||
/* This method is called for each process in the design. */
|
||||
virtual void process(class Design*des, class NetProcTop*);
|
||||
|
||||
/* This method is called for each FF in the design. */
|
||||
virtual void lpm_ff(class Design*des, class NetFF*);
|
||||
};
|
||||
|
||||
struct proc_match_t {
|
||||
virtual ~proc_match_t();
|
||||
|
||||
virtual int assign(class NetAssign*);
|
||||
virtual int condit(class NetCondit*);
|
||||
virtual int pevent(class NetPEvent*);
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
* $Log: functor.h,v $
|
||||
* Revision 1.3 1999/12/01 06:06:16 steve
|
||||
* Redo synth to use match_proc_t scanner.
|
||||
*
|
||||
* Revision 1.2 1999/11/01 02:07:40 steve
|
||||
* Add the synth functor to do generic synthesis
|
||||
* and add the LPM_FF device to handle rows of
|
||||
* flip-flops.
|
||||
*
|
||||
* Revision 1.1 1999/07/17 22:01:13 steve
|
||||
* Add the functor interface for functor transforms.
|
||||
*
|
||||
|
||||
+6
-5
@@ -18,7 +18,7 @@
|
||||
# 59 Temple Place - Suite 330
|
||||
# Boston, MA 02111-1307, USA
|
||||
#
|
||||
#ident "$Id: Makefile.in,v 1.5 1999/07/30 00:42:33 steve Exp $"
|
||||
#ident "$Id: Makefile.in,v 1.6.2.1 1999/12/03 17:43:49 steve Exp $"
|
||||
#
|
||||
#
|
||||
SHELL = /bin/sh
|
||||
@@ -33,6 +33,7 @@ VPATH = $(srcdir)
|
||||
|
||||
bindir = $(exec_prefix)/bin
|
||||
libdir = $(exec_prefix)/lib
|
||||
libexecdir = $(libdir)/ivl
|
||||
includedir = $(prefix)/include
|
||||
|
||||
CC = @CC@
|
||||
@@ -60,13 +61,13 @@ lexor.c: lexor.lex
|
||||
parse.h parse.c: parse.y
|
||||
bison --verbose -t -d parse.y -o parse.c
|
||||
|
||||
install: all installdirs $(bindir)/ivlpp
|
||||
install: all installdirs $(libexecdir)/ivlpp
|
||||
|
||||
$(bindir)/ivlpp: ivlpp
|
||||
$(INSTALL_PROGRAM) ./ivlpp $(bindir)/ivlpp
|
||||
$(libexecdir)/ivlpp: ivlpp
|
||||
$(INSTALL_PROGRAM) ./ivlpp $(libexecdir)/ivlpp
|
||||
|
||||
installdirs: ../mkinstalldirs
|
||||
$(srcdir)/../mkinstalldirs $(includedir) $(bindir)
|
||||
$(srcdir)/../mkinstalldirs $(bindir)
|
||||
|
||||
uninstall:
|
||||
rm -f $(bindir)/ivlpp
|
||||
|
||||
+5
-2
@@ -19,12 +19,12 @@
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
|
||||
*/
|
||||
#if !defined(WINNT)
|
||||
#ident "$Id: globals.h,v 1.1 1999/07/03 20:03:47 steve Exp $"
|
||||
#ident "$Id: globals.h,v 1.2 1999/09/05 22:33:18 steve Exp $"
|
||||
#endif
|
||||
|
||||
# include <stdio.h>
|
||||
|
||||
extern void reset_lexor(FILE*out, const char*ipath);
|
||||
extern void reset_lexor(FILE*out, char*paths[]);
|
||||
extern void define_macro(const char*name, const char*value);
|
||||
|
||||
/* These variables contain the include directories to be searched when
|
||||
@@ -40,6 +40,9 @@ extern int yyparse();
|
||||
|
||||
/*
|
||||
* $Log: globals.h,v $
|
||||
* Revision 1.2 1999/09/05 22:33:18 steve
|
||||
* Take multiple source files on the command line.
|
||||
*
|
||||
* Revision 1.1 1999/07/03 20:03:47 steve
|
||||
* Add include path and line directives.
|
||||
*
|
||||
|
||||
+67
-12
@@ -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.11 1999/07/25 00:03:13 steve Exp $"
|
||||
#ident "$Id: lexor.lex,v 1.14 1999/10/08 17:27:56 steve Exp $"
|
||||
#endif
|
||||
|
||||
# include <stdio.h>
|
||||
@@ -60,6 +60,7 @@ struct include_stack_t {
|
||||
struct include_stack_t*next;
|
||||
};
|
||||
|
||||
static struct include_stack_t*file_queue = 0;
|
||||
static struct include_stack_t*istack = 0;
|
||||
static struct include_stack_t*standby = 0;
|
||||
|
||||
@@ -114,7 +115,7 @@ W [ \t\b\f]+
|
||||
that follows it. when the directive ends, the do_include function
|
||||
performs the include operation. */
|
||||
|
||||
^`include { BEGIN(PPINCLUDE); }
|
||||
^{W}?`include { BEGIN(PPINCLUDE); }
|
||||
|
||||
<PPINCLUDE>\"[^\"]*\" { include_filename(); }
|
||||
|
||||
@@ -128,7 +129,7 @@ W [ \t\b\f]+
|
||||
directive and the name, go into PPDEFINE mode and prepare to
|
||||
collect the defined value. */
|
||||
|
||||
^`define{W}[a-zA-Z][a-zA-Z0-9_]*{W}? { BEGIN(PPDEFINE); def_start(); }
|
||||
`define{W}[a-zA-Z][a-zA-Z0-9_]*{W}? { BEGIN(PPDEFINE); def_start(); }
|
||||
|
||||
<PPDEFINE>.*\n {
|
||||
do_define();
|
||||
@@ -137,7 +138,7 @@ W [ \t\b\f]+
|
||||
BEGIN(0);
|
||||
}
|
||||
|
||||
^`undef{W}[a-zA-Z][a-zA-Z0-9_]*{W}?.* { def_undefine(); }
|
||||
`undef{W}[a-zA-Z][a-zA-Z0-9_]*{W}?.* { def_undefine(); }
|
||||
|
||||
|
||||
/* Detect conditional compilation directives, and parse them. If I
|
||||
@@ -466,15 +467,22 @@ 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);
|
||||
}
|
||||
|
||||
/*
|
||||
* The lexical analyzer calls this function when the current file
|
||||
* ends. Here I pop the include stack and resume the previous file. If
|
||||
* there is no previous file, then the main input is ended.
|
||||
*/
|
||||
static int yywrap()
|
||||
{
|
||||
int line_mask_flag = 0;
|
||||
struct include_stack_t*isp = istack;
|
||||
istack = isp->next;
|
||||
|
||||
/* Delete the current input buffers, and free the cell. */
|
||||
yy_delete_buffer(YY_CURRENT_BUFFER);
|
||||
if (isp->file) {
|
||||
fclose(isp->file);
|
||||
@@ -492,13 +500,42 @@ static int yywrap()
|
||||
}
|
||||
free(isp);
|
||||
|
||||
if (istack == 0)
|
||||
return 1;
|
||||
/* If I am out if include stack, the main input is
|
||||
done. Look for another file to process in the input
|
||||
queue. If none are there, give up. Otherwise, open the file
|
||||
and continue parsing. */
|
||||
if (istack == 0) {
|
||||
if (file_queue == 0)
|
||||
return 1;
|
||||
|
||||
istack = file_queue;
|
||||
file_queue = file_queue->next;
|
||||
istack->next = 0;
|
||||
istack->lineno = 0;
|
||||
|
||||
istack->file = fopen(istack->path, "r");
|
||||
if (istack->file == 0) {
|
||||
perror(istack->path);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
if (line_direct_flag)
|
||||
fprintf(yyout, "\n#line \"%s\" 0\n", istack->path);
|
||||
|
||||
yyrestart(isp->file);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/* Otherwise, resume the input buffer that is the new stack
|
||||
top. If I need to print a line directive, do so. */
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
@@ -507,14 +544,16 @@ static int yywrap()
|
||||
* opened, and the lexor is initialized. The include stack is cleared
|
||||
* and ready to go.
|
||||
*/
|
||||
void reset_lexor(FILE*out, const char*path)
|
||||
void reset_lexor(FILE*out, char*paths[])
|
||||
{
|
||||
unsigned idx;
|
||||
struct include_stack_t*tail = 0;
|
||||
struct include_stack_t*isp = malloc(sizeof(struct include_stack_t));
|
||||
isp->path = strdup(path);
|
||||
isp->file = fopen(path, "r");
|
||||
isp->path = strdup(paths[0]);
|
||||
isp->file = fopen(paths[0], "r");
|
||||
isp->str = 0;
|
||||
if (isp->file == 0) {
|
||||
perror(path);
|
||||
perror(paths[0]);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
@@ -525,4 +564,20 @@ void reset_lexor(FILE*out, const char*path)
|
||||
assert(istack == 0);
|
||||
istack = isp;
|
||||
isp->next = 0;
|
||||
|
||||
/* Now build up a queue of all the remaining file names, so
|
||||
that yywrap can pull them when needed. */
|
||||
file_queue = 0;
|
||||
for (idx = 1 ; paths[idx] ; idx += 1) {
|
||||
isp = malloc(sizeof(struct include_stack_t));
|
||||
isp->path = strdup(paths[idx]);
|
||||
isp->str = 0;
|
||||
isp->next = 0;
|
||||
if (tail)
|
||||
tail->next = isp;
|
||||
else
|
||||
file_queue = isp;
|
||||
|
||||
tail = isp;
|
||||
}
|
||||
}
|
||||
|
||||
+17
-3
@@ -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.2 1999/07/03 20:03:47 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;
|
||||
@@ -109,7 +112,7 @@ int main(int argc, char*argv[])
|
||||
flag_errors += 1;
|
||||
|
||||
if (flag_errors) {
|
||||
fprintf(stderr, "\nUsage: %s [-v][-L][-I<dir>][-D<def>] <file>\n"
|
||||
fprintf(stderr, "\nUsage: %s [-v][-L][-I<dir>][-D<def>] <file>...\n"
|
||||
" -D<def> - Predefine a value.\n"
|
||||
" -I<dir> - Add an include file search directory\n"
|
||||
" -L - Emit line number directives\n"
|
||||
@@ -129,12 +132,23 @@ int main(int argc, char*argv[])
|
||||
out = stdout;
|
||||
}
|
||||
|
||||
reset_lexor(out, argv[optind]);
|
||||
if (argv[optind] == 0) {
|
||||
fprintf(stderr, "%s: No input files given.\n", argv[0]);
|
||||
return 1;
|
||||
}
|
||||
|
||||
reset_lexor(out, argv+optind);
|
||||
return yyparse();
|
||||
}
|
||||
|
||||
/*
|
||||
* $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.
|
||||
*
|
||||
* Revision 1.2 1999/07/03 20:03:47 steve
|
||||
* Add include path and line directives.
|
||||
*
|
||||
|
||||
@@ -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.33 1999/07/17 18:25:38 steve Exp $"
|
||||
#ident "$Id: lexor.lex,v 1.38 1999/11/23 02:49:04 steve Exp $"
|
||||
#endif
|
||||
|
||||
//# define YYSTYPE lexval
|
||||
@@ -40,8 +40,9 @@ extern YYLTYPE yylloc;
|
||||
|
||||
static void reset_lexor();
|
||||
static void line_directive();
|
||||
static void line_directive2();
|
||||
|
||||
static int check_identifier(const char*name);
|
||||
extern int check_identifier(const char*str, int len);
|
||||
static verinum*make_sized_binary(const char*txt);
|
||||
static verinum*make_sized_dec(const char*txt);
|
||||
static verinum*make_unsized_dec(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; }
|
||||
@@ -128,7 +130,7 @@ W [ \t\b\f\r]+
|
||||
<UDPTABLE>[pPnN01\?\*\-] { return yytext[0]; }
|
||||
|
||||
[a-zA-Z_][a-zA-Z0-9$_]* {
|
||||
int rc = check_identifier(yytext);
|
||||
int rc = check_identifier(yytext, yyleng);
|
||||
if (rc == IDENTIFIER)
|
||||
yylval.text = strdup(yytext);
|
||||
else
|
||||
@@ -150,11 +152,14 @@ W [ \t\b\f\r]+
|
||||
yylval.text = strdup(yytext);
|
||||
return SYSTEM_IDENTIFIER; }
|
||||
|
||||
\.[a-zA-Z_][a-zA-Z0-9$_]* {
|
||||
yylval.text = strdup(yytext+1);
|
||||
\.{W}?[a-zA-Z_][a-zA-Z0-9$_]* {
|
||||
char*cp = yytext+1;
|
||||
while (! (isalpha(*cp) || (*cp == '_')))
|
||||
cp += 1;
|
||||
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_\?]+ {
|
||||
@@ -305,118 +310,6 @@ void lex_end_table()
|
||||
BEGIN(INITIAL);
|
||||
}
|
||||
|
||||
static const struct { const char*name; int code; } key_table[] = {
|
||||
{ "always", K_always },
|
||||
{ "and", K_and },
|
||||
{ "assign", K_assign },
|
||||
{ "begin", K_begin },
|
||||
{ "buf", K_buf },
|
||||
{ "bufif0", K_bufif0 },
|
||||
{ "bufif1", K_bufif1 },
|
||||
{ "case", K_case },
|
||||
{ "casex", K_casex },
|
||||
{ "casez", K_casez },
|
||||
{ "cmos", K_cmos },
|
||||
{ "deassign", K_deassign },
|
||||
{ "default", K_default },
|
||||
{ "defparam", K_defparam },
|
||||
{ "disable", K_disable },
|
||||
{ "edge", K_edge },
|
||||
{ "else", K_else },
|
||||
{ "end", K_end },
|
||||
{ "endcase", K_endcase },
|
||||
{ "endfunction", K_endfunction },
|
||||
{ "endmodule", K_endmodule },
|
||||
{ "endprimitive", K_endprimitive },
|
||||
{ "endspecify", K_endspecify },
|
||||
{ "endtable", K_endtable },
|
||||
{ "endtask", K_endtask },
|
||||
{ "event", K_event },
|
||||
{ "for", K_for },
|
||||
{ "force", K_force },
|
||||
{ "forever", K_forever },
|
||||
{ "fork", K_fork },
|
||||
{ "function", K_function },
|
||||
{ "highz0", K_highz0 },
|
||||
{ "highz1", K_highz1 },
|
||||
{ "if", K_if },
|
||||
{ "initial", K_initial },
|
||||
{ "inout", K_inout },
|
||||
{ "input", K_input },
|
||||
{ "integer", K_integer },
|
||||
{ "join", K_join },
|
||||
{ "large", K_large },
|
||||
{ "macromodule", K_macromodule },
|
||||
{ "medium", K_medium },
|
||||
{ "module", K_module },
|
||||
{ "nand", K_nand },
|
||||
{ "negedge", K_negedge },
|
||||
{ "nmos", K_nmos },
|
||||
{ "nor", K_nor },
|
||||
{ "not", K_not },
|
||||
{ "notif0", K_notif0 },
|
||||
{ "notif1", K_notif1 },
|
||||
{ "or", K_or },
|
||||
{ "output", K_output },
|
||||
{ "parameter", K_parameter },
|
||||
{ "pmos", K_pmos },
|
||||
{ "posedge", K_posedge },
|
||||
{ "primitive", K_primitive },
|
||||
{ "pull0", K_pull0 },
|
||||
{ "pull1", K_pull1 },
|
||||
{ "pulldown", K_pulldown },
|
||||
{ "pullup", K_pullup },
|
||||
{ "rcmos", K_rcmos },
|
||||
{ "reg", K_reg },
|
||||
{ "release", K_release },
|
||||
{ "repeat", K_repeat },
|
||||
{ "rnmos", K_rnmos },
|
||||
{ "rpmos", K_rpmos },
|
||||
{ "rtran", K_rtran },
|
||||
{ "rtranif0", K_rtranif0 },
|
||||
{ "rtranif1", K_rtranif1 },
|
||||
{ "scalered", K_scalered },
|
||||
{ "small", K_small },
|
||||
{ "specify", K_specify },
|
||||
{ "specparam", K_specparam },
|
||||
{ "strong0", K_strong0 },
|
||||
{ "strong1", K_strong1 },
|
||||
{ "supply0", K_supply0 },
|
||||
{ "supply1", K_supply1 },
|
||||
{ "table", K_table },
|
||||
{ "task", K_task },
|
||||
{ "time", K_time },
|
||||
{ "tran", K_tran },
|
||||
{ "tranif0", K_tranif0 },
|
||||
{ "tranif1", K_tranif1 },
|
||||
{ "tri", K_tri },
|
||||
{ "tri0", K_tri0 },
|
||||
{ "tri1", K_tri1 },
|
||||
{ "triand", K_triand },
|
||||
{ "trior", K_trior },
|
||||
{ "trireg", K_trireg },
|
||||
{ "vectored", K_vectored },
|
||||
{ "wait", K_wait },
|
||||
{ "wand", K_wand },
|
||||
{ "weak0", K_weak0 },
|
||||
{ "weak1", K_weak1 },
|
||||
{ "while", K_while },
|
||||
{ "wire", K_wire },
|
||||
{ "wor", K_wor },
|
||||
{ "xnor", K_xnor },
|
||||
{ "xor", K_xor },
|
||||
{ 0, IDENTIFIER }
|
||||
};
|
||||
|
||||
static int check_identifier(const char*name)
|
||||
{
|
||||
for (unsigned idx = 0 ; key_table[idx].name ; idx += 1)
|
||||
if (strcmp(key_table[idx].name, name) == 0)
|
||||
return key_table[idx].code;
|
||||
|
||||
return IDENTIFIER;
|
||||
}
|
||||
|
||||
static verinum*make_binary_with_size(unsigned size, bool fixed, const char*ptr)
|
||||
{
|
||||
assert(tolower(*ptr) == 'b');
|
||||
@@ -540,47 +433,77 @@ static verinum*make_sized_octal(const char*txt)
|
||||
ptr += 1;
|
||||
assert(tolower(*ptr) == 'o');
|
||||
|
||||
/* We know from the size number how bit to make the verinom
|
||||
array, so make it now. */
|
||||
verinum::V*bits = new verinum::V[size];
|
||||
|
||||
/* skip white space between size and the base token. */
|
||||
while (*ptr && ((*ptr == ' ') || (*ptr == '\t')))
|
||||
ptr += 1;
|
||||
|
||||
unsigned idx = 0;
|
||||
/* Find the end of the digits. ptr already points to the start. */
|
||||
char*eptr = ptr + strlen(ptr);
|
||||
|
||||
while ((eptr > ptr) && (idx < (size-3))) {
|
||||
switch (*eptr) {
|
||||
/* From the last digit and forward, build up the number, least
|
||||
significant bit first. This loop will not get the last few
|
||||
bits if the size is not a multiple of 3. */
|
||||
unsigned idx = 0;
|
||||
while ((eptr > ptr) && ((idx/3) < (size/3))) switch (*--eptr) {
|
||||
|
||||
case 'x': case 'X':
|
||||
bits[idx++] = verinum::Vx;
|
||||
bits[idx++] = verinum::Vx;
|
||||
bits[idx++] = verinum::Vx;
|
||||
break;
|
||||
|
||||
case 'z': case 'Z': case '?':
|
||||
bits[idx++] = verinum::Vz;
|
||||
bits[idx++] = verinum::Vz;
|
||||
bits[idx++] = verinum::Vz;
|
||||
break;
|
||||
|
||||
default: {
|
||||
unsigned val = *eptr - '0';
|
||||
bits[idx++] = (val&1)? verinum::V1 : verinum::V0;
|
||||
bits[idx++] = (val&2)? verinum::V1 : verinum::V0;
|
||||
bits[idx++] = (val&4)? verinum::V1 : verinum::V0;
|
||||
}
|
||||
}
|
||||
|
||||
eptr -= 1;
|
||||
}
|
||||
|
||||
// zero extend octal numbers
|
||||
while (idx < size) switch (ptr[1]) {
|
||||
if ((eptr > ptr) && (idx < size)) switch (*--eptr) {
|
||||
|
||||
case 'x': case 'X':
|
||||
bits[idx++] = verinum::Vx;
|
||||
for ( ; idx < size ; idx += 1)
|
||||
bits[idx] = verinum::Vx;
|
||||
break;
|
||||
|
||||
case 'z': case 'Z': case '?':
|
||||
bits[idx++] = verinum::Vz;
|
||||
for ( ; idx < size ; idx += 1)
|
||||
bits[idx] = verinum::Vz;
|
||||
break;
|
||||
default:
|
||||
bits[idx++] = verinum::V0;
|
||||
|
||||
default: {
|
||||
unsigned val = *eptr - '0';
|
||||
for ( ; idx < size ; idx += 1) {
|
||||
bits[idx] = (val&1)? verinum::V1 : verinum::V0;
|
||||
val >>= 1;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
// zero extend octal numbers
|
||||
while (idx < size) switch (ptr[1]) {
|
||||
case 'x': case 'X':
|
||||
bits[idx++] = verinum::Vx;
|
||||
break;
|
||||
case 'z': case 'Z': case '?':
|
||||
bits[idx++] = verinum::Vz;
|
||||
break;
|
||||
default:
|
||||
bits[idx++] = verinum::V0;
|
||||
}
|
||||
}
|
||||
|
||||
return new verinum(bits, size, true);
|
||||
@@ -857,6 +780,31 @@ static void line_directive()
|
||||
yylloc.first_line = strtoul(qt2,0,0);
|
||||
}
|
||||
|
||||
static void line_directive2()
|
||||
{
|
||||
assert(strncmp(yytext,"`line",5) == 0);
|
||||
char*cp = yytext + strlen("`line");
|
||||
cp += strspn(cp, " ");
|
||||
yylloc.first_line = strtoul(cp,&cp,10);
|
||||
|
||||
cp += strspn(cp, " ");
|
||||
if (*cp == 0) return;
|
||||
|
||||
char*qt1 = strchr(yytext, '"');
|
||||
assert(qt1);
|
||||
qt1 += 1;
|
||||
|
||||
char*qt2 = strchr(qt1, '"');
|
||||
assert(qt2);
|
||||
|
||||
char*buf = new char[qt2-qt1+1];
|
||||
strncpy(buf, qt1, qt2-qt1);
|
||||
buf[qt2-qt1] = 0;
|
||||
|
||||
delete[]yylloc.text;
|
||||
yylloc.text = buf;
|
||||
}
|
||||
|
||||
static void reset_lexor()
|
||||
{
|
||||
yyrestart(vl_input);
|
||||
|
||||
@@ -0,0 +1,230 @@
|
||||
/* C code produced by gperf version 2.7 */
|
||||
/* Command-line: gperf -o -i 1 -C -k 1-3,$ -L C -H keyword_hash -N check_identifier -tT lexor_keyword.gperf > lexor_keyword.cc */
|
||||
|
||||
#include "parse_misc.h"
|
||||
#include "parse.h"
|
||||
#include <string.h>
|
||||
|
||||
|
||||
#define TOTAL_KEYWORDS 99
|
||||
#define MIN_WORD_LENGTH 2
|
||||
#define MAX_WORD_LENGTH 12
|
||||
#define MIN_HASH_VALUE 7
|
||||
#define MAX_HASH_VALUE 239
|
||||
/* maximum key range = 233, duplicates = 0 */
|
||||
|
||||
#ifdef __GNUC__
|
||||
__inline
|
||||
#endif
|
||||
static unsigned int
|
||||
keyword_hash (const char *str, int len)
|
||||
{
|
||||
static const unsigned char asso_values[] =
|
||||
{
|
||||
240, 240, 240, 240, 240, 240, 240, 240, 240, 240,
|
||||
240, 240, 240, 240, 240, 240, 240, 240, 240, 240,
|
||||
240, 240, 240, 240, 240, 240, 240, 240, 240, 240,
|
||||
240, 240, 240, 240, 240, 240, 240, 240, 240, 240,
|
||||
240, 240, 240, 240, 240, 240, 240, 240, 126, 66,
|
||||
240, 240, 240, 240, 240, 240, 240, 240, 240, 240,
|
||||
240, 240, 240, 240, 240, 240, 240, 240, 240, 240,
|
||||
240, 240, 240, 240, 240, 240, 240, 240, 240, 240,
|
||||
240, 240, 240, 240, 240, 240, 240, 240, 240, 240,
|
||||
240, 240, 240, 240, 240, 240, 240, 31, 11, 81,
|
||||
1, 1, 81, 26, 11, 51, 11, 21, 81, 81,
|
||||
1, 46, 16, 240, 1, 1, 6, 11, 36, 46,
|
||||
21, 16, 6, 240, 240, 240, 240, 240, 240, 240,
|
||||
240, 240, 240, 240, 240, 240, 240, 240, 240, 240,
|
||||
240, 240, 240, 240, 240, 240, 240, 240, 240, 240,
|
||||
240, 240, 240, 240, 240, 240, 240, 240, 240, 240,
|
||||
240, 240, 240, 240, 240, 240, 240, 240, 240, 240,
|
||||
240, 240, 240, 240, 240, 240, 240, 240, 240, 240,
|
||||
240, 240, 240, 240, 240, 240, 240, 240, 240, 240,
|
||||
240, 240, 240, 240, 240, 240, 240, 240, 240, 240,
|
||||
240, 240, 240, 240, 240, 240, 240, 240, 240, 240,
|
||||
240, 240, 240, 240, 240, 240, 240, 240, 240, 240,
|
||||
240, 240, 240, 240, 240, 240, 240, 240, 240, 240,
|
||||
240, 240, 240, 240, 240, 240, 240, 240, 240, 240,
|
||||
240, 240, 240, 240, 240, 240, 240, 240, 240, 240,
|
||||
240, 240, 240, 240, 240, 240
|
||||
};
|
||||
int hval = len;
|
||||
|
||||
hval += asso_values[(unsigned char)str[len - 1]];
|
||||
hval += asso_values[(unsigned char)str[0]];
|
||||
hval += asso_values[(unsigned char)str[1]];
|
||||
|
||||
if (len > 2)
|
||||
hval += asso_values[(unsigned char)str[2]];
|
||||
|
||||
return hval ;
|
||||
}
|
||||
|
||||
int
|
||||
check_identifier (const char *str, int len)
|
||||
{
|
||||
static const struct { const char *name; int tokenType; } wordlist[] =
|
||||
{
|
||||
{""}, {""}, {""}, {""}, {""}, {""}, {""},
|
||||
{"end", K_end},
|
||||
{""}, {""}, {""},
|
||||
{"endcase", K_endcase},
|
||||
{"endtable", K_endtable},
|
||||
{"endmodule", K_endmodule},
|
||||
{"rtran", K_rtran},
|
||||
{"endfunction", K_endfunction},
|
||||
{"endprimitive", K_endprimitive},
|
||||
{""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""},
|
||||
{""}, {""}, {""},
|
||||
{"endspecify", K_endspecify},
|
||||
{"repeat", K_repeat},
|
||||
{"endtask", K_endtask},
|
||||
{""},
|
||||
{"edge", K_edge},
|
||||
{""}, {""},
|
||||
{"negedge", K_negedge},
|
||||
{"and", K_and},
|
||||
{"nand", K_nand},
|
||||
{""},
|
||||
{"assign", K_assign},
|
||||
{"specify", K_specify},
|
||||
{"deassign", K_deassign},
|
||||
{"tran", K_tran},
|
||||
{"begin", K_begin},
|
||||
{""}, {""}, {""}, {""},
|
||||
{"event", K_event},
|
||||
{"or", K_or},
|
||||
{""},
|
||||
{"nor", K_nor},
|
||||
{""},
|
||||
{"table", K_table},
|
||||
{""}, {""},
|
||||
{"reg", K_reg},
|
||||
{"parameter", K_parameter},
|
||||
{""}, {""},
|
||||
{"disable", K_disable},
|
||||
{"not", K_not},
|
||||
{"task", K_task},
|
||||
{"trior", K_trior},
|
||||
{"triand", K_triand},
|
||||
{"integer", K_integer},
|
||||
{""}, {""}, {""}, {""},
|
||||
{"posedge", K_posedge},
|
||||
{"xor", K_xor},
|
||||
{"xnor", K_xnor},
|
||||
{""},
|
||||
{"output", K_output},
|
||||
{""}, {""},
|
||||
{"primitive", K_primitive},
|
||||
{"input", K_input},
|
||||
{""},
|
||||
{"strong1", K_strong1},
|
||||
{"rtranif1", K_rtranif1},
|
||||
{"wand", K_wand},
|
||||
{""}, {""}, {""}, {""},
|
||||
{"else", K_else},
|
||||
{"rnmos", K_rnmos},
|
||||
{"trireg", K_trireg},
|
||||
{"release", K_release},
|
||||
{""}, {""}, {""}, {""},
|
||||
{"default", K_default},
|
||||
{"wor", K_wor},
|
||||
{""}, {""}, {""},
|
||||
{"supply1", K_supply1},
|
||||
{"function", K_function},
|
||||
{"wire", K_wire},
|
||||
{"rpmos", K_rpmos},
|
||||
{""}, {""}, {""},
|
||||
{"specparam", K_specparam},
|
||||
{"inout", K_inout},
|
||||
{""},
|
||||
{"tranif1", K_tranif1},
|
||||
{"tri", K_tri},
|
||||
{"join", K_join},
|
||||
{"while", K_while},
|
||||
{""}, {""},
|
||||
{"pulldown", K_pulldown},
|
||||
{"case", K_case},
|
||||
{"large", K_large},
|
||||
{""}, {""},
|
||||
{"scalered", K_scalered},
|
||||
{""},
|
||||
{"casez", K_casez},
|
||||
{"notif1", K_notif1},
|
||||
{""},
|
||||
{"vectored", K_vectored},
|
||||
{"tri1", K_tri1},
|
||||
{""},
|
||||
{"pullup", K_pullup},
|
||||
{""},
|
||||
{"for", K_for},
|
||||
{"nmos", K_nmos},
|
||||
{"force", K_force},
|
||||
{"module", K_module},
|
||||
{"forever", K_forever},
|
||||
{""},
|
||||
{"wait", K_wait},
|
||||
{"casex", K_casex},
|
||||
{""},
|
||||
{"strong0", K_strong0},
|
||||
{"rtranif0", K_rtranif0},
|
||||
{"time", K_time},
|
||||
{""}, {""}, {""}, {""},
|
||||
{"pmos", K_pmos},
|
||||
{"weak1", K_weak1},
|
||||
{""}, {""}, {""},
|
||||
{"fork", K_fork},
|
||||
{""}, {""}, {""}, {""}, {""}, {""},
|
||||
{"highz1", K_highz1},
|
||||
{"supply0", K_supply0},
|
||||
{""}, {""}, {""},
|
||||
{"always", K_always},
|
||||
{""}, {""}, {""},
|
||||
{"rcmos", K_rcmos},
|
||||
{"medium", K_medium},
|
||||
{"tranif0", K_tranif0},
|
||||
{"defparam", K_defparam},
|
||||
{""}, {""},
|
||||
{"bufif1", K_bufif1},
|
||||
{""}, {""}, {""},
|
||||
{"pull1", K_pull1},
|
||||
{""}, {""}, {""}, {""}, {""},
|
||||
{"notif0", K_notif0},
|
||||
{""},
|
||||
{"buf", K_buf},
|
||||
{"tri0", K_tri0},
|
||||
{""}, {""},
|
||||
{"initial", K_initial},
|
||||
{""}, {""}, {""}, {""}, {""}, {""}, {""},
|
||||
{"small", K_small},
|
||||
{""}, {""}, {""}, {""}, {""},
|
||||
{"macromodule", K_macromodule},
|
||||
{""}, {""}, {""},
|
||||
{"weak0", K_weak0},
|
||||
{""}, {""}, {""},
|
||||
{"cmos", K_cmos},
|
||||
{""},
|
||||
{"if", K_if},
|
||||
{""}, {""}, {""}, {""},
|
||||
{"highz0", K_highz0},
|
||||
{""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""},
|
||||
{""}, {""}, {""}, {""}, {""},
|
||||
{"bufif0", K_bufif0},
|
||||
{""}, {""}, {""},
|
||||
{"pull0", K_pull0}
|
||||
};
|
||||
|
||||
if (len <= MAX_WORD_LENGTH && len >= MIN_WORD_LENGTH)
|
||||
{
|
||||
int key = keyword_hash (str, len);
|
||||
|
||||
if (key <= MAX_HASH_VALUE && key >= 0)
|
||||
{
|
||||
const char *s = wordlist[key].name;
|
||||
|
||||
if (*str == *s && !strcmp (str + 1, s + 1))
|
||||
return wordlist[key].tokenType;
|
||||
}
|
||||
}
|
||||
return IDENTIFIER;
|
||||
}
|
||||
@@ -0,0 +1,112 @@
|
||||
%{
|
||||
/* Command-line: gperf -o -i 1 -C -k 1-3,$ -L C -H keyword_hash -N check_identifier -tT lexor_keyword.gperf */
|
||||
|
||||
#include "parse_misc.h"
|
||||
#include "parse.h"
|
||||
#include <string.h>
|
||||
|
||||
%}
|
||||
struct Keywords {
|
||||
char *name;
|
||||
int tokenType;
|
||||
} Keywords;
|
||||
%%
|
||||
always, K_always
|
||||
and, K_and
|
||||
assign, K_assign
|
||||
begin, K_begin
|
||||
buf, K_buf
|
||||
bufif0, K_bufif0
|
||||
bufif1, K_bufif1
|
||||
case, K_case
|
||||
casex, K_casex
|
||||
casez, K_casez
|
||||
cmos, K_cmos
|
||||
deassign, K_deassign
|
||||
default, K_default
|
||||
defparam, K_defparam
|
||||
disable, K_disable
|
||||
edge, K_edge
|
||||
else, K_else
|
||||
end, K_end
|
||||
endcase, K_endcase
|
||||
endfunction, K_endfunction
|
||||
endmodule, K_endmodule
|
||||
endprimitive, K_endprimitive
|
||||
endspecify, K_endspecify
|
||||
endtable, K_endtable
|
||||
endtask, K_endtask
|
||||
event, K_event
|
||||
for, K_for
|
||||
force, K_force
|
||||
forever, K_forever
|
||||
fork, K_fork
|
||||
function, K_function
|
||||
highz0, K_highz0
|
||||
highz1, K_highz1
|
||||
if, K_if
|
||||
initial, K_initial
|
||||
inout, K_inout
|
||||
input, K_input
|
||||
integer, K_integer
|
||||
join, K_join
|
||||
large, K_large
|
||||
macromodule, K_macromodule
|
||||
medium, K_medium
|
||||
module, K_module
|
||||
nand, K_nand
|
||||
negedge, K_negedge
|
||||
nmos, K_nmos
|
||||
nor, K_nor
|
||||
not, K_not
|
||||
notif0, K_notif0
|
||||
notif1, K_notif1
|
||||
or, K_or
|
||||
output, K_output
|
||||
parameter, K_parameter
|
||||
pmos, K_pmos
|
||||
posedge, K_posedge
|
||||
primitive, K_primitive
|
||||
pull0, K_pull0
|
||||
pull1, K_pull1
|
||||
pulldown, K_pulldown
|
||||
pullup, K_pullup
|
||||
rcmos, K_rcmos
|
||||
reg, K_reg
|
||||
release, K_release
|
||||
repeat, K_repeat
|
||||
rnmos, K_rnmos
|
||||
rpmos, K_rpmos
|
||||
rtran, K_rtran
|
||||
rtranif0, K_rtranif0
|
||||
rtranif1, K_rtranif1
|
||||
scalered, K_scalered
|
||||
small, K_small
|
||||
specify, K_specify
|
||||
specparam, K_specparam
|
||||
strong0, K_strong0
|
||||
strong1, K_strong1
|
||||
supply0, K_supply0
|
||||
supply1, K_supply1
|
||||
table, K_table
|
||||
task, K_task
|
||||
time, K_time
|
||||
tran, K_tran
|
||||
tranif0, K_tranif0
|
||||
tranif1, K_tranif1
|
||||
tri, K_tri
|
||||
tri0, K_tri0
|
||||
tri1, K_tri1
|
||||
triand, K_triand
|
||||
trior, K_trior
|
||||
trireg, K_trireg
|
||||
vectored, K_vectored
|
||||
wait, K_wait
|
||||
wand, K_wand
|
||||
weak0, K_weak0
|
||||
weak1, K_weak1
|
||||
while, K_while
|
||||
wire, K_wire
|
||||
wor, K_wor
|
||||
xnor, K_xnor
|
||||
xor, K_xor
|
||||
@@ -0,0 +1,26 @@
|
||||
|
||||
WHAT IS LPM
|
||||
|
||||
LPM (Library of Paramaterized Modules) is EIS-IS standard 103-A. It is
|
||||
a standard library of abstract devices that are designed to be close
|
||||
enough to the target hardware to be easily translated, yet abstract
|
||||
enough to support a variety of target technologies without excessive
|
||||
constraints. Icarus Verilog uses LPM internally to represent idealized
|
||||
hardware, especially when doing target neutral synthesis.
|
||||
|
||||
In general, the user does not even see the LPM that Icarus Verilog
|
||||
generates, because the LPM devices are translated into technology
|
||||
specific devices by the final code generator or target specific
|
||||
optimizers.
|
||||
|
||||
INTERNAL USES OF LPM
|
||||
|
||||
Internally, Icarus Verilog uses LPM devices to represent the design in
|
||||
abstract, especially when synthesizing such functions as addition,
|
||||
flip-flops, etc. The ``synth'' functor generates LPM modules when
|
||||
interpreting procedural constructs. The functor generates the LPM
|
||||
objects needed to replace a behavioral description, and uses
|
||||
attributes to tag the devices with LPM properties.
|
||||
|
||||
Code generators need to understand the supported LPM devices so that
|
||||
they can translate the devices into technology specific devices.
|
||||
@@ -19,7 +19,7 @@ const char COPYRIGHT[] =
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
|
||||
*/
|
||||
#if !defined(WINNT)
|
||||
#ident "$Id: main.cc,v 1.22 1999/08/03 04:14:49 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"
|
||||
@@ -75,12 +78,13 @@ static void parm_to_flagmap(const string&flag)
|
||||
extern Design* elaborate(const map<string,Module*>&modules,
|
||||
const map<string,PUdp*>&primitives,
|
||||
const string&root);
|
||||
extern void emit(ostream&o, const Design*, const char*);
|
||||
|
||||
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);
|
||||
|
||||
@@ -91,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 }
|
||||
@@ -252,6 +258,7 @@ int main(int argc, char*argv[])
|
||||
}
|
||||
|
||||
|
||||
bool emit_rc;
|
||||
if (out_path) {
|
||||
ofstream out;
|
||||
out.open(out_path);
|
||||
@@ -261,10 +268,15 @@ int main(int argc, char*argv[])
|
||||
return 1;
|
||||
}
|
||||
|
||||
emit(out, des, target);
|
||||
emit_rc = emit(out, des, target);
|
||||
|
||||
} else {
|
||||
emit(cout, des, target);
|
||||
emit_rc = emit(cout, des, target);
|
||||
}
|
||||
|
||||
if (!emit_rc) {
|
||||
cerr << "internal error: Code generation had errors." << endl;
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
@@ -272,6 +284,22 @@ 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.
|
||||
*
|
||||
* Revision 1.22 1999/08/03 04:14:49 steve
|
||||
* Parse into pform arbitrarily complex module
|
||||
* port declarations.
|
||||
|
||||
+1566
-398
File diff suppressed because it is too large
Load Diff
+79
-11
@@ -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.3 1999/07/24 02:11:20 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
|
||||
@@ -53,14 +53,39 @@ in the vector.
|
||||
Node and net pins can be connected together via the connect
|
||||
function. Connections are transitive (A==B and B==c means A==C) so
|
||||
connections accumulate on a link as items are connected to it. The
|
||||
descructors for nets and nodes automatically arrange for pins to be
|
||||
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,
|
||||
they represent elabrated behavioral statements. The type of the object
|
||||
they represent elaborated behavioral statements. The type of the object
|
||||
implies what the behavior of the statement does. For example, a
|
||||
NetCondit object represents an ``if'' statement, and carries a
|
||||
condition expression and up to two alternative sub-statements.
|
||||
@@ -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
|
||||
@@ -105,7 +159,7 @@ structurally as events are like devices that trigger behavioral
|
||||
statements.
|
||||
|
||||
However, typical expressions the behavioral description are
|
||||
represented as a tree of NetExpr nodes. The derived clas of the node
|
||||
represented as a tree of NetExpr nodes. The derived class of the node
|
||||
encodes what kind of operator the node represents.
|
||||
|
||||
EXPRESSION BIT WIDTH
|
||||
@@ -150,17 +204,14 @@ 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
|
||||
|
||||
The obvious hierarchical structure of verilog is the module. The
|
||||
The obvious hierarchical structure of Verilog is the module. The
|
||||
Verilog program may contain any number of instantiations of modules in
|
||||
order to form an hierarchical design. However, the elaboration of the
|
||||
design into a netlist erases module boundaries. Modules are expanded
|
||||
@@ -189,6 +240,23 @@ 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.
|
||||
|
||||
Revision 1.3 1999/07/24 02:11:20 steve
|
||||
Elaborate task input ports.
|
||||
|
||||
|
||||
@@ -0,0 +1,42 @@
|
||||
#ifndef __netmisc_H
|
||||
#define __netmisc_H
|
||||
/*
|
||||
* 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: netmisc.h,v 1.1 1999/09/29 00:42:51 steve Exp $"
|
||||
#endif
|
||||
|
||||
# include "netlist.h"
|
||||
|
||||
/*
|
||||
* This funciton transforms an expression by padding the high bits
|
||||
* with V0 until the expression has the desired width. This may mean
|
||||
* not transforming the expression at all, if it is already wide
|
||||
* enough.
|
||||
*/
|
||||
extern NetExpr*pad_to_width(NetExpr*expr, unsigned wid);
|
||||
|
||||
|
||||
/*
|
||||
* $Log: netmisc.h,v $
|
||||
* Revision 1.1 1999/09/29 00:42:51 steve
|
||||
* Allow expanding of additive operators.
|
||||
*
|
||||
*/
|
||||
#endif
|
||||
+86
@@ -0,0 +1,86 @@
|
||||
/*
|
||||
* Copyright (c) 1999Stephen Williams (steve@icarus.com)
|
||||
*
|
||||
* This source code is free software; you can redistribute it
|
||||
* and/or modify it in source code form under the terms of the GNU
|
||||
* General Public License as published by the Free Software
|
||||
* Foundation; either version 2 of the License, or (at your option)
|
||||
* any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
|
||||
*/
|
||||
#if !defined(WINNT)
|
||||
#ident "$Id: nodangle.cc,v 1.2 1999/11/28 23:42:02 steve Exp $"
|
||||
#endif
|
||||
|
||||
/*
|
||||
* This functor scans the design looking for dangling objects and
|
||||
* excess local signals. These deletions are not necessarily required
|
||||
* for proper functioning of anything, but they can clean up the
|
||||
* appearance of design files that are generated.
|
||||
*/
|
||||
# include "functor.h"
|
||||
# include "netlist.h"
|
||||
|
||||
class nodangle_f : public functor_t {
|
||||
public:
|
||||
void signal(Design*des, NetNet*sig);
|
||||
};
|
||||
|
||||
|
||||
void nodangle_f::signal(Design*des, NetNet*sig)
|
||||
{
|
||||
if (! sig->local_flag())
|
||||
return;
|
||||
if (sig->get_eref() > 0)
|
||||
return;
|
||||
|
||||
/* Check to see if there is some significant signal connected
|
||||
to every pin of this signal. */
|
||||
unsigned significant_flags = 0;
|
||||
for (unsigned idx = 0 ; idx < sig->pin_count() ; idx += 1) {
|
||||
NetObj::Link&lnk = sig->pin(idx);
|
||||
for (NetObj::Link*cur = lnk.next_link()
|
||||
; cur != &lnk ; cur = cur->next_link()) {
|
||||
NetNet*cursig = dynamic_cast<NetNet*>(cur->get_obj());
|
||||
if (cursig == 0)
|
||||
continue;
|
||||
if (cursig->local_flag())
|
||||
continue;
|
||||
significant_flags += 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* If every pin is connected to another significant signal,
|
||||
then I can delete this one. */
|
||||
if (significant_flags == sig->pin_count())
|
||||
delete sig;
|
||||
}
|
||||
|
||||
void nodangle(Design*des)
|
||||
{
|
||||
nodangle_f fun;
|
||||
des->functor(&fun);
|
||||
}
|
||||
|
||||
/*
|
||||
* $Log: nodangle.cc,v $
|
||||
* Revision 1.2 1999/11/28 23:42:02 steve
|
||||
* NetESignal object no longer need to be NetNode
|
||||
* objects. Let them keep a pointer to NetNet objects.
|
||||
*
|
||||
* Revision 1.1 1999/11/18 03:52:20 steve
|
||||
* Turn NetTmp objects into normal local NetNet objects,
|
||||
* and add the nodangle functor to clean up the local
|
||||
* symbols generated by elaboration and other steps.
|
||||
*
|
||||
*/
|
||||
|
||||
@@ -0,0 +1,53 @@
|
||||
/*
|
||||
* 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: pad_to_width.cc,v 1.1 1999/09/29 00:42:51 steve Exp $"
|
||||
#endif
|
||||
|
||||
# include "netlist.h"
|
||||
# include "netmisc.h"
|
||||
|
||||
/*
|
||||
* This funciton transforms an expression by padding the high bits
|
||||
* with V0 until the expression has the desired width. This may mean
|
||||
* not transforming the expression at all, if it is already wide
|
||||
* enough.
|
||||
*/
|
||||
NetExpr*pad_to_width(NetExpr*expr, unsigned wid)
|
||||
{
|
||||
if (wid > expr->expr_width()) {
|
||||
verinum pad(verinum::V0, wid - expr->expr_width());
|
||||
NetEConst*co = new NetEConst(pad);
|
||||
NetEConcat*cc = new NetEConcat(2);
|
||||
cc->set(0, co);
|
||||
cc->set(1, expr);
|
||||
cc->set_width(wid);
|
||||
expr = cc;
|
||||
}
|
||||
return expr;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* $Log: pad_to_width.cc,v $
|
||||
* Revision 1.1 1999/09/29 00:42:51 steve
|
||||
* Allow expanding of additive operators.
|
||||
*
|
||||
*/
|
||||
|
||||
@@ -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.58 1999/08/03 04:48:51 steve Exp $"
|
||||
#ident "$Id: parse.y,v 1.76 1999/11/15 04:43:52 steve Exp $"
|
||||
#endif
|
||||
|
||||
# include "parse_misc.h"
|
||||
@@ -109,7 +109,7 @@ extern void lex_end_table();
|
||||
%type <text> net_decl_assign
|
||||
%type <strings> net_decl_assigns
|
||||
|
||||
%type <mport> port port_reference port_reference_list
|
||||
%type <mport> port port_opt port_reference port_reference_list
|
||||
%type <mports> list_of_ports list_of_ports_opt
|
||||
|
||||
%type <wires> task_item task_item_list task_item_list_opt
|
||||
@@ -129,6 +129,7 @@ extern void lex_end_table();
|
||||
%type <expr> delay_value
|
||||
%type <exprs> delay delay_opt delay_value_list
|
||||
%type <exprs> expression_list
|
||||
%type <exprs> assign assign_list
|
||||
|
||||
%type <exprs> range range_opt
|
||||
%type <nettype> net_type
|
||||
@@ -137,17 +138,19 @@ extern void lex_end_table();
|
||||
|
||||
%type <task> task_body
|
||||
%type <function> func_body
|
||||
%type <exprs> range_or_type_opt
|
||||
%type <event_expr> event_expression_list
|
||||
%type <event_expr> event_expression
|
||||
%type <event_statement> event_control
|
||||
%type <statement> statement statement_opt
|
||||
%type <statement_list> statement_list
|
||||
|
||||
%left '?' ':'
|
||||
%right '?' ':'
|
||||
%left K_LOR
|
||||
%left K_LAND
|
||||
%left '|'
|
||||
%left '^'
|
||||
%left '&'
|
||||
%left '^' K_NXOR K_NOR
|
||||
%left '&' K_NAND
|
||||
%left K_EQ K_NE K_CEQ K_CNE
|
||||
%left K_GE K_LE '<' '>'
|
||||
%left K_LS K_RS
|
||||
@@ -155,16 +158,37 @@ extern void lex_end_table();
|
||||
%left '*' '/' '%'
|
||||
%left UNARY_PREC
|
||||
|
||||
/* to resolve dangling else ambiguity: */
|
||||
%nonassoc less_than_K_else
|
||||
%nonassoc K_else
|
||||
|
||||
%%
|
||||
|
||||
/* A degenerate source file can be completely empty. */
|
||||
main : source_file | ;
|
||||
|
||||
source_file
|
||||
: description
|
||||
| source_file description
|
||||
;
|
||||
|
||||
/* The block_item_decl is used in function definitions, task
|
||||
definitions, module definitions and named blocks. Wherever a new
|
||||
scope is entered, the source may declare new registers and
|
||||
integers. This rule matches those declarations. The containing
|
||||
rule has presumably set up the scope. */
|
||||
block_item_decl
|
||||
: K_reg range_opt register_variable_list ';'
|
||||
: K_reg range register_variable_list ';'
|
||||
{ pform_set_net_range($3, $2);
|
||||
delete $2;
|
||||
delete $3;
|
||||
}
|
||||
| K_reg register_variable_list ';'
|
||||
{ delete $2; }
|
||||
| K_integer list_of_variables ';'
|
||||
{ pform_set_reg_integer($2);
|
||||
delete $2;
|
||||
}
|
||||
;
|
||||
|
||||
block_item_decls
|
||||
@@ -196,7 +220,7 @@ case_item
|
||||
$$ = tmp;
|
||||
}
|
||||
| error ':' statement_opt
|
||||
{ yyerror(@1, "Incomprehensible case expression.");
|
||||
{ yyerror(@1, "error: Incomprehensible case expression.");
|
||||
yyerrok;
|
||||
}
|
||||
;
|
||||
@@ -230,11 +254,12 @@ defparam_assign
|
||||
: identifier '=' expression
|
||||
{ PExpr*tmp = $3;
|
||||
if (!pform_expression_is_constant(tmp)) {
|
||||
yyerror(@3, "parameter value must be constant.");
|
||||
yyerror(@3, "error: parameter value "
|
||||
"must be constant.");
|
||||
delete tmp;
|
||||
tmp = 0;
|
||||
}
|
||||
yyerror(@1, "Sorry, defparam assignments not supported.");
|
||||
yyerror(@1, "sorry: defparam assignments not supported.");
|
||||
delete $1;
|
||||
delete $3;
|
||||
}
|
||||
@@ -243,8 +268,8 @@ defparam_assign
|
||||
defparam_assign_list
|
||||
: defparam_assign
|
||||
| range defparam_assign
|
||||
{ yyerror(@1, "Ranges in parameter definition "
|
||||
"are not supported.");
|
||||
{ yywarn(@1, "Ranges in parameter definition "
|
||||
"are not supported.");
|
||||
delete $1;
|
||||
}
|
||||
| defparam_assign_list ',' defparam_assign
|
||||
@@ -270,7 +295,7 @@ delay_value
|
||||
: NUMBER
|
||||
{ verinum*tmp = $1;
|
||||
if (tmp == 0) {
|
||||
yyerror(@1, "XXXX internal error: delay.");
|
||||
yyerror(@1, "internal error: delay.");
|
||||
$$ = 0;
|
||||
} else {
|
||||
$$ = new PENumber(tmp);
|
||||
@@ -311,12 +336,29 @@ 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.");
|
||||
{ yyerror(@1, "sorry: event control not supported.");
|
||||
$$ = 0;
|
||||
}
|
||||
| '@' '(' event_expression ')'
|
||||
| '@' '(' event_expression_list ')'
|
||||
{ PEventStatement*tmp = new PEventStatement(*$3);
|
||||
tmp->set_file(@1.text);
|
||||
tmp->set_lineno(@1.first_line);
|
||||
@@ -324,11 +366,22 @@ event_control
|
||||
$$ = tmp;
|
||||
}
|
||||
| '@' '(' error ')'
|
||||
{ yyerror(@1, "Malformed event control expression.");
|
||||
{ yyerror(@1, "error: Malformed event control expression.");
|
||||
$$ = 0;
|
||||
}
|
||||
;
|
||||
|
||||
event_expression_list
|
||||
: event_expression
|
||||
{ $$ = $1; }
|
||||
| event_expression_list K_or event_expression
|
||||
{ svector<PEEvent*>*tmp = new svector<PEEvent*>(*$1, *$3);
|
||||
delete $1;
|
||||
delete $3;
|
||||
$$ = tmp;
|
||||
}
|
||||
;
|
||||
|
||||
event_expression
|
||||
: K_posedge expression
|
||||
{ PEEvent*tmp = new PEEvent(NetNEvent::POSEDGE, $2);
|
||||
@@ -354,12 +407,6 @@ event_expression
|
||||
(*tl)[0] = tmp;
|
||||
$$ = tl;
|
||||
}
|
||||
| event_expression K_or event_expression
|
||||
{ svector<PEEvent*>*tmp = new svector<PEEvent*>(*$1, *$3);
|
||||
delete $1;
|
||||
delete $3;
|
||||
$$ = tmp;
|
||||
}
|
||||
;
|
||||
|
||||
expression
|
||||
@@ -469,6 +516,18 @@ expression
|
||||
tmp->set_lineno(@2.first_line);
|
||||
$$ = tmp;
|
||||
}
|
||||
| expression K_NOR expression
|
||||
{ PEBinary*tmp = new PEBinary('O', $1, $3);
|
||||
tmp->set_file(@2.text);
|
||||
tmp->set_lineno(@2.first_line);
|
||||
$$ = tmp;
|
||||
}
|
||||
| expression K_NXOR expression
|
||||
{ PEBinary*tmp = new PEBinary('X', $1, $3);
|
||||
tmp->set_file(@2.text);
|
||||
tmp->set_lineno(@2.first_line);
|
||||
$$ = tmp;
|
||||
}
|
||||
| expression '<' expression
|
||||
{ PEBinary*tmp = new PEBinary('<', $1, $3);
|
||||
tmp->set_file(@2.text);
|
||||
@@ -579,7 +638,7 @@ expr_primary
|
||||
$$ = tmp;
|
||||
}
|
||||
| REALTIME
|
||||
{ yyerror(@1, "Sorry, real constants not supported.");
|
||||
{ yyerror(@1, "sorry: real constants not supported.");
|
||||
delete $1;
|
||||
$$ = 0;
|
||||
}
|
||||
@@ -628,13 +687,15 @@ expr_primary
|
||||
$$ = tmp;
|
||||
}
|
||||
| SYSTEM_IDENTIFIER '(' expression_list ')'
|
||||
{ yyerror(@2, "Sorry, function calls not supported.");
|
||||
$$ = 0;
|
||||
{ PECallFunction*tmp = new PECallFunction($1, *$3);
|
||||
tmp->set_file(@1.text);
|
||||
tmp->set_lineno(@1.first_line);
|
||||
$$ = tmp;
|
||||
}
|
||||
| '(' expression ')'
|
||||
{ $$ = $2; }
|
||||
| '(' expression ':' expression ':' expression ')'
|
||||
{ yyerror(@2, "Sorry, (min:typ:max) not supported.");
|
||||
{ yyerror(@2, "sorry: (min:typ:max) not supported.");
|
||||
$$ = $4;
|
||||
delete $2;
|
||||
delete $6;
|
||||
@@ -649,7 +710,8 @@ expr_primary
|
||||
| '{' expression '{' expression_list '}' '}'
|
||||
{ PExpr*rep = $2;
|
||||
if (!pform_expression_is_constant($2)) {
|
||||
yyerror(@2, "Repeat expression must be constant.");
|
||||
yyerror(@2, "error: Repeat expression "
|
||||
"must be constant.");
|
||||
delete rep;
|
||||
delete $2;
|
||||
rep = 0;
|
||||
@@ -667,31 +729,45 @@ func_body
|
||||
: function_item_list statement
|
||||
{ $$ = new PFunction($1, $2); }
|
||||
| function_item_list
|
||||
{ yyerror(@1, "function body has no statement."); }
|
||||
{ yyerror(@1, "error: function body has no statement.");
|
||||
$$ = new PFunction($1, 0);
|
||||
}
|
||||
;
|
||||
|
||||
/* A function_item is either a block item (i.e. a reg or integer
|
||||
declaration) or an input declaration. There are no output or
|
||||
inout ports. */
|
||||
function_item
|
||||
: K_input range_opt list_of_variables ';'
|
||||
{ svector<PWire*>*tmp
|
||||
= pform_make_task_ports(NetNet::PINPUT, $2, $3);
|
||||
= pform_make_task_ports(NetNet::PINPUT, $2, $3,
|
||||
@1.text, @1.first_line);
|
||||
delete $2;
|
||||
delete $3;
|
||||
$$ = tmp;
|
||||
}
|
||||
| K_reg range_opt list_of_variables ';'
|
||||
{ $$ = 0; }
|
||||
| K_integer list_of_variables ';'
|
||||
| block_item_decl
|
||||
{ $$ = 0; }
|
||||
;
|
||||
|
||||
/* A function_item_list only lists the input/output/inout
|
||||
declarations. The integer and reg declarations are handled in
|
||||
place, so are not listed. The list builder needs to account for
|
||||
the possibility that the various parts may be NULL. */
|
||||
function_item_list
|
||||
: function_item
|
||||
{ $$ = $1; }
|
||||
| function_item_list function_item
|
||||
{ svector<PWire*>*tmp = new svector<PWire*>(*$1, *$2);
|
||||
delete $1;
|
||||
delete $2;
|
||||
$$ = tmp;
|
||||
{ if ($1 && $2) {
|
||||
svector<PWire*>*tmp = new svector<PWire*>(*$1, *$2);
|
||||
delete $1;
|
||||
delete $2;
|
||||
$$ = tmp;
|
||||
} else if ($1) {
|
||||
$$ = $1;
|
||||
} else {
|
||||
$$ = $2;
|
||||
}
|
||||
}
|
||||
;
|
||||
|
||||
@@ -798,19 +874,18 @@ identifier
|
||||
: IDENTIFIER
|
||||
{ $$ = $1; }
|
||||
| HIDENTIFIER
|
||||
{ yyerror(@1, "Sorry, qualified identifiers not supported.");
|
||||
$$ = $1;
|
||||
{ $$ = $1;
|
||||
}
|
||||
;
|
||||
|
||||
list_of_ports
|
||||
: port
|
||||
: port_opt
|
||||
{ svector<Module::port_t*>*tmp
|
||||
= new svector<Module::port_t*>(1);
|
||||
(*tmp)[0] = $1;
|
||||
$$ = tmp;
|
||||
}
|
||||
| list_of_ports ',' port
|
||||
| list_of_ports ',' port_opt
|
||||
{ svector<Module::port_t*>*tmp
|
||||
= new svector<Module::port_t*>(*$1, $3);
|
||||
delete $1;
|
||||
@@ -820,7 +895,6 @@ list_of_ports
|
||||
|
||||
list_of_ports_opt
|
||||
: '(' list_of_ports ')' { $$ = $2; }
|
||||
| '(' ')' { $$ = 0; }
|
||||
| { $$ = 0; }
|
||||
;
|
||||
|
||||
@@ -854,7 +928,7 @@ lavalue
|
||||
{ PEIdent*tmp = new PEIdent($1);
|
||||
PExpr*sel = $3;
|
||||
if (! pform_expression_is_constant(sel)) {
|
||||
yyerror(@2, "Bit select in lvalue must "
|
||||
yyerror(@2, "eror: Bit select in lvalue must "
|
||||
"contain a constant expression.");
|
||||
delete sel;
|
||||
} else {
|
||||
@@ -922,6 +996,26 @@ lpvalue
|
||||
}
|
||||
;
|
||||
|
||||
assign
|
||||
: lavalue '=' expression
|
||||
{ svector<PExpr*>*tmp = new svector<PExpr*>(2);
|
||||
(*tmp)[0] = $1;
|
||||
(*tmp)[1] = $3;
|
||||
$$ = tmp;
|
||||
}
|
||||
;
|
||||
|
||||
assign_list
|
||||
: assign_list ',' assign
|
||||
{ svector<PExpr*>*tmp = new svector<PExpr*>(*$1, *$3);
|
||||
delete $1;
|
||||
delete $3;
|
||||
$$ = tmp;
|
||||
}
|
||||
| assign
|
||||
{ $$ = $1; }
|
||||
;
|
||||
|
||||
module
|
||||
: K_module IDENTIFIER list_of_ports_opt ';'
|
||||
{ pform_startmodule($2, $3);
|
||||
@@ -958,7 +1052,7 @@ module_item
|
||||
delete $3;
|
||||
}
|
||||
| K_trireg charge_strength_opt range_opt delay_opt list_of_variables ';'
|
||||
{ yyerror(@1, "Sorry, trireg nets not supported.");
|
||||
{ yyerror(@1, "sorry: trireg nets not supported.");
|
||||
delete $3;
|
||||
}
|
||||
| port_type range_opt list_of_variables ';'
|
||||
@@ -969,20 +1063,10 @@ module_item
|
||||
}
|
||||
delete $3;
|
||||
}
|
||||
| K_reg range register_variable_list ';'
|
||||
{ pform_set_net_range($3, $2);
|
||||
delete $2;
|
||||
delete $3;
|
||||
}
|
||||
| K_reg register_variable_list ';'
|
||||
{ delete $2; }
|
||||
| K_integer register_variable_list ';'
|
||||
{ pform_set_reg_integer($2);
|
||||
delete $2;
|
||||
}
|
||||
| block_item_decl
|
||||
| K_defparam defparam_assign_list ';'
|
||||
| K_event list_of_variables ';'
|
||||
{ yyerror(@1, "Sorry, named events not supported.");
|
||||
{ yyerror(@1, "sorry: named events not supported.");
|
||||
delete $2;
|
||||
}
|
||||
| K_parameter parameter_assign_list ';'
|
||||
@@ -990,18 +1074,11 @@ module_item
|
||||
{ pform_makegates($1, $2, $3);
|
||||
}
|
||||
| IDENTIFIER delay_opt gate_instance_list ';'
|
||||
{ pform_make_modgates($1, $3);
|
||||
{ pform_make_modgates($1, $2, $3);
|
||||
delete $1;
|
||||
if ($2) {
|
||||
yyerror(@2, "Sorry, parameter override not supported.");
|
||||
delete $2;
|
||||
}
|
||||
}
|
||||
| K_assign delay_opt lavalue '=' expression ';'
|
||||
{ PGAssign*tmp = pform_make_pgassign($3, $5, $2);
|
||||
tmp->set_file(@1.text);
|
||||
tmp->set_lineno(@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);
|
||||
@@ -1032,7 +1109,7 @@ module_item
|
||||
{ PFunction *tmp = $6;
|
||||
tmp->set_file(@1.text);
|
||||
tmp->set_lineno(@1.first_line);
|
||||
pform_set_function($3, $6);
|
||||
pform_set_function($3, $2, $6);
|
||||
delete $3;
|
||||
}
|
||||
| K_specify specify_item_list K_endspecify
|
||||
@@ -1045,7 +1122,7 @@ module_item
|
||||
delete $7;
|
||||
}
|
||||
| KK_attribute '(' error ')' ';'
|
||||
{ yyerror(@1, "Misformed $attribute parameter list."); }
|
||||
{ yyerror(@1, "error: Misformed $attribute parameter list."); }
|
||||
;
|
||||
|
||||
module_item_list
|
||||
@@ -1105,7 +1182,8 @@ parameter_assign
|
||||
: IDENTIFIER '=' expression
|
||||
{ PExpr*tmp = $3;
|
||||
if (!pform_expression_is_constant(tmp)) {
|
||||
yyerror(@3, "parameter value must be constant.");
|
||||
yyerror(@3, "error: parameter value "
|
||||
"must be constant.");
|
||||
delete tmp;
|
||||
tmp = 0;
|
||||
}
|
||||
@@ -1117,7 +1195,7 @@ parameter_assign
|
||||
parameter_assign_list
|
||||
: parameter_assign
|
||||
| range parameter_assign
|
||||
{ yyerror(@1, "Ranges in parameter definition "
|
||||
{ yywarn(@1, "Ranges in parameter definition "
|
||||
"are not supported.");
|
||||
delete $1;
|
||||
}
|
||||
@@ -1159,6 +1237,11 @@ port
|
||||
}
|
||||
;
|
||||
|
||||
port_opt
|
||||
: port { $$ = $1; }
|
||||
| { $$ = 0; }
|
||||
;
|
||||
|
||||
port_reference
|
||||
: IDENTIFIER
|
||||
{ Module::port_t*ptmp = new Module::port_t(1);
|
||||
@@ -1177,11 +1260,11 @@ port_reference
|
||||
wtmp->set_file(@1.text);
|
||||
wtmp->set_lineno(@1.first_line);
|
||||
if (!pform_expression_is_constant($3)) {
|
||||
yyerror(@3, "msb expression of port bit select "
|
||||
yyerror(@3, "error: msb expression of port bit select "
|
||||
"must be constant.");
|
||||
}
|
||||
if (!pform_expression_is_constant($5)) {
|
||||
yyerror(@5, "lsb expression of port bit select "
|
||||
yyerror(@5, "error: lsb expression of port bit select "
|
||||
"must be constant.");
|
||||
}
|
||||
wtmp->set_range($3, $5);
|
||||
@@ -1192,7 +1275,7 @@ port_reference
|
||||
$$ = ptmp;
|
||||
}
|
||||
| IDENTIFIER '[' error ']'
|
||||
{ yyerror(@1, "invalid port bit select");
|
||||
{ yyerror(@1, "error: invalid port bit select");
|
||||
Module::port_t*ptmp = new Module::port_t(1);
|
||||
PWire*wtmp = new PWire($1, NetNet::IMPLICIT,
|
||||
NetNet::PIMPLICIT);
|
||||
@@ -1229,7 +1312,7 @@ port_name
|
||||
$$ = tmp;
|
||||
}
|
||||
| PORTNAME '(' error ')'
|
||||
{ yyerror(@3, "invalid port connection expression.");
|
||||
{ yyerror(@3, "error: invalid port connection expression.");
|
||||
portname_t*tmp = new portname_t;
|
||||
tmp->name = $1;
|
||||
tmp->parm = 0;
|
||||
@@ -1269,12 +1352,12 @@ range
|
||||
: '[' expression ':' expression ']'
|
||||
{ svector<PExpr*>*tmp = new svector<PExpr*> (2);
|
||||
if (!pform_expression_is_constant($2))
|
||||
yyerror(@2, "msb of range must be constant.");
|
||||
yyerror(@2, "error: msb of range must be constant.");
|
||||
|
||||
(*tmp)[0] = $2;
|
||||
|
||||
if (!pform_expression_is_constant($4))
|
||||
yyerror(@4, "msb of range must be constant.");
|
||||
yyerror(@4, "error: msb of range must be constant.");
|
||||
|
||||
(*tmp)[1] = $4;
|
||||
|
||||
@@ -1288,12 +1371,12 @@ range_opt
|
||||
;
|
||||
|
||||
range_or_type_opt
|
||||
: range { }
|
||||
| K_integer
|
||||
| K_real
|
||||
| K_realtime
|
||||
| K_time
|
||||
|
|
||||
: range { $$ = $1; }
|
||||
| K_integer { $$ = 0; }
|
||||
| K_real { $$ = 0; }
|
||||
| K_realtime { $$ = 0; }
|
||||
| K_time { $$ = 0; }
|
||||
| { $$ = 0; }
|
||||
;
|
||||
/* The register_variable rule is matched only when I am parsing
|
||||
variables in a "reg" definition. I therefore know that I am
|
||||
@@ -1307,16 +1390,16 @@ register_variable
|
||||
}
|
||||
| IDENTIFIER '=' expression
|
||||
{ pform_makewire(@1, $1, NetNet::REG);
|
||||
yyerror(@2, "net declaration assignment to reg/integer not allowed.");
|
||||
yyerror(@2, "error: net declaration assignment to reg/integer not allowed.");
|
||||
delete $3;
|
||||
$$ = $1;
|
||||
}
|
||||
| IDENTIFIER '[' expression ':' expression ']'
|
||||
{ pform_makewire(@1, $1, NetNet::REG);
|
||||
if (! pform_expression_is_constant($3))
|
||||
yyerror(@3, "msb of register range must be constant.");
|
||||
yyerror(@3, "error: msb of register range must be constant.");
|
||||
if (! pform_expression_is_constant($5))
|
||||
yyerror(@3, "lsb of register range must be constant.");
|
||||
yyerror(@3, "error: lsb of register range must be constant.");
|
||||
pform_set_reg_idx($1, $3, $5);
|
||||
$$ = $1;
|
||||
}
|
||||
@@ -1340,8 +1423,7 @@ register_variable_list
|
||||
specify_item
|
||||
: K_specparam specparam_list ';'
|
||||
| specify_simple_path '=' '(' expression_list ')' ';'
|
||||
{ /* yyerror(@1, "Sorry, specify path declarations not supported."); */
|
||||
delete $4;
|
||||
{ delete $4;
|
||||
}
|
||||
;
|
||||
|
||||
@@ -1357,8 +1439,7 @@ specify_simple_path
|
||||
|
||||
specparam
|
||||
: IDENTIFIER '=' expression
|
||||
{ /* yyerror(@1, "Sorry, specparam assignments not supported."); */
|
||||
delete $1;
|
||||
{ delete $1;
|
||||
delete $3;
|
||||
}
|
||||
;
|
||||
@@ -1372,7 +1453,7 @@ spec_polarity: '+' | '-' | ;
|
||||
|
||||
statement
|
||||
: K_assign lavalue '=' expression ';'
|
||||
{ yyerror(@1, "Sorry, procedural continuous assign not supported.");
|
||||
{ yyerror(@1, "sorry: procedural continuous assign not supported.");
|
||||
$$ = 0;
|
||||
}
|
||||
| K_begin statement_list K_end
|
||||
@@ -1409,16 +1490,16 @@ statement
|
||||
| K_begin error K_end
|
||||
{ yyerrok; }
|
||||
| K_deassign lavalue';'
|
||||
{ yyerror(@1, "Sorry, deassign not supported.");
|
||||
{ yyerror(@1, "sorry:, deassign not supported.");
|
||||
$$ = 0;
|
||||
}
|
||||
| K_disable IDENTIFIER ';'
|
||||
{ yyerror(@1, "Sorry, disable statements not supported.");
|
||||
{ yyerror(@1, "sorry: disable statements not supported.");
|
||||
delete $2;
|
||||
$$ = 0;
|
||||
}
|
||||
| K_force lavalue '=' expression ';'
|
||||
{ yyerror(@1, "Sorry, procedural force assign not supported.");
|
||||
{ yyerror(@1, "sorry: procedural force assign not supported.");
|
||||
$$ = 0;
|
||||
}
|
||||
| K_forever statement
|
||||
@@ -1434,14 +1515,16 @@ statement
|
||||
delete $2;
|
||||
$$ = tmp;
|
||||
}
|
||||
| K_release lavalue ';'
|
||||
{ yyerror(@1, "Sorry, release not supported.");
|
||||
$$ = 0;
|
||||
}
|
||||
| K_repeat '(' expression ')' statement
|
||||
{ PRepeat*tmp = new PRepeat($3, $5);
|
||||
| K_fork ':' IDENTIFIER
|
||||
{ pform_push_scope($3); }
|
||||
block_item_decls_opt
|
||||
statement_list K_join
|
||||
{ pform_pop_scope();
|
||||
PBlock*tmp = new PBlock($3, PBlock::BL_PAR, *$6);
|
||||
tmp->set_file(@1.text);
|
||||
tmp->set_lineno(@1.first_line);
|
||||
delete $3;
|
||||
delete $6;
|
||||
$$ = tmp;
|
||||
}
|
||||
| K_fork K_join
|
||||
@@ -1450,24 +1533,38 @@ statement
|
||||
tmp->set_lineno(@1.first_line);
|
||||
$$ = tmp;
|
||||
}
|
||||
| K_fork ':' IDENTIFIER K_join
|
||||
{ PBlock*tmp = new PBlock(PBlock::BL_PAR);
|
||||
tmp->set_file(@1.text);
|
||||
tmp->set_lineno(@1.first_line);
|
||||
$$ = tmp;
|
||||
}
|
||||
| K_release lavalue ';'
|
||||
{ yyerror(@1, "sorry: release not supported.");
|
||||
$$ = 0;
|
||||
}
|
||||
| K_repeat '(' expression ')' statement
|
||||
{ PRepeat*tmp = new PRepeat($3, $5);
|
||||
tmp->set_file(@1.text);
|
||||
tmp->set_lineno(@1.first_line);
|
||||
$$ = tmp;
|
||||
}
|
||||
| K_case '(' expression ')' case_items K_endcase
|
||||
{ PCase*tmp = new PCase($3, $5);
|
||||
{ PCase*tmp = new PCase(NetCase::EQ, $3, $5);
|
||||
tmp->set_file(@1.text);
|
||||
tmp->set_lineno(@1.first_line);
|
||||
$$ = tmp;
|
||||
}
|
||||
| K_casex '(' expression ')' case_items K_endcase
|
||||
{ PCase*tmp = new PCase($3, $5);
|
||||
{ PCase*tmp = new PCase(NetCase::EQX, $3, $5);
|
||||
tmp->set_file(@1.text);
|
||||
tmp->set_lineno(@1.first_line);
|
||||
yywarn(@1, "casex not properly supported, using case.");
|
||||
$$ = tmp;
|
||||
}
|
||||
| K_casez '(' expression ')' case_items K_endcase
|
||||
{ PCase*tmp = new PCase($3, $5);
|
||||
{ PCase*tmp = new PCase(NetCase::EQZ, $3, $5);
|
||||
tmp->set_file(@1.text);
|
||||
tmp->set_lineno(@1.first_line);
|
||||
yywarn(@1, "casez not properly supported, using case.");
|
||||
$$ = tmp;
|
||||
}
|
||||
| K_case '(' expression ')' error K_endcase
|
||||
@@ -1476,7 +1573,7 @@ statement
|
||||
{ yyerrok; }
|
||||
| K_casez '(' expression ')' error K_endcase
|
||||
{ yyerrok; }
|
||||
| K_if '(' expression ')' statement_opt
|
||||
| K_if '(' expression ')' statement_opt %prec less_than_K_else
|
||||
{ PCondit*tmp = new PCondit($3, $5, 0);
|
||||
tmp->set_file(@1.text);
|
||||
tmp->set_lineno(@1.first_line);
|
||||
@@ -1488,12 +1585,12 @@ statement
|
||||
tmp->set_lineno(@1.first_line);
|
||||
$$ = tmp;
|
||||
}
|
||||
| K_if '(' error ')' statement_opt
|
||||
{ yyerror(@1, "Malformed conditional expression.");
|
||||
| K_if '(' error ')' statement_opt %prec less_than_K_else
|
||||
{ yyerror(@1, "error: Malformed conditional expression.");
|
||||
$$ = $5;
|
||||
}
|
||||
| K_if '(' error ')' statement_opt K_else statement_opt
|
||||
{ yyerror(@1, "Malformed conditional expression.");
|
||||
{ yyerror(@1, "error: Malformed conditional expression.");
|
||||
$$ = $5;
|
||||
}
|
||||
| K_for '(' lpvalue '=' expression ';' expression ';'
|
||||
@@ -1506,16 +1603,16 @@ statement
|
||||
| K_for '(' lpvalue '=' expression ';' expression ';'
|
||||
error ')' statement
|
||||
{ $$ = 0;
|
||||
yyerror(@9, "Error in for loop step assigment.");
|
||||
yyerror(@9, "error: Error in for loop step assigment.");
|
||||
}
|
||||
| K_for '(' lpvalue '=' expression ';' error ';'
|
||||
lpvalue '=' expression ')' statement
|
||||
{ $$ = 0;
|
||||
yyerror(@7, "Error in for loop condition expression.");
|
||||
yyerror(@7, "error: Error in for loop condition expression.");
|
||||
}
|
||||
| K_for '(' error ')' statement
|
||||
{ $$ = 0;
|
||||
yyerror(@3, "Incomprehensible for loop.");
|
||||
yyerror(@3, "error: Incomprehensible for loop.");
|
||||
}
|
||||
| K_while '(' expression ')' statement
|
||||
{ PWhile*tmp = new PWhile($3, $5);
|
||||
@@ -1523,12 +1620,12 @@ statement
|
||||
}
|
||||
| K_while '(' error ')' statement
|
||||
{ $$ = 0;
|
||||
yyerror(@3, "Error in while loop condition.");
|
||||
yyerror(@3, "error: Error in while loop condition.");
|
||||
}
|
||||
| delay statement_opt
|
||||
{ PExpr*del = (*$1)[0];
|
||||
if ($1->count() != 1)
|
||||
yyerror(@1, "Sorry, delay lists not supported here.");
|
||||
yyerror(@1, "sorry: delay lists not supported here.");
|
||||
PDelayStatement*tmp = new PDelayStatement(del, $2);
|
||||
tmp->set_file(@1.text);
|
||||
tmp->set_lineno(@1.first_line);
|
||||
@@ -1537,7 +1634,7 @@ statement
|
||||
| event_control statement_opt
|
||||
{ PEventStatement*tmp = $1;
|
||||
if (tmp == 0) {
|
||||
yyerror(@1, "Invalid event control.");
|
||||
yyerror(@1, "error: Invalid event control.");
|
||||
$$ = 0;
|
||||
} else {
|
||||
tmp->set_statement($2);
|
||||
@@ -1559,12 +1656,34 @@ statement
|
||||
| lpvalue '=' delay expression ';'
|
||||
{ PExpr*del = (*$3)[0];
|
||||
if ($3->count() != 1)
|
||||
yyerror(@1, "Sorry, delay lists not supported here.");
|
||||
yyerror(@1, "sorry: Delay lists not supported here.");
|
||||
PAssign*tmp = new PAssign($1,del,$4);
|
||||
tmp->set_file(@1.text);
|
||||
tmp->set_lineno(@1.first_line);
|
||||
$$ = tmp;
|
||||
}
|
||||
| lpvalue K_LE delay expression ';'
|
||||
{ PExpr*del = (*$3)[0];
|
||||
if ($3->count() != 1)
|
||||
yyerror(@1, "sorry: Delay lists not supported here.");
|
||||
PAssignNB*tmp = new PAssignNB($1,del,$4);
|
||||
tmp->set_file(@1.text);
|
||||
tmp->set_lineno(@1.first_line);
|
||||
$$ = tmp;
|
||||
}
|
||||
| lpvalue '=' event_control expression ';'
|
||||
{ PAssign*tmp = new PAssign($1,$3,$4);
|
||||
tmp->set_file(@1.text);
|
||||
tmp->set_lineno(@1.first_line);
|
||||
$$ = tmp;
|
||||
}
|
||||
| lpvalue K_LE event_control expression ';'
|
||||
{ yyerror(@1, "sorry: Event controls not supported here.");
|
||||
PAssignNB*tmp = new PAssignNB($1,$4);
|
||||
tmp->set_file(@1.text);
|
||||
tmp->set_lineno(@1.first_line);
|
||||
$$ = tmp;
|
||||
}
|
||||
| K_wait '(' expression ')' statement_opt
|
||||
{ PEventStatement*tmp;
|
||||
PEEvent*etmp = new PEEvent(NetNEvent::POSITIVE, $3);
|
||||
@@ -1621,7 +1740,7 @@ statement
|
||||
$$ = tmp;
|
||||
}
|
||||
| error ';'
|
||||
{ yyerror(@1, "malformed statement");
|
||||
{ yyerror(@1, "error: malformed statement");
|
||||
yyerrok;
|
||||
$$ = new PNoop;
|
||||
}
|
||||
@@ -1654,24 +1773,27 @@ task_body
|
||||
|
||||
task_item
|
||||
: block_item_decl
|
||||
{ $$ = 0; }
|
||||
{ $$ = new svector<PWire*>(0); }
|
||||
| K_input range_opt list_of_variables ';'
|
||||
{ svector<PWire*>*tmp
|
||||
= pform_make_task_ports(NetNet::PINPUT, $2, $3);
|
||||
= pform_make_task_ports(NetNet::PINPUT, $2,
|
||||
$3, @1.text, @1.first_line);
|
||||
delete $2;
|
||||
delete $3;
|
||||
$$ = tmp;
|
||||
}
|
||||
| K_output range_opt list_of_variables ';'
|
||||
{ svector<PWire*>*tmp
|
||||
= pform_make_task_ports(NetNet::POUTPUT, $2, $3);
|
||||
= pform_make_task_ports(NetNet::POUTPUT, $2, $3,
|
||||
@1.text, @1.first_line);
|
||||
delete $2;
|
||||
delete $3;
|
||||
$$ = tmp;
|
||||
}
|
||||
| K_inout range_opt list_of_variables ';'
|
||||
{ svector<PWire*>*tmp
|
||||
= pform_make_task_ports(NetNet::PINOUT, $2, $3);
|
||||
= pform_make_task_ports(NetNet::PINOUT, $2, $3,
|
||||
@1.text, @1.first_line);
|
||||
delete $2;
|
||||
delete $3;
|
||||
$$ = tmp;
|
||||
|
||||
+5
-2
@@ -17,7 +17,7 @@
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
|
||||
*/
|
||||
#if !defined(WINNT)
|
||||
#ident "$Id: parse_misc.cc,v 1.2 1998/11/07 17:05:05 steve Exp $"
|
||||
#ident "$Id: parse_misc.cc,v 1.3 1999/09/29 21:15:31 steve Exp $"
|
||||
#endif
|
||||
|
||||
# include "parse_misc.h"
|
||||
@@ -48,7 +48,7 @@ void yywarn(const YYLTYPE&loc, const char*msg)
|
||||
if (loc.text)
|
||||
cerr << loc.text << ":";
|
||||
|
||||
cerr << loc.first_line << ": warning -- " << msg << endl;
|
||||
cerr << loc.first_line << ": warning: " << msg << endl;
|
||||
}
|
||||
|
||||
int VLwrap()
|
||||
@@ -58,6 +58,9 @@ int VLwrap()
|
||||
|
||||
/*
|
||||
* $Log: parse_misc.cc,v $
|
||||
* Revision 1.3 1999/09/29 21:15:31 steve
|
||||
* Standardize formatting of warning messages.
|
||||
*
|
||||
* Revision 1.2 1998/11/07 17:05:05 steve
|
||||
* Handle procedural conditional, and some
|
||||
* of the conditional expressions.
|
||||
|
||||
@@ -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.37 1999/08/03 04:14:49 steve Exp $"
|
||||
#ident "$Id: pform.cc,v 1.47 1999/11/23 01:04:57 steve Exp $"
|
||||
#endif
|
||||
|
||||
# include "compiler.h"
|
||||
@@ -42,7 +42,9 @@ static Module*pform_cur_module = 0;
|
||||
/*
|
||||
* The scope stack and the following functions handle the processing
|
||||
* of scope. As I enter a scope, the push function is called, and as I
|
||||
* leave a scope the opo function is called.
|
||||
* leave a scope the pop function is called.
|
||||
*
|
||||
* The top module is not included in the scope list.
|
||||
*/
|
||||
struct scope_name_t {
|
||||
string name;
|
||||
@@ -97,6 +99,15 @@ static unsigned long evaluate_delay(PExpr*delay)
|
||||
void pform_startmodule(const string&name, svector<Module::port_t*>*ports)
|
||||
{
|
||||
assert( pform_cur_module == 0 );
|
||||
|
||||
/* The parser parses ``module foo()'' as having one
|
||||
unconnected port, but it is really a module with no
|
||||
ports. Fix it up here. */
|
||||
if (ports && (ports->count() == 1) && ((*ports)[0] == 0)) {
|
||||
delete ports;
|
||||
ports = 0;
|
||||
}
|
||||
|
||||
pform_cur_module = new Module(name, ports);
|
||||
delete ports;
|
||||
}
|
||||
@@ -296,6 +307,7 @@ void pform_makegates(PGBuiltin::Type type,
|
||||
*/
|
||||
static void pform_make_modgate(const string&type,
|
||||
const string&name,
|
||||
svector<PExpr*>*overrides,
|
||||
svector<PExpr*>*wires,
|
||||
const string&fn, unsigned ln)
|
||||
{
|
||||
@@ -306,7 +318,7 @@ static void pform_make_modgate(const string&type,
|
||||
return;
|
||||
}
|
||||
|
||||
PGate*cur = new PGModule(type, name, wires);
|
||||
PGate*cur = new PGModule(type, name, overrides, wires);
|
||||
cur->set_file(fn);
|
||||
cur->set_lineno(ln);
|
||||
pform_cur_module->add_gate(cur);
|
||||
@@ -314,6 +326,7 @@ static void pform_make_modgate(const string&type,
|
||||
|
||||
static void pform_make_modgate(const string&type,
|
||||
const string&name,
|
||||
svector<PExpr*>*overrides,
|
||||
svector<portname_t*>*bind,
|
||||
const string&fn, unsigned ln)
|
||||
{
|
||||
@@ -332,27 +345,29 @@ static void pform_make_modgate(const string&type,
|
||||
pins[idx].parm = curp->parm;
|
||||
}
|
||||
|
||||
PGate*cur = new PGModule(type, name, pins, npins);
|
||||
PGate*cur = new PGModule(type, name, overrides, pins, npins);
|
||||
cur->set_file(fn);
|
||||
cur->set_lineno(ln);
|
||||
pform_cur_module->add_gate(cur);
|
||||
}
|
||||
|
||||
void pform_make_modgates(const string&type, svector<lgate>*gates)
|
||||
void pform_make_modgates(const string&type,
|
||||
svector<PExpr*>*overrides,
|
||||
svector<lgate>*gates)
|
||||
{
|
||||
for (unsigned idx = 0 ; idx < gates->count() ; idx += 1) {
|
||||
lgate cur = (*gates)[idx];
|
||||
|
||||
if (cur.parms_by_name) {
|
||||
pform_make_modgate(type, cur.name, cur.parms_by_name,
|
||||
pform_make_modgate(type, cur.name, overrides, cur.parms_by_name,
|
||||
cur.file, cur.lineno);
|
||||
|
||||
} else if (cur.parms) {
|
||||
pform_make_modgate(type, cur.name, cur.parms, cur.file,
|
||||
pform_make_modgate(type, cur.name, overrides, cur.parms, cur.file,
|
||||
cur.lineno);
|
||||
} else {
|
||||
svector<PExpr*>*wires = new svector<PExpr*>(0);
|
||||
pform_make_modgate(type, cur.name, wires, cur.file,
|
||||
pform_make_modgate(type, cur.name, overrides, wires, cur.file,
|
||||
cur.lineno);
|
||||
}
|
||||
}
|
||||
@@ -378,6 +393,20 @@ PGAssign* pform_make_pgassign(PExpr*lval, PExpr*rval,
|
||||
return cur;
|
||||
}
|
||||
|
||||
void pform_make_pgassign_list(svector<PExpr*>*alist,
|
||||
svector<PExpr*>*del,
|
||||
const string& text,
|
||||
unsigned lineno)
|
||||
{
|
||||
PGAssign*tmp;
|
||||
for (unsigned idx = 0 ; idx < alist->count()/2 ; idx += 1) {
|
||||
tmp = pform_make_pgassign((*alist)[2*idx],
|
||||
(*alist)[2*idx+1], del);
|
||||
tmp->set_file(text);
|
||||
tmp->set_lineno(lineno);
|
||||
}
|
||||
}
|
||||
|
||||
void pform_makewire(const vlltype&li, const string&nm,
|
||||
NetNet::Type type)
|
||||
{
|
||||
@@ -465,8 +494,11 @@ void pform_set_port_type(const string&name, NetNet::PortType pt)
|
||||
*/
|
||||
svector<PWire*>*pform_make_task_ports(NetNet::PortType pt,
|
||||
const svector<PExpr*>*range,
|
||||
const list<string>*names)
|
||||
const list<string>*names,
|
||||
const string& file,
|
||||
unsigned lineno)
|
||||
{
|
||||
assert(names);
|
||||
svector<PWire*>*res = new svector<PWire*>(0);
|
||||
for (list<string>::const_iterator cur = names->begin()
|
||||
; cur != names->end() ; cur ++ ) {
|
||||
@@ -480,6 +512,8 @@ svector<PWire*>*pform_make_task_ports(NetNet::PortType pt,
|
||||
curw->set_port_type(pt);
|
||||
} else {
|
||||
curw = new PWire(name, NetNet::IMPLICIT_REG, pt);
|
||||
curw->set_file(file);
|
||||
curw->set_lineno(lineno);
|
||||
pform_cur_module->add_wire(curw);
|
||||
}
|
||||
|
||||
@@ -500,8 +534,21 @@ void pform_set_task(const string&name, PTask*task)
|
||||
pform_cur_module->add_task(name, task);
|
||||
}
|
||||
|
||||
void pform_set_function(const string&name, PFunction *func)
|
||||
/*
|
||||
* This function is called to fill out the definition of the function
|
||||
* with the trappings that are discovered after the basic function
|
||||
* name is parsed.
|
||||
*/
|
||||
void pform_set_function(const string&name, svector<PExpr*>*ra, PFunction *func)
|
||||
{
|
||||
PWire*out = new PWire(name+"."+name, NetNet::REG, NetNet::POUTPUT);
|
||||
if (ra) {
|
||||
assert(ra->count() == 2);
|
||||
out->set_range((*ra)[0], (*ra)[1]);
|
||||
delete ra;
|
||||
}
|
||||
pform_cur_module->add_wire(out);
|
||||
func->set_output(out);
|
||||
pform_cur_module->add_function(name, func);
|
||||
}
|
||||
|
||||
@@ -536,21 +583,26 @@ void pform_set_reg_idx(const string&name, PExpr*l, PExpr*r)
|
||||
{
|
||||
PWire*cur = pform_cur_module->get_wire(name);
|
||||
if (cur == 0) {
|
||||
VLerror("name is not a valid net.");
|
||||
VLerror(" error: name is not a valid net.");
|
||||
return;
|
||||
}
|
||||
|
||||
cur->set_memory_idx(l, r);
|
||||
}
|
||||
|
||||
/*
|
||||
* This function attaches a range to a given name. The function is
|
||||
* only called by the parser within the scope of the net declaration,
|
||||
* and the name that I receive only has the tail component.
|
||||
*/
|
||||
static void pform_set_net_range(const string&name, const svector<PExpr*>*range)
|
||||
{
|
||||
assert(range);
|
||||
assert(range->count() == 2);
|
||||
|
||||
PWire*cur = pform_cur_module->get_wire(name);
|
||||
PWire*cur = pform_cur_module->get_wire(scoped_name(name));
|
||||
if (cur == 0) {
|
||||
VLerror("name is not a valid net.");
|
||||
VLerror(" error: name is not a valid net.");
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -573,6 +625,7 @@ void pform_set_net_range(list<string>*names, const svector<PExpr*>*range)
|
||||
void pform_set_parameter(const string&name, PExpr*expr)
|
||||
{
|
||||
pform_cur_module->parameters[name] = expr;
|
||||
pform_cur_module->param_names.push_back(name);
|
||||
}
|
||||
|
||||
void pform_set_port_type(list<string>*names, NetNet::PortType pt)
|
||||
@@ -584,12 +637,18 @@ void pform_set_port_type(list<string>*names, NetNet::PortType pt)
|
||||
}
|
||||
}
|
||||
|
||||
static void pform_set_reg_integer(const string&name)
|
||||
static void pform_set_reg_integer(const string&nm)
|
||||
{
|
||||
string name = scoped_name(nm);
|
||||
PWire*cur = pform_cur_module->get_wire(name);
|
||||
if (cur == 0) {
|
||||
cur = new PWire(name, NetNet::INTEGER, NetNet::NOT_A_PORT);
|
||||
pform_cur_module->add_wire(cur);
|
||||
} else {
|
||||
bool rc = cur->set_wire_type(NetNet::INTEGER);
|
||||
assert(rc);
|
||||
}
|
||||
assert(cur);
|
||||
bool rc = cur->set_wire_type(NetNet::INTEGER);
|
||||
assert(rc);
|
||||
|
||||
cur->set_range(new PENumber(new verinum(INTEGER_WIDTH-1, INTEGER_WIDTH)),
|
||||
new PENumber(new verinum(0UL, INTEGER_WIDTH)));
|
||||
@@ -634,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;
|
||||
@@ -655,6 +717,37 @@ 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.
|
||||
*
|
||||
* Revision 1.45 1999/09/21 00:58:33 steve
|
||||
* Get scope right when setting the net range.
|
||||
*
|
||||
* Revision 1.44 1999/09/17 02:06:26 steve
|
||||
* Handle unconnected module ports.
|
||||
*
|
||||
* Revision 1.43 1999/09/15 01:55:06 steve
|
||||
* Elaborate non-blocking assignment to memories.
|
||||
*
|
||||
* Revision 1.42 1999/09/10 05:02:09 steve
|
||||
* Handle integers at task parameters.
|
||||
*
|
||||
* Revision 1.41 1999/08/31 22:38:29 steve
|
||||
* Elaborate and emit to vvm procedural functions.
|
||||
*
|
||||
* Revision 1.40 1999/08/27 15:08:37 steve
|
||||
* continuous assignment lists.
|
||||
*
|
||||
* Revision 1.39 1999/08/25 22:22:41 steve
|
||||
* elaborate some aspects of functions.
|
||||
*
|
||||
* Revision 1.38 1999/08/23 16:48:39 steve
|
||||
* Parameter overrides support from Peter Monta
|
||||
* AND and XOR support wide expressions.
|
||||
*
|
||||
* Revision 1.37 1999/08/03 04:14:49 steve
|
||||
* Parse into pform arbitrarily complex module
|
||||
* port declarations.
|
||||
|
||||
@@ -19,7 +19,7 @@
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
|
||||
*/
|
||||
#if !defined(WINNT)
|
||||
#ident "$Id: pform.h,v 1.27 1999/08/03 04:14:49 steve Exp $"
|
||||
#ident "$Id: pform.h,v 1.31 1999/09/10 05:02:09 steve Exp $"
|
||||
#endif
|
||||
|
||||
# include "netlist.h"
|
||||
@@ -121,7 +121,7 @@ extern void pform_set_net_range(list<string>*names, const svector<PExpr*>*);
|
||||
extern void pform_set_reg_idx(const string&name, PExpr*l, PExpr*r);
|
||||
extern void pform_set_reg_integer(list<string>*names);
|
||||
extern void pform_set_task(const string&, PTask*);
|
||||
extern void pform_set_function(const string&, PFunction*);
|
||||
extern void pform_set_function(const string&, svector<PExpr*>*, PFunction*);
|
||||
extern void pform_set_attrib(const string&name, const string&key,
|
||||
const string&value);
|
||||
extern void pform_set_type_attrib(const string&name, const string&key,
|
||||
@@ -141,18 +141,25 @@ extern void pform_makegates(PGBuiltin::Type type,
|
||||
svector<PExpr*>*delay,
|
||||
svector<lgate>*gates);
|
||||
|
||||
extern void pform_make_modgates(const string&type, svector<lgate>*gates);
|
||||
extern void pform_make_modgates(const string&type,
|
||||
svector<PExpr*>*overrides,
|
||||
svector<lgate>*gates);
|
||||
|
||||
/* Make a continuous assignment node, with optional bit- or part- select. */
|
||||
extern PGAssign* pform_make_pgassign(PExpr*lval, PExpr*rval,
|
||||
svector<PExpr*>*delays);
|
||||
|
||||
extern void pform_make_pgassign_list(svector<PExpr*>*alist,
|
||||
svector<PExpr*>*del,
|
||||
const string& text,
|
||||
unsigned lineno);
|
||||
|
||||
/* Given a port type and a list of names, make a list of wires that
|
||||
can be used as task port information. */
|
||||
extern svector<PWire*>*pform_make_task_ports(NetNet::PortType pt,
|
||||
const svector<PExpr*>*range,
|
||||
const list<string>*names);
|
||||
const list<string>*names,
|
||||
const string& file,
|
||||
unsigned lineno);
|
||||
|
||||
|
||||
/*
|
||||
@@ -167,6 +174,19 @@ extern void pform_dump(ostream&out, Module*mod);
|
||||
|
||||
/*
|
||||
* $Log: pform.h,v $
|
||||
* Revision 1.31 1999/09/10 05:02:09 steve
|
||||
* Handle integers at task parameters.
|
||||
*
|
||||
* Revision 1.30 1999/08/27 15:08:37 steve
|
||||
* continuous assignment lists.
|
||||
*
|
||||
* Revision 1.29 1999/08/25 22:22:41 steve
|
||||
* elaborate some aspects of functions.
|
||||
*
|
||||
* Revision 1.28 1999/08/23 16:48:39 steve
|
||||
* Parameter overrides support from Peter Monta
|
||||
* AND and XOR support wide expressions.
|
||||
*
|
||||
* Revision 1.27 1999/08/03 04:14:49 steve
|
||||
* Parse into pform arbitrarily complex module
|
||||
* port declarations.
|
||||
|
||||
+112
-22
@@ -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.34 1999/08/03 04:49:13 steve Exp $"
|
||||
#ident "$Id: pform_dump.cc,v 1.45 1999/10/10 01:59:55 steve Exp $"
|
||||
#endif
|
||||
|
||||
/*
|
||||
@@ -37,6 +37,12 @@ ostream& operator << (ostream&out, const PExpr&obj)
|
||||
return out;
|
||||
}
|
||||
|
||||
ostream& operator << (ostream&o, const PDelays&d)
|
||||
{
|
||||
d.dump_delays(o);
|
||||
return o;
|
||||
}
|
||||
|
||||
void PExpr::dump(ostream&out) const
|
||||
{
|
||||
out << typeid(*this).name();
|
||||
@@ -65,7 +71,7 @@ void PECallFunction::dump(ostream &out) const
|
||||
{
|
||||
out << name_ << "(";
|
||||
parms_[0]->dump(out);
|
||||
for (unsigned idx = 0; idx < parms_.count(); ++idx) {
|
||||
for (unsigned idx = 1; idx < parms_.count(); ++idx) {
|
||||
out << ", ";
|
||||
parms_[idx]->dump(out);
|
||||
}
|
||||
@@ -126,6 +132,9 @@ void PEBinary::dump(ostream&out) const
|
||||
{
|
||||
out << "(" << *left_ << ")";
|
||||
switch (op_) {
|
||||
case 'a':
|
||||
out << "&&";
|
||||
break;
|
||||
case 'e':
|
||||
out << "==";
|
||||
break;
|
||||
@@ -209,7 +218,7 @@ void PGate::dump_pins(ostream&out) const
|
||||
}
|
||||
}
|
||||
|
||||
void PGate::dump_delays(ostream&out) const
|
||||
void PDelays::dump_delays(ostream&out) const
|
||||
{
|
||||
if (delay_[0] && delay_[1] && delay_[2])
|
||||
out << "#(" << *delay_[0] << "," << *delay_[1] << "," <<
|
||||
@@ -221,10 +230,15 @@ void PGate::dump_delays(ostream&out) const
|
||||
|
||||
}
|
||||
|
||||
void PGate::dump_delays(ostream&out) const
|
||||
{
|
||||
delay_.dump_delays(out);
|
||||
}
|
||||
|
||||
void PGate::dump(ostream&out) const
|
||||
{
|
||||
out << " " << typeid(*this).name() << " ";
|
||||
dump_delays(out);
|
||||
delay_.dump_delays(out);
|
||||
out << " " << get_name() << "(";
|
||||
dump_pins(out);
|
||||
out << ");" << endl;
|
||||
@@ -268,12 +282,25 @@ void PGBuiltin::dump(ostream&out) const
|
||||
|
||||
void PGModule::dump(ostream&out) const
|
||||
{
|
||||
out << " " << type_ << " " << get_name() << "(";
|
||||
out << " " << type_ << " ";
|
||||
if (overrides_) {
|
||||
out << "#(";
|
||||
out << *((*overrides_)[0]);
|
||||
for (unsigned idx = 1 ; idx < overrides_->count() ; idx += 1) {
|
||||
out << "," << *((*overrides_)[idx]);
|
||||
}
|
||||
out << ") ";
|
||||
}
|
||||
out << get_name() << "(";
|
||||
if (pins_) {
|
||||
out << "." << pins_[0].name << "(" << *pins_[0].parm << ")";
|
||||
out << "." << pins_[0].name << "(";
|
||||
if (pins_[0].parm) out << *pins_[0].parm;
|
||||
out << ")";
|
||||
for (unsigned idx = 1 ; idx < npins_ ; idx += 1) {
|
||||
out << ", ." << pins_[idx].name << "(" <<
|
||||
*pins_[idx].parm << ")";
|
||||
out << ", ." << pins_[idx].name << "(";
|
||||
if (pins_[idx].parm)
|
||||
out << *pins_[idx].parm;
|
||||
out << ")";
|
||||
}
|
||||
} else {
|
||||
dump_pins(out);
|
||||
@@ -294,18 +321,14 @@ void Statement::dump(ostream&out, unsigned ind) const
|
||||
void PAssign::dump(ostream&out, unsigned ind) const
|
||||
{
|
||||
out << setw(ind) << "";
|
||||
out << *lval() << " = ";
|
||||
if (delay()) out << "#" << *delay() << " ";
|
||||
out << *rval() << ";";
|
||||
out << *lval() << " = " << delay_ << " " << *rval() << ";";
|
||||
out << " /* " << get_line() << " */" << endl;
|
||||
}
|
||||
|
||||
void PAssignNB::dump(ostream&out, unsigned ind) const
|
||||
{
|
||||
out << setw(ind) << "";
|
||||
out << *lval() << " <= ";
|
||||
if (delay()) out << "#" << *delay() << " ";
|
||||
out << *rval() << ";";
|
||||
out << *lval() << " <= " << delay_ << " " << *rval() << ";";
|
||||
out << " /* " << get_line() << " */" << endl;
|
||||
}
|
||||
|
||||
@@ -317,7 +340,10 @@ void PBlock::dump(ostream&out, unsigned ind) const
|
||||
out << endl;
|
||||
|
||||
for (unsigned idx = 0 ; idx < list_.count() ; idx += 1) {
|
||||
list_[idx]->dump(out, ind+2);
|
||||
if (list_[idx])
|
||||
list_[idx]->dump(out, ind+2);
|
||||
else
|
||||
out << setw(ind+2) << "" << "/* NOOP */ ;" << endl;
|
||||
}
|
||||
|
||||
out << setw(ind) << "" << "end" << endl;
|
||||
@@ -345,8 +371,19 @@ void PCallTask::dump(ostream&out, unsigned ind) const
|
||||
|
||||
void PCase::dump(ostream&out, unsigned ind) const
|
||||
{
|
||||
out << setw(ind) << "" << "case (" << *expr_ << ") /* " <<
|
||||
get_line() << " */" << endl;
|
||||
out << setw(ind) << "";
|
||||
switch (type_) {
|
||||
case NetCase::EQ:
|
||||
out << "case";
|
||||
break;
|
||||
case NetCase::EQX:
|
||||
out << "casex";
|
||||
break;
|
||||
case NetCase::EQZ:
|
||||
out << "casez";
|
||||
break;
|
||||
}
|
||||
out << " (" << *expr_ << ") /* " << get_line() << " */" << endl;
|
||||
|
||||
for (unsigned idx = 0 ; idx < items_->count() ; idx += 1) {
|
||||
PCase::Item*cur = (*items_)[idx];
|
||||
@@ -377,7 +414,10 @@ void PCase::dump(ostream&out, unsigned ind) const
|
||||
void PCondit::dump(ostream&out, unsigned ind) const
|
||||
{
|
||||
out << setw(ind) << "" << "if (" << *expr_ << ")" << endl;
|
||||
if_->dump(out, ind+3);
|
||||
if (if_)
|
||||
if_->dump(out, ind+3);
|
||||
else
|
||||
out << setw(ind) << ";" << endl;
|
||||
if (else_) {
|
||||
out << setw(ind) << "" << "else" << endl;
|
||||
else_->dump(out, ind+3);
|
||||
@@ -430,13 +470,17 @@ void PForStatement::dump(ostream&out, unsigned ind) const
|
||||
|
||||
void PFunction::dump(ostream&out, unsigned ind) const
|
||||
{
|
||||
out << setw(ind) << "" << "output " << out_->name() << ";" << endl;
|
||||
for (unsigned idx = 0 ; idx < ports_->count() ; idx += 1) {
|
||||
out << setw(ind) << "";
|
||||
out << "input ";
|
||||
out << (*ports_)[idx]->name() << ";" << endl;
|
||||
}
|
||||
|
||||
statement_->dump(out, ind);
|
||||
if (statement_)
|
||||
statement_->dump(out, ind);
|
||||
else
|
||||
out << setw(ind) << "" << "/* NOOP */" << endl;
|
||||
}
|
||||
|
||||
void PRepeat::dump(ostream&out, unsigned ind) const
|
||||
@@ -464,7 +508,10 @@ void PTask::dump(ostream&out, unsigned ind) const
|
||||
out << (*ports_)[idx]->name() << ";" << endl;
|
||||
}
|
||||
|
||||
statement_->dump(out, ind);
|
||||
if (statement_)
|
||||
statement_->dump(out, ind);
|
||||
else
|
||||
out << setw(ind) << "" << "/* NOOP */" << endl;
|
||||
}
|
||||
|
||||
|
||||
@@ -496,6 +543,12 @@ void Module::dump(ostream&out) const
|
||||
|
||||
for (unsigned idx = 0 ; idx < ports_.count() ; idx += 1) {
|
||||
port_t*cur = ports_[idx];
|
||||
|
||||
if (cur == 0) {
|
||||
out << " unconnected" << endl;
|
||||
continue;
|
||||
}
|
||||
|
||||
switch (cur->wires[0]->get_port_type()) {
|
||||
case NetNet::PINPUT:
|
||||
out << " input ." << cur->name << "(";
|
||||
@@ -522,8 +575,11 @@ void Module::dump(ostream&out) const
|
||||
typedef map<string,PExpr*>::const_iterator parm_iter_t;
|
||||
for (parm_iter_t cur = parameters.begin()
|
||||
; cur != parameters.end() ; cur ++) {
|
||||
out << " parameter " << (*cur).first << " = " <<
|
||||
*(*cur).second << ";" << endl;
|
||||
out << " parameter " << (*cur).first << " = ";
|
||||
if ((*cur).second)
|
||||
out << *(*cur).second << ";" << endl;
|
||||
else
|
||||
out << "/* ERROR */;" << endl;
|
||||
}
|
||||
|
||||
// Iterate through and display all the wires.
|
||||
@@ -619,6 +675,40 @@ 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.
|
||||
*
|
||||
* Revision 1.43 1999/09/30 00:48:50 steve
|
||||
* Cope with errors during ternary operator elaboration.
|
||||
*
|
||||
* Revision 1.42 1999/09/29 21:15:58 steve
|
||||
* Handle some mor missing names.
|
||||
*
|
||||
* Revision 1.41 1999/09/29 20:23:53 steve
|
||||
* Handle empty named ports in the dump.
|
||||
*
|
||||
* Revision 1.40 1999/09/29 18:36:04 steve
|
||||
* Full case support
|
||||
*
|
||||
* Revision 1.39 1999/09/17 02:06:26 steve
|
||||
* Handle unconnected module ports.
|
||||
*
|
||||
* Revision 1.38 1999/09/08 02:24:39 steve
|
||||
* Empty conditionals (pmonta@imedia.com)
|
||||
*
|
||||
* Revision 1.37 1999/09/04 19:11:46 steve
|
||||
* Add support for delayed non-blocking assignments.
|
||||
*
|
||||
* Revision 1.36 1999/08/25 22:22:41 steve
|
||||
* elaborate some aspects of functions.
|
||||
*
|
||||
* Revision 1.35 1999/08/23 16:48:39 steve
|
||||
* Parameter overrides support from Peter Monta
|
||||
* AND and XOR support wide expressions.
|
||||
*
|
||||
* Revision 1.34 1999/08/03 04:49:13 steve
|
||||
* Proper port type names.
|
||||
*
|
||||
|
||||
+280
@@ -0,0 +1,280 @@
|
||||
/*
|
||||
* 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: set_width.cc,v 1.6 1999/10/05 06:19:46 steve Exp $"
|
||||
#endif
|
||||
|
||||
/*
|
||||
* This file contains set_width methods for the various NetExpr
|
||||
* classes. The set_width method is used by elaboration to ask the
|
||||
* expression to resize itself. If the expression can't, then the
|
||||
* set_width method will return false and the caller will arrange for
|
||||
* whatever is needed to deal with the size mismatch.
|
||||
*/
|
||||
# include "netlist.h"
|
||||
# include "netmisc.h"
|
||||
# include <typeinfo>
|
||||
|
||||
|
||||
bool NetExpr::set_width(unsigned w)
|
||||
{
|
||||
cerr << typeid(*this).name() << ": set_width(unsigned) "
|
||||
"not implemented." << endl;
|
||||
expr_width(w);
|
||||
return false;
|
||||
}
|
||||
|
||||
bool NetEBinary::set_width(unsigned w)
|
||||
{
|
||||
bool flag = true;
|
||||
switch (op_) {
|
||||
|
||||
case 'l': // left shift (<<)
|
||||
case 'r': // right shift (>>)
|
||||
flag = left_->set_width(w);
|
||||
expr_width(w);
|
||||
break;
|
||||
|
||||
/* The default rule is that the operands of the binary
|
||||
operator might as well use the same width as the
|
||||
output from the binary operation. */
|
||||
default:
|
||||
expr_width(left_->expr_width() > right_->expr_width()
|
||||
? left_->expr_width() : right_->expr_width());
|
||||
cerr << "NetEBinary::set_width(): Using default for " <<
|
||||
op_ << "." << endl;
|
||||
flag = false;
|
||||
|
||||
case '%':
|
||||
case '/':
|
||||
flag = left_->set_width(w) && flag;
|
||||
flag = right_->set_width(w) && flag;
|
||||
expr_width(w);
|
||||
break;
|
||||
}
|
||||
return flag;
|
||||
}
|
||||
|
||||
/*
|
||||
* The bitwise logical operators have operands the same size as the
|
||||
* result. Anything else is a mess.
|
||||
*/
|
||||
bool NetEBAdd::set_width(unsigned w)
|
||||
{
|
||||
|
||||
unsigned wid = w;
|
||||
if (left_->expr_width() > wid)
|
||||
wid = left_->expr_width();
|
||||
if (right_->expr_width() > wid)
|
||||
wid = right_->expr_width();
|
||||
|
||||
left_->set_width(wid);
|
||||
right_->set_width(wid);
|
||||
|
||||
if (left_->expr_width() < wid) {
|
||||
NetExpr*tmp = pad_to_width(left_, wid);
|
||||
assert(tmp);
|
||||
left_ = tmp;
|
||||
}
|
||||
|
||||
if (right_->expr_width() < wid) {
|
||||
NetExpr*tmp = pad_to_width(right_, wid);
|
||||
assert(tmp);
|
||||
right_ = tmp;
|
||||
}
|
||||
|
||||
expr_width(wid);
|
||||
return wid == w;
|
||||
}
|
||||
|
||||
/*
|
||||
* The bitwise logical operators have operands the same size as the
|
||||
* result. Anything else is a mess.
|
||||
*/
|
||||
bool NetEBBits::set_width(unsigned w)
|
||||
{
|
||||
bool flag = true;
|
||||
|
||||
flag = left_->set_width(w) && flag;
|
||||
flag = right_->set_width(w) && flag;
|
||||
if (flag)
|
||||
expr_width(w);
|
||||
|
||||
return flag;
|
||||
}
|
||||
|
||||
/*
|
||||
* Comparison operators allow the subexpressions to have
|
||||
* their own natural width, but the comparison operator result has a
|
||||
* fixed width of 1.
|
||||
*/
|
||||
bool NetEBComp::set_width(unsigned w)
|
||||
{
|
||||
bool flag = true;
|
||||
return (w == 1);
|
||||
}
|
||||
|
||||
bool NetEBLogic::set_width(unsigned w)
|
||||
{
|
||||
bool flag;
|
||||
flag = left_->set_width(right_->expr_width());
|
||||
if (!flag)
|
||||
flag = right_->set_width(left_->expr_width());
|
||||
return (w == 1);
|
||||
}
|
||||
|
||||
/*
|
||||
* The shift operator allows the shift amount to have its own
|
||||
* natural width. The width of the operator result is the width of the
|
||||
* left operand, the value that is to be shifted.
|
||||
*/
|
||||
bool NetEBShift::set_width(unsigned w)
|
||||
{
|
||||
bool flag;
|
||||
flag = left_->set_width(w);
|
||||
return flag;
|
||||
}
|
||||
|
||||
/*
|
||||
* Add up the widths from all the expressions that are concatenated
|
||||
* together. This is the width of the expression, tough luck if you
|
||||
* want it otherwise.
|
||||
*
|
||||
* If during the course of elaboration one of the sub-expressions is
|
||||
* broken, then don't count it in the width. This doesn't really
|
||||
* matter because the null expression is indication of an error and
|
||||
* the compiler will not go beyond elaboration.
|
||||
*/
|
||||
bool NetEConcat::set_width(unsigned w)
|
||||
{
|
||||
unsigned sum = 0;
|
||||
for (unsigned idx = 0 ; idx < parms_.count() ; idx += 1)
|
||||
if (parms_[idx] != 0)
|
||||
sum += parms_[idx]->expr_width();
|
||||
|
||||
sum *= repeat_;
|
||||
expr_width(sum);
|
||||
if (sum != w) return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool NetEConst::set_width(unsigned w)
|
||||
{
|
||||
if (w > value_.len())
|
||||
return false;
|
||||
|
||||
assert(w <= value_.len());
|
||||
value_ = verinum(value_, w);
|
||||
expr_width(w);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool NetEMemory::set_width(unsigned w)
|
||||
{
|
||||
if (w != mem_->width())
|
||||
return false;
|
||||
|
||||
expr_width(w);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool NetEParam::set_width(unsigned)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
/*
|
||||
* The signal should automatically pad with zeros to get to th desired
|
||||
* width. Do not allow signal bits to be truncated, however.
|
||||
*/
|
||||
bool NetESignal::set_width(unsigned w)
|
||||
{
|
||||
if (w != pin_count())
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool NetESubSignal::set_width(unsigned w)
|
||||
{
|
||||
if (w != 1) return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool NetETernary::set_width(unsigned w)
|
||||
{
|
||||
bool flag = true;
|
||||
flag = flag && true_val_->set_width(w);
|
||||
flag = flag && false_val_->set_width(w);
|
||||
expr_width(true_val_->expr_width());
|
||||
return flag;
|
||||
}
|
||||
|
||||
/*
|
||||
* XXXX FIX ME: For now, just take whatever the caller says as my
|
||||
* width. What I really need to do is note the width of the output
|
||||
* parameter of the function definition and take that into account.
|
||||
*/
|
||||
bool NetEUFunc::set_width(unsigned wid)
|
||||
{
|
||||
expr_width(wid);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool NetEUnary::set_width(unsigned w)
|
||||
{
|
||||
bool flag = true;
|
||||
switch (op_) {
|
||||
case '~':
|
||||
case '-':
|
||||
flag = expr_->set_width(w);
|
||||
break;
|
||||
default:
|
||||
flag = expr_width() == w;
|
||||
break;
|
||||
}
|
||||
expr_width(w);
|
||||
return flag;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* $Log: set_width.cc,v $
|
||||
* Revision 1.6 1999/10/05 06:19:46 steve
|
||||
* Add support for reduction NOR.
|
||||
*
|
||||
* Revision 1.5 1999/10/05 04:02:10 steve
|
||||
* Relaxed width handling for <= assignment.
|
||||
*
|
||||
* Revision 1.4 1999/09/29 00:42:51 steve
|
||||
* Allow expanding of additive operators.
|
||||
*
|
||||
* Revision 1.3 1999/09/23 03:56:57 steve
|
||||
* Support shift operators.
|
||||
*
|
||||
* Revision 1.2 1999/09/23 02:27:50 steve
|
||||
* comparison parameter width is self determined.
|
||||
*
|
||||
* Revision 1.1 1999/09/23 00:21:55 steve
|
||||
* Move set_width methods into a single file,
|
||||
* Add the NetEBLogic class for logic expressions,
|
||||
* Fix error setting with of && in if statements.
|
||||
*
|
||||
*/
|
||||
|
||||
+23
-2
@@ -17,7 +17,7 @@
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
|
||||
*/
|
||||
#if !defined(WINNT)
|
||||
#ident "$Id: sigfold.cc,v 1.2 1998/12/02 04:37:13 steve Exp $"
|
||||
#ident "$Id: sigfold.cc,v 1.3 1999/11/06 04:51:11 steve Exp $"
|
||||
#endif
|
||||
|
||||
# include "netlist.h"
|
||||
@@ -83,6 +83,24 @@ static void clear_extra_signals(NetNet*net, unsigned npin)
|
||||
continue;
|
||||
}
|
||||
|
||||
if (NetTmp*tmp = dynamic_cast<NetTmp*>(sig)) {
|
||||
cerr << "internal warning: sigfold found NetTmp--"
|
||||
"deleting it." << endl;
|
||||
|
||||
// save the next link, ...
|
||||
NetObj*nxt;
|
||||
unsigned pnxt;
|
||||
cur->pin(pin).next_link(nxt, pnxt);
|
||||
|
||||
// disconnect the target signal, ...
|
||||
sig->pin(pin).unlink();
|
||||
|
||||
// And onward.
|
||||
cur = nxt;
|
||||
pin = pnxt;
|
||||
continue;
|
||||
}
|
||||
|
||||
// Skip the node if it has incompatible attributes.
|
||||
if (! net->has_compat_attributes(*sig)) {
|
||||
|
||||
@@ -152,10 +170,13 @@ void sigfold(Design*des)
|
||||
|
||||
/*
|
||||
* $Log: sigfold.cc,v $
|
||||
* Revision 1.3 1999/11/06 04:51:11 steve
|
||||
* Catch NetTmp objects.
|
||||
*
|
||||
* Revision 1.2 1998/12/02 04:37:13 steve
|
||||
* Add the nobufz function to eliminate bufz objects,
|
||||
* Object links are marked with direction,
|
||||
* constant propagation is more careful will wide links,
|
||||
* constant propagation is more careful with wide links,
|
||||
* Signal folding is aware of attributes, and
|
||||
* the XNF target can dump UDP objects based on LCA
|
||||
* attributes.
|
||||
|
||||
@@ -0,0 +1,210 @@
|
||||
/*
|
||||
* Copyright (c) 1999 Stephen Williams (steve@icarus.com)
|
||||
*
|
||||
* This source code is free software; you can redistribute it
|
||||
* and/or modify it in source code form under the terms of the GNU
|
||||
* General Public License as published by the Free Software
|
||||
* Foundation; either version 2 of the License, or (at your option)
|
||||
* any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
|
||||
*/
|
||||
#if !defined(WINNT)
|
||||
#ident "$Id: synth.cc,v 1.3 1999/12/01 06:06:16 steve Exp $"
|
||||
#endif
|
||||
|
||||
/*
|
||||
* The synth function searches the behavioral description for
|
||||
* patterns that are known to represent LPM library components. This
|
||||
* is especially interesting for the sequential components such as
|
||||
* flip flops and latches. As threads are transformed into components,
|
||||
* the design is rewritten.
|
||||
*/
|
||||
# include "functor.h"
|
||||
# include "netlist.h"
|
||||
|
||||
/*
|
||||
* This transform recognizes the following patterns:
|
||||
*
|
||||
* always @(posedge CLK) Q = D
|
||||
* always @(negedge CLK) Q = D
|
||||
*
|
||||
* always @(posedge CLK) if (CE) Q = D;
|
||||
* always @(negedge CLK) if (CE) Q = D;
|
||||
*
|
||||
* The r-value of the assignments must be identifiers (i.e. wires or
|
||||
* registers) and the CE must be single-bit identifiers. The generated
|
||||
* device will be wide enough to accomodate Q and D.
|
||||
*/
|
||||
class match_dff : public proc_match_t {
|
||||
|
||||
public:
|
||||
match_dff(Design*d, NetProcTop*t)
|
||||
: des_(d), top_(t), pclk_(0), nclk_(0), con_(0), ce_(0),
|
||||
asn_(0), d_(0)
|
||||
{ }
|
||||
|
||||
~match_dff() { }
|
||||
|
||||
void make_it();
|
||||
|
||||
private:
|
||||
virtual int assign(NetAssign*);
|
||||
virtual int condit(NetCondit*);
|
||||
virtual int pevent(NetPEvent*);
|
||||
|
||||
Design*des_;
|
||||
NetProcTop*top_;
|
||||
NetPEvent*pclk_;
|
||||
NetNEvent*nclk_;
|
||||
|
||||
NetCondit *con_;
|
||||
NetNet*ce_;
|
||||
NetAssign *asn_;
|
||||
|
||||
NetNet*d_;
|
||||
};
|
||||
|
||||
int match_dff::assign(NetAssign*as)
|
||||
{
|
||||
if (!pclk_)
|
||||
return 0;
|
||||
if (asn_)
|
||||
return 0;
|
||||
|
||||
asn_ = as;
|
||||
d_ = asn_->rval()->synthesize(des_);
|
||||
if (d_ == 0)
|
||||
return 0;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int match_dff::condit(NetCondit*co)
|
||||
{
|
||||
if (!pclk_)
|
||||
return 0;
|
||||
if (con_ || asn_)
|
||||
return 0;
|
||||
|
||||
con_ = co;
|
||||
if (con_->else_clause())
|
||||
return 0;
|
||||
ce_ = con_->expr()->synthesize(des_);
|
||||
if (ce_ == 0)
|
||||
return 0;
|
||||
|
||||
return con_->if_clause()->match_proc(this);
|
||||
}
|
||||
|
||||
int match_dff::pevent(NetPEvent*pe)
|
||||
{
|
||||
if (pclk_ || con_ || asn_)
|
||||
return 0;
|
||||
|
||||
pclk_ = pe;
|
||||
|
||||
// ... there must be a single event source, ...
|
||||
svector<class NetNEvent*>*neb = pclk_->back_list();
|
||||
if (neb == 0)
|
||||
return 0;
|
||||
if (neb->count() != 1) {
|
||||
delete neb;
|
||||
return 0;
|
||||
}
|
||||
nclk_ = (*neb)[0];
|
||||
delete neb;
|
||||
return pclk_->statement()->match_proc(this);
|
||||
}
|
||||
|
||||
void match_dff::make_it()
|
||||
{
|
||||
NetFF*ff = new NetFF(asn_->name(), asn_->pin_count());
|
||||
|
||||
for (unsigned idx = 0 ; idx < ff->width() ; idx += 1) {
|
||||
connect(ff->pin_Data(idx), d_->pin(idx));
|
||||
connect(ff->pin_Q(idx), asn_->pin(idx));
|
||||
}
|
||||
|
||||
connect(ff->pin_Clock(), nclk_->pin(0));
|
||||
if (ce_) connect(ff->pin_Enable(), ce_->pin(0));
|
||||
|
||||
ff->attribute("LPM_FFType", "DFF");
|
||||
if (nclk_->type() == NetNEvent::NEGEDGE)
|
||||
ff->attribute("Clock:LPM_Polarity", "INVERT");
|
||||
|
||||
des_->add_node(ff);
|
||||
}
|
||||
|
||||
class synth_f : public functor_t {
|
||||
|
||||
public:
|
||||
void process(class Design*, class NetProcTop*);
|
||||
|
||||
private:
|
||||
void proc_always_(class Design*);
|
||||
|
||||
NetProcTop*top_;
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
* Look at a process, and divide the problem into always and initial
|
||||
* threads.
|
||||
*/
|
||||
void synth_f::process(class Design*des, class NetProcTop*top)
|
||||
{
|
||||
switch (top->type()) {
|
||||
case NetProcTop::KALWAYS:
|
||||
top_ = top;
|
||||
proc_always_(des);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* An "always ..." statement has been found.
|
||||
*/
|
||||
void synth_f::proc_always_(class Design*des)
|
||||
{
|
||||
match_dff dff_pat(des, top_);
|
||||
if (top_->statement()->match_proc(&dff_pat)) {
|
||||
dff_pat.make_it();
|
||||
des->delete_process(top_);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void synth(Design*des)
|
||||
{
|
||||
synth_f synth_obj;
|
||||
des->functor(&synth_obj);
|
||||
}
|
||||
|
||||
/*
|
||||
* $Log: synth.cc,v $
|
||||
* Revision 1.3 1999/12/01 06:06:16 steve
|
||||
* Redo synth to use match_proc_t scanner.
|
||||
*
|
||||
* Revision 1.2 1999/11/02 04:55:34 steve
|
||||
* Add the synthesize method to NetExpr to handle
|
||||
* synthesis of expressions, and use that method
|
||||
* to improve r-value handling of LPM_FF synthesis.
|
||||
*
|
||||
* Modify the XNF target to handle LPM_FF objects.
|
||||
*
|
||||
* Revision 1.1 1999/11/01 02:07:41 steve
|
||||
* Add the synth functor to do generic synthesis
|
||||
* and add the LPM_FF device to handle rows of
|
||||
* flip-flops.
|
||||
*
|
||||
*/
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
|
||||
*/
|
||||
#if !defined(WINNT)
|
||||
#ident "$Id: t-null.cc,v 1.4 1999/07/03 02:12:52 steve Exp $"
|
||||
#ident "$Id: t-null.cc,v 1.8 1999/10/05 03:26:37 steve Exp $"
|
||||
#endif
|
||||
|
||||
# include "netlist.h"
|
||||
@@ -33,19 +33,36 @@ static class target_null_t : public target_t {
|
||||
void bufz(ostream&os, const NetBUFZ*) { }
|
||||
void memory(ostream&, const NetMemory*) { }
|
||||
void task_def(ostream&, const NetTaskDef*) { }
|
||||
void net_assign(ostream&os, const NetAssign*) { }
|
||||
void net_assign_nb(ostream&os, const NetAssignNB*) { }
|
||||
void net_esignal(ostream&, const NetESignal*) { }
|
||||
void net_event(ostream&, const NetNEvent*) { }
|
||||
void proc_block(ostream&, const NetBlock*) { }
|
||||
bool proc_block(ostream&, const NetBlock*) { return true; }
|
||||
void proc_condit(ostream&, const NetCondit*) { }
|
||||
void proc_delay(ostream&, const NetPDelay*) { }
|
||||
void proc_event(ostream&, const NetPEvent*) { }
|
||||
void proc_forever(ostream&, const NetForever*) { }
|
||||
void proc_repeat(ostream&, const NetRepeat*) { }
|
||||
void proc_stask(ostream&, const NetSTask*) { }
|
||||
void proc_utask(ostream&os, const NetUTask*) { }
|
||||
|
||||
} target_null_obj;
|
||||
|
||||
extern const struct target tgt_null = { "null", &target_null_obj };
|
||||
/*
|
||||
* $Log: t-null.cc,v $
|
||||
* Revision 1.8 1999/10/05 03:26:37 steve
|
||||
* null target ignore assignment nodes.
|
||||
*
|
||||
* Revision 1.7 1999/09/30 21:27:29 steve
|
||||
* Ignore user task definitions.
|
||||
*
|
||||
* Revision 1.6 1999/09/22 16:57:24 steve
|
||||
* Catch parallel blocks in vvm emit.
|
||||
*
|
||||
* Revision 1.5 1999/09/17 02:06:26 steve
|
||||
* Handle unconnected module ports.
|
||||
*
|
||||
* Revision 1.4 1999/07/03 02:12:52 steve
|
||||
* Elaborate user defined tasks.
|
||||
*
|
||||
|
||||
+7
-3
@@ -17,7 +17,7 @@
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
|
||||
*/
|
||||
#if !defined(WINNT)
|
||||
#ident "$Id: t-verilog.cc,v 1.7 1999/08/01 16:34:50 steve Exp $"
|
||||
#ident "$Id: t-verilog.cc,v 1.8 1999/09/22 16:57:24 steve Exp $"
|
||||
#endif
|
||||
|
||||
/*
|
||||
@@ -43,7 +43,7 @@ class target_verilog : public target_t {
|
||||
virtual void logic(ostream&os, const NetLogic*);
|
||||
virtual void bufz(ostream&os, const NetBUFZ*);
|
||||
virtual void start_process(ostream&os, const NetProcTop*);
|
||||
virtual void proc_block(ostream&os, const NetBlock*);
|
||||
virtual bool proc_block(ostream&os, const NetBlock*);
|
||||
virtual void proc_delay(ostream&os, const NetPDelay*);
|
||||
virtual void proc_event(ostream&os, const NetPEvent*);
|
||||
virtual void proc_stask(ostream&os, const NetSTask*);
|
||||
@@ -173,13 +173,14 @@ void target_verilog::emit_expr_(ostream&os, const NetExpr*expr)
|
||||
}
|
||||
}
|
||||
|
||||
void target_verilog::proc_block(ostream&os, const NetBlock*net)
|
||||
bool target_verilog::proc_block(ostream&os, const NetBlock*net)
|
||||
{
|
||||
os << setw(indent_) << "" << "begin" << endl;
|
||||
indent_ += 4;
|
||||
net->emit_recurse(os, this);
|
||||
indent_ -= 4;
|
||||
os << setw(indent_) << "" << "end" << endl;
|
||||
return true;
|
||||
}
|
||||
|
||||
void target_verilog::proc_delay(ostream&os, const NetPDelay*net)
|
||||
@@ -271,6 +272,9 @@ const struct target tgt_verilog = {
|
||||
|
||||
/*
|
||||
* $Log: t-verilog.cc,v $
|
||||
* Revision 1.8 1999/09/22 16:57:24 steve
|
||||
* Catch parallel blocks in vvm emit.
|
||||
*
|
||||
* Revision 1.7 1999/08/01 16:34:50 steve
|
||||
* Parse and elaborate rise/fall/decay times
|
||||
* for gates, and handle the rules for partial
|
||||
|
||||
@@ -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.7 1999/07/17 03:39:11 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,19 +78,33 @@ 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_;
|
||||
};
|
||||
|
||||
/*
|
||||
* This function takes a signal name and mangles it into an equivilent
|
||||
* This function takes a signal name and mangles it into an equivalent
|
||||
* name that is suitable to the XNF format.
|
||||
*/
|
||||
string target_xnf::mangle(const string&name)
|
||||
@@ -101,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)
|
||||
{
|
||||
@@ -121,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)
|
||||
@@ -166,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)
|
||||
@@ -251,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;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -313,6 +618,21 @@ void target_xnf::logic(ostream&os, const NetLogic*net)
|
||||
os << "END" << endl;
|
||||
}
|
||||
|
||||
void target_xnf::bufz(ostream&os, const NetBUFZ*net)
|
||||
{
|
||||
static int warned_once=0;
|
||||
if (!warned_once) {
|
||||
cerr << "Warning: BUFZ object found for xnf output."
|
||||
" Try -Fnobufz." << endl;
|
||||
warned_once=1;
|
||||
}
|
||||
os << "SYM, " << mangle(net->name()) << ", BUF, LIBVER=2.0.0" << endl;
|
||||
assert(net->pin_count() == 2);
|
||||
draw_pin(os, "O", net->pin(0));
|
||||
draw_pin(os, "I", net->pin(1));
|
||||
os << "END" << endl;
|
||||
}
|
||||
|
||||
void target_xnf::udp(ostream&os, const NetUDP*net)
|
||||
{
|
||||
string lca = net->attribute("XNF-LCA");
|
||||
@@ -333,6 +653,60 @@ 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.
|
||||
*
|
||||
* Revision 1.8 1999/08/18 04:00:02 steve
|
||||
* Fixup spelling and some error messages. <LRDoolittle@lbl.gov>
|
||||
*
|
||||
* Revision 1.7 1999/07/17 03:39:11 steve
|
||||
* simplified process scan for targets.
|
||||
*
|
||||
|
||||
@@ -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.15 1999/07/17 19:51:00 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*)
|
||||
{
|
||||
}
|
||||
@@ -41,6 +45,12 @@ void target_t::memory(ostream&os, const NetMemory*)
|
||||
"Unhandled memory." << endl;
|
||||
}
|
||||
|
||||
void target_t::func_def(ostream&os, const NetFuncDef*)
|
||||
{
|
||||
cerr << "target (" << typeid(*this).name() << "): "
|
||||
"Unhandled function definition." << endl;
|
||||
}
|
||||
|
||||
void target_t::task_def(ostream&os, const NetTaskDef*)
|
||||
{
|
||||
cerr << "target (" << typeid(*this).name() << "): "
|
||||
@@ -63,6 +73,42 @@ void target_t::udp(ostream&os, const NetUDP*)
|
||||
"Unhandled UDP." << endl;
|
||||
}
|
||||
|
||||
void target_t::lpm_add_sub(ostream&, const NetAddSub*)
|
||||
{
|
||||
cerr << "target (" << typeid(*this).name() << "): "
|
||||
"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*)
|
||||
{
|
||||
}
|
||||
@@ -73,27 +119,28 @@ 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*)
|
||||
{
|
||||
cerr << "target (" << typeid(*this).name() << "): "
|
||||
"Unhandled Expression Signal node." << endl;
|
||||
}
|
||||
|
||||
void target_t::net_event(ostream&os, const NetNEvent*)
|
||||
void target_t::net_event(ostream&os, const NetNEvent*net)
|
||||
{
|
||||
cerr << "target (" << typeid(*this).name() << "): "
|
||||
"Unhandled EVENT net node." << endl;
|
||||
net->dump_node(cerr, 4);
|
||||
}
|
||||
|
||||
void target_t::process(ostream&os, const NetProcTop*top)
|
||||
bool target_t::process(ostream&os, const NetProcTop*top)
|
||||
{
|
||||
top->statement()->emit_proc(os, this);
|
||||
return top->statement()->emit_proc(os, this);
|
||||
}
|
||||
|
||||
void target_t::proc_assign(ostream&os, const NetAssign*)
|
||||
@@ -114,10 +161,17 @@ void target_t::proc_assign_nb(ostream&os, const NetAssignNB*)
|
||||
"Unhandled non-blocking assignment." << endl;
|
||||
}
|
||||
|
||||
void target_t::proc_block(ostream&os, const NetBlock*)
|
||||
void target_t::proc_assign_mem_nb(ostream&os, const NetAssignMemNB*)
|
||||
{
|
||||
cerr << "target (" << typeid(*this).name() << "): "
|
||||
"Unhandled non-blocking memory assignment." << endl;
|
||||
}
|
||||
|
||||
bool target_t::proc_block(ostream&os, const NetBlock*)
|
||||
{
|
||||
cerr << "target (" << typeid(*this).name() << "): "
|
||||
"Unhandled proc_block." << endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
void target_t::proc_case(ostream&os, const NetCase*cur)
|
||||
@@ -140,10 +194,11 @@ void target_t::proc_delay(ostream&os, const NetPDelay*)
|
||||
"Unhandled proc_delay." << endl;
|
||||
}
|
||||
|
||||
void target_t::proc_event(ostream&os, const NetPEvent*)
|
||||
void target_t::proc_event(ostream&os, const NetPEvent*net)
|
||||
{
|
||||
cerr << "target (" << typeid(*this).name() << "): "
|
||||
"Unhandled proc_event." << endl;
|
||||
net->dump(cerr, 4);
|
||||
}
|
||||
|
||||
void target_t::proc_forever(ostream&os, const NetForever*)
|
||||
@@ -209,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() << "): "
|
||||
@@ -227,6 +288,12 @@ void expr_scan_t::expr_ternary(const NetETernary*)
|
||||
"unhandled expr_ternary." << endl;
|
||||
}
|
||||
|
||||
void expr_scan_t::expr_ufunc(const NetEUFunc*)
|
||||
{
|
||||
cerr << "expr_scan_t (" << typeid(*this).name() << "): "
|
||||
"unhandled function call." << endl;
|
||||
}
|
||||
|
||||
void expr_scan_t::expr_unary(const NetEUnary*)
|
||||
{
|
||||
cerr << "expr_scan_t (" << typeid(*this).name() << "): "
|
||||
@@ -241,6 +308,57 @@ 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.
|
||||
*
|
||||
* Revision 1.19 1999/09/15 01:55:06 steve
|
||||
* Elaborate non-blocking assignment to memories.
|
||||
*
|
||||
* Revision 1.18 1999/09/03 04:28:38 steve
|
||||
* elaborate the binary plus operator.
|
||||
*
|
||||
* Revision 1.17 1999/08/31 22:38:29 steve
|
||||
* Elaborate and emit to vvm procedural functions.
|
||||
*
|
||||
* Revision 1.16 1999/08/18 04:00:02 steve
|
||||
* Fixup spelling and some error messages. <LRDoolittle@lbl.gov>
|
||||
*
|
||||
* Revision 1.15 1999/07/17 19:51:00 steve
|
||||
* netlist support for ternary operator.
|
||||
*
|
||||
|
||||
@@ -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.15 1999/07/17 19:51:00 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*);
|
||||
|
||||
@@ -63,6 +67,15 @@ struct target_t {
|
||||
|
||||
/* Output a defined task. */
|
||||
virtual void task_def(ostream&, const NetTaskDef*);
|
||||
virtual void func_def(ostream&, const NetFuncDef*);
|
||||
|
||||
/* 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*);
|
||||
@@ -70,19 +83,20 @@ 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
|
||||
target to recurse if desired. */
|
||||
virtual void process(ostream&os, const NetProcTop*);
|
||||
virtual bool process(ostream&os, const NetProcTop*);
|
||||
|
||||
/* Various kinds of process nodes are dispatched through these. */
|
||||
virtual void proc_assign(ostream&os, const NetAssign*);
|
||||
virtual void proc_assign_mem(ostream&os, const NetAssignMem*);
|
||||
virtual void proc_assign_nb(ostream&os, const NetAssignNB*);
|
||||
virtual void proc_block(ostream&os, const NetBlock*);
|
||||
virtual void proc_assign_mem_nb(ostream&os, const NetAssignMemNB*);
|
||||
virtual bool proc_block(ostream&os, const NetBlock*);
|
||||
virtual void proc_case(ostream&os, const NetCase*);
|
||||
virtual void proc_condit(ostream&os, const NetCondit*);
|
||||
virtual void proc_forever(ostream&os, const NetForever*);
|
||||
@@ -106,9 +120,11 @@ 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*);
|
||||
virtual void expr_ufunc(const NetEUFunc*);
|
||||
virtual void expr_unary(const NetEUnary*);
|
||||
virtual void expr_binary(const NetEBinary*);
|
||||
};
|
||||
@@ -117,7 +133,7 @@ struct expr_scan_t {
|
||||
/* The emit functions take a design and emit it to the output stream
|
||||
using the specified target. If the target is given by name, it is
|
||||
located in the target_table and used. */
|
||||
extern void emit(ostream&o, const Design*des, const char*type);
|
||||
extern bool emit(ostream&o, const Design*des, const char*type);
|
||||
|
||||
/* This function takes a fully qualified verilog name (which may have,
|
||||
for example, dots in it) and produces a mangled version that can be
|
||||
@@ -130,6 +146,54 @@ 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.
|
||||
*
|
||||
* Revision 1.18 1999/09/15 01:55:06 steve
|
||||
* Elaborate non-blocking assignment to memories.
|
||||
*
|
||||
* Revision 1.17 1999/09/03 04:28:38 steve
|
||||
* elaborate the binary plus operator.
|
||||
*
|
||||
* Revision 1.16 1999/08/31 22:38:29 steve
|
||||
* Elaborate and emit to vvm procedural functions.
|
||||
*
|
||||
* Revision 1.15 1999/07/17 19:51:00 steve
|
||||
* netlist support for ternary operator.
|
||||
*
|
||||
|
||||
@@ -0,0 +1,86 @@
|
||||
.TH verilog 1 "Septemeber 13th, 1999" Version 19990913
|
||||
.SH NAME
|
||||
verilog - Icarus Verilog Driver
|
||||
.SH SYNOPSIS
|
||||
.B verilog
|
||||
[-Dmacro[=defn]] [-Iincludepath] [-X] [-o outputfilename] [-s topmodule] sourcefile[s]
|
||||
.SH DESCRIPTION
|
||||
.PP
|
||||
\fIverilog\fP is the compiler driver script for compiling Verilog code
|
||||
to either a VVM-format (Verilog Virtual Machine) for simulation or to
|
||||
XNF (Xilinx Netlist Format) to be used in Xilinx FPGA's.
|
||||
|
||||
\fIverilog\fP is just massaging the input switches and then calls
|
||||
the preprocessor (ivlpp), the compiler (ivl) and (optional) the C++
|
||||
compiler.
|
||||
|
||||
Please read the official documentation (very minimal at this point)
|
||||
on how to use \fIivl et al\fP, since this man page just describes the
|
||||
"easy startscript" \fIverilog\fP.
|
||||
|
||||
.SH OPTIONS
|
||||
.l
|
||||
\fIverilog\fP accepts the following options:
|
||||
.TP 8
|
||||
.B -D\fImacro\fP
|
||||
Defines macro \fImacro\fP with the string `1' as its definition.
|
||||
.TP 8
|
||||
.B -D\fImacro=defn\fP
|
||||
Defines macro \fImacro\fP as \fIdefn\fP.
|
||||
.TP 8
|
||||
.B -I\fIincludepath\fP
|
||||
Append path \fIincludepath\fP to list of paths searched for include files.
|
||||
.TP 8
|
||||
.B -X
|
||||
Generate XNF files as output. Default is VVM-format.
|
||||
.TP 8
|
||||
.B -x
|
||||
Executes the generated file directly after compilation.
|
||||
.TP 8
|
||||
.B -o \fIfilename\fP
|
||||
Place output in the file \fIfilename\fP. If not given, \fIverilog\fP tries to
|
||||
make a guess; if the input filename is "hello.v", the output
|
||||
filename will be "hello" (for VVM target) or "hello.xnf" (for XNF target).
|
||||
If several files are given on the command line, the \fIlast\fP filename will
|
||||
be used.
|
||||
.TP 8
|
||||
.B -s \fItopmodule name\fP
|
||||
To explicitly set the module \fIivl\fP will use as a top-level module.
|
||||
|
||||
.SH EXAMPLES
|
||||
These examples assume that you have a Verilog source file called hello.v in
|
||||
the current directory
|
||||
|
||||
To compile hello.v to an executable file called hello:
|
||||
|
||||
verilog hello.v
|
||||
|
||||
To compile hello.v to an executable file called runnable:
|
||||
|
||||
verilog -o runnable hello.v
|
||||
|
||||
To compile hello.v to a file in XNF-format called hello.xnf
|
||||
|
||||
verilog -X hello.v
|
||||
|
||||
|
||||
.SH "ENVIRONMENT"
|
||||
.ta \w'VPI_MODULE_PATH 'u
|
||||
VPI_MODULE_PATH path to PLI modules
|
||||
|
||||
.SH "AUTHORS"
|
||||
.nf
|
||||
.ta \w'verilog 'u
|
||||
verilog Stefan Petersen ([email protected])
|
||||
ivlpp Steve Williams ([email protected])
|
||||
ivl Steve Williams ([email protected])
|
||||
|
||||
.SH SEE ALSO
|
||||
.BR ivlpp (N/A)
|
||||
.BR ivl (N/A)
|
||||
.SH COPYRIGHT
|
||||
.nf
|
||||
Copyright \(co 1999 Stefan Petersen
|
||||
|
||||
This document can be freely redistributed according to the terms of the
|
||||
GNU General Public License version 2.0
|
||||
+131
@@ -0,0 +1,131 @@
|
||||
#!/bin/sh
|
||||
|
||||
# verilog - A wrapper shell script for ivl
|
||||
# Copyright (C) 1999 Stefan Petersen ([email protected])
|
||||
#
|
||||
# This program 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., 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=@libdir@/ivl
|
||||
execIVLPP=${execPath}/ivlpp
|
||||
execIVL=${execPath}/ivl
|
||||
execCpp=@CXX@
|
||||
|
||||
tmpDir=/tmp
|
||||
tmpPPFile=${tmpDir}/ivl$$.pp
|
||||
tmpCCFile=${tmpDir}/ivl$$.cc
|
||||
|
||||
includedir=@includedir@
|
||||
libdir=@libdir@
|
||||
VPIModulePath=@libdir@/ivl
|
||||
|
||||
target="vvm"
|
||||
targetSuffix=""
|
||||
functors=""
|
||||
flags=""
|
||||
|
||||
# If VPI module path aren't set up, warn at least
|
||||
if test -z "${VPI_MODULE_PATH}" ; then
|
||||
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: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) 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 ;;
|
||||
esac
|
||||
|
||||
done
|
||||
|
||||
# The rest is filenames
|
||||
verilogFile=$@;
|
||||
|
||||
if test -z "${verilogFile}" ; then
|
||||
echo "Missing infile";
|
||||
echo "verilog [-Dmacro[=defn]] [-Iincludepath] [-X] [-x] [-o outputfilename] [-s topmodule] sourcefile[s]" ;
|
||||
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
|
||||
if test -z "${outputFile}" ; then
|
||||
outputFile=`echo ${verilogFile} | sed -e 's;.* ;;' | sed -e 's;\..*$;;'`
|
||||
outputFile="${outputFile}${targetSuffix}" ;
|
||||
fi
|
||||
|
||||
# Preprocess
|
||||
${execIVLPP} ${extDefines} ${extIncPath} -L -o ${tmpPPFile} ${verilogFile}
|
||||
if test $? -ne 0 ; then
|
||||
echo "Preprocessing failed. Terminating compilation."
|
||||
rm -f ${tmpPPFile}
|
||||
exit 1
|
||||
fi
|
||||
|
||||
|
||||
# Compile preprocessed verilog file
|
||||
${execIVL} -t ${target} -o ${tmpCCFile} ${topModule} ${functors} ${flags} ${tmpPPFile}
|
||||
if test $? -ne 0 ; then
|
||||
echo "Verilog compilation failed. Terminating compilation."
|
||||
rm -f ${tmpCCFile}
|
||||
exit 1
|
||||
fi
|
||||
rm -f ${tmpPPFile}
|
||||
|
||||
|
||||
case "${target}" in
|
||||
|
||||
"xnf") mv ${tmpCCFile} ${outputFile} ;;
|
||||
|
||||
"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} ;;
|
||||
|
||||
*) mv ${tmpCCFile} ${outputFile} ;;
|
||||
|
||||
esac
|
||||
|
||||
if test ${execute} ; then
|
||||
./${outputFile}
|
||||
fi
|
||||
+171
-5
@@ -17,7 +17,7 @@
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
|
||||
*/
|
||||
#if !defined(WINNT)
|
||||
#ident "$Id: verinum.cc,v 1.9 1999/07/20 05:12:22 steve Exp $"
|
||||
#ident "$Id: verinum.cc,v 1.12 1999/11/06 16:00:17 steve Exp $"
|
||||
#endif
|
||||
|
||||
# include "verinum.h"
|
||||
@@ -213,6 +213,18 @@ string verinum::as_string() const
|
||||
return result;
|
||||
}
|
||||
|
||||
bool verinum::is_before(const verinum&that) const
|
||||
{
|
||||
if (that.nbits_ > nbits_) return true;
|
||||
if (that.nbits_ < nbits_) return false;
|
||||
|
||||
for (unsigned idx = nbits_ ; idx > 0 ; idx -= 1) {
|
||||
if (bits_[idx-1] < that.bits_[idx-1]) return true;
|
||||
if (bits_[idx-1] > that.bits_[idx-1]) return false;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool verinum::is_defined() const
|
||||
{
|
||||
for (unsigned idx = 0 ; idx < nbits_ ; idx += 1) {
|
||||
@@ -296,20 +308,174 @@ ostream& operator<< (ostream&o, const verinum&v)
|
||||
return o;
|
||||
}
|
||||
|
||||
bool operator == (const verinum&left, const verinum&right)
|
||||
verinum::V operator == (const verinum&left, const verinum&right)
|
||||
{
|
||||
if (left.len() != right.len())
|
||||
return false;
|
||||
return verinum::V0;
|
||||
|
||||
for (unsigned idx = 0 ; idx < left.len() ; idx += 1)
|
||||
if (left[idx] != right[idx])
|
||||
return false;
|
||||
return verinum::V0;
|
||||
|
||||
return true;
|
||||
return verinum::V1;
|
||||
}
|
||||
|
||||
verinum::V operator <= (const verinum&left, const verinum&right)
|
||||
{
|
||||
unsigned idx;
|
||||
for (idx = left.len() ; idx > right.len() ; idx -= 1) {
|
||||
if (left[idx-1] != verinum::V0) return verinum::V0;
|
||||
}
|
||||
|
||||
for (idx = right.len() ; idx > left.len() ; idx -= 1) {
|
||||
if (right[idx-1] != verinum::V0) return verinum::V0;
|
||||
}
|
||||
|
||||
while (idx > 0) {
|
||||
if (left[idx-1] == verinum::Vx) return verinum::Vx;
|
||||
if (left[idx-1] == verinum::Vz) return verinum::Vx;
|
||||
if (right[idx-1] == verinum::Vx) return verinum::Vx;
|
||||
if (right[idx-1] == verinum::Vz) return verinum::Vx;
|
||||
if (left[idx-1] > right[idx-1]) return verinum::V0;
|
||||
idx -= 1;
|
||||
}
|
||||
|
||||
return verinum::V1;
|
||||
}
|
||||
|
||||
static verinum::V add_with_carry(verinum::V l, verinum::V r, verinum::V&c)
|
||||
{
|
||||
unsigned sum = 0;
|
||||
switch (c) {
|
||||
case verinum::Vx:
|
||||
case verinum::Vz:
|
||||
c = verinum::Vx;
|
||||
return verinum::Vx;
|
||||
case verinum::V0:
|
||||
break;
|
||||
case verinum::V1:
|
||||
sum += 1;
|
||||
}
|
||||
|
||||
switch (l) {
|
||||
case verinum::Vx:
|
||||
case verinum::Vz:
|
||||
c = verinum::Vx;
|
||||
return verinum::Vx;
|
||||
case verinum::V0:
|
||||
break;
|
||||
case verinum::V1:
|
||||
sum += 1;
|
||||
break;
|
||||
}
|
||||
|
||||
switch (r) {
|
||||
case verinum::Vx:
|
||||
case verinum::Vz:
|
||||
c = verinum::Vx;
|
||||
return verinum::Vx;
|
||||
case verinum::V0:
|
||||
break;
|
||||
case verinum::V1:
|
||||
sum += 1;
|
||||
break;
|
||||
}
|
||||
|
||||
if (sum & 2)
|
||||
c = verinum::V1;
|
||||
else
|
||||
c = verinum::V0;
|
||||
if (sum & 1)
|
||||
return verinum::V1;
|
||||
else
|
||||
return verinum::V0;
|
||||
}
|
||||
|
||||
verinum not(const verinum&left)
|
||||
{
|
||||
verinum val = left;
|
||||
for (unsigned idx = 0 ; idx < val.len() ; idx += 1)
|
||||
switch (val[idx]) {
|
||||
case verinum::V0:
|
||||
val.set(idx, verinum::V1);
|
||||
break;
|
||||
case verinum::V1:
|
||||
val.set(idx, verinum::V0);
|
||||
break;
|
||||
default:
|
||||
val.set(idx, verinum::Vx);
|
||||
break;
|
||||
}
|
||||
|
||||
return val;
|
||||
}
|
||||
|
||||
/*
|
||||
* Addition works a bit at a time, from the least significant up to
|
||||
* the most significant.
|
||||
*/
|
||||
verinum operator + (const verinum&left, const verinum&right)
|
||||
{
|
||||
unsigned min = left.len();
|
||||
if (right.len() < min) min = right.len();
|
||||
|
||||
unsigned max = left.len();
|
||||
if (right.len() > max) max = right.len();
|
||||
|
||||
verinum val (verinum::V0, max);
|
||||
|
||||
verinum::V carry = verinum::V0;
|
||||
for (unsigned idx = 0 ; idx < min ; idx += 1)
|
||||
val.set(idx, add_with_carry(left[idx], right[idx], carry));
|
||||
|
||||
if (left.len() > right.len()) {
|
||||
for (unsigned idx = min ; idx < max ; idx += 1)
|
||||
val.set(idx,add_with_carry(left[idx], verinum::V0, carry));
|
||||
} else {
|
||||
for (unsigned idx = min ; idx < max ; idx += 1)
|
||||
val.set(idx, add_with_carry(verinum::V0, right[idx], carry));
|
||||
}
|
||||
|
||||
return val;
|
||||
}
|
||||
|
||||
verinum operator - (const verinum&left, const verinum&r)
|
||||
{
|
||||
verinum right = not(r);
|
||||
unsigned min = left.len();
|
||||
if (right.len() < min) min = right.len();
|
||||
|
||||
unsigned max = left.len();
|
||||
if (right.len() > max) max = right.len();
|
||||
|
||||
verinum val (verinum::V0, max);
|
||||
|
||||
verinum::V carry = verinum::V1;
|
||||
for (unsigned idx = 0 ; idx < min ; idx += 1)
|
||||
val.set(idx, add_with_carry(left[idx], right[idx], carry));
|
||||
|
||||
if (left.len() > right.len()) {
|
||||
for (unsigned idx = min ; idx < max ; idx += 1)
|
||||
val.set(idx,add_with_carry(left[idx], verinum::V0, carry));
|
||||
} else {
|
||||
for (unsigned idx = min ; idx < max ; idx += 1)
|
||||
val.set(idx, add_with_carry(verinum::V0, right[idx], carry));
|
||||
}
|
||||
|
||||
return val;
|
||||
}
|
||||
|
||||
/*
|
||||
* $Log: verinum.cc,v $
|
||||
* Revision 1.12 1999/11/06 16:00:17 steve
|
||||
* Put number constants into a static table.
|
||||
*
|
||||
* Revision 1.11 1999/10/22 23:57:53 steve
|
||||
* do the <= in bits, not numbers.
|
||||
*
|
||||
* Revision 1.10 1999/10/10 23:29:37 steve
|
||||
* Support evaluating + operator at compile time.
|
||||
*
|
||||
* Revision 1.9 1999/07/20 05:12:22 steve
|
||||
* Implement the set method.
|
||||
*
|
||||
|
||||
@@ -19,7 +19,7 @@
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
|
||||
*/
|
||||
#if !defined(WINNT)
|
||||
#ident "$Id: verinum.h,v 1.5 1999/05/13 04:02:09 steve Exp $"
|
||||
#ident "$Id: verinum.h,v 1.8 1999/11/06 16:00:17 steve Exp $"
|
||||
#endif
|
||||
|
||||
# include <string>
|
||||
@@ -63,6 +63,9 @@ class verinum {
|
||||
// an ascii description instead of a number value.
|
||||
bool is_string() const { return string_flag_; }
|
||||
|
||||
// Comparison for use in sorting algorithms.
|
||||
bool is_before(const verinum&that) const;
|
||||
|
||||
// Individual bits can be accessed with the get and set
|
||||
// methods.
|
||||
V get(unsigned idx) const;
|
||||
@@ -90,10 +93,22 @@ class ostream;
|
||||
extern ostream& operator<< (ostream&, const verinum&);
|
||||
extern ostream& operator<< (ostream&, verinum::V);
|
||||
|
||||
extern bool operator == (const verinum&left, const verinum&right);
|
||||
extern verinum::V operator == (const verinum&left, const verinum&right);
|
||||
extern verinum::V operator <= (const verinum&left, const verinum&right);
|
||||
extern verinum operator + (const verinum&left, const verinum&right);
|
||||
extern verinum operator - (const verinum&left, const verinum&right);
|
||||
|
||||
/*
|
||||
* $Log: verinum.h,v $
|
||||
* Revision 1.8 1999/11/06 16:00:17 steve
|
||||
* Put number constants into a static table.
|
||||
*
|
||||
* Revision 1.7 1999/10/22 23:57:53 steve
|
||||
* do the <= in bits, not numbers.
|
||||
*
|
||||
* Revision 1.6 1999/10/10 23:29:37 steve
|
||||
* Support evaluating + operator at compile time.
|
||||
*
|
||||
* Revision 1.5 1999/05/13 04:02:09 steve
|
||||
* More precise handling of verinum bit lengths.
|
||||
*
|
||||
|
||||
@@ -0,0 +1,56 @@
|
||||
|
||||
HOW IT WORKS
|
||||
|
||||
The VPI interface for Icarus Verilog works by creating from a
|
||||
collection of PLI applications a single vpi module. The vpi module
|
||||
includes compiled code for the applications linked together (with any
|
||||
other libraries that the applications need) into a module with a
|
||||
single exported symbol, the vlog_startup_routines array.
|
||||
|
||||
The product that wishes to invoke the module (normally at run time)
|
||||
loads the module, locates the vlog_startup_routines table, and calls
|
||||
all the startup routines contained in that table. It is possible for a
|
||||
product to link with many modules. In that case, all the modules are
|
||||
linked in and startup routines are called in order.
|
||||
|
||||
The product that uses vpi modules uses the environment variable
|
||||
VPI_MODULE_PATH as a ':' separated list of directories. This is the
|
||||
module search path. When a module is specified by name (using whatever
|
||||
means the product supports) the module search path is scanned until
|
||||
the module is located.
|
||||
|
||||
The special module name "system.vpi" is part of the core Icarus
|
||||
Verilog distribution and includes implementations of the standard
|
||||
system tasks/functions.
|
||||
|
||||
COMPILING A VPI MODULE (LINUX)
|
||||
|
||||
To compile a module, first compile down to object files all the PLI
|
||||
applications that you wish to include in the module. Then, create a
|
||||
small "C" source file that defines only the startup table like so:
|
||||
|
||||
extern void hello_register();
|
||||
void (*vlog_startup_routines[])() = {
|
||||
hello_register,
|
||||
0
|
||||
};
|
||||
|
||||
Compile this table source down to its object file, as well. Finally,
|
||||
link the application with the command:
|
||||
|
||||
cc -o foo.vpi -shared <all the .o files>
|
||||
|
||||
No VPI libraries need to be included because the product that loads
|
||||
the module will supply all the standard vpi functions. If you use any
|
||||
non-vpi library functions, you may need to include libraries to
|
||||
support them.
|
||||
|
||||
The resulting foo.vpi file is the vpi module. Place it in a location
|
||||
where the product to use it can locate it.
|
||||
|
||||
|
||||
CAVEAT EMPTOR
|
||||
|
||||
Only the calltf function is supported. The compiletf and sizetf
|
||||
functions are invoked at compile time, and the ivl compiler does not
|
||||
yet support VPI.
|
||||
@@ -0,0 +1,3 @@
|
||||
Makefile
|
||||
system.vpi
|
||||
dep
|
||||
@@ -0,0 +1,81 @@
|
||||
#
|
||||
# This source code is free software; you can redistribute it
|
||||
# and/or modify it in source code form under the terms of the GNU
|
||||
# Library 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 Library General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU Library 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
|
||||
#
|
||||
#ident "$Id: Makefile.in,v 1.7 1999/11/07 20:33:30 steve Exp $"
|
||||
#
|
||||
#
|
||||
SHELL = /bin/sh
|
||||
|
||||
VERSION = 0.0
|
||||
|
||||
prefix = @prefix@
|
||||
exec_prefix = @exec_prefix@
|
||||
srcdir = @srcdir@
|
||||
|
||||
VPATH = $(srcdir)
|
||||
|
||||
bindir = $(exec_prefix)/bin
|
||||
libdir = $(exec_prefix)/lib
|
||||
includedir = $(prefix)/include
|
||||
|
||||
CC = @CC@
|
||||
CXX = @CXX@
|
||||
INSTALL = @INSTALL@
|
||||
INSTALL_PROGRAM = @INSTALL_PROGRAM@
|
||||
INSTALL_DATA = @INSTALL_DATA@
|
||||
|
||||
CPPFLAGS = @CPPFLAGS@ @DEFS@ -fpic
|
||||
CXXFLAGS = @CXXFLAGS@
|
||||
LDFLAGS = @LDFLAGS@
|
||||
|
||||
all: system.vpi
|
||||
|
||||
%.o dep/%.d: %.c
|
||||
@[ -d dep ] || mkdir dep
|
||||
$(CC) -Wall $(CPPFLAGS) -I$(srcdir) -MD -c $< -o $*.o
|
||||
mv $*.d dep
|
||||
|
||||
O = sys_table.o sys_display.o sys_finish.o sys_vcd.o
|
||||
|
||||
system.vpi: $O
|
||||
$(CC) -shared -o $@ $O
|
||||
|
||||
clean:
|
||||
rm -f *.o dep/*.d
|
||||
|
||||
install: all installdirs $(libdir)/ivl/system.vpi \
|
||||
$(includedir)/vpi_user.h
|
||||
|
||||
$(libdir)/ivl/system.vpi: ./system.vpi
|
||||
$(INSTALL_PROGRAM) ./system.vpi $(libdir)/ivl/system.vpi
|
||||
|
||||
$(includedir)/vpi_user.h: $(srcdir)/vpi_user.h
|
||||
$(INSTALL_DATA) $(srcdir)/vpi_user.h $(includedir)/vpi_user.h
|
||||
|
||||
|
||||
installdirs: ../mkinstalldirs
|
||||
$(srcdir)/../mkinstalldirs $(includedir) $(bindir) $(libdir)/ivl
|
||||
|
||||
uninstall:
|
||||
rm -f $(libdir)/ivl/system.vpi
|
||||
rm -f $(includedir)/vpi_user.h
|
||||
|
||||
|
||||
-include $(patsubst %.o, dep/%.d, $O)
|
||||
@@ -0,0 +1,447 @@
|
||||
/*
|
||||
* 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_display.c,v 1.9 1999/11/07 02:25:07 steve Exp $"
|
||||
#endif
|
||||
|
||||
# include "vpi_user.h"
|
||||
# include <assert.h>
|
||||
# include <string.h>
|
||||
# include <ctype.h>
|
||||
# include <stdlib.h>
|
||||
|
||||
struct strobe_cb_info {
|
||||
char*name;
|
||||
vpiHandle*items;
|
||||
unsigned nitems;
|
||||
};
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* If $display discovers a string as a parameter, this function is
|
||||
* called to process it as a format string. I need the argv handle as
|
||||
* well so that I can look for arguments as I move forward through the
|
||||
* string.
|
||||
*/
|
||||
static int format_str(char*fmt, int argc, vpiHandle*argv)
|
||||
{
|
||||
s_vpi_value value;
|
||||
char buf[256];
|
||||
char*cp = fmt;
|
||||
int idx;
|
||||
|
||||
assert(fmt);
|
||||
|
||||
idx = 0;
|
||||
|
||||
while (*cp) {
|
||||
size_t cnt = strcspn(cp, "%\\");
|
||||
if (cnt > 0) {
|
||||
if (cnt >= sizeof buf)
|
||||
cnt = sizeof buf - 1;
|
||||
strncpy(buf, cp, cnt);
|
||||
buf[cnt] = 0;
|
||||
vpi_printf("%s", buf);
|
||||
cp += cnt;
|
||||
|
||||
} else if (*cp == '%') {
|
||||
int fsize = -1;
|
||||
|
||||
cp += 1;
|
||||
if (isdigit(*cp))
|
||||
fsize = strtoul(cp, &cp, 10);
|
||||
|
||||
switch (*cp) {
|
||||
case 0:
|
||||
break;
|
||||
case 'b':
|
||||
case 'B':
|
||||
value.format = vpiBinStrVal;
|
||||
vpi_get_value(argv[idx++], &value);
|
||||
vpi_printf("%s", value.value.str);
|
||||
cp += 1;
|
||||
break;
|
||||
case 'd':
|
||||
case 'D':
|
||||
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':
|
||||
value.format = vpiHexStrVal;
|
||||
vpi_get_value(argv[idx++], &value);
|
||||
vpi_printf("%s", value.value.str);
|
||||
cp += 1;
|
||||
break;
|
||||
case 'm':
|
||||
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 '%':
|
||||
vpi_printf("%%");
|
||||
cp += 1;
|
||||
break;
|
||||
default:
|
||||
vpi_printf("%c", *cp);
|
||||
cp += 1;
|
||||
break;
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
cp += 1;
|
||||
switch (*cp) {
|
||||
case 0:
|
||||
break;
|
||||
case 'n':
|
||||
vpi_printf("\n");
|
||||
cp += 1;
|
||||
break;
|
||||
default:
|
||||
vpi_printf("%c", *cp);
|
||||
cp += 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return idx;
|
||||
}
|
||||
|
||||
static void do_display(struct strobe_cb_info*info)
|
||||
{
|
||||
s_vpi_value value;
|
||||
int idx;
|
||||
|
||||
for (idx = 0 ; idx < info->nitems ; idx += 1) {
|
||||
vpiHandle item = info->items[idx];
|
||||
|
||||
switch (vpi_get(vpiType, item)) {
|
||||
|
||||
case 0:
|
||||
vpi_printf(" ");
|
||||
break;
|
||||
|
||||
case vpiConstant:
|
||||
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;
|
||||
|
||||
case vpiNet:
|
||||
case vpiReg:
|
||||
value.format = vpiBinStrVal;
|
||||
vpi_get_value(item, &value);
|
||||
vpi_printf("%s", value.value.str);
|
||||
break;
|
||||
|
||||
case vpiTimeVar:
|
||||
value.format = vpiTimeVal;
|
||||
vpi_get_value(item, &value);
|
||||
vpi_printf("%u", value.value.time->low);
|
||||
break;
|
||||
|
||||
default:
|
||||
vpi_printf("?");
|
||||
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");
|
||||
|
||||
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;
|
||||
|
||||
tf_data.type = vpiSysTask;
|
||||
tf_data.tfname = "$display";
|
||||
tf_data.calltf = sys_display_calltf;
|
||||
tf_data.compiletf = 0;
|
||||
tf_data.sizetf = 0;
|
||||
tf_data.user_data = "$display";
|
||||
vpi_register_systf(&tf_data);
|
||||
|
||||
tf_data.type = vpiSysTask;
|
||||
tf_data.tfname = "$write";
|
||||
tf_data.calltf = sys_display_calltf;
|
||||
tf_data.compiletf = 0;
|
||||
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.
|
||||
*
|
||||
* Revision 1.1 1999/08/15 01:23:56 steve
|
||||
* Convert vvm to implement system tasks with vpi.
|
||||
*
|
||||
*/
|
||||
|
||||
@@ -0,0 +1,55 @@
|
||||
/*
|
||||
* 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_finish.c,v 1.3 1999/08/28 02:10:44 steve Exp $"
|
||||
#endif
|
||||
|
||||
# include "vpi_user.h"
|
||||
|
||||
static int sys_finish_calltf(char *xx)
|
||||
{
|
||||
vpi_sim_control(vpiFinish, 0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void sys_finish_register()
|
||||
{
|
||||
s_vpi_systf_data tf_data;
|
||||
|
||||
tf_data.type = vpiSysTask;
|
||||
tf_data.tfname = "$finish";
|
||||
tf_data.calltf = sys_finish_calltf;
|
||||
tf_data.compiletf = 0;
|
||||
tf_data.sizetf = 0;
|
||||
vpi_register_systf(&tf_data);
|
||||
}
|
||||
|
||||
/*
|
||||
* $Log: sys_finish.c,v $
|
||||
* Revision 1.3 1999/08/28 02:10:44 steve
|
||||
* Call the right vpiFinish code.
|
||||
*
|
||||
* Revision 1.2 1999/08/19 02:51:03 steve
|
||||
* Add vpi_sim_control
|
||||
*
|
||||
* Revision 1.1 1999/08/15 01:23:56 steve
|
||||
* Convert vvm to implement system tasks with vpi.
|
||||
*
|
||||
*/
|
||||
|
||||
@@ -0,0 +1,44 @@
|
||||
/*
|
||||
* 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_table.c,v 1.2 1999/11/07 20:33:30 steve Exp $"
|
||||
#endif
|
||||
|
||||
extern void sys_finish_register();
|
||||
extern void sys_display_register();
|
||||
extern void sys_vcd_register();
|
||||
|
||||
void (*vlog_startup_routines[])() = {
|
||||
sys_finish_register,
|
||||
sys_display_register,
|
||||
sys_vcd_register,
|
||||
0
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
* $Log: sys_table.c,v $
|
||||
* Revision 1.2 1999/11/07 20:33:30 steve
|
||||
* Add VCD output and related system tasks.
|
||||
*
|
||||
* Revision 1.1 1999/08/15 01:23:56 steve
|
||||
* Convert vvm to implement system tasks with vpi.
|
||||
*
|
||||
*/
|
||||
|
||||
+237
@@ -0,0 +1,237 @@
|
||||
/*
|
||||
* Copyright (c) 1999 Stephen Williams (steve@icarus.com)
|
||||
*
|
||||
* This source code is free software; you can redistribute it
|
||||
* and/or modify it in source code form under the terms of the GNU
|
||||
* General Public License as published by the Free Software
|
||||
* Foundation; either version 2 of the License, or (at your option)
|
||||
* any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
|
||||
*/
|
||||
#if !defined(WINNT)
|
||||
#ident "$Id: sys_vcd.c,v 1.2 1999/11/28 00:56:08 steve Exp $"
|
||||
#endif
|
||||
|
||||
/*
|
||||
* This file contains the implementations of the VCD related
|
||||
* funcitons.
|
||||
*/
|
||||
|
||||
# include <vpi_user.h>
|
||||
# include <stdio.h>
|
||||
# include <stdlib.h>
|
||||
# include <string.h>
|
||||
# include <assert.h>
|
||||
|
||||
static FILE*dump_file = 0;
|
||||
|
||||
struct vcd_info {
|
||||
vpiHandle item;
|
||||
vpiHandle cb;
|
||||
struct t_vpi_time time;
|
||||
char*ident;
|
||||
struct vcd_info*next;
|
||||
};
|
||||
|
||||
static struct vcd_info*vcd_list = 0;
|
||||
unsigned long vcd_cur_time = 0;
|
||||
|
||||
static int variable_cb(p_cb_data cause)
|
||||
{
|
||||
unsigned long now = cause->time->low;
|
||||
s_vpi_value value;
|
||||
struct t_cb_data cb;
|
||||
struct vcd_info*info = (struct vcd_info*)cause->user_data;
|
||||
|
||||
/* Reschedule this event so that it happens for the next
|
||||
trigger on this variable. */
|
||||
cb = *cause;
|
||||
vpi_register_cb(&cb);
|
||||
|
||||
if (now != vcd_cur_time) {
|
||||
fprintf(dump_file, "#%lu\n", now);
|
||||
vcd_cur_time = now;
|
||||
}
|
||||
|
||||
if (vpi_get(vpiSize, info->item) == 1) {
|
||||
value.format = vpiBinStrVal;
|
||||
vpi_get_value(info->item, &value);
|
||||
fprintf(dump_file, "%s%s\n", value.value.str, info->ident);
|
||||
} else {
|
||||
value.format = vpiBinStrVal;
|
||||
vpi_get_value(info->item, &value);
|
||||
fprintf(dump_file, "b%s %s\n", value.value.str, info->ident);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int sys_dumpall_calltf(char*name)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int sys_dumpfile_calltf(char*name)
|
||||
{
|
||||
char*path;
|
||||
|
||||
vpiHandle sys = vpi_handle(vpiSysTfCall, 0);
|
||||
vpiHandle argv = vpi_iterate(vpiArgument, sys);
|
||||
vpiHandle item = vpi_scan(argv);
|
||||
|
||||
if (item) {
|
||||
s_vpi_value value;
|
||||
|
||||
if (vpi_get(vpiType, item) != vpiConstant) {
|
||||
vpi_printf("ERROR: %s parameter must be a constant\n", name);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (vpi_get(vpiConstType, item) != vpiStringConst) {
|
||||
vpi_printf("ERROR: %s parameter must be a constant\n", name);
|
||||
return 0;
|
||||
}
|
||||
|
||||
value.format = vpiStringVal;
|
||||
vpi_get_value(item, &value);
|
||||
path = strdup(value.value.str);
|
||||
|
||||
vpi_free_object(argv);
|
||||
|
||||
} else {
|
||||
path = strdup("dumpfile.vcd");
|
||||
}
|
||||
|
||||
assert(dump_file == 0);
|
||||
dump_file = fopen(path, "w");
|
||||
if (dump_file == 0) {
|
||||
vpi_printf("ERROR: Unable to open %s for output.\n", path);
|
||||
return 0;
|
||||
}
|
||||
|
||||
free(path);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void scan_scope(unsigned depth, vpiHandle argv)
|
||||
{
|
||||
struct t_cb_data cb;
|
||||
struct vcd_info*info;
|
||||
char ident[64];
|
||||
unsigned nident = 0;
|
||||
|
||||
vpiHandle item;
|
||||
vpiHandle sublist;
|
||||
|
||||
cb.reason = cbValueChange;
|
||||
cb.cb_rtn = variable_cb;
|
||||
|
||||
for (item = vpi_scan(argv) ; item ; item = vpi_scan(argv)) {
|
||||
const char*type;
|
||||
|
||||
switch (vpi_get(vpiType, item)) {
|
||||
case vpiNet:
|
||||
case vpiReg:
|
||||
type = "wire";
|
||||
if (vpi_get(vpiType, item) == vpiReg)
|
||||
type = "reg";
|
||||
|
||||
sprintf(ident, "<%u", nident++);
|
||||
info = malloc(sizeof(*info));
|
||||
info->time.type = vpiSimTime;
|
||||
cb.time = &info->time;
|
||||
cb.user_data = (char*)info;
|
||||
cb.obj = item;
|
||||
info->item = item;
|
||||
info->ident = strdup(ident);
|
||||
info->cb = vpi_register_cb(&cb);
|
||||
info->next = vcd_list;
|
||||
vcd_list = info;
|
||||
fprintf(dump_file, "$var %s %u %s %s $end\n",
|
||||
type, vpi_get(vpiSize, item), ident,
|
||||
vpi_get_str(vpiFullName, item));
|
||||
break;
|
||||
|
||||
case vpiModule:
|
||||
sublist = vpi_iterate(vpiInternalScope, item);
|
||||
if (sublist && (depth > 0))
|
||||
scan_scope(depth-1, sublist);
|
||||
break;
|
||||
|
||||
default:
|
||||
vpi_printf("ERROR: $dumpvars: Unsupported parameter type\n");
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
static int sys_dumpvars_calltf(char*name)
|
||||
{
|
||||
vpiHandle sys = vpi_handle(vpiSysTfCall, 0);
|
||||
vpiHandle argv = vpi_iterate(vpiArgument, sys);
|
||||
vpiHandle item = vpi_scan(argv);
|
||||
|
||||
if (item == 0) {
|
||||
vpi_printf("SORRY: %s requires arguments\n", name);
|
||||
return 0;
|
||||
}
|
||||
|
||||
assert(dump_file);
|
||||
|
||||
scan_scope(99, argv);
|
||||
|
||||
fprintf(dump_file, "$enddefinitions $end\n");
|
||||
fprintf(dump_file, "#0\n");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void sys_vcd_register()
|
||||
{
|
||||
s_vpi_systf_data tf_data;
|
||||
|
||||
tf_data.type = vpiSysTask;
|
||||
tf_data.tfname = "$dumpall";
|
||||
tf_data.calltf = sys_dumpall_calltf;
|
||||
tf_data.compiletf = 0;
|
||||
tf_data.sizetf = 0;
|
||||
tf_data.user_data = "$dumpall";
|
||||
vpi_register_systf(&tf_data);
|
||||
|
||||
tf_data.type = vpiSysTask;
|
||||
tf_data.tfname = "$dumpfile";
|
||||
tf_data.calltf = sys_dumpfile_calltf;
|
||||
tf_data.compiletf = 0;
|
||||
tf_data.sizetf = 0;
|
||||
tf_data.user_data = "$dumpfile";
|
||||
vpi_register_systf(&tf_data);
|
||||
|
||||
tf_data.type = vpiSysTask;
|
||||
tf_data.tfname = "$dumpvars";
|
||||
tf_data.calltf = sys_dumpvars_calltf;
|
||||
tf_data.compiletf = 0;
|
||||
tf_data.sizetf = 0;
|
||||
tf_data.user_data = "$dumpvars";
|
||||
vpi_register_systf(&tf_data);
|
||||
}
|
||||
|
||||
/*
|
||||
* $Log: sys_vcd.c,v $
|
||||
* Revision 1.2 1999/11/28 00:56:08 steve
|
||||
* Build up the lists in the scope of a module,
|
||||
* and get $dumpvars to scan the scope for items.
|
||||
*
|
||||
* Revision 1.1 1999/11/07 20:33:30 steve
|
||||
* Add VCD output and related system tasks.
|
||||
*
|
||||
*/
|
||||
|
||||
+246
@@ -0,0 +1,246 @@
|
||||
#ifndef __vpi_user_H
|
||||
#define __vpi_user_H
|
||||
/*
|
||||
* 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_user.h,v 1.9 1999/11/28 00:56:08 steve Exp $"
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
typedef struct __vpiHandle *vpiHandle;
|
||||
|
||||
/*
|
||||
* This structure is created by the VPI application to provide hooks
|
||||
* into the application that the compiler/simulator can access.
|
||||
*/
|
||||
typedef struct t_vpi_systf_data {
|
||||
int type;
|
||||
int subtype;
|
||||
char *tfname;
|
||||
int (*calltf)(char*);
|
||||
int (*compiletf)(char*);
|
||||
int (*sizetf)();
|
||||
char *user_data;
|
||||
} s_vpi_systf_data, *p_vpi_systf_data;
|
||||
|
||||
/* The type in the above structure can have one of the following
|
||||
values: */
|
||||
#define vpiSysTask 1
|
||||
#define vpiSysFunc 2
|
||||
|
||||
|
||||
typedef struct t_vpi_time {
|
||||
int type;
|
||||
unsigned int high;
|
||||
unsigned int low;
|
||||
double real;
|
||||
} s_vpi_time, *p_vpi_time;
|
||||
|
||||
#define vpiScaledRealTime 1
|
||||
#define vpiSimTime 2
|
||||
#define vpiSuppressTime 3
|
||||
|
||||
/*
|
||||
* This structure holds values that are passed back and forth between
|
||||
* the simulator and the application.
|
||||
*/
|
||||
typedef struct t_vpi_value {
|
||||
int format;
|
||||
union {
|
||||
char*str;
|
||||
int scalar;
|
||||
int integer;
|
||||
double real;
|
||||
struct t_vpi_time *time;
|
||||
struct t_vpi_vecval *vector;
|
||||
struct t_vpi_strengthval *strength;
|
||||
char*misc;
|
||||
} value;
|
||||
} s_vpi_value, *p_vpi_value;
|
||||
|
||||
/* These are valid codes for the format of the t_vpi_value structure. */
|
||||
#define vpiBinStrVal 1
|
||||
#define vpiOctStrVal 2
|
||||
#define vpiDecStrVal 3
|
||||
#define vpiHexStrVal 4
|
||||
#define vpiScalerVal 5
|
||||
#define vpiIntVal 6
|
||||
#define vpiReadVal 7
|
||||
#define vpiStringVal 8
|
||||
#define vpiVectorVal 9
|
||||
#define vpiStrengthVal 10
|
||||
#define vpiTimeVal 11
|
||||
#define vpiObjTypeVal 12
|
||||
#define vpiSuppressVal 13
|
||||
|
||||
|
||||
/* 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
|
||||
# define vpiBinaryConst 3
|
||||
# define vpiOctConst 4
|
||||
# define vpiHexConst 5
|
||||
# define vpiStringConst 6
|
||||
|
||||
|
||||
/* VPI FUNCTIONS */
|
||||
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
|
||||
* perform. The remaining parameters (if any) are interpreted by the
|
||||
* operation. The vpi_sim_control definition was added to P1364-2000
|
||||
* 14 July 1999. See PLI Task Force ID: PTF-161
|
||||
*
|
||||
* vpiFinish - perform the $finish operation, as soon as the user
|
||||
* function returns. This operation takes a single
|
||||
* parameter, a diagnostic exit code.
|
||||
*
|
||||
* vpiStop -
|
||||
* vpiReset -
|
||||
* vpiSetInteractiveScope -
|
||||
*/
|
||||
extern void vpi_sim_control(int operation, ...);
|
||||
#define vpiStop 1
|
||||
#define vpiFinish 2
|
||||
#define vpiReset 3
|
||||
#define vpiSetInteractiveScope 4
|
||||
|
||||
extern vpiHandle vpi_handle(int type, vpiHandle ref);
|
||||
extern vpiHandle vpi_iterate(int type, vpiHandle ref);
|
||||
extern vpiHandle vpi_scan(vpiHandle iter);
|
||||
|
||||
extern int vpi_get(int property, vpiHandle ref);
|
||||
extern char* vpi_get_str(int property, vpiHandle ref);
|
||||
extern void vpi_get_value(vpiHandle expr, p_vpi_value value);
|
||||
|
||||
extern int vpi_free_object(vpiHandle ref);
|
||||
|
||||
|
||||
/* This is the table of startup routines included in each module. */
|
||||
extern void (*vlog_startup_routines[])();
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
* $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
|
||||
*
|
||||
* Revision 1.2 1999/08/18 03:44:49 steve
|
||||
* declare vou_sim_control
|
||||
*
|
||||
* Revision 1.1 1999/08/15 01:23:56 steve
|
||||
* Convert vvm to implement system tasks with vpi.
|
||||
*
|
||||
*/
|
||||
#endif
|
||||
@@ -16,6 +16,17 @@ So a sample command line to compile a Verilog file to C++ would be:
|
||||
|
||||
ivl -F nobufz -F sigfold -F propinit -t vvm -o foo.cc foo.vl
|
||||
|
||||
Once the program is compiled down to C++ code, it needs to be further
|
||||
compiled and linked into an executable image. The command for doing
|
||||
this is highly dependent on the system where you use Icarus
|
||||
Verilog. For Linux, the compile command is typically:
|
||||
|
||||
c++ -rdynamic -o foo foo.cc -lvvm -ldl
|
||||
|
||||
On any system, the compiled program requires that the VPI_MODULE_PATH
|
||||
be set to a ':' separated list of directories to search for vpi files,
|
||||
the system.vpi file in particular. This is a run time requirement.
|
||||
|
||||
ATTRIBUTES
|
||||
|
||||
(none)
|
||||
@@ -99,8 +110,14 @@ bits are at:
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
|
||||
*/
|
||||
|
||||
$Id: vvm.txt,v 1.1 1999/04/29 16:29:04 steve Exp $
|
||||
$Id: vvm.txt,v 1.3 1999/08/18 03:45:36 steve Exp $
|
||||
$Log: vvm.txt,v $
|
||||
Revision 1.3 1999/08/18 03:45:36 steve
|
||||
Update compile command line.
|
||||
|
||||
Revision 1.2 1999/08/15 01:23:56 steve
|
||||
Convert vvm to implement system tasks with vpi.
|
||||
|
||||
Revision 1.1 1999/04/29 16:29:04 steve
|
||||
Add vvm target documentation
|
||||
|
||||
|
||||
+27
-10
@@ -18,7 +18,7 @@
|
||||
# 59 Temple Place - Suite 330
|
||||
# Boston, MA 02111-1307, USA
|
||||
#
|
||||
#ident "$Id: Makefile.in,v 1.3 1999/05/09 01:24:59 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@
|
||||
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,23 +53,35 @@ all: libvvm.a
|
||||
$(CXX) -Wall -fno-exceptions $(CXXFLAGS) -MD -c $< -o $*.o
|
||||
mv $*.d dep
|
||||
|
||||
TF = display.o
|
||||
O = vvm_bit.o vvm_calltf.o vvm_event.o vvm_monitor.o vvm_pevent.o \
|
||||
vvm_simulation.o vvm_thread.o $(TF)
|
||||
%.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
|
||||
|
||||
install: all installdirs $(libdir)/libvvm.a \
|
||||
$(includedir)/vvm.h \
|
||||
$(includedir)/vvm_calltf.h \
|
||||
$(includedir)/vpi_priv.h \
|
||||
$(includedir)/vvm_func.h \
|
||||
$(includedir)/vvm_gates.h \
|
||||
$(includedir)/vvm_thread.h
|
||||
$(includedir)/vvm_thread.h \
|
||||
$(includedir)/vvm_calltf.h
|
||||
|
||||
$(libdir)/libvvm.a: ./libvvm.a
|
||||
$(INSTALL_PROGRAM) ./libvvm.a $(libdir)/libvvm.a
|
||||
@@ -88,8 +101,11 @@ $(includedir)/vvm_gates.h: $(srcdir)/vvm_gates.h
|
||||
$(includedir)/vvm_thread.h: $(srcdir)/vvm_thread.h
|
||||
$(INSTALL_DATA) $(srcdir)/vvm_thread.h $(includedir)/vvm_thread.h
|
||||
|
||||
$(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
|
||||
@@ -98,6 +114,7 @@ uninstall:
|
||||
rm -f $(includedir)/vvm_func.h
|
||||
rm -f $(includedir)/vvm_gates.h
|
||||
rm -f $(includedir)/vvm_thread.h
|
||||
rm -f $(includedir)/vpi_priv.h
|
||||
|
||||
|
||||
-include $(patsubst %.o, dep/%.d, $O)
|
||||
|
||||
-264
@@ -1,264 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 1998 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: display.cc,v 1.5 1999/05/31 15:46:36 steve Exp $"
|
||||
#endif
|
||||
|
||||
# include "vvm.h"
|
||||
# include "vvm_calltf.h"
|
||||
# include <iostream>
|
||||
|
||||
static void format_hex(vvm_simulation*sim, ostream&os,
|
||||
class vvm_calltf_parm*parm)
|
||||
{
|
||||
switch (parm->type()) {
|
||||
case vvm_calltf_parm::TIME:
|
||||
os << sim->get_sim_time();
|
||||
break;
|
||||
case vvm_calltf_parm::NONE:
|
||||
os << "z";
|
||||
break;
|
||||
case vvm_calltf_parm::ULONG:
|
||||
os << ((parm->as_ulong()&1) ? "0" : "1");
|
||||
break;
|
||||
case vvm_calltf_parm::STRING:
|
||||
os << parm->as_string();
|
||||
break;
|
||||
case vvm_calltf_parm::BITS:
|
||||
unsigned c = 0;
|
||||
for (unsigned idx = parm->as_bits()->get_width()
|
||||
; idx > 0 ; idx -= 1)
|
||||
c = (c << 1) | parm->as_bits()->get_bit(idx-1);
|
||||
cout.form("%x",c);
|
||||
break;
|
||||
}
|
||||
}
|
||||
static void format_bit(vvm_simulation*sim, ostream&os,
|
||||
class vvm_calltf_parm*parm)
|
||||
{
|
||||
switch (parm->type()) {
|
||||
case vvm_calltf_parm::TIME:
|
||||
os << (sim->get_sim_time()&1);
|
||||
break;
|
||||
case vvm_calltf_parm::NONE:
|
||||
os << "z";
|
||||
break;
|
||||
case vvm_calltf_parm::ULONG:
|
||||
os << ((parm->as_ulong()&1) ? "0" : "1");
|
||||
break;
|
||||
case vvm_calltf_parm::STRING:
|
||||
os << parm->as_string();
|
||||
break;
|
||||
case vvm_calltf_parm::BITS:
|
||||
for (unsigned idx = parm->as_bits()->get_width()
|
||||
; idx > 0 ; idx -= 1)
|
||||
os << parm->as_bits()->get_bit(idx-1);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void format_dec(vvm_simulation*sim, ostream&os,
|
||||
class vvm_calltf_parm*parm)
|
||||
{
|
||||
switch (parm->type()) {
|
||||
case vvm_calltf_parm::TIME:
|
||||
os << sim->get_sim_time();
|
||||
break;
|
||||
case vvm_calltf_parm::NONE:
|
||||
os << "0";
|
||||
break;
|
||||
case vvm_calltf_parm::ULONG:
|
||||
os << parm->as_ulong();
|
||||
break;
|
||||
case vvm_calltf_parm::STRING:
|
||||
os << parm->as_string();
|
||||
break;
|
||||
case vvm_calltf_parm::BITS: {
|
||||
unsigned long val = 0;
|
||||
unsigned long mask = 1;
|
||||
const vvm_bits_t*bstr = parm->as_bits();
|
||||
for (unsigned idx = 0 ; idx < bstr->get_width() ; idx += 1) {
|
||||
if (bstr->get_bit(idx) == V1) val |= mask;
|
||||
mask <<= 1;
|
||||
}
|
||||
os << val;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void format_name(ostream&os, class vvm_calltf_parm*parm)
|
||||
{
|
||||
switch (parm->type()) {
|
||||
case vvm_calltf_parm::TIME:
|
||||
os << "$time";
|
||||
break;
|
||||
case vvm_calltf_parm::NONE:
|
||||
break;
|
||||
case vvm_calltf_parm::ULONG:
|
||||
os << parm->as_ulong();
|
||||
break;
|
||||
case vvm_calltf_parm::STRING:
|
||||
os << "\"" << parm->as_string() << "\"";
|
||||
break;
|
||||
case vvm_calltf_parm::BITS:
|
||||
os << parm->sig_name();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static unsigned format(vvm_simulation*sim, const string&str,
|
||||
unsigned nparms,
|
||||
class vvm_calltf_parm*parms)
|
||||
{
|
||||
char prev = 0;
|
||||
unsigned next_parm = 0;
|
||||
unsigned idx = 0;
|
||||
while (idx < str.length()) {
|
||||
if (prev == '%') {
|
||||
switch (str[idx]) {
|
||||
case 'b':
|
||||
case 'B':
|
||||
format_bit(sim, cout, parms+next_parm);
|
||||
next_parm += 1;
|
||||
break;
|
||||
case 'x':
|
||||
case 'X':
|
||||
case 'h':
|
||||
case 'H':
|
||||
format_hex(sim, cout, parms+next_parm);
|
||||
next_parm += 1;
|
||||
break;
|
||||
case 'd':
|
||||
case 'D':
|
||||
format_dec(sim, cout, parms+next_parm);
|
||||
next_parm += 1;
|
||||
break;
|
||||
case 'm':
|
||||
case 'M':
|
||||
format_name(cout, parms+next_parm);
|
||||
next_parm += 1;
|
||||
break;
|
||||
case '%':
|
||||
cout << str[idx];
|
||||
break;
|
||||
}
|
||||
|
||||
prev = 0;
|
||||
|
||||
} else {
|
||||
if (str[idx] != '%')
|
||||
cout << str[idx];
|
||||
else
|
||||
prev = '%';
|
||||
}
|
||||
|
||||
idx += 1;
|
||||
}
|
||||
|
||||
return next_parm;
|
||||
}
|
||||
|
||||
void Sdisplay(vvm_simulation*sim, const string&name,
|
||||
unsigned nparms, class vvm_calltf_parm*parms)
|
||||
{
|
||||
for (unsigned idx = 0 ; idx < nparms ; idx += 1)
|
||||
switch (parms[idx].type()) {
|
||||
case vvm_calltf_parm::NONE:
|
||||
cout << " ";
|
||||
break;
|
||||
case vvm_calltf_parm::TIME:
|
||||
cout << sim->get_sim_time();
|
||||
break;
|
||||
case vvm_calltf_parm::ULONG:
|
||||
cout << parms[idx].as_ulong();
|
||||
break;
|
||||
case vvm_calltf_parm::STRING:
|
||||
idx += format(sim, parms[idx].as_string(),
|
||||
nparms-idx-1, parms+idx+1);
|
||||
break;
|
||||
case vvm_calltf_parm::BITS:
|
||||
cout << *parms[idx].as_bits();
|
||||
break;
|
||||
}
|
||||
|
||||
cout << endl;
|
||||
}
|
||||
|
||||
class monitor_event : public vvm_event {
|
||||
public:
|
||||
monitor_event(vvm_simulation*sim,
|
||||
unsigned nparms, class vvm_calltf_parm*parms)
|
||||
{ sim_ = sim;
|
||||
nparms_ = nparms;
|
||||
parms_ = new vvm_calltf_parm[nparms];
|
||||
for (unsigned idx = 0 ; idx < nparms_ ; idx += 1)
|
||||
parms_[idx] = parms[idx];
|
||||
}
|
||||
|
||||
~monitor_event() { delete[]parms_; }
|
||||
|
||||
private:
|
||||
vvm_simulation*sim_;
|
||||
unsigned nparms_;
|
||||
vvm_calltf_parm*parms_;
|
||||
void event_function();
|
||||
};
|
||||
|
||||
void monitor_event::event_function()
|
||||
{
|
||||
Sdisplay(sim_, "$display", nparms_, parms_);
|
||||
}
|
||||
|
||||
static monitor_event*mon = 0;
|
||||
|
||||
void Smonitor(vvm_simulation*sim, const string&name,
|
||||
unsigned nparms, class vvm_calltf_parm*parms)
|
||||
{
|
||||
if (mon) delete mon;
|
||||
mon = new monitor_event(sim, nparms, parms);
|
||||
|
||||
for (unsigned idx = 0 ; idx < nparms ; idx += 1) {
|
||||
if (parms[idx].type() != vvm_calltf_parm::BITS)
|
||||
continue;
|
||||
|
||||
parms[idx].as_mon()->enable(mon);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* $Log: display.cc,v $
|
||||
* Revision 1.5 1999/05/31 15:46:36 steve
|
||||
* Handle time in more places.
|
||||
*
|
||||
* Revision 1.4 1999/05/12 04:02:17 steve
|
||||
* Add %x support contributed by Steve Wilson.
|
||||
*
|
||||
* Revision 1.3 1999/01/01 01:44:40 steve
|
||||
* Proberly print vectors in binary.
|
||||
*
|
||||
* 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:10 steve
|
||||
* Add vvm library.
|
||||
*
|
||||
*/
|
||||
@@ -0,0 +1,188 @@
|
||||
/*
|
||||
* Copyright (c) 1999 Stephen Williams (steve@icarus.com)
|
||||
*
|
||||
* This source code is free software; you can redistribute it
|
||||
* and/or modify it in source code form under the terms of the GNU
|
||||
* General Public License as published by the Free Software
|
||||
* Foundation; either version 2 of the License, or (at your option)
|
||||
* any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
|
||||
*/
|
||||
#if !defined(WINNT)
|
||||
#ident "$Id: vpi_callback.c,v 1.4 1999/11/07 20:33:30 steve Exp $"
|
||||
#endif
|
||||
|
||||
# include "vpi_priv.h"
|
||||
# include <stdlib.h>
|
||||
# include <assert.h>
|
||||
|
||||
static struct __vpirt vpip_callback_rt = {
|
||||
vpiCallback,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0
|
||||
};
|
||||
|
||||
/*
|
||||
* This function is called by the scheduler to execute an event of
|
||||
* some sort. The parameter is a vpiHandle of the callback that is to
|
||||
* be executed.
|
||||
*/
|
||||
static void vpip_call_callback(void*cp)
|
||||
{
|
||||
unsigned long now;
|
||||
struct __vpiCallback*rfp = (struct __vpiCallback*)cp;
|
||||
assert(rfp->base.vpi_type->type_code == vpiCallback);
|
||||
|
||||
switch (rfp->cb_data.time->type) {
|
||||
case vpiSuppressTime:
|
||||
case vpiScaledRealTime: // XXXX not supported
|
||||
break;
|
||||
|
||||
case vpiSimTime:
|
||||
now = ((struct __vpiTimeVar*)vpip_sim_time())->time;
|
||||
rfp->cb_data.time->low = now;
|
||||
rfp->cb_data.time->high = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
rfp->cb_data.cb_rtn(&rfp->cb_data);
|
||||
free(rfp);
|
||||
}
|
||||
|
||||
/*
|
||||
* This function is called by the product when it changes the value of
|
||||
* a signal. It arranges for all the value chance callbacks to be
|
||||
* called.
|
||||
*/
|
||||
void vpip_run_value_changes(struct __vpiSignal*sig)
|
||||
{
|
||||
struct __vpiCallback*cur;
|
||||
if (sig->monitor == 0) return;
|
||||
|
||||
while (sig->monitor->next != sig->monitor) {
|
||||
cur = sig->monitor->next;
|
||||
sig->monitor->next = cur->next;
|
||||
|
||||
cur->next = 0;
|
||||
cur->ev = vpip_sim_insert_event(0, cur, vpip_call_callback, 0);
|
||||
}
|
||||
|
||||
cur = sig->monitor;
|
||||
sig->monitor = 0;
|
||||
cur->next = 0;
|
||||
cur->ev = vpip_sim_insert_event(0, cur, vpip_call_callback, 0);
|
||||
}
|
||||
|
||||
/*
|
||||
* Handle read-only synch events. This causes the callback to be
|
||||
* scheduled for a moment at the end of the time period. This method
|
||||
* handles scheduling with itme delays.
|
||||
*/
|
||||
static void go_readonly_synch(struct __vpiCallback*rfp)
|
||||
{
|
||||
unsigned long tim;
|
||||
assert(rfp->cb_data.time);
|
||||
assert(rfp->cb_data.time->type == vpiSimTime);
|
||||
assert(rfp->cb_data.time->high == 0);
|
||||
tim = rfp->cb_data.time->low;
|
||||
rfp->ev = vpip_sim_insert_event(tim, rfp, vpip_call_callback, 1);
|
||||
}
|
||||
|
||||
/*
|
||||
* To schedule a value change, attach the callback to the signal to me
|
||||
* monitored. I'll be inserted as an event later.
|
||||
*/
|
||||
static void go_value_change(struct __vpiCallback*rfp)
|
||||
{
|
||||
struct __vpiSignal*sig = (struct __vpiSignal*)rfp->cb_data.obj;
|
||||
assert((sig->base.vpi_type->type_code == vpiReg)
|
||||
|| (sig->base.vpi_type->type_code == vpiNet));
|
||||
|
||||
/* If there are no monitor events, start the list. */
|
||||
if (sig->monitor == 0) {
|
||||
rfp->next = rfp;
|
||||
sig->monitor = rfp;
|
||||
return;
|
||||
}
|
||||
|
||||
/* Put me at the end of the list. Remember that the monitor
|
||||
points to the *last* item in the list. */
|
||||
rfp->next = sig->monitor->next;
|
||||
sig->monitor->next = rfp;
|
||||
sig->monitor = rfp;
|
||||
}
|
||||
|
||||
/*
|
||||
* Register callbacks. This supports a variety of callback reasons,
|
||||
* mostly by dispatching them to a type specific handler.
|
||||
*/
|
||||
vpiHandle vpi_register_cb(p_cb_data data)
|
||||
{
|
||||
struct __vpiCallback*rfp = calloc(1, sizeof(struct __vpiCallback));
|
||||
rfp->base.vpi_type = &vpip_callback_rt;
|
||||
rfp->cb_data = *data;
|
||||
|
||||
switch (data->reason) {
|
||||
case cbReadOnlySynch:
|
||||
go_readonly_synch(rfp);
|
||||
break;
|
||||
|
||||
case cbValueChange:
|
||||
go_value_change(rfp);
|
||||
break;
|
||||
|
||||
default:
|
||||
assert(0);
|
||||
}
|
||||
|
||||
return &(rfp->base);
|
||||
}
|
||||
|
||||
|
||||
int vpi_remove_cb(vpiHandle ref)
|
||||
{
|
||||
struct __vpiCallback*rfp = (struct __vpiCallback*)ref;
|
||||
assert(ref->vpi_type->type_code == vpiCallback);
|
||||
|
||||
if (rfp->ev) {
|
||||
/* callbacks attached to events are easy. */
|
||||
vpip_sim_cancel_event(rfp->ev);
|
||||
|
||||
} else {
|
||||
assert(0);
|
||||
}
|
||||
|
||||
free(rfp);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* $Log: vpi_callback.c,v $
|
||||
* Revision 1.4 1999/11/07 20:33:30 steve
|
||||
* Add VCD output and related system tasks.
|
||||
*
|
||||
* Revision 1.3 1999/10/29 03:37:22 steve
|
||||
* Support vpiValueChance callbacks.
|
||||
*
|
||||
* Revision 1.2 1999/10/28 04:47:57 steve
|
||||
* Support delay in constSync callback.
|
||||
*
|
||||
* Revision 1.1 1999/10/28 00:47:25 steve
|
||||
* Rewrite vvm VPI support to make objects more
|
||||
* persistent, rewrite the simulation scheduler
|
||||
* in C (to interface with VPI) and add VPI support
|
||||
* for callbacks.
|
||||
*
|
||||
*/
|
||||
|
||||
+336
@@ -0,0 +1,336 @@
|
||||
/*
|
||||
* Copyright (c) 1999 Stephen Williams (steve@icarus.com)
|
||||
*
|
||||
* This source code is free software; you can redistribute it
|
||||
* and/or modify it in source code form under the terms of the GNU
|
||||
* General Public License as published by the Free Software
|
||||
* Foundation; either version 2 of the License, or (at your option)
|
||||
* any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
|
||||
*/
|
||||
#if !defined(WINNT)
|
||||
#ident "$Id: vpi_const.c,v 1.4 1999/11/06 22:16:50 steve Exp $"
|
||||
#endif
|
||||
|
||||
# include "vpi_priv.h"
|
||||
# include <assert.h>
|
||||
# include <string.h>
|
||||
# include <stdio.h>
|
||||
|
||||
|
||||
/*
|
||||
* This function is used in a couple places to interpret a bit string
|
||||
* as a value.
|
||||
*/
|
||||
void vpip_bits_get_value(enum vpip_bit_t*bits, unsigned nbits, s_vpi_value*vp)
|
||||
{
|
||||
static char buff[1024];
|
||||
char*cp;
|
||||
unsigned val;
|
||||
unsigned idx;
|
||||
|
||||
cp = buff;
|
||||
|
||||
switch (vp->format) {
|
||||
case vpiObjTypeVal:
|
||||
case vpiBinStrVal:
|
||||
for (idx = 0 ; idx < nbits ; idx += 1)
|
||||
switch (bits[nbits-idx-1]) {
|
||||
case V0:
|
||||
*cp++ = '0';
|
||||
break;
|
||||
case V1:
|
||||
*cp++ = '1';
|
||||
break;
|
||||
case Vx:
|
||||
*cp++ = 'x';
|
||||
break;
|
||||
case Vz:
|
||||
*cp++ = 'z';
|
||||
break;
|
||||
}
|
||||
vp->format = vpiBinStrVal;
|
||||
break;
|
||||
|
||||
case vpiDecStrVal:
|
||||
val = 0;
|
||||
for (idx = 0 ; idx < nbits ; idx += 1) {
|
||||
val *= 2;
|
||||
switch (bits[nbits-idx-1]) {
|
||||
case V0:
|
||||
case Vx:
|
||||
case Vz:
|
||||
break;
|
||||
case V1:
|
||||
val += 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
sprintf(cp, "%u", val);
|
||||
cp += strlen(cp);
|
||||
break;
|
||||
|
||||
case vpiOctStrVal:
|
||||
if (nbits%3) {
|
||||
unsigned x = 0;
|
||||
unsigned z = 0;
|
||||
unsigned v = 0;
|
||||
unsigned i;
|
||||
for (i = 0 ; i < nbits%3 ; i += 1) {
|
||||
v *= 2;
|
||||
switch (bits[nbits-i-1]) {
|
||||
case V0:
|
||||
break;
|
||||
case V1:
|
||||
v += 1;
|
||||
break;
|
||||
case Vx:
|
||||
x += 1;
|
||||
break;
|
||||
case Vz:
|
||||
z += 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (x == nbits%3)
|
||||
*cp++ = 'x';
|
||||
else if (x > 0)
|
||||
*cp++ = 'X';
|
||||
else if (z == nbits%3)
|
||||
*cp++ = 'z';
|
||||
else if (z > 0)
|
||||
*cp++ = 'Z';
|
||||
else
|
||||
*cp++ = "01234567"[v];
|
||||
}
|
||||
|
||||
for (idx = nbits%3 ; idx < nbits ; idx += 3) {
|
||||
unsigned x = 0;
|
||||
unsigned z = 0;
|
||||
unsigned v = 0;
|
||||
unsigned i;
|
||||
for (i = idx ; i < idx+3 ; i += 1) {
|
||||
v *= 2;
|
||||
switch (bits[nbits-i-1]) {
|
||||
case V0:
|
||||
break;
|
||||
case V1:
|
||||
v += 1;
|
||||
break;
|
||||
case Vx:
|
||||
x += 1;
|
||||
break;
|
||||
case Vz:
|
||||
z += 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (x == 3)
|
||||
*cp++ = 'x';
|
||||
else if (x > 0)
|
||||
*cp++ = 'X';
|
||||
else if (z == 3)
|
||||
*cp++ = 'z';
|
||||
else if (z > 0)
|
||||
*cp++ = 'Z';
|
||||
else
|
||||
*cp++ = "01234567"[v];
|
||||
}
|
||||
break;
|
||||
|
||||
case vpiHexStrVal:
|
||||
if (nbits%4) {
|
||||
unsigned x = 0;
|
||||
unsigned z = 0;
|
||||
unsigned v = 0;
|
||||
unsigned i;
|
||||
for (i = 0 ; i < nbits%4 ; i += 1) {
|
||||
v *= 2;
|
||||
switch (bits[nbits-i-1]) {
|
||||
case V0:
|
||||
break;
|
||||
case V1:
|
||||
v += 1;
|
||||
break;
|
||||
case Vx:
|
||||
x += 1;
|
||||
break;
|
||||
case Vz:
|
||||
z += 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (x == nbits%4)
|
||||
*cp++ = 'x';
|
||||
else if (x > 0)
|
||||
*cp++ = 'X';
|
||||
else if (z == nbits%4)
|
||||
*cp++ = 'z';
|
||||
else if (z > 0)
|
||||
*cp++ = 'Z';
|
||||
else
|
||||
*cp++ = "0123456789abcdef"[v];
|
||||
}
|
||||
|
||||
for (idx = nbits%4 ; idx < nbits ; idx += 4) {
|
||||
unsigned x = 0;
|
||||
unsigned z = 0;
|
||||
unsigned v = 0;
|
||||
unsigned i;
|
||||
for (i = idx ; i < idx+4 ; i += 1) {
|
||||
v *= 2;
|
||||
switch (bits[nbits-i-1]) {
|
||||
case V0:
|
||||
break;
|
||||
case V1:
|
||||
v += 1;
|
||||
break;
|
||||
case Vx:
|
||||
x += 1;
|
||||
break;
|
||||
case Vz:
|
||||
z += 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (x == 4)
|
||||
*cp++ = 'x';
|
||||
else if (x > 0)
|
||||
*cp++ = 'X';
|
||||
else if (z == 4)
|
||||
*cp++ = 'z';
|
||||
else if (z > 0)
|
||||
*cp++ = 'Z';
|
||||
else
|
||||
*cp++ = "0123456789abcdef"[v];
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
*cp++ = '(';
|
||||
*cp++ = '?';
|
||||
*cp++ = ')';
|
||||
break;
|
||||
}
|
||||
|
||||
*cp++ = 0;
|
||||
vp->value.str = buff;
|
||||
}
|
||||
|
||||
static int string_get(int code, vpiHandle ref)
|
||||
{
|
||||
struct __vpiStringConst*rfp = (struct __vpiStringConst*)ref;
|
||||
assert(ref->vpi_type->type_code == vpiConstant);
|
||||
|
||||
switch (code) {
|
||||
case vpiConstType:
|
||||
return vpiStringConst;
|
||||
|
||||
default:
|
||||
assert(0);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
static void string_value(vpiHandle ref, p_vpi_value vp)
|
||||
{
|
||||
struct __vpiStringConst*rfp = (struct __vpiStringConst*)ref;
|
||||
assert(ref->vpi_type->type_code == vpiConstant);
|
||||
|
||||
switch (vp->format) {
|
||||
case vpiObjTypeVal:
|
||||
case vpiStringVal:
|
||||
vp->value.str = rfp->value;
|
||||
vp->format = vpiStringVal;
|
||||
break;
|
||||
|
||||
default:
|
||||
vp->format = vpiSuppressVal;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static int number_get(int code, vpiHandle ref)
|
||||
{
|
||||
struct __vpiNumberConst*rfp = (struct __vpiNumberConst*)ref;
|
||||
assert(ref->vpi_type->type_code == vpiConstant);
|
||||
|
||||
switch (code) {
|
||||
case vpiConstType:
|
||||
return vpiBinaryConst;
|
||||
|
||||
default:
|
||||
assert(0);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
static void number_value(vpiHandle ref, p_vpi_value vp)
|
||||
{
|
||||
struct __vpiNumberConst*rfp = (struct __vpiNumberConst*)ref;
|
||||
assert(ref->vpi_type->type_code == vpiConstant);
|
||||
vpip_bits_get_value(rfp->bits, rfp->nbits, vp);
|
||||
}
|
||||
|
||||
static const struct __vpirt vpip_string_rt = {
|
||||
vpiConstant,
|
||||
string_get,
|
||||
0,
|
||||
string_value,
|
||||
0,
|
||||
0
|
||||
};
|
||||
|
||||
static const struct __vpirt vpip_number_rt = {
|
||||
vpiConstant,
|
||||
number_get,
|
||||
0,
|
||||
number_value,
|
||||
0,
|
||||
0
|
||||
};
|
||||
|
||||
vpiHandle vpip_make_string_const(struct __vpiStringConst*ref, const char*val)
|
||||
{
|
||||
ref->base.vpi_type = &vpip_string_rt;
|
||||
ref->value = val;
|
||||
return &(ref->base);
|
||||
}
|
||||
|
||||
vpiHandle vpip_make_number_const(struct __vpiNumberConst*ref,
|
||||
const enum vpip_bit_t*bits,
|
||||
unsigned nbits)
|
||||
{
|
||||
ref->base.vpi_type = &vpip_number_rt;
|
||||
ref->bits = bits;
|
||||
ref->nbits = nbits;
|
||||
return &(ref->base);
|
||||
}
|
||||
|
||||
/*
|
||||
* $Log: vpi_const.c,v $
|
||||
* Revision 1.4 1999/11/06 22:16:50 steve
|
||||
* Get the $strobe task working.
|
||||
*
|
||||
* Revision 1.3 1999/11/06 16:52:16 steve
|
||||
* complete value retrieval for number constants.
|
||||
*
|
||||
* Revision 1.2 1999/11/06 16:00:18 steve
|
||||
* Put number constants into a static table.
|
||||
*
|
||||
* Revision 1.1 1999/10/28 00:47:25 steve
|
||||
* Rewrite vvm VPI support to make objects more
|
||||
* persistent, rewrite the simulation scheduler
|
||||
* in C (to interface with VPI) and add VPI support
|
||||
* for callbacks.
|
||||
*
|
||||
*/
|
||||
|
||||
@@ -0,0 +1,77 @@
|
||||
/*
|
||||
* Copyright (c) 1999 Stephen Williams (steve@icarus.com)
|
||||
*
|
||||
* This source code is free software; you can redistribute it
|
||||
* and/or modify it in source code form under the terms of the GNU
|
||||
* General Public License as published by the Free Software
|
||||
* Foundation; either version 2 of the License, or (at your option)
|
||||
* any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
|
||||
*/
|
||||
#if !defined(WINNT)
|
||||
#ident "$Id: vpi_iter.c,v 1.1 1999/10/28 00:47:25 steve Exp $"
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Find here the methods functions in support of iterator objects.
|
||||
*/
|
||||
|
||||
# include "vpi_priv.h"
|
||||
# include <stdlib.h>
|
||||
# include <assert.h>
|
||||
|
||||
static const struct __vpirt vpip_iterator_rt = {
|
||||
vpiIterator,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0
|
||||
};
|
||||
|
||||
vpiHandle vpip_make_iterator(unsigned nargs, vpiHandle*args)
|
||||
{
|
||||
struct __vpiIterator*res = calloc(1, sizeof(struct __vpiIterator));
|
||||
res->base.vpi_type = &vpip_iterator_rt;
|
||||
res->args = args;
|
||||
res->nargs = nargs;
|
||||
res->next = 0;
|
||||
|
||||
return &(res->base);
|
||||
}
|
||||
|
||||
/*
|
||||
* The vpi_scan function only applies to iterators. It returns the
|
||||
* next vpiHandle in the iterated list.
|
||||
*/
|
||||
vpiHandle vpi_scan(vpiHandle ref)
|
||||
{
|
||||
struct __vpiIterator*hp = (struct __vpiIterator*)ref;
|
||||
assert(ref->vpi_type->type_code == vpiIterator);
|
||||
|
||||
if (hp->next == hp->nargs) {
|
||||
vpi_free_object(ref);
|
||||
return 0;
|
||||
}
|
||||
|
||||
return hp->args[hp->next++];
|
||||
}
|
||||
|
||||
/*
|
||||
* $Log: vpi_iter.c,v $
|
||||
* Revision 1.1 1999/10/28 00:47:25 steve
|
||||
* Rewrite vvm VPI support to make objects more
|
||||
* persistent, rewrite the simulation scheduler
|
||||
* in C (to interface with VPI) and add VPI support
|
||||
* for callbacks.
|
||||
*
|
||||
*/
|
||||
|
||||
@@ -0,0 +1,91 @@
|
||||
/*
|
||||
* Copyright (c) 1999 Picture Elements, Inc.
|
||||
* Stephen Williams (steve@picturel.com)
|
||||
*
|
||||
* This source code is free software; you can redistribute it
|
||||
* and/or modify it in source code form under the terms of the GNU
|
||||
* General Public License as published by the Free Software
|
||||
* Foundation; either version 2 of the License, or (at your option)
|
||||
* any later version. In order to redistribute the software in
|
||||
* binary form, you will need a Picture Elements Binary Software
|
||||
* License.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
|
||||
* ---
|
||||
* You should also have recieved a copy of the Picture Elements
|
||||
* Binary Software License offer along with the source. This offer
|
||||
* allows you to obtain the right to redistribute the software in
|
||||
* binary (compiled) form. If you have not received it, contact
|
||||
* Picture Elements, Inc., 777 Panoramic Way, Berkeley, CA 94704.
|
||||
*/
|
||||
#if !defined(WINNT)
|
||||
#ident "$Id: vpi_memory.c,v 1.1 1999/11/10 02:52:24 steve Exp $"
|
||||
#endif
|
||||
|
||||
# include "vpi_priv.h"
|
||||
# include <stdlib.h>
|
||||
# include <assert.h>
|
||||
|
||||
static int memory_get(int code, vpiHandle ref)
|
||||
{
|
||||
struct __vpiMemory*rfp = (struct __vpiMemory*)ref;
|
||||
|
||||
assert(ref->vpi_type->type_code==vpiMemory);
|
||||
|
||||
switch (code) {
|
||||
case vpiSize:
|
||||
return rfp->size;
|
||||
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
static char* memory_get_str(int code, vpiHandle ref)
|
||||
{
|
||||
struct __vpiMemory*rfp = (struct __vpiMemory*)ref;
|
||||
|
||||
assert(ref->vpi_type->type_code==vpiMemory);
|
||||
|
||||
switch (code) {
|
||||
|
||||
case vpiFullName:
|
||||
return (char*)rfp->name;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct __vpirt vpip_memory_rt = {
|
||||
vpiMemory,
|
||||
memory_get,
|
||||
memory_get_str,
|
||||
0,
|
||||
0,
|
||||
0
|
||||
};
|
||||
|
||||
vpiHandle vpip_make_memory(struct __vpiMemory*ref, const char*name,
|
||||
unsigned wid, unsigned siz)
|
||||
{
|
||||
ref->base.vpi_type = &vpip_memory_rt;
|
||||
ref->name = name;
|
||||
ref->bits = calloc(wid*siz, sizeof(enum vpip_bit_t));
|
||||
ref->width = wid;
|
||||
ref->size = siz;
|
||||
return &(ref->base);
|
||||
}
|
||||
/*
|
||||
* $Log: vpi_memory.c,v $
|
||||
* Revision 1.1 1999/11/10 02:52:24 steve
|
||||
* Create the vpiMemory handle type.
|
||||
*
|
||||
*/
|
||||
|
||||
@@ -0,0 +1,47 @@
|
||||
/*
|
||||
* Copyright (c) 1999 Stephen Williams (steve@icarus.com)
|
||||
*
|
||||
* This source code is free software; you can redistribute it
|
||||
* and/or modify it in source code form under the terms of the GNU
|
||||
* General Public License as published by the Free Software
|
||||
* Foundation; either version 2 of the License, or (at your option)
|
||||
* any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
|
||||
*/
|
||||
#if !defined(WINNT)
|
||||
#ident "$Id: vpi_null.c,v 1.1 1999/10/28 00:47:25 steve Exp $"
|
||||
#endif
|
||||
|
||||
# include "vpi_priv.h"
|
||||
|
||||
static const struct __vpirt vpip_null_rt = {
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0
|
||||
};
|
||||
|
||||
struct __vpiNull vpip_null = {
|
||||
{ &vpip_null_rt }
|
||||
};
|
||||
|
||||
/*
|
||||
* $Log: vpi_null.c,v $
|
||||
* Revision 1.1 1999/10/28 00:47:25 steve
|
||||
* Rewrite vvm VPI support to make objects more
|
||||
* persistent, rewrite the simulation scheduler
|
||||
* in C (to interface with VPI) and add VPI support
|
||||
* for callbacks.
|
||||
*
|
||||
*/
|
||||
|
||||
+160
@@ -0,0 +1,160 @@
|
||||
/*
|
||||
* Copyright (c) 1999 Stephen Williams (steve@icarus.com)
|
||||
*
|
||||
* This source code is free software; you can redistribute it
|
||||
* and/or modify it in source code form under the terms of the GNU
|
||||
* General Public License as published by the Free Software
|
||||
* Foundation; either version 2 of the License, or (at your option)
|
||||
* any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
|
||||
*/
|
||||
#if !defined(WINNT)
|
||||
#ident "$Id: vpi_priv.c,v 1.1 1999/10/28 00:47:25 steve Exp $"
|
||||
#endif
|
||||
|
||||
# include "vpi_priv.h"
|
||||
# include <assert.h>
|
||||
# include <stdarg.h>
|
||||
# include <stdio.h>
|
||||
# include <stdlib.h>
|
||||
# include <string.h>
|
||||
|
||||
/*
|
||||
* Keep a list of vpi_systf_data structures. This list is searched
|
||||
* forward whenever a function is invoked by name, and items are
|
||||
* pushed in front of the list whenever they are registered. This
|
||||
* allows entries to override older entries.
|
||||
*/
|
||||
struct systf_entry {
|
||||
struct systf_entry* next;
|
||||
s_vpi_systf_data systf_data;
|
||||
};
|
||||
|
||||
static struct systf_entry*systf_list = 0;
|
||||
|
||||
/* This is the handle of the task currently being called. */
|
||||
static struct __vpiSysTaskCall*vpip_cur_task;
|
||||
|
||||
|
||||
void vpip_calltask(const char*fname, unsigned nparms, vpiHandle*parms)
|
||||
{
|
||||
struct systf_entry*idx;
|
||||
struct __vpiSysTaskCall cur_task;
|
||||
cur_task.base.vpi_type = &vpip_systask_rt;
|
||||
cur_task.args = parms;
|
||||
cur_task.nargs = nparms;
|
||||
|
||||
vpip_cur_task = &cur_task;
|
||||
|
||||
/* Look for a systf function to invoke. */
|
||||
for (idx = systf_list ; idx ; idx = idx->next)
|
||||
if (strcmp(fname, idx->systf_data.tfname) == 0) {
|
||||
cur_task.info = &idx->systf_data;
|
||||
idx->systf_data.calltf(idx->systf_data.user_data);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
/* Finally, if nothing is found then something is not
|
||||
right. Print out the function name all the parameters
|
||||
passed, so that someone can deal with it. */
|
||||
vpi_printf("Call %s\n", fname);
|
||||
}
|
||||
|
||||
|
||||
int vpi_free_object(vpiHandle ref)
|
||||
{
|
||||
free(ref);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int vpi_get(int property, vpiHandle ref)
|
||||
{
|
||||
if (property == vpiType)
|
||||
return ref->vpi_type->type_code;
|
||||
|
||||
if (ref->vpi_type->vpi_get_ == 0)
|
||||
return -1;
|
||||
|
||||
return (ref->vpi_type->vpi_get_)(property, ref);
|
||||
}
|
||||
|
||||
char* vpi_get_str(int property, vpiHandle ref)
|
||||
{
|
||||
if (ref->vpi_type->vpi_get_str_ == 0)
|
||||
return 0;
|
||||
|
||||
return (ref->vpi_type->vpi_get_str_)(property, ref);
|
||||
}
|
||||
|
||||
void vpi_get_value(vpiHandle expr, s_vpi_value*vp)
|
||||
{
|
||||
if (expr->vpi_type->vpi_get_value_) {
|
||||
(expr->vpi_type->vpi_get_value_)(expr, vp);
|
||||
return;
|
||||
}
|
||||
|
||||
vp->format = vpiSuppressVal;
|
||||
}
|
||||
|
||||
vpiHandle vpi_handle(int type, vpiHandle ref)
|
||||
{
|
||||
if (type == vpiSysTfCall) {
|
||||
assert(ref == 0);
|
||||
return &vpip_cur_task->base;
|
||||
}
|
||||
|
||||
assert(ref->vpi_type->handle_);
|
||||
return (ref->vpi_type->handle_)(type, ref);
|
||||
}
|
||||
|
||||
/*
|
||||
* This function asks the object to return an iterator for
|
||||
* the specified reference. It is up to the iterate_ method to
|
||||
* allocate a properly formed iterator.
|
||||
*/
|
||||
vpiHandle vpi_iterate(int type, vpiHandle ref)
|
||||
{
|
||||
assert(ref->vpi_type->iterate_);
|
||||
return (ref->vpi_type->iterate_)(type, ref);
|
||||
}
|
||||
|
||||
void vpi_printf(const char*fmt, ...)
|
||||
{
|
||||
va_list ap;
|
||||
va_start(ap, fmt);
|
||||
vprintf(fmt, ap);
|
||||
va_end(ap);
|
||||
}
|
||||
|
||||
/*
|
||||
* This function adds the information that the user supplies to a list
|
||||
* that I keep.
|
||||
*/
|
||||
void vpi_register_systf(const struct t_vpi_systf_data*systf)
|
||||
{
|
||||
struct systf_entry*cur = calloc(1, sizeof(struct systf_entry));
|
||||
cur->systf_data = *systf;
|
||||
cur->systf_data.tfname = strdup(systf->tfname);
|
||||
cur->next = systf_list;
|
||||
systf_list = cur;
|
||||
}
|
||||
|
||||
/*
|
||||
* $Log: vpi_priv.c,v $
|
||||
* Revision 1.1 1999/10/28 00:47:25 steve
|
||||
* Rewrite vvm VPI support to make objects more
|
||||
* persistent, rewrite the simulation scheduler
|
||||
* in C (to interface with VPI) and add VPI support
|
||||
* for callbacks.
|
||||
*
|
||||
*/
|
||||
|
||||
+306
@@ -0,0 +1,306 @@
|
||||
#ifndef __vpi_priv_H
|
||||
#define __vpi_priv_H
|
||||
/*
|
||||
* 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.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 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 {
|
||||
const struct __vpirt *vpi_type;
|
||||
};
|
||||
|
||||
/*
|
||||
* 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;
|
||||
|
||||
/* 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);
|
||||
|
||||
/* These methods follow references. */
|
||||
vpiHandle (*handle_)(int, vpiHandle);
|
||||
vpiHandle (*iterate_)(int, vpiHandle);
|
||||
};
|
||||
|
||||
/*
|
||||
* 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;
|
||||
|
||||
struct vpip_event*ev;
|
||||
struct __vpiCallback*next;
|
||||
};
|
||||
|
||||
/*
|
||||
* 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;
|
||||
};
|
||||
|
||||
|
||||
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
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
* $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.
|
||||
*
|
||||
*/
|
||||
#endif
|
||||
@@ -0,0 +1,86 @@
|
||||
/*
|
||||
* Copyright (c) 1999 Stephen Williams (steve@icarus.com)
|
||||
*
|
||||
* This source code is free software; you can redistribute it
|
||||
* and/or modify it in source code form under the terms of the GNU
|
||||
* General Public License as published by the Free Software
|
||||
* Foundation; either version 2 of the License, or (at your option)
|
||||
* any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
|
||||
*/
|
||||
#if !defined(WINNT)
|
||||
#ident "$Id: vpi_scope.c,v 1.2 1999/11/28 00:56:08 steve Exp $"
|
||||
#endif
|
||||
|
||||
# include "vpi_priv.h"
|
||||
# include <stdlib.h>
|
||||
# include <assert.h>
|
||||
|
||||
static vpiHandle module_iter(int code, vpiHandle obj)
|
||||
{
|
||||
struct __vpiScope*ref = (struct __vpiScope*)obj;
|
||||
assert(obj->vpi_type->type_code == vpiModule);
|
||||
|
||||
switch (code) {
|
||||
case vpiInternalScope:
|
||||
return vpip_make_iterator(ref->nintern, ref->intern);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct __vpirt vpip_module_rt = {
|
||||
vpiModule,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
module_iter
|
||||
};
|
||||
|
||||
vpiHandle vpip_make_scope(struct __vpiScope*ref, int type, const char*name)
|
||||
{
|
||||
ref->intern = 0;
|
||||
ref->nintern = 0;
|
||||
|
||||
switch (type) {
|
||||
case vpiModule:
|
||||
ref->base.vpi_type = &vpip_module_rt;
|
||||
break;
|
||||
default:
|
||||
assert(0);
|
||||
}
|
||||
|
||||
return &ref->base;
|
||||
}
|
||||
|
||||
void vpip_attach_to_scope(struct __vpiScope*ref, vpiHandle obj)
|
||||
{
|
||||
unsigned idx = ref->nintern++;
|
||||
|
||||
if (ref->intern == 0)
|
||||
ref->intern = malloc(sizeof(vpiHandle));
|
||||
else
|
||||
ref->intern = realloc(ref->intern, sizeof(vpiHandle)*ref->nintern);
|
||||
|
||||
ref->intern[idx] = obj;
|
||||
}
|
||||
|
||||
/*
|
||||
* $Log: vpi_scope.c,v $
|
||||
* Revision 1.2 1999/11/28 00:56:08 steve
|
||||
* Build up the lists in the scope of a module,
|
||||
* and get $dumpvars to scan the scope for items.
|
||||
*
|
||||
* Revision 1.1 1999/11/27 19:07:58 steve
|
||||
* Support the creation of scopes.
|
||||
*
|
||||
*/
|
||||
|
||||
@@ -0,0 +1,123 @@
|
||||
/*
|
||||
* Copyright (c) 1999 Stephen Williams (steve@icarus.com)
|
||||
*
|
||||
* This source code is free software; you can redistribute it
|
||||
* and/or modify it in source code form under the terms of the GNU
|
||||
* General Public License as published by the Free Software
|
||||
* Foundation; either version 2 of the License, or (at your option)
|
||||
* any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
|
||||
*/
|
||||
#if !defined(WINNT)
|
||||
#ident "$Id: vpi_signal.c,v 1.5 1999/11/07 20:33:30 steve Exp $"
|
||||
#endif
|
||||
|
||||
# include "vpi_priv.h"
|
||||
# include <assert.h>
|
||||
|
||||
|
||||
static int signal_get(int code, vpiHandle ref)
|
||||
{
|
||||
struct __vpiSignal*rfp = (struct __vpiSignal*)ref;
|
||||
|
||||
assert((ref->vpi_type->type_code==vpiNet)
|
||||
|| (ref->vpi_type->type_code==vpiReg));
|
||||
|
||||
switch (code) {
|
||||
case vpiSize:
|
||||
return rfp->nbits;
|
||||
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
static char* signal_get_str(int code, vpiHandle ref)
|
||||
{
|
||||
struct __vpiSignal*rfp = (struct __vpiSignal*)ref;
|
||||
|
||||
assert((ref->vpi_type->type_code==vpiNet)
|
||||
|| (ref->vpi_type->type_code==vpiReg));
|
||||
|
||||
switch (code) {
|
||||
|
||||
case vpiFullName:
|
||||
return (char*)rfp->name;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void signal_get_value(vpiHandle ref, s_vpi_value*vp)
|
||||
{
|
||||
struct __vpiSignal*rfp = (struct __vpiSignal*)ref;
|
||||
assert((ref->vpi_type->type_code==vpiNet)
|
||||
|| (ref->vpi_type->type_code==vpiReg));
|
||||
|
||||
vpip_bits_get_value(rfp->bits, rfp->nbits, vp);
|
||||
}
|
||||
|
||||
static const struct __vpirt vpip_net_rt = {
|
||||
vpiNet,
|
||||
signal_get,
|
||||
signal_get_str,
|
||||
signal_get_value,
|
||||
0,
|
||||
0
|
||||
};
|
||||
|
||||
vpiHandle vpip_make_net(struct __vpiSignal*ref, const char*name)
|
||||
{
|
||||
ref->base.vpi_type = &vpip_net_rt;
|
||||
ref->name = name;
|
||||
ref->monitor = 0;
|
||||
return &(ref->base);
|
||||
}
|
||||
|
||||
static const struct __vpirt vpip_reg_rt = {
|
||||
vpiReg,
|
||||
signal_get,
|
||||
signal_get_str,
|
||||
signal_get_value,
|
||||
0,
|
||||
0
|
||||
};
|
||||
|
||||
vpiHandle vpip_make_reg(struct __vpiSignal*ref, const char*name)
|
||||
{
|
||||
ref->base.vpi_type = &vpip_reg_rt;
|
||||
ref->name = name;
|
||||
ref->monitor = 0;
|
||||
return &(ref->base);
|
||||
}
|
||||
|
||||
/*
|
||||
* $Log: vpi_signal.c,v $
|
||||
* Revision 1.5 1999/11/07 20:33:30 steve
|
||||
* Add VCD output and related system tasks.
|
||||
*
|
||||
* Revision 1.4 1999/11/07 02:25:08 steve
|
||||
* Add the $monitor implementation.
|
||||
*
|
||||
* Revision 1.3 1999/11/06 16:52:16 steve
|
||||
* complete value retrieval for number constants.
|
||||
*
|
||||
* Revision 1.2 1999/10/29 03:37:22 steve
|
||||
* Support vpiValueChance callbacks.
|
||||
*
|
||||
* Revision 1.1 1999/10/28 00:47:25 steve
|
||||
* Rewrite vvm VPI support to make objects more
|
||||
* persistent, rewrite the simulation scheduler
|
||||
* in C (to interface with VPI) and add VPI support
|
||||
* for callbacks.
|
||||
*
|
||||
*/
|
||||
|
||||
@@ -0,0 +1,205 @@
|
||||
/*
|
||||
* Copyright (c) 1999 Stephen Williams (steve@icarus.com)
|
||||
*
|
||||
* This source code is free software; you can redistribute it
|
||||
* and/or modify it in source code form under the terms of the GNU
|
||||
* General Public License as published by the Free Software
|
||||
* Foundation; either version 2 of the License, or (at your option)
|
||||
* any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
|
||||
*/
|
||||
#if !defined(WINNT)
|
||||
#ident "$Id: vpi_simulation.c,v 1.1 1999/10/28 00:47:25 steve Exp $"
|
||||
#endif
|
||||
|
||||
# include "vpi_priv.h"
|
||||
# include <stdlib.h>
|
||||
# include <assert.h>
|
||||
|
||||
struct vpip_event {
|
||||
void*user_data;
|
||||
void (*sim_fun)(void*);
|
||||
struct vpip_event*next;
|
||||
};
|
||||
|
||||
struct vpip_simulation vpip_simulation_obj;
|
||||
|
||||
void vpi_sim_control(int func, ...)
|
||||
{
|
||||
switch (func) {
|
||||
case vpiFinish:
|
||||
vpip_simulation_obj.going_flag = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* The simulation event queue is a list of simulation cycles that in
|
||||
* turn contain lists of simulation events. The simulation cycle
|
||||
* represents the happening at some simulation time.
|
||||
*/
|
||||
struct vpip_simulation_cycle {
|
||||
unsigned long delay;
|
||||
|
||||
struct vpip_simulation_cycle*next;
|
||||
struct vpip_simulation_cycle*prev;
|
||||
|
||||
struct vpip_event*event_list;
|
||||
struct vpip_event*event_last;
|
||||
struct vpip_event*nonblock_list;
|
||||
struct vpip_event*nonblock_last;
|
||||
};
|
||||
|
||||
void vpip_init_simulation()
|
||||
{
|
||||
struct vpip_simulation_cycle*cur;
|
||||
|
||||
vpip_make_time_var(&vpip_simulation_obj.sim_time, "$time");
|
||||
vpip_simulation_obj.read_sync_list = 0;
|
||||
|
||||
/* Allocate a header cell for the simulation event list. */
|
||||
cur = calloc(1, sizeof(struct vpip_simulation_cycle));
|
||||
cur->delay = 0;
|
||||
cur->next = cur->prev = cur;
|
||||
vpip_simulation_obj.sim = cur;
|
||||
}
|
||||
|
||||
vpiHandle vpip_sim_time()
|
||||
{
|
||||
return &vpip_simulation_obj.sim_time.base;
|
||||
}
|
||||
|
||||
struct vpip_event* vpip_sim_insert_event(unsigned long delay,
|
||||
void*user_data,
|
||||
void (*sim_fun)(void*),
|
||||
int nonblock_flag)
|
||||
{
|
||||
struct vpip_event*event;
|
||||
struct vpip_simulation_cycle*cur;
|
||||
|
||||
event = calloc(1, sizeof(struct vpip_event));
|
||||
event->user_data = user_data;
|
||||
event->sim_fun = sim_fun;
|
||||
|
||||
cur = vpip_simulation_obj.sim->next;
|
||||
while ((cur != vpip_simulation_obj.sim) && (cur->delay < delay)) {
|
||||
delay -= cur->delay;
|
||||
cur = cur->next;
|
||||
}
|
||||
|
||||
/* If there is no cycle cell for the specified time, create one. */
|
||||
if ((cur == vpip_simulation_obj.sim) || (cur->delay > delay)) {
|
||||
struct vpip_simulation_cycle*cell
|
||||
= calloc(1,sizeof(struct vpip_simulation_cycle));
|
||||
cell->delay = delay;
|
||||
if (cur != vpip_simulation_obj.sim)
|
||||
cur->delay -= delay;
|
||||
cell->next = cur;
|
||||
cell->prev = cur->prev;
|
||||
cell->next->prev = cell;
|
||||
cell->prev->next = cell;
|
||||
cur = cell;
|
||||
}
|
||||
|
||||
/* Put the event into the end of the cycle list. */
|
||||
event->next = 0;
|
||||
if (nonblock_flag) {
|
||||
if (cur->nonblock_list == 0) {
|
||||
cur->nonblock_list = cur->nonblock_last = event;
|
||||
|
||||
} else {
|
||||
cur->nonblock_last->next = event;
|
||||
cur->nonblock_last = event;
|
||||
}
|
||||
} else {
|
||||
if (cur->event_list == 0) {
|
||||
cur->event_list = cur->event_last = event;
|
||||
|
||||
} else {
|
||||
cur->event_last->next = event;
|
||||
cur->event_last = event;
|
||||
}
|
||||
}
|
||||
|
||||
return event;
|
||||
}
|
||||
|
||||
void vpip_sim_cancel_event(struct vpip_event*ev)
|
||||
{
|
||||
assert(0);
|
||||
}
|
||||
|
||||
int vpip_finished()
|
||||
{
|
||||
return ! vpip_simulation_obj.going_flag;
|
||||
}
|
||||
|
||||
void vpip_simulation_run()
|
||||
{
|
||||
vpip_simulation_obj.sim_time.time = 0;
|
||||
vpip_simulation_obj.going_flag = !0;
|
||||
|
||||
while (vpip_simulation_obj.going_flag) {
|
||||
struct vpip_simulation_cycle*sim = vpip_simulation_obj.sim;
|
||||
|
||||
/* Step the time forward to the next time cycle. */
|
||||
vpip_simulation_obj.sim_time.time += sim->delay;
|
||||
sim->delay = 0;
|
||||
|
||||
while (vpip_simulation_obj.going_flag) {
|
||||
struct vpip_event*active = sim->event_list;
|
||||
sim->event_list = 0;
|
||||
sim->event_last = 0;
|
||||
|
||||
if (active == 0) {
|
||||
active = sim->nonblock_list;
|
||||
sim->nonblock_list = 0;
|
||||
sim->nonblock_last = 0;
|
||||
}
|
||||
|
||||
if (active == 0)
|
||||
break;
|
||||
|
||||
while (active && vpip_simulation_obj.going_flag) {
|
||||
struct vpip_event*cur = active;
|
||||
active = cur->next;
|
||||
(cur->sim_fun)(cur->user_data);
|
||||
free(cur);
|
||||
}
|
||||
}
|
||||
|
||||
if (! vpip_simulation_obj.going_flag)
|
||||
break;
|
||||
|
||||
{ struct vpip_simulation_cycle*next = sim->next;
|
||||
if (next == sim) {
|
||||
vpip_simulation_obj.going_flag = 0;
|
||||
break;
|
||||
}
|
||||
sim->next->prev = sim->prev;
|
||||
sim->prev->next = sim->next;
|
||||
free(sim);
|
||||
vpip_simulation_obj.sim = next;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* $Log: vpi_simulation.c,v $
|
||||
* Revision 1.1 1999/10/28 00:47:25 steve
|
||||
* Rewrite vvm VPI support to make objects more
|
||||
* persistent, rewrite the simulation scheduler
|
||||
* in C (to interface with VPI) and add VPI support
|
||||
* for callbacks.
|
||||
*
|
||||
*/
|
||||
|
||||
@@ -0,0 +1,56 @@
|
||||
/*
|
||||
* Copyright (c) 1999 Stephen Williams (steve@icarus.com)
|
||||
*
|
||||
* This source code is free software; you can redistribute it
|
||||
* and/or modify it in source code form under the terms of the GNU
|
||||
* General Public License as published by the Free Software
|
||||
* Foundation; either version 2 of the License, or (at your option)
|
||||
* any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
|
||||
*/
|
||||
#if !defined(WINNT)
|
||||
#ident "$Id: vpi_systask.c,v 1.1 1999/10/28 00:47:25 steve Exp $"
|
||||
#endif
|
||||
|
||||
# include "vpi_priv.h"
|
||||
# include <stdlib.h>
|
||||
# include <assert.h>
|
||||
|
||||
static vpiHandle systask_iter(int type, vpiHandle ref)
|
||||
{
|
||||
struct __vpiSysTaskCall*rfp = (struct __vpiSysTaskCall*)ref;
|
||||
assert(ref->vpi_type->type_code == vpiSysTaskCall);
|
||||
|
||||
if (rfp->nargs == 0)
|
||||
return 0;
|
||||
|
||||
return vpip_make_iterator(rfp->nargs, rfp->args);
|
||||
}
|
||||
|
||||
const struct __vpirt vpip_systask_rt = {
|
||||
vpiSysTaskCall,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
systask_iter
|
||||
};
|
||||
|
||||
/*
|
||||
* $Log: vpi_systask.c,v $
|
||||
* Revision 1.1 1999/10/28 00:47:25 steve
|
||||
* Rewrite vvm VPI support to make objects more
|
||||
* persistent, rewrite the simulation scheduler
|
||||
* in C (to interface with VPI) and add VPI support
|
||||
* for callbacks.
|
||||
*
|
||||
*/
|
||||
|
||||
@@ -0,0 +1,84 @@
|
||||
/*
|
||||
* Copyright (c) 1999 Stephen Williams (steve@icarus.com)
|
||||
*
|
||||
* This source code is free software; you can redistribute it
|
||||
* and/or modify it in source code form under the terms of the GNU
|
||||
* General Public License as published by the Free Software
|
||||
* Foundation; either version 2 of the License, or (at your option)
|
||||
* any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
|
||||
*/
|
||||
#if !defined(WINNT)
|
||||
#ident "$Id: vpi_time.c,v 1.1 1999/10/28 00:47:25 steve Exp $"
|
||||
#endif
|
||||
|
||||
# include "vpi_priv.h"
|
||||
# include <assert.h>
|
||||
# include <stdio.h>
|
||||
|
||||
/*
|
||||
* IEEE-1364 VPI pretty much mandates the existance of this sort of
|
||||
* thing. (Either this or a huge memory leak.) Sorry.
|
||||
*/
|
||||
static char buf_obj[128];
|
||||
|
||||
static void timevar_get_value(vpiHandle ref, s_vpi_value*vp)
|
||||
{
|
||||
struct __vpiTimeVar*rfp = (struct __vpiTimeVar*)ref;
|
||||
assert(ref->vpi_type->type_code == vpiTimeVar);
|
||||
|
||||
switch (vp->format) {
|
||||
case vpiObjTypeVal:
|
||||
case vpiTimeVal:
|
||||
rfp->time_obj.low = rfp->time;
|
||||
vp->value.time = &rfp->time_obj;
|
||||
vp->format = vpiTimeVal;
|
||||
break;
|
||||
|
||||
case vpiDecStrVal:
|
||||
sprintf(buf_obj, "%lu", rfp->time);
|
||||
vp->value.str = buf_obj;
|
||||
break;
|
||||
|
||||
default:
|
||||
vp->format = vpiSuppressVal;
|
||||
vp->value.str = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static const struct __vpirt vpip_time_var_rt = {
|
||||
vpiTimeVar,
|
||||
0,
|
||||
0,
|
||||
timevar_get_value,
|
||||
0,
|
||||
0
|
||||
};
|
||||
|
||||
vpiHandle vpip_make_time_var(struct __vpiTimeVar*ref, const char*val)
|
||||
{
|
||||
ref->base.vpi_type = &vpip_time_var_rt;
|
||||
ref->name = val;
|
||||
return &(ref->base);
|
||||
}
|
||||
|
||||
/*
|
||||
* $Log: vpi_time.c,v $
|
||||
* Revision 1.1 1999/10/28 00:47:25 steve
|
||||
* Rewrite vvm VPI support to make objects more
|
||||
* persistent, rewrite the simulation scheduler
|
||||
* in C (to interface with VPI) and add VPI support
|
||||
* for callbacks.
|
||||
*
|
||||
*/
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
#ifndef __vvm_H
|
||||
#define __vvm_H
|
||||
/*
|
||||
* Copyright (c) 1998 Stephen Williams (steve@icarus.com)
|
||||
* Copyright (c) 1998-1999 Stephen Williams (steve@icarus.com)
|
||||
*
|
||||
* This source code is free software; you can redistribute it
|
||||
* and/or modify it in source code form under the terms of the GNU
|
||||
@@ -19,12 +19,11 @@
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
|
||||
*/
|
||||
#if !defined(WINNT)
|
||||
#ident "$Id: vvm.h,v 1.9 1999/06/21 01:02:34 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,9 +74,18 @@ inline vvm_bit_t less_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);
|
||||
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;
|
||||
if (l > r) return V1;
|
||||
if (l < r) return V0;
|
||||
return c;
|
||||
}
|
||||
|
||||
inline vvm_bit_t not(vvm_bit_t l)
|
||||
extern vpip_bit_t add_with_carry(vpip_bit_t l, vpip_bit_t r, vpip_bit_t&carry);
|
||||
|
||||
inline vpip_bit_t not(vpip_bit_t l)
|
||||
{
|
||||
switch (l) {
|
||||
case V0:
|
||||
@@ -94,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.
|
||||
@@ -115,33 +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_bit_t operator[] (unsigned idx) const { return bits_[idx]; }
|
||||
vvm_bit_t&operator[] (unsigned idx) { return bits_[idx]; }
|
||||
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);
|
||||
for (unsigned idx = wid ; idx < WIDTH ; idx += 1)
|
||||
bits[idx] = V0;
|
||||
}
|
||||
|
||||
|
||||
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]; }
|
||||
|
||||
bool eequal(const vvm_bitset_t<WIDTH>&that) const
|
||||
{ for (unsigned idx = 0 ; idx < WIDTH ; idx += 1)
|
||||
if (bits_[idx] != that.bits_[idx])
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
private:
|
||||
vvm_bit_t bits_[WIDTH];
|
||||
public:
|
||||
vpip_bit_t bits[WIDTH];
|
||||
};
|
||||
|
||||
/*
|
||||
@@ -154,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&);
|
||||
@@ -205,18 +213,7 @@ class vvm_simulation {
|
||||
// only one event can be a monitor.
|
||||
void monitor_event(vvm_event*);
|
||||
|
||||
unsigned long get_sim_time() const { return time_; }
|
||||
|
||||
void s_finish();
|
||||
|
||||
private:
|
||||
bool going_;
|
||||
vvm_simulation_cycle*sim_;
|
||||
|
||||
// Triggered monitor event.
|
||||
vvm_event*mon_;
|
||||
|
||||
unsigned long time_;
|
||||
bool finished() const;
|
||||
|
||||
private: // not implemented
|
||||
vvm_simulation(const vvm_simulation&);
|
||||
@@ -224,62 +221,131 @@ class 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 string&);
|
||||
|
||||
void trigger(vvm_simulation*sim)
|
||||
{ if (event_) sim->monitor_event(event_); }
|
||||
|
||||
const string& name() const { return name_; }
|
||||
|
||||
void enable(vvm_event*e) { event_ = e; }
|
||||
|
||||
private:
|
||||
string 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 string&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.
|
||||
*
|
||||
* Revision 1.13 1999/10/05 04:02:10 steve
|
||||
* Relaxed width handling for <= assignment.
|
||||
*
|
||||
* Revision 1.12 1999/09/29 18:36:04 steve
|
||||
* Full case support
|
||||
*
|
||||
* Revision 1.11 1999/09/28 01:13:15 steve
|
||||
* Support in vvm > and >= behavioral operators.
|
||||
*
|
||||
* Revision 1.10 1999/08/15 01:23:56 steve
|
||||
* Convert vvm to implement system tasks with vpi.
|
||||
*
|
||||
* Revision 1.9 1999/06/21 01:02:34 steve
|
||||
* Add init to vvm_signal_t.
|
||||
*
|
||||
|
||||
+65
-3
@@ -17,12 +17,13 @@
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
|
||||
*/
|
||||
#if !defined(WINNT)
|
||||
#ident "$Id: vvm_bit.cc,v 1.2 1998/11/10 00:48:31 steve Exp $"
|
||||
#ident "$Id: vvm_bit.cc,v 1.7 1999/12/02 03:36:01 steve Exp $"
|
||||
#endif
|
||||
|
||||
# include "vvm.h"
|
||||
# include <iostream>
|
||||
|
||||
ostream& operator << (ostream&os, vvm_bit_t bit)
|
||||
ostream& operator << (ostream&os, vpip_bit_t bit)
|
||||
{
|
||||
switch (bit) {
|
||||
case V0:
|
||||
@@ -41,6 +42,20 @@ ostream& operator << (ostream&os, vvm_bit_t bit)
|
||||
return os;
|
||||
}
|
||||
|
||||
bool posedge(vpip_bit_t from, vpip_bit_t to)
|
||||
{
|
||||
switch (from) {
|
||||
case V1:
|
||||
return false;
|
||||
case V0:
|
||||
return from != to;
|
||||
case Vx:
|
||||
case Vz:
|
||||
return to == V1;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
ostream& operator << (ostream&os, const vvm_bits_t&str)
|
||||
{
|
||||
os << str.get_width() << "b'";
|
||||
@@ -54,7 +69,34 @@ vvm_bits_t::~vvm_bits_t()
|
||||
{
|
||||
}
|
||||
|
||||
vvm_bit_t add_with_carry(vvm_bit_t l, vvm_bit_t r, vvm_bit_t&carry)
|
||||
unsigned vvm_bits_t::as_unsigned() const
|
||||
{
|
||||
unsigned result = 0;
|
||||
unsigned width = get_width();
|
||||
for (unsigned idx = width ; idx > 0 ; idx -= 1) {
|
||||
result <<= 1;
|
||||
switch (get_bit(idx-1)) {
|
||||
case V0:
|
||||
case Vx:
|
||||
case Vz:
|
||||
break;
|
||||
case V1:
|
||||
result |= 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
vvm_ram_callback::vvm_ram_callback()
|
||||
{
|
||||
}
|
||||
|
||||
vvm_ram_callback::~vvm_ram_callback()
|
||||
{
|
||||
}
|
||||
|
||||
vpip_bit_t add_with_carry(vpip_bit_t l, vpip_bit_t r, vpip_bit_t&carry)
|
||||
{
|
||||
unsigned li, ri, ci;
|
||||
switch (l) {
|
||||
@@ -100,6 +142,26 @@ vvm_bit_t add_with_carry(vvm_bit_t l, vvm_bit_t r, vvm_bit_t&carry)
|
||||
|
||||
/*
|
||||
* $Log: vvm_bit.cc,v $
|
||||
* Revision 1.7 1999/12/02 03:36:01 steve
|
||||
* shiftl and shiftr take unsized second parameter.
|
||||
*
|
||||
* Revision 1.6 1999/11/22 00:30:52 steve
|
||||
* Detemplate some and, or and nor methods.
|
||||
*
|
||||
* Revision 1.5 1999/11/21 00:13:09 steve
|
||||
* Support memories in continuous assignments.
|
||||
*
|
||||
* Revision 1.4 1999/11/01 02:07:41 steve
|
||||
* Add the synth functor to do generic synthesis
|
||||
* and add the LPM_FF device to handle rows of
|
||||
* flip-flops.
|
||||
*
|
||||
* Revision 1.3 1999/10/28 00:47:25 steve
|
||||
* Rewrite vvm VPI support to make objects more
|
||||
* persistent, rewrite the simulation scheduler
|
||||
* in C (to interface with VPI) and add VPI support
|
||||
* for callbacks.
|
||||
*
|
||||
* Revision 1.2 1998/11/10 00:48:31 steve
|
||||
* Add support it vvm target for level-sensitive
|
||||
* triggers (i.e. the Verilog wait).
|
||||
|
||||
+113
-136
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* 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
|
||||
@@ -17,153 +17,130 @@
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
|
||||
*/
|
||||
#if !defined(WINNT)
|
||||
#ident "$Id: vvm_calltf.cc,v 1.2 1999/05/31 15:46:36 steve Exp $"
|
||||
#ident "$Id: vvm_calltf.cc,v 1.9 1999/11/28 18:05:37 steve Exp $"
|
||||
#endif
|
||||
|
||||
# include "vvm_calltf.h"
|
||||
# include <vpi_user.h>
|
||||
# include "vpi_priv.h"
|
||||
# include <new>
|
||||
# include <iostream>
|
||||
# include <assert.h>
|
||||
# include <stdlib.h>
|
||||
# include <stdarg.h>
|
||||
# include <malloc.h>
|
||||
# include <stdio.h>
|
||||
# include <dlfcn.h>
|
||||
|
||||
vvm_calltf_parm::vvm_calltf_parm()
|
||||
: type_(NONE)
|
||||
# define MAX_PATHLEN 1024
|
||||
|
||||
static char*module_path = 0;
|
||||
|
||||
void vvm_set_module_path(const char*path)
|
||||
{
|
||||
}
|
||||
|
||||
vvm_calltf_parm::vvm_calltf_parm(TYPE t)
|
||||
: type_(t)
|
||||
{
|
||||
assert((t == NONE) || (t == TIME));
|
||||
}
|
||||
|
||||
void vvm_calltf_parm::release_()
|
||||
{
|
||||
switch (type_) {
|
||||
case NONE:
|
||||
case TIME:
|
||||
case ULONG:
|
||||
break;
|
||||
case STRING:
|
||||
((string*)string_)->string::~string();
|
||||
break;
|
||||
case BITS:
|
||||
break;
|
||||
}
|
||||
type_ = NONE;
|
||||
}
|
||||
|
||||
vvm_calltf_parm& vvm_calltf_parm::operator= (unsigned long val)
|
||||
{
|
||||
release_();
|
||||
type_ = ULONG;
|
||||
ulong_ = val;
|
||||
return *this;
|
||||
}
|
||||
|
||||
vvm_calltf_parm& vvm_calltf_parm::operator= (const string&val)
|
||||
{
|
||||
release_();
|
||||
type_ = STRING;
|
||||
new (string_) string (val);
|
||||
return *this;
|
||||
}
|
||||
|
||||
vvm_calltf_parm& vvm_calltf_parm::operator= (const vvm_calltf_parm::SIG&val)
|
||||
{
|
||||
release_();
|
||||
type_ = BITS;
|
||||
bits_ = val;
|
||||
return *this;
|
||||
}
|
||||
|
||||
vvm_calltf_parm& vvm_calltf_parm::operator= (const vvm_calltf_parm&that)
|
||||
{
|
||||
if (this == &that)
|
||||
return *this;
|
||||
|
||||
release_();
|
||||
switch (that.type_) {
|
||||
case NONE:
|
||||
case TIME:
|
||||
type_ = that.type_;
|
||||
break;
|
||||
case ULONG:
|
||||
type_ = ULONG;
|
||||
ulong_ = that.ulong_;
|
||||
break;
|
||||
case STRING:
|
||||
type_ = STRING;
|
||||
new (string_) string (that.as_string());
|
||||
break;
|
||||
case BITS:
|
||||
type_ = BITS;
|
||||
bits_ = that.bits_;
|
||||
break;
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
vvm_calltf_parm::~vvm_calltf_parm()
|
||||
{
|
||||
release_();
|
||||
}
|
||||
|
||||
extern void Sdisplay(vvm_simulation*sim, const string&name,
|
||||
unsigned nparms, class vvm_calltf_parm*parms);
|
||||
extern void Smonitor(vvm_simulation*sim, const string&name,
|
||||
unsigned nparms, class vvm_calltf_parm*parms);
|
||||
|
||||
static void Sfinish(vvm_simulation*sim, const string&,
|
||||
unsigned, class vvm_calltf_parm*)
|
||||
{
|
||||
sim->s_finish();
|
||||
}
|
||||
|
||||
static struct {
|
||||
const string name;
|
||||
void (*func)(vvm_simulation*, const string&,
|
||||
unsigned, class vvm_calltf_parm*);
|
||||
} sys_table[] = {
|
||||
{ "$display", &Sdisplay },
|
||||
{ "$finish", &Sfinish },
|
||||
{ "$monitor", &Smonitor },
|
||||
{ "", 0 }
|
||||
};
|
||||
|
||||
void vvm_calltask(vvm_simulation*sim, const string&fname,
|
||||
unsigned nparms, class vvm_calltf_parm*parms)
|
||||
{
|
||||
|
||||
for (unsigned idx = 0 ; sys_table[idx].func ; idx += 1)
|
||||
if (fname == sys_table[idx].name) {
|
||||
sys_table[idx].func(sim, fname, nparms, parms);
|
||||
return;
|
||||
}
|
||||
|
||||
cout << "Call " << fname << "(";
|
||||
for (unsigned idx = 0 ; idx < nparms ; idx += 1) {
|
||||
if (idx > 0) cout << ", ";
|
||||
switch (parms[idx].type()) {
|
||||
case vvm_calltf_parm::NONE:
|
||||
break;
|
||||
case vvm_calltf_parm::ULONG:
|
||||
cout << parms[idx].as_ulong();
|
||||
break;
|
||||
case vvm_calltf_parm::STRING:
|
||||
cout << "\"" << parms[idx].as_string() << "\"";
|
||||
break;
|
||||
case vvm_calltf_parm::BITS:
|
||||
cout << *parms[idx].as_bits();
|
||||
break;
|
||||
case vvm_calltf_parm::TIME:
|
||||
break;
|
||||
}
|
||||
}
|
||||
cout << ")" << endl;
|
||||
if (module_path) free(module_path);
|
||||
module_path = strdup(path);
|
||||
}
|
||||
|
||||
/*
|
||||
* The load_vpi_module function attempts to locate and load the named
|
||||
* vpi module and call the included startup routines. This is invoked
|
||||
* by the generated C++ code to load all the modules that the
|
||||
* simulation requires.
|
||||
*
|
||||
* If there is a '/' character in the name, or there is no
|
||||
* VPI_MODULE_PATH, the the name is usd as is. No path is searched for
|
||||
* the module.
|
||||
*
|
||||
* If there is a VPI_MODULE_PATH and there is no '/' in the name, the
|
||||
* VPI_MODULE_PATH is taken as a ':' separated list of directory
|
||||
* names. Each directory is searched for a module with the right name
|
||||
* that will link in. The current working directory is not implicitly
|
||||
* tried. If you wish '.' be in th search path, include it.
|
||||
*/
|
||||
typedef void (*vlog_startup_routines_t)(void);
|
||||
|
||||
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);
|
||||
if (mod == 0) {
|
||||
cerr << name << ": " << dlerror() << endl;
|
||||
return;
|
||||
}
|
||||
|
||||
} else {
|
||||
const char*cur = path;
|
||||
const char*ep;
|
||||
for (cur = path ; cur ; cur = ep? ep+1 : 0) {
|
||||
char dest[MAX_PATHLEN+1];
|
||||
|
||||
ep = strchr(cur, ':');
|
||||
size_t n = ep? ep-cur : strlen(cur);
|
||||
if ((n + strlen(name) + 2) > sizeof dest)
|
||||
continue;
|
||||
|
||||
strncpy(dest, cur, n);
|
||||
dest[n] = '/';
|
||||
dest[n+1] = 0;
|
||||
strcat(dest, name);
|
||||
|
||||
mod = dlopen(dest, RTLD_NOW);
|
||||
if (mod) break;
|
||||
}
|
||||
}
|
||||
|
||||
if (mod == 0) {
|
||||
cerr << dlerror() << endl;
|
||||
return;
|
||||
}
|
||||
|
||||
void*table = dlsym(mod, "vlog_startup_routines");
|
||||
vlog_startup_routines_t*routines = (vlog_startup_routines_t*)table;
|
||||
if (routines == 0) {
|
||||
cerr << name << ": Unable to locate the vlog_startup_routines"
|
||||
" table." << endl;
|
||||
dlclose(mod);
|
||||
return;
|
||||
}
|
||||
|
||||
for (unsigned idx = 0 ; routines[idx] ; idx += 1)
|
||||
(routines[idx])();
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*
|
||||
* $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.
|
||||
*
|
||||
* Revision 1.5 1999/09/13 03:08:10 steve
|
||||
* fix vpiHexStrVal dumping of digits to strings.
|
||||
*
|
||||
* Revision 1.4 1999/08/19 02:51:11 steve
|
||||
* Add vpi_sim_control
|
||||
*
|
||||
* Revision 1.3 1999/08/15 01:23:56 steve
|
||||
* Convert vvm to implement system tasks with vpi.
|
||||
*
|
||||
* Revision 1.2 1999/05/31 15:46:36 steve
|
||||
* Handle time in more places.
|
||||
*
|
||||
|
||||
+17
-52
@@ -19,69 +19,34 @@
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
|
||||
*/
|
||||
#if !defined(WINNT)
|
||||
#ident "$Id: vvm_calltf.h,v 1.1 1998/11/09 23:44:11 steve Exp $"
|
||||
#ident "$Id: vvm_calltf.h,v 1.4 1999/11/28 18:05:37 steve Exp $"
|
||||
#endif
|
||||
|
||||
# include "vvm.h"
|
||||
# include <string>
|
||||
|
||||
|
||||
/*
|
||||
* 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 function (by name) and calls the
|
||||
* C++ code that implements the task.
|
||||
*
|
||||
* The parameters of the task are implemented as an array of
|
||||
* vvm_calltf_parm objects. Each object represents a paramter from the
|
||||
* source.
|
||||
* This function loads a vpi module by name.
|
||||
*/
|
||||
class vvm_calltf_parm {
|
||||
extern void vvm_set_module_path(const char*path);
|
||||
extern void vvm_load_vpi_module(const char*path);
|
||||
|
||||
public:
|
||||
enum TYPE { NONE, ULONG, STRING, BITS, TIME };
|
||||
|
||||
vvm_calltf_parm();
|
||||
explicit vvm_calltf_parm(TYPE);
|
||||
vvm_calltf_parm(const vvm_calltf_parm&);
|
||||
~vvm_calltf_parm();
|
||||
|
||||
TYPE type() const { return type_; }
|
||||
|
||||
struct SIG {
|
||||
vvm_bits_t*bits;
|
||||
vvm_monitor_t*mon;
|
||||
};
|
||||
|
||||
unsigned long as_ulong() const { return ulong_; }
|
||||
string as_string() const { return *(string*)string_; }
|
||||
vvm_bits_t* as_bits() const { return bits_.bits; }
|
||||
vvm_monitor_t* as_mon() const { return bits_.mon; }
|
||||
|
||||
const string& sig_name() const { return bits_.mon->name(); }
|
||||
|
||||
vvm_calltf_parm& operator= (unsigned long);
|
||||
vvm_calltf_parm& operator= (const string&);
|
||||
vvm_calltf_parm& operator= (const SIG&);
|
||||
vvm_calltf_parm& operator= (const vvm_calltf_parm&);
|
||||
|
||||
private:
|
||||
TYPE type_;
|
||||
|
||||
union {
|
||||
unsigned long ulong_;
|
||||
char string_[sizeof(string)];
|
||||
SIG bits_;
|
||||
};
|
||||
|
||||
void release_();
|
||||
};
|
||||
|
||||
extern void vvm_calltask(vvm_simulation*sim, const string&name,
|
||||
unsigned nparms, class vvm_calltf_parm*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.
|
||||
*
|
||||
* Revision 1.1 1998/11/09 23:44:11 steve
|
||||
* Add vvm library.
|
||||
*
|
||||
|
||||
+19
-1
@@ -17,18 +17,36 @@
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
|
||||
*/
|
||||
#if !defined(WINNT)
|
||||
#ident "$Id: vvm_event.cc,v 1.1 1998/11/09 23:44:11 steve Exp $"
|
||||
#ident "$Id: vvm_event.cc,v 1.2 1999/10/28 00:47:25 steve Exp $"
|
||||
#endif
|
||||
|
||||
# include "vvm.h"
|
||||
# include <assert.h>
|
||||
|
||||
vvm_event::vvm_event()
|
||||
{
|
||||
event_ = 0;
|
||||
}
|
||||
|
||||
vvm_event::~vvm_event()
|
||||
{
|
||||
}
|
||||
|
||||
void vvm_event::callback_(void*cbd)
|
||||
{
|
||||
vvm_event*obj = reinterpret_cast<vvm_event*>(cbd);
|
||||
obj->event_function();
|
||||
delete obj;
|
||||
}
|
||||
|
||||
/*
|
||||
* $Log: vvm_event.cc,v $
|
||||
* Revision 1.2 1999/10/28 00:47:25 steve
|
||||
* Rewrite vvm VPI support to make objects more
|
||||
* persistent, rewrite the simulation scheduler
|
||||
* in C (to interface with VPI) and add VPI support
|
||||
* for callbacks.
|
||||
*
|
||||
* Revision 1.1 1998/11/09 23:44:11 steve
|
||||
* Add vvm library.
|
||||
*
|
||||
|
||||
+313
-5
@@ -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.7 1999/06/24 04:20:47 steve Exp $"
|
||||
#ident "$Id: vvm_func.h,v 1.16 1999/12/02 03:36:01 steve Exp $"
|
||||
#endif
|
||||
|
||||
# include "vvm.h"
|
||||
@@ -78,6 +78,13 @@ vvm_bitset_t<1> vvm_unop_or(const vvm_bitset_t<WIDTH>&r)
|
||||
return res;
|
||||
}
|
||||
|
||||
template <unsigned WIDTH>
|
||||
vvm_bitset_t<1> vvm_unop_nor(const vvm_bitset_t<WIDTH>&r)
|
||||
{
|
||||
vvm_bitset_t<1>res = vvm_unop_or(r);
|
||||
return vvm_unop_not(res);
|
||||
}
|
||||
|
||||
template <unsigned WIDTH>
|
||||
vvm_bitset_t<1> vvm_unop_lnot(const vvm_bitset_t<WIDTH>&r)
|
||||
{
|
||||
@@ -85,6 +92,44 @@ vvm_bitset_t<1> vvm_unop_lnot(const vvm_bitset_t<WIDTH>&r)
|
||||
return vvm_unop_not(res);
|
||||
}
|
||||
|
||||
/*
|
||||
* The unary XOR is the reduction XOR. It returns a single bit.
|
||||
*/
|
||||
template <unsigned WIDTH>
|
||||
vvm_bitset_t<1> vvm_unop_xor(const vvm_bitset_t<WIDTH>&r)
|
||||
{
|
||||
vvm_bitset_t<1> res;
|
||||
res[0] = V0;
|
||||
|
||||
for (unsigned idx = 0 ; idx < WIDTH ; idx += 1) {
|
||||
if (r[idx] == V1)
|
||||
res[0] = not(res[0]);
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
template <unsigned WIDTH>
|
||||
vvm_bitset_t<1> vvm_unop_xnor(const vvm_bitset_t<WIDTH>&r)
|
||||
{
|
||||
return not(vvm_unop_xor(r));
|
||||
}
|
||||
|
||||
//
|
||||
// simple-minded unary minus operator (two's complement)
|
||||
//
|
||||
template <unsigned WIDTH>
|
||||
vvm_bitset_t<WIDTH> vvm_unop_uminus(const vvm_bitset_t<WIDTH>&l)
|
||||
{
|
||||
vvm_bitset_t<WIDTH> res;
|
||||
res = vvm_unop_not(l);
|
||||
vpip_bit_t carry = V1;
|
||||
for (int i = 0; i < WIDTH; i++)
|
||||
res[i] = add_with_carry(res[i], V0, carry);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
/*
|
||||
* Implement the binary AND operator. This is a bitwise and with all
|
||||
* the parameters and the result having the same width.
|
||||
@@ -125,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);
|
||||
|
||||
@@ -143,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);
|
||||
|
||||
@@ -165,6 +210,40 @@ vvm_bitset_t<WIDTH> vvm_binop_xor(const vvm_bitset_t<WIDTH>&l,
|
||||
return result;
|
||||
}
|
||||
|
||||
/*
|
||||
* the binary 'l' operator is a logic left-shift by the number of positions
|
||||
* indicated by argument r. r is an unsigned integer, which is represented
|
||||
* internally as a 32-bit bitvector.
|
||||
*/
|
||||
template <unsigned WIDTH>
|
||||
vvm_bitset_t<WIDTH> vvm_binop_shiftl(const vvm_bitset_t<WIDTH>&l,
|
||||
const vvm_bits_t&r)
|
||||
{
|
||||
vvm_bitset_t<WIDTH> result;
|
||||
vvm_u32 s = r.as_unsigned();
|
||||
for (unsigned idx = 0; idx < WIDTH; idx++)
|
||||
result[idx] = (idx < s) ? V0 : l[idx-s];
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/*
|
||||
* The binary 'r' operator is a logic right-shift by the number of positions
|
||||
* indicated by argument r. r is an unsigned integer, which is represented
|
||||
* internally by a 32-bit bitvector.
|
||||
*/
|
||||
template <unsigned WIDTH>
|
||||
vvm_bitset_t<WIDTH> vvm_binop_shiftr(const vvm_bitset_t<WIDTH>&l,
|
||||
const vvm_bits_t&r)
|
||||
{
|
||||
vvm_bitset_t<WIDTH> result;
|
||||
vvm_u32 s = r.as_unsigned();
|
||||
for (unsigned idx = 0; idx < WIDTH; idx++)
|
||||
result[idx] = (idx < (WIDTH-s)) ? l[idx+s] : V0;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/*
|
||||
* Tests for equality are a bit tricky, as they allow for the left and
|
||||
* right subexpressions to have different size. The shorter bitset is
|
||||
@@ -239,6 +318,10 @@ vvm_bitset_t<1> vvm_binop_eq(const vvm_bitset_t<LW>&l,
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* This function return true if all the bits are the same. Even x and
|
||||
* z bites are compared for equality.
|
||||
*/
|
||||
template <unsigned LW, unsigned RW>
|
||||
vvm_bitset_t<1> vvm_binop_eeq(const vvm_bitset_t<LW>&l,
|
||||
const vvm_bitset_t<RW>&r)
|
||||
@@ -277,6 +360,112 @@ vvm_bitset_t<1> vvm_binop_eeq(const vvm_bitset_t<LW>&l,
|
||||
return result;
|
||||
}
|
||||
|
||||
/*
|
||||
* This function return true if all the bits are the same. The x and z
|
||||
* bits are don't care, s don't make the result false.
|
||||
*/
|
||||
template <unsigned LW, unsigned RW>
|
||||
vvm_bitset_t<1> vvm_binop_xeq(const vvm_bitset_t<LW>&l,
|
||||
const vvm_bitset_t<RW>&r)
|
||||
{
|
||||
vvm_bitset_t<1> result;
|
||||
result[0] = V1;
|
||||
|
||||
if (LW <= RW) {
|
||||
for (unsigned idx = 0 ; idx < LW ; idx += 1) {
|
||||
if ((l[idx] == Vz) || (r[idx] == Vz))
|
||||
continue;
|
||||
if ((l[idx] == Vx) || (r[idx] == Vx))
|
||||
continue;
|
||||
if (l[idx] != r[idx]) {
|
||||
result[0] = V0;
|
||||
return result;
|
||||
}
|
||||
}
|
||||
for (unsigned idx = LW ; idx < RW ; idx += 1) {
|
||||
if ((r[idx] == Vx) || (r[idx] == Vz))
|
||||
continue;
|
||||
if (r[idx] != V0) {
|
||||
result[0] = V0;
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
} else {
|
||||
for (unsigned idx = 0 ; idx < RW ; idx += 1) {
|
||||
if ((l[idx] == Vz) || (r[idx] == Vz))
|
||||
continue;
|
||||
if ((l[idx] == Vx) || (r[idx] == Vx))
|
||||
continue;
|
||||
if (l[idx] != r[idx]) {
|
||||
result[0] = V0;
|
||||
return result;
|
||||
}
|
||||
}
|
||||
for (unsigned idx = RW ; idx < LW ; idx += 1) {
|
||||
if ((l[idx] == Vx) || (l[idx] == Vz))
|
||||
continue;
|
||||
if (l[idx] != V0) {
|
||||
result[0] = V0;
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/*
|
||||
* This function return true if all the bits are the same. The z
|
||||
* bits are don't care, so don't make the result false.
|
||||
*/
|
||||
template <unsigned LW, unsigned RW>
|
||||
vvm_bitset_t<1> vvm_binop_zeq(const vvm_bitset_t<LW>&l,
|
||||
const vvm_bitset_t<RW>&r)
|
||||
{
|
||||
vvm_bitset_t<1> result;
|
||||
result[0] = V1;
|
||||
|
||||
if (LW <= RW) {
|
||||
for (unsigned idx = 0 ; idx < LW ; idx += 1) {
|
||||
if ((l[idx] == Vz) || (r[idx] == Vz))
|
||||
continue;
|
||||
if (l[idx] != r[idx]) {
|
||||
result[0] = V0;
|
||||
return result;
|
||||
}
|
||||
}
|
||||
for (unsigned idx = LW ; idx < RW ; idx += 1) {
|
||||
if (r[idx] == Vz)
|
||||
continue;
|
||||
if (r[idx] != V0) {
|
||||
result[0] = V0;
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
} else {
|
||||
for (unsigned idx = 0 ; idx < RW ; idx += 1) {
|
||||
if ((l[idx] == Vz) || (r[idx] == Vz))
|
||||
continue;
|
||||
if (l[idx] != r[idx]) {
|
||||
result[0] = V0;
|
||||
return result;
|
||||
}
|
||||
}
|
||||
for (unsigned idx = RW ; idx < LW ; idx += 1) {
|
||||
if (l[idx] == Vz)
|
||||
continue;
|
||||
if (l[idx] != V0) {
|
||||
result[0] = V0;
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
template <unsigned LW, unsigned RW>
|
||||
vvm_bitset_t<1> vvm_binop_ne(const vvm_bitset_t<LW>&l,
|
||||
const vvm_bitset_t<RW>&r)
|
||||
@@ -299,12 +488,87 @@ template <unsigned LW, unsigned RW>
|
||||
vvm_bitset_t<1> vvm_binop_lt(const vvm_bitset_t<LW>&l,
|
||||
const vvm_bitset_t<RW>&r)
|
||||
{
|
||||
assert(LW == RW);
|
||||
vvm_bitset_t<1> result;
|
||||
result[0] = V0;
|
||||
for (unsigned idx = 0 ; idx < LW ; idx += 1)
|
||||
const unsigned common = (LW < RW)? LW : RW;
|
||||
for (unsigned idx = 0 ; idx < common ; idx += 1)
|
||||
result[0] = less_with_cascade(l[idx], r[idx], result[0]);
|
||||
|
||||
if (LW > RW) {
|
||||
for (unsigned idx = RW ; idx < LW ; idx += 1)
|
||||
result[0] = less_with_cascade(l[idx], V0, result[0]);
|
||||
} else {
|
||||
for (unsigned idx = LW ; idx < RW ; idx += 1)
|
||||
result[0] = less_with_cascade(V0, r[idx], result[0]);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/*
|
||||
* The <= operator takes operands of natural width and returns a
|
||||
* single bit. The result is V1 if l <= r, otherwise V0;
|
||||
*/
|
||||
template <unsigned LW, unsigned RW>
|
||||
vvm_bitset_t<1> vvm_binop_le(const vvm_bitset_t<LW>&l,
|
||||
const vvm_bitset_t<RW>&r)
|
||||
{
|
||||
vvm_bitset_t<1> result;
|
||||
result[0] = V1;
|
||||
const unsigned common = (LW < RW)? LW : RW;
|
||||
for (unsigned idx = 0 ; idx < common ; idx += 1)
|
||||
result[0] = less_with_cascade(l[idx], r[idx], result[0]);
|
||||
|
||||
if (LW > RW) {
|
||||
for (unsigned idx = RW ; idx < LW ; idx += 1)
|
||||
result[0] = less_with_cascade(l[idx], V0, result[0]);
|
||||
} else {
|
||||
for (unsigned idx = LW ; idx < RW ; idx += 1)
|
||||
result[0] = less_with_cascade(V0, r[idx], result[0]);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
template <unsigned LW, unsigned RW>
|
||||
vvm_bitset_t<1> vvm_binop_gt(const vvm_bitset_t<LW>&l,
|
||||
const vvm_bitset_t<RW>&r)
|
||||
{
|
||||
vvm_bitset_t<1> result;
|
||||
result[0] = V0;
|
||||
const unsigned common = (LW < RW)? LW : RW;
|
||||
for (unsigned idx = 0 ; idx < common ; idx += 1)
|
||||
result[0] = greater_with_cascade(l[idx], r[idx], result[0]);
|
||||
|
||||
if (LW > RW) {
|
||||
for (unsigned idx = RW ; idx < LW ; idx += 1)
|
||||
result[0] = greater_with_cascade(l[idx], V0, result[0]);
|
||||
} else {
|
||||
for (unsigned idx = LW ; idx < RW ; idx += 1)
|
||||
result[0] = greater_with_cascade(V0, r[idx], result[0]);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
template <unsigned LW, unsigned RW>
|
||||
vvm_bitset_t<1> vvm_binop_ge(const vvm_bitset_t<LW>&l,
|
||||
const vvm_bitset_t<RW>&r)
|
||||
{
|
||||
vvm_bitset_t<1> result;
|
||||
result[0] = V1;
|
||||
const unsigned common = (LW < RW)? LW : RW;
|
||||
for (unsigned idx = 0 ; idx < common ; idx += 1)
|
||||
result[0] = greater_with_cascade(l[idx], r[idx], result[0]);
|
||||
|
||||
if (LW > RW) {
|
||||
for (unsigned idx = RW ; idx < LW ; idx += 1)
|
||||
result[0] = greater_with_cascade(l[idx], V0, result[0]);
|
||||
} else {
|
||||
for (unsigned idx = LW ; idx < RW ; idx += 1)
|
||||
result[0] = greater_with_cascade(V0, r[idx], result[0]);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -328,8 +592,52 @@ vvm_bitset_t<1> vvm_binop_lor(const vvm_bitset_t<LW>&l,
|
||||
return res1;
|
||||
}
|
||||
|
||||
template <unsigned W>
|
||||
vvm_bitset_t<W> vvm_ternary(vpip_bit_t c, const vvm_bitset_t<W>&t,
|
||||
const vvm_bitset_t<W>&f)
|
||||
{
|
||||
switch (c) {
|
||||
case V0:
|
||||
return f;
|
||||
case V1:
|
||||
return t;
|
||||
default:
|
||||
return f;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* $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.
|
||||
*
|
||||
* Revision 1.13 1999/10/01 15:26:29 steve
|
||||
* Add some vvm operators from Eric Aardoom.
|
||||
*
|
||||
* Revision 1.12 1999/09/29 22:57:26 steve
|
||||
* LT supports different width objects.
|
||||
*
|
||||
* Revision 1.11 1999/09/29 18:36:04 steve
|
||||
* Full case support
|
||||
*
|
||||
* Revision 1.10 1999/09/28 01:13:16 steve
|
||||
* Support in vvm > and >= behavioral operators.
|
||||
*
|
||||
* Revision 1.9 1999/09/23 04:39:52 steve
|
||||
* The <= operator takes different width operands.
|
||||
*
|
||||
* Revision 1.8 1999/09/11 04:43:17 steve
|
||||
* Support ternary and <= operators in vvm.
|
||||
*
|
||||
* Revision 1.7 1999/06/24 04:20:47 steve
|
||||
* Add !== and === operators.
|
||||
*
|
||||
|
||||
@@ -0,0 +1,159 @@
|
||||
/*
|
||||
* Copyright (c) 1999 Stephen Williams (steve@icarus.com)
|
||||
*
|
||||
* This source code is free software; you can redistribute it
|
||||
* and/or modify it in source code form under the terms of the GNU
|
||||
* General Public License as published by the Free Software
|
||||
* Foundation; either version 2 of the License, or (at your option)
|
||||
* any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
|
||||
* ---
|
||||
* You should also have recieved a copy of the Picture Elements
|
||||
* Binary Software License offer along with the source. This offer
|
||||
* allows you to obtain the right to redistribute the software in
|
||||
* binary (compiled) form. If you have not received it, contact
|
||||
* Picture Elements, Inc., 777 Panoramic Way, Berkeley, CA 94704.
|
||||
*/
|
||||
#if !defined(WINNT)
|
||||
#ident "$Id: vvm_gates.cc,v 1.3 1999/12/02 04:54:11 steve Exp $"
|
||||
#endif
|
||||
|
||||
# include "vvm_gates.h"
|
||||
|
||||
vvm_out_event::vvm_out_event(vvm_simulation*s, vpip_bit_t v, action_t o)
|
||||
: output_(o), sim_(s), val_(v)
|
||||
{
|
||||
}
|
||||
|
||||
vvm_out_event::~vvm_out_event()
|
||||
{
|
||||
}
|
||||
|
||||
void vvm_out_event::event_function()
|
||||
{
|
||||
output_(sim_, val_);
|
||||
}
|
||||
|
||||
vvm_1bit_out::vvm_1bit_out(vvm_out_event::action_t o, unsigned d)
|
||||
: output_(o), delay_(d)
|
||||
{
|
||||
}
|
||||
|
||||
vvm_1bit_out::~vvm_1bit_out()
|
||||
{
|
||||
}
|
||||
|
||||
void vvm_1bit_out::output(vvm_simulation*sim, vpip_bit_t val)
|
||||
{
|
||||
vvm_event*ev = new vvm_out_event(sim, val, output_);
|
||||
if (delay_ > 0)
|
||||
sim->insert_event(delay_, ev);
|
||||
else
|
||||
sim->active_event(ev);
|
||||
}
|
||||
|
||||
|
||||
vpip_bit_t compute_and(const vpip_bit_t*inp, unsigned count)
|
||||
{
|
||||
vpip_bit_t outval = inp[0];
|
||||
for (unsigned i = 1 ; i < count ; i += 1)
|
||||
outval = outval & inp[i];
|
||||
return outval;
|
||||
}
|
||||
|
||||
vpip_bit_t compute_or(const vpip_bit_t*inp, unsigned count)
|
||||
{
|
||||
vpip_bit_t outval = inp[0];
|
||||
for (unsigned i = 1 ; i < count ; i += 1)
|
||||
outval = outval | inp[i];
|
||||
return outval;
|
||||
}
|
||||
|
||||
vpip_bit_t compute_nor(const vpip_bit_t*inp, unsigned count)
|
||||
{
|
||||
vpip_bit_t outval = inp[0];
|
||||
for (unsigned i = 1 ; i < count ; i += 1)
|
||||
outval = outval | inp[i];
|
||||
return not(outval);
|
||||
}
|
||||
|
||||
vpip_bit_t compute_xor(const vpip_bit_t*inp, unsigned count)
|
||||
{
|
||||
vpip_bit_t outval = inp[0];
|
||||
for (unsigned i = 1; i < count; i++)
|
||||
outval = outval ^ inp[i];
|
||||
return outval;
|
||||
}
|
||||
|
||||
vpip_bit_t compute_nand(const vpip_bit_t*inp, unsigned count)
|
||||
{
|
||||
return not(compute_and(inp,count));
|
||||
}
|
||||
|
||||
vpip_bit_t compute_xnor(const vpip_bit_t*inp, unsigned count)
|
||||
{
|
||||
return not(compute_xor(inp,count));
|
||||
}
|
||||
|
||||
void compute_mux(vpip_bit_t*out, unsigned wid,
|
||||
const vpip_bit_t*sel, unsigned swid,
|
||||
const vpip_bit_t*dat, unsigned size)
|
||||
{
|
||||
unsigned tmp = 0;
|
||||
for (unsigned idx = 0 ; idx < swid ; idx += 1)
|
||||
switch (sel[idx]) {
|
||||
case V0:
|
||||
break;
|
||||
case V1:
|
||||
tmp |= (1<<idx);
|
||||
break;
|
||||
default:
|
||||
tmp = size;
|
||||
break;
|
||||
}
|
||||
|
||||
if (tmp >= size) {
|
||||
|
||||
if (swid > 1) {
|
||||
for (unsigned idx = 0; idx < wid ; idx += 1)
|
||||
out[idx] = Vx;
|
||||
} else {
|
||||
const unsigned b0 = 0;
|
||||
const unsigned b1 = wid;
|
||||
for (unsigned idx = 0 ; idx < wid ; idx += 1) {
|
||||
if (dat[idx+b0] == dat[idx+b1])
|
||||
out[idx] = dat[idx+b0];
|
||||
else
|
||||
out[idx] = Vx;
|
||||
}
|
||||
}
|
||||
|
||||
} else {
|
||||
unsigned b = tmp * wid;
|
||||
for (unsigned idx = 0; idx < wid ; idx += 1)
|
||||
out[idx] = dat[idx+b];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* $Log: vvm_gates.cc,v $
|
||||
* Revision 1.3 1999/12/02 04:54:11 steve
|
||||
* Handle mux sel of X, if inputs are equal.
|
||||
*
|
||||
* Revision 1.2 1999/11/24 04:38:49 steve
|
||||
* LT and GT fixes from Eric Aardoom.
|
||||
*
|
||||
* Revision 1.1 1999/11/22 00:30:52 steve
|
||||
* Detemplate some and, or and nor methods.
|
||||
*
|
||||
*/
|
||||
|
||||
+619
-179
@@ -19,12 +19,23 @@
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
|
||||
*/
|
||||
#if !defined(WINNT)
|
||||
#ident "$Id: vvm_gates.h,v 1.12 1999/07/17 03:07:27 steve Exp $"
|
||||
#ident "$Id: vvm_gates.h,v 1.30 1999/12/02 16:58:58 steve Exp $"
|
||||
#endif
|
||||
|
||||
# include "vvm.h"
|
||||
# include <assert.h>
|
||||
|
||||
extern vpip_bit_t compute_nand(const vpip_bit_t*inp, unsigned count);
|
||||
extern vpip_bit_t compute_and(const vpip_bit_t*inp, unsigned count);
|
||||
extern vpip_bit_t compute_nor(const vpip_bit_t*inp, unsigned count);
|
||||
extern vpip_bit_t compute_or(const vpip_bit_t*inp, unsigned count);
|
||||
extern vpip_bit_t compute_xor(const vpip_bit_t*inp, unsigned count);
|
||||
extern vpip_bit_t compute_xnor(const vpip_bit_t*inp, unsigned count);
|
||||
|
||||
extern void compute_mux(vpip_bit_t*out, unsigned wid,
|
||||
const vpip_bit_t*sel, unsigned swid,
|
||||
const vpip_bit_t*dat, unsigned size);
|
||||
|
||||
/*
|
||||
* A vvm gate is constructed with an input width and an output
|
||||
* function. The input width represents all the input signals that go
|
||||
@@ -36,83 +47,533 @@
|
||||
class vvm_out_event : public vvm_event {
|
||||
|
||||
public:
|
||||
typedef void (*action_t)(vvm_simulation*, vvm_bit_t);
|
||||
vvm_out_event(vvm_simulation*s, vvm_bit_t v, action_t o)
|
||||
: output_(o), sim_(s), val_(v) { }
|
||||
typedef void (*action_t)(vvm_simulation*, vpip_bit_t);
|
||||
|
||||
void event_function()
|
||||
{ output_(sim_, val_); }
|
||||
vvm_out_event(vvm_simulation*s, vpip_bit_t v, action_t o);
|
||||
~vvm_out_event();
|
||||
|
||||
void event_function();
|
||||
|
||||
private:
|
||||
const action_t output_;
|
||||
vvm_simulation*const sim_;
|
||||
const vvm_bit_t val_;
|
||||
const vpip_bit_t val_;
|
||||
};
|
||||
|
||||
template <unsigned WIDTH, unsigned long DELAY> class vvm_and {
|
||||
class vvm_1bit_out {
|
||||
|
||||
public:
|
||||
vvm_1bit_out(vvm_out_event::action_t, unsigned delay);
|
||||
~vvm_1bit_out();
|
||||
void output(vvm_simulation*sim, vpip_bit_t);
|
||||
|
||||
private:
|
||||
vvm_out_event::action_t output_;
|
||||
unsigned delay_;
|
||||
};
|
||||
|
||||
/*
|
||||
* This template implements the LPM_ADD_SUB device type. The width of
|
||||
* the device is a template parameter. The device handles addition and
|
||||
* subtraction, selectable by the Add_Sub input. When configured as a
|
||||
* subtractor, the device works by adding the 2s complement of
|
||||
* DataB.
|
||||
*/
|
||||
template <unsigned WIDTH> class vvm_add_sub {
|
||||
|
||||
public:
|
||||
vvm_add_sub() : ndir_(V0) { }
|
||||
|
||||
void config_rout(unsigned idx, vvm_out_event::action_t a)
|
||||
{ o_[idx] = a;
|
||||
}
|
||||
|
||||
void init_DataA(unsigned idx, vpip_bit_t val)
|
||||
{ a_[idx] = val;
|
||||
}
|
||||
|
||||
void init_DataB(unsigned idx, vpip_bit_t val)
|
||||
{ b_[idx] = val;
|
||||
}
|
||||
|
||||
void init_Add_Sub(unsigned, vpip_bit_t val)
|
||||
{ ndir_ = not(val);
|
||||
}
|
||||
|
||||
void set_DataA(vvm_simulation*sim, unsigned idx, vpip_bit_t val)
|
||||
{ a_[idx] = val;
|
||||
compute_(sim);
|
||||
}
|
||||
void set_DataB(vvm_simulation*sim, unsigned idx, vpip_bit_t val)
|
||||
{ b_[idx] = val;
|
||||
compute_(sim);
|
||||
}
|
||||
|
||||
private:
|
||||
vpip_bit_t a_[WIDTH];
|
||||
vpip_bit_t b_[WIDTH];
|
||||
vpip_bit_t r_[WIDTH];
|
||||
|
||||
// this is the inverse of the Add_Sub port. It is 0 for add,
|
||||
// and 1 for subtract.
|
||||
vpip_bit_t ndir_;
|
||||
|
||||
vvm_out_event::action_t o_[WIDTH];
|
||||
|
||||
void compute_(vvm_simulation*sim)
|
||||
{ vpip_bit_t carry = ndir_;
|
||||
for (unsigned idx = 0 ; idx < WIDTH ; idx += 1) {
|
||||
vpip_bit_t val;
|
||||
val = add_with_carry(a_[idx], b_[idx] ^ ndir_, carry);
|
||||
if (val == r_[idx]) continue;
|
||||
r_[idx] = val;
|
||||
if (o_[idx] == 0) continue;
|
||||
vvm_event*ev = new vvm_out_event(sim, val, o_[idx]);
|
||||
sim->insert_event(0, ev);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
template <unsigned WIDTH, unsigned long DELAY>
|
||||
class vvm_and : private vvm_1bit_out {
|
||||
|
||||
public:
|
||||
explicit vvm_and(vvm_out_event::action_t o)
|
||||
: output_(o) { }
|
||||
: vvm_1bit_out(o, DELAY) { }
|
||||
|
||||
void init(unsigned idx, vvm_bit_t val)
|
||||
{ input_[idx-1] = val; }
|
||||
void init_I(unsigned idx, vpip_bit_t val)
|
||||
{ input_[idx] = val; }
|
||||
|
||||
void start(vvm_simulation*sim)
|
||||
{ vvm_event*ev = new vvm_out_event(sim, compute_(), output_);
|
||||
if (DELAY > 0)
|
||||
sim->insert_event(DELAY, ev);
|
||||
else
|
||||
sim->active_event(ev);
|
||||
}
|
||||
{ output(sim, compute_and(input_,WIDTH)); }
|
||||
|
||||
void set(vvm_simulation*sim, unsigned idx, vvm_bit_t val)
|
||||
{ if (input_[idx-1] == val)
|
||||
return;
|
||||
input_[idx-1] = val;
|
||||
|
||||
vvm_event*ev = new vvm_out_event(sim, compute_(), output_);
|
||||
if (DELAY > 0)
|
||||
sim->insert_event(DELAY, ev);
|
||||
else
|
||||
sim->active_event(ev);
|
||||
void set_I(vvm_simulation*sim, unsigned idx, vpip_bit_t val)
|
||||
{ if (input_[idx] == val) return;
|
||||
input_[idx] = val;
|
||||
output(sim, compute_and(input_,WIDTH));
|
||||
}
|
||||
|
||||
private:
|
||||
vvm_bit_t compute_() const
|
||||
{ vvm_bit_t outval = input_[0];
|
||||
for (unsigned i = 1 ; i < WIDTH ; i += 1)
|
||||
outval = outval & input_[i];
|
||||
return outval;
|
||||
}
|
||||
|
||||
vvm_bit_t input_[WIDTH];
|
||||
vvm_out_event::action_t output_;
|
||||
vpip_bit_t input_[WIDTH];
|
||||
};
|
||||
|
||||
template <unsigned WIDTH, unsigned long DELAY> class vvm_or {
|
||||
template <unsigned WIDTH, unsigned WDIST> class vvm_clshift {
|
||||
|
||||
public:
|
||||
explicit vvm_clshift()
|
||||
{ dir_ = V0;
|
||||
dist_val_ = WIDTH;
|
||||
for (unsigned idx = 0 ; idx < WIDTH ; idx += 1)
|
||||
data_[idx] = Vx;
|
||||
for (unsigned idx = 0 ; idx < WIDTH ; idx += 1)
|
||||
out_[idx] = 0;
|
||||
for (unsigned idx = 0 ; idx < WDIST ; idx += 1)
|
||||
dist_[idx] = Vx;
|
||||
}
|
||||
|
||||
~vvm_clshift() { }
|
||||
|
||||
void init_Data(unsigned idx, vpip_bit_t val)
|
||||
{ data_[idx] = val;
|
||||
}
|
||||
void init_Distance(unsigned idx, vpip_bit_t val)
|
||||
{ dist_[idx] = val;
|
||||
calculate_dist_();
|
||||
}
|
||||
void init_Direction(vpip_bit_t val)
|
||||
{ dir_ = val; }
|
||||
|
||||
void set_Data(vvm_simulation*sim, unsigned idx, vpip_bit_t val)
|
||||
{ if (data_[idx] == val) return;
|
||||
data_[idx] = val;
|
||||
if ((dist_val_ + idx) >= WIDTH) return;
|
||||
if ((dist_val_ + idx) < 0) return;
|
||||
vvm_out_event::action_t out = out_[dist_val_+idx];
|
||||
if (out == 0) return;
|
||||
vvm_event*ev = new vvm_out_event(sim, val, out);
|
||||
sim->active_event(ev);
|
||||
}
|
||||
|
||||
void set_Distance(vvm_simulation*sim, unsigned idx, vpip_bit_t val)
|
||||
{ if (dist_[idx] == val) return;
|
||||
dist_[idx] = val;
|
||||
calculate_dist_();
|
||||
compute_(sim);
|
||||
}
|
||||
|
||||
void set_Direction(vvm_simulation*sim, unsigned, vpip_bit_t val)
|
||||
{ if (dir_ == val) return;
|
||||
dir_ = val;
|
||||
calculate_dist_();
|
||||
compute_(sim);
|
||||
}
|
||||
|
||||
void config_rout(unsigned idx, vvm_out_event::action_t o)
|
||||
{ out_[idx] = o;
|
||||
}
|
||||
|
||||
private:
|
||||
vpip_bit_t dir_;
|
||||
vpip_bit_t data_[WIDTH];
|
||||
vpip_bit_t dist_[WDIST];
|
||||
vvm_out_event::action_t out_[WIDTH];
|
||||
int dist_val_;
|
||||
|
||||
void calculate_dist_()
|
||||
{ int tmp = 0;
|
||||
for (unsigned idx = 0 ; idx < WDIST ; idx += 1)
|
||||
switch (dist_[idx]) {
|
||||
case V0:
|
||||
break;
|
||||
case V1:
|
||||
tmp |= 1<<idx;
|
||||
break;
|
||||
default:
|
||||
tmp = WIDTH;
|
||||
}
|
||||
if (tmp > WIDTH)
|
||||
tmp = WIDTH;
|
||||
else if (dir_ == V1)
|
||||
tmp = -tmp;
|
||||
dist_val_ = tmp;
|
||||
}
|
||||
|
||||
void compute_(vvm_simulation*sim)
|
||||
{ vvm_event*ev;
|
||||
if (dist_val_ == WIDTH) {
|
||||
for (unsigned idx = 0 ; idx < WIDTH ; idx += 1) {
|
||||
if (out_[idx] == 0) continue;
|
||||
ev = new vvm_out_event(sim, Vx, out_[idx]);
|
||||
sim->active_event(ev);
|
||||
}
|
||||
return;
|
||||
}
|
||||
for (int idx = 0 ; idx < WIDTH ; idx += 1) {
|
||||
if (out_[idx] == 0) continue;
|
||||
vpip_bit_t val;
|
||||
if ((idx-dist_val_) >= WIDTH) val = V0;
|
||||
else if ((idx-dist_val_) < 0) val = V0;
|
||||
else val = data_[idx-dist_val_];
|
||||
ev = new vvm_out_event(sim, val, out_[idx]);
|
||||
sim->active_event(ev);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
template <unsigned WIDTH> class vvm_compare {
|
||||
|
||||
public:
|
||||
explicit vvm_compare()
|
||||
{ out_lt_ = 0;
|
||||
out_le_ = 0;
|
||||
gt_ = Vx;
|
||||
lt_ = Vx;
|
||||
for (unsigned idx = 0 ; idx < WIDTH ; idx += 1) {
|
||||
a_[idx] = Vx;
|
||||
b_[idx] = Vx;
|
||||
}
|
||||
}
|
||||
~vvm_compare() { }
|
||||
|
||||
void init_DataA(unsigned idx, vpip_bit_t val)
|
||||
{ a_[idx] = val; }
|
||||
void init_DataB(unsigned idx, vpip_bit_t val)
|
||||
{ b_[idx] = val; }
|
||||
|
||||
void set_DataA(vvm_simulation*sim, unsigned idx, vpip_bit_t val)
|
||||
{ if (a_[idx] == val) return;
|
||||
a_[idx] = val;
|
||||
compute_(sim);
|
||||
}
|
||||
|
||||
void set_DataB(vvm_simulation*sim, unsigned idx, vpip_bit_t val)
|
||||
{ if (b_[idx] == val) return;
|
||||
b_[idx] = val;
|
||||
compute_(sim);
|
||||
}
|
||||
|
||||
void config_ALB_out(vvm_out_event::action_t o)
|
||||
{ out_lt_ = o; }
|
||||
|
||||
void config_ALEB_out(vvm_out_event::action_t o)
|
||||
{ out_le_ = o; }
|
||||
|
||||
void config_AGB_out(vvm_out_event::action_t o)
|
||||
{ out_gt_ = o; }
|
||||
|
||||
void config_AGEB_out(vvm_out_event::action_t o)
|
||||
{ out_ge_ = o; }
|
||||
|
||||
private:
|
||||
vpip_bit_t a_[WIDTH];
|
||||
vpip_bit_t b_[WIDTH];
|
||||
|
||||
vpip_bit_t gt_;
|
||||
vpip_bit_t lt_;
|
||||
|
||||
vvm_out_event::action_t out_lt_;
|
||||
vvm_out_event::action_t out_le_;
|
||||
vvm_out_event::action_t out_gt_;
|
||||
vvm_out_event::action_t out_ge_;
|
||||
|
||||
void compute_(vvm_simulation*sim)
|
||||
{ vpip_bit_t gt = V0;
|
||||
vpip_bit_t lt = V0;
|
||||
vvm_event*ev;
|
||||
for (unsigned idx = 0 ; idx < WIDTH ; idx += 1) {
|
||||
gt = greater_with_cascade(a_[idx], b_[idx], gt);
|
||||
lt = less_with_cascade(a_[idx], b_[idx], lt);
|
||||
}
|
||||
|
||||
if ((gt_ == gt) && (lt_ == lt)) return;
|
||||
gt_ = gt;
|
||||
lt_ = lt;
|
||||
if (out_lt_) {
|
||||
ev = new vvm_out_event(sim, lt_, out_lt_);
|
||||
sim->active_event(ev);
|
||||
}
|
||||
if (out_le_) {
|
||||
ev = new vvm_out_event(sim, not(gt_), out_le_);
|
||||
sim->active_event(ev);
|
||||
}
|
||||
if (out_gt_) {
|
||||
ev = new vvm_out_event(sim, gt_, out_gt_);
|
||||
sim->active_event(ev);
|
||||
}
|
||||
if (out_ge_) {
|
||||
ev = new vvm_out_event(sim, not(lt_), out_ge_);
|
||||
sim->active_event(ev);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
* This class simulates the LPM flip-flop device.
|
||||
* XXXX Inverted clock not yet supported.
|
||||
*/
|
||||
template <unsigned WIDTH> class vvm_ff {
|
||||
|
||||
public:
|
||||
explicit vvm_ff()
|
||||
{ clk_ = Vx;
|
||||
for (unsigned idx = 0 ; idx < WIDTH ; idx += 1)
|
||||
q_[idx] = Vx;
|
||||
}
|
||||
~vvm_ff() { }
|
||||
|
||||
void init_Data(unsigned idx, vpip_bit_t val) { d_[idx] = val; }
|
||||
void init_Clock(unsigned, vpip_bit_t val) { clk_ = val; }
|
||||
|
||||
void set_Clock(vvm_simulation*sim, unsigned, vpip_bit_t val)
|
||||
{ if (val == clk_) return;
|
||||
bool flag = posedge(clk_, val);
|
||||
clk_ = val;
|
||||
if (flag) latch_(sim);
|
||||
}
|
||||
|
||||
void set_Data(vvm_simulation*sim, unsigned idx, vpip_bit_t val)
|
||||
{ d_[idx] = val;
|
||||
}
|
||||
|
||||
void config_rout(unsigned idx, vvm_out_event::action_t o)
|
||||
{ out_[idx] = o;
|
||||
}
|
||||
|
||||
private:
|
||||
vpip_bit_t d_[WIDTH];
|
||||
vpip_bit_t q_[WIDTH];
|
||||
vpip_bit_t clk_;
|
||||
|
||||
vvm_out_event::action_t out_[WIDTH];
|
||||
|
||||
void latch_(vvm_simulation*sim)
|
||||
{ q_ = d_;
|
||||
for (unsigned idx = 0 ; idx < WIDTH ; idx += 1)
|
||||
if (out_[idx]) {
|
||||
vvm_event*ev = new vvm_out_event(sim, q_[idx],
|
||||
out_[idx]);
|
||||
sim->active_event(ev);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
/*
|
||||
* This class supports mux devices. The width is the width of the data
|
||||
* (or bus) path, SIZE is the number of alternative inputs and SELWID
|
||||
* is the size (in bits) of the selector input.
|
||||
*/
|
||||
template <unsigned WIDTH, unsigned SIZE, unsigned SELWID> class vvm_mux {
|
||||
|
||||
public:
|
||||
explicit vvm_mux()
|
||||
{ unsigned idx;
|
||||
for (idx = 0 ; idx < WIDTH ; idx += 1) out_[idx] = 0;
|
||||
for (idx = 0 ; idx < WIDTH ; idx += 1) output_[idx] = Vx;
|
||||
for (idx = 0 ; idx < SELWID; idx += 1) sel_[idx] = Vx;
|
||||
for (idx = 0 ; idx < WIDTH*SIZE; idx += 1) input_[idx] = Vx;
|
||||
}
|
||||
|
||||
void init_Sel(unsigned idx, vpip_bit_t val)
|
||||
{ sel_[idx] = val; }
|
||||
|
||||
void init_Data(unsigned idx, vpip_bit_t val)
|
||||
{ input_[idx] = val; }
|
||||
|
||||
void set_Sel(vvm_simulation*sim, unsigned idx, vpip_bit_t val)
|
||||
{ if (sel_[idx] == val) return;
|
||||
sel_[idx] = val;
|
||||
evaluate_(sim);
|
||||
}
|
||||
|
||||
void set_Data(vvm_simulation*sim, unsigned idx, vpip_bit_t val)
|
||||
{ if (input_[idx] == val) return;
|
||||
input_[idx] = val;
|
||||
evaluate_(sim);
|
||||
}
|
||||
|
||||
void config_rout(unsigned idx, vvm_out_event::action_t o)
|
||||
{ out_[idx] = o; }
|
||||
|
||||
private:
|
||||
vpip_bit_t sel_[SELWID];
|
||||
vpip_bit_t input_[WIDTH * SIZE];
|
||||
vpip_bit_t output_[WIDTH];
|
||||
|
||||
vvm_out_event::action_t out_[WIDTH];
|
||||
|
||||
void evaluate_(vvm_simulation*sim)
|
||||
{ vpip_bit_t tmp[WIDTH];
|
||||
compute_mux(tmp, WIDTH, sel_, SELWID, input_, SIZE);
|
||||
for (unsigned idx = 0 ; idx < WIDTH ; idx += 1)
|
||||
if (tmp[idx] != output_[idx]) {
|
||||
output_[idx] = tmp[idx];
|
||||
vvm_event*ev = new vvm_out_event(sim,
|
||||
output_[idx],
|
||||
out_[idx]);
|
||||
sim->active_event(ev);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
template <unsigned WIDTH, unsigned long DELAY>
|
||||
class vvm_or : private vvm_1bit_out {
|
||||
|
||||
public:
|
||||
explicit vvm_or(vvm_out_event::action_t o)
|
||||
: output_(o) { }
|
||||
: vvm_1bit_out(o,DELAY) { }
|
||||
|
||||
void init(unsigned idx, vvm_bit_t val)
|
||||
{ input_[idx-1] = val; }
|
||||
void init_I(unsigned idx, vpip_bit_t val)
|
||||
{ input_[idx] = val; }
|
||||
|
||||
void start(vvm_simulation*sim)
|
||||
{ vvm_event*ev = new vvm_out_event(sim, compute_(), output_);
|
||||
if (DELAY > 0)
|
||||
sim->insert_event(DELAY, ev);
|
||||
else
|
||||
sim->active_event(ev);
|
||||
{ output(sim, compute_or(input_,WIDTH)); }
|
||||
|
||||
void set_I(vvm_simulation*sim, unsigned idx, vpip_bit_t val)
|
||||
{ if (input_[idx] == val)
|
||||
return;
|
||||
input_[idx] = val;
|
||||
output(sim, compute_or(input_,WIDTH));
|
||||
}
|
||||
|
||||
void set(vvm_simulation*sim, unsigned idx, vvm_bit_t val)
|
||||
{ if (input_[idx-1] == val)
|
||||
return;
|
||||
input_[idx-1] = val;
|
||||
private:
|
||||
vpip_bit_t input_[WIDTH];
|
||||
};
|
||||
|
||||
vvm_event*ev = new vvm_out_event(sim, compute_(), output_);
|
||||
template <unsigned WIDTH, unsigned long DELAY>
|
||||
class vvm_nor : private vvm_1bit_out {
|
||||
|
||||
public:
|
||||
explicit vvm_nor(vvm_out_event::action_t o)
|
||||
: vvm_1bit_out(o, DELAY) { }
|
||||
|
||||
void init_I(unsigned idx, vpip_bit_t val)
|
||||
{ input_[idx] = val; }
|
||||
|
||||
void start(vvm_simulation*sim)
|
||||
{ output(sim, compute_nor(input_,WIDTH)); }
|
||||
|
||||
void set_I(vvm_simulation*sim, unsigned idx, vpip_bit_t val)
|
||||
{ if (input_[idx] == val)
|
||||
return;
|
||||
input_[idx] = val;
|
||||
output(sim, compute_nor(input_,WIDTH));
|
||||
}
|
||||
|
||||
private:
|
||||
vpip_bit_t input_[WIDTH];
|
||||
};
|
||||
|
||||
template <unsigned WIDTH, unsigned AWIDTH, unsigned SIZE>
|
||||
class vvm_ram_dq : protected vvm_ram_callback {
|
||||
|
||||
public:
|
||||
vvm_ram_dq(vvm_memory_t<WIDTH,SIZE>*mem)
|
||||
: mem_(mem)
|
||||
{ mem->set_callback(this);
|
||||
for (unsigned idx = 0 ; idx < WIDTH ; idx += 1)
|
||||
out_[idx] = 0;
|
||||
for (unsigned idx = 0 ; idx < AWIDTH ; idx += 1)
|
||||
addr_[idx] = Vx;
|
||||
}
|
||||
|
||||
void init_Address(unsigned idx, vpip_bit_t val)
|
||||
{ addr_[idx] = val; }
|
||||
|
||||
void set_Address(vvm_simulation*sim, unsigned idx, vpip_bit_t val)
|
||||
{ if (addr_[idx] == val) return;
|
||||
addr_[idx] = val;
|
||||
compute_();
|
||||
send_out_(sim);
|
||||
}
|
||||
|
||||
void handle_write(vvm_simulation*sim, unsigned idx)
|
||||
{ if (idx == addr_val_) send_out_(sim); }
|
||||
|
||||
void config_rout(unsigned idx, vvm_out_event::action_t o)
|
||||
{ out_[idx] = o; }
|
||||
|
||||
private:
|
||||
vvm_memory_t<WIDTH,SIZE>*mem_;
|
||||
vpip_bit_t addr_[AWIDTH];
|
||||
vvm_out_event::action_t out_[WIDTH];
|
||||
|
||||
unsigned long addr_val_;
|
||||
|
||||
void compute_()
|
||||
{ unsigned bit;
|
||||
unsigned mask;
|
||||
addr_val_ = 0;
|
||||
for (bit = 0, mask = 1 ; bit < AWIDTH ; bit += 1, mask <<= 1)
|
||||
if (addr_[bit] == V1) addr_val_ |= mask;
|
||||
}
|
||||
|
||||
void send_out_(vvm_simulation*sim)
|
||||
{ vvm_bitset_t<WIDTH>ov = mem_->get_word(addr_val_);
|
||||
for (unsigned bit = 0 ; bit < WIDTH ; bit += 1)
|
||||
if (out_[bit]) {
|
||||
vvm_event*ev = new vvm_out_event(sim,
|
||||
ov[bit],
|
||||
out_[bit]);
|
||||
sim->active_event(ev);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
template <unsigned long DELAY> class vvm_buf {
|
||||
|
||||
public:
|
||||
explicit vvm_buf(vvm_out_event::action_t o)
|
||||
: output_(o)
|
||||
{ }
|
||||
|
||||
void init_I(unsigned, vpip_bit_t) { }
|
||||
void start(vvm_simulation*) { }
|
||||
|
||||
void set_I(vvm_simulation*sim, unsigned, vpip_bit_t val)
|
||||
{ vpip_bit_t outval = val;
|
||||
if (val == Vz) val = Vx;
|
||||
vvm_event*ev = new vvm_out_event(sim, outval, output_);
|
||||
if (DELAY > 0)
|
||||
sim->insert_event(DELAY, ev);
|
||||
else
|
||||
@@ -120,14 +581,6 @@ template <unsigned WIDTH, unsigned long DELAY> class vvm_or {
|
||||
}
|
||||
|
||||
private:
|
||||
vvm_bit_t compute_() const
|
||||
{ vvm_bit_t outval = input_[0];
|
||||
for (unsigned i = 1 ; i < WIDTH ; i += 1)
|
||||
outval = outval | input_[i];
|
||||
return outval;
|
||||
}
|
||||
|
||||
vvm_bit_t input_[WIDTH];
|
||||
vvm_out_event::action_t output_;
|
||||
};
|
||||
|
||||
@@ -140,7 +593,7 @@ template <unsigned long DELAY> class vvm_bufif1 {
|
||||
input_[1] = Vx;
|
||||
}
|
||||
|
||||
void set(vvm_simulation*sim, unsigned idx, vvm_bit_t val)
|
||||
void set(vvm_simulation*sim, unsigned idx, vpip_bit_t val)
|
||||
{ if (input_[idx-1] == val)
|
||||
return;
|
||||
input_[idx-1] = val;
|
||||
@@ -156,126 +609,115 @@ template <unsigned long DELAY> class vvm_bufif1 {
|
||||
}
|
||||
|
||||
private:
|
||||
vvm_bit_t input_[2];
|
||||
vpip_bit_t input_[2];
|
||||
vvm_out_event::action_t output_;
|
||||
|
||||
vvm_bit_t compute_() const
|
||||
vpip_bit_t compute_() const
|
||||
{ if (input_[1] != V1) return Vz;
|
||||
if (input_[0] == Vz) return Vx;
|
||||
return input_[0];
|
||||
}
|
||||
};
|
||||
|
||||
template <unsigned WIDTH, unsigned long DELAY> class vvm_nand {
|
||||
template <unsigned WIDTH, unsigned long DELAY>
|
||||
class vvm_nand : private vvm_1bit_out {
|
||||
|
||||
public:
|
||||
explicit vvm_nand(vvm_out_event::action_t o)
|
||||
: output_(o)
|
||||
{ for (unsigned idx = 0 ; idx < WIDTH ; idx += 1)
|
||||
input_[idx] = V0;
|
||||
}
|
||||
: vvm_1bit_out(o, DELAY) { }
|
||||
|
||||
void init(unsigned idx, vvm_bit_t val) { input_[idx-1] = val; }
|
||||
void init_I(unsigned idx, vpip_bit_t val)
|
||||
{ input_[idx] = val; }
|
||||
|
||||
// Set an input of the NAND gate causes a new output value to
|
||||
// be calculated and an event generated to make the output
|
||||
// happen. The input pins are numbered from 1 - WIDTH.
|
||||
void set(vvm_simulation*sim, unsigned idx, vvm_bit_t val)
|
||||
{ if (input_[idx-1] == val)
|
||||
return;
|
||||
input_[idx-1] = val;
|
||||
vvm_bit_t outval = input_[0];
|
||||
for (unsigned i = 1 ; i < WIDTH ; i += 1)
|
||||
outval = outval & input_[i];
|
||||
void start(vvm_simulation*sim)
|
||||
{ output(sim, compute_nand(input_,WIDTH)); }
|
||||
|
||||
vvm_event*ev = new vvm_out_event(sim, not(outval), output_);
|
||||
if (DELAY > 0)
|
||||
sim->insert_event(DELAY, ev);
|
||||
else
|
||||
sim->active_event(ev);
|
||||
void set_I(vvm_simulation*sim, unsigned idx, vpip_bit_t val)
|
||||
{ if (input_[idx] == val) return;
|
||||
input_[idx] = val;
|
||||
output(sim, compute_nand(input_,WIDTH));
|
||||
}
|
||||
|
||||
private:
|
||||
vvm_bit_t input_[WIDTH];
|
||||
vvm_out_event::action_t output_;
|
||||
vpip_bit_t input_[WIDTH];
|
||||
};
|
||||
|
||||
/*
|
||||
* Simple inverter buffer.
|
||||
*/
|
||||
template <unsigned long DELAY> class vvm_not {
|
||||
template <unsigned long DELAY> class vvm_not : private vvm_1bit_out {
|
||||
|
||||
public:
|
||||
explicit vvm_not(vvm_out_event::action_t o)
|
||||
: output_(o)
|
||||
{ }
|
||||
: vvm_1bit_out(o, DELAY) { }
|
||||
|
||||
void init(unsigned, vvm_bit_t) { }
|
||||
void init_I(unsigned, vpip_bit_t) { }
|
||||
void start(vvm_simulation*) { }
|
||||
|
||||
void set(vvm_simulation*sim, unsigned, vvm_bit_t val)
|
||||
{ vvm_bit_t outval = not(val);
|
||||
vvm_event*ev = new vvm_out_event(sim, outval, output_);
|
||||
if (DELAY > 0)
|
||||
sim->insert_event(DELAY, ev);
|
||||
else
|
||||
sim->active_event(ev);
|
||||
}
|
||||
void set_I(vvm_simulation*sim, unsigned, vpip_bit_t val)
|
||||
{ output(sim, not(val)); }
|
||||
|
||||
private:
|
||||
vvm_out_event::action_t output_;
|
||||
};
|
||||
|
||||
template <unsigned WIDTH, unsigned long DELAY> class vvm_xnor {
|
||||
template <unsigned WIDTH, unsigned long DELAY>
|
||||
class vvm_xnor : private vvm_1bit_out {
|
||||
|
||||
public:
|
||||
explicit vvm_xnor(vvm_out_event::action_t o)
|
||||
: output_(o) { }
|
||||
: vvm_1bit_out(o,DELAY) { }
|
||||
|
||||
void init_I(unsigned idx, vpip_bit_t val) { input_[idx] = val; }
|
||||
|
||||
void init(unsigned idx, vvm_bit_t val) { input_[idx-1] = val; }
|
||||
void start(vvm_simulation*sim)
|
||||
{ vvm_event*ev = new vvm_out_event(sim, compute_(), output_);
|
||||
if (DELAY > 0)
|
||||
sim->insert_event(DELAY, ev);
|
||||
else
|
||||
sim->active_event(ev);
|
||||
}
|
||||
{ output(sim,compute_xnor(input_,WIDTH)); }
|
||||
|
||||
|
||||
|
||||
void set(vvm_simulation*sim, unsigned idx, vvm_bit_t val)
|
||||
{ if (input_[idx-1] == val)
|
||||
void set_I(vvm_simulation*sim, unsigned idx, vpip_bit_t val)
|
||||
{ if (input_[idx] == val)
|
||||
return;
|
||||
input_[idx-1] = val;
|
||||
vvm_bit_t outval = compute_();
|
||||
vvm_event*ev = new vvm_out_event(sim, outval, output_);
|
||||
if (DELAY > 0)
|
||||
sim->insert_event(DELAY, ev);
|
||||
else
|
||||
sim->active_event(ev);
|
||||
input_[idx] = val;
|
||||
output(sim,compute_xnor(input_,WIDTH));
|
||||
}
|
||||
|
||||
private:
|
||||
vvm_bit_t compute_() const
|
||||
{ vvm_bit_t outval = input_[0];
|
||||
for (unsigned i = 1 ; i < WIDTH ; i += 1)
|
||||
outval = outval ^ input_[i];
|
||||
|
||||
outval = not(outval);
|
||||
return outval;
|
||||
}
|
||||
vvm_bit_t input_[WIDTH];
|
||||
vvm_out_event::action_t output_;
|
||||
vpip_bit_t input_[WIDTH];
|
||||
};
|
||||
|
||||
template <unsigned WIDTH, unsigned long DELAY> class vvm_xor {
|
||||
template <unsigned WIDTH, unsigned long DELAY>
|
||||
class vvm_xor : private vvm_1bit_out {
|
||||
|
||||
public:
|
||||
explicit vvm_xor(vvm_out_event::action_t o)
|
||||
: vvm_1bit_out(o,DELAY) { }
|
||||
|
||||
void init_I(unsigned idx, vpip_bit_t val)
|
||||
{ input_[idx] = val; }
|
||||
|
||||
void start(vvm_simulation*sim)
|
||||
{ output(sim,compute_xor(input_,WIDTH)); }
|
||||
|
||||
void set_I(vvm_simulation*sim, unsigned idx, vpip_bit_t val)
|
||||
{ if (input_[idx] == val)
|
||||
return;
|
||||
input_[idx] = val;
|
||||
output(sim,compute_xor(input_,WIDTH)); }
|
||||
|
||||
private:
|
||||
vpip_bit_t input_[WIDTH];
|
||||
};
|
||||
|
||||
/*
|
||||
* This gate has only 3 pins, the output at pin 0 and two inputs. The
|
||||
* output is 1 or 0 if the two inputs are exactly equal or not.
|
||||
*/
|
||||
template <unsigned long DELAY> class vvm_eeq {
|
||||
|
||||
public:
|
||||
explicit vvm_eeq(vvm_out_event::action_t o)
|
||||
: output_(o) { }
|
||||
|
||||
void init(unsigned idx, vvm_bit_t val)
|
||||
{ input_[idx-1] = val; }
|
||||
void init_I(unsigned idx, vpip_bit_t val)
|
||||
{ input_[idx] = val; }
|
||||
|
||||
void start(vvm_simulation*sim)
|
||||
{ vvm_event*ev = new vvm_out_event(sim, compute_(), output_);
|
||||
@@ -285,23 +727,23 @@ template <unsigned WIDTH, unsigned long DELAY> class vvm_xor {
|
||||
sim->active_event(ev);
|
||||
}
|
||||
|
||||
void set(vvm_simulation*sim, unsigned idx, vvm_bit_t val)
|
||||
{ if (input_[idx-1] == val)
|
||||
void set_I(vvm_simulation*sim, unsigned idx, vpip_bit_t val)
|
||||
{ if (input_[idx] == val)
|
||||
return;
|
||||
input_[idx-1] = val;
|
||||
input_[idx] = val;
|
||||
start(sim);
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
vvm_bit_t compute_() const
|
||||
{ vvm_bit_t outval = input_[0];
|
||||
for (unsigned i = 1 ; i < WIDTH ; i += 1)
|
||||
outval = outval ^ input_[i];
|
||||
vpip_bit_t compute_() const
|
||||
{ vpip_bit_t outval = V0;
|
||||
if (input_[0] == input_[1])
|
||||
outval = V1;
|
||||
return outval;
|
||||
}
|
||||
|
||||
vvm_bit_t input_[WIDTH];
|
||||
vpip_bit_t input_[2];
|
||||
vvm_out_event::action_t output_;
|
||||
};
|
||||
|
||||
@@ -315,7 +757,7 @@ template <unsigned WIDTH, unsigned long DELAY> class vvm_xor {
|
||||
template <unsigned WIDTH> class vvm_udp_ssequ {
|
||||
|
||||
public:
|
||||
explicit vvm_udp_ssequ(vvm_out_event::action_t o, vvm_bit_t i,
|
||||
explicit vvm_udp_ssequ(vvm_out_event::action_t o, vpip_bit_t i,
|
||||
const vvm_u32*tab)
|
||||
: output_(o), table_(tab)
|
||||
{ state_[0] = i;
|
||||
@@ -323,10 +765,10 @@ template <unsigned WIDTH> class vvm_udp_ssequ {
|
||||
state_[idx] = Vx;
|
||||
}
|
||||
|
||||
void init(unsigned pin, vvm_bit_t val)
|
||||
void init(unsigned pin, vpip_bit_t val)
|
||||
{ state_[pin] = val; }
|
||||
|
||||
void set(vvm_simulation*sim, unsigned pin, vvm_bit_t val)
|
||||
void set(vvm_simulation*sim, unsigned pin, vpip_bit_t val)
|
||||
{ assert(pin > 0);
|
||||
assert(pin < WIDTH+1);
|
||||
if (val == Vz) val = Vx;
|
||||
@@ -353,8 +795,8 @@ template <unsigned WIDTH> class vvm_udp_ssequ {
|
||||
code &= 3;
|
||||
break;
|
||||
}
|
||||
// Convert the code to a vvm_bit_t and run with it.
|
||||
vvm_bit_t outval = (code == 0)? V0 : (code == 1)? V1 : Vx;
|
||||
// Convert the code to a vpip_bit_t and run with it.
|
||||
vpip_bit_t outval = (code == 0)? V0 : (code == 1)? V1 : Vx;
|
||||
state_[0] = outval;
|
||||
state_[pin] = val;
|
||||
vvm_event*ev = new vvm_out_event(sim, outval, output_);
|
||||
@@ -364,7 +806,7 @@ template <unsigned WIDTH> class vvm_udp_ssequ {
|
||||
private:
|
||||
vvm_out_event::action_t output_;
|
||||
const vvm_u32*const table_;
|
||||
vvm_bit_t state_[WIDTH+1];
|
||||
vpip_bit_t state_[WIDTH+1];
|
||||
};
|
||||
|
||||
class vvm_bufz {
|
||||
@@ -373,9 +815,9 @@ class vvm_bufz {
|
||||
: output_(o)
|
||||
{ }
|
||||
|
||||
void init(unsigned idx, vvm_bit_t val) { }
|
||||
void init(unsigned idx, vpip_bit_t val) { }
|
||||
|
||||
void set(vvm_simulation*sim, unsigned idx, vvm_bit_t val)
|
||||
void set(vvm_simulation*sim, unsigned idx, vpip_bit_t val)
|
||||
{ output_(sim, val); }
|
||||
|
||||
private:
|
||||
@@ -420,7 +862,7 @@ template <unsigned WIDTH> class vvm_pevent {
|
||||
|
||||
vvm_bitset_t<WIDTH> get() const { return value_; }
|
||||
|
||||
void set(vvm_simulation*sim, unsigned idx, vvm_bit_t val)
|
||||
void set_P(vvm_simulation*sim, unsigned idx, vpip_bit_t val)
|
||||
{ if (value_[idx] == val) return;
|
||||
switch (edge_) {
|
||||
case ANYEDGE:
|
||||
@@ -438,7 +880,7 @@ template <unsigned WIDTH> class vvm_pevent {
|
||||
value_[idx] = val;
|
||||
}
|
||||
|
||||
void init(int idx, vvm_bit_t val)
|
||||
void init_P(int idx, vpip_bit_t val)
|
||||
{ assert(idx < WIDTH);
|
||||
value_[idx] = val;
|
||||
}
|
||||
@@ -455,48 +897,46 @@ template <unsigned WIDTH> class vvm_pevent {
|
||||
|
||||
/*
|
||||
* $Log: vvm_gates.h,v $
|
||||
* Revision 1.12 1999/07/17 03:07:27 steve
|
||||
* pevent objects have initial values.
|
||||
* Revision 1.30 1999/12/02 16:58:58 steve
|
||||
* Update case comparison (Eric Aardoom).
|
||||
*
|
||||
* Revision 1.11 1999/06/09 00:58:29 steve
|
||||
* Support for binary | (Stephen Tell)
|
||||
* Revision 1.29 1999/12/02 04:54:11 steve
|
||||
* Handle mux sel of X, if inputs are equal.
|
||||
*
|
||||
* Revision 1.10 1999/05/03 01:51:29 steve
|
||||
* Restore support for wait event control.
|
||||
* Revision 1.28 1999/11/25 01:34:04 steve
|
||||
* Reduce more gate templates to use vvm_1bit_out (Eric Aardoom)
|
||||
*
|
||||
* Revision 1.9 1999/05/01 20:43:55 steve
|
||||
* Handle wide events, such as @(a) where a has
|
||||
* many bits in it.
|
||||
* Revision 1.27 1999/11/24 04:38:49 steve
|
||||
* LT and GT fixes from Eric Aardoom.
|
||||
*
|
||||
* Add to vvm the binary ^ and unary & operators.
|
||||
* Revision 1.26 1999/11/22 00:30:52 steve
|
||||
* Detemplate some and, or and nor methods.
|
||||
*
|
||||
* Dump events a bit more completely.
|
||||
* Revision 1.25 1999/11/21 01:16:51 steve
|
||||
* Fix coding errors handling names of logic devices,
|
||||
* and add support for buf device in vvm.
|
||||
*
|
||||
* Revision 1.8 1999/05/01 02:57:53 steve
|
||||
* Handle much more complex event expressions.
|
||||
* Revision 1.24 1999/11/21 00:13:09 steve
|
||||
* Support memories in continuous assignments.
|
||||
*
|
||||
* Revision 1.7 1999/02/15 05:52:50 steve
|
||||
* Mangle that handles device instance numbers.
|
||||
* Revision 1.23 1999/11/15 00:42:31 steve
|
||||
* Fixup to include right shift support.
|
||||
*
|
||||
* Revision 1.6 1999/01/31 18:15:55 steve
|
||||
* Missing start methods.
|
||||
* Revision 1.22 1999/11/14 23:43:46 steve
|
||||
* Support combinatorial comparators.
|
||||
*
|
||||
* Revision 1.5 1999/01/01 01:44:56 steve
|
||||
* Support the start() method.
|
||||
* Revision 1.21 1999/11/14 20:24:28 steve
|
||||
* Add support for the LPM_CLSHIFT device.
|
||||
*
|
||||
* Revision 1.4 1998/12/20 02:05:41 steve
|
||||
* Function to calculate wire initial value.
|
||||
* Revision 1.20 1999/11/14 18:22:12 steve
|
||||
* Fix NAND gate support to use named pins.
|
||||
*
|
||||
* Revision 1.3 1998/12/17 23:54:58 steve
|
||||
* VVM support for small sequential UDP objects.
|
||||
*
|
||||
* Revision 1.2 1998/11/10 00:48:31 steve
|
||||
* Add support it vvm target for level-sensitive
|
||||
* triggers (i.e. the Verilog wait).
|
||||
* Fix display of $time is format strings.
|
||||
*
|
||||
* Revision 1.1 1998/11/09 23:44:11 steve
|
||||
* Add vvm library.
|
||||
* Revision 1.19 1999/11/13 03:46:52 steve
|
||||
* Support the LPM_MUX in vvm.
|
||||
*
|
||||
* Revision 1.18 1999/11/01 02:07:41 steve
|
||||
* Add the synth functor to do generic synthesis
|
||||
* and add the LPM_FF device to handle rows of
|
||||
* flip-flops.
|
||||
*/
|
||||
#endif
|
||||
|
||||
+23
-135
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* 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
|
||||
@@ -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.4 1999/06/19 03:31:33 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,62 +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;
|
||||
|
||||
for (;;) {
|
||||
/* 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) {
|
||||
vvm_event*cur = active;
|
||||
active = cur->next_;
|
||||
cur->event_function();
|
||||
delete cur;
|
||||
}
|
||||
}
|
||||
|
||||
/* 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 {
|
||||
@@ -188,14 +69,9 @@ class delay_event : public vvm_event {
|
||||
vvm_thread*thr_;
|
||||
};
|
||||
|
||||
void vvm_simulation::s_finish()
|
||||
{
|
||||
going_ = false;
|
||||
}
|
||||
|
||||
void vvm_simulation::thread_delay(unsigned long delay, vvm_thread*thr)
|
||||
{
|
||||
assert(delay > 0);
|
||||
delay_event*ev = new delay_event(thr);
|
||||
insert_event(delay, ev);
|
||||
}
|
||||
@@ -209,6 +85,18 @@ 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.
|
||||
*
|
||||
* Revision 1.5 1999/09/29 02:53:33 steve
|
||||
* Useless assertion.
|
||||
*
|
||||
* Revision 1.4 1999/06/19 03:31:33 steve
|
||||
* End run if events run out.
|
||||
*
|
||||
|
||||
@@ -0,0 +1,92 @@
|
||||
|
||||
For those of you who wish to use Icarus Verilog, in combination with
|
||||
the Xilinx back end (Foundation or Alliance), it can be done. I have
|
||||
run some admittedly simple (no arithmetic, 600 equivalent gates) designs
|
||||
through this setup, targeting a Spartan XCS10.
|
||||
|
||||
Verilog:
|
||||
|
||||
As of Icarus Verilog 19990814, you still can't have logic buried
|
||||
in procedural (flip-flop) assignment. I use a hacked workaround
|
||||
copy of ivl that allows 1-bit wide logic. The other approach
|
||||
is to use temporary wires, assign them to the logic, and assign
|
||||
the reg to that wire. For example, instead of
|
||||
always @ (posedge Clk) Z = ~Q1 & ~Q2 & ~Q3 & ~Q4;
|
||||
you can write
|
||||
wire newZ;
|
||||
assign newZ = ~Q1 & ~Q2 & ~Q3 & ~Q4;
|
||||
always @ (posedge Clk) Z = newZ;
|
||||
|
||||
Procedural assignments have to be given one at a time, to be
|
||||
"found" by xnfsyn. Say
|
||||
always @ (posedge Clk) Y = newY;
|
||||
always @ (posedge Clk) Z = newZ;
|
||||
rather than
|
||||
always @ (posedge Clk) begin
|
||||
Y = newY;
|
||||
Z = newZ;
|
||||
end
|
||||
|
||||
I had reason to use a global clock net. I used this snippet of
|
||||
Verilog code to make it happen:
|
||||
primitive BUFG ( O, I );
|
||||
output O;
|
||||
input I;
|
||||
table
|
||||
0:0;
|
||||
1:1;
|
||||
endtable
|
||||
endprimitive
|
||||
$attribute(BUFG,"XNF-LCA","BUFG:O,I")
|
||||
|
||||
Oh, yes, you probably also want to choose I/O pins! Try this:
|
||||
wire d1;
|
||||
$attribute(d1, "PAD", "i45"); // input
|
||||
wire vsync;
|
||||
$attribute(vsync, "PAD", "o67"); // output
|
||||
|
||||
Running ivl:
|
||||
|
||||
The -F switches are important. The following order seems to robustly
|
||||
generate valid XNF files:
|
||||
-Fxnfio -Fnobufz -Fsigfold -Fxnfsyn
|
||||
|
||||
Generating .pcf files:
|
||||
|
||||
The ngdbuild step seems to lose pin placement information that ivl
|
||||
puts in the XNF file. Use xnf2pcf to extract this information to
|
||||
a .pcf file, which the Xilinx place-and-route software _will_ pay
|
||||
attention to.
|
||||
|
||||
Running the Xilinx back end:
|
||||
|
||||
You can presumably use the GUI, but that doesn't fit in Makefiles :-).
|
||||
Here is the command sequence in pseudo-shell-script:
|
||||
ngdbuild -p $part $1.xnf $1.ngd
|
||||
map -p $part -o map.ncd $1.ngd
|
||||
xnf2pcf <$1.xnf >$1.pcf # see above
|
||||
par -w -ol 2 -d 0 map.ncd $1.ncd $1.pcf
|
||||
bitgen_flags = -g ConfigRate:SLOW -g TdoPin:PULLNONE -g DonePin:PULLUP \
|
||||
-g CRC:enable -g StartUpClk:CCLK -g SyncToDone:no \
|
||||
-g DoneActive:C1 -g OutputsActive:C3 -g GSRInactive:C4 \
|
||||
-g ReadClk:CCLK -g ReadCapture:enable -g ReadAbort:disable
|
||||
bitgen $1.ncd -l -w $bitgen_flags
|
||||
|
||||
The Xilinx software has diarrhea of the temp files (14, not including
|
||||
.xnf, .pcf, .ngd, .ncd, and .bit), so this sequence is best done in a
|
||||
dedicated directory. Note in particular that map.ncd is a generic name.
|
||||
|
||||
Downloading:
|
||||
|
||||
I use the XESS (http://www.xess.com/) XSP-10 development board, which
|
||||
uses the PC parallel (printer) port for downloading and interaction
|
||||
with the host. They made an old version of their download program
|
||||
public domain, posted it at
|
||||
http://www.xess.com/FPGA/xstools.zip ,
|
||||
and now there is a Linux port at
|
||||
ftp://ftp.microux.com/pub/pilotscope/xstools.tar.gz .
|
||||
|
||||
The above hints are based on my experience with Foundation 1.5 on NT
|
||||
(gack) and Alliance 2.1i on Solaris. Your mileage may vary. Good luck!
|
||||
|
||||
- Larry Doolittle <[email protected]> August 19, 1999
|
||||
@@ -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 -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,26 @@ 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.
|
||||
|
||||
Revision 1.3 1999/07/22 02:05:20 steve
|
||||
is_constant method for PEConcat.
|
||||
|
||||
|
||||
+26
@@ -0,0 +1,26 @@
|
||||
#!/bin/sh
|
||||
|
||||
# xnf2pcf
|
||||
|
||||
# Converts perfectly good EXT records from an XNF file to
|
||||
# a .pcf file for the "par" step of the Xilinx toolchain.
|
||||
# Why on earth is this needed? Oh, well, the joys of working
|
||||
# with black-box-ware.
|
||||
|
||||
# Usage: xnf2pcf <design.xnf >design.pcf
|
||||
|
||||
# Refer to the resulting .pcf file in the invocation of "par", syntax:
|
||||
# par [options] infile[.ncd] outfile pcf_file[.pcf]
|
||||
|
||||
# Tested (successfully!) with XNF from Icarus Verilog, see
|
||||
# http://www.geda.seul.org/tools/verilog/index.html
|
||||
# and Xilinx back end tools from Foundation 1.5
|
||||
|
||||
# Author: Larry Doolittle <[email protected]>
|
||||
# Date: August 19, 1999
|
||||
|
||||
echo "SCHEMATIC START ;"
|
||||
echo "SCHEMATIC END ;"
|
||||
echo
|
||||
|
||||
awk '/^EXT/{gsub(",",""); printf("COMP \"%s\" LOCATE = SITE \"P%s\" ;\n", $2, $4)}'
|
||||
@@ -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.
|
||||
*
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user