mirror of
https://github.com/steveicarus/iverilog.git
synced 2026-08-23 06:16:47 +02:00
Compare commits
223
Commits
version0_1
...
s20000512
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
b44abcd481 | ||
|
|
c3282bfa6c | ||
|
|
367db72c99 | ||
|
|
4f0b0cb8ce | ||
|
|
d68339a96a | ||
|
|
6021c7b192 | ||
|
|
d4bab8709b | ||
|
|
2f59918c74 | ||
|
|
de1a7a0933 | ||
|
|
e9742c662b | ||
|
|
e81ce68e8c | ||
|
|
c98e4b25b3 | ||
|
|
c4d8ded269 | ||
|
|
35a2690d75 | ||
|
|
ca6631fdda | ||
|
|
b28f258463 | ||
|
|
b90cda1f3f | ||
|
|
ca2fd41bb6 | ||
|
|
43643ba98f | ||
|
|
f847b9cfeb | ||
|
|
fbe475ef7d | ||
|
|
f95b082339 | ||
|
|
0a70a8a954 | ||
|
|
ed5e587cf1 | ||
|
|
1db70a0c46 | ||
|
|
69612ceb73 | ||
|
|
8d8f1e2401 | ||
|
|
b175e4aef7 | ||
|
|
8a4937bada | ||
|
|
b5b15a5990 | ||
|
|
3aef1be0e7 | ||
|
|
77361fb8a0 | ||
|
|
3a9be680a4 | ||
|
|
acfb5c177d | ||
|
|
2b40c7ce11 | ||
|
|
08e9a114a2 | ||
|
|
1f7090135b | ||
|
|
1412eb2697 | ||
|
|
dab5999621 | ||
|
|
906c7b4783 | ||
|
|
e78af393de | ||
|
|
72c8897d13 | ||
|
|
9ca1791b43 | ||
|
|
6e8fe39cc7 | ||
|
|
6446add9cd | ||
|
|
ebacf88b14 | ||
|
|
a8114ae122 | ||
|
|
44838f8973 | ||
|
|
ad8811282b | ||
|
|
181b776f0c | ||
|
|
c0d51dd2eb | ||
|
|
99a891b8a1 | ||
|
|
23725cf42c | ||
|
|
9a36dcd33d | ||
|
|
d539b0b5fe | ||
|
|
37e65614a0 | ||
|
|
88d3ad51b0 | ||
|
|
2094a2f466 | ||
|
|
74c43032b3 | ||
|
|
4f07c43976 | ||
|
|
726f7b8b11 | ||
|
|
5624a66bbb | ||
|
|
7484feceb5 | ||
|
|
d033509359 | ||
|
|
62c6422724 | ||
|
|
df0808d5bb | ||
|
|
4493e968da | ||
|
|
59bbc27268 | ||
|
|
b1fd927acb | ||
|
|
b0d0cdbd7d | ||
|
|
8dbd64121f | ||
|
|
72b3508911 | ||
|
|
8d16ee9dd5 | ||
|
|
cad5df1e9f | ||
|
|
e9b06f1022 | ||
|
|
7307deb3a9 | ||
|
|
f6959ba09e | ||
|
|
2693a8cd7d | ||
|
|
30e8289239 | ||
|
|
b62a7ace5c | ||
|
|
67bdd433a9 | ||
|
|
6150be2324 | ||
|
|
694ff934af | ||
|
|
2dd010dc04 | ||
|
|
26dcecebdb | ||
|
|
d97ab9be23 | ||
|
|
995f7e89d1 | ||
|
|
995f61ace4 | ||
|
|
b9d19d3358 | ||
|
|
ffc3a42405 | ||
|
|
8a10511105 | ||
|
|
9f84deeb56 | ||
|
|
dcaea50b8f | ||
|
|
c790ccca5a | ||
|
|
edc40f1792 | ||
|
|
eb9ed665f3 | ||
|
|
d4370a0878 | ||
|
|
a9e11d6546 | ||
|
|
649ce73047 | ||
|
|
3265f3f63a | ||
|
|
c3da6febbd | ||
|
|
c5b64b4ad4 | ||
|
|
44d30ad127 | ||
|
|
94270ff988 | ||
|
|
2deb379c06 | ||
|
|
09e0d668a6 | ||
|
|
80bd855329 | ||
|
|
567de6ba39 | ||
|
|
48de739506 | ||
|
|
3adaf23aab | ||
|
|
e71413123e | ||
|
|
51e96a2d8b | ||
|
|
38fd245767 | ||
|
|
20712d3fcc | ||
|
|
8cbf4f815e | ||
|
|
5ea3610d4a | ||
|
|
9deb7f6ba5 | ||
|
|
7ab6ff77ad | ||
|
|
2563e2b717 | ||
|
|
2e05f7f7ec | ||
|
|
01c5147079 | ||
|
|
71a506a28a | ||
|
|
6eef54595f | ||
|
|
79f772200a | ||
|
|
78ab1a7bba | ||
|
|
61822d48aa | ||
|
|
e7efc2709a | ||
|
|
0fbca815b4 | ||
|
|
1698a19cf6 | ||
|
|
7b5b5c2f39 | ||
|
|
2a68121685 | ||
|
|
380d5620e6 | ||
|
|
aae17041ef | ||
|
|
1d7cf5bb8c | ||
|
|
8696a4363a | ||
|
|
59c240bc9b | ||
|
|
d751b05cec | ||
|
|
843af31958 | ||
|
|
5aea537ab9 | ||
|
|
b734ecf02f | ||
|
|
5b52c384d6 | ||
|
|
2cba0a50f3 | ||
|
|
b354cf68b8 | ||
|
|
a9264d71c6 | ||
|
|
e0873f6c14 | ||
|
|
b8ddbcf62b | ||
|
|
bd09bed662 | ||
|
|
1ee4015aa8 | ||
|
|
a8d787bd66 | ||
|
|
e77bcf6910 | ||
|
|
2bc8f79e0f | ||
|
|
e58be1b128 | ||
|
|
ee180f6cf0 | ||
|
|
ce0b97a8f0 | ||
|
|
cf8d17a6ab | ||
|
|
e6bd088984 | ||
|
|
9b3c3b6e7a | ||
|
|
dc5bd8ea59 | ||
|
|
121b6c2ecb | ||
|
|
57d28e4f86 | ||
|
|
d84b72609d | ||
|
|
ef98be1192 | ||
|
|
3b9dedbc86 | ||
|
|
aa8908c52f | ||
|
|
3d1ffced57 | ||
|
|
f37f69f160 | ||
|
|
fac3bde2c8 | ||
|
|
9125a4c451 | ||
|
|
bed47a4ab4 | ||
|
|
2de887c2ff | ||
|
|
fdf2c1b0d0 | ||
|
|
7f78b9bf56 | ||
|
|
d6f53b2582 | ||
|
|
848110bc33 | ||
|
|
eb4cdc5026 | ||
|
|
3d673c1f02 | ||
|
|
a48b4c4f8d | ||
|
|
ba7fdb580d | ||
|
|
9e5ff89ef3 | ||
|
|
0d5e4b40d0 | ||
|
|
142b9e667d | ||
|
|
f3b76d958d | ||
|
|
87d6df5204 | ||
|
|
c7193fa6fe | ||
|
|
645c24289e | ||
|
|
e52a5be16e | ||
|
|
7e37b61a05 | ||
|
|
cbd353fbb8 | ||
|
|
4c274223cf | ||
|
|
65e4e9f428 | ||
|
|
e6820ed169 | ||
|
|
c3cb0f2371 | ||
|
|
31f1ceea9f | ||
|
|
94afe54741 | ||
|
|
080f161c37 | ||
|
|
5ce35e3e60 | ||
|
|
6d0edcf58a | ||
|
|
7033836e01 | ||
|
|
b7409d98ff | ||
|
|
b6d1bb1fa7 | ||
|
|
4558a7d8d0 | ||
|
|
22c2625ace | ||
|
|
4de8ba489d | ||
|
|
65ae92859c | ||
|
|
d355270c2d | ||
|
|
ced7cc6d60 | ||
|
|
d54cc14ca2 | ||
|
|
98a57f4fac | ||
|
|
40ca71b10b | ||
|
|
e7e58cdd71 | ||
|
|
1dcf9de34c | ||
|
|
fcb1d8dc72 | ||
|
|
5fa7e1c31b | ||
|
|
6e3c258edb | ||
|
|
6be5421c8a | ||
|
|
76655ce2bb | ||
|
|
3e1738dcec | ||
|
|
ec8dec74a6 | ||
|
|
838d25890b | ||
|
|
4a6d3a5104 | ||
|
|
b688cdbc40 | ||
|
|
09de918198 | ||
|
|
3e2bb85f58 |
@@ -1,3 +1,4 @@
|
||||
lexor_keyword.cc
|
||||
parse.h
|
||||
parse.cc
|
||||
parse.cc.output
|
||||
@@ -7,6 +8,8 @@ dep
|
||||
configure
|
||||
Makefile
|
||||
verilog
|
||||
gverilog
|
||||
iverilog
|
||||
config.status
|
||||
config.log
|
||||
config.cache
|
||||
|
||||
+5
-2
@@ -18,8 +18,8 @@
|
||||
* 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: LineInfo.h,v 1.3 1999/02/15 02:06:15 steve Exp $"
|
||||
#if !defined(WINNT) && !defined(macintosh)
|
||||
#ident "$Id: LineInfo.h,v 1.4 2000/02/23 02:56:53 steve Exp $"
|
||||
#endif
|
||||
|
||||
# include <cstdio>
|
||||
@@ -50,6 +50,9 @@ class LineInfo {
|
||||
|
||||
/*
|
||||
* $Log: LineInfo.h,v $
|
||||
* Revision 1.4 2000/02/23 02:56:53 steve
|
||||
* Macintosh compilers do not support ident.
|
||||
*
|
||||
* Revision 1.3 1999/02/15 02:06:15 steve
|
||||
* Elaborate gate ranges.
|
||||
*
|
||||
|
||||
+39
-14
@@ -18,12 +18,12 @@
|
||||
# 59 Temple Place - Suite 330
|
||||
# Boston, MA 02111-1307, USA
|
||||
#
|
||||
#ident "$Id: Makefile.in,v 1.30 1999/11/29 17:02:21 steve Exp $"
|
||||
#ident "$Id: Makefile.in,v 1.54 2000/05/12 05:23:15 steve Exp $"
|
||||
#
|
||||
#
|
||||
SHELL = /bin/sh
|
||||
|
||||
VERSION = 0.0
|
||||
VERSION = 0.3PRE
|
||||
|
||||
prefix = @prefix@
|
||||
exec_prefix = @exec_prefix@
|
||||
@@ -39,6 +39,7 @@ includedir = $(prefix)/include
|
||||
CC = @CC@
|
||||
CXX = @CXX@
|
||||
INSTALL = @INSTALL@
|
||||
INSTALL_SCRIPT = @INSTALL_SCRIPT@
|
||||
INSTALL_PROGRAM = @INSTALL_PROGRAM@
|
||||
INSTALL_DATA = @INSTALL_DATA@
|
||||
STRIP = @STRIP@
|
||||
@@ -47,7 +48,7 @@ CPPFLAGS = @CPPFLAGS@ @DEFS@
|
||||
CXXFLAGS = @CXXFLAGS@ -I$(srcdir)
|
||||
LDFLAGS = @LDFLAGS@
|
||||
|
||||
all: ivl verilog
|
||||
all: ivl verilog iverilog
|
||||
cd vpi ; $(MAKE) all
|
||||
cd vvm ; $(MAKE) all
|
||||
cd ivlpp ; $(MAKE) all
|
||||
@@ -66,14 +67,18 @@ distclean: clean
|
||||
rm -f Makefile
|
||||
|
||||
TT = t-null.o t-verilog.o t-vvm.o t-xnf.o
|
||||
FF = nobufz.o nodangle.o propinit.o sigfold.o synth.o xnfio.o xnfsyn.o
|
||||
FF = nodangle.o propinit.o synth.o xnfio.o
|
||||
|
||||
O = main.o cprop.o design_dump.o dup_expr.o elaborate.o elab_expr.o \
|
||||
elab_net.o emit.o eval.o eval_tree.o expr_synth.o functor.o \
|
||||
lexor.o lexor_keyword.o mangle.o netlist.o pad_to_width.o \
|
||||
elab_net.o elab_pexpr.o elab_scope.o elab_sig.o emit.o eval.o eval_tree.o \
|
||||
expr_synth.o functor.o lexor.o lexor_keyword.o link_const.o \
|
||||
mangle.o netlist.o \
|
||||
net_design.o net_event.o net_force.o net_scope.o net_udp.o nexus_from_link.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 \
|
||||
verinum.o verireal.o target.o targets.o util.o Module.o PDelays.o PEvent.o \
|
||||
PExpr.o PGate.o \
|
||||
PTask.o PFunction.o PWire.o Statement.o \
|
||||
$(FF) $(TT)
|
||||
|
||||
@@ -91,11 +96,15 @@ verilog: $(srcdir)/verilog.sh
|
||||
sed -e 's;@$(tmp1)@;@bindir@;' \
|
||||
-e 's;@$(tmp2)@;@libdir@;' \
|
||||
-e 's;@$(tmp3)@;@includedir@;' \
|
||||
-e 's;@dllib@;@DLLIB@;' \
|
||||
-e 's;@$(tmp4)@;@CXX@;' < $< > $@
|
||||
|
||||
ivl: $O
|
||||
$(CXX) $(CXXFLAGS) -o ivl $O
|
||||
|
||||
iverilog: iverilog.c
|
||||
$(CC) $(CPPFLAGS) -o iverilog -DCXX='"@CXX@"' -DIVL_ROOT='"@libdir@/ivl"' -DIVL_INC='"@includedir@"' -DIVL_LIB='"@libdir@"' -DDLLIB='"@DLLIB@"' iverilog.c
|
||||
|
||||
%.o dep/%.d: %.cc
|
||||
@[ -d dep ] || mkdir dep
|
||||
$(CXX) $(CPPFLAGS) $(CXXFLAGS) -MD -c $< -o $*.o
|
||||
@@ -113,28 +122,44 @@ parse.h parse.cc: $(srcdir)/parse.y
|
||||
lexor.cc: $(srcdir)/lexor.lex
|
||||
flex -PVL -s -olexor.cc $(srcdir)/lexor.lex
|
||||
|
||||
install: all installdirs $(bindir)/verilog $(bindir)/ivl $(mandir)/man1/verilog.1
|
||||
lexor_keyword.o dep/lexor_keyword.d: lexor_keyword.cc
|
||||
|
||||
lexor_keyword.cc: lexor_keyword.gperf
|
||||
gperf -o -i 7 -C -k 1-3,$$ -L ANSI-C -H keyword_hash -N check_identifier -t lexor_keyword.gperf > lexor_keyword.cc
|
||||
|
||||
|
||||
install: all installdirs $(bindir)/verilog $(bindir)/iverilog $(libdir)/ivl/ivl $(mandir)/man1/verilog.1 $(mandir)/man1/iverilog.1
|
||||
cd vpi ; $(MAKE) install
|
||||
cd vvm ; $(MAKE) install
|
||||
cd ivlpp ; $(MAKE) install
|
||||
|
||||
$(bindir)/verilog: ./verilog
|
||||
$(INSTALL_PROGRAM) ./verilog $(bindir)/verilog
|
||||
$(INSTALL_SCRIPT) ./verilog $(bindir)/verilog
|
||||
|
||||
$(bindir)/ivl: ivl
|
||||
$(INSTALL_PROGRAM) ./ivl $(bindir)/ivl
|
||||
$(STRIP) $(bindir)/ivl
|
||||
$(bindir)/iverilog: ./iverilog
|
||||
$(INSTALL_PROGRAM) ./iverilog $(bindir)/iverilog
|
||||
$(STRIP) $(bindir)/iverilog
|
||||
|
||||
$(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
|
||||
|
||||
$(mandir)/man1/iverilog.1: $(srcdir)/iverilog.man
|
||||
$(INSTALL_DATA) $(srcdir)/iverilog.man $(mandir)/man1/iverilog.1
|
||||
|
||||
installdirs: mkinstalldirs
|
||||
$(srcdir)/mkinstalldirs $(bindir) $(mandir)/man1
|
||||
$(srcdir)/mkinstalldirs $(bindir) $(libdir)/ivl $(mandir)/man1
|
||||
|
||||
uninstall:
|
||||
rm -f $(bindir)/ivl
|
||||
rm -f $(libdir)/ivl/ivl
|
||||
rm -f $(bindir)/verilog
|
||||
rm -f $(bindir)/gverilog
|
||||
rm -f $(bindir)/iverilog
|
||||
rm -f $(mandir)/man1/verilog.1
|
||||
rm -f $(mandir)/man1/iverilog.1
|
||||
cd vpi ; $(MAKE) uninstall
|
||||
cd vvm ; $(MAKE) uninstall
|
||||
cd ivlpp ; $(MAKE) uninstall
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 1998 Stephen Williams ([email protected])
|
||||
* Copyright (c) 1998-2000 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
|
||||
@@ -16,24 +16,38 @@
|
||||
* 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: Module.cc,v 1.7 1999/09/17 02:06:25 steve Exp $"
|
||||
#if !defined(WINNT) && !defined(macintosh)
|
||||
#ident "$Id: Module.cc,v 1.11 2000/03/12 17:09:40 steve Exp $"
|
||||
#endif
|
||||
|
||||
# include "Module.h"
|
||||
# include "PGate.h"
|
||||
# include "PWire.h"
|
||||
# include <assert.h>
|
||||
|
||||
Module::Module(const string&name, const svector<Module::port_t*>*pp)
|
||||
: name_(name)
|
||||
{
|
||||
if (pp) {
|
||||
// Save the list of ports, then scan the list to make
|
||||
// the implicit wires. Add those wires to the wire map.
|
||||
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]);
|
||||
|
||||
// The port can actually be a list of wires, to
|
||||
// remember to scan the set. Also note the case
|
||||
// where a wire may be connected to multiple
|
||||
// ports, and reuse the link if that happens.
|
||||
for (unsigned jdx = 0; jdx < cur->wires.count(); jdx += 1) {
|
||||
PWire*tmp = add_wire(cur->wires[jdx]);
|
||||
if (tmp != cur->wires[jdx]) {
|
||||
delete cur->wires[jdx];
|
||||
cur->wires[jdx] = tmp;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -53,9 +67,14 @@ void Module::add_function(const string &name, PFunction *func)
|
||||
funcs_[name] = func;
|
||||
}
|
||||
|
||||
void Module::add_wire(PWire*wire)
|
||||
PWire* Module::add_wire(PWire*wire)
|
||||
{
|
||||
wires_.push_back(wire);
|
||||
PWire*&ep = wires_[wire->name()];
|
||||
if (ep) return ep;
|
||||
|
||||
assert(ep == 0);
|
||||
ep = wire;
|
||||
return wire;
|
||||
}
|
||||
|
||||
void Module::add_behavior(PProcess*b)
|
||||
@@ -85,22 +104,58 @@ unsigned Module::find_port(const string&name) const
|
||||
}
|
||||
|
||||
|
||||
PWire* Module::get_wire(const string&name)
|
||||
PWire* Module::get_wire(const string&name) const
|
||||
{
|
||||
for (list<PWire*>::iterator cur = wires_.begin()
|
||||
; cur != wires_.end()
|
||||
map<string,PWire*>::const_iterator obj = wires_.find(name);
|
||||
if (obj == wires_.end())
|
||||
return 0;
|
||||
else
|
||||
return (*obj).second;
|
||||
}
|
||||
|
||||
PGate* Module::get_gate(const string&name)
|
||||
{
|
||||
for (list<PGate*>::iterator cur = gates_.begin()
|
||||
; cur != gates_.end()
|
||||
; cur ++ ) {
|
||||
|
||||
if ((*cur)->name() == name)
|
||||
if ((*cur)->get_name() == name)
|
||||
return *cur;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
const map<string,PWire*>& Module::get_wires() const
|
||||
{
|
||||
return wires_;
|
||||
}
|
||||
|
||||
const list<PGate*>& Module::get_gates() const
|
||||
{
|
||||
return gates_;
|
||||
}
|
||||
|
||||
const list<PProcess*>& Module::get_behaviors() const
|
||||
{
|
||||
return behaviors_;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* $Log: Module.cc,v $
|
||||
* Revision 1.11 2000/03/12 17:09:40 steve
|
||||
* Support localparam.
|
||||
*
|
||||
* Revision 1.10 2000/02/23 02:56:53 steve
|
||||
* Macintosh compilers do not support ident.
|
||||
*
|
||||
* Revision 1.9 2000/01/09 20:37:57 steve
|
||||
* Careful with wires connected to multiple ports.
|
||||
*
|
||||
* Revision 1.8 1999/12/11 05:45:41 steve
|
||||
* Fix support for attaching attributes to primitive gates.
|
||||
*
|
||||
* Revision 1.7 1999/09/17 02:06:25 steve
|
||||
* Handle unconnected module ports.
|
||||
*
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
#ifndef __Module_H
|
||||
#define __Module_H
|
||||
/*
|
||||
* Copyright (c) 1998 Stephen Williams ([email protected])
|
||||
* Copyright (c) 1998-2000 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
|
||||
@@ -18,14 +18,16 @@
|
||||
* 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: Module.h,v 1.10 1999/11/27 19:07:57 steve Exp $"
|
||||
#if !defined(WINNT) && !defined(macintosh)
|
||||
#ident "$Id: Module.h,v 1.18 2000/05/02 16:27:38 steve Exp $"
|
||||
#endif
|
||||
|
||||
# include <list>
|
||||
# include <map>
|
||||
# include "svector.h"
|
||||
# include "named.h"
|
||||
# include <string>
|
||||
class PEvent;
|
||||
class PExpr;
|
||||
class PGate;
|
||||
class PTask;
|
||||
@@ -64,6 +66,13 @@ class Module {
|
||||
module is elaborated. During parsing, I put the parameters
|
||||
into this map. */
|
||||
map<string,PExpr*>parameters;
|
||||
map<string,PExpr*>localparams;
|
||||
|
||||
/* The module also has defparam assignments which don't create
|
||||
new parameters within the module, but may be used to set
|
||||
values within this module (when instantiated) or in other
|
||||
instantiated modules. */
|
||||
map<string,PExpr*>defparms;
|
||||
|
||||
/* Parameters may be overridden at instantiation time;
|
||||
the overrides do not contain explicit parameter names,
|
||||
@@ -73,10 +82,19 @@ class Module {
|
||||
a parameter-index to its name. */
|
||||
list<string> param_names;
|
||||
|
||||
/* Keep a table of named events declared in the module. */
|
||||
map<string,PEvent*>events;
|
||||
|
||||
|
||||
const string&get_name() const { return name_; }
|
||||
|
||||
void add_gate(PGate*gate);
|
||||
void add_wire(PWire*wire);
|
||||
|
||||
// The add_wire method adds a wire by name, but only if the
|
||||
// wire name doesn't already exist. Either way, the result is
|
||||
// the existing wire or the pointer passed in.
|
||||
PWire* add_wire(PWire*wire);
|
||||
|
||||
void add_behavior(PProcess*behave);
|
||||
void add_task(const string&name, PTask*def);
|
||||
void add_function(const string&name, PFunction*def);
|
||||
@@ -87,20 +105,25 @@ class Module {
|
||||
|
||||
// Find a wire by name. This is used for connecting gates to
|
||||
// existing wires, etc.
|
||||
PWire* get_wire(const string&name);
|
||||
PWire* get_wire(const string&name) const;
|
||||
PGate* get_gate(const string&name);
|
||||
|
||||
const list<PWire*>& get_wires() const { return wires_; }
|
||||
const list<PGate*>& get_gates() const { return gates_; }
|
||||
const list<PProcess*>& get_behaviors() const { return behaviors_; }
|
||||
const map<string,PWire*>& get_wires() const;
|
||||
const list<PGate*>& get_gates() const;
|
||||
const list<PProcess*>& get_behaviors() const;
|
||||
|
||||
void dump(ostream&out) const;
|
||||
bool elaborate(Design*, NetScope*scope, svector<PExpr*>*overrides_) const;
|
||||
bool elaborate(Design*, NetScope*scope) const;
|
||||
|
||||
bool elaborate_scope(Design*, NetScope*scope) const;
|
||||
|
||||
bool elaborate_sig(Design*, NetScope*scope) const;
|
||||
|
||||
private:
|
||||
const string name_;
|
||||
|
||||
svector<port_t*> ports_;
|
||||
list<PWire*> wires_;
|
||||
map<string,PWire*> wires_;
|
||||
list<PGate*> gates_;
|
||||
list<PProcess*> behaviors_;
|
||||
map<string,PTask*> tasks_;
|
||||
@@ -114,6 +137,34 @@ class Module {
|
||||
|
||||
/*
|
||||
* $Log: Module.h,v $
|
||||
* Revision 1.18 2000/05/02 16:27:38 steve
|
||||
* Move signal elaboration to a seperate pass.
|
||||
*
|
||||
* Revision 1.17 2000/04/01 19:31:57 steve
|
||||
* Named events as far as the pform.
|
||||
*
|
||||
* Revision 1.16 2000/03/12 17:09:40 steve
|
||||
* Support localparam.
|
||||
*
|
||||
* Revision 1.15 2000/03/08 04:36:53 steve
|
||||
* Redesign the implementation of scopes and parameters.
|
||||
* I now generate the scopes and notice the parameters
|
||||
* in a separate pass over the pform. Once the scopes
|
||||
* are generated, I can process overrides and evalutate
|
||||
* paremeters before elaboration begins.
|
||||
*
|
||||
* Revision 1.14 2000/02/23 02:56:53 steve
|
||||
* Macintosh compilers do not support ident.
|
||||
*
|
||||
* Revision 1.13 2000/01/09 20:37:57 steve
|
||||
* Careful with wires connected to multiple ports.
|
||||
*
|
||||
* Revision 1.12 2000/01/09 05:50:48 steve
|
||||
* Support named parameter override lists.
|
||||
*
|
||||
* Revision 1.11 1999/12/11 05:45:41 steve
|
||||
* Fix support for attaching attributes to primitive gates.
|
||||
*
|
||||
* Revision 1.10 1999/11/27 19:07:57 steve
|
||||
* Support the creation of scopes.
|
||||
*
|
||||
|
||||
+5
-2
@@ -16,8 +16,8 @@
|
||||
* 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 $"
|
||||
#if !defined(WINNT) && !defined(macintosh)
|
||||
#ident "$Id: PDelays.cc,v 1.2 2000/02/23 02:56:53 steve Exp $"
|
||||
#endif
|
||||
|
||||
# include "PDelays.h"
|
||||
@@ -96,6 +96,9 @@ void PDelays::eval_delays(Design*des, const string&path,
|
||||
|
||||
/*
|
||||
* $Log: PDelays.cc,v $
|
||||
* Revision 1.2 2000/02/23 02:56:53 steve
|
||||
* Macintosh compilers do not support ident.
|
||||
*
|
||||
* Revision 1.1 1999/09/04 19:11:46 steve
|
||||
* Add support for delayed non-blocking assignments.
|
||||
*
|
||||
|
||||
@@ -18,8 +18,8 @@
|
||||
* 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 $"
|
||||
#if !defined(WINNT) && !defined(macintosh)
|
||||
#ident "$Id: PDelays.h,v 1.2 2000/02/23 02:56:53 steve Exp $"
|
||||
#endif
|
||||
|
||||
# include "svector.h"
|
||||
@@ -60,6 +60,9 @@ ostream& operator << (ostream&o, const PDelays&);
|
||||
|
||||
/*
|
||||
* $Log: PDelays.h,v $
|
||||
* Revision 1.2 2000/02/23 02:56:53 steve
|
||||
* Macintosh compilers do not support ident.
|
||||
*
|
||||
* Revision 1.1 1999/09/04 19:11:46 steve
|
||||
* Add support for delayed non-blocking assignments.
|
||||
*
|
||||
|
||||
@@ -0,0 +1,45 @@
|
||||
/*
|
||||
* Copyright (c) 200Stephen 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) && !defined(macintosh)
|
||||
#ident "$Id: PEvent.cc,v 1.1 2000/04/01 19:31:57 steve Exp $"
|
||||
#endif
|
||||
|
||||
# include "PEvent.h"
|
||||
|
||||
PEvent::PEvent(const string&n)
|
||||
: name_(n)
|
||||
{
|
||||
}
|
||||
|
||||
PEvent::~PEvent()
|
||||
{
|
||||
}
|
||||
|
||||
string PEvent::name() const
|
||||
{
|
||||
return name_;
|
||||
}
|
||||
|
||||
/*
|
||||
* $Log: PEvent.cc,v $
|
||||
* Revision 1.1 2000/04/01 19:31:57 steve
|
||||
* Named events as far as the pform.
|
||||
*
|
||||
*/
|
||||
|
||||
@@ -0,0 +1,65 @@
|
||||
#ifndef __PEvent_H
|
||||
#define __PEvent_H
|
||||
/*
|
||||
* Copyright (c) 2000 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) && !defined(macintosh)
|
||||
#ident "$Id: PEvent.h,v 1.3 2000/04/09 17:44:30 steve Exp $"
|
||||
#endif
|
||||
|
||||
# include "LineInfo.h"
|
||||
# include <string>
|
||||
class ostream;
|
||||
class Design;
|
||||
class NetScope;
|
||||
|
||||
/*
|
||||
* The PEvent class represents event objects. These are things that
|
||||
* are declared in Verilog as ``event foo;''
|
||||
*/
|
||||
class PEvent : public LineInfo {
|
||||
|
||||
public:
|
||||
explicit PEvent(const string&name);
|
||||
~PEvent();
|
||||
|
||||
string name() const;
|
||||
|
||||
void elaborate_scope(Design*des, NetScope*scope) const;
|
||||
|
||||
private:
|
||||
string name_;
|
||||
|
||||
private: // not implemented
|
||||
PEvent(const PEvent&);
|
||||
PEvent& operator= (const PEvent&);
|
||||
};
|
||||
|
||||
/*
|
||||
* $Log: PEvent.h,v $
|
||||
* Revision 1.3 2000/04/09 17:44:30 steve
|
||||
* Catch event declarations during scope elaborate.
|
||||
*
|
||||
* Revision 1.2 2000/04/04 03:20:15 steve
|
||||
* Simulate named event trigger and waits.
|
||||
*
|
||||
* Revision 1.1 2000/04/01 19:31:57 steve
|
||||
* Named events as far as the pform.
|
||||
*
|
||||
*/
|
||||
#endif
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 1998 Stephen Williams <[email protected]>
|
||||
* Copyright (c) 1998-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
|
||||
@@ -16,14 +16,18 @@
|
||||
* 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: PExpr.cc,v 1.11 1999/10/31 04:11:27 steve Exp $"
|
||||
#if !defined(WINNT) && !defined(macintosh)
|
||||
#ident "$Id: PExpr.cc,v 1.18 2000/05/07 04:37:55 steve Exp $"
|
||||
#endif
|
||||
|
||||
# include "PExpr.h"
|
||||
# include "Module.h"
|
||||
# include <typeinfo>
|
||||
|
||||
PExpr::PExpr()
|
||||
{
|
||||
}
|
||||
|
||||
PExpr::~PExpr()
|
||||
{
|
||||
}
|
||||
@@ -41,16 +45,18 @@ bool PExpr::is_constant(Module*) const
|
||||
NetNet* PExpr::elaborate_net(Design*des, const string&path, unsigned,
|
||||
unsigned long,
|
||||
unsigned long,
|
||||
unsigned long) const
|
||||
unsigned long,
|
||||
Link::strength_t,
|
||||
Link::strength_t) const
|
||||
{
|
||||
cerr << "Don't know how to elaborate `" << *this
|
||||
<< "' as gates." << endl;
|
||||
cerr << get_line() << ": error: Unable 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: "
|
||||
cerr << get_line() << ": error: expression not valid in assign l-value: "
|
||||
<< *this << endl;
|
||||
return 0;
|
||||
}
|
||||
@@ -60,15 +66,25 @@ 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)
|
||||
PECallFunction::PECallFunction(const char*n, const svector<PExpr *> &parms)
|
||||
: name_(n), parms_(parms)
|
||||
{
|
||||
}
|
||||
|
||||
PECallFunction::PECallFunction(const char*n)
|
||||
: name_(n)
|
||||
{
|
||||
}
|
||||
|
||||
PECallFunction::~PECallFunction()
|
||||
{
|
||||
}
|
||||
|
||||
PEConcat::PEConcat(const svector<PExpr*>&p, PExpr*r)
|
||||
: parms_(p), repeat_(r)
|
||||
{
|
||||
}
|
||||
|
||||
bool PEConcat::is_constant(Module *mod) const
|
||||
{
|
||||
bool constant = repeat_? repeat_->is_constant(mod) : true;
|
||||
@@ -83,14 +99,70 @@ PEConcat::~PEConcat()
|
||||
delete repeat_;
|
||||
}
|
||||
|
||||
PEEvent::PEEvent(PEEvent::edge_t t, PExpr*e)
|
||||
: type_(t), expr_(e)
|
||||
{
|
||||
}
|
||||
|
||||
PEEvent::~PEEvent()
|
||||
{
|
||||
}
|
||||
|
||||
PEEvent::edge_t PEEvent::type() const
|
||||
{
|
||||
return type_;
|
||||
}
|
||||
|
||||
PExpr* PEEvent::expr() const
|
||||
{
|
||||
return expr_;
|
||||
}
|
||||
|
||||
PEIdent::PEIdent(const string&s)
|
||||
: text_(s), msb_(0), lsb_(0), idx_(0)
|
||||
{
|
||||
}
|
||||
|
||||
PEIdent::~PEIdent()
|
||||
{
|
||||
}
|
||||
|
||||
string PEIdent::name() const
|
||||
{
|
||||
return text_;
|
||||
}
|
||||
|
||||
/*
|
||||
* An identifier can be in a constant expresion if (and only if) it is
|
||||
* a parameter.
|
||||
*/
|
||||
bool PEIdent::is_constant(Module*mod) const
|
||||
{
|
||||
map<string,PExpr*>::const_iterator cur = mod->parameters.find(text_);
|
||||
return cur != mod->parameters.end();
|
||||
map<string,PExpr*>::const_iterator cur;
|
||||
|
||||
cur = mod->parameters.find(text_);
|
||||
if (cur != mod->parameters.end()) return true;
|
||||
|
||||
cur = mod->localparams.find(text_);
|
||||
if (cur != mod->localparams.end()) return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
PENumber::PENumber(verinum*vp)
|
||||
: value_(vp)
|
||||
{
|
||||
assert(vp);
|
||||
}
|
||||
|
||||
PENumber::~PENumber()
|
||||
{
|
||||
delete value_;
|
||||
}
|
||||
|
||||
const verinum& PENumber::value() const
|
||||
{
|
||||
return *value_;
|
||||
}
|
||||
|
||||
bool PENumber::is_the_same(const PExpr*that) const
|
||||
@@ -107,6 +179,20 @@ bool PENumber::is_constant(Module*) const
|
||||
return true;
|
||||
}
|
||||
|
||||
PEString::PEString(const string&s)
|
||||
: text_(s)
|
||||
{
|
||||
}
|
||||
|
||||
PEString::~PEString()
|
||||
{
|
||||
}
|
||||
|
||||
string PEString::value() const
|
||||
{
|
||||
return text_;
|
||||
}
|
||||
|
||||
bool PEString::is_constant(Module*) const
|
||||
{
|
||||
return true;
|
||||
@@ -128,6 +214,43 @@ bool PETernary::is_constant(Module*) const
|
||||
|
||||
/*
|
||||
* $Log: PExpr.cc,v $
|
||||
* Revision 1.18 2000/05/07 04:37:55 steve
|
||||
* Carry strength values from Verilog source to the
|
||||
* pform and netlist for gates.
|
||||
*
|
||||
* Change vvm constants to use the driver_t to drive
|
||||
* a constant value. This works better if there are
|
||||
* multiple drivers on a signal.
|
||||
*
|
||||
* Revision 1.17 2000/05/04 03:37:58 steve
|
||||
* Add infrastructure for system functions, move
|
||||
* $time to that structure and add $random.
|
||||
*
|
||||
* Revision 1.16 2000/04/12 04:23:57 steve
|
||||
* Named events really should be expressed with PEIdent
|
||||
* objects in the pform,
|
||||
*
|
||||
* Handle named events within the mix of net events
|
||||
* and edges. As a unified lot they get caught together.
|
||||
* wait statements are broken into more complex statements
|
||||
* that include a conditional.
|
||||
*
|
||||
* Do not generate NetPEvent or NetNEvent objects in
|
||||
* elaboration. NetEvent, NetEvWait and NetEvProbe
|
||||
* take over those functions in the netlist.
|
||||
*
|
||||
* Revision 1.15 2000/04/01 19:31:57 steve
|
||||
* Named events as far as the pform.
|
||||
*
|
||||
* Revision 1.14 2000/03/12 18:22:11 steve
|
||||
* Binary and unary operators in parameter expressions.
|
||||
*
|
||||
* Revision 1.13 2000/02/23 02:56:53 steve
|
||||
* Macintosh compilers do not support ident.
|
||||
*
|
||||
* Revision 1.12 1999/12/31 17:38:37 steve
|
||||
* Standardize some of the error messages.
|
||||
*
|
||||
* 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
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
#ifndef __PExpr_H
|
||||
#define __PExpr_H
|
||||
/*
|
||||
* Copyright (c) 1998-1999 Stephen Williams <[email protected]>
|
||||
* Copyright (c) 1998-2000 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
|
||||
@@ -18,8 +18,8 @@
|
||||
* 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: PExpr.h,v 1.25 1999/11/21 00:13:08 steve Exp $"
|
||||
#if !defined(WINNT) && !defined(macintosh)
|
||||
#ident "$Id: PExpr.h,v 1.37 2000/05/07 04:37:56 steve Exp $"
|
||||
#endif
|
||||
|
||||
# include <string>
|
||||
@@ -32,6 +32,7 @@ class Design;
|
||||
class Module;
|
||||
class NetNet;
|
||||
class NetExpr;
|
||||
class NetScope;
|
||||
|
||||
/*
|
||||
* The PExpr class hierarchy supports the description of
|
||||
@@ -43,13 +44,21 @@ class NetExpr;
|
||||
*/
|
||||
|
||||
class PExpr : public LineInfo {
|
||||
|
||||
public:
|
||||
PExpr();
|
||||
virtual ~PExpr();
|
||||
|
||||
virtual void dump(ostream&) const;
|
||||
|
||||
// Procedural elaboration of the expression.
|
||||
virtual NetExpr*elaborate_expr(Design*des, const string&path) const;
|
||||
virtual NetExpr*elaborate_expr(Design*des, NetScope*scope) const;
|
||||
|
||||
// Elaborate expressions that are the r-value of parameter
|
||||
// assignments. This elaboration follows the restrictions of
|
||||
// constant expressions and supports later overriding and
|
||||
// evaluation of parameters.
|
||||
virtual NetExpr*elaborate_pexpr(Design*des, NetScope*sc) const;
|
||||
|
||||
// This method elaborate the expression as gates, for use in a
|
||||
// continuous assign or other wholly structural context.
|
||||
@@ -57,7 +66,10 @@ class PExpr : public LineInfo {
|
||||
unsigned lwidth,
|
||||
unsigned long rise,
|
||||
unsigned long fall,
|
||||
unsigned long decay) const;
|
||||
unsigned long decay,
|
||||
Link::strength_t drive0 =Link::STRONG,
|
||||
Link::strength_t drive1 =Link::STRONG)
|
||||
const;
|
||||
|
||||
// This method elaborates the expression as gates, but
|
||||
// restricted for use as l-values of continuous assignments.
|
||||
@@ -79,6 +91,9 @@ class PExpr : public LineInfo {
|
||||
// of expresions.
|
||||
virtual bool is_constant(Module*) const;
|
||||
|
||||
private: // not implemented
|
||||
PExpr(const PExpr&);
|
||||
PExpr& operator= (const PExpr&);
|
||||
};
|
||||
|
||||
ostream& operator << (ostream&, const PExpr&);
|
||||
@@ -86,8 +101,7 @@ ostream& operator << (ostream&, const PExpr&);
|
||||
class PEConcat : public PExpr {
|
||||
|
||||
public:
|
||||
PEConcat(const svector<PExpr*>&p, PExpr*r =0)
|
||||
: parms_(p), repeat_(r) { }
|
||||
PEConcat(const svector<PExpr*>&p, PExpr*r =0);
|
||||
~PEConcat();
|
||||
|
||||
virtual void dump(ostream&) const;
|
||||
@@ -96,8 +110,10 @@ class PEConcat : public PExpr {
|
||||
unsigned width,
|
||||
unsigned long rise,
|
||||
unsigned long fall,
|
||||
unsigned long decay) const;
|
||||
virtual NetExpr*elaborate_expr(Design*des, const string&path) const;
|
||||
unsigned long decay,
|
||||
Link::strength_t drive0,
|
||||
Link::strength_t drive1) const;
|
||||
virtual NetExpr*elaborate_expr(Design*des, NetScope*) const;
|
||||
virtual bool is_constant(Module*) const;
|
||||
|
||||
private:
|
||||
@@ -105,28 +121,38 @@ class PEConcat : public PExpr {
|
||||
PExpr*repeat_;
|
||||
};
|
||||
|
||||
/*
|
||||
* Event expressions are expressions that can be combined with the
|
||||
* event "or" operator. These include "posedge foo" and similar, and
|
||||
* also include named events. "edge" events are associated with an
|
||||
* expression, whereas named events simply have a name, which
|
||||
* represents an event variable.
|
||||
*/
|
||||
class PEEvent : public PExpr {
|
||||
|
||||
public:
|
||||
PEEvent(NetNEvent::Type t, PExpr*e)
|
||||
: type_(t), expr_(e)
|
||||
{ }
|
||||
enum edge_t {ANYEDGE, POSEDGE, NEGEDGE, POSITIVE};
|
||||
|
||||
NetNEvent::Type type() const { return type_; }
|
||||
PExpr* expr() const { return expr_; }
|
||||
// Use this constructor to create events based on edges or levels.
|
||||
PEEvent(edge_t t, PExpr*e);
|
||||
|
||||
~PEEvent();
|
||||
|
||||
edge_t type() const;
|
||||
PExpr* expr() const;
|
||||
|
||||
virtual void dump(ostream&) const;
|
||||
|
||||
private:
|
||||
NetNEvent::Type type_;
|
||||
PExpr*expr_;
|
||||
edge_t type_;
|
||||
PExpr *expr_;
|
||||
};
|
||||
|
||||
class PEIdent : public PExpr {
|
||||
|
||||
public:
|
||||
explicit PEIdent(const string&s)
|
||||
: text_(s), msb_(0), lsb_(0), idx_(0) { }
|
||||
explicit PEIdent(const string&s);
|
||||
~PEIdent();
|
||||
|
||||
virtual void dump(ostream&) const;
|
||||
|
||||
@@ -138,15 +164,17 @@ class PEIdent : public PExpr {
|
||||
unsigned lwidth,
|
||||
unsigned long rise,
|
||||
unsigned long fall,
|
||||
unsigned long decay) const;
|
||||
unsigned long decay,
|
||||
Link::strength_t drive0,
|
||||
Link::strength_t drive1) const;
|
||||
|
||||
virtual NetExpr*elaborate_expr(Design*des, const string&path) const;
|
||||
virtual NetExpr*elaborate_expr(Design*des, NetScope*) const;
|
||||
virtual NetExpr*elaborate_pexpr(Design*des, NetScope*sc) const;
|
||||
|
||||
virtual bool is_constant(Module*) const;
|
||||
verinum* eval_const(const Design*des, const string&path) const;
|
||||
|
||||
// XXXX
|
||||
string name() const { return text_; }
|
||||
string name() const;
|
||||
|
||||
private:
|
||||
string text_;
|
||||
@@ -170,19 +198,21 @@ class PEIdent : public PExpr {
|
||||
class PENumber : public PExpr {
|
||||
|
||||
public:
|
||||
explicit PENumber(verinum*vp)
|
||||
: value_(vp) { assert(vp); }
|
||||
~PENumber() { delete value_; }
|
||||
explicit PENumber(verinum*vp);
|
||||
~PENumber();
|
||||
|
||||
const verinum& value() const { return *value_; }
|
||||
const verinum& value() const;
|
||||
|
||||
virtual void dump(ostream&) const;
|
||||
virtual NetNet* elaborate_net(Design*des, const string&path,
|
||||
unsigned lwidth,
|
||||
unsigned long rise,
|
||||
unsigned long fall,
|
||||
unsigned long decay) const;
|
||||
virtual NetExpr*elaborate_expr(Design*des, const string&path) const;
|
||||
unsigned long decay,
|
||||
Link::strength_t drive0,
|
||||
Link::strength_t drive1) const;
|
||||
virtual NetEConst*elaborate_expr(Design*des, NetScope*) const;
|
||||
virtual NetExpr*elaborate_pexpr(Design*des, NetScope*sc) const;
|
||||
virtual verinum* eval_const(const Design*des, const string&path) const;
|
||||
|
||||
virtual bool is_the_same(const PExpr*that) const;
|
||||
@@ -195,12 +225,12 @@ class PENumber : public PExpr {
|
||||
class PEString : public PExpr {
|
||||
|
||||
public:
|
||||
explicit PEString(const string&s)
|
||||
: text_(s) { }
|
||||
explicit PEString(const string&s);
|
||||
~PEString();
|
||||
|
||||
string value() const { return text_; }
|
||||
string value() const;
|
||||
virtual void dump(ostream&) const;
|
||||
virtual NetExpr*elaborate_expr(Design*des, const string&path) const;
|
||||
virtual NetEConst*elaborate_expr(Design*des, NetScope*) const;
|
||||
|
||||
virtual bool is_constant(Module*) const;
|
||||
|
||||
@@ -219,8 +249,11 @@ class PEUnary : public PExpr {
|
||||
unsigned width,
|
||||
unsigned long rise,
|
||||
unsigned long fall,
|
||||
unsigned long decay) const;
|
||||
virtual NetExpr*elaborate_expr(Design*des, const string&path) const;
|
||||
unsigned long decay,
|
||||
Link::strength_t drive0,
|
||||
Link::strength_t drive1) const;
|
||||
virtual NetEUnary*elaborate_expr(Design*des, NetScope*) const;
|
||||
virtual NetExpr*elaborate_pexpr(Design*des, NetScope*sc) const;
|
||||
|
||||
private:
|
||||
char op_;
|
||||
@@ -240,8 +273,11 @@ class PEBinary : public PExpr {
|
||||
unsigned width,
|
||||
unsigned long rise,
|
||||
unsigned long fall,
|
||||
unsigned long decay) const;
|
||||
virtual NetExpr*elaborate_expr(Design*des, const string&path) const;
|
||||
unsigned long decay,
|
||||
Link::strength_t drive0,
|
||||
Link::strength_t drive1) const;
|
||||
virtual NetEBinary*elaborate_expr(Design*des, NetScope*) const;
|
||||
virtual NetExpr*elaborate_pexpr(Design*des, NetScope*sc) const;
|
||||
virtual verinum* eval_const(const Design*des, const string&path) const;
|
||||
|
||||
private:
|
||||
@@ -249,16 +285,38 @@ class PEBinary : public PExpr {
|
||||
PExpr*left_;
|
||||
PExpr*right_;
|
||||
|
||||
NetEBinary*elaborate_expr_base_(Design*, NetExpr*lp, NetExpr*rp) const;
|
||||
|
||||
NetNet* elaborate_net_add_(Design*des, const string&path,
|
||||
unsigned lwidth,
|
||||
unsigned long rise,
|
||||
unsigned long fall,
|
||||
unsigned long decay) const;
|
||||
NetNet* elaborate_net_bit_(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_div_(Design*des, const string&path,
|
||||
unsigned lwidth,
|
||||
unsigned long rise,
|
||||
unsigned long fall,
|
||||
unsigned long decay) const;
|
||||
NetNet* elaborate_net_log_(Design*des, const string&path,
|
||||
unsigned lwidth,
|
||||
unsigned long rise,
|
||||
unsigned long fall,
|
||||
unsigned long decay) const;
|
||||
NetNet* elaborate_net_mul_(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,
|
||||
@@ -281,10 +339,12 @@ 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;
|
||||
virtual NetExpr*elaborate_expr(Design*des, const string&path) const;
|
||||
unsigned long rise,
|
||||
unsigned long fall,
|
||||
unsigned long decay,
|
||||
Link::strength_t drive0,
|
||||
Link::strength_t drive1) const;
|
||||
virtual NetETernary*elaborate_expr(Design*des, NetScope*) const;
|
||||
virtual verinum* eval_const(const Design*des, const string&path) const;
|
||||
|
||||
private:
|
||||
@@ -294,25 +354,83 @@ class PETernary : public PExpr {
|
||||
};
|
||||
|
||||
/*
|
||||
* This class represents a parsed call to a function.
|
||||
* This class represents a parsed call to a function, including calls
|
||||
* to system functions.
|
||||
*/
|
||||
class PECallFunction : public PExpr {
|
||||
public:
|
||||
explicit PECallFunction(const string &n, const svector<PExpr *> &parms);
|
||||
explicit PECallFunction(const char*n, const svector<PExpr *> &parms);
|
||||
explicit PECallFunction(const char*n);
|
||||
~PECallFunction();
|
||||
|
||||
virtual void dump(ostream &) const;
|
||||
virtual NetExpr*elaborate_expr(Design*des, const string&path) const;
|
||||
virtual NetExpr*elaborate_expr(Design*des, NetScope*scope) const;
|
||||
|
||||
private:
|
||||
string name_;
|
||||
svector<PExpr *> parms_;
|
||||
|
||||
NetESFunc* elaborate_sfunc_(Design*des, const string&path) const;
|
||||
NetExpr* elaborate_sfunc_(Design*des, NetScope*scope) const;
|
||||
};
|
||||
|
||||
/*
|
||||
* $Log: PExpr.h,v $
|
||||
* Revision 1.37 2000/05/07 04:37:56 steve
|
||||
* Carry strength values from Verilog source to the
|
||||
* pform and netlist for gates.
|
||||
*
|
||||
* Change vvm constants to use the driver_t to drive
|
||||
* a constant value. This works better if there are
|
||||
* multiple drivers on a signal.
|
||||
*
|
||||
* Revision 1.36 2000/05/04 03:37:58 steve
|
||||
* Add infrastructure for system functions, move
|
||||
* $time to that structure and add $random.
|
||||
*
|
||||
* Revision 1.35 2000/04/12 04:23:57 steve
|
||||
* Named events really should be expressed with PEIdent
|
||||
* objects in the pform,
|
||||
*
|
||||
* Handle named events within the mix of net events
|
||||
* and edges. As a unified lot they get caught together.
|
||||
* wait statements are broken into more complex statements
|
||||
* that include a conditional.
|
||||
*
|
||||
* Do not generate NetPEvent or NetNEvent objects in
|
||||
* elaboration. NetEvent, NetEvWait and NetEvProbe
|
||||
* take over those functions in the netlist.
|
||||
*
|
||||
* Revision 1.34 2000/04/01 21:40:22 steve
|
||||
* Add support for integer division.
|
||||
*
|
||||
* Revision 1.33 2000/04/01 19:31:57 steve
|
||||
* Named events as far as the pform.
|
||||
*
|
||||
* Revision 1.32 2000/03/12 18:22:11 steve
|
||||
* Binary and unary operators in parameter expressions.
|
||||
*
|
||||
* Revision 1.31 2000/03/12 04:35:22 steve
|
||||
* Allow parameter identifiers in parameter expressions.
|
||||
*
|
||||
* Revision 1.30 2000/03/08 04:36:53 steve
|
||||
* Redesign the implementation of scopes and parameters.
|
||||
* I now generate the scopes and notice the parameters
|
||||
* in a separate pass over the pform. Once the scopes
|
||||
* are generated, I can process overrides and evalutate
|
||||
* paremeters before elaboration begins.
|
||||
*
|
||||
* Revision 1.29 2000/02/23 02:56:53 steve
|
||||
* Macintosh compilers do not support ident.
|
||||
*
|
||||
* Revision 1.28 2000/02/16 03:58:27 steve
|
||||
* Fix up width matching in structural bitwise operators.
|
||||
*
|
||||
* Revision 1.27 2000/01/13 03:35:35 steve
|
||||
* Multiplication all the way to simulation.
|
||||
*
|
||||
* Revision 1.26 1999/12/16 03:46:39 steve
|
||||
* Structural logical or.
|
||||
*
|
||||
* Revision 1.25 1999/11/21 00:13:08 steve
|
||||
* Support memories in continuous assignments.
|
||||
*
|
||||
|
||||
+5
-2
@@ -16,8 +16,8 @@
|
||||
* 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 $"
|
||||
#if !defined(WINNT) && !defined(macintosh)
|
||||
#ident "$Id: PFunction.cc,v 1.3 2000/02/23 02:56:53 steve Exp $"
|
||||
#endif
|
||||
|
||||
#include "PTask.h"
|
||||
@@ -39,6 +39,9 @@ void PFunction::set_output(PWire*o)
|
||||
|
||||
/*
|
||||
* $Log: PFunction.cc,v $
|
||||
* Revision 1.3 2000/02/23 02:56:53 steve
|
||||
* Macintosh compilers do not support ident.
|
||||
*
|
||||
* Revision 1.2 1999/08/25 22:22:41 steve
|
||||
* elaborate some aspects of functions.
|
||||
*
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 1999 Stephen Williams ([email protected])
|
||||
* Copyright (c) 1999-2000 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
|
||||
@@ -16,8 +16,8 @@
|
||||
* 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: PGate.cc,v 1.5 1999/09/14 01:50:35 steve Exp $"
|
||||
#if !defined(WINNT) && !defined(macintosh)
|
||||
#ident "$Id: PGate.cc,v 1.9 2000/05/06 15:41:56 steve Exp $"
|
||||
#endif
|
||||
|
||||
# include "PGate.h"
|
||||
@@ -31,6 +31,8 @@ PGate::PGate(const string&name,
|
||||
: name_(name), pins_(pins)
|
||||
{
|
||||
if (del) delay_.set_delays(del);
|
||||
str0_ = STRONG;
|
||||
str1_ = STRONG;
|
||||
}
|
||||
|
||||
PGate::PGate(const string&name,
|
||||
@@ -39,17 +41,45 @@ PGate::PGate(const string&name,
|
||||
: name_(name), pins_(pins)
|
||||
{
|
||||
if (del) delay_.set_delay(del);
|
||||
str0_ = STRONG;
|
||||
str1_ = STRONG;
|
||||
}
|
||||
|
||||
PGate::PGate(const string&name, svector<PExpr*>*pins)
|
||||
: name_(name), pins_(pins)
|
||||
{
|
||||
str0_ = STRONG;
|
||||
str1_ = STRONG;
|
||||
}
|
||||
|
||||
PGate::~PGate()
|
||||
{
|
||||
}
|
||||
|
||||
PGate::strength_t PGate::strength0() const
|
||||
{
|
||||
return str0_;
|
||||
}
|
||||
|
||||
void PGate::strength0(PGate::strength_t s)
|
||||
{
|
||||
str0_ = s;
|
||||
}
|
||||
|
||||
PGate::strength_t PGate::strength1() const
|
||||
{
|
||||
return str1_;
|
||||
}
|
||||
|
||||
void PGate::strength1(PGate::strength_t s)
|
||||
{
|
||||
str1_ = s;
|
||||
}
|
||||
|
||||
void PGate::elaborate_scope(Design*, NetScope*) const
|
||||
{
|
||||
}
|
||||
|
||||
/*
|
||||
* This method is used during elaboration to calculate the
|
||||
* rise/fall/decay times for the gate. These values were set in pform
|
||||
@@ -110,8 +140,60 @@ void PGBuiltin::set_range(PExpr*msb, PExpr*lsb)
|
||||
lsb_ = lsb;
|
||||
}
|
||||
|
||||
PGModule::PGModule(const string&type, const string&name, svector<PExpr*>*pins)
|
||||
: PGate(name, pins), type_(type), overrides_(0), pins_(0),
|
||||
npins_(0), parms_(0), nparms_(0), msb_(0), lsb_(0)
|
||||
{
|
||||
}
|
||||
|
||||
PGModule::PGModule(const string&type, const string&name,
|
||||
named<PExpr*>*pins, unsigned npins)
|
||||
: PGate(name, 0), type_(type), overrides_(0), pins_(pins),
|
||||
npins_(npins), parms_(0), nparms_(0), msb_(0), lsb_(0)
|
||||
{
|
||||
}
|
||||
|
||||
void PGModule::set_parameters(svector<PExpr*>*o)
|
||||
{
|
||||
assert(overrides_ == 0);
|
||||
overrides_ = o;
|
||||
}
|
||||
|
||||
void PGModule::set_parameters(named<PExpr*>*pa, unsigned npa)
|
||||
{
|
||||
assert(parms_ == 0);
|
||||
assert(overrides_ == 0);
|
||||
parms_ = pa;
|
||||
nparms_ = npa;
|
||||
}
|
||||
|
||||
void PGModule::set_range(PExpr*msb, PExpr*lsb)
|
||||
{
|
||||
assert(msb_ == 0);
|
||||
assert(lsb_ == 0);
|
||||
|
||||
msb_ = msb;
|
||||
lsb_ = lsb;
|
||||
}
|
||||
|
||||
/*
|
||||
* $Log: PGate.cc,v $
|
||||
* Revision 1.9 2000/05/06 15:41:56 steve
|
||||
* Carry assignment strength to pform.
|
||||
*
|
||||
* Revision 1.8 2000/03/08 04:36:53 steve
|
||||
* Redesign the implementation of scopes and parameters.
|
||||
* I now generate the scopes and notice the parameters
|
||||
* in a separate pass over the pform. Once the scopes
|
||||
* are generated, I can process overrides and evalutate
|
||||
* paremeters before elaboration begins.
|
||||
*
|
||||
* Revision 1.7 2000/02/23 02:56:53 steve
|
||||
* Macintosh compilers do not support ident.
|
||||
*
|
||||
* Revision 1.6 2000/02/18 05:15:02 steve
|
||||
* Catch module instantiation arrays.
|
||||
*
|
||||
* Revision 1.5 1999/09/14 01:50:35 steve
|
||||
* Handle gates without delays.
|
||||
*
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
#ifndef __PGate_H
|
||||
#define __PGate_H
|
||||
/*
|
||||
* Copyright (c) 1998-1999 Stephen Williams ([email protected])
|
||||
* Copyright (c) 1998-2000 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
|
||||
@@ -18,16 +18,20 @@
|
||||
* 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: PGate.h,v 1.10 1999/09/04 19:11:46 steve Exp $"
|
||||
#if !defined(WINNT) && !defined(macintosh)
|
||||
#ident "$Id: PGate.h,v 1.18 2000/05/06 15:41:56 steve Exp $"
|
||||
#endif
|
||||
|
||||
# include "svector.h"
|
||||
# include "named.h"
|
||||
# include "LineInfo.h"
|
||||
# include "PDelays.h"
|
||||
# include <map>
|
||||
# include <string>
|
||||
class PExpr;
|
||||
class PUdp;
|
||||
class Design;
|
||||
class NetScope;
|
||||
class Module;
|
||||
|
||||
/*
|
||||
@@ -38,10 +42,17 @@ class Module;
|
||||
* This pins of a gate are connected to expressions. The elaboration
|
||||
* step will need to convert expressions to a network of gates in
|
||||
* order to elaborate expression inputs, but that can easily be done.
|
||||
*
|
||||
* The PGate base class also carries the strength0 and strength1
|
||||
* strengths for those gates where the driver[s] can be described by a
|
||||
* single strength pair. There is a strength of the 0 drive, and a
|
||||
* strength of the 1 drive.
|
||||
*/
|
||||
class PGate : public LineInfo {
|
||||
|
||||
public:
|
||||
enum strength_t { HIGHZ, WEAK, PULL, STRONG, SUPPLY };
|
||||
|
||||
explicit PGate(const string&name, svector<PExpr*>*pins,
|
||||
const svector<PExpr*>*del);
|
||||
|
||||
@@ -62,8 +73,18 @@ class PGate : public LineInfo {
|
||||
unsigned pin_count() const { return pins_? pins_->count() : 0; }
|
||||
const PExpr*pin(unsigned idx) const { return (*pins_)[idx]; }
|
||||
|
||||
strength_t strength0() const;
|
||||
strength_t strength1() const;
|
||||
|
||||
void strength0(strength_t);
|
||||
void strength1(strength_t);
|
||||
|
||||
map<string,string> attributes;
|
||||
|
||||
virtual void dump(ostream&out) const;
|
||||
virtual void elaborate(Design*des, const string&path) const;
|
||||
virtual void elaborate_scope(Design*des, NetScope*sc) const;
|
||||
virtual bool elaborate_sig(Design*des, NetScope*scope) const;
|
||||
|
||||
protected:
|
||||
const svector<PExpr*>* get_pins() const { return pins_; }
|
||||
@@ -76,6 +97,8 @@ class PGate : public LineInfo {
|
||||
PDelays delay_;
|
||||
svector<PExpr*>*pins_;
|
||||
|
||||
strength_t str0_, str1_;
|
||||
|
||||
private: // not implemented
|
||||
PGate(const PGate&);
|
||||
PGate& operator= (const PGate&);
|
||||
@@ -151,35 +174,79 @@ 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*>*overrides, svector<PExpr*>*pins)
|
||||
: PGate(name, pins), type_(type), overrides_(overrides), pins_(0), npins_(0) { }
|
||||
svector<PExpr*>*pins);
|
||||
|
||||
// If the binding of ports is by name, this constructor takes
|
||||
// the bindings and stores them for later elaboration.
|
||||
struct bind_t {
|
||||
string name;
|
||||
PExpr* parm;
|
||||
};
|
||||
explicit PGModule(const string&type, const string&name,
|
||||
svector<PExpr*>*overrides, bind_t*pins, unsigned npins)
|
||||
: PGate(name, 0), type_(type), overrides_(overrides), pins_(pins), npins_(npins) { }
|
||||
named<PExpr*>*pins, unsigned npins);
|
||||
|
||||
|
||||
// Parameter overrides can come as an ordered list, or a set
|
||||
// of named expressions.
|
||||
void set_parameters(svector<PExpr*>*o);
|
||||
void set_parameters(named<PExpr*>*pa, unsigned npa);
|
||||
|
||||
// Modules can be instantiated in ranges. The parser uses this
|
||||
// method to pass the range to the pform.
|
||||
void set_range(PExpr*msb, PExpr*lsb);
|
||||
|
||||
virtual void dump(ostream&out) const;
|
||||
virtual void elaborate(Design*, const string&path) const;
|
||||
virtual void elaborate_scope(Design*des, NetScope*sc) const;
|
||||
virtual bool elaborate_sig(Design*des, NetScope*scope) const;
|
||||
|
||||
private:
|
||||
string type_;
|
||||
svector<PExpr*>*overrides_;
|
||||
bind_t*pins_;
|
||||
named<PExpr*>*pins_;
|
||||
unsigned npins_;
|
||||
|
||||
// These members support parameter override by name
|
||||
named<PExpr*>*parms_;
|
||||
unsigned nparms_;
|
||||
|
||||
// Arrays of modules are give if these are set.
|
||||
PExpr*msb_;
|
||||
PExpr*lsb_;
|
||||
|
||||
void elaborate_mod_(Design*, Module*mod, const string&path) const;
|
||||
void elaborate_udp_(Design*, PUdp *udp, const string&path) const;
|
||||
void elaborate_sudp_(Design*, PUdp *udp, const string&path) const;
|
||||
void elaborate_cudp_(Design*, PUdp *udp, const string&path) const;
|
||||
void elaborate_scope_mod_(Design*des, Module*mod, NetScope*sc) const;
|
||||
bool elaborate_sig_mod_(Design*des, NetScope*scope, Module*mod) const;
|
||||
};
|
||||
|
||||
/*
|
||||
* $Log: PGate.h,v $
|
||||
* Revision 1.18 2000/05/06 15:41:56 steve
|
||||
* Carry assignment strength to pform.
|
||||
*
|
||||
* Revision 1.17 2000/05/02 16:27:38 steve
|
||||
* Move signal elaboration to a seperate pass.
|
||||
*
|
||||
* Revision 1.16 2000/03/29 04:37:10 steve
|
||||
* New and improved combinational primitives.
|
||||
*
|
||||
* Revision 1.15 2000/03/08 04:36:53 steve
|
||||
* Redesign the implementation of scopes and parameters.
|
||||
* I now generate the scopes and notice the parameters
|
||||
* in a separate pass over the pform. Once the scopes
|
||||
* are generated, I can process overrides and evalutate
|
||||
* paremeters before elaboration begins.
|
||||
*
|
||||
* Revision 1.14 2000/02/23 02:56:53 steve
|
||||
* Macintosh compilers do not support ident.
|
||||
*
|
||||
* Revision 1.13 2000/02/18 05:15:02 steve
|
||||
* Catch module instantiation arrays.
|
||||
*
|
||||
* Revision 1.12 2000/01/09 05:50:48 steve
|
||||
* Support named parameter override lists.
|
||||
*
|
||||
* Revision 1.11 1999/12/11 05:45:41 steve
|
||||
* Fix support for attaching attributes to primitive gates.
|
||||
*
|
||||
* Revision 1.10 1999/09/04 19:11:46 steve
|
||||
* Add support for delayed non-blocking assignments.
|
||||
*
|
||||
|
||||
@@ -16,8 +16,8 @@
|
||||
* 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: PTask.cc,v 1.2 1999/07/24 02:11:19 steve Exp $"
|
||||
#if !defined(WINNT) && !defined(macintosh)
|
||||
#ident "$Id: PTask.cc,v 1.3 2000/02/23 02:56:53 steve Exp $"
|
||||
#endif
|
||||
|
||||
# include "PTask.h"
|
||||
@@ -33,6 +33,9 @@ PTask::~PTask()
|
||||
|
||||
/*
|
||||
* $Log: PTask.cc,v $
|
||||
* Revision 1.3 2000/02/23 02:56:53 steve
|
||||
* Macintosh compilers do not support ident.
|
||||
*
|
||||
* Revision 1.2 1999/07/24 02:11:19 steve
|
||||
* Elaborate task input ports.
|
||||
*
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
#ifndef __PTask_H
|
||||
#define __PTask_H
|
||||
/*
|
||||
* Copyright (c) 1999 Stephen Williams ([email protected])
|
||||
* Copyright (c) 1999-2000 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
|
||||
@@ -18,14 +18,15 @@
|
||||
* 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: PTask.h,v 1.6 1999/09/30 21:28:34 steve Exp $"
|
||||
#if !defined(WINNT) && !defined(macintosh)
|
||||
#ident "$Id: PTask.h,v 1.8 2000/03/08 04:36:53 steve Exp $"
|
||||
#endif
|
||||
|
||||
# include "LineInfo.h"
|
||||
# include "svector.h"
|
||||
# include <string>
|
||||
class Design;
|
||||
class NetScope;
|
||||
class PWire;
|
||||
class Statement;
|
||||
|
||||
@@ -38,6 +39,12 @@ class PTask : public LineInfo {
|
||||
explicit PTask(svector<PWire*>*p, Statement*s);
|
||||
~PTask();
|
||||
|
||||
// Tasks introduce scope, to need to be handled during the
|
||||
// scope elaboration pass. The scope passed is my scope,
|
||||
// created by the containing scope. I fill it in with stuff if
|
||||
// I need to.
|
||||
void elaborate_scope(Design*des, NetScope*scope) const;
|
||||
|
||||
void elaborate_1(Design*des, const string&path) const;
|
||||
void elaborate_2(Design*des, const string&path) const;
|
||||
|
||||
@@ -65,9 +72,11 @@ class PFunction : public LineInfo {
|
||||
|
||||
void set_output(PWire*);
|
||||
|
||||
void elaborate_scope(Design*des, NetScope*scope) const;
|
||||
|
||||
/* 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 elaborate_1(Design *des, NetScope*) const;
|
||||
void elaborate_2(Design *des, NetScope*) const;
|
||||
|
||||
void dump(ostream&, unsigned) const;
|
||||
|
||||
@@ -79,6 +88,16 @@ class PFunction : public LineInfo {
|
||||
|
||||
/*
|
||||
* $Log: PTask.h,v $
|
||||
* Revision 1.8 2000/03/08 04:36:53 steve
|
||||
* Redesign the implementation of scopes and parameters.
|
||||
* I now generate the scopes and notice the parameters
|
||||
* in a separate pass over the pform. Once the scopes
|
||||
* are generated, I can process overrides and evalutate
|
||||
* paremeters before elaboration begins.
|
||||
*
|
||||
* Revision 1.7 2000/02/23 02:56:53 steve
|
||||
* Macintosh compilers do not support ident.
|
||||
*
|
||||
* Revision 1.6 1999/09/30 21:28:34 steve
|
||||
* Handle mutual reference of tasks by elaborating
|
||||
* task definitions in two passes, like functions.
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
#ifndef __PUdp_H
|
||||
#define __PUdp_H
|
||||
/*
|
||||
* Copyright (c) 1998 Stephen Williams ([email protected])
|
||||
* Copyright (c) 1998-2000 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
|
||||
@@ -18,8 +18,8 @@
|
||||
* 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: PUdp.h,v 1.3 1999/06/15 03:44:53 steve Exp $"
|
||||
#if !defined(WINNT) && !defined(macintosh)
|
||||
#ident "$Id: PUdp.h,v 1.4 2000/02/23 02:56:53 steve Exp $"
|
||||
#endif
|
||||
|
||||
# include <map>
|
||||
@@ -82,6 +82,9 @@ class PUdp {
|
||||
|
||||
/*
|
||||
* $Log: PUdp.h,v $
|
||||
* Revision 1.4 2000/02/23 02:56:53 steve
|
||||
* Macintosh compilers do not support ident.
|
||||
*
|
||||
* Revision 1.3 1999/06/15 03:44:53 steve
|
||||
* Get rid of the STL vector template.
|
||||
*
|
||||
|
||||
@@ -16,8 +16,8 @@
|
||||
* 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: PWire.cc,v 1.2 1999/09/10 05:02:09 steve Exp $"
|
||||
#if !defined(WINNT) && !defined(macintosh)
|
||||
#ident "$Id: PWire.cc,v 1.3 2000/02/23 02:56:54 steve Exp $"
|
||||
#endif
|
||||
|
||||
# include "PWire.h"
|
||||
@@ -100,6 +100,9 @@ void PWire::set_memory_idx(PExpr*ldx, PExpr*rdx)
|
||||
|
||||
/*
|
||||
* $Log: PWire.cc,v $
|
||||
* Revision 1.3 2000/02/23 02:56:54 steve
|
||||
* Macintosh compilers do not support ident.
|
||||
*
|
||||
* Revision 1.2 1999/09/10 05:02:09 steve
|
||||
* Handle integers at task parameters.
|
||||
*
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
#ifndef __PWire_H
|
||||
#define __PWire_H
|
||||
/*
|
||||
* Copyright (c) 1998 Stephen Williams ([email protected])
|
||||
* Copyright (c) 1998-2000 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
|
||||
@@ -18,8 +18,8 @@
|
||||
* 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: PWire.h,v 1.6 1999/11/27 19:07:57 steve Exp $"
|
||||
#if !defined(WINNT) && !defined(macintosh)
|
||||
#ident "$Id: PWire.h,v 1.8 2000/05/02 16:27:38 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*, NetScope*scope) const;
|
||||
void elaborate_sig(Design*, NetScope*scope) const;
|
||||
|
||||
private:
|
||||
string name_;
|
||||
@@ -82,6 +82,12 @@ class PWire : public LineInfo {
|
||||
|
||||
/*
|
||||
* $Log: PWire.h,v $
|
||||
* Revision 1.8 2000/05/02 16:27:38 steve
|
||||
* Move signal elaboration to a seperate pass.
|
||||
*
|
||||
* Revision 1.7 2000/02/23 02:56:54 steve
|
||||
* Macintosh compilers do not support ident.
|
||||
*
|
||||
* Revision 1.6 1999/11/27 19:07:57 steve
|
||||
* Support the creation of scopes.
|
||||
*
|
||||
|
||||
+50
-16
@@ -42,6 +42,12 @@ on a UNIX-like system:
|
||||
|
||||
- bison
|
||||
|
||||
- gperf 2.7
|
||||
The lexical analyzer doesn't recognize keywords directly,
|
||||
but instead matches symbols and looks them up in a hash
|
||||
table in order to get the proper lexical code. The gperf
|
||||
program generates the lookup table.
|
||||
|
||||
2.2 Compilation
|
||||
|
||||
Unpack the tar-ball and cd into the verilog-######### directory
|
||||
@@ -104,6 +110,33 @@ 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>.
|
||||
|
||||
Elaboration is actually performed it two steps: scopes and parameters
|
||||
first, followed by the structural and behavioral elaboration.
|
||||
|
||||
3.3.1 Scope Elaboration
|
||||
|
||||
This pass scans through the pform looking for scopes and
|
||||
parameters. A tree of NetScope objects is built up and placed in the
|
||||
Design object, with the root module represented by the root NetScope
|
||||
object.
|
||||
|
||||
The elab_scope.cc and elab_pexpr.cc files contain most of the code for
|
||||
handling this phase.
|
||||
|
||||
The tail of the elaborate_scope behavior (after the pform is
|
||||
traversed) includes a scan of the NetScope tree to locate defparam
|
||||
assignments that were collected during scope elaboration. This is when
|
||||
the defparam overrides are applied to the parameters.
|
||||
|
||||
3.3.2 Netlist Elaboration
|
||||
|
||||
After the scopes and parameters are generated and the NetScope tree
|
||||
fully formed, the elaboration runs through teh pform again, this time
|
||||
generating the structural and behavioral netlist. Parameters are
|
||||
elaborated and evaluated by now so all the constants of code
|
||||
generation are now known locally, so the netlist can be generated by
|
||||
simply passing through the pform.
|
||||
|
||||
3.4 Optimization
|
||||
|
||||
This is actually a collection of processing steps that perform
|
||||
@@ -166,6 +199,17 @@ Usage: ivl <options>... file
|
||||
target specific information to the target back-end, or
|
||||
options/parameters to optimization functions, if any are defined.
|
||||
|
||||
-m <module>
|
||||
Cause a named VPI module to be included in the module
|
||||
list. This parameter appends the named module to the end of
|
||||
the VPI_MODULE_LIST. This is an ordered list of modules to be
|
||||
loaded into the simulation at runtime.
|
||||
|
||||
This list can also be set with -fVPI_MODULE_LIST=<list> which
|
||||
sets the list completely. Then, -m after this will append
|
||||
module names to the list sp specified. The default list
|
||||
includes "system".
|
||||
|
||||
-N <file>
|
||||
Dump the elaborated netlist to the named file. The netlist is
|
||||
the folly elaborated netlist, after all the function modules
|
||||
@@ -273,13 +317,6 @@ current state of support for Verilog.
|
||||
|
||||
- Min/Typ/Max expressions: Example: a = (1 : 6 : 14);
|
||||
|
||||
- Memories work, but only in procedural code.
|
||||
|
||||
reg [1:0] b [2:0], bar;
|
||||
wire [1:0] foo;
|
||||
always foo = b[i]; // sorry
|
||||
always @(i) bar = b[i]; // OK
|
||||
|
||||
- `timescale directive
|
||||
|
||||
- force/release/assign/deassign procedural assignments not
|
||||
@@ -295,19 +332,14 @@ current state of support for Verilog.
|
||||
|
||||
- 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.
|
||||
- multiplicative operators (*, /, %) are not supported in
|
||||
general. They do work if the compiler can evaluate them at compile
|
||||
time.
|
||||
|
||||
assign foo = a * b; // sorry
|
||||
always @(a or b) foo = a * b; // sorry
|
||||
@@ -340,15 +372,17 @@ 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]>
|
||||
Stephan I. Boettcher <[email protected]>
|
||||
Ed Carter <[email protected]>
|
||||
Larry Doolittle <[email protected]>
|
||||
Guy Hutchison <[email protected]>
|
||||
Ales Hvezda <[email protected]>
|
||||
Yasuhisa Kato <[email protected]>
|
||||
James Lee <[email protected]>
|
||||
Peter Monta <[email protected]>
|
||||
Daniel H. Nelsen <[email protected]>
|
||||
Stefan Petersen <[email protected]>
|
||||
Jason Schonberg <schon@mips.com>
|
||||
Jason Schonberg <schonm@yahoo.com>
|
||||
Stuart Sutherland <[email protected]>
|
||||
Stephen Tell <[email protected]>
|
||||
Stefan Theide <[email protected]>
|
||||
|
||||
+117
-3
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 1998 Stephen Williams ([email protected])
|
||||
* Copyright (c) 1998-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
|
||||
@@ -16,8 +16,8 @@
|
||||
* 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: Statement.cc,v 1.16 1999/09/29 18:36:02 steve Exp $"
|
||||
#if !defined(WINNT) && !defined(macintosh)
|
||||
#ident "$Id: Statement.cc,v 1.21 2000/05/11 23:37:26 steve Exp $"
|
||||
#endif
|
||||
|
||||
# include "Statement.h"
|
||||
@@ -122,6 +122,22 @@ PCase::~PCase()
|
||||
delete[]items_;
|
||||
}
|
||||
|
||||
PCAssign::PCAssign(PExpr*l, PExpr*r)
|
||||
: lval_(l), expr_(r)
|
||||
{
|
||||
}
|
||||
|
||||
PCAssign::~PCAssign()
|
||||
{
|
||||
delete lval_;
|
||||
delete expr_;
|
||||
}
|
||||
|
||||
PCondit::PCondit(PExpr*ex, Statement*i, Statement*e)
|
||||
: expr_(ex), if_(i), else_(e)
|
||||
{
|
||||
}
|
||||
|
||||
PCondit::~PCondit()
|
||||
{
|
||||
delete expr_;
|
||||
@@ -129,6 +145,60 @@ PCondit::~PCondit()
|
||||
delete else_;
|
||||
}
|
||||
|
||||
PDeassign::PDeassign(PExpr*l)
|
||||
: lval_(l)
|
||||
{
|
||||
}
|
||||
|
||||
PDeassign::~PDeassign()
|
||||
{
|
||||
delete lval_;
|
||||
}
|
||||
|
||||
|
||||
PDelayStatement::PDelayStatement(PExpr*d, Statement*st)
|
||||
: delay_(d), statement_(st)
|
||||
{
|
||||
}
|
||||
|
||||
PDelayStatement::~PDelayStatement()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
PEventStatement::PEventStatement(const svector<PEEvent*>&ee)
|
||||
: expr_(ee), statement_(0)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
PEventStatement::PEventStatement(PEEvent*ee)
|
||||
: expr_(1), statement_(0)
|
||||
{
|
||||
expr_[0] = ee;
|
||||
}
|
||||
|
||||
PEventStatement::~PEventStatement()
|
||||
{
|
||||
// delete the events and the statement?
|
||||
}
|
||||
|
||||
void PEventStatement::set_statement(Statement*st)
|
||||
{
|
||||
statement_ = st;
|
||||
}
|
||||
|
||||
PForce::PForce(PExpr*l, PExpr*r)
|
||||
: lval_(l), expr_(r)
|
||||
{
|
||||
}
|
||||
|
||||
PForce::~PForce()
|
||||
{
|
||||
delete lval_;
|
||||
delete expr_;
|
||||
}
|
||||
|
||||
PForever::PForever(Statement*s)
|
||||
: statement_(s)
|
||||
{
|
||||
@@ -144,6 +214,16 @@ PProcess::~PProcess()
|
||||
delete statement_;
|
||||
}
|
||||
|
||||
PRelease::PRelease(PExpr*l)
|
||||
: lval_(l)
|
||||
{
|
||||
}
|
||||
|
||||
PRelease::~PRelease()
|
||||
{
|
||||
delete lval_;
|
||||
}
|
||||
|
||||
PRepeat::PRepeat(PExpr*e, Statement*s)
|
||||
: expr_(e), statement_(s)
|
||||
{
|
||||
@@ -155,6 +235,15 @@ PRepeat::~PRepeat()
|
||||
delete statement_;
|
||||
}
|
||||
|
||||
PTrigger::PTrigger(const string&e)
|
||||
: event_(e)
|
||||
{
|
||||
}
|
||||
|
||||
PTrigger::~PTrigger()
|
||||
{
|
||||
}
|
||||
|
||||
PWhile::~PWhile()
|
||||
{
|
||||
delete cond_;
|
||||
@@ -163,6 +252,31 @@ PWhile::~PWhile()
|
||||
|
||||
/*
|
||||
* $Log: Statement.cc,v $
|
||||
* Revision 1.21 2000/05/11 23:37:26 steve
|
||||
* Add support for procedural continuous assignment.
|
||||
*
|
||||
* Revision 1.20 2000/04/22 04:20:19 steve
|
||||
* Add support for force assignment.
|
||||
*
|
||||
* Revision 1.19 2000/04/12 04:23:57 steve
|
||||
* Named events really should be expressed with PEIdent
|
||||
* objects in the pform,
|
||||
*
|
||||
* Handle named events within the mix of net events
|
||||
* and edges. As a unified lot they get caught together.
|
||||
* wait statements are broken into more complex statements
|
||||
* that include a conditional.
|
||||
*
|
||||
* Do not generate NetPEvent or NetNEvent objects in
|
||||
* elaboration. NetEvent, NetEvWait and NetEvProbe
|
||||
* take over those functions in the netlist.
|
||||
*
|
||||
* Revision 1.18 2000/04/01 19:31:57 steve
|
||||
* Named events as far as the pform.
|
||||
*
|
||||
* Revision 1.17 2000/02/23 02:56:54 steve
|
||||
* Macintosh compilers do not support ident.
|
||||
*
|
||||
* Revision 1.16 1999/09/29 18:36:02 steve
|
||||
* Full case support
|
||||
*
|
||||
|
||||
+130
-12
@@ -1,7 +1,7 @@
|
||||
#ifndef __Statement_H
|
||||
#define __Statement_H
|
||||
/*
|
||||
* Copyright (c) 1998 Stephen Williams ([email protected])
|
||||
* Copyright (c) 1998-2000 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
|
||||
@@ -18,8 +18,8 @@
|
||||
* 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: Statement.h,v 1.20 1999/09/29 18:36:02 steve Exp $"
|
||||
#if !defined(WINNT) && !defined(macintosh)
|
||||
#ident "$Id: Statement.h,v 1.26 2000/05/11 23:37:26 steve Exp $"
|
||||
#endif
|
||||
|
||||
# include <string>
|
||||
@@ -30,6 +30,10 @@
|
||||
class PExpr;
|
||||
class Statement;
|
||||
class PEventStatement;
|
||||
class Design;
|
||||
class NetCAssign;
|
||||
class NetDeassign;
|
||||
class NetScope;
|
||||
|
||||
/*
|
||||
* The PProcess is the root of a behavioral process. Each process gets
|
||||
@@ -70,6 +74,7 @@ class Statement : public LineInfo {
|
||||
|
||||
virtual void dump(ostream&out, unsigned ind) const;
|
||||
virtual NetProc* elaborate(Design*des, const string&path) const;
|
||||
virtual void elaborate_scope(Design*des, NetScope*scope) const;
|
||||
};
|
||||
|
||||
/*
|
||||
@@ -155,6 +160,7 @@ class PBlock : public Statement {
|
||||
|
||||
virtual void dump(ostream&out, unsigned ind) const;
|
||||
virtual NetProc* elaborate(Design*des, const string&path) const;
|
||||
virtual void elaborate_scope(Design*des, NetScope*scope) const;
|
||||
|
||||
private:
|
||||
string name_;
|
||||
@@ -204,6 +210,7 @@ class PCase : public Statement {
|
||||
~PCase();
|
||||
|
||||
virtual NetProc* elaborate(Design*des, const string&path) const;
|
||||
virtual void elaborate_scope(Design*des, NetScope*scope) const;
|
||||
virtual void dump(ostream&out, unsigned ind) const;
|
||||
|
||||
private:
|
||||
@@ -217,14 +224,28 @@ class PCase : public Statement {
|
||||
PCase& operator= (const PCase&);
|
||||
};
|
||||
|
||||
class PCAssign : public Statement {
|
||||
|
||||
public:
|
||||
explicit PCAssign(PExpr*l, PExpr*r);
|
||||
~PCAssign();
|
||||
|
||||
virtual NetCAssign* elaborate(Design*des, const string&path) const;
|
||||
virtual void dump(ostream&out, unsigned ind) const;
|
||||
|
||||
private:
|
||||
PExpr*lval_;
|
||||
PExpr*expr_;
|
||||
};
|
||||
|
||||
class PCondit : public Statement {
|
||||
|
||||
public:
|
||||
PCondit(PExpr*ex, Statement*i, Statement*e)
|
||||
: expr_(ex), if_(i), else_(e) { }
|
||||
PCondit(PExpr*ex, Statement*i, Statement*e);
|
||||
~PCondit();
|
||||
|
||||
virtual NetProc* elaborate(Design*des, const string&path) const;
|
||||
virtual void elaborate_scope(Design*des, NetScope*scope) const;
|
||||
virtual void dump(ostream&out, unsigned ind) const;
|
||||
|
||||
private:
|
||||
@@ -237,34 +258,55 @@ class PCondit : public Statement {
|
||||
PCondit& operator= (const PCondit&);
|
||||
};
|
||||
|
||||
class PDeassign : public Statement {
|
||||
|
||||
public:
|
||||
explicit PDeassign(PExpr*l);
|
||||
~PDeassign();
|
||||
|
||||
virtual NetDeassign* elaborate(Design*des, const string&path) const;
|
||||
virtual void dump(ostream&out, unsigned ind) const;
|
||||
|
||||
private:
|
||||
PExpr*lval_;
|
||||
};
|
||||
|
||||
class PDelayStatement : public Statement {
|
||||
|
||||
public:
|
||||
PDelayStatement(PExpr*d, Statement*st)
|
||||
: delay_(d), statement_(st) { }
|
||||
PDelayStatement(PExpr*d, Statement*st);
|
||||
~PDelayStatement();
|
||||
|
||||
virtual void dump(ostream&out, unsigned ind) const;
|
||||
virtual NetProc* elaborate(Design*des, const string&path) const;
|
||||
virtual void elaborate_scope(Design*des, NetScope*scope) const;
|
||||
|
||||
private:
|
||||
PExpr*delay_;
|
||||
Statement*statement_;
|
||||
};
|
||||
|
||||
/*
|
||||
* The event statement represents the event delay in behavioral
|
||||
* code. It comes from such things as:
|
||||
*
|
||||
* @name <statement>;
|
||||
* @(expr) <statement>;
|
||||
*/
|
||||
class PEventStatement : public Statement {
|
||||
|
||||
public:
|
||||
|
||||
PEventStatement(const svector<PEEvent*>&ee)
|
||||
: expr_(ee), statement_(0) { }
|
||||
explicit PEventStatement(const svector<PEEvent*>&ee);
|
||||
explicit PEventStatement(PEEvent*ee);
|
||||
|
||||
PEventStatement(PEEvent*ee)
|
||||
: expr_(1), statement_(0) { expr_[0] = ee; }
|
||||
~PEventStatement();
|
||||
|
||||
void set_statement(Statement*st) { statement_ = st; }
|
||||
void set_statement(Statement*st);
|
||||
|
||||
virtual void dump(ostream&out, unsigned ind) const;
|
||||
virtual NetProc* elaborate(Design*des, const string&path) const;
|
||||
virtual void elaborate_scope(Design*des, NetScope*scope) const;
|
||||
|
||||
// This method is used to elaborate, but attach a previously
|
||||
// elaborated statement to the event.
|
||||
@@ -275,12 +317,27 @@ class PEventStatement : public Statement {
|
||||
Statement*statement_;
|
||||
};
|
||||
|
||||
class PForce : public Statement {
|
||||
|
||||
public:
|
||||
explicit PForce(PExpr*l, PExpr*r);
|
||||
~PForce();
|
||||
|
||||
virtual NetProc* elaborate(Design*des, const string&path) const;
|
||||
virtual void dump(ostream&out, unsigned ind) const;
|
||||
|
||||
private:
|
||||
PExpr*lval_;
|
||||
PExpr*expr_;
|
||||
};
|
||||
|
||||
class PForever : public Statement {
|
||||
public:
|
||||
explicit PForever(Statement*s);
|
||||
~PForever();
|
||||
|
||||
virtual NetProc* elaborate(Design*des, const string&path) const;
|
||||
virtual void elaborate_scope(Design*des, NetScope*scope) const;
|
||||
virtual void dump(ostream&out, unsigned ind) const;
|
||||
|
||||
private:
|
||||
@@ -297,6 +354,7 @@ class PForStatement : public Statement {
|
||||
{ }
|
||||
|
||||
virtual NetProc* elaborate(Design*des, const string&path) const;
|
||||
virtual void elaborate_scope(Design*des, NetScope*scope) const;
|
||||
virtual void dump(ostream&out, unsigned ind) const;
|
||||
|
||||
private:
|
||||
@@ -323,6 +381,7 @@ class PRepeat : public Statement {
|
||||
~PRepeat();
|
||||
|
||||
virtual NetProc* elaborate(Design*des, const string&path) const;
|
||||
virtual void elaborate_scope(Design*des, NetScope*scope) const;
|
||||
virtual void dump(ostream&out, unsigned ind) const;
|
||||
|
||||
private:
|
||||
@@ -330,6 +389,36 @@ class PRepeat : public Statement {
|
||||
Statement*statement_;
|
||||
};
|
||||
|
||||
class PRelease : public Statement {
|
||||
|
||||
public:
|
||||
explicit PRelease(PExpr*l);
|
||||
~PRelease();
|
||||
|
||||
virtual NetProc* elaborate(Design*des, const string&path) const;
|
||||
virtual void dump(ostream&out, unsigned ind) const;
|
||||
|
||||
private:
|
||||
PExpr*lval_;
|
||||
};
|
||||
|
||||
/*
|
||||
* The PTrigger statement sends a trigger to a named event. Take the
|
||||
* name here.
|
||||
*/
|
||||
class PTrigger : public Statement {
|
||||
|
||||
public:
|
||||
explicit PTrigger(const string&ev);
|
||||
~PTrigger();
|
||||
|
||||
virtual NetProc* elaborate(Design*des, const string&path) const;
|
||||
virtual void dump(ostream&out, unsigned ind) const;
|
||||
|
||||
private:
|
||||
string event_;
|
||||
};
|
||||
|
||||
class PWhile : public Statement {
|
||||
|
||||
public:
|
||||
@@ -338,6 +427,7 @@ class PWhile : public Statement {
|
||||
~PWhile();
|
||||
|
||||
virtual NetProc* elaborate(Design*des, const string&path) const;
|
||||
virtual void elaborate_scope(Design*des, NetScope*scope) const;
|
||||
virtual void dump(ostream&out, unsigned ind) const;
|
||||
|
||||
private:
|
||||
@@ -347,6 +437,34 @@ class PWhile : public Statement {
|
||||
|
||||
/*
|
||||
* $Log: Statement.h,v $
|
||||
* Revision 1.26 2000/05/11 23:37:26 steve
|
||||
* Add support for procedural continuous assignment.
|
||||
*
|
||||
* Revision 1.25 2000/04/22 04:20:19 steve
|
||||
* Add support for force assignment.
|
||||
*
|
||||
* Revision 1.24 2000/04/12 04:23:57 steve
|
||||
* Named events really should be expressed with PEIdent
|
||||
* objects in the pform,
|
||||
*
|
||||
* Handle named events within the mix of net events
|
||||
* and edges. As a unified lot they get caught together.
|
||||
* wait statements are broken into more complex statements
|
||||
* that include a conditional.
|
||||
*
|
||||
* Do not generate NetPEvent or NetNEvent objects in
|
||||
* elaboration. NetEvent, NetEvWait and NetEvProbe
|
||||
* take over those functions in the netlist.
|
||||
*
|
||||
* Revision 1.23 2000/04/01 19:31:57 steve
|
||||
* Named events as far as the pform.
|
||||
*
|
||||
* Revision 1.22 2000/03/11 03:25:51 steve
|
||||
* Locate scopes in statements.
|
||||
*
|
||||
* Revision 1.21 2000/02/23 02:56:54 steve
|
||||
* Macintosh compilers do not support ident.
|
||||
*
|
||||
* Revision 1.20 1999/09/29 18:36:02 steve
|
||||
* Full case support
|
||||
*
|
||||
|
||||
+18
-3
@@ -1,7 +1,7 @@
|
||||
#ifndef __compiler_H
|
||||
#define __compiler_H
|
||||
/*
|
||||
* Copyright (c) 1999 Stephen Williams ([email protected])
|
||||
* Copyright (c) 1999-2000 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
|
||||
@@ -18,8 +18,8 @@
|
||||
* 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: compiler.h,v 1.1 1999/06/06 20:42:48 steve Exp $"
|
||||
#if !defined(WINNT) && !defined(macintosh)
|
||||
#ident "$Id: compiler.h,v 1.3 2000/03/17 21:50:25 steve Exp $"
|
||||
#endif
|
||||
|
||||
/*
|
||||
@@ -33,8 +33,23 @@
|
||||
# define INTEGER_WIDTH 32
|
||||
#endif
|
||||
|
||||
/*
|
||||
* These are flags to enable various sorts of warnings. By default all
|
||||
* the warnings are of, the -W<list> parameter arranges for each to be
|
||||
* enabled.
|
||||
*/
|
||||
|
||||
/* Implicit definitions of wires. */
|
||||
extern bool warn_implicit;
|
||||
|
||||
/*
|
||||
* $Log: compiler.h,v $
|
||||
* Revision 1.3 2000/03/17 21:50:25 steve
|
||||
* Switch to control warnings.
|
||||
*
|
||||
* Revision 1.2 2000/02/23 02:56:54 steve
|
||||
* Macintosh compilers do not support ident.
|
||||
*
|
||||
* Revision 1.1 1999/06/06 20:42:48 steve
|
||||
* Make compiler width a compile time constant.
|
||||
*
|
||||
|
||||
@@ -7,5 +7,47 @@ AC_PROG_CXX
|
||||
AC_CHECK_TOOL(STRIP, strip, true)
|
||||
AC_CHECK_HEADERS(getopt.h)
|
||||
AC_PROG_INSTALL
|
||||
AC_CHECK_LIB(dl,main,[DLLIB=-ldl])
|
||||
AC_SUBST(DLLIB)
|
||||
|
||||
#######################
|
||||
## test for underscores
|
||||
#######################
|
||||
|
||||
AC_MSG_CHECKING("for leading and/or trailing underscores")
|
||||
cat << EOF > underscore.c
|
||||
void underscore(void){}
|
||||
EOF
|
||||
$CC -c underscore.c > /dev/null 2>&1
|
||||
|
||||
CC_LEADING_UNDERSCORE=no
|
||||
CC_TRAILING_UNDERSCORE=no
|
||||
|
||||
output=`nm underscore.o|grep _underscore 2>&1`
|
||||
if test ! -z "$output"; then
|
||||
CC_LEADING_UNDERSCORE=yes
|
||||
AC_DEFINE(NEED_LU)
|
||||
fi
|
||||
|
||||
output=`nm underscore.o|grep underscore_ 2>&1`
|
||||
if test ! -z "$output"; then
|
||||
CC_TRAILING_UNDERSCORE=yes
|
||||
AC_DEFINE(NEED_TU)
|
||||
fi
|
||||
|
||||
if test "$CC_LEADING_UNDERSCORE" = yes; then
|
||||
AC_DEFINE(WLU)
|
||||
fi
|
||||
if test "$CC_TRAILING_UNDERSCORE" = yes; then
|
||||
AC_DEFINE(WTU)
|
||||
fi
|
||||
|
||||
rm underscore.c underscore.o
|
||||
|
||||
AC_MSG_RESULT("$CC_LEADING_UNDERSCORE $CC_TRAILING_UNDERSCORE")
|
||||
|
||||
#######################
|
||||
## end of test for underscores
|
||||
#######################
|
||||
|
||||
AC_OUTPUT(Makefile vpi/Makefile ivlpp/Makefile vvm/Makefile)
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 1998 Stephen Williams ([email protected])
|
||||
* Copyright (c) 1998-2000 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
|
||||
@@ -16,13 +16,53 @@
|
||||
* 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: cprop.cc,v 1.2 1998/12/02 04:37:13 steve Exp $"
|
||||
#if !defined(WINNT) && !defined(macintosh)
|
||||
#ident "$Id: cprop.cc,v 1.9 2000/05/07 04:37:56 steve Exp $"
|
||||
#endif
|
||||
|
||||
# include "netlist.h"
|
||||
# include "functor.h"
|
||||
# include <assert.h>
|
||||
|
||||
/*
|
||||
* This local function returns true if all the the possible drivers of
|
||||
* this link are constant. It will also return true if there are no
|
||||
* drivers at all.
|
||||
*/
|
||||
static bool all_drivers_constant(const Link&lnk)
|
||||
{
|
||||
for (const Link*cur = lnk.next_link()
|
||||
; *cur != lnk ; cur = cur->next_link()) {
|
||||
|
||||
if (cur->get_dir() == Link::INPUT)
|
||||
continue;
|
||||
if (cur->get_dir() == Link::PASSIVE)
|
||||
continue;
|
||||
if (! dynamic_cast<const NetConst*>(cur->get_obj()))
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
* This function returns the value of the constant driving this link,
|
||||
* or Vz if there is no constant. The results of this function are
|
||||
* only meaningful if all_drivers_constant(lnk) == true.
|
||||
*/
|
||||
static verinum::V driven_value(const Link&lnk)
|
||||
{
|
||||
for (const Link*cur = lnk.next_link()
|
||||
; *cur != lnk ; cur = cur->next_link()) {
|
||||
|
||||
const NetConst*obj;
|
||||
if (obj = dynamic_cast<const NetConst*>(cur->get_obj()))
|
||||
return obj->value(cur->get_pin());
|
||||
}
|
||||
|
||||
return verinum::Vz;
|
||||
}
|
||||
|
||||
/*
|
||||
* The cprop function below invokes constant propogation where
|
||||
* possible. The elaboration generates NetConst objects. I can remove
|
||||
@@ -30,163 +70,281 @@
|
||||
* may even be able to replace nets with a new constant.
|
||||
*/
|
||||
|
||||
static bool is_a_const_node(const NetNode*obj)
|
||||
struct cprop_functor : public functor_t {
|
||||
|
||||
unsigned count;
|
||||
|
||||
virtual void lpm_add_sub(Design*des, NetAddSub*obj);
|
||||
virtual void lpm_ff(Design*des, NetFF*obj);
|
||||
virtual void lpm_logic(Design*des, NetLogic*obj);
|
||||
};
|
||||
|
||||
void cprop_functor::lpm_add_sub(Design*des, NetAddSub*obj)
|
||||
{
|
||||
return dynamic_cast<const NetConst*>(obj);
|
||||
// For now, only additions are handled.
|
||||
if (obj->attribute("LPM_Direction") != "ADD")
|
||||
return;
|
||||
|
||||
// If the low bit on the A side is 0, then eliminate it from
|
||||
// the adder, and pass the B side directly to the
|
||||
// result. Don't reduce the adder smaller then a 1-bit
|
||||
// adder. These will be eliminated later.
|
||||
while ((obj->width() > 1)
|
||||
&& all_drivers_constant(obj->pin_DataA(0))
|
||||
&& (driven_value(obj->pin_DataA(0)) == verinum::V0)) {
|
||||
|
||||
NetAddSub*tmp = 0;
|
||||
tmp = new NetAddSub(obj->name(), obj->width()-1);
|
||||
//connect(tmp->pin_Aclr(), obj->pin_Aclr());
|
||||
//connect(tmp->pin_Add_Sub(), obj->pin_Add_Sub());
|
||||
//connect(tmp->pin_Clock(), obj->pin_Clock());
|
||||
//connect(tmp->pin_Cin(), obj->pin_Cin());
|
||||
connect(tmp->pin_Cout(), obj->pin_Cout());
|
||||
//connect(tmp->pin_Overflow(), obj->pin_Overflow());
|
||||
for (unsigned idx = 0 ; idx < tmp->width() ; idx += 1) {
|
||||
connect(tmp->pin_DataA(idx), obj->pin_DataA(idx+1));
|
||||
connect(tmp->pin_DataB(idx), obj->pin_DataB(idx+1));
|
||||
connect(tmp->pin_Result(idx), obj->pin_Result(idx+1));
|
||||
}
|
||||
connect(obj->pin_Result(0), obj->pin_DataB(0));
|
||||
delete obj;
|
||||
des->add_node(tmp);
|
||||
obj = tmp;
|
||||
count += 1;
|
||||
}
|
||||
|
||||
// Now do the same thing on the B side.
|
||||
while ((obj->width() > 1)
|
||||
&& all_drivers_constant(obj->pin_DataB(0))
|
||||
&& (driven_value(obj->pin_DataB(0)) == verinum::V0)) {
|
||||
|
||||
NetAddSub*tmp = 0;
|
||||
tmp = new NetAddSub(obj->name(), obj->width()-1);
|
||||
//connect(tmp->pin_Aclr(), obj->pin_Aclr());
|
||||
//connect(tmp->pin_Add_Sub(), obj->pin_Add_Sub());
|
||||
//connect(tmp->pin_Clock(), obj->pin_Clock());
|
||||
//connect(tmp->pin_Cin(), obj->pin_Cin());
|
||||
connect(tmp->pin_Cout(), obj->pin_Cout());
|
||||
//connect(tmp->pin_Overflow(), obj->pin_Overflow());
|
||||
for (unsigned idx = 0 ; idx < tmp->width() ; idx += 1) {
|
||||
connect(tmp->pin_DataA(idx), obj->pin_DataA(idx+1));
|
||||
connect(tmp->pin_DataB(idx), obj->pin_DataB(idx+1));
|
||||
connect(tmp->pin_Result(idx), obj->pin_Result(idx+1));
|
||||
}
|
||||
connect(obj->pin_Result(0), obj->pin_DataA(0));
|
||||
delete obj;
|
||||
des->add_node(tmp);
|
||||
obj = tmp;
|
||||
count += 1;
|
||||
}
|
||||
|
||||
// If the adder is only 1 bit wide, then replace it with the
|
||||
// simple logic gate.
|
||||
if (obj->width() == 1) {
|
||||
NetLogic*tmp;
|
||||
if (obj->pin_Cout().is_linked()) {
|
||||
tmp = new NetLogic(des->local_symbol(obj->name()), 3,
|
||||
NetLogic::AND);
|
||||
connect(tmp->pin(0), obj->pin_Cout());
|
||||
connect(tmp->pin(1), obj->pin_DataA(0));
|
||||
connect(tmp->pin(2), obj->pin_DataB(0));
|
||||
des->add_node(tmp);
|
||||
}
|
||||
tmp = new NetLogic(obj->name(), 3, NetLogic::XOR);
|
||||
connect(tmp->pin(0), obj->pin_Result(0));
|
||||
connect(tmp->pin(1), obj->pin_DataA(0));
|
||||
connect(tmp->pin(2), obj->pin_DataB(0));
|
||||
delete obj;
|
||||
des->add_node(tmp);
|
||||
count += 1;
|
||||
return;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
static bool const_into_xnor(Design*des, NetConst*obj,
|
||||
NetLogic*log, unsigned pin)
|
||||
void cprop_functor::lpm_ff(Design*des, NetFF*obj)
|
||||
{
|
||||
assert(pin > 0);
|
||||
|
||||
/* if this is the last input pin of the XNOR device, then
|
||||
the device is simply buffering the constant value. */
|
||||
if (log->pin_count() == 2) {
|
||||
cerr << "cprop: delete gate " << log->name() <<
|
||||
" and propogate " << obj->value() << "." << endl;
|
||||
|
||||
assert(pin == 1);
|
||||
connect(log->pin(0), log->pin(1));
|
||||
|
||||
delete log;
|
||||
return true;
|
||||
}
|
||||
|
||||
/* If this is a constant 0, then replace the gate with one
|
||||
1-pin smaller. Skip this pin. */
|
||||
if (obj->value() == verinum::V0) {
|
||||
cerr << "cprop: disconnect pin " << pin << " from gate "
|
||||
<< log->name() << "." << endl;
|
||||
|
||||
NetLogic*tmp = new NetLogic(log->name(),
|
||||
log->pin_count()-1,
|
||||
NetLogic::XNOR);
|
||||
connect(log->pin(0), tmp->pin(0));
|
||||
unsigned idx, jdx;
|
||||
for (idx = 1, jdx = 1 ; idx < log->pin_count() ; idx += 1) {
|
||||
if (idx == pin) continue;
|
||||
connect(log->pin(idx), tmp->pin(jdx));
|
||||
jdx += 1;
|
||||
// Look for and count unlinked FF outputs. Note that if the
|
||||
// Data and Q pins are connected together, they can be removed
|
||||
// from the circuit.
|
||||
unsigned unlinked_count = 0;
|
||||
for (unsigned idx = 0 ; idx < obj->width() ; idx += 1) {
|
||||
if (connected(obj->pin_Data(idx), obj->pin_Q(idx))) {
|
||||
obj->pin_Data(idx).unlink();
|
||||
obj->pin_Q(idx).unlink();
|
||||
}
|
||||
|
||||
delete log;
|
||||
des->add_node(tmp);
|
||||
return true;
|
||||
if (! obj->pin_Q(idx).is_linked())
|
||||
unlinked_count += 1;
|
||||
}
|
||||
|
||||
/* If this is a constant 1, then replace the gate with an XOR
|
||||
that is 1-pin smaller. Removing the constant 1 causes the
|
||||
sense of the output to change. */
|
||||
if (obj->value() == verinum::V1) {
|
||||
cerr << "cprop: disconnect pin " << pin << " from gate "
|
||||
<< log->name() << "." << endl;
|
||||
|
||||
NetLogic*tmp = new NetLogic(log->name(),
|
||||
log->pin_count()-1,
|
||||
NetLogic::XOR);
|
||||
connect(log->pin(0), tmp->pin(0));
|
||||
unsigned idx, jdx;
|
||||
for (idx = 1, jdx = 1 ; idx < log->pin_count() ; idx += 1) {
|
||||
if (idx == pin) continue;
|
||||
connect(log->pin(idx), tmp->pin(jdx));
|
||||
jdx += 1;
|
||||
}
|
||||
|
||||
delete log;
|
||||
des->add_node(tmp);
|
||||
return true;
|
||||
// If the entire FF is unlinked, remove the whole thing.
|
||||
if (unlinked_count == obj->width()) {
|
||||
delete obj;
|
||||
count += 1;
|
||||
return;
|
||||
}
|
||||
|
||||
/* If this is a constant X or Z, then the gate is certain to
|
||||
generate an X. Replace the gate with a constant X. This may
|
||||
cause other signals all over to become dangling. */
|
||||
if ((obj->value() == verinum::Vx) || (obj->value() == verinum::Vz)) {
|
||||
cerr << "cprop: replace gate " << log->name() << " with "
|
||||
"a constant X." << endl;
|
||||
// If some of the FFs are unconnected, make a new FF array
|
||||
// that does not include the useless FF devices.
|
||||
if (unlinked_count > 0) {
|
||||
NetFF*tmp = new NetFF(obj->name(), obj->width()-unlinked_count);
|
||||
connect(tmp->pin_Clock(), obj->pin_Clock());
|
||||
connect(tmp->pin_Enable(), obj->pin_Enable());
|
||||
connect(tmp->pin_Aload(), obj->pin_Aload());
|
||||
connect(tmp->pin_Aset(), obj->pin_Aset());
|
||||
connect(tmp->pin_Aclr(), obj->pin_Aclr());
|
||||
connect(tmp->pin_Sload(), obj->pin_Sload());
|
||||
connect(tmp->pin_Sset(), obj->pin_Sset());
|
||||
connect(tmp->pin_Sclr(), obj->pin_Sclr());
|
||||
|
||||
NetConst*tmp = new NetConst(log->name(), verinum::Vx);
|
||||
connect(log->pin(0), tmp->pin(0));
|
||||
delete log;
|
||||
unsigned tidx = 0;
|
||||
for (unsigned idx = 0 ; idx < obj->width() ; idx += 1)
|
||||
if (obj->pin_Q(idx).is_linked()) {
|
||||
connect(tmp->pin_Data(tidx), obj->pin_Data(idx));
|
||||
connect(tmp->pin_Q(tidx), obj->pin_Q(idx));
|
||||
tidx += 1;
|
||||
}
|
||||
|
||||
assert(tidx == obj->width() - unlinked_count);
|
||||
delete obj;
|
||||
des->add_node(tmp);
|
||||
return true;
|
||||
count += 1;
|
||||
return;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static void look_for_core_logic(Design*des, NetConst*obj)
|
||||
void cprop_functor::lpm_logic(Design*des, NetLogic*obj)
|
||||
{
|
||||
NetObj*cur = obj;
|
||||
unsigned pin = 0;
|
||||
for (obj->pin(0).next_link(cur, pin)
|
||||
; cur != obj
|
||||
; cur->pin(pin).next_link(cur, pin)) {
|
||||
switch (obj->type()) {
|
||||
|
||||
NetLogic*log = dynamic_cast<NetLogic*>(cur);
|
||||
if (log == 0)
|
||||
continue;
|
||||
|
||||
bool flag = false;
|
||||
switch (log->type()) {
|
||||
case NetLogic::XNOR:
|
||||
flag = const_into_xnor(des, obj, log, pin);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
case NetLogic::AND:
|
||||
// If there is one zero input to an AND gate, we know
|
||||
// the resulting output is going to be zero and can
|
||||
// elininate the gate.
|
||||
for (unsigned idx = 1 ; idx < obj->pin_count() ; idx += 1) {
|
||||
if (! all_drivers_constant(obj->pin(idx)))
|
||||
continue;
|
||||
if (driven_value(obj->pin(idx)) == verinum::V0) {
|
||||
connect(obj->pin(0), obj->pin(idx));
|
||||
delete obj;
|
||||
count += 1;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
/* If the optimization test tells me that a link was
|
||||
deleted, restart the scan. */
|
||||
if (flag) obj->pin(0).next_link(cur, pin);
|
||||
// There are no zero constant drivers. If there are any
|
||||
// non-constant drivers, give up.
|
||||
for (unsigned idx = 1 ; idx < obj->pin_count() ; idx += 1) {
|
||||
if (! all_drivers_constant(obj->pin(idx)))
|
||||
return;
|
||||
}
|
||||
|
||||
// If there are any non-1 values (Vx or Vz) then the
|
||||
// result is Vx.
|
||||
for (unsigned idx = 1 ; idx < obj->pin_count() ; idx += 1) {
|
||||
if (driven_value(obj->pin(idx)) != verinum::V1) {
|
||||
connect(obj->pin(0), obj->pin(idx));
|
||||
delete obj;
|
||||
count += 1;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// What's left? The inputs are all 1's, return the first
|
||||
// input as the output value and remove the gate.
|
||||
connect(obj->pin(0), obj->pin(1));
|
||||
delete obj;
|
||||
count += 1;
|
||||
return;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* This function looks to see if the constant is connected to nothing
|
||||
* This functor looks to see if the constant is connected to nothing
|
||||
* but signals. If that is the case, delete the dangling constant and
|
||||
* the now useless signals.
|
||||
* the now useless signals. This functor is applied after the regular
|
||||
* functor to clean up dangling constants that might be left behind.
|
||||
*/
|
||||
static void dangling_const(Design*des, NetConst*obj)
|
||||
struct cprop_dc_functor : public functor_t {
|
||||
|
||||
virtual void lpm_const(Design*des, NetConst*obj);
|
||||
};
|
||||
|
||||
void cprop_dc_functor::lpm_const(Design*des, NetConst*obj)
|
||||
{
|
||||
// If there are any links that take input, abort this
|
||||
// operation.
|
||||
if (count_inputs(obj->pin(0)) > 0)
|
||||
return;
|
||||
|
||||
// If there are no other drivers, delete all the signals that
|
||||
// are also dangling.
|
||||
if (count_outputs(obj->pin(0)) == 1) {
|
||||
// If there are any links that take input, the constant is
|
||||
// used structurally somewhere.
|
||||
for (unsigned idx = 0 ; idx < obj->pin_count() ; idx += 1)
|
||||
if (count_inputs(obj->pin(idx)) > 0)
|
||||
return;
|
||||
|
||||
// Look for signals that have NetESignal nodes attached to
|
||||
// them. If I find any, this this constant is used by a
|
||||
// behavioral expression somewhere.
|
||||
for (unsigned idx = 0 ; idx < obj->pin_count() ; idx += 1) {
|
||||
NetObj*cur;
|
||||
unsigned pin;
|
||||
obj->pin(0).next_link(cur, pin);
|
||||
obj->pin(idx).next_link(cur, pin);
|
||||
while (cur != obj) {
|
||||
cerr << "cprop: delete dangling signal " << cur->name() <<
|
||||
"." << endl;
|
||||
delete cur;
|
||||
obj->pin(0).next_link(cur, pin);
|
||||
NetNet*tmp = dynamic_cast<NetNet*>(cur);
|
||||
if (tmp && tmp->get_eref() > 0)
|
||||
return;
|
||||
|
||||
cur->pin(pin).next_link(cur, pin);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Done. Delete me.
|
||||
delete obj;
|
||||
}
|
||||
|
||||
|
||||
void cprop(Design*des)
|
||||
{
|
||||
des->clear_node_marks();
|
||||
while (NetNode*obj = des->find_node(&is_a_const_node)) {
|
||||
NetConst*cur = dynamic_cast<NetConst*>(obj);
|
||||
look_for_core_logic(des, cur);
|
||||
cur->set_mark();
|
||||
dangling_const(des, cur);
|
||||
}
|
||||
// Continually propogate constants until a scan finds nothing
|
||||
// to do.
|
||||
cprop_functor prop;
|
||||
do {
|
||||
prop.count = 0;
|
||||
des->functor(&prop);
|
||||
} while (prop.count > 0);
|
||||
|
||||
cprop_dc_functor dc;
|
||||
des->functor(&dc);
|
||||
}
|
||||
|
||||
/*
|
||||
* $Log: cprop.cc,v $
|
||||
* Revision 1.9 2000/05/07 04:37:56 steve
|
||||
* Carry strength values from Verilog source to the
|
||||
* pform and netlist for gates.
|
||||
*
|
||||
* Change vvm constants to use the driver_t to drive
|
||||
* a constant value. This works better if there are
|
||||
* multiple drivers on a signal.
|
||||
*
|
||||
* Revision 1.8 2000/04/28 21:00:28 steve
|
||||
* Over agressive signal elimination in constant probadation.
|
||||
*
|
||||
* Revision 1.7 2000/02/23 02:56:54 steve
|
||||
* Macintosh compilers do not support ident.
|
||||
*
|
||||
* Revision 1.6 2000/01/02 17:56:42 steve
|
||||
* Do not delete constants that input to exressions.
|
||||
*
|
||||
* Revision 1.5 1999/12/30 04:19:12 steve
|
||||
* Propogate constant 0 in low bits of adders.
|
||||
*
|
||||
* Revision 1.4 1999/12/17 06:18:15 steve
|
||||
* Rewrite the cprop functor to use the functor_t interface.
|
||||
*
|
||||
* Revision 1.3 1999/12/17 03:38:46 steve
|
||||
* NetConst can now hold wide constants.
|
||||
*
|
||||
* Revision 1.2 1998/12/02 04:37:13 steve
|
||||
* Add the nobufz function to eliminate bufz objects,
|
||||
* Object links are marked with direction,
|
||||
|
||||
+288
-349
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 1998 Stephen Williams ([email protected])
|
||||
* Copyright (c) 1998-2000 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
|
||||
@@ -16,8 +16,8 @@
|
||||
* 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: design_dump.cc,v 1.61 1999/11/28 23:42:02 steve Exp $"
|
||||
#if !defined(WINNT) && !defined(macintosh)
|
||||
#ident "$Id: design_dump.cc,v 1.85 2000/05/11 23:37:27 steve Exp $"
|
||||
#endif
|
||||
|
||||
/*
|
||||
@@ -42,6 +42,30 @@ static ostream& operator<< (ostream&o, NetBlock::Type t)
|
||||
return o;
|
||||
}
|
||||
|
||||
ostream& operator << (ostream&o, Link::strength_t str)
|
||||
{
|
||||
switch (str) {
|
||||
case Link::HIGHZ:
|
||||
o << "highz";
|
||||
break;
|
||||
case Link::WEAK:
|
||||
o << "weak";
|
||||
break;
|
||||
case Link::PULL:
|
||||
o << "pull";
|
||||
break;
|
||||
case Link::STRONG:
|
||||
o << "strong";
|
||||
break;
|
||||
case Link::SUPPLY:
|
||||
o << "supply";
|
||||
break;
|
||||
default:
|
||||
assert(0);
|
||||
}
|
||||
return o;
|
||||
}
|
||||
|
||||
/* Dump a net. This can be a wire or register. */
|
||||
void NetNet::dump_net(ostream&o, unsigned ind) const
|
||||
{
|
||||
@@ -49,6 +73,7 @@ void NetNet::dump_net(ostream&o, unsigned ind) const
|
||||
pin_count() << "]";
|
||||
if (local_flag_)
|
||||
o << " (local)";
|
||||
o << " (eref=" << get_eref() << ")";
|
||||
if (scope_)
|
||||
o << " scope=" << scope_->name();
|
||||
o << " #(" << rise_time() << "," << fall_time() << "," <<
|
||||
@@ -56,6 +81,23 @@ void NetNet::dump_net(ostream&o, unsigned ind) const
|
||||
for (unsigned idx = pin_count() ; idx > 0 ; idx -= 1)
|
||||
o << ivalue_[idx-1];
|
||||
o << endl;
|
||||
|
||||
for (unsigned idx = 0 ; idx < pin_count() ; idx += 1) {
|
||||
if (! pin(idx).is_linked())
|
||||
continue;
|
||||
|
||||
o << setw(ind+4) << "" << "[" << idx << "]:";
|
||||
|
||||
unsigned cpin;
|
||||
const NetObj*cur;
|
||||
for (pin(idx).next_link(cur, cpin)
|
||||
; (cur != this) || (cpin != idx)
|
||||
; cur->pin(cpin).next_link(cur, cpin)) {
|
||||
|
||||
o << " " << cur->name() << "[" << cpin << "]";
|
||||
}
|
||||
o << endl;
|
||||
}
|
||||
dump_obj_attr(o, ind+4);
|
||||
}
|
||||
|
||||
@@ -100,7 +142,9 @@ void NetObj::dump_node_pins(ostream&o, unsigned ind) const
|
||||
o << " O";
|
||||
break;
|
||||
}
|
||||
o << ":";
|
||||
|
||||
o << " (" << pin(idx).drive0() << "0 "
|
||||
<< pin(idx).drive1() << "1):";
|
||||
|
||||
unsigned cpin;
|
||||
const NetObj*cur;
|
||||
@@ -132,6 +176,13 @@ void NetAddSub::dump_node(ostream&o, unsigned ind) const
|
||||
dump_obj_attr(o, ind+4);
|
||||
}
|
||||
|
||||
void NetCAssign::dump_node(ostream&o, unsigned ind) const
|
||||
{
|
||||
o << setw(ind) << "" << "Procedural continuous assign (NetCAssign): "
|
||||
<< name() << endl;
|
||||
dump_node_pins(o, ind+4);
|
||||
}
|
||||
|
||||
void NetCLShift::dump_node(ostream&o, unsigned ind) const
|
||||
{
|
||||
o << setw(ind) << "" << "Combinatorial shift (NetCLShift): " <<
|
||||
@@ -142,8 +193,27 @@ void NetCLShift::dump_node(ostream&o, unsigned ind) const
|
||||
|
||||
void NetCompare::dump_node(ostream&o, unsigned ind) const
|
||||
{
|
||||
o << setw(ind) << "" << "LPM_COMPARE (NetCompare): " <<
|
||||
name() << endl;
|
||||
o << setw(ind) << "" << "LPM_COMPARE (NetCompare): " << name() << endl;
|
||||
dump_node_pins(o, ind+4);
|
||||
dump_obj_attr(o, ind+4);
|
||||
}
|
||||
|
||||
void NetDivide::dump_node(ostream&o, unsigned ind) const
|
||||
{
|
||||
o << setw(ind) << "" << "NET_DIVIDE (NetDivide): " << name() << endl;
|
||||
dump_node_pins(o, ind+4);
|
||||
dump_obj_attr(o, ind+4);
|
||||
}
|
||||
|
||||
void NetForce::dump_node(ostream&o, unsigned ind) const
|
||||
{
|
||||
o << setw(ind) << "" << "force " << lval_->name() << endl;
|
||||
dump_node_pins(o, ind+4);
|
||||
}
|
||||
|
||||
void NetMult::dump_node(ostream&o, unsigned ind) const
|
||||
{
|
||||
o << setw(ind) << "" << "LPM_MULT (NetMult): " << name() << endl;
|
||||
dump_node_pins(o, ind+4);
|
||||
dump_obj_attr(o, ind+4);
|
||||
}
|
||||
@@ -189,7 +259,10 @@ void NetCaseCmp::dump_node(ostream&o, unsigned ind) const
|
||||
|
||||
void NetConst::dump_node(ostream&o, unsigned ind) const
|
||||
{
|
||||
o << setw(ind) << "" << "constant " << value_ << ": " << name() << endl;
|
||||
o << setw(ind) << "" << "constant ";
|
||||
for (unsigned idx = pin_count() ; idx > 0 ; idx -= 1)
|
||||
o << value_[idx-1];
|
||||
o << ": " << name() << endl;
|
||||
dump_node_pins(o, ind+4);
|
||||
}
|
||||
|
||||
@@ -327,18 +400,7 @@ void NetUDP::dump_sequ_(ostream&o, unsigned ind) const
|
||||
|
||||
void NetUDP::dump_comb_(ostream&o, unsigned ind) const
|
||||
{
|
||||
o << setw(ind) << "" << "Combinational UDP: ";
|
||||
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);
|
||||
assert(0);
|
||||
}
|
||||
|
||||
void NetUDP::dump_node(ostream&o, unsigned ind) const
|
||||
@@ -349,27 +411,20 @@ void NetUDP::dump_node(ostream&o, unsigned ind) const
|
||||
dump_comb_(o, ind);
|
||||
}
|
||||
|
||||
void NetNEvent::dump_node(ostream&o, unsigned ind) const
|
||||
void NetUDP_COMB::dump_node(ostream&o, unsigned ind) const
|
||||
{
|
||||
o << setw(ind) << "" << "event: ";
|
||||
switch (edge_) {
|
||||
case ANYEDGE:
|
||||
o << "anyedge ";
|
||||
break;
|
||||
case POSEDGE:
|
||||
o << "posedge ";
|
||||
break;
|
||||
case NEGEDGE:
|
||||
o << "negedge ";
|
||||
break;
|
||||
case POSITIVE:
|
||||
o << "positive ";
|
||||
break;
|
||||
o << setw(ind) << "" << "Combinational primitive: ";
|
||||
o << " #(" << rise_time() << "," << fall_time() << "," << decay_time() <<
|
||||
") " << name() << endl;
|
||||
|
||||
for (map<string,char>::const_iterator ent = cm_.begin()
|
||||
; ent != cm_.end() ; ent++) {
|
||||
o << setw(ind+6) << "" << (*ent).first << " --> " <<
|
||||
(*ent).second << endl;
|
||||
}
|
||||
|
||||
o << name() << " --> " << fore_ptr()->name() << endl;
|
||||
|
||||
dump_node_pins(o, ind+4);
|
||||
dump_obj_attr(o, ind+4);
|
||||
}
|
||||
|
||||
void NetProcTop::dump(ostream&o, unsigned ind) const
|
||||
@@ -428,9 +483,7 @@ void NetAssignMem::dump(ostream&o, unsigned ind) const
|
||||
o << setw(ind) << "";
|
||||
o << "/* " << get_line() << " */" << endl;
|
||||
o << setw(ind) << "";
|
||||
o << memory()->name() << "[";
|
||||
index()->dump(o);
|
||||
o << "] = ";
|
||||
o << memory()->name() << "[" << index()->name() << "] = ";
|
||||
rval()->dump(o);
|
||||
o << ";" << endl;
|
||||
}
|
||||
@@ -440,9 +493,7 @@ 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 << "] <= ";
|
||||
o << memory()->name() << "[" << index()->name() << "] <= ";
|
||||
rval()->dump(o);
|
||||
o << ";" << endl;
|
||||
}
|
||||
@@ -495,6 +546,12 @@ void NetCase::dump(ostream&o, unsigned ind) const
|
||||
o << setw(ind) << "" << "endcase" << endl;
|
||||
}
|
||||
|
||||
void NetCAssign::dump(ostream&o, unsigned ind) const
|
||||
{
|
||||
o << setw(ind) << "" << "cassign " << lval_->name() << " = "
|
||||
<< name() << ";" << endl;
|
||||
}
|
||||
|
||||
void NetCondit::dump(ostream&o, unsigned ind) const
|
||||
{
|
||||
o << setw(ind) << "" << "if (";
|
||||
@@ -510,6 +567,60 @@ void NetCondit::dump(ostream&o, unsigned ind) const
|
||||
}
|
||||
}
|
||||
|
||||
void NetDeassign::dump(ostream&o, unsigned ind) const
|
||||
{
|
||||
o << setw(ind) << "" << "deassign " << lval_->name() << "; "
|
||||
<< "/* " << get_line() << " */" << endl;
|
||||
}
|
||||
|
||||
void NetEvProbe::dump_node(ostream&o, unsigned ind) const
|
||||
{
|
||||
o << setw(ind) << "";
|
||||
|
||||
switch (edge_) {
|
||||
case ANYEDGE:
|
||||
o << "anyedge ";
|
||||
break;
|
||||
case POSEDGE:
|
||||
o << "posedge ";
|
||||
break;
|
||||
case NEGEDGE:
|
||||
o << "negedge ";
|
||||
break;
|
||||
}
|
||||
o << setw(ind) << "" << "-> " << event_->full_name() << "; " << endl;
|
||||
dump_node_pins(o, ind+4);
|
||||
dump_obj_attr(o, ind+4);
|
||||
}
|
||||
|
||||
void NetEvTrig::dump(ostream&o, unsigned ind) const
|
||||
{
|
||||
o << setw(ind) << "" << "-> " << event_->name() << "; "
|
||||
<< "// " << get_line() << endl;
|
||||
}
|
||||
|
||||
void NetEvWait::dump(ostream&o, unsigned ind) const
|
||||
{
|
||||
assert(nevents() > 0);
|
||||
o << setw(ind) <<"" << "@(" << event(0)->name();
|
||||
|
||||
for (unsigned idx = 1 ; idx < nevents() ; idx += 1)
|
||||
o << " or " << event(idx)->name();
|
||||
|
||||
o << ") // " << get_line() << endl;
|
||||
|
||||
if (statement_)
|
||||
statement_->dump(o, ind+2);
|
||||
else
|
||||
o << setw(ind+2) << "" << "/* noop */ ;" << endl;
|
||||
}
|
||||
|
||||
void NetForce::dump(ostream&o, unsigned ind) const
|
||||
{
|
||||
o << setw(ind) << "" << "force " << lval_->name() << " = "
|
||||
<< name() << ";" << endl;
|
||||
}
|
||||
|
||||
void NetForever::dump(ostream&o, unsigned ind) const
|
||||
{
|
||||
o << setw(ind) << "" << "forever" << endl;
|
||||
@@ -518,7 +629,7 @@ void NetForever::dump(ostream&o, unsigned ind) const
|
||||
|
||||
void NetFuncDef::dump(ostream&o, unsigned ind) const
|
||||
{
|
||||
o << setw(ind) << "" << "function " << name_ << endl;
|
||||
o << setw(ind) << "" << "function " << scope_->name() << endl;
|
||||
if (statement_)
|
||||
statement_->dump(o, ind+2);
|
||||
else
|
||||
@@ -536,43 +647,10 @@ void NetPDelay::dump(ostream&o, unsigned ind) const
|
||||
}
|
||||
}
|
||||
|
||||
void NetPEvent::dump(ostream&o, unsigned ind) const
|
||||
void NetRelease::dump(ostream&o, unsigned ind) const
|
||||
{
|
||||
o << setw(ind) << "" << "@(";
|
||||
svector<const NetNEvent*>*list = back_list();
|
||||
(*list)[0]->dump_proc(o);
|
||||
for (unsigned idx = 1 ; idx < list->count() ; idx += 1) {
|
||||
o << " or ";
|
||||
(*list)[idx]->dump_proc(o);
|
||||
}
|
||||
delete list;
|
||||
o << ") /* " << name_ << " */";
|
||||
|
||||
if (statement_) {
|
||||
o << endl;
|
||||
statement_->dump(o, ind+2);
|
||||
} else {
|
||||
o << " /* noop */;" << endl;
|
||||
}
|
||||
}
|
||||
|
||||
void NetNEvent::dump_proc(ostream&o) const
|
||||
{
|
||||
switch (edge_) {
|
||||
case ANYEDGE:
|
||||
o << "anyedge ";
|
||||
break;
|
||||
case POSEDGE:
|
||||
o << "posedge ";
|
||||
break;
|
||||
case NEGEDGE:
|
||||
o << "negedge ";
|
||||
break;
|
||||
case POSITIVE:
|
||||
o << "positive ";
|
||||
break;
|
||||
}
|
||||
o << name();
|
||||
o << setw(ind) << "" << "release " << lval_->name() << "; "
|
||||
<< "/* " << get_line() << " */" << endl;
|
||||
}
|
||||
|
||||
void NetRepeat::dump(ostream&o, unsigned ind) const
|
||||
@@ -583,7 +661,7 @@ void NetRepeat::dump(ostream&o, unsigned ind) const
|
||||
|
||||
void NetScope::dump(ostream&o) const
|
||||
{
|
||||
o << name_;
|
||||
o << name();
|
||||
switch (type_) {
|
||||
case BEGIN_END:
|
||||
o << " sequential block";
|
||||
@@ -591,11 +669,71 @@ void NetScope::dump(ostream&o) const
|
||||
case FORK_JOIN:
|
||||
o << " parallel block";
|
||||
break;
|
||||
case FUNC:
|
||||
o << " function";
|
||||
break;
|
||||
case MODULE:
|
||||
o << " module";
|
||||
break;
|
||||
case TASK:
|
||||
o << " task";
|
||||
break;
|
||||
}
|
||||
o << endl;
|
||||
|
||||
/* Dump the parameters for this scope. */
|
||||
{
|
||||
map<string,NetExpr*>::const_iterator pp;
|
||||
for (pp = parameters_.begin()
|
||||
; pp != parameters_.end() ; pp ++) {
|
||||
o << " parameter " << (*pp).first << " = " <<
|
||||
*(*pp).second << ";" << endl;
|
||||
}
|
||||
|
||||
for (pp = localparams_.begin()
|
||||
; pp != localparams_.end() ; pp ++) {
|
||||
o << " localparam " << (*pp).first << " = " <<
|
||||
*(*pp).second << ";" << endl;
|
||||
}
|
||||
}
|
||||
|
||||
/* Dump the saved defparam assignments here. */
|
||||
{
|
||||
map<string,NetExpr*>::const_iterator pp;
|
||||
for (pp = defparams.begin()
|
||||
; pp != defparams.end() ; pp ++ ) {
|
||||
o << " defparam " << (*pp).first << " = " <<
|
||||
*(*pp).second << ";" << endl;
|
||||
}
|
||||
}
|
||||
|
||||
/* Dump the events in this scope. */
|
||||
for (NetEvent*cur = events_ ; cur ; cur = cur->snext_) {
|
||||
o << " event " << cur->name() << "; "
|
||||
<< "// " << cur->get_line() << endl;
|
||||
}
|
||||
|
||||
// Dump the signals,
|
||||
if (signals_) {
|
||||
NetNet*cur = signals_->sig_next_;
|
||||
do {
|
||||
cur->dump_net(o, 4);
|
||||
cur = cur->sig_next_;
|
||||
} while (cur != signals_->sig_next_);
|
||||
}
|
||||
|
||||
// Dump the memories,
|
||||
if (memories_) {
|
||||
NetMemory*cur = memories_->snext_;
|
||||
do {
|
||||
cur->dump(o, 4);
|
||||
cur = cur->snext_;
|
||||
} while (cur != memories_->snext_);
|
||||
}
|
||||
|
||||
/* Dump any sub-scopes. */
|
||||
for (NetScope*cur = sub_ ; cur ; cur = cur->sib_)
|
||||
cur->dump(o);
|
||||
}
|
||||
|
||||
void NetSTask::dump(ostream&o, unsigned ind) const
|
||||
@@ -729,6 +867,16 @@ void NetEScope::dump(ostream&o) const
|
||||
o << "<scope=" << scope_->name() << ">";
|
||||
}
|
||||
|
||||
void NetESFunc::dump(ostream&o) const
|
||||
{
|
||||
o << name_ << "(";
|
||||
if (nparms() > 0)
|
||||
o << *parm(0);
|
||||
for (unsigned idx = 1 ; idx < nparms() ; idx += 1)
|
||||
o << ", " << *parm(idx);
|
||||
o << ")";
|
||||
}
|
||||
|
||||
void NetESignal::dump(ostream&o) const
|
||||
{
|
||||
o << name();
|
||||
@@ -745,13 +893,13 @@ void NetESubSignal::dump(ostream&o) const
|
||||
void NetEMemory::dump(ostream&o) const
|
||||
{
|
||||
o << mem_->name() << "[";
|
||||
idx_->dump(o);
|
||||
if (idx_) idx_->dump(o);
|
||||
o << "]";
|
||||
}
|
||||
|
||||
void NetEParam::dump(ostream&o) const
|
||||
{
|
||||
o << "<" << path_ << "." << name_ << ">";
|
||||
o << "<" << scope_->name() << "." << name_ << ">";
|
||||
}
|
||||
|
||||
void NetETernary::dump(ostream&o) const
|
||||
@@ -790,42 +938,7 @@ void NetEUnary::dump(ostream&o) const
|
||||
void Design::dump(ostream&o) const
|
||||
{
|
||||
o << "SCOPES:" << endl;
|
||||
{
|
||||
map<string,NetScope*>::const_iterator pp;
|
||||
for (pp = scopes_.begin()
|
||||
; pp != scopes_.end() ; pp ++)
|
||||
(*pp).second -> dump(o);
|
||||
}
|
||||
|
||||
o << "ELABORATED PARAMETERS:" << endl;
|
||||
{
|
||||
map<string,NetExpr*>::const_iterator pp;
|
||||
for (pp = parameters_.begin()
|
||||
; pp != parameters_.end() ; pp ++) {
|
||||
o << " " << (*pp).first << " = " <<
|
||||
*(*pp).second << ";" << endl;
|
||||
}
|
||||
}
|
||||
|
||||
o << "ELABORATED SIGNALS:" << endl;
|
||||
|
||||
// Dump the signals,
|
||||
if (signals_) {
|
||||
NetNet*cur = signals_->sig_next_;
|
||||
do {
|
||||
cur->dump_net(o, 0);
|
||||
cur = cur->sig_next_;
|
||||
} while (cur != signals_->sig_next_);
|
||||
}
|
||||
|
||||
o << "ELABORATED MEMORIES:" << endl;
|
||||
{
|
||||
map<string,NetMemory*>::const_iterator pp;
|
||||
for (pp = memories_.begin()
|
||||
; pp != memories_.end() ; pp ++) {
|
||||
(*pp).second->dump(o, 0);
|
||||
}
|
||||
}
|
||||
root_scope_->dump(o);
|
||||
|
||||
o << "ELABORATED FUNCTION DEFINITIONS:" << endl;
|
||||
{
|
||||
@@ -866,256 +979,82 @@ 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.85 2000/05/11 23:37:27 steve
|
||||
* Add support for procedural continuous assignment.
|
||||
*
|
||||
* Revision 1.60 1999/11/27 19:07:57 steve
|
||||
* Support the creation of scopes.
|
||||
* Revision 1.84 2000/05/07 18:20:07 steve
|
||||
* Import MCD support from Stephen Tell, and add
|
||||
* system function parameter support to the IVL core.
|
||||
*
|
||||
* Revision 1.59 1999/11/24 04:01:58 steve
|
||||
* Detect and list scope names.
|
||||
* Revision 1.83 2000/05/07 04:37:56 steve
|
||||
* Carry strength values from Verilog source to the
|
||||
* pform and netlist for gates.
|
||||
*
|
||||
* Revision 1.58 1999/11/21 00:13:08 steve
|
||||
* Support memories in continuous assignments.
|
||||
* Change vvm constants to use the driver_t to drive
|
||||
* a constant value. This works better if there are
|
||||
* multiple drivers on a signal.
|
||||
*
|
||||
* Revision 1.57 1999/11/14 23:43:45 steve
|
||||
* Support combinatorial comparators.
|
||||
* Revision 1.82 2000/05/04 03:37:58 steve
|
||||
* Add infrastructure for system functions, move
|
||||
* $time to that structure and add $random.
|
||||
*
|
||||
* Revision 1.56 1999/11/14 20:24:28 steve
|
||||
* Add support for the LPM_CLSHIFT device.
|
||||
* Revision 1.81 2000/05/02 03:13:30 steve
|
||||
* Move memories to the NetScope object.
|
||||
*
|
||||
* Revision 1.55 1999/11/04 03:53:26 steve
|
||||
* Patch to synthesize unary ~ and the ternary operator.
|
||||
* Thanks to Larry Doolittle <[email protected]>.
|
||||
* Revision 1.80 2000/05/02 00:58:11 steve
|
||||
* Move signal tables to the NetScope class.
|
||||
*
|
||||
* 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.
|
||||
* Revision 1.79 2000/04/28 21:00:29 steve
|
||||
* Over agressive signal elimination in constant probadation.
|
||||
*
|
||||
* Rewrite elaborate_net for the PETernary class to
|
||||
* also use the LPM_MUX device.
|
||||
* Revision 1.78 2000/04/23 03:45:24 steve
|
||||
* Add support for the procedural release statement.
|
||||
*
|
||||
* Revision 1.54 1999/11/04 01:12:41 steve
|
||||
* Elaborate combinational UDP devices.
|
||||
* Revision 1.77 2000/04/22 04:20:19 steve
|
||||
* Add support for force assignment.
|
||||
*
|
||||
* 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.76 2000/04/12 20:02:52 steve
|
||||
* Finally remove the NetNEvent and NetPEvent classes,
|
||||
* Get synthesis working with the NetEvWait class,
|
||||
* and get started supporting multiple events in a
|
||||
* wait in vvm.
|
||||
*
|
||||
* Revision 1.52 1999/10/31 20:08:24 steve
|
||||
* Include subtraction in LPM_ADD_SUB device.
|
||||
* Revision 1.75 2000/04/12 04:23:57 steve
|
||||
* Named events really should be expressed with PEIdent
|
||||
* objects in the pform,
|
||||
*
|
||||
* 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.
|
||||
* Handle named events within the mix of net events
|
||||
* and edges. As a unified lot they get caught together.
|
||||
* wait statements are broken into more complex statements
|
||||
* that include a conditional.
|
||||
*
|
||||
* Revision 1.50 1999/10/10 01:59:54 steve
|
||||
* Structural case equals device.
|
||||
* Do not generate NetPEvent or NetNEvent objects in
|
||||
* elaboration. NetEvent, NetEvWait and NetEvProbe
|
||||
* take over those functions in the netlist.
|
||||
*
|
||||
* Revision 1.49 1999/10/08 02:00:35 steve
|
||||
* Fix dump of sase statements.
|
||||
* Revision 1.74 2000/04/10 05:26:05 steve
|
||||
* All events now use the NetEvent class.
|
||||
*
|
||||
* Revision 1.48 1999/10/07 05:25:33 steve
|
||||
* Add non-const bit select in l-value of assignment.
|
||||
* Revision 1.73 2000/04/04 03:20:15 steve
|
||||
* Simulate named event trigger and waits.
|
||||
*
|
||||
* Revision 1.47 1999/10/06 05:06:16 steve
|
||||
* Move the rvalue into NetAssign_ common code.
|
||||
* Revision 1.72 2000/04/02 04:26:06 steve
|
||||
* Remove the useless sref template.
|
||||
*
|
||||
* Revision 1.46 1999/10/05 06:19:46 steve
|
||||
* Add support for reduction NOR.
|
||||
* Revision 1.71 2000/04/01 21:40:22 steve
|
||||
* Add support for integer division.
|
||||
*
|
||||
* Revision 1.45 1999/09/30 02:43:01 steve
|
||||
* Elaborate ~^ and ~| operators.
|
||||
* Revision 1.70 2000/03/29 04:37:10 steve
|
||||
* New and improved combinational primitives.
|
||||
*
|
||||
* 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
|
||||
* lists of times.
|
||||
*
|
||||
* Revision 1.33 1999/07/24 02:11:20 steve
|
||||
* Elaborate task input ports.
|
||||
*
|
||||
* Revision 1.32 1999/07/17 19:50:59 steve
|
||||
* netlist support for ternary operator.
|
||||
*
|
||||
* Revision 1.31 1999/07/03 02:12:51 steve
|
||||
* Elaborate user defined tasks.
|
||||
*
|
||||
* Revision 1.30 1999/06/19 21:06:16 steve
|
||||
* Elaborate and supprort to vvm the forever
|
||||
* and repeat statements.
|
||||
*
|
||||
* Revision 1.29 1999/06/15 05:38:15 steve
|
||||
* Handle total lack of signals or nodes.
|
||||
*
|
||||
* Revision 1.28 1999/06/09 03:00:05 steve
|
||||
* Add support for procedural concatenation expression.
|
||||
*
|
||||
* Revision 1.27 1999/06/06 20:45:38 steve
|
||||
* Add parse and elaboration of non-blocking assignments,
|
||||
* Replace list<PCase::Item*> with an svector version,
|
||||
* Add integer support.
|
||||
*
|
||||
* Revision 1.26 1999/05/31 15:46:20 steve
|
||||
* Compilation warning.
|
||||
*
|
||||
* Revision 1.25 1999/05/30 01:11:46 steve
|
||||
* Exressions are trees that can duplicate, and not DAGS.
|
||||
*
|
||||
* Revision 1.24 1999/05/17 04:53:47 steve
|
||||
* translate the letter synonyms for operators.
|
||||
*
|
||||
* Revision 1.23 1999/05/10 00:16:58 steve
|
||||
* Parse and elaborate the concatenate operator
|
||||
* in structural contexts, Replace vector<PExpr*>
|
||||
* and list<PExpr*> with svector<PExpr*>, evaluate
|
||||
* constant expressions with parameters, handle
|
||||
* memories as lvalues.
|
||||
*
|
||||
* Parse task declarations, integer types.
|
||||
*
|
||||
* Revision 1.22 1999/05/06 02:29:32 steve
|
||||
* Excesss endl.
|
||||
*
|
||||
* Revision 1.21 1999/05/05 03:04:46 steve
|
||||
* Fix handling of null delay statements.
|
||||
*
|
||||
* Revision 1.20 1999/05/01 20:43:55 steve
|
||||
* Handle wide events, such as @(a) where a has
|
||||
* many bits in it.
|
||||
*
|
||||
* Add to vvm the binary ^ and unary & operators.
|
||||
*
|
||||
* Dump events a bit more completely.
|
||||
*
|
||||
* Revision 1.19 1999/05/01 02:57:52 steve
|
||||
* Handle much more complex event expressions.
|
||||
*
|
||||
* Revision 1.18 1999/04/25 00:44:10 steve
|
||||
* Core handles subsignal expressions.
|
||||
*
|
||||
* Revision 1.17 1999/04/19 01:59:36 steve
|
||||
* Add memories to the parse and elaboration phases.
|
||||
*
|
||||
* Revision 1.16 1999/03/15 02:43:32 steve
|
||||
* Support more operators, especially logical.
|
||||
*
|
||||
* Revision 1.15 1999/03/01 03:27:53 steve
|
||||
* Prevent the duplicate allocation of ESignal objects.
|
||||
*
|
||||
* Revision 1.14 1999/02/21 17:01:57 steve
|
||||
* Add support for module parameters.
|
||||
*
|
||||
* Revision 1.13 1999/02/15 02:06:15 steve
|
||||
* Elaborate gate ranges.
|
||||
*
|
||||
* Revision 1.12 1999/02/08 02:49:56 steve
|
||||
* Turn the NetESignal into a NetNode so
|
||||
* that it can connect to the netlist.
|
||||
* Implement the case statement.
|
||||
* Convince t-vvm to output code for
|
||||
* the case statement.
|
||||
*
|
||||
* Revision 1.11 1999/02/03 04:20:11 steve
|
||||
* Parse and elaborate the Verilog CASE statement.
|
||||
*
|
||||
* Revision 1.10 1999/02/01 00:26:48 steve
|
||||
* Carry some line info to the netlist,
|
||||
* Dump line numbers for processes.
|
||||
* Elaborate prints errors about port vector
|
||||
* width mismatch
|
||||
* Emit better handles null statements.
|
||||
*
|
||||
* Revision 1.9 1998/12/20 02:05:41 steve
|
||||
* Function to calculate wire initial value.
|
||||
*
|
||||
* Revision 1.8 1998/12/14 02:01:34 steve
|
||||
* Fully elaborate Sequential UDP behavior.
|
||||
*
|
||||
* Revision 1.7 1998/12/07 04:53:17 steve
|
||||
* Generate OBUF or IBUF attributes (and the gates
|
||||
* to garry them) where a wire is a pad. This involved
|
||||
* figuring out enough of the netlist to know when such
|
||||
* was needed, and to generate new gates and signales
|
||||
* to handle what's missing.
|
||||
*
|
||||
* Revision 1.6 1998/12/02 04:37:13 steve
|
||||
* Add the nobufz function to eliminate bufz objects,
|
||||
* Object links are marked with direction,
|
||||
* constant propagation is more careful will wide links,
|
||||
* Signal folding is aware of attributes, and
|
||||
* the XNF target can dump UDP objects based on LCA
|
||||
* attributes.
|
||||
*
|
||||
* Revision 1.5 1998/12/01 00:42:13 steve
|
||||
* Elaborate UDP devices,
|
||||
* Support UDP type attributes, and
|
||||
* pass those attributes to nodes that
|
||||
* are instantiated by elaboration,
|
||||
* Put modules into a map instead of
|
||||
* a simple list.
|
||||
*
|
||||
* Revision 1.4 1998/11/23 00:20:22 steve
|
||||
* NetAssign handles lvalues as pin links
|
||||
* instead of a signal pointer,
|
||||
* Wire attributes added,
|
||||
* Ability to parse UDP descriptions added,
|
||||
* XNF generates EXT records for signals with
|
||||
* the PAD attribute.
|
||||
*
|
||||
* Revision 1.3 1998/11/09 18:55:34 steve
|
||||
* Add procedural while loops,
|
||||
* Parse procedural for loops,
|
||||
* Add procedural wait statements,
|
||||
* Add constant nodes,
|
||||
* Add XNOR logic gate,
|
||||
* Make vvm output look a bit prettier.
|
||||
*
|
||||
* Revision 1.2 1998/11/07 17:05:05 steve
|
||||
* Handle procedural conditional, and some
|
||||
* of the conditional expressions.
|
||||
*
|
||||
* Elaborate signals and identifiers differently,
|
||||
* allowing the netlist to hold signal information.
|
||||
*
|
||||
* Revision 1.1 1998/11/03 23:28:56 steve
|
||||
* Introduce verilog to CVS.
|
||||
* Revision 1.69 2000/03/12 17:09:40 steve
|
||||
* Support localparam.
|
||||
*
|
||||
* Revision 1.68 2000/03/08 04:36:53 steve
|
||||
* Redesign the implementation of scopes and parameters.
|
||||
* I now generate the scopes and notice the parameters
|
||||
* in a separate pass over the pform. Once the scopes
|
||||
* are generated, I can process overrides and evalutate
|
||||
* paremeters before elaboration begins.
|
||||
*/
|
||||
|
||||
|
||||
+22
-2
@@ -16,8 +16,8 @@
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
|
||||
*/
|
||||
#if !defined(WINNT)
|
||||
#ident "$Id: dup_expr.cc,v 1.1 1999/11/27 19:07:57 steve Exp $"
|
||||
#if !defined(WINNT) && !defined(macintosh)
|
||||
#ident "$Id: dup_expr.cc,v 1.4 2000/05/07 18:20:07 steve Exp $"
|
||||
#endif
|
||||
|
||||
# include "netlist.h"
|
||||
@@ -29,8 +29,28 @@ NetEScope* NetEScope::dup_expr() const
|
||||
return 0;
|
||||
}
|
||||
|
||||
NetESFunc* NetESFunc::dup_expr() const
|
||||
{
|
||||
NetESFunc*tmp = new NetESFunc(name_, expr_width(), nparms());
|
||||
for (unsigned idx = 0 ; idx < nparms() ; idx += 1)
|
||||
tmp->parm(idx, tmp->parm(idx)->dup_expr());
|
||||
|
||||
return tmp;
|
||||
}
|
||||
|
||||
/*
|
||||
* $Log: dup_expr.cc,v $
|
||||
* Revision 1.4 2000/05/07 18:20:07 steve
|
||||
* Import MCD support from Stephen Tell, and add
|
||||
* system function parameter support to the IVL core.
|
||||
*
|
||||
* Revision 1.3 2000/05/04 03:37:58 steve
|
||||
* Add infrastructure for system functions, move
|
||||
* $time to that structure and add $random.
|
||||
*
|
||||
* Revision 1.2 2000/02/23 02:56:54 steve
|
||||
* Macintosh compilers do not support ident.
|
||||
*
|
||||
* Revision 1.1 1999/11/27 19:07:57 steve
|
||||
* Support the creation of scopes.
|
||||
*
|
||||
|
||||
+227
-51
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 1999 Stephen Williams ([email protected])
|
||||
* Copyright (c) 1999-2000 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
|
||||
@@ -16,24 +16,30 @@
|
||||
* 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 $"
|
||||
#if !defined(WINNT) && !defined(macintosh)
|
||||
#ident "$Id: elab_expr.cc,v 1.25 2000/05/07 18:20:07 steve Exp $"
|
||||
#endif
|
||||
|
||||
|
||||
# include "pform.h"
|
||||
# include "netlist.h"
|
||||
|
||||
NetExpr* PExpr::elaborate_expr(Design*des, NetScope*) const
|
||||
{
|
||||
cerr << get_line() << ": I do not know how to elaborate expression: "
|
||||
<< *this << endl;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* 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
|
||||
NetEBinary* PEBinary::elaborate_expr(Design*des, NetScope*scope) const
|
||||
{
|
||||
bool flag;
|
||||
NetExpr*lp = left_->elaborate_expr(des, path);
|
||||
NetExpr*rp = right_->elaborate_expr(des, path);
|
||||
NetExpr*lp = left_->elaborate_expr(des, scope);
|
||||
NetExpr*rp = right_->elaborate_expr(des, scope);
|
||||
if ((lp == 0) || (rp == 0)) {
|
||||
delete lp;
|
||||
delete rp;
|
||||
@@ -55,7 +61,21 @@ NetExpr* PEBinary::elaborate_expr(Design*des, const string&path) const
|
||||
}
|
||||
}
|
||||
|
||||
NetEBinary*tmp = elaborate_expr_base_(des, lp, rp);
|
||||
return tmp;
|
||||
}
|
||||
|
||||
/*
|
||||
* This is common elaboration of the operator. It presumes that the
|
||||
* operands are elaborated as necessary, and all I need to do is make
|
||||
* the correct NetEBinary object and connect the parameters.
|
||||
*/
|
||||
NetEBinary* PEBinary::elaborate_expr_base_(Design*des,
|
||||
NetExpr*lp, NetExpr*rp) const
|
||||
{
|
||||
bool flag;
|
||||
NetEBinary*tmp;
|
||||
|
||||
switch (op_) {
|
||||
default:
|
||||
tmp = new NetEBinary(op_, lp, rp);
|
||||
@@ -68,6 +88,17 @@ NetExpr* PEBinary::elaborate_expr(Design*des, const string&path) const
|
||||
tmp->set_line(*this);
|
||||
break;
|
||||
|
||||
case '*':
|
||||
tmp = new NetEBMult(op_, lp, rp);
|
||||
tmp->set_line(*this);
|
||||
break;
|
||||
|
||||
case '/':
|
||||
case '%':
|
||||
tmp = new NetEBDiv(op_, lp, rp);
|
||||
tmp->set_line(*this);
|
||||
break;
|
||||
|
||||
case 'l':
|
||||
case 'r':
|
||||
tmp = new NetEBShift(op_, lp, rp);
|
||||
@@ -111,38 +142,59 @@ NetExpr* PEBinary::elaborate_expr(Design*des, const string&path) const
|
||||
return tmp;
|
||||
}
|
||||
|
||||
NetESFunc* PECallFunction::elaborate_sfunc_(Design*des, const string&path) const
|
||||
NetExpr* PECallFunction::elaborate_sfunc_(Design*des, NetScope*scope) const
|
||||
{
|
||||
cerr << get_line() << ": sorry: system functions not supported."
|
||||
<< endl;
|
||||
des->errors += 1;
|
||||
return 0;
|
||||
unsigned wid = 32;
|
||||
|
||||
if (name_ == "$time")
|
||||
wid = 64;
|
||||
|
||||
NetESFunc*fun = new NetESFunc(name_, wid, parms_.count());
|
||||
for (unsigned idx = 0 ; idx < parms_.count() ; idx += 1) {
|
||||
PExpr*expr = parms_[idx];
|
||||
NetExpr*tmp = expr->elaborate_expr(des, scope);
|
||||
fun->parm(idx, tmp);
|
||||
}
|
||||
|
||||
return fun;
|
||||
}
|
||||
|
||||
NetExpr* PECallFunction::elaborate_expr(Design*des, const string&path) const
|
||||
NetExpr* PECallFunction::elaborate_expr(Design*des, NetScope*scope) const
|
||||
{
|
||||
if (name_[0] == '$')
|
||||
return elaborate_sfunc_(des, path);
|
||||
return elaborate_sfunc_(des, scope);
|
||||
|
||||
string myname = path+"."+name_;
|
||||
NetFuncDef*def = des->find_function(path, name_);
|
||||
NetFuncDef*def = des->find_function(scope->name(), name_);
|
||||
if (def == 0) {
|
||||
cerr << get_line() << ": error: No function " << name_ <<
|
||||
" in this context (" << path << ")." << endl;
|
||||
" in this context (" << scope->name() << ")." << endl;
|
||||
des->errors += 1;
|
||||
return 0;
|
||||
}
|
||||
assert(def);
|
||||
|
||||
NetScope*dscope = des->find_scope(def->name());
|
||||
assert(dscope);
|
||||
|
||||
svector<NetExpr*> parms (parms_.count());
|
||||
|
||||
/* Elaborate the input expressions for the function. This is
|
||||
done in the scope of the function call, and not the scope
|
||||
of the function being called. The scope of the called
|
||||
function is elaborated when the definition is elaborated. */
|
||||
|
||||
for (unsigned idx = 0 ; idx < parms.count() ; idx += 1) {
|
||||
NetExpr*tmp = parms_[idx]->elaborate_expr(des, myname);
|
||||
NetExpr*tmp = parms_[idx]->elaborate_expr(des, scope);
|
||||
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_);
|
||||
|
||||
/* Look for the return value signal for the called
|
||||
function. This return value is a magic signal in the scope
|
||||
of the function, that has the name of the function. The
|
||||
function code assigns to this signal to return a value. */
|
||||
|
||||
NetNet*res = des->find_signal(dscope, name_);
|
||||
if (res == 0) {
|
||||
cerr << get_line() << ": internal error: Unable to locate "
|
||||
"function return value for " << name_ << " in " <<
|
||||
@@ -159,22 +211,57 @@ NetExpr* PECallFunction::elaborate_expr(Design*des, const string&path) const
|
||||
}
|
||||
|
||||
|
||||
NetExpr* PEIdent::elaborate_expr(Design*des, const string&path) const
|
||||
NetExpr* PEConcat::elaborate_expr(Design*des, NetScope*scope) const
|
||||
{
|
||||
// System identifiers show up in the netlist as identifiers.
|
||||
if (text_[0] == '$')
|
||||
return new NetEIdent(text_, 64);
|
||||
unsigned repeat = 1;
|
||||
|
||||
string name = path+"."+text_;
|
||||
/* If there is a repeat expression, then evaluate the constant
|
||||
value and set the repeat count. */
|
||||
if (repeat_) {
|
||||
verinum*vrep = repeat_->eval_const(des, scope->name());
|
||||
if (vrep == 0) {
|
||||
cerr << get_line() << ": error: "
|
||||
"concatenation repeat expression cannot be evaluated."
|
||||
<< endl;
|
||||
des->errors += 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
repeat = vrep->as_ulong();
|
||||
delete vrep;
|
||||
}
|
||||
|
||||
/* Make the empty concat expression. */
|
||||
NetEConcat*tmp = new NetEConcat(parms_.count(), repeat);
|
||||
tmp->set_line(*this);
|
||||
|
||||
/* Elaborate all the parameters and attach them to the concat node. */
|
||||
for (unsigned idx = 0 ; idx < parms_.count() ; idx += 1) {
|
||||
assert(parms_[idx]);
|
||||
NetExpr*ex = parms_[idx]->elaborate_expr(des, scope);
|
||||
if (ex == 0) continue;
|
||||
ex->set_line(*parms_[idx]);
|
||||
tmp->set(idx, ex);
|
||||
}
|
||||
|
||||
return tmp;
|
||||
}
|
||||
|
||||
NetExpr* PEIdent::elaborate_expr(Design*des, NetScope*scope) const
|
||||
{
|
||||
assert(text_[0] != '$');
|
||||
|
||||
//string name = path+"."+text_;
|
||||
assert(scope);
|
||||
|
||||
// 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_)) {
|
||||
if (const NetExpr*ex = des->find_parameter(scope, text_)) {
|
||||
NetExpr*tmp;
|
||||
if (dynamic_cast<const NetExpr*>(ex))
|
||||
tmp = ex->dup_expr();
|
||||
else
|
||||
tmp = new NetEParam(des, path, text_);
|
||||
tmp = new NetEParam(des, scope, text_);
|
||||
|
||||
tmp->set_line(*this);
|
||||
return tmp;
|
||||
@@ -182,15 +269,15 @@ NetExpr* PEIdent::elaborate_expr(Design*des, const string&path) const
|
||||
|
||||
// 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 (NetNet*net = des->find_signal(scope, 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);
|
||||
verinum*lsn = lsb_->eval_const(des, scope->name());
|
||||
verinum*msn = msb_->eval_const(des, scope->name());
|
||||
if ((lsn == 0) || (msn == 0)) {
|
||||
cerr << get_line() << ": error: "
|
||||
"Part select expresions must be "
|
||||
@@ -207,8 +294,8 @@ NetExpr* PEIdent::elaborate_expr(Design*des, const string&path) const
|
||||
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);
|
||||
string tname = des->local_symbol(scope->name());
|
||||
NetTmp*tsig = new NetTmp(scope, tname, wid);
|
||||
|
||||
// Connect the pins from the lsb up to the msb.
|
||||
unsigned off = net->sb_to_idx(lsv);
|
||||
@@ -218,7 +305,6 @@ NetExpr* PEIdent::elaborate_expr(Design*des, const string&path) const
|
||||
NetESignal*tmp = new NetESignal(tsig);
|
||||
tmp->set_line(*this);
|
||||
|
||||
des->add_signal(tsig);
|
||||
return tmp;
|
||||
}
|
||||
|
||||
@@ -226,17 +312,25 @@ NetExpr* PEIdent::elaborate_expr(Design*des, const string&path) const
|
||||
// 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))) {
|
||||
if (msb_ && (msn = msb_->eval_const(des, scope->name()))) {
|
||||
assert(idx_ == 0);
|
||||
unsigned long msv = msn->as_ulong();
|
||||
unsigned idx = net->sb_to_idx(msv);
|
||||
|
||||
string tname = des->local_symbol(path);
|
||||
NetTmp*tsig = new NetTmp(tname);
|
||||
connect(tsig->pin(0), net->pin(msv));
|
||||
if (idx >= net->pin_count()) {
|
||||
cerr << get_line() << ": internal error: "
|
||||
<< "bit " << msv << " out of range of net "
|
||||
<< net->name() << "[" << net->msb()
|
||||
<< ":" << net->lsb() << "]." << endl;
|
||||
return 0;
|
||||
}
|
||||
|
||||
string tname = des->local_symbol(scope->name());
|
||||
NetTmp*tsig = new NetTmp(scope, tname);
|
||||
connect(tsig->pin(0), net->pin(idx));
|
||||
NetESignal*tmp = new NetESignal(tsig);
|
||||
tmp->set_line(*this);
|
||||
|
||||
des->add_signal(tsig);
|
||||
return tmp;
|
||||
}
|
||||
|
||||
@@ -246,7 +340,7 @@ NetExpr* PEIdent::elaborate_expr(Design*des, const string&path) const
|
||||
// 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);
|
||||
NetExpr*ex = msb_->elaborate_expr(des, scope);
|
||||
NetESubSignal*ss = new NetESubSignal(node, ex);
|
||||
ss->set_line(*this);
|
||||
return ss;
|
||||
@@ -261,17 +355,16 @@ NetExpr* PEIdent::elaborate_expr(Design*des, const string&path) const
|
||||
// If the identifier names a memory, then this is a
|
||||
// memory reference and I must generate a NetEMemory
|
||||
// object to handle it.
|
||||
if (NetMemory*mem = des->find_memory(path, text_)) {
|
||||
if (NetMemory*mem = des->find_memory(scope, text_)) {
|
||||
if (msb_ == 0) {
|
||||
cerr << get_line() << ": error: Memory ``" << name <<
|
||||
"'' referenced without an index expression." << endl;
|
||||
des->errors += 1;
|
||||
return 0;
|
||||
NetEMemory*node = new NetEMemory(mem);
|
||||
node->set_line(*this);
|
||||
return node;
|
||||
}
|
||||
assert(msb_ != 0);
|
||||
assert(lsb_ == 0);
|
||||
assert(idx_ == 0);
|
||||
NetExpr*i = msb_->elaborate_expr(des, path);
|
||||
NetExpr*i = msb_->elaborate_expr(des, scope);
|
||||
if (msb_ && i == 0) {
|
||||
cerr << get_line() << ": error: Unable to exaborate "
|
||||
"index expression `" << *msb_ << "'" << endl;
|
||||
@@ -293,33 +386,48 @@ NetExpr* PEIdent::elaborate_expr(Design*des, const string&path) const
|
||||
|
||||
// I cannot interpret this identifier. Error message.
|
||||
cerr << get_line() << ": error: Unable to bind wire/reg/memory "
|
||||
"`" << path << "." << text_ << "'" << endl;
|
||||
"`" << text_ << "' in `" << scope->name() << "'" << endl;
|
||||
des->errors += 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
NetEConst* PENumber::elaborate_expr(Design*des, NetScope*) const
|
||||
{
|
||||
assert(value_);
|
||||
NetEConst*tmp = new NetEConst(*value_);
|
||||
tmp->set_line(*this);
|
||||
return tmp;
|
||||
}
|
||||
|
||||
NetEConst* PEString::elaborate_expr(Design*des, NetScope*) const
|
||||
{
|
||||
NetEConst*tmp = new NetEConst(value());
|
||||
tmp->set_line(*this);
|
||||
return tmp;
|
||||
}
|
||||
|
||||
/*
|
||||
* 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
|
||||
NetETernary*PETernary::elaborate_expr(Design*des, NetScope*scope) const
|
||||
{
|
||||
assert(expr_);
|
||||
assert(tru_);
|
||||
assert(fal_);
|
||||
|
||||
NetExpr*con = expr_->elaborate_expr(des, path);
|
||||
NetExpr*con = expr_->elaborate_expr(des, scope);
|
||||
if (con == 0)
|
||||
return 0;
|
||||
|
||||
NetExpr*tru = tru_->elaborate_expr(des, path);
|
||||
NetExpr*tru = tru_->elaborate_expr(des, scope);
|
||||
if (tru == 0) {
|
||||
delete con;
|
||||
return 0;
|
||||
}
|
||||
|
||||
NetExpr*fal = fal_->elaborate_expr(des, path);
|
||||
NetExpr*fal = fal_->elaborate_expr(des, scope);
|
||||
if (fal == 0) {
|
||||
delete con;
|
||||
delete tru;
|
||||
@@ -330,8 +438,76 @@ NetExpr*PETernary::elaborate_expr(Design*des, const string&path) const
|
||||
return res;
|
||||
}
|
||||
|
||||
NetEUnary* PEUnary::elaborate_expr(Design*des, NetScope*scope) const
|
||||
{
|
||||
NetExpr*ip = expr_->elaborate_expr(des, scope);
|
||||
if (ip == 0) return 0;
|
||||
|
||||
/* Should we evaluate expressions ahead of time,
|
||||
* just like in PEBinary::elaborate_expr() ?
|
||||
*/
|
||||
|
||||
NetEUnary*tmp;
|
||||
switch (op_) {
|
||||
default:
|
||||
tmp = new NetEUnary(op_, ip);
|
||||
tmp->set_line(*this);
|
||||
break;
|
||||
case '~':
|
||||
tmp = new NetEUBits(op_, ip);
|
||||
tmp->set_line(*this);
|
||||
break;
|
||||
}
|
||||
return tmp;
|
||||
}
|
||||
|
||||
/*
|
||||
* $Log: elab_expr.cc,v $
|
||||
* Revision 1.25 2000/05/07 18:20:07 steve
|
||||
* Import MCD support from Stephen Tell, and add
|
||||
* system function parameter support to the IVL core.
|
||||
*
|
||||
* Revision 1.24 2000/05/04 03:37:58 steve
|
||||
* Add infrastructure for system functions, move
|
||||
* $time to that structure and add $random.
|
||||
*
|
||||
* Revision 1.23 2000/05/02 03:13:30 steve
|
||||
* Move memories to the NetScope object.
|
||||
*
|
||||
* Revision 1.22 2000/05/02 00:58:11 steve
|
||||
* Move signal tables to the NetScope class.
|
||||
*
|
||||
* Revision 1.21 2000/04/28 18:43:23 steve
|
||||
* integer division in expressions properly get width.
|
||||
*
|
||||
* Revision 1.20 2000/03/29 04:06:28 steve
|
||||
* Forgot to return elaborate result (Dan Nelsen)
|
||||
*
|
||||
* Revision 1.19 2000/03/20 16:57:22 steve
|
||||
* select correct bit when reg has non-zero lsb.
|
||||
*
|
||||
* Revision 1.18 2000/03/12 18:22:11 steve
|
||||
* Binary and unary operators in parameter expressions.
|
||||
*
|
||||
* Revision 1.17 2000/03/08 04:36:53 steve
|
||||
* Redesign the implementation of scopes and parameters.
|
||||
* I now generate the scopes and notice the parameters
|
||||
* in a separate pass over the pform. Once the scopes
|
||||
* are generated, I can process overrides and evalutate
|
||||
* paremeters before elaboration begins.
|
||||
*
|
||||
* Revision 1.16 2000/02/23 02:56:54 steve
|
||||
* Macintosh compilers do not support ident.
|
||||
*
|
||||
* Revision 1.15 2000/01/13 03:35:35 steve
|
||||
* Multiplication all the way to simulation.
|
||||
*
|
||||
* Revision 1.14 2000/01/01 06:18:00 steve
|
||||
* Handle synthesis of concatenation.
|
||||
*
|
||||
* Revision 1.13 1999/12/12 06:03:14 steve
|
||||
* Allow memories without indices in expressions.
|
||||
*
|
||||
* Revision 1.12 1999/11/30 04:54:01 steve
|
||||
* Match scope names as last resort.
|
||||
*
|
||||
|
||||
+888
-212
File diff suppressed because it is too large
Load Diff
+123
@@ -0,0 +1,123 @@
|
||||
/*
|
||||
* Copyright (c) 2000 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) && !defined(macintosh)
|
||||
#ident "$Id: elab_pexpr.cc,v 1.3 2000/03/12 18:22:11 steve Exp $"
|
||||
#endif
|
||||
|
||||
# include "PExpr.h"
|
||||
|
||||
NetExpr*PExpr::elaborate_pexpr(Design*des, NetScope*sc) const
|
||||
{
|
||||
cerr << get_line() << ": error: invalid parameter expression: "
|
||||
<< *this << endl;
|
||||
des->errors += 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Binary operators have sub-expressions that must be elaborated as
|
||||
* parameter expressions. If either of them fail, then give up. Once
|
||||
* they are taken care of, make the base object just as in any other
|
||||
* expression.
|
||||
*/
|
||||
NetExpr*PEBinary::elaborate_pexpr (Design*des, NetScope*scope) const
|
||||
{
|
||||
NetExpr*lp = left_->elaborate_pexpr(des, scope);
|
||||
NetExpr*rp = right_->elaborate_pexpr(des, scope);
|
||||
if ((lp == 0) || (rp == 0)) {
|
||||
delete lp;
|
||||
delete rp;
|
||||
return 0;
|
||||
}
|
||||
|
||||
NetEBinary*tmp = elaborate_expr_base_(des, lp, rp);
|
||||
return tmp;
|
||||
}
|
||||
|
||||
/*
|
||||
* Parameter expressions may reference other parameters, but only in
|
||||
* the current scope. Preserve the parameter reference in the
|
||||
* parameter expression I'm generating, instead of evaluating it now,
|
||||
* because the referenced parameter may yet be overridden.
|
||||
*/
|
||||
NetExpr*PEIdent::elaborate_pexpr(Design*des, NetScope*scope) const
|
||||
{
|
||||
const NetExpr*ex = scope->get_parameter(text_);
|
||||
if (ex == 0) {
|
||||
cerr << get_line() << ": error: identifier ``" << text_ <<
|
||||
"'' is not a parameter in " << scope->name() << "." << endl;
|
||||
des->errors += 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
NetExpr*res = new NetEParam(des, scope, text_);
|
||||
assert(res);
|
||||
return res;
|
||||
}
|
||||
|
||||
/*
|
||||
* Simple numbers can be elaborated by the elaborate_expr method.
|
||||
*/
|
||||
NetExpr*PENumber::elaborate_pexpr(Design*des, NetScope*sc) const
|
||||
{
|
||||
return elaborate_expr(des, sc);
|
||||
}
|
||||
|
||||
|
||||
NetExpr*PEUnary::elaborate_pexpr (Design*des, NetScope*scope) const
|
||||
{
|
||||
NetExpr*ip = expr_->elaborate_pexpr(des, scope);
|
||||
if (ip == 0) return 0;
|
||||
|
||||
/* Should we evaluate expressions ahead of time,
|
||||
* just like in PEBinary::elaborate_expr() ?
|
||||
*/
|
||||
|
||||
NetEUnary*tmp;
|
||||
switch (op_) {
|
||||
default:
|
||||
tmp = new NetEUnary(op_, ip);
|
||||
tmp->set_line(*this);
|
||||
break;
|
||||
case '~':
|
||||
tmp = new NetEUBits(op_, ip);
|
||||
tmp->set_line(*this);
|
||||
break;
|
||||
}
|
||||
return tmp;
|
||||
}
|
||||
|
||||
/*
|
||||
* $Log: elab_pexpr.cc,v $
|
||||
* Revision 1.3 2000/03/12 18:22:11 steve
|
||||
* Binary and unary operators in parameter expressions.
|
||||
*
|
||||
* Revision 1.2 2000/03/12 04:35:22 steve
|
||||
* Allow parameter identifiers in parameter expressions.
|
||||
*
|
||||
* Revision 1.1 2000/03/08 04:36:53 steve
|
||||
* Redesign the implementation of scopes and parameters.
|
||||
* I now generate the scopes and notice the parameters
|
||||
* in a separate pass over the pform. Once the scopes
|
||||
* are generated, I can process overrides and evalutate
|
||||
* paremeters before elaboration begins.
|
||||
*
|
||||
*/
|
||||
|
||||
+435
@@ -0,0 +1,435 @@
|
||||
/*
|
||||
* Copyright (c) 2000 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) && !defined(macintosh)
|
||||
#ident "$Id: elab_scope.cc,v 1.4 2000/04/09 17:44:30 steve Exp $"
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Elaboration happens in two passes, generally. The first scans the
|
||||
* pform to generate the NetScope tree and attach it to the Design
|
||||
* object. The methods in this source file implement the elaboration
|
||||
* of the scopes.
|
||||
*/
|
||||
|
||||
# include "Module.h"
|
||||
# include "PEvent.h"
|
||||
# include "PExpr.h"
|
||||
# include "PGate.h"
|
||||
# include "PTask.h"
|
||||
# include "Statement.h"
|
||||
# include "netlist.h"
|
||||
# include <typeinfo>
|
||||
|
||||
bool Module::elaborate_scope(Design*des, NetScope*scope) const
|
||||
{
|
||||
// Generate all the parameters that this instance of this
|
||||
// module introduces to the design. This loop elaborates the
|
||||
// parameters, but doesn't evaluate references to
|
||||
// parameters. This scan practically locates all the
|
||||
// parameters and puts them in the parameter table in the
|
||||
// design.
|
||||
|
||||
// No expressions are evaluated, yet. For now, leave them in
|
||||
// the pform and just place a NetEParam placeholder in the
|
||||
// place of the elaborated expression.
|
||||
|
||||
typedef map<string,PExpr*>::const_iterator mparm_it_t;
|
||||
|
||||
|
||||
// This loop scans the parameters in the module, and creates
|
||||
// stub parameter entries in the scope for the parameter name.
|
||||
|
||||
for (mparm_it_t cur = parameters.begin()
|
||||
; cur != parameters.end() ; cur ++) {
|
||||
|
||||
scope->set_parameter((*cur).first, new NetEParam);
|
||||
}
|
||||
|
||||
for (mparm_it_t cur = localparams.begin()
|
||||
; cur != localparams.end() ; cur ++) {
|
||||
|
||||
scope->set_parameter((*cur).first, new NetEParam);
|
||||
}
|
||||
|
||||
|
||||
// Now scan the parameters again, this time elaborating them
|
||||
// for use as parameter values. This is after the previous
|
||||
// scan so that local parameter names can be used in the
|
||||
// r-value expressions.
|
||||
|
||||
for (mparm_it_t cur = parameters.begin()
|
||||
; cur != parameters.end() ; cur ++) {
|
||||
|
||||
PExpr*ex = (*cur).second;
|
||||
assert(ex);
|
||||
|
||||
NetExpr*val = ex->elaborate_pexpr(des, scope);
|
||||
val = scope->set_parameter((*cur).first, val);
|
||||
assert(val);
|
||||
delete val;
|
||||
}
|
||||
|
||||
for (mparm_it_t cur = localparams.begin()
|
||||
; cur != localparams.end() ; cur ++) {
|
||||
|
||||
PExpr*ex = (*cur).second;
|
||||
assert(ex);
|
||||
|
||||
NetExpr*val = ex->elaborate_pexpr(des, scope);
|
||||
val = scope->set_parameter((*cur).first, val);
|
||||
assert(val);
|
||||
delete val;
|
||||
}
|
||||
|
||||
// Run through the defparams for this module, elaborate the
|
||||
// expressions in this context and save the result is a table
|
||||
// for later final override.
|
||||
|
||||
// It is OK to elaborate the expressions of the defparam here
|
||||
// because Verilog requires that the expressions only use
|
||||
// local parameter names. It is *not* OK to do the override
|
||||
// here becuase the parameter receiving the assignment may be
|
||||
// in a scope not discovered by this pass.
|
||||
|
||||
for (mparm_it_t cur = defparms.begin()
|
||||
; cur != defparms.end() ; cur ++ ) {
|
||||
|
||||
PExpr*ex = (*cur).second;
|
||||
assert(ex);
|
||||
|
||||
NetExpr*val = ex->elaborate_pexpr(des, scope);
|
||||
if (val == 0) continue;
|
||||
scope->defparams[(*cur).first] = val;
|
||||
}
|
||||
|
||||
|
||||
// Tasks introduce new scopes, so scan the tasks in this
|
||||
// module. Create a scope for the task and pass that to the
|
||||
// elaborate_scope method of the PTask for detailed
|
||||
// processing.
|
||||
|
||||
typedef map<string,PTask*>::const_iterator tasks_it_t;
|
||||
|
||||
for (tasks_it_t cur = tasks_.begin()
|
||||
; cur != tasks_.end() ; cur ++ ) {
|
||||
|
||||
NetScope*task_scope = new NetScope(scope, (*cur).first,
|
||||
NetScope::TASK);
|
||||
(*cur).second->elaborate_scope(des, task_scope);
|
||||
}
|
||||
|
||||
|
||||
// Functions are very similar to tasks, at least from the
|
||||
// perspective of scopes. So handle them exactly the same
|
||||
// way.
|
||||
|
||||
typedef map<string,PFunction*>::const_iterator funcs_it_t;
|
||||
|
||||
for (funcs_it_t cur = funcs_.begin()
|
||||
; cur != funcs_.end() ; cur ++ ) {
|
||||
|
||||
NetScope*func_scope = new NetScope(scope, (*cur).first,
|
||||
NetScope::FUNC);
|
||||
(*cur).second->elaborate_scope(des, func_scope);
|
||||
}
|
||||
|
||||
|
||||
// Gates include modules, which might introduce new scopes, so
|
||||
// scan all of them to create those scopes.
|
||||
|
||||
typedef list<PGate*>::const_iterator gates_it_t;
|
||||
|
||||
for (gates_it_t cur = gates_.begin()
|
||||
; cur != gates_.end() ; cur ++ ) {
|
||||
|
||||
(*cur) -> elaborate_scope(des, scope);
|
||||
}
|
||||
|
||||
|
||||
// initial and always blocks may contain begin-end and
|
||||
// fork-join blocks that can introduce scopes. Therefore, I
|
||||
// get to scan processes here.
|
||||
|
||||
typedef list<PProcess*>::const_iterator proc_it_t;
|
||||
|
||||
for (proc_it_t cur = behaviors_.begin()
|
||||
; cur != behaviors_.end() ; cur ++ ) {
|
||||
|
||||
(*cur) -> statement() -> elaborate_scope(des, scope);
|
||||
}
|
||||
|
||||
// Scan through all the named events in this scope. We do not
|
||||
// need anything more then the current scope to do this
|
||||
// elaboration, so do it now. This allows for normal
|
||||
// elaboration to reference these events.
|
||||
|
||||
for (map<string,PEvent*>::const_iterator et = events.begin()
|
||||
; et != events.end() ; et ++ ) {
|
||||
|
||||
(*et).second->elaborate_scope(des, scope);
|
||||
}
|
||||
|
||||
return des->errors == 0;
|
||||
}
|
||||
|
||||
void PGModule::elaborate_scope_mod_(Design*des, Module*mod, NetScope*sc) const
|
||||
{
|
||||
// Missing module instance names have already been rejected.
|
||||
assert(get_name() != "");
|
||||
|
||||
string path = sc->name();
|
||||
|
||||
// Check for duplicate scopes. Simply look up the scope I'm
|
||||
// about to create, and if I find it then somebody beat me to
|
||||
// it.
|
||||
|
||||
if (NetScope*tmp = des->find_scope(path + "." + get_name())) {
|
||||
cerr << get_line() << ": error: Instance/Scope name " <<
|
||||
get_name() << " already used in this context." <<
|
||||
endl;
|
||||
des->errors += 1;
|
||||
return;
|
||||
}
|
||||
|
||||
// Create the new scope as a MODULE with my name.
|
||||
NetScope*my_scope = new NetScope(sc, get_name(), NetScope::MODULE);
|
||||
|
||||
|
||||
// This call actually arranges for the description of the
|
||||
// module type to process this instance and handle parameters
|
||||
// and sub-scopes that might occur. Parameters are also
|
||||
// created in that scope, as they exist. (I'll override them
|
||||
// later.)
|
||||
mod->elaborate_scope(des, my_scope);
|
||||
|
||||
// Look for module parameter replacements. This map receives
|
||||
// those replacements.
|
||||
|
||||
typedef map<string,PExpr*>::const_iterator mparm_it_t;
|
||||
map<string,PExpr*> replace;
|
||||
|
||||
|
||||
// Positional parameter overrides are matched to parameter
|
||||
// names by using the param_names list of parameter
|
||||
// names. This is an ordered list of names so the first name
|
||||
// is parameter 0, the second parameter 1, and so on.
|
||||
|
||||
if (overrides_) {
|
||||
assert(parms_ == 0);
|
||||
list<string>::const_iterator cur = mod->param_names.begin();
|
||||
for (unsigned idx = 0
|
||||
; idx < overrides_->count()
|
||||
; idx += 1, cur++) {
|
||||
replace[*cur] = (*overrides_)[idx];
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// Named parameter overrides carry a name with each override
|
||||
// so the mapping into the replace list is much easier.
|
||||
if (parms_) {
|
||||
assert(overrides_ == 0);
|
||||
for (unsigned idx = 0 ; idx < nparms_ ; idx += 1)
|
||||
replace[parms_[idx].name] = parms_[idx].parm;
|
||||
|
||||
}
|
||||
|
||||
|
||||
// And here we scan the replacements we collected. Elaborate
|
||||
// the expression in my context, then replace the sub-scope
|
||||
// parameter value with the new expression.
|
||||
|
||||
for (mparm_it_t cur = replace.begin()
|
||||
; cur != replace.end() ; cur ++ ) {
|
||||
|
||||
PExpr*tmp = (*cur).second;
|
||||
NetExpr*val = tmp->elaborate_pexpr(des, sc);
|
||||
val = my_scope->set_parameter((*cur).first, val);
|
||||
assert(val);
|
||||
delete val;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* The isn't really able to create new scopes, but it does create the
|
||||
* event name in the current scope, so can be done during the
|
||||
* elaborate_scope scan.
|
||||
*/
|
||||
void PEvent::elaborate_scope(Design*des, NetScope*scope) const
|
||||
{
|
||||
NetEvent*ev = new NetEvent(name_);
|
||||
ev->set_line(*this);
|
||||
scope->add_event(ev);
|
||||
}
|
||||
|
||||
void PFunction::elaborate_scope(Design*des, NetScope*scope) const
|
||||
{
|
||||
}
|
||||
|
||||
void PTask::elaborate_scope(Design*des, NetScope*scope) const
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* The base statement does not have sub-statements and does not
|
||||
* introduce any scope, so this is a no-op.
|
||||
*/
|
||||
void Statement::elaborate_scope(Design*, NetScope*) const
|
||||
{
|
||||
}
|
||||
|
||||
/*
|
||||
* When I get a behavioral block, check to see if it has a name. If it
|
||||
* does, then create a new scope for the statements within it,
|
||||
* otherwise use the current scope. Use the selected scope to scan the
|
||||
* statements that I contain.
|
||||
*/
|
||||
void PBlock::elaborate_scope(Design*des, NetScope*scope) const
|
||||
{
|
||||
NetScope*my_scope = scope;
|
||||
|
||||
if (name_ != "") {
|
||||
my_scope = new NetScope(scope, name_, bl_type_==BL_PAR
|
||||
? NetScope::FORK_JOIN
|
||||
: NetScope::BEGIN_END);
|
||||
}
|
||||
|
||||
for (unsigned idx = 0 ; idx < list_.count() ; idx += 1)
|
||||
list_[idx] -> elaborate_scope(des, my_scope);
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
* The case statement itseof does not introduce scope, but contains
|
||||
* other statements that may be named blocks. So scan the case items
|
||||
* with the elaborate_scope method.
|
||||
*/
|
||||
void PCase::elaborate_scope(Design*des, NetScope*scope) const
|
||||
{
|
||||
assert(items_);
|
||||
for (unsigned idx = 0 ; idx < (*items_).count() ; idx += 1) {
|
||||
assert( (*items_)[idx] );
|
||||
|
||||
if (Statement*sp = (*items_)[idx]->stat)
|
||||
sp -> elaborate_scope(des, scope);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* The conditional statement (if-else) does not introduce scope, but
|
||||
* the statements of the clauses may, so elaborate_scope the contained
|
||||
* statements.
|
||||
*/
|
||||
void PCondit::elaborate_scope(Design*des, NetScope*scope) const
|
||||
{
|
||||
if (if_)
|
||||
if_ -> elaborate_scope(des, scope);
|
||||
|
||||
if (else_)
|
||||
else_ -> elaborate_scope(des, scope);
|
||||
}
|
||||
|
||||
/*
|
||||
* Statements that contain a further statement but do not
|
||||
* intrinsically add a scope need to elaborate_scope the contained
|
||||
* statement.
|
||||
*/
|
||||
void PDelayStatement::elaborate_scope(Design*des, NetScope*scope) const
|
||||
{
|
||||
if (statement_)
|
||||
statement_ -> elaborate_scope(des, scope);
|
||||
}
|
||||
|
||||
/*
|
||||
* Statements that contain a further statement but do not
|
||||
* intrinsically add a scope need to elaborate_scope the contained
|
||||
* statement.
|
||||
*/
|
||||
void PEventStatement::elaborate_scope(Design*des, NetScope*scope) const
|
||||
{
|
||||
if (statement_)
|
||||
statement_ -> elaborate_scope(des, scope);
|
||||
}
|
||||
|
||||
/*
|
||||
* Statements that contain a further statement but do not
|
||||
* intrinsically add a scope need to elaborate_scope the contained
|
||||
* statement.
|
||||
*/
|
||||
void PForever::elaborate_scope(Design*des, NetScope*scope) const
|
||||
{
|
||||
if (statement_)
|
||||
statement_ -> elaborate_scope(des, scope);
|
||||
}
|
||||
|
||||
/*
|
||||
* Statements that contain a further statement but do not
|
||||
* intrinsically add a scope need to elaborate_scope the contained
|
||||
* statement.
|
||||
*/
|
||||
void PForStatement::elaborate_scope(Design*des, NetScope*scope) const
|
||||
{
|
||||
if (statement_)
|
||||
statement_ -> elaborate_scope(des, scope);
|
||||
}
|
||||
|
||||
/*
|
||||
* Statements that contain a further statement but do not
|
||||
* intrinsically add a scope need to elaborate_scope the contained
|
||||
* statement.
|
||||
*/
|
||||
void PRepeat::elaborate_scope(Design*des, NetScope*scope) const
|
||||
{
|
||||
if (statement_)
|
||||
statement_ -> elaborate_scope(des, scope);
|
||||
}
|
||||
|
||||
/*
|
||||
* Statements that contain a further statement but do not
|
||||
* intrinsically add a scope need to elaborate_scope the contained
|
||||
* statement.
|
||||
*/
|
||||
void PWhile::elaborate_scope(Design*des, NetScope*scope) const
|
||||
{
|
||||
if (statement_)
|
||||
statement_ -> elaborate_scope(des, scope);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* $Log: elab_scope.cc,v $
|
||||
* Revision 1.4 2000/04/09 17:44:30 steve
|
||||
* Catch event declarations during scope elaborate.
|
||||
*
|
||||
* Revision 1.3 2000/03/12 17:09:41 steve
|
||||
* Support localparam.
|
||||
*
|
||||
* Revision 1.2 2000/03/11 03:25:52 steve
|
||||
* Locate scopes in statements.
|
||||
*
|
||||
* Revision 1.1 2000/03/08 04:36:53 steve
|
||||
* Redesign the implementation of scopes and parameters.
|
||||
* I now generate the scopes and notice the parameters
|
||||
* in a separate pass over the pform. Once the scopes
|
||||
* are generated, I can process overrides and evalutate
|
||||
* paremeters before elaboration begins.
|
||||
*
|
||||
*/
|
||||
|
||||
+222
@@ -0,0 +1,222 @@
|
||||
/*
|
||||
* Copyright (c) 2000 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) && !defined(macintosh)
|
||||
#ident "$Id: elab_sig.cc,v 1.1 2000/05/02 16:27:38 steve Exp $"
|
||||
#endif
|
||||
|
||||
# include "Module.h"
|
||||
# include "PExpr.h"
|
||||
# include "PGate.h"
|
||||
# include "PWire.h"
|
||||
# include "netlist.h"
|
||||
# include "util.h"
|
||||
|
||||
|
||||
bool Module::elaborate_sig(Design*des, NetScope*scope) const
|
||||
{
|
||||
bool flag = true;
|
||||
|
||||
// Get all the explicitly declared wires of the module and
|
||||
// start the signals list with them.
|
||||
const map<string,PWire*>&wl = get_wires();
|
||||
|
||||
for (map<string,PWire*>::const_iterator wt = wl.begin()
|
||||
; wt != wl.end()
|
||||
; wt ++ ) {
|
||||
|
||||
(*wt).second->elaborate_sig(des, scope);
|
||||
}
|
||||
|
||||
// Get all the gates of the module and elaborate them by
|
||||
// connecting them to the signals. The gate may be simple or
|
||||
// complex. What we are looking for is gates that are modules
|
||||
// that can create scopes and signals.
|
||||
|
||||
const list<PGate*>&gl = get_gates();
|
||||
|
||||
for (list<PGate*>::const_iterator gt = gl.begin()
|
||||
; gt != gl.end()
|
||||
; gt ++ ) {
|
||||
|
||||
flag &= (*gt)->elaborate_sig(des, scope);
|
||||
}
|
||||
|
||||
return flag;
|
||||
}
|
||||
|
||||
bool PGModule::elaborate_sig_mod_(Design*des, NetScope*scope,
|
||||
Module*rmod) const
|
||||
{
|
||||
// Missing module instance names have already been rejected.
|
||||
assert(get_name() != "");
|
||||
|
||||
if (msb_) {
|
||||
cerr << get_line() << ": sorry: Module instantiation arrays "
|
||||
"are not yet supported." << endl;
|
||||
des->errors += 1;
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
// I know a priori that the elaborate_scope created the scope
|
||||
// already, so just look it up as a child of the current scope.
|
||||
NetScope*my_scope = scope->child(get_name());
|
||||
assert(my_scope);
|
||||
|
||||
return rmod->elaborate_sig(des, my_scope);
|
||||
}
|
||||
|
||||
|
||||
bool PGate::elaborate_sig(Design*des, NetScope*scope) const
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
* Elaborate a source wire. The "wire" is the declaration of wires,
|
||||
* registers, ports and memories. The parser has already merged the
|
||||
* multiple properties of a wire (i.e. "input wire") so come the
|
||||
* elaboration this creates an object in the design that represent the
|
||||
* defined item.
|
||||
*/
|
||||
void PWire::elaborate_sig(Design*des, NetScope*scope) const
|
||||
{
|
||||
/* The parser may produce hierarchical names for wires. I here
|
||||
follow the scopes down to the base where I actually want to
|
||||
elaborate the NetNet object. */
|
||||
string basename = name_;
|
||||
for (;;) {
|
||||
string p = parse_first_name(basename);
|
||||
if (basename == "") {
|
||||
basename = p;
|
||||
break;
|
||||
}
|
||||
|
||||
scope = scope->child(p);
|
||||
assert(scope);
|
||||
}
|
||||
|
||||
const string path = scope->name();
|
||||
NetNet::Type wtype = type_;
|
||||
if (wtype == NetNet::IMPLICIT)
|
||||
wtype = NetNet::WIRE;
|
||||
if (wtype == NetNet::IMPLICIT_REG)
|
||||
wtype = NetNet::REG;
|
||||
|
||||
unsigned wid = 1;
|
||||
long lsb = 0, msb = 0;
|
||||
|
||||
if (msb_.count()) {
|
||||
svector<long>mnum (msb_.count());
|
||||
svector<long>lnum (msb_.count());
|
||||
|
||||
/* There may be multiple declarations of ranges, because
|
||||
the symbol may have its range declared in i.e. input
|
||||
and reg declarations. Calculate *all* the numbers
|
||||
here. I will resolve the values later. */
|
||||
|
||||
for (unsigned idx = 0 ; idx < msb_.count() ; idx += 1) {
|
||||
verinum*mval = msb_[idx]->eval_const(des,path);
|
||||
if (mval == 0) {
|
||||
cerr << msb_[idx]->get_line() << ": error: "
|
||||
"Unable to evaluate constant expression ``" <<
|
||||
*msb_[idx] << "''." << endl;
|
||||
des->errors += 1;
|
||||
return;
|
||||
}
|
||||
verinum*lval = lsb_[idx]->eval_const(des, path);
|
||||
if (mval == 0) {
|
||||
cerr << lsb_[idx]->get_line() << ": error: "
|
||||
"Unable to evaluate constant expression ``" <<
|
||||
*lsb_[idx] << "''." << endl;
|
||||
des->errors += 1;
|
||||
return;
|
||||
}
|
||||
|
||||
mnum[idx] = mval->as_long();
|
||||
lnum[idx] = lval->as_long();
|
||||
delete mval;
|
||||
delete lval;
|
||||
}
|
||||
|
||||
/* Make sure all the values for msb and lsb match by
|
||||
value. If not, report an error. */
|
||||
for (unsigned idx = 1 ; idx < msb_.count() ; idx += 1) {
|
||||
if ((mnum[idx] != mnum[0]) || (lnum[idx] != lnum[0])) {
|
||||
cerr << get_line() << ": error: Inconsistent width, "
|
||||
"[" << mnum[idx] << ":" << lnum[idx] << "]"
|
||||
" vs. [" << mnum[0] << ":" << lnum[0] << "]"
|
||||
" for signal ``" << basename << "''" << endl;
|
||||
des->errors += 1;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
lsb = lnum[0];
|
||||
msb = mnum[0];
|
||||
if (mnum[0] > lnum[0])
|
||||
wid = mnum[0] - lnum[0] + 1;
|
||||
else
|
||||
wid = lnum[0] - mnum[0] + 1;
|
||||
|
||||
|
||||
}
|
||||
|
||||
if (lidx_ || ridx_) {
|
||||
assert(lidx_ && ridx_);
|
||||
|
||||
// If the register has indices, then this is a
|
||||
// memory. Create the memory object.
|
||||
verinum*lval = lidx_->eval_const(des, path);
|
||||
assert(lval);
|
||||
verinum*rval = ridx_->eval_const(des, path);
|
||||
assert(rval);
|
||||
|
||||
long lnum = lval->as_long();
|
||||
long rnum = rval->as_long();
|
||||
delete lval;
|
||||
delete rval;
|
||||
NetMemory*sig = new NetMemory(scope, path+"."+basename,
|
||||
wid, lnum, rnum);
|
||||
sig->set_attributes(attributes);
|
||||
|
||||
} else {
|
||||
|
||||
NetNet*sig = new NetNet(scope, path + "." +basename, wtype, msb, lsb);
|
||||
sig->set_line(*this);
|
||||
sig->port_type(port_type_);
|
||||
sig->set_attributes(attributes);
|
||||
|
||||
verinum::V iv = verinum::Vz;
|
||||
if (wtype == NetNet::REG)
|
||||
iv = verinum::Vx;
|
||||
|
||||
for (unsigned idx = 0 ; idx < wid ; idx += 1)
|
||||
sig->set_ival(idx, iv);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* $Log: elab_sig.cc,v $
|
||||
* Revision 1.1 2000/05/02 16:27:38 steve
|
||||
* Move signal elaboration to a seperate pass.
|
||||
*
|
||||
*/
|
||||
|
||||
+875
-596
File diff suppressed because it is too large
Load Diff
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 1998 Stephen Williams ([email protected])
|
||||
* Copyright (c) 1998-2000 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
|
||||
@@ -16,8 +16,8 @@
|
||||
* 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: emit.cc,v 1.31 1999/11/28 23:42:02 steve Exp $"
|
||||
#if !defined(WINNT) && !defined(macintosh)
|
||||
#ident "$Id: emit.cc,v 1.45 2000/05/11 23:37:27 steve Exp $"
|
||||
#endif
|
||||
|
||||
/*
|
||||
@@ -40,6 +40,11 @@ void NetLogic::emit_node(ostream&o, struct target_t*tgt) const
|
||||
tgt->logic(o, this);
|
||||
}
|
||||
|
||||
void NetUDP_COMB::emit_node(ostream&o, struct target_t*tgt) const
|
||||
{
|
||||
tgt->udp_comb(o, this);
|
||||
}
|
||||
|
||||
void NetUDP::emit_node(ostream&o, struct target_t*tgt) const
|
||||
{
|
||||
tgt->udp(o, this);
|
||||
@@ -65,6 +70,11 @@ void NetCaseCmp::emit_node(ostream&o, struct target_t*tgt) const
|
||||
tgt->net_case_cmp(o, this);
|
||||
}
|
||||
|
||||
void NetCAssign::emit_node(ostream&o, struct target_t*tgt) const
|
||||
{
|
||||
tgt->net_cassign(o, this);
|
||||
}
|
||||
|
||||
void NetCLShift::emit_node(ostream&o, struct target_t*tgt) const
|
||||
{
|
||||
tgt->lpm_clshift(o, this);
|
||||
@@ -80,11 +90,26 @@ void NetConst::emit_node(ostream&o, struct target_t*tgt) const
|
||||
tgt->net_const(o, this);
|
||||
}
|
||||
|
||||
void NetDivide::emit_node(ostream&o, struct target_t*tgt) const
|
||||
{
|
||||
tgt->lpm_divide(o, this);
|
||||
}
|
||||
|
||||
void NetFF::emit_node(ostream&o, struct target_t*tgt) const
|
||||
{
|
||||
tgt->lpm_ff(o, this);
|
||||
}
|
||||
|
||||
void NetForce::emit_node(ostream&o, struct target_t*tgt) const
|
||||
{
|
||||
tgt->net_force(o, this);
|
||||
}
|
||||
|
||||
void NetMult::emit_node(ostream&o, struct target_t*tgt) const
|
||||
{
|
||||
tgt->lpm_mult(o, this);
|
||||
}
|
||||
|
||||
void NetMux::emit_node(ostream&o, struct target_t*tgt) const
|
||||
{
|
||||
tgt->lpm_mux(o, this);
|
||||
@@ -95,11 +120,6 @@ 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);
|
||||
}
|
||||
|
||||
void NetBUFZ::emit_node(ostream&o, struct target_t*tgt) const
|
||||
{
|
||||
tgt->bufz(o, this);
|
||||
@@ -151,12 +171,27 @@ bool NetCase::emit_proc(ostream&o, struct target_t*tgt) const
|
||||
return true;
|
||||
}
|
||||
|
||||
bool NetCAssign::emit_proc(ostream&o, struct target_t*tgt) const
|
||||
{
|
||||
return tgt->proc_cassign(o, this);
|
||||
}
|
||||
|
||||
bool NetCondit::emit_proc(ostream&o, struct target_t*tgt) const
|
||||
{
|
||||
tgt->proc_condit(o, this);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool NetDeassign::emit_proc(ostream&o, struct target_t*tgt) const
|
||||
{
|
||||
return tgt->proc_deassign(o, this);
|
||||
}
|
||||
|
||||
bool NetForce::emit_proc(ostream&o, struct target_t*tgt) const
|
||||
{
|
||||
return tgt->proc_force(o, this);
|
||||
}
|
||||
|
||||
bool NetForever::emit_proc(ostream&o, struct target_t*tgt) const
|
||||
{
|
||||
tgt->proc_forever(o, this);
|
||||
@@ -174,15 +209,9 @@ void NetPDelay::emit_proc_recurse(ostream&o, struct target_t*tgt) const
|
||||
if (statement_) statement_->emit_proc(o, tgt);
|
||||
}
|
||||
|
||||
bool NetPEvent::emit_proc(ostream&o, struct target_t*tgt) const
|
||||
bool NetRelease::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
|
||||
{
|
||||
if (statement_) statement_->emit_proc(o, tgt);
|
||||
return tgt->proc_release(o, this);
|
||||
}
|
||||
|
||||
bool NetRepeat::emit_proc(ostream&o, struct target_t*tgt) const
|
||||
@@ -233,6 +262,27 @@ void NetCondit::emit_recurse_else(ostream&o, struct target_t*tgt) const
|
||||
else_->emit_proc(o, tgt);
|
||||
}
|
||||
|
||||
void NetEvProbe::emit_node(ostream&o, struct target_t*tgt) const
|
||||
{
|
||||
tgt->net_probe(o, this);
|
||||
}
|
||||
|
||||
bool NetEvTrig::emit_proc(ostream&o, struct target_t*tgt) const
|
||||
{
|
||||
return tgt->proc_trigger(o, this);
|
||||
}
|
||||
|
||||
bool NetEvWait::emit_proc(ostream&o, struct target_t*tgt) const
|
||||
{
|
||||
return tgt->proc_wait(o, this);
|
||||
}
|
||||
|
||||
bool NetEvWait::emit_recurse(ostream&o, struct target_t*tgt) const
|
||||
{
|
||||
if (!statement_) return true;
|
||||
return statement_->emit_proc(o, tgt);
|
||||
}
|
||||
|
||||
void NetForever::emit_recurse(ostream&o, struct target_t*tgt) const
|
||||
{
|
||||
if (statement_)
|
||||
@@ -245,6 +295,33 @@ void NetRepeat::emit_recurse(ostream&o, struct target_t*tgt) const
|
||||
statement_->emit_proc(o, tgt);
|
||||
}
|
||||
|
||||
void NetScope::emit_scope(ostream&o, struct target_t*tgt) const
|
||||
{
|
||||
tgt->scope(o, this);
|
||||
|
||||
for (NetEvent*cur = events_ ; cur ; cur = cur->snext_)
|
||||
tgt->event(o, cur);
|
||||
|
||||
for (NetScope*cur = sub_ ; cur ; cur = cur->sib_)
|
||||
cur->emit_scope(o, tgt);
|
||||
|
||||
if (signals_) {
|
||||
NetNet*cur = signals_->sig_next_;
|
||||
do {
|
||||
tgt->signal(o, cur);
|
||||
cur = cur->sig_next_;
|
||||
} while (cur != signals_->sig_next_);
|
||||
}
|
||||
|
||||
if (memories_) {
|
||||
NetMemory*cur = memories_->snext_;
|
||||
do {
|
||||
tgt->memory(o, cur);
|
||||
cur = cur->snext_;
|
||||
} while (cur != memories_->snext_);
|
||||
}
|
||||
}
|
||||
|
||||
void NetWhile::emit_proc_recurse(ostream&o, struct target_t*tgt) const
|
||||
{
|
||||
proc_->emit_proc(o, tgt);
|
||||
@@ -256,29 +333,7 @@ bool Design::emit(ostream&o, struct target_t*tgt) const
|
||||
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_;
|
||||
do {
|
||||
tgt->signal(o, cur);
|
||||
cur = cur->sig_next_;
|
||||
} while (cur != signals_->sig_next_);
|
||||
}
|
||||
|
||||
|
||||
// emit memories
|
||||
{
|
||||
map<string,NetMemory*>::const_iterator mi;
|
||||
for (mi = memories_.begin() ; mi != memories_.end() ; mi++) {
|
||||
tgt->memory(o, (*mi).second);
|
||||
}
|
||||
}
|
||||
root_scope_->emit_scope(o, tgt);
|
||||
|
||||
|
||||
// emit nodes
|
||||
@@ -351,6 +406,11 @@ void NetEScope::expr_scan(struct expr_scan_t*tgt) const
|
||||
tgt->expr_scope(this);
|
||||
}
|
||||
|
||||
void NetESFunc::expr_scan(struct expr_scan_t*tgt) const
|
||||
{
|
||||
tgt->expr_sfunc(this);
|
||||
}
|
||||
|
||||
void NetEUFunc::expr_scan(struct expr_scan_t*tgt) const
|
||||
{
|
||||
tgt->expr_ufunc(this);
|
||||
@@ -389,6 +449,63 @@ bool emit(ostream&o, const Design*des, const char*type)
|
||||
|
||||
/*
|
||||
* $Log: emit.cc,v $
|
||||
* Revision 1.45 2000/05/11 23:37:27 steve
|
||||
* Add support for procedural continuous assignment.
|
||||
*
|
||||
* Revision 1.44 2000/05/04 03:37:58 steve
|
||||
* Add infrastructure for system functions, move
|
||||
* $time to that structure and add $random.
|
||||
*
|
||||
* Revision 1.43 2000/05/02 03:13:31 steve
|
||||
* Move memories to the NetScope object.
|
||||
*
|
||||
* Revision 1.42 2000/05/02 00:58:12 steve
|
||||
* Move signal tables to the NetScope class.
|
||||
*
|
||||
* Revision 1.41 2000/04/23 03:45:24 steve
|
||||
* Add support for the procedural release statement.
|
||||
*
|
||||
* Revision 1.40 2000/04/22 04:20:19 steve
|
||||
* Add support for force assignment.
|
||||
*
|
||||
* Revision 1.39 2000/04/12 04:23:58 steve
|
||||
* Named events really should be expressed with PEIdent
|
||||
* objects in the pform,
|
||||
*
|
||||
* Handle named events within the mix of net events
|
||||
* and edges. As a unified lot they get caught together.
|
||||
* wait statements are broken into more complex statements
|
||||
* that include a conditional.
|
||||
*
|
||||
* Do not generate NetPEvent or NetNEvent objects in
|
||||
* elaboration. NetEvent, NetEvWait and NetEvProbe
|
||||
* take over those functions in the netlist.
|
||||
*
|
||||
* Revision 1.38 2000/04/10 05:26:06 steve
|
||||
* All events now use the NetEvent class.
|
||||
*
|
||||
* Revision 1.37 2000/04/04 03:20:15 steve
|
||||
* Simulate named event trigger and waits.
|
||||
*
|
||||
* Revision 1.36 2000/04/01 21:40:22 steve
|
||||
* Add support for integer division.
|
||||
*
|
||||
* Revision 1.35 2000/03/29 04:37:11 steve
|
||||
* New and improved combinational primitives.
|
||||
*
|
||||
* Revision 1.34 2000/03/08 04:36:53 steve
|
||||
* Redesign the implementation of scopes and parameters.
|
||||
* I now generate the scopes and notice the parameters
|
||||
* in a separate pass over the pform. Once the scopes
|
||||
* are generated, I can process overrides and evalutate
|
||||
* paremeters before elaboration begins.
|
||||
*
|
||||
* Revision 1.33 2000/02/23 02:56:54 steve
|
||||
* Macintosh compilers do not support ident.
|
||||
*
|
||||
* Revision 1.32 2000/01/13 03:35:35 steve
|
||||
* Multiplication all the way to simulation.
|
||||
*
|
||||
* 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.
|
||||
@@ -475,49 +592,5 @@ bool emit(ostream&o, const Design*des, const char*type)
|
||||
*
|
||||
* Revision 1.8 1999/04/25 00:44:10 steve
|
||||
* Core handles subsignal expressions.
|
||||
*
|
||||
* Revision 1.7 1999/04/19 01:59:36 steve
|
||||
* Add memories to the parse and elaboration phases.
|
||||
*
|
||||
* Revision 1.6 1999/02/08 02:49:56 steve
|
||||
* Turn the NetESignal into a NetNode so
|
||||
* that it can connect to the netlist.
|
||||
* Implement the case statement.
|
||||
* Convince t-vvm to output code for
|
||||
* the case statement.
|
||||
*
|
||||
* Revision 1.5 1999/02/01 00:26:49 steve
|
||||
* Carry some line info to the netlist,
|
||||
* Dump line numbers for processes.
|
||||
* Elaborate prints errors about port vector
|
||||
* width mismatch
|
||||
* Emit better handles null statements.
|
||||
*
|
||||
* Revision 1.4 1998/12/01 00:42:14 steve
|
||||
* Elaborate UDP devices,
|
||||
* Support UDP type attributes, and
|
||||
* pass those attributes to nodes that
|
||||
* are instantiated by elaboration,
|
||||
* Put modules into a map instead of
|
||||
* a simple list.
|
||||
*
|
||||
* Revision 1.3 1998/11/09 18:55:34 steve
|
||||
* Add procedural while loops,
|
||||
* Parse procedural for loops,
|
||||
* Add procedural wait statements,
|
||||
* Add constant nodes,
|
||||
* Add XNOR logic gate,
|
||||
* Make vvm output look a bit prettier.
|
||||
*
|
||||
* Revision 1.2 1998/11/07 17:05:05 steve
|
||||
* Handle procedural conditional, and some
|
||||
* of the conditional expressions.
|
||||
*
|
||||
* Elaborate signals and identifiers differently,
|
||||
* allowing the netlist to hold signal information.
|
||||
*
|
||||
* Revision 1.1 1998/11/03 23:28:57 steve
|
||||
* Introduce verilog to CVS.
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 1998 Stephen Williams ([email protected])
|
||||
* Copyright (c) 1998-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
|
||||
@@ -16,8 +16,8 @@
|
||||
* 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.cc,v 1.12 1999/11/30 04:48:17 steve Exp $"
|
||||
#if !defined(WINNT) && !defined(macintosh)
|
||||
#ident "$Id: eval.cc,v 1.14 2000/03/08 04:36:53 steve Exp $"
|
||||
#endif
|
||||
|
||||
# include "PExpr.h"
|
||||
@@ -96,7 +96,9 @@ verinum* PEBinary::eval_const(const Design*des, const string&path) const
|
||||
*/
|
||||
verinum* PEIdent::eval_const(const Design*des, const string&path) const
|
||||
{
|
||||
const NetExpr*expr = des->find_parameter(path, text_);
|
||||
const NetScope*scope = des->find_scope(path);
|
||||
assert(scope);
|
||||
const NetExpr*expr = des->find_parameter(scope, text_);
|
||||
|
||||
if (expr == 0)
|
||||
return 0;
|
||||
@@ -142,6 +144,16 @@ verinum* PETernary::eval_const(const Design*des, const string&path) const
|
||||
|
||||
/*
|
||||
* $Log: eval.cc,v $
|
||||
* Revision 1.14 2000/03/08 04:36:53 steve
|
||||
* Redesign the implementation of scopes and parameters.
|
||||
* I now generate the scopes and notice the parameters
|
||||
* in a separate pass over the pform. Once the scopes
|
||||
* are generated, I can process overrides and evalutate
|
||||
* paremeters before elaboration begins.
|
||||
*
|
||||
* Revision 1.13 2000/02/23 02:56:54 steve
|
||||
* Macintosh compilers do not support ident.
|
||||
*
|
||||
* Revision 1.12 1999/11/30 04:48:17 steve
|
||||
* Handle evaluation of ternary during elaboration.
|
||||
*
|
||||
|
||||
+34
-5
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 1999 Stephen Williams ([email protected])
|
||||
* Copyright (c) 1999-2000 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
|
||||
@@ -16,8 +16,8 @@
|
||||
* 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 $"
|
||||
#if !defined(WINNT) && !defined(macintosh)
|
||||
#ident "$Id: eval_tree.cc,v 1.10 2000/04/28 18:43:23 steve Exp $"
|
||||
#endif
|
||||
|
||||
# include "netlist.h"
|
||||
@@ -132,12 +132,24 @@ NetEConst* NetEBComp::eval_tree()
|
||||
}
|
||||
}
|
||||
|
||||
NetEConst* NetEBDiv::eval_tree()
|
||||
{
|
||||
eval_sub_tree_();
|
||||
return 0;
|
||||
}
|
||||
|
||||
NetEConst* NetEBLogic::eval_tree()
|
||||
{
|
||||
eval_sub_tree_();
|
||||
return 0;
|
||||
}
|
||||
|
||||
NetEConst* NetEBMult::eval_tree()
|
||||
{
|
||||
eval_sub_tree_();
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Evaluate the shift operator if possible. For this to work, both
|
||||
* operands must be constant.
|
||||
@@ -235,7 +247,8 @@ NetExpr* NetEParam::eval_tree()
|
||||
if (des_ == 0)
|
||||
return 0;
|
||||
|
||||
const NetExpr*expr = des_->find_parameter(path_, name_);
|
||||
assert(scope_);
|
||||
const NetExpr*expr = scope_->get_parameter(name_);
|
||||
assert(expr);
|
||||
|
||||
NetExpr*nexpr = expr->dup_expr();
|
||||
@@ -256,12 +269,28 @@ NetExpr* NetEParam::eval_tree()
|
||||
|
||||
// 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);
|
||||
scope_->set_parameter(name_, res);
|
||||
return res->dup_expr();
|
||||
}
|
||||
|
||||
/*
|
||||
* $Log: eval_tree.cc,v $
|
||||
* Revision 1.10 2000/04/28 18:43:23 steve
|
||||
* integer division in expressions properly get width.
|
||||
*
|
||||
* Revision 1.9 2000/03/08 04:36:53 steve
|
||||
* Redesign the implementation of scopes and parameters.
|
||||
* I now generate the scopes and notice the parameters
|
||||
* in a separate pass over the pform. Once the scopes
|
||||
* are generated, I can process overrides and evalutate
|
||||
* paremeters before elaboration begins.
|
||||
*
|
||||
* Revision 1.8 2000/02/23 02:56:54 steve
|
||||
* Macintosh compilers do not support ident.
|
||||
*
|
||||
* Revision 1.7 2000/01/13 03:35:35 steve
|
||||
* Multiplication all the way to simulation.
|
||||
*
|
||||
* Revision 1.6 1999/10/22 23:57:53 steve
|
||||
* do the <= in bits, not numbers.
|
||||
*
|
||||
|
||||
@@ -0,0 +1,47 @@
|
||||
/*
|
||||
* Copyright (c) 1998 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
|
||||
*/
|
||||
|
||||
/*
|
||||
* Here we have the canonical "Hello, World" program written in Verilog.
|
||||
* We simply print to the program output a simple message. This example
|
||||
* demonstrates the process of compiling and executing a program with
|
||||
* Icarus Verilog.
|
||||
*
|
||||
* Compile this program with the command:
|
||||
*
|
||||
* verilog hello.vl
|
||||
*
|
||||
* After churning for a little while, the program will create the output
|
||||
* file "hello" which is compiled, linked and ready to run. Run this
|
||||
* program like so:
|
||||
*
|
||||
* ./hello
|
||||
*
|
||||
* and the program will print the message to its output. Easy!
|
||||
*/
|
||||
|
||||
module main();
|
||||
|
||||
initial
|
||||
begin
|
||||
$display("Hello, World");
|
||||
$finish ;
|
||||
end
|
||||
|
||||
endmodule
|
||||
@@ -0,0 +1,76 @@
|
||||
/*
|
||||
* 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
|
||||
* 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
|
||||
*/
|
||||
|
||||
/*
|
||||
* IVL should generate an AND gate, and should make an OBUF and two
|
||||
* IBUF objects, along with the PAD objects.
|
||||
*
|
||||
* To compile this for XNF, try a command like this:
|
||||
*
|
||||
* verilog -X -fpart=XC4010XLPQ160 -fncf=outff.ncf outff.v
|
||||
*
|
||||
* That command causes an outff.xnf and outff.ncf file to be created.
|
||||
* Next, make the outff.ngd file with the command:
|
||||
*
|
||||
* xnf2ngd -l xilinxun -u outff.xnf outff.ngo
|
||||
* ngdbuild outff.ngo outff.ngd
|
||||
*
|
||||
* Finally, map the file to fully render it in the target part. The
|
||||
* par command is the step that actually optimizes the design and tries
|
||||
* to meet timing constraints.
|
||||
*
|
||||
* map -o map.ncd outff.ngd
|
||||
* par -w map.ncd outff.ncd
|
||||
*
|
||||
* At this point, you can use the FPGA Editor to edit the outff.ncd
|
||||
* file to see that the AND gate is in a CLB and the IOB for pin 150
|
||||
* has its flip-flop in use, and that gbuf is a global buffer.
|
||||
*/
|
||||
|
||||
module main;
|
||||
|
||||
wire clk, iclk;
|
||||
wire i0, i1;
|
||||
wire out;
|
||||
reg o0;
|
||||
|
||||
// This simple logic gate get turned into a function unit.
|
||||
// The par program will map this into a CLB F or G unit.
|
||||
and (out, i0, i1);
|
||||
|
||||
// This creates a global clock buffer. Notice how I attach an
|
||||
// attribute to the named gate to force it to be mapped to the
|
||||
// desired XNF device. This device will not be pulled into the
|
||||
// IOB associated with iclk because of the attribute.
|
||||
buf gbuf(clk, iclk);
|
||||
$attribute(gbuf, "XNF-LCA", "GCLK:O,I");
|
||||
|
||||
// This is mapped to a DFF. Since o0 is connected to a PAD, it
|
||||
// is turned into a OUTFF so that it get placed into an IOB.
|
||||
always @(posedge clk) o0 = out;
|
||||
|
||||
// These attribute commands assign pins to the listed wires.
|
||||
// This can be done to wires and registers, as internally both
|
||||
// are treated as named signals.
|
||||
$attribute(o0, "PAD", "o150");
|
||||
$attribute(i0, "PAD", "i152");
|
||||
$attribute(i1, "PAD", "i153");
|
||||
$attribute(iclk,"PAD", "i154");
|
||||
|
||||
endmodule /* main */
|
||||
@@ -0,0 +1,114 @@
|
||||
/*
|
||||
* 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
|
||||
*/
|
||||
|
||||
/*
|
||||
* This example program simulates a 16x1 ram, and is used as an
|
||||
* example for using VCD output and waveform viewers.
|
||||
*
|
||||
* Like any other Verilog simulation, compile this program with the
|
||||
* command:
|
||||
*
|
||||
* verilog show_vcd.vl
|
||||
*
|
||||
* This will generate the show_vcd command in the current directory.
|
||||
* When you run the command, you will see the output from all the
|
||||
* calls to $display, but also there will be a dump file ``show_vcd.vcd''.
|
||||
* The name of this file is set by the statement:
|
||||
*
|
||||
* $dumpfile("show_vcd.vcd");
|
||||
*
|
||||
* in the main module. The output file uses the standard VCD file format
|
||||
* so can be viewed using off-the-shelf waveform viewers. The remaining
|
||||
* steps describe how to use GTKWave to view the file. If you are using
|
||||
* a different viewer, see the documentation for that tool.
|
||||
*
|
||||
* To view the output generated by running show_vcd, start the GTKWave
|
||||
* viewer with the command:
|
||||
*
|
||||
* wave show_vcd.vcd
|
||||
*
|
||||
* The GTKWave program will display its main window, and show in a small
|
||||
* status box (upper left corner) that it succeeded in loading the dump
|
||||
* file. However, there are no waveforms displayed yet. Select signals to
|
||||
* add to the waveform display using the menu selection:
|
||||
*
|
||||
* "Search --> Signal Search Tree"
|
||||
*
|
||||
* This will bring up a dialog box that shows in directory tree format
|
||||
* the signals of the program. Select the signals you wish to view, and
|
||||
* click one of the buttons on the bottom of the dialog box to display
|
||||
* the selected signals in the waveform window. Click "Exit" on the box
|
||||
* to get rid of it.
|
||||
*
|
||||
* The magic that makes all this work is contained in the $dumpfile and
|
||||
* $dumpvars system tasks. The $dumpfile task tells the simulation where
|
||||
* to write the VCD output. This task must be called once before the
|
||||
* $dumpvars task is called.
|
||||
*
|
||||
* The $dumpvars task tells the simulation what variables to write to
|
||||
* the VCD output. The first parameter is how far to descend while
|
||||
* scanning a scope, and the remaining paramters are signals or scope
|
||||
* names to include in the dump. If a scope name is given, all the
|
||||
* signals within the scope are dumped. If a wire or register name is
|
||||
* given, that signal is included.
|
||||
*/
|
||||
|
||||
module ram16x1 (q, d, a, we, wclk);
|
||||
output q;
|
||||
input d;
|
||||
input [3:0] a;
|
||||
input we;
|
||||
input wclk;
|
||||
|
||||
reg mem[15:0];
|
||||
|
||||
assign q = mem[a];
|
||||
always @(posedge wclk) if (we) mem[a] = d;
|
||||
|
||||
endmodule /* ram16x1 */
|
||||
|
||||
module main;
|
||||
wire q;
|
||||
reg d;
|
||||
reg [3:0] a;
|
||||
reg we, wclk;
|
||||
|
||||
ram16x1 r1 (q, d, a, we, wclk);
|
||||
|
||||
initial begin
|
||||
$dumpfile("show_vcd.vcd");
|
||||
$dumpvars(1, main.r1);
|
||||
wclk = 0;
|
||||
we = 1;
|
||||
for (a = 0 ; a < 4'hf ; a = a + 1) begin
|
||||
d = a[0];
|
||||
#1 wclk = 1;
|
||||
#1 wclk = 0;
|
||||
$display("r1[%x] == %b", a, q);
|
||||
end
|
||||
|
||||
for (a = 0 ; a < 4'hf ; a = a + 1)
|
||||
#1 if (q !== a[0]) begin
|
||||
$display("FAILED -- mem[%h] !== %b", a, a[0]);
|
||||
$finish;
|
||||
end
|
||||
|
||||
$display("PASSED");
|
||||
end
|
||||
endmodule /* main */
|
||||
@@ -0,0 +1,127 @@
|
||||
/*
|
||||
* 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
|
||||
*
|
||||
* $Id: sqrt.vl,v 1.1 1999/12/05 21:08:56 steve Exp $"
|
||||
*/
|
||||
|
||||
/*
|
||||
* This module approximates the square root of an unsigned 32bit
|
||||
* number. The algorithm works by doing a bit-wise binary search.
|
||||
* Starting from the most significant bit, the accumulated value
|
||||
* tries to put a 1 in the bit position. If that makes the square
|
||||
* to big for the input, the bit is left zero, otherwise it is set
|
||||
* in the result. This continues for each bit, decreasing in
|
||||
* significance, until all the bits are calculated or all the
|
||||
* remaining bits are zero.
|
||||
*
|
||||
* Since the result is an integer, this function really calculates
|
||||
* value of the expression:
|
||||
*
|
||||
* x = floor(sqrt(y))
|
||||
*
|
||||
* where sqrt(y) is the exact square root of y and floor(N) is the
|
||||
* largest integer <= N.
|
||||
*
|
||||
* For 32bit numbers, this will never run more then 16 iterations,
|
||||
* which amounts to 16 clocks.
|
||||
*/
|
||||
|
||||
module sqrt32(clk, rdy, reset, x, .y(acc));
|
||||
input clk;
|
||||
output rdy;
|
||||
input reset;
|
||||
|
||||
input [31:0] x;
|
||||
output [15:0] acc;
|
||||
|
||||
|
||||
// acc holds the accumulated result, and acc2 is the accumulated
|
||||
// square of the accumulated result.
|
||||
reg [15:0] acc;
|
||||
reg [31:0] acc2;
|
||||
|
||||
// Keep track of which bit I'm working on.
|
||||
reg [4:0] bitl;
|
||||
wire [15:0] bit = 1 << bitl;
|
||||
wire [31:0] bit2 = 1 << (bitl << 1);
|
||||
|
||||
// The output is ready when the bitl counter underflows.
|
||||
wire rdy = bitl[4];
|
||||
|
||||
// guess holds the potential next values for acc, and guess2 holds
|
||||
// the square of that guess. The guess2 calculation is a little bit
|
||||
// subtle. The idea is that:
|
||||
//
|
||||
// guess2 = (acc + bit) * (acc + bit)
|
||||
// = (acc * acc) + 2*acc*bit + bit*bit
|
||||
// = acc2 + 2*acc*bit + bit2
|
||||
// = acc2 + 2 * (acc<<bitl) + bit
|
||||
//
|
||||
// This works out using shifts because bit and bit2 are known to
|
||||
// have only a single bit in them.
|
||||
wire [15:0] guess = acc | bit;
|
||||
wire [31:0] guess2 = acc2 + bit2 + ((acc << bitl) << 1);
|
||||
|
||||
task clear;
|
||||
begin
|
||||
acc = 0;
|
||||
acc2 = 0;
|
||||
bitl = 15;
|
||||
end
|
||||
endtask
|
||||
|
||||
initial clear;
|
||||
|
||||
always @(reset or posedge clk)
|
||||
if (reset)
|
||||
clear;
|
||||
else begin
|
||||
if (guess2 <= x) begin
|
||||
acc <= guess;
|
||||
acc2 <= guess2;
|
||||
end
|
||||
bitl <= bitl - 1;
|
||||
end
|
||||
|
||||
endmodule
|
||||
|
||||
module main;
|
||||
|
||||
reg clk, reset;
|
||||
reg [31:0] value;
|
||||
wire [15:0] result;
|
||||
wire rdy;
|
||||
|
||||
sqrt32 root(.clk(clk), .rdy(rdy), .reset(reset), .x(value), .y(result));
|
||||
|
||||
always #5 clk = ~clk;
|
||||
|
||||
always @(posedge rdy) begin
|
||||
$display("sqrt(%d) --> %d", value, result);
|
||||
$finish;
|
||||
end
|
||||
|
||||
|
||||
initial begin
|
||||
clk = 0;
|
||||
reset = 1;
|
||||
$monitor($time,,"%m = %b", root.acc, root.acc);
|
||||
#100 value = 63;
|
||||
reset = 0;
|
||||
end
|
||||
endmodule /* main */
|
||||
@@ -0,0 +1,102 @@
|
||||
/*
|
||||
* 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
|
||||
*/
|
||||
|
||||
/*
|
||||
* This example demonstrates Icarus Verilog's ability to synthesize
|
||||
* efficient adders for Xilinx 4000 series FPGAs. The synthesis and
|
||||
* code generation makes an adder and translates that into XOR gates
|
||||
* and fast carry chain hardware.
|
||||
*
|
||||
* To compile this for XNF, try a command like this:
|
||||
*
|
||||
* verilog -X -fpart=XC4010XLPQ160 -fncf=xnf_add.ncf xnf_add.v
|
||||
*
|
||||
* That command causes an xnf_add.xnf and xnf_add.ncf file to be created.
|
||||
* Next, make the xnf_add.ngd file with the command:
|
||||
*
|
||||
* xnf2ngd -l xilinxun -u xnf_add.xnf xnf_add.ngo
|
||||
* ngdbuild xnf_add.ngo xnf_add.ngd
|
||||
*
|
||||
* Finally, map the file to fully render it in the target part. The
|
||||
* par command is the step that actually optimizes the design and tries
|
||||
* to meet timing constraints.
|
||||
*
|
||||
* map -o map.ncd xnf_add.ngd
|
||||
* par -w map.ncd xnf_add.ncd
|
||||
*
|
||||
* At this point, you can use the FPGA Editor to edit the xnf_add.ncd
|
||||
* file to see the carry chains made up to support the adder.
|
||||
*/
|
||||
|
||||
module main;
|
||||
|
||||
wire [3:0] a, b;
|
||||
wire [3:0] out;
|
||||
wire carry;
|
||||
|
||||
wire a0, a1, a2, a3, b0, b1, b2, b3;
|
||||
wire out0, out1, out2, out3;
|
||||
|
||||
// This creates the actual adder. Note that we also create a link
|
||||
// to the carry output. The principle adder is 4 bits wide, so two
|
||||
// IOBs are used to to the actual addition. PAR will place them in
|
||||
// order along carry lines. An extra carry cell from below a[0] is
|
||||
// used in FORCE-0 mode to load the bottom carry node.
|
||||
//
|
||||
// The carry signal from the top CY device is used to drive the
|
||||
// main.carry wire shown here. It is managed in this case by using
|
||||
// an ADD-FG-CI CY device for the top pair and using the CLB above
|
||||
// the carry chain, with its CY in EXAMINE-CI mode, to put the carry
|
||||
// out through its G function unit.
|
||||
|
||||
assign {carry, out} = a + b;
|
||||
|
||||
|
||||
// These attribute commands assign pins to the listed wires.
|
||||
// This can be done to wires and registers, as internally both
|
||||
// are treated as named signals. It doesn't work (yet) on vectors,
|
||||
// though, so break out the vectors with scaler assignments.
|
||||
|
||||
assign a[0] = a0;
|
||||
assign a[1] = a1;
|
||||
assign a[2] = a2;
|
||||
assign a[3] = a3;
|
||||
$attribute(a0, "PAD", "i150");
|
||||
$attribute(a1, "PAD", "i152");
|
||||
$attribute(a2, "PAD", "i153");
|
||||
$attribute(a3, "PAD", "i154");
|
||||
assign b[0] = b0;
|
||||
assign b[1] = b1;
|
||||
assign b[2] = b2;
|
||||
assign b[3] = b3;
|
||||
$attribute(b0, "PAD", "i155");
|
||||
$attribute(b1, "PAD", "i156");
|
||||
$attribute(b2, "PAD", "i157");
|
||||
$attribute(b3, "PAD", "i158");
|
||||
assign out0 = out[0];
|
||||
assign out1 = out[1];
|
||||
assign out2 = out[2];
|
||||
assign out3 = out[3];
|
||||
$attribute(out0, "PAD", "o71");
|
||||
$attribute(out1, "PAD", "o72");
|
||||
$attribute(out2, "PAD", "o73");
|
||||
$attribute(out3, "PAD", "o74");
|
||||
$attribute(carry, "PAD", "o75");
|
||||
|
||||
endmodule /* main */
|
||||
+166
-19
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 1999 Stephen Williams (steve@icarus.com)
|
||||
* Copyright (c) 1999-2000 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
|
||||
@@ -16,8 +16,8 @@
|
||||
* 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 $"
|
||||
#if !defined(WINNT) && !defined(macintosh)
|
||||
#ident "$Id: expr_synth.cc,v 1.14 2000/05/02 00:58:12 steve Exp $"
|
||||
#endif
|
||||
|
||||
# include "netlist.h"
|
||||
@@ -45,7 +45,7 @@ NetNet* NetEBAdd::synthesize(Design*des)
|
||||
assert(lsig->pin_count() == rsig->pin_count());
|
||||
unsigned width=lsig->pin_count();
|
||||
|
||||
NetNet*osig = new NetNet(0, path, NetNet::IMPLICIT, width);
|
||||
NetNet*osig = new NetNet(lsig->scope(), path, NetNet::IMPLICIT, width);
|
||||
|
||||
string oname = des->local_symbol(path);
|
||||
NetAddSub *adder = new NetAddSub(oname, width);
|
||||
@@ -55,7 +55,6 @@ NetNet* NetEBAdd::synthesize(Design*des)
|
||||
connect(osig->pin(idx), adder->pin_Result(idx));
|
||||
}
|
||||
des->add_node(adder);
|
||||
des->add_signal(osig);
|
||||
|
||||
switch (op()) {
|
||||
case '+':
|
||||
@@ -82,7 +81,9 @@ NetNet* NetEBBits::synthesize(Design*des)
|
||||
NetNet*rsig = right_->synthesize(des);
|
||||
|
||||
assert(lsig->pin_count() == rsig->pin_count());
|
||||
NetNet*osig = new NetNet(0, path, NetNet::IMPLICIT, lsig->pin_count());
|
||||
NetNet*osig = new NetNet(lsig->scope(), path, NetNet::IMPLICIT,
|
||||
lsig->pin_count());
|
||||
osig->local_flag(true);
|
||||
|
||||
for (unsigned idx = 0 ; idx < osig->pin_count() ; idx += 1) {
|
||||
string oname = des->local_symbol(path);
|
||||
@@ -115,23 +116,139 @@ NetNet* NetEBBits::synthesize(Design*des)
|
||||
des->add_node(gate);
|
||||
}
|
||||
|
||||
des->add_signal(osig);
|
||||
return osig;
|
||||
}
|
||||
|
||||
NetNet* NetEBComp::synthesize(Design*des)
|
||||
{
|
||||
string path = des->local_symbol("SYNTH");
|
||||
NetNet*lsig = left_->synthesize(des);
|
||||
NetNet*rsig = right_->synthesize(des);
|
||||
|
||||
unsigned width = lsig->pin_count();
|
||||
if (rsig->pin_count() > lsig->pin_count())
|
||||
width = rsig->pin_count();
|
||||
|
||||
NetNet*osig = new NetNet(lsig->scope(), path, NetNet::IMPLICIT, 1);
|
||||
osig->local_flag(true);
|
||||
|
||||
/* Handle the special case of a single bit equality
|
||||
operation. Make an XNOR gate instead of a comparator. */
|
||||
if ((width == 1) && ((op_ == 'e') || (op_ == 'E'))) {
|
||||
NetLogic*gate = new NetLogic(des->local_symbol(path),
|
||||
3, NetLogic::XNOR);
|
||||
connect(gate->pin(0), osig->pin(0));
|
||||
connect(gate->pin(1), lsig->pin(0));
|
||||
connect(gate->pin(2), rsig->pin(0));
|
||||
des->add_node(gate);
|
||||
return osig;
|
||||
}
|
||||
|
||||
/* Handle the special case of a single bit inequality
|
||||
operation. This is similar to single bit equality, but uses
|
||||
an XOR instead of an XNOR gate. */
|
||||
if ((width == 1) && ((op_ == 'n') || (op_ == 'N'))) {
|
||||
NetLogic*gate = new NetLogic(des->local_symbol(path),
|
||||
3, NetLogic::XOR);
|
||||
connect(gate->pin(0), osig->pin(0));
|
||||
connect(gate->pin(1), lsig->pin(0));
|
||||
connect(gate->pin(2), rsig->pin(0));
|
||||
des->add_node(gate);
|
||||
return osig;
|
||||
}
|
||||
|
||||
|
||||
NetCompare*dev = new NetCompare(des->local_symbol(path), width);
|
||||
des->add_node(dev);
|
||||
|
||||
for (unsigned idx = 0 ; idx < lsig->pin_count() ; idx += 1)
|
||||
connect(dev->pin_DataA(idx), lsig->pin(idx));
|
||||
|
||||
for (unsigned idx = 0 ; idx < rsig->pin_count() ; idx += 1)
|
||||
connect(dev->pin_DataB(idx), rsig->pin(idx));
|
||||
|
||||
|
||||
switch (op_) {
|
||||
case '<':
|
||||
connect(dev->pin_ALB(), osig->pin(0));
|
||||
break;
|
||||
case '>':
|
||||
connect(dev->pin_AGB(), osig->pin(0));
|
||||
break;
|
||||
case 'e': // ==
|
||||
case 'E': // === ?
|
||||
connect(dev->pin_AEB(), osig->pin(0));
|
||||
break;
|
||||
case 'G': // >=
|
||||
connect(dev->pin_AGEB(), osig->pin(0));
|
||||
break;
|
||||
case 'L': // <=
|
||||
connect(dev->pin_ALEB(), osig->pin(0));
|
||||
break;
|
||||
case 'n': // !=
|
||||
case 'N': // !==
|
||||
connect(dev->pin_ANEB(), osig->pin(0));
|
||||
break;
|
||||
|
||||
default:
|
||||
cerr << get_line() << ": internal error: cannot synthesize "
|
||||
"comparison: " << *this << endl;
|
||||
des->errors += 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
return osig;
|
||||
}
|
||||
|
||||
NetNet* NetEBDiv::synthesize(Design*des)
|
||||
{
|
||||
cerr << get_line() << ": internal error: cannot synthesize division: "
|
||||
<< *this << endl;
|
||||
des->errors += 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
NetNet* NetEConcat::synthesize(Design*des)
|
||||
{
|
||||
NetScope*scope = des->find_root_scope();
|
||||
assert(scope);
|
||||
assert(repeat_ == 1);
|
||||
|
||||
string path = des->local_symbol("SYNTH");
|
||||
NetNet*osig = new NetNet(scope, path, NetNet::IMPLICIT, expr_width());
|
||||
osig->local_flag(true);
|
||||
|
||||
unsigned obit = 0;
|
||||
for (unsigned idx = parms_.count() ; idx > 0 ; idx -= 1) {
|
||||
NetNet*tmp = parms_[idx-1]->synthesize(des);
|
||||
|
||||
for (unsigned bit = 0 ; bit < tmp->pin_count() ; bit += 1) {
|
||||
connect(osig->pin(obit), tmp->pin(bit));
|
||||
obit += 1;
|
||||
}
|
||||
|
||||
if (tmp->local_flag())
|
||||
delete tmp;
|
||||
}
|
||||
|
||||
return osig;
|
||||
}
|
||||
|
||||
NetNet* NetEConst::synthesize(Design*des)
|
||||
{
|
||||
NetScope*scope = des->find_root_scope();
|
||||
assert(scope);
|
||||
|
||||
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);
|
||||
NetNet*osig = new NetNet(scope, path, NetNet::IMPLICIT, width);
|
||||
osig->local_flag(true);
|
||||
NetConst*con = new NetConst(des->local_symbol(path), value());
|
||||
for (unsigned idx = 0 ; idx < width; idx += 1)
|
||||
connect(osig->pin(idx), con->pin(idx));
|
||||
|
||||
des->add_node(con);
|
||||
return osig;
|
||||
}
|
||||
|
||||
@@ -144,7 +261,9 @@ 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());
|
||||
NetNet*osig = new NetNet(isig->scope(), path, NetNet::IMPLICIT,
|
||||
isig->pin_count());
|
||||
osig->local_flag(true);
|
||||
|
||||
for (unsigned idx = 0 ; idx < osig->pin_count() ; idx += 1) {
|
||||
string oname = des->local_symbol(path);
|
||||
@@ -163,7 +282,7 @@ NetNet* NetEUBits::synthesize(Design*des)
|
||||
|
||||
des->add_node(gate);
|
||||
}
|
||||
des->add_signal(osig);
|
||||
|
||||
return osig;
|
||||
}
|
||||
|
||||
@@ -178,7 +297,8 @@ NetNet* NetETernary::synthesize(Design *des)
|
||||
assert(csig->pin_count() == 1);
|
||||
assert(tsig->pin_count() == fsig->pin_count());
|
||||
unsigned width=tsig->pin_count();
|
||||
NetNet*osig = new NetNet(0, path, NetNet::IMPLICIT, width);
|
||||
NetNet*osig = new NetNet(csig->scope(), path, NetNet::IMPLICIT, width);
|
||||
osig->local_flag(true);
|
||||
|
||||
string oname = des->local_symbol(path);
|
||||
NetMux *mux = new NetMux(oname, width, 2, 1);
|
||||
@@ -189,7 +309,7 @@ NetNet* NetETernary::synthesize(Design *des)
|
||||
}
|
||||
des->add_node(mux);
|
||||
connect(csig->pin(0), mux->pin_Sel(0));
|
||||
des->add_signal(osig);
|
||||
|
||||
return osig;
|
||||
}
|
||||
|
||||
@@ -200,6 +320,33 @@ NetNet* NetESignal::synthesize(Design*des)
|
||||
|
||||
/*
|
||||
* $Log: expr_synth.cc,v $
|
||||
* Revision 1.14 2000/05/02 00:58:12 steve
|
||||
* Move signal tables to the NetScope class.
|
||||
*
|
||||
* Revision 1.13 2000/04/28 18:43:23 steve
|
||||
* integer division in expressions properly get width.
|
||||
*
|
||||
* Revision 1.12 2000/04/20 00:28:03 steve
|
||||
* Catch some simple identity compareoptimizations.
|
||||
*
|
||||
* Revision 1.11 2000/04/16 23:32:18 steve
|
||||
* Synthesis of comparator in expressions.
|
||||
*
|
||||
* Connect the NetEvent and related classes
|
||||
* together better.
|
||||
*
|
||||
* Revision 1.10 2000/02/23 02:56:54 steve
|
||||
* Macintosh compilers do not support ident.
|
||||
*
|
||||
* Revision 1.9 2000/01/01 06:18:00 steve
|
||||
* Handle synthesis of concatenation.
|
||||
*
|
||||
* Revision 1.8 1999/12/17 06:18:15 steve
|
||||
* Rewrite the cprop functor to use the functor_t interface.
|
||||
*
|
||||
* Revision 1.7 1999/12/17 03:38:46 steve
|
||||
* NetConst can now hold wide constants.
|
||||
*
|
||||
* 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.
|
||||
|
||||
+153
-12
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 1999 Stephen Williams (steve@icarus.com)
|
||||
* Copyright (c) 1999-2000 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
|
||||
@@ -16,8 +16,8 @@
|
||||
* 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: functor.cc,v 1.5 1999/12/01 06:06:16 steve Exp $"
|
||||
#if !defined(WINNT) && !defined(macintosh)
|
||||
#ident "$Id: functor.cc,v 1.18 2000/05/02 00:58:12 steve Exp $"
|
||||
#endif
|
||||
|
||||
# include "functor.h"
|
||||
@@ -27,6 +27,10 @@ functor_t::~functor_t()
|
||||
{
|
||||
}
|
||||
|
||||
void functor_t::event(class Design*, class NetEvent*)
|
||||
{
|
||||
}
|
||||
|
||||
void functor_t::signal(class Design*, class NetNet*)
|
||||
{
|
||||
}
|
||||
@@ -35,21 +39,61 @@ void functor_t::process(class Design*, class NetProcTop*)
|
||||
{
|
||||
}
|
||||
|
||||
void functor_t::lpm_add_sub(class Design*, class NetAddSub*)
|
||||
{
|
||||
}
|
||||
|
||||
void functor_t::lpm_compare(class Design*, class NetCompare*)
|
||||
{
|
||||
}
|
||||
|
||||
void functor_t::lpm_const(class Design*, class NetConst*)
|
||||
{
|
||||
}
|
||||
|
||||
void functor_t::lpm_divide(class Design*, class NetDivide*)
|
||||
{
|
||||
}
|
||||
|
||||
void functor_t::lpm_ff(class Design*, class NetFF*)
|
||||
{
|
||||
}
|
||||
|
||||
void Design::functor(functor_t*fun)
|
||||
void functor_t::lpm_logic(class Design*, class NetLogic*)
|
||||
{
|
||||
}
|
||||
|
||||
void functor_t::lpm_mult(class Design*, class NetMult*)
|
||||
{
|
||||
}
|
||||
|
||||
void NetScope::run_functor(Design*des, functor_t*fun)
|
||||
{
|
||||
for (NetScope*cur = sub_ ; cur ; cur = cur->sib_) {
|
||||
cur->run_functor(des, fun);
|
||||
}
|
||||
|
||||
for (NetEvent*cur = events_ ; cur ; /* */) {
|
||||
NetEvent*tmp = cur;
|
||||
cur = cur->snext_;
|
||||
fun->event(des, tmp);
|
||||
}
|
||||
|
||||
// apply to signals
|
||||
if (signals_) {
|
||||
NetNet*cur = signals_->sig_next_;
|
||||
do {
|
||||
NetNet*tmp = cur->sig_next_;
|
||||
fun->signal(this, cur);
|
||||
fun->signal(des, cur);
|
||||
cur = tmp;
|
||||
} while (cur != signals_->sig_next_);
|
||||
}
|
||||
}
|
||||
|
||||
void Design::functor(functor_t*fun)
|
||||
{
|
||||
// Scan the scopes
|
||||
root_scope_->run_functor(this, fun);
|
||||
|
||||
// apply to processes
|
||||
procs_idx_ = procs_;
|
||||
@@ -66,7 +110,7 @@ void Design::functor(functor_t*fun)
|
||||
NetNode*tmp = cur->node_next_;
|
||||
cur->functor_node(this, fun);
|
||||
cur = tmp;
|
||||
} while (cur != nodes_->node_next_);
|
||||
} while (nodes_ && cur != nodes_->node_next_);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -75,11 +119,41 @@ void NetNode::functor_node(Design*, functor_t*)
|
||||
{
|
||||
}
|
||||
|
||||
void NetAddSub::functor_node(Design*des, functor_t*fun)
|
||||
{
|
||||
fun->lpm_add_sub(des, this);
|
||||
}
|
||||
|
||||
void NetCompare::functor_node(Design*des, functor_t*fun)
|
||||
{
|
||||
fun->lpm_compare(des, this);
|
||||
}
|
||||
|
||||
void NetConst::functor_node(Design*des, functor_t*fun)
|
||||
{
|
||||
fun->lpm_const(des, this);
|
||||
}
|
||||
|
||||
void NetDivide::functor_node(Design*des, functor_t*fun)
|
||||
{
|
||||
fun->lpm_divide(des, this);
|
||||
}
|
||||
|
||||
void NetFF::functor_node(Design*des, functor_t*fun)
|
||||
{
|
||||
fun->lpm_ff(des, this);
|
||||
}
|
||||
|
||||
void NetLogic::functor_node(Design*des, functor_t*fun)
|
||||
{
|
||||
fun->lpm_logic(des, this);
|
||||
}
|
||||
|
||||
void NetMult::functor_node(Design*des, functor_t*fun)
|
||||
{
|
||||
fun->lpm_mult(des, this);
|
||||
}
|
||||
|
||||
proc_match_t::~proc_match_t()
|
||||
{
|
||||
}
|
||||
@@ -99,6 +173,28 @@ int NetAssign::match_proc(proc_match_t*that)
|
||||
return that->assign(this);
|
||||
}
|
||||
|
||||
int proc_match_t::assign_mem(NetAssignMem*)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
int NetAssignMem::match_proc(proc_match_t*that)
|
||||
{
|
||||
return that->assign_mem(this);
|
||||
}
|
||||
|
||||
int proc_match_t::block(NetBlock*)
|
||||
{
|
||||
cerr << "default (failing) match for block" << endl;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int NetBlock::match_proc(proc_match_t*that)
|
||||
{
|
||||
cerr << "NetBlock::match_proc" << endl;
|
||||
return that->block(this);
|
||||
}
|
||||
|
||||
int proc_match_t::condit(NetCondit*)
|
||||
{
|
||||
return 0;
|
||||
@@ -109,18 +205,63 @@ int NetCondit::match_proc(proc_match_t*that)
|
||||
return that->condit(this);
|
||||
}
|
||||
|
||||
int proc_match_t::pevent(NetPEvent*)
|
||||
int NetEvWait::match_proc(proc_match_t*that)
|
||||
{
|
||||
return that->event_wait(this);
|
||||
}
|
||||
|
||||
int proc_match_t::event_wait(NetEvWait*)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
int NetPEvent::match_proc(proc_match_t*that)
|
||||
{
|
||||
return that->pevent(this);
|
||||
}
|
||||
|
||||
/*
|
||||
* $Log: functor.cc,v $
|
||||
* Revision 1.18 2000/05/02 00:58:12 steve
|
||||
* Move signal tables to the NetScope class.
|
||||
*
|
||||
* Revision 1.17 2000/04/20 00:28:03 steve
|
||||
* Catch some simple identity compareoptimizations.
|
||||
*
|
||||
* Revision 1.16 2000/04/18 04:50:19 steve
|
||||
* Clean up unneeded NetEvent objects.
|
||||
*
|
||||
* Revision 1.15 2000/04/16 23:32:18 steve
|
||||
* Synthesis of comparator in expressions.
|
||||
*
|
||||
* Connect the NetEvent and related classes
|
||||
* together better.
|
||||
*
|
||||
* Revision 1.14 2000/04/12 20:02:53 steve
|
||||
* Finally remove the NetNEvent and NetPEvent classes,
|
||||
* Get synthesis working with the NetEvWait class,
|
||||
* and get started supporting multiple events in a
|
||||
* wait in vvm.
|
||||
*
|
||||
* Revision 1.13 2000/04/01 21:40:22 steve
|
||||
* Add support for integer division.
|
||||
*
|
||||
* Revision 1.12 2000/02/23 02:56:54 steve
|
||||
* Macintosh compilers do not support ident.
|
||||
*
|
||||
* Revision 1.11 2000/02/13 04:35:43 steve
|
||||
* Include some block matching from Larry.
|
||||
*
|
||||
* Revision 1.10 2000/01/13 03:35:35 steve
|
||||
* Multiplication all the way to simulation.
|
||||
*
|
||||
* Revision 1.9 2000/01/02 17:57:20 steve
|
||||
* Handle nodes running out during node scan.
|
||||
*
|
||||
* Revision 1.8 1999/12/30 04:19:12 steve
|
||||
* Propogate constant 0 in low bits of adders.
|
||||
*
|
||||
* Revision 1.7 1999/12/17 06:18:16 steve
|
||||
* Rewrite the cprop functor to use the functor_t interface.
|
||||
*
|
||||
* Revision 1.6 1999/12/05 02:24:08 steve
|
||||
* Synthesize LPM_RAM_DQ for writes into memories.
|
||||
*
|
||||
* Revision 1.5 1999/12/01 06:06:16 steve
|
||||
* Redo synth to use match_proc_t scanner.
|
||||
*
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
#ifndef __functor_H
|
||||
#define __functor_H
|
||||
/*
|
||||
* Copyright (c) 1999 Stephen Williams (steve@icarus.com)
|
||||
* Copyright (c) 1999-2000 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
|
||||
@@ -18,8 +18,8 @@
|
||||
* 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: functor.h,v 1.3 1999/12/01 06:06:16 steve Exp $"
|
||||
#if !defined(WINNT) && !defined(macintosh)
|
||||
#ident "$Id: functor.h,v 1.13 2000/04/20 00:28:03 steve Exp $"
|
||||
#endif
|
||||
|
||||
/*
|
||||
@@ -35,38 +35,78 @@ class NetProcTop;
|
||||
struct functor_t {
|
||||
virtual ~functor_t();
|
||||
|
||||
/* Signals are scanned first. This is called once for each
|
||||
signal in the design. */
|
||||
/* Events are scanned here. */
|
||||
virtual void event(class Design*des, class NetEvent*);
|
||||
|
||||
/* This is called once for each signal in the design. */
|
||||
virtual void signal(class Design*des, class NetNet*);
|
||||
|
||||
/* This method is called for each process in the design. */
|
||||
virtual void process(class Design*des, class NetProcTop*);
|
||||
|
||||
/* This method is called for each structural adder. */
|
||||
virtual void lpm_add_sub(class Design*des, class NetAddSub*);
|
||||
|
||||
/* This method is called for each structural comparator. */
|
||||
virtual void lpm_compare(class Design*des, class NetCompare*);
|
||||
|
||||
/* This method is called for each structural constant. */
|
||||
virtual void lpm_const(class Design*des, class NetConst*);
|
||||
|
||||
/* This method is called for each structural constant. */
|
||||
virtual void lpm_divide(class Design*des, class NetDivide*);
|
||||
|
||||
/* This method is called for each FF in the design. */
|
||||
virtual void lpm_ff(class Design*des, class NetFF*);
|
||||
|
||||
/* Handle LPM combinational logic devices. */
|
||||
virtual void lpm_logic(class Design*des, class NetLogic*);
|
||||
|
||||
/* This method is called for each multiplier. */
|
||||
virtual void lpm_mult(class Design*des, class NetMult*);
|
||||
};
|
||||
|
||||
struct proc_match_t {
|
||||
virtual ~proc_match_t();
|
||||
|
||||
virtual int assign(class NetAssign*);
|
||||
virtual int assign_mem(class NetAssignMem*);
|
||||
virtual int condit(class NetCondit*);
|
||||
virtual int pevent(class NetPEvent*);
|
||||
virtual int event_wait(class NetEvWait*);
|
||||
virtual int block(class NetBlock*);
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
* $Log: functor.h,v $
|
||||
* Revision 1.3 1999/12/01 06:06:16 steve
|
||||
* Redo synth to use match_proc_t scanner.
|
||||
* Revision 1.13 2000/04/20 00:28:03 steve
|
||||
* Catch some simple identity compareoptimizations.
|
||||
*
|
||||
* 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.12 2000/04/18 04:50:19 steve
|
||||
* Clean up unneeded NetEvent objects.
|
||||
*
|
||||
* Revision 1.1 1999/07/17 22:01:13 steve
|
||||
* Add the functor interface for functor transforms.
|
||||
* Revision 1.11 2000/04/12 20:02:53 steve
|
||||
* Finally remove the NetNEvent and NetPEvent classes,
|
||||
* Get synthesis working with the NetEvWait class,
|
||||
* and get started supporting multiple events in a
|
||||
* wait in vvm.
|
||||
*
|
||||
* Revision 1.10 2000/04/01 21:40:22 steve
|
||||
* Add support for integer division.
|
||||
*
|
||||
* Revision 1.9 2000/02/23 02:56:54 steve
|
||||
* Macintosh compilers do not support ident.
|
||||
*
|
||||
* Revision 1.8 2000/02/13 04:35:43 steve
|
||||
* Include some block matching from Larry.
|
||||
*
|
||||
* Revision 1.7 2000/01/13 03:35:35 steve
|
||||
* Multiplication all the way to simulation.
|
||||
*
|
||||
* Revision 1.6 1999/12/30 04:19:12 steve
|
||||
* Propogate constant 0 in low bits of adders.
|
||||
*
|
||||
* Revision 1.5 1999/12/17 06:18:16 steve
|
||||
* Rewrite the cprop functor to use the functor_t interface.
|
||||
*/
|
||||
#endif
|
||||
|
||||
+395
@@ -0,0 +1,395 @@
|
||||
/*
|
||||
* Copyright (c) 2000 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: iverilog.c,v 1.12 2000/05/09 00:02:13 steve Exp $"
|
||||
#endif
|
||||
|
||||
#include <stdio.h>
|
||||
#include <unistd.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#ifndef IVL_ROOT
|
||||
# define IVL_ROOT "."
|
||||
#endif
|
||||
|
||||
const char*base = IVL_ROOT;
|
||||
const char*opath = "a.out";
|
||||
const char*targ = "vvm";
|
||||
const char*start = 0;
|
||||
|
||||
char warning_flags[16] = "";
|
||||
|
||||
char*inc_list = 0;
|
||||
char*def_list = 0;
|
||||
|
||||
char*f_list = 0;
|
||||
|
||||
int synth_flag = 0;
|
||||
int verbose_flag = 0;
|
||||
|
||||
char tmp[4096];
|
||||
|
||||
static int t_null(char*cmd, unsigned ncmd)
|
||||
{
|
||||
int rc;
|
||||
|
||||
sprintf(tmp, " | %s/ivl %s", base, warning_flags);
|
||||
rc = strlen(tmp);
|
||||
cmd = realloc(cmd, ncmd+rc+1);
|
||||
strcpy(cmd+ncmd, tmp);
|
||||
ncmd += rc;
|
||||
|
||||
if (start) {
|
||||
sprintf(tmp, " -s%s", start);
|
||||
rc = strlen(tmp);
|
||||
cmd = realloc(cmd, ncmd+rc+1);
|
||||
strcpy(cmd+ncmd, tmp);
|
||||
ncmd += rc;
|
||||
}
|
||||
|
||||
if (verbose_flag) {
|
||||
sprintf(tmp, " -v");
|
||||
rc = strlen(tmp);
|
||||
cmd = realloc(cmd, ncmd+rc+1);
|
||||
strcpy(cmd+ncmd, tmp);
|
||||
ncmd += rc;
|
||||
}
|
||||
|
||||
sprintf(tmp, " -- -");
|
||||
rc = strlen(tmp);
|
||||
cmd = realloc(cmd, ncmd+rc+1);
|
||||
strcpy(cmd+ncmd, tmp);
|
||||
ncmd += rc;
|
||||
|
||||
if (verbose_flag)
|
||||
printf("translate: %s\n", cmd);
|
||||
|
||||
rc = system(cmd);
|
||||
return rc;
|
||||
}
|
||||
|
||||
/*
|
||||
* This function handles the vvm target. After preprocessing, run the
|
||||
* ivl translator to get C++, then run g++ to make an executable
|
||||
* program out of that.
|
||||
*/
|
||||
static int t_vvm(char*cmd, unsigned ncmd)
|
||||
{
|
||||
int rc;
|
||||
|
||||
sprintf(tmp, " | %s/ivl %s -o %s.cc -tvvm -Fcprop %s -Fnodangle"
|
||||
" -fVPI_MODULE_PATH=%s", base, warning_flags, opath,
|
||||
synth_flag?"-Fsynth":"", base);
|
||||
|
||||
rc = strlen(tmp);
|
||||
cmd = realloc(cmd, ncmd+rc+1);
|
||||
strcpy(cmd+ncmd, tmp);
|
||||
ncmd += rc;
|
||||
|
||||
if (f_list) {
|
||||
rc = strlen(f_list);
|
||||
cmd = realloc(cmd, ncmd+rc+1);
|
||||
strcpy(cmd+ncmd, tmp);
|
||||
ncmd += rc;
|
||||
}
|
||||
|
||||
if (start) {
|
||||
sprintf(tmp, " -s%s", start);
|
||||
rc = strlen(tmp);
|
||||
cmd = realloc(cmd, ncmd+rc+1);
|
||||
strcpy(cmd+ncmd, tmp);
|
||||
ncmd += rc;
|
||||
}
|
||||
sprintf(tmp, " -- -");
|
||||
rc = strlen(tmp);
|
||||
cmd = realloc(cmd, ncmd+rc+1);
|
||||
strcpy(cmd+ncmd, tmp);
|
||||
ncmd += rc;
|
||||
|
||||
if (verbose_flag)
|
||||
printf("translate: %s\n", cmd);
|
||||
|
||||
rc = system(cmd);
|
||||
if (rc != 0) {
|
||||
fprintf(stderr, "errors translating Verilog program.\n");
|
||||
return rc;
|
||||
}
|
||||
|
||||
sprintf(tmp, "%s -O -rdynamic -fno-exceptions -o %s -I%s "
|
||||
"-L%s %s.cc -lvvm %s", CXX, opath, IVL_INC, IVL_LIB,
|
||||
opath, DLLIB);
|
||||
|
||||
if (verbose_flag)
|
||||
printf("compile: %s\n", tmp);
|
||||
|
||||
rc = system(tmp);
|
||||
if (rc != 0) {
|
||||
fprintf(stderr, "errors compiling translated program.\n");
|
||||
return rc;
|
||||
}
|
||||
|
||||
sprintf(tmp, "%s.cc", opath);
|
||||
unlink(tmp);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int t_xnf(char*cmd, unsigned ncmd)
|
||||
{
|
||||
int rc;
|
||||
|
||||
sprintf(tmp, " | %s/ivl %s -o %s -txnf -Fcprop -Fsynth "
|
||||
"-Fnodangle -Fxnfio", base, warning_flags, opath);
|
||||
|
||||
rc = strlen(tmp);
|
||||
cmd = realloc(cmd, ncmd+rc+1);
|
||||
strcpy(cmd+ncmd, tmp);
|
||||
ncmd += rc;
|
||||
|
||||
if (f_list) {
|
||||
rc = strlen(f_list);
|
||||
cmd = realloc(cmd, ncmd+rc+1);
|
||||
strcpy(cmd+ncmd, tmp);
|
||||
ncmd += rc;
|
||||
}
|
||||
|
||||
if (start) {
|
||||
sprintf(tmp, " -s%s", start);
|
||||
rc = strlen(tmp);
|
||||
cmd = realloc(cmd, ncmd+rc+1);
|
||||
strcpy(cmd+ncmd, tmp);
|
||||
ncmd += rc;
|
||||
}
|
||||
sprintf(tmp, " -- -");
|
||||
rc = strlen(tmp);
|
||||
cmd = realloc(cmd, ncmd+rc+1);
|
||||
strcpy(cmd+ncmd, tmp);
|
||||
ncmd += rc;
|
||||
|
||||
if (verbose_flag)
|
||||
printf("translate: %s\n", cmd);
|
||||
|
||||
rc = system(cmd);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
static void process_warning_switch(const char*name)
|
||||
{
|
||||
if (warning_flags[0] == 0)
|
||||
strcpy(warning_flags, "-W");
|
||||
|
||||
if (strcmp(name,"all") == 0) {
|
||||
strcat(warning_flags, "i");
|
||||
|
||||
} else if (strcmp(name,"implicit") == 0) {
|
||||
if (! strchr(warning_flags+2, 'i'))
|
||||
strcat(warning_flags, "i");
|
||||
}
|
||||
}
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
char*cmd;
|
||||
unsigned ncmd;
|
||||
int e_flag = 0;
|
||||
int opt, idx;
|
||||
char*cp;
|
||||
|
||||
while ((opt = getopt(argc, argv, "B:D:Ef:I:o:Ss:t:vW:")) != EOF) {
|
||||
|
||||
switch (opt) {
|
||||
case 'B':
|
||||
base = optarg;
|
||||
break;
|
||||
case 'D':
|
||||
if (def_list == 0) {
|
||||
def_list = malloc(strlen(" -D")+strlen(optarg)+1);
|
||||
strcpy(def_list, " -D");
|
||||
strcat(def_list, optarg);
|
||||
} else {
|
||||
def_list = realloc(def_list, strlen(def_list)
|
||||
+ strlen(" -D")
|
||||
+ strlen(optarg) + 1);
|
||||
strcat(def_list, " -D");
|
||||
strcat(def_list, optarg);
|
||||
}
|
||||
break;
|
||||
case 'E':
|
||||
e_flag = 1;
|
||||
break;
|
||||
case 'f':
|
||||
if (f_list == 0) {
|
||||
f_list = malloc(strlen("-f")+strlen(optarg)+1);
|
||||
strcpy(f_list, "-f");
|
||||
strcat(f_list, optarg);
|
||||
} else {
|
||||
f_list = realloc(f_list, strlen(f_list) +
|
||||
strlen(" -f") +
|
||||
strlen(optarg) + 1);
|
||||
strcat(f_list, " -f");
|
||||
strcat(f_list, optarg);
|
||||
}
|
||||
break;
|
||||
case 'I':
|
||||
if (inc_list == 0) {
|
||||
inc_list = malloc(strlen(" -I")+strlen(optarg)+1);
|
||||
strcpy(inc_list, " -I");
|
||||
strcat(inc_list, optarg);
|
||||
} else {
|
||||
inc_list = realloc(inc_list, strlen(inc_list)
|
||||
+ strlen(" -I")
|
||||
+ strlen(optarg) + 1);
|
||||
strcat(inc_list, " -I");
|
||||
strcat(inc_list, optarg);
|
||||
}
|
||||
break;
|
||||
case 'o':
|
||||
opath = optarg;
|
||||
break;
|
||||
case 'S':
|
||||
synth_flag = 1;
|
||||
break;
|
||||
case 's':
|
||||
start = optarg;
|
||||
break;
|
||||
case 't':
|
||||
targ = optarg;
|
||||
break;
|
||||
case 'v':
|
||||
verbose_flag = 1;
|
||||
break;
|
||||
case 'W':
|
||||
process_warning_switch(optarg);
|
||||
break;
|
||||
case '?':
|
||||
default:
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
if (optind == argc) {
|
||||
fprintf(stderr, "%s: No input files.\n", argv[0]);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Start building the preprocess command line. */
|
||||
|
||||
sprintf(tmp, "%s/ivlpp %s%s", base,
|
||||
verbose_flag?" -v":"",
|
||||
e_flag?"":" -L");
|
||||
|
||||
ncmd = strlen(tmp);
|
||||
cmd = malloc(ncmd + 1);
|
||||
strcpy(cmd, tmp);
|
||||
|
||||
if (inc_list) {
|
||||
cmd = realloc(cmd, ncmd + strlen(inc_list) + 1);
|
||||
strcat(cmd, inc_list);
|
||||
ncmd += strlen(inc_list);
|
||||
}
|
||||
|
||||
if (def_list) {
|
||||
cmd = realloc(cmd, ncmd + strlen(def_list) + 1);
|
||||
strcat(cmd, def_list);
|
||||
ncmd += strlen(def_list);
|
||||
}
|
||||
|
||||
/* Add all the verilog source files to the preprocess command line. */
|
||||
|
||||
for (idx = optind ; idx < argc ; idx += 1) {
|
||||
sprintf(tmp, " %s", argv[idx]);
|
||||
cmd = realloc(cmd, ncmd+strlen(tmp)+1);
|
||||
strcpy(cmd+ncmd, tmp);
|
||||
ncmd += strlen(tmp);
|
||||
}
|
||||
|
||||
|
||||
/* If the -E flag was given on the command line, then all we
|
||||
do is run the preprocessor and put the output where the
|
||||
user wants it. */
|
||||
if (e_flag) {
|
||||
if (strcmp(opath,"-") != 0) {
|
||||
sprintf(tmp, " > %s", opath);
|
||||
cmd = realloc(cmd, ncmd+strlen(tmp)+1);
|
||||
strcpy(cmd+ncmd, tmp);
|
||||
ncmd += strlen(tmp);
|
||||
}
|
||||
|
||||
if (verbose_flag)
|
||||
printf("preprocess: %s\n", cmd);
|
||||
|
||||
return system(cmd);
|
||||
}
|
||||
|
||||
if (strcmp(targ,"null") == 0)
|
||||
return t_null(cmd, ncmd);
|
||||
else if (strcmp(targ,"vvm") == 0)
|
||||
return t_vvm(cmd, ncmd);
|
||||
else if (strcmp(targ,"xnf") == 0)
|
||||
return t_xnf(cmd, ncmd);
|
||||
else {
|
||||
fprintf(stderr, "Unknown target: %s\n", targ);
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* $Log: iverilog.c,v $
|
||||
* Revision 1.12 2000/05/09 00:02:13 steve
|
||||
* Parameterize LD lib in C++ command line.
|
||||
*
|
||||
* Revision 1.11 2000/05/05 01:07:42 steve
|
||||
* Add the -I and -D switches to iverilog.
|
||||
*
|
||||
* Revision 1.10 2000/05/04 20:08:20 steve
|
||||
* Tell ivlpp to generate line number directives.
|
||||
*
|
||||
* Revision 1.9 2000/05/03 22:14:31 steve
|
||||
* More features of ivl available through iverilog.
|
||||
*
|
||||
* Revision 1.8 2000/05/01 23:55:22 steve
|
||||
* Better inc and lib paths for iverilog.
|
||||
*
|
||||
* Revision 1.7 2000/04/29 01:20:14 steve
|
||||
* The -f flag is now in place.
|
||||
*
|
||||
* Revision 1.6 2000/04/26 21:11:41 steve
|
||||
* Mussed up command string mashing.
|
||||
*
|
||||
* Revision 1.5 2000/04/26 03:33:32 steve
|
||||
* Do not set width too small to hold significant bits.
|
||||
*
|
||||
* Revision 1.4 2000/04/23 21:14:32 steve
|
||||
* The -s flag.
|
||||
*
|
||||
* Revision 1.3 2000/04/21 22:54:47 steve
|
||||
* module path in vvm target.
|
||||
*
|
||||
* Revision 1.2 2000/04/21 22:51:38 steve
|
||||
* Support the -tnull target type.
|
||||
*
|
||||
* Revision 1.1 2000/04/21 06:41:03 steve
|
||||
* Add the iverilog driver program.
|
||||
*
|
||||
*/
|
||||
|
||||
+155
@@ -0,0 +1,155 @@
|
||||
.TH iverilog 1 "$Date: 2000/05/05 01:07:42 $" Version "$Date: 2000/05/05 01:07:42 $"
|
||||
.SH NAME
|
||||
iverilog - Icarus Verilog compiler
|
||||
|
||||
.SH SYNOPSIS
|
||||
.B iverilog
|
||||
[-ESv] [-Dmacro[=defn]] [-fflag=value] [-Iincludepath] [-mmodule] [-ooutputfilename] [-s topmodule] [-ttype] [-Wclass] sourcefile[s]
|
||||
|
||||
.SH DESCRIPTION
|
||||
.PP
|
||||
\fIiverilog\fP is a compiler that translates Verilog source code into
|
||||
executable programs for simulation, or other netlist formats for
|
||||
further processing. The currenty supported targets are \fIvvm\fP (for
|
||||
executable simulation) and \fIxnf\fP for synthesis. Other target
|
||||
types are added as code generators are implemented.
|
||||
|
||||
.SH OPTIONS
|
||||
.l
|
||||
\fIiverilog\fP accepts the following options:
|
||||
.TP 8
|
||||
.B -B\fIbase\fP
|
||||
The \fIiverilog\fP program uses external programs to preprocess and
|
||||
compile the verilog source. Normally, the path used to locate these
|
||||
tools is built into the \fIiverilog\fP program. However, the \fB-B\fP
|
||||
switch allows the user to select a different set of programs. The path
|
||||
given is used to locate \fIivlpp\fP, \fIivl\fP and the VPI modules.
|
||||
.TP 8
|
||||
.B -D\fImacro\fP
|
||||
Defines macro \fImacro\fP with the string `1' as its definition. This
|
||||
form is normally only used to trigger ifdef conditionals in the
|
||||
Verilog source.
|
||||
.TP 8
|
||||
.B -D\fImacro=defn\fP
|
||||
Defines macro \fImacro\fP as \fIdefn\fP.
|
||||
.TP 8
|
||||
.B -E
|
||||
Preprocess the Verilog source, but do not compile it. The output file
|
||||
is the Verilog input, but with file inclusions and macro references
|
||||
expanded and removed. This is useful, for example, to preprocess
|
||||
verilog source for use by other compilers.
|
||||
.TP 8
|
||||
.B -f\fIflag=value\fP
|
||||
Assign a value to a target specific flag. The \fB-f\fP switch may be
|
||||
used as often as necessary to specify all the desired flags. The flags
|
||||
that are used depend on the target that is selected, and are described
|
||||
in target specific documentation. Flags that are not used are ignored.
|
||||
.TP 8
|
||||
.B -I\fIincludedir\fP
|
||||
Append directory \fIincludepdir\fP to list of directoriess searched
|
||||
for Verilog include files. The \fB-I\fP switch may be used many times
|
||||
to specify several directories to search, the directories are searched
|
||||
in the order they appear on the command line.
|
||||
.TP 8
|
||||
.B -m\fImodule\fP
|
||||
Add this module to the list of VPI modules to be loaded by the
|
||||
simulation. (NOT IMPLEMENTED)
|
||||
.TP 8
|
||||
.B -o \fIfilename\fP
|
||||
Place output in the file \fIfilename\fP. If no output file name is
|
||||
specified, \fIiverilog\fP uses the default name \fBa.out\fP.
|
||||
.TP 8
|
||||
.B -S
|
||||
Synthesize. Normally, if the target can accept behavioral
|
||||
descriptions the compiler will leave processes in behavioral
|
||||
form. The \fB-S\fP switch causes the compiler to perform synthesis
|
||||
even if it is not necessary for the target. If the target type is a
|
||||
netlist format, the \fB-S\fP switch is unnecessary and has no effect.
|
||||
.TP 8
|
||||
.B -s \fItopmodule\fP
|
||||
Specify the top level module to elaborate. Icarus Verilog will by default
|
||||
choose the only module that has no ports. However, this simplistic
|
||||
heuristic is often not sufficient, and sometimes not what is wanted
|
||||
anyhow.
|
||||
.TP 8
|
||||
.B -t\fItarget\fP
|
||||
Use this switch to specify the target output format. See the
|
||||
\fBTARGETS\fP section below for a list of valid output formats.
|
||||
.TP 8
|
||||
.B -v
|
||||
Turn on verbose messages. This will print the command lines that are
|
||||
executed to perform the actual compilation, along with version
|
||||
information from the various components.
|
||||
.TP 8
|
||||
.B -W\fIclass\fP
|
||||
Turn on different classes of warnings. See the \fBWARNING TYPES\fP
|
||||
section below for desctriptions of the different warning groups. If
|
||||
multiple \fB-W\fP switches are used, the warning set is the union of
|
||||
all the requested classes.
|
||||
|
||||
.SH TARGETS
|
||||
|
||||
The Icarus Verilog compiler supports a variety of targets, for
|
||||
different purposes, and the \fB-t\fP switch is used to select the
|
||||
desired target.
|
||||
|
||||
.TP 8
|
||||
.B null
|
||||
The null target causes no code to be generated. It is useful for
|
||||
checking the syntax of the Verilog source.
|
||||
.TP 8
|
||||
.B vvm
|
||||
This is the default. The target is an executable program that uses the
|
||||
vvm simulation runtime. The compiler actually generates C++ code, then
|
||||
compiles and links that code to make the output executable.
|
||||
.TP 8
|
||||
.B xnf
|
||||
This is the Xilinx Netlist Format used by many tools for placing
|
||||
devices in FPGAs or other programmable devices. The Icarus Verilog XNF
|
||||
code generator can generate complete designs or XNF macros that can be
|
||||
imported into larger designs by other tools.
|
||||
|
||||
.SH "WARNING TYPES"
|
||||
These are the types of warnings that can be selected by the \fB-W\fP
|
||||
switch.
|
||||
|
||||
.TP 8
|
||||
.B all
|
||||
This enables all supported warning categories.
|
||||
|
||||
.TP 8
|
||||
.B implicit
|
||||
This enables warnings for creation of implicit declarations. For
|
||||
example, if a scaler wire X is used but not declared in the Verilog
|
||||
source, this will print a warning at its first use.
|
||||
|
||||
.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 a.out:
|
||||
|
||||
verilog hello.v
|
||||
|
||||
To compile hello.v to an executable file called hello:
|
||||
|
||||
verilog -o hello hello.v
|
||||
|
||||
To compile hello.v to a file in XNF-format called hello.xnf
|
||||
|
||||
verilog -txnf -ohello.xnf hello.v
|
||||
|
||||
|
||||
.SH "AUTHOR"
|
||||
.nf
|
||||
Steve Williams ([email protected])
|
||||
|
||||
.SH SEE ALSO
|
||||
.BR "<http://www.icarus.com/eda/verilog/>"
|
||||
|
||||
.SH COPYRIGHT
|
||||
.nf
|
||||
Copyright \(co 2000 Stephen Williams
|
||||
|
||||
This document can be freely redistributed according to the terms of the
|
||||
GNU General Public License version 2.0
|
||||
+6
-6
@@ -18,7 +18,7 @@
|
||||
# 59 Temple Place - Suite 330
|
||||
# Boston, MA 02111-1307, USA
|
||||
#
|
||||
#ident "$Id: Makefile.in,v 1.6 1999/10/16 20:48:15 steve Exp $"
|
||||
#ident "$Id: Makefile.in,v 1.7 2000/01/01 20:57:51 steve Exp $"
|
||||
#
|
||||
#
|
||||
SHELL = /bin/sh
|
||||
@@ -60,16 +60,16 @@ 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 $(libdir)/ivl/ivlpp
|
||||
|
||||
$(bindir)/ivlpp: ivlpp
|
||||
$(INSTALL_PROGRAM) ./ivlpp $(bindir)/ivlpp
|
||||
$(libdir)/ivl/ivlpp: ivlpp
|
||||
$(INSTALL_PROGRAM) ./ivlpp $(libdir)/ivl/ivlpp
|
||||
|
||||
installdirs: ../mkinstalldirs
|
||||
$(srcdir)/../mkinstalldirs $(bindir)
|
||||
$(srcdir)/../mkinstalldirs $(libdir)/ivl
|
||||
|
||||
uninstall:
|
||||
rm -f $(bindir)/ivlpp
|
||||
rm -f $(libdir)/ivl/ivlpp
|
||||
|
||||
lexor.o: lexor.c parse.h globals.h
|
||||
main.o: main.c globals.h
|
||||
|
||||
+35
-8
@@ -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.14 1999/10/08 17:27:56 steve Exp $"
|
||||
#ident "$Id: lexor.lex,v 1.18 2000/04/26 01:35:26 steve Exp $"
|
||||
#endif
|
||||
|
||||
# include <stdio.h>
|
||||
@@ -35,6 +35,7 @@ static void output_init();
|
||||
|
||||
static void def_match();
|
||||
static void def_start();
|
||||
static void def_finish();
|
||||
static void def_undefine();
|
||||
static void do_define();
|
||||
static int is_defined(const char*name);
|
||||
@@ -115,13 +116,23 @@ W [ \t\b\f]+
|
||||
that follows it. when the directive ends, the do_include function
|
||||
performs the include operation. */
|
||||
|
||||
^{W}?`include { BEGIN(PPINCLUDE); }
|
||||
^{W}?`include { yy_push_state(PPINCLUDE); }
|
||||
|
||||
<PPINCLUDE>\"[^\"]*\" { include_filename(); }
|
||||
|
||||
<PPINCLUDE>[ \t\b\f] { ; }
|
||||
|
||||
<PPINCLUDE>\n { istack->lineno += 1; BEGIN(0); do_include(); }
|
||||
/* Catch single-line comments that share the line with an include
|
||||
directive. And while I'm at it, I might as well preserve the
|
||||
comment in the output stream. */
|
||||
|
||||
<PPINCLUDE>"//".* { ECHO; }
|
||||
|
||||
/* These finish the include directive (EOF or EOL) so I revert the
|
||||
lexor state and execute the inclusion. */
|
||||
|
||||
<PPINCLUDE>\n { istack->lineno += 1; yy_pop_state(); do_include(); }
|
||||
<PPINCLUDE><<EOF>> { istack->lineno += 1; yy_pop_state(); do_include(); }
|
||||
|
||||
|
||||
/* Detect the define directive, and match the name. Match any
|
||||
@@ -129,13 +140,22 @@ 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}? { yy_push_state(PPDEFINE); def_start(); }
|
||||
|
||||
<PPDEFINE>.*\n {
|
||||
do_define();
|
||||
<PPDEFINE>.* { do_define(); }
|
||||
|
||||
<PPDEFINE>\n {
|
||||
def_finish();
|
||||
istack->lineno += 1;
|
||||
fputc('\n', yyout);
|
||||
BEGIN(0);
|
||||
yy_pop_state();
|
||||
}
|
||||
|
||||
<PPDEFINE><<EOF>> {
|
||||
def_finish();
|
||||
istack->lineno += 1;
|
||||
fputc('\n', yyout);
|
||||
yy_pop_state();
|
||||
}
|
||||
|
||||
`undef{W}[a-zA-Z][a-zA-Z0-9_]*{W}?.* { def_undefine(); }
|
||||
@@ -318,6 +338,13 @@ static void do_define()
|
||||
}
|
||||
|
||||
define_macro(def_name, yytext);
|
||||
def_name[0] = 0;
|
||||
}
|
||||
|
||||
static void def_finish()
|
||||
{
|
||||
if (def_name[0])
|
||||
define_macro(def_name, "1");
|
||||
}
|
||||
|
||||
static void def_undefine()
|
||||
@@ -522,7 +549,7 @@ static int yywrap()
|
||||
if (line_direct_flag)
|
||||
fprintf(yyout, "\n#line \"%s\" 0\n", istack->path);
|
||||
|
||||
yyrestart(isp->file);
|
||||
yyrestart(istack->file);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
|
||||
%{
|
||||
/*
|
||||
* Copyright (c) 1998-1999 Stephen Williams ([email protected])
|
||||
* Copyright (c) 1998-2000 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
|
||||
@@ -18,8 +18,8 @@
|
||||
* 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: lexor.lex,v 1.38 1999/11/23 02:49:04 steve Exp $"
|
||||
#if !defined(WINNT) && !defined(macintosh)
|
||||
#ident "$Id: lexor.lex,v 1.44 2000/03/12 17:09:41 steve Exp $"
|
||||
#endif
|
||||
|
||||
//# define YYSTYPE lexval
|
||||
@@ -30,6 +30,7 @@
|
||||
# include "parse.h"
|
||||
# include <ctype.h>
|
||||
# include <string.h>
|
||||
# include "lexor_keyword.h"
|
||||
|
||||
extern FILE*vl_input;
|
||||
extern string vl_file;
|
||||
@@ -42,7 +43,6 @@ static void reset_lexor();
|
||||
static void line_directive();
|
||||
static void line_directive2();
|
||||
|
||||
extern int check_identifier(const char*str, int len);
|
||||
static verinum*make_sized_binary(const char*txt);
|
||||
static verinum*make_sized_dec(const char*txt);
|
||||
static verinum*make_unsized_dec(const char*txt);
|
||||
@@ -97,6 +97,7 @@ W [ \t\b\f\r]+
|
||||
"~^" { return K_NXOR; }
|
||||
"^~" { return K_NXOR; }
|
||||
"~&" { return K_NAND; }
|
||||
"->" { return K_TRIGGER; }
|
||||
|
||||
|
||||
[}{;:\[\],()#=.@&!?<>%|^~+*/-] { return yytext[0]; }
|
||||
@@ -113,16 +114,16 @@ W [ \t\b\f\r]+
|
||||
return STRING; }
|
||||
<CSTRING>. { yymore(); }
|
||||
|
||||
<UDPTABLE>\(\?0\) { return '_'; }
|
||||
<UDPTABLE>\(\?1\) { return '+'; }
|
||||
<UDPTABLE>\(\?x\) { return '%'; }
|
||||
<UDPTABLE>\(\?\?\) { return '*'; }
|
||||
<UDPTABLE>\(01\) { return 'r'; }
|
||||
<UDPTABLE>\(0x\) { return 'P'; }
|
||||
<UDPTABLE>\(10\) { return 'f'; }
|
||||
<UDPTABLE>\(1x\) { return 'N'; }
|
||||
<UDPTABLE>\(x0\) { return 'F'; }
|
||||
<UDPTABLE>\(x1\) { return 'R'; }
|
||||
<UDPTABLE>\(\?0\) { return '_'; }
|
||||
<UDPTABLE>\(\?1\) { return '+'; }
|
||||
<UDPTABLE>\(\?[xX]\) { return '%'; }
|
||||
<UDPTABLE>\(\?\?\) { return '*'; }
|
||||
<UDPTABLE>\(01\) { return 'r'; }
|
||||
<UDPTABLE>\(0[xX]\) { return 'P'; }
|
||||
<UDPTABLE>\(10\) { return 'f'; }
|
||||
<UDPTABLE>\(1[xX]\) { return 'N'; }
|
||||
<UDPTABLE>\([xX]0\) { return 'F'; }
|
||||
<UDPTABLE>\([xX]1\) { return 'R'; }
|
||||
<UDPTABLE>[bB] { return 'b'; }
|
||||
<UDPTABLE>[fF] { return 'f'; }
|
||||
<UDPTABLE>[rR] { return 'r'; }
|
||||
@@ -130,13 +131,15 @@ W [ \t\b\f\r]+
|
||||
<UDPTABLE>[pPnN01\?\*\-] { return yytext[0]; }
|
||||
|
||||
[a-zA-Z_][a-zA-Z0-9$_]* {
|
||||
int rc = check_identifier(yytext, yyleng);
|
||||
int rc = lexor_keyword_code(yytext, yyleng);
|
||||
if (rc == IDENTIFIER)
|
||||
yylval.text = strdup(yytext);
|
||||
else
|
||||
yylval.text = 0;
|
||||
|
||||
return rc; }
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
||||
[a-zA-Z_][a-zA-Z0-9$_]*(\.[a-zA-Z_][a-zA-Z0-9$_]*)+ {
|
||||
yylval.text = strdup(yytext);
|
||||
@@ -159,26 +162,26 @@ W [ \t\b\f\r]+
|
||||
yylval.text = strdup(cp);
|
||||
return PORTNAME; }
|
||||
|
||||
[0-9][0-9_]*[ \t]*\'[dD][ \t]*[0-9][0-9_]* {
|
||||
[0-9][0-9_]*[ \t]*\'[sS]?[dD][ \t]*[0-9][0-9_]* {
|
||||
yylval.number = make_sized_dec(yytext);
|
||||
return NUMBER; }
|
||||
[0-9][0-9_]*[ \t]*\'[bB][ \t]*[0-1xzXZ_\?]+ {
|
||||
[0-9][0-9_]*[ \t]*\'[sS]?[bB][ \t]*[0-1xzXZ_\?]+ {
|
||||
yylval.number = make_sized_binary(yytext);
|
||||
return NUMBER; }
|
||||
[0-9][0-9_]*[ \t]*\'[oO][ \t]*[0-7xzXZ_\?]+ {
|
||||
[0-9][0-9_]*[ \t]*\'[sS]?[oO][ \t]*[0-7xzXZ_\?]+ {
|
||||
yylval.number = make_sized_octal(yytext);
|
||||
return NUMBER; }
|
||||
[0-9][0-9_]*[ \t]*\'[hH][ \t]*[0-9a-fA-FxzXZ_\?]+ {
|
||||
[0-9][0-9_]*[ \t]*\'[sS]?[hH][ \t]*[0-9a-fA-FxzXZ_\?]+ {
|
||||
yylval.number = make_sized_hex(yytext);
|
||||
return NUMBER; }
|
||||
|
||||
\'d[ \t]*[0-9][0-9_]* { yylval.number = make_unsized_dec(yytext);
|
||||
return NUMBER; }
|
||||
\'[bB][ \t]*[0-1xzXZ_\?]+ { yylval.number = make_unsized_binary(yytext);
|
||||
\'[sS]?[dD][ \t]*[0-9][0-9_]* { yylval.number = make_unsized_dec(yytext);
|
||||
return NUMBER; }
|
||||
\'[sS]?[bB][ \t]*[0-1xzXZ_\?]+ { yylval.number = make_unsized_binary(yytext);
|
||||
return NUMBER; }
|
||||
\'[oO][ \t]*[0-7xzXZ_\?]+ { yylval.number = make_unsized_octal(yytext);
|
||||
\'[sS]?[oO][ \t]*[0-7xzXZ_\?]+ { yylval.number = make_unsized_octal(yytext);
|
||||
return NUMBER; }
|
||||
\'[hH][ \t]*[0-9a-fA-FxzXZ_\?]+ { yylval.number = make_unsized_hex(yytext);
|
||||
\'[sS]?[hH][ \t]*[0-9a-fA-FxzXZ_\?]+ { yylval.number = make_unsized_hex(yytext);
|
||||
return NUMBER; }
|
||||
|
||||
[0-9][0-9_]* {
|
||||
@@ -198,6 +201,7 @@ W [ \t\b\f\r]+
|
||||
}
|
||||
|
||||
yylval.number = new verinum(bits, nbits, false);
|
||||
yylval.number->has_sign(true);
|
||||
delete[]bits;
|
||||
return NUMBER; }
|
||||
|
||||
@@ -312,22 +316,26 @@ void lex_end_table()
|
||||
|
||||
static verinum*make_binary_with_size(unsigned size, bool fixed, const char*ptr)
|
||||
{
|
||||
assert(tolower(*ptr) == 'b');
|
||||
bool sign_flag = false;
|
||||
verinum::V*bits = new verinum::V[size];
|
||||
|
||||
if (tolower(ptr[0]) == 's') {
|
||||
ptr += 1;
|
||||
sign_flag = true;
|
||||
}
|
||||
assert(tolower(*ptr) == 'b');
|
||||
ptr += 1;
|
||||
|
||||
while (*ptr && ((*ptr == ' ') || (*ptr == '\t')))
|
||||
ptr += 1;
|
||||
|
||||
unsigned idx = 0;
|
||||
const char*eptr = ptr + strlen(ptr) - 1;
|
||||
while ((eptr > ptr) && (idx < size)) {
|
||||
|
||||
if (*eptr == '_') {
|
||||
eptr -= 1;
|
||||
continue;
|
||||
}
|
||||
while ((eptr >= ptr) && (idx < size)) {
|
||||
|
||||
switch (*eptr) {
|
||||
case '_':
|
||||
break;
|
||||
case '0':
|
||||
bits[idx++] = verinum::V0;
|
||||
break;
|
||||
@@ -349,7 +357,7 @@ static verinum*make_binary_with_size(unsigned size, bool fixed, const char*ptr)
|
||||
// Zero-extend binary number, except that z or x is extended
|
||||
// if it is the highest supplied digit.
|
||||
while (idx < size) {
|
||||
switch (ptr[1]) {
|
||||
switch (ptr[0]) {
|
||||
case '0':
|
||||
case '1':
|
||||
bits[idx++] = verinum::V0;
|
||||
@@ -365,7 +373,10 @@ static verinum*make_binary_with_size(unsigned size, bool fixed, const char*ptr)
|
||||
}
|
||||
}
|
||||
|
||||
return new verinum(bits, size, fixed);
|
||||
verinum*out = new verinum(bits, size, fixed);
|
||||
delete[]bits;
|
||||
out->has_sign(sign_flag);
|
||||
return out;
|
||||
}
|
||||
|
||||
static verinum*make_sized_binary(const char*txt)
|
||||
@@ -376,16 +387,21 @@ static verinum*make_sized_binary(const char*txt)
|
||||
ptr += 1;
|
||||
assert(*ptr == '\'');
|
||||
ptr += 1;
|
||||
assert(tolower(*ptr) == 'b');
|
||||
|
||||
return make_binary_with_size(size, true, ptr);
|
||||
}
|
||||
|
||||
static verinum*make_unsized_binary(const char*txt)
|
||||
{
|
||||
bool sign_flag = false;
|
||||
const char*ptr = txt;
|
||||
assert(*ptr == '\'');
|
||||
ptr += 1;
|
||||
|
||||
if (tolower(*ptr) == 's') {
|
||||
sign_flag = true;
|
||||
ptr += 1;
|
||||
}
|
||||
assert(tolower(*ptr) == 'b');
|
||||
while (*ptr && ((*ptr == 'b') || (*ptr == ' ') || (*ptr == '\t')))
|
||||
ptr += 1;
|
||||
@@ -420,17 +436,27 @@ static verinum*make_unsized_binary(const char*txt)
|
||||
ptr += 1;
|
||||
}
|
||||
|
||||
return new verinum(bits, size);
|
||||
verinum*out = new verinum(bits, size);
|
||||
out->has_sign(sign_flag);
|
||||
delete[]bits;
|
||||
return out;
|
||||
}
|
||||
|
||||
static verinum*make_sized_octal(const char*txt)
|
||||
{
|
||||
bool sign_flag = false;
|
||||
char*ptr;
|
||||
|
||||
unsigned size = strtoul(txt,&ptr,10);
|
||||
while (*ptr && ((*ptr == ' ') || (*ptr == '\t')))
|
||||
ptr += 1;
|
||||
assert(*ptr == '\'');
|
||||
ptr += 1;
|
||||
|
||||
if (tolower(*ptr) == 's') {
|
||||
sign_flag = true;
|
||||
ptr += 1;
|
||||
}
|
||||
assert(tolower(*ptr) == 'o');
|
||||
|
||||
/* We know from the size number how bit to make the verinom
|
||||
@@ -506,14 +532,24 @@ static verinum*make_sized_octal(const char*txt)
|
||||
}
|
||||
}
|
||||
|
||||
return new verinum(bits, size, true);
|
||||
verinum*out = new verinum(bits, size, true);
|
||||
delete[]bits;
|
||||
out->has_sign(sign_flag);
|
||||
return out;
|
||||
}
|
||||
|
||||
static verinum*make_unsized_octal(const char*txt)
|
||||
{
|
||||
bool sign_flag = false;
|
||||
const char*ptr = txt;
|
||||
assert(*ptr == '\'');
|
||||
ptr += 1;
|
||||
|
||||
if (tolower(*ptr) == 's') {
|
||||
sign_flag = true;
|
||||
ptr += 1;
|
||||
}
|
||||
|
||||
assert(tolower(*ptr) == 'o');
|
||||
ptr += 1;
|
||||
|
||||
@@ -555,11 +591,15 @@ static verinum*make_unsized_octal(const char*txt)
|
||||
ptr += 1;
|
||||
}
|
||||
|
||||
return new verinum(bits, size);
|
||||
verinum*out = new verinum(bits, size);
|
||||
out->has_sign(sign_flag);
|
||||
delete[]bits;
|
||||
return out;
|
||||
}
|
||||
|
||||
static verinum*make_sized_hex(const char*txt)
|
||||
{
|
||||
bool sign_flag = false;
|
||||
char*ptr;
|
||||
unsigned size = strtoul(txt,&ptr,10);
|
||||
|
||||
@@ -568,6 +608,12 @@ static verinum*make_sized_hex(const char*txt)
|
||||
|
||||
assert(*ptr == '\'');
|
||||
ptr += 1;
|
||||
|
||||
if (tolower(*ptr) == 's') {
|
||||
sign_flag = true;
|
||||
ptr += 1;
|
||||
}
|
||||
|
||||
assert(tolower(*ptr) == 'h');
|
||||
|
||||
ptr += 1;
|
||||
@@ -634,14 +680,23 @@ static verinum*make_sized_hex(const char*txt)
|
||||
bits[idx++] = verinum::V0;
|
||||
}
|
||||
|
||||
return new verinum(bits, size, true);
|
||||
verinum*out = new verinum(bits, size, true);
|
||||
out->has_sign(sign_flag);
|
||||
delete[]bits;
|
||||
return out;
|
||||
}
|
||||
|
||||
static verinum*make_unsized_hex(const char*txt)
|
||||
{
|
||||
bool sign_flag = false;
|
||||
const char*ptr = txt;
|
||||
assert(*ptr == '\'');
|
||||
ptr += 1;
|
||||
|
||||
if (tolower(*ptr) == 's') {
|
||||
sign_flag = true;
|
||||
ptr += 1;
|
||||
}
|
||||
assert(tolower(*ptr) == 'h');
|
||||
|
||||
ptr += 1;
|
||||
@@ -694,7 +749,10 @@ static verinum*make_unsized_hex(const char*txt)
|
||||
ptr += 1;
|
||||
}
|
||||
|
||||
return new verinum(bits, size);
|
||||
verinum*out = new verinum(bits, size);
|
||||
out->has_sign(sign_flag);
|
||||
delete[]bits;
|
||||
return out;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -703,6 +761,11 @@ static verinum*make_unsized_hex(const char*txt)
|
||||
*/
|
||||
static verinum*make_dec_with_size(unsigned size, bool fixed, const char*ptr)
|
||||
{
|
||||
bool signed_flag = false;
|
||||
if (tolower(*ptr) == 's') {
|
||||
signed_flag = true;
|
||||
ptr += 1;
|
||||
}
|
||||
assert(tolower(*ptr) == 'd');
|
||||
|
||||
ptr += 1;
|
||||
@@ -726,7 +789,10 @@ static verinum*make_dec_with_size(unsigned size, bool fixed, const char*ptr)
|
||||
value /= 2;
|
||||
}
|
||||
|
||||
return new verinum(bits, size, fixed);
|
||||
verinum*out = new verinum(bits, size, fixed);
|
||||
out->has_sign(signed_flag);
|
||||
delete[]bits;
|
||||
return out;
|
||||
}
|
||||
|
||||
static verinum*make_sized_dec(const char*txt)
|
||||
@@ -739,7 +805,6 @@ static verinum*make_sized_dec(const char*txt)
|
||||
|
||||
assert(*ptr == '\'');
|
||||
ptr += 1;
|
||||
assert(tolower(*ptr) == 'd');
|
||||
|
||||
return make_dec_with_size(size, true, ptr);
|
||||
}
|
||||
|
||||
@@ -1,230 +0,0 @@
|
||||
/* 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;
|
||||
}
|
||||
+15
-5
@@ -4,12 +4,10 @@
|
||||
#include "parse_misc.h"
|
||||
#include "parse.h"
|
||||
#include <string.h>
|
||||
#include "lexor_keyword.h"
|
||||
|
||||
%}
|
||||
struct Keywords {
|
||||
char *name;
|
||||
int tokenType;
|
||||
} Keywords;
|
||||
struct lexor_keyword { const char*name; int tokenType; };
|
||||
%%
|
||||
always, K_always
|
||||
and, K_and
|
||||
@@ -51,6 +49,7 @@ input, K_input
|
||||
integer, K_integer
|
||||
join, K_join
|
||||
large, K_large
|
||||
localparam, K_localparam
|
||||
macromodule, K_macromodule
|
||||
medium, K_medium
|
||||
module, K_module
|
||||
@@ -81,6 +80,7 @@ rtran, K_rtran
|
||||
rtranif0, K_rtranif0
|
||||
rtranif1, K_rtranif1
|
||||
scalered, K_scalered
|
||||
signed, K_signed
|
||||
small, K_small
|
||||
specify, K_specify
|
||||
specparam, K_specparam
|
||||
@@ -109,4 +109,14 @@ while, K_while
|
||||
wire, K_wire
|
||||
wor, K_wor
|
||||
xnor, K_xnor
|
||||
xor, K_xor
|
||||
xor, K_xor
|
||||
%%
|
||||
|
||||
int lexor_keyword_code(const char*str, unsigned nstr)
|
||||
{
|
||||
const struct lexor_keyword*rc = check_identifier(str, nstr);
|
||||
if (rc == 0)
|
||||
return IDENTIFIER;
|
||||
else
|
||||
return rc->tokenType;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,33 @@
|
||||
#ifndef __lexor_keyword_H
|
||||
#define __lexor_keyword_H
|
||||
/*
|
||||
* Copyright (c) 2000 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) && !defined(macintosh)
|
||||
#ident "$Id: lexor_keyword.h,v 1.1 2000/03/12 17:09:41 steve Exp $"
|
||||
#endif
|
||||
|
||||
extern int lexor_keyword_code (const char*str, unsigned len);
|
||||
|
||||
/*
|
||||
* $Log: lexor_keyword.h,v $
|
||||
* Revision 1.1 2000/03/12 17:09:41 steve
|
||||
* Support localparam.
|
||||
*
|
||||
*/
|
||||
#endif
|
||||
@@ -0,0 +1,64 @@
|
||||
/*
|
||||
* Copyright (c) 2000 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) && !defined(macintosh)
|
||||
#ident "$Id: link_const.cc,v 1.2 2000/05/07 04:37:56 steve Exp $"
|
||||
#endif
|
||||
|
||||
# include "netlist.h"
|
||||
# include "netmisc.h"
|
||||
|
||||
NetConst* link_const_value(Link&pin, unsigned&idx)
|
||||
{
|
||||
NetConst*robj = 0;
|
||||
unsigned ridx = 0;
|
||||
|
||||
for (Link*cur = pin.next_link()
|
||||
; *cur != pin ; cur = cur->next_link()) {
|
||||
|
||||
NetConst*tmp;
|
||||
if ((tmp = dynamic_cast<NetConst*>(cur->get_obj())) == 0)
|
||||
continue;
|
||||
|
||||
if (robj != 0)
|
||||
continue;
|
||||
|
||||
robj = tmp;
|
||||
ridx = cur->get_pin();
|
||||
}
|
||||
|
||||
idx = ridx;
|
||||
return robj;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* $Log: link_const.cc,v $
|
||||
* Revision 1.2 2000/05/07 04:37:56 steve
|
||||
* Carry strength values from Verilog source to the
|
||||
* pform and netlist for gates.
|
||||
*
|
||||
* Change vvm constants to use the driver_t to drive
|
||||
* a constant value. This works better if there are
|
||||
* multiple drivers on a signal.
|
||||
*
|
||||
* Revision 1.1 2000/04/20 00:28:03 steve
|
||||
* Catch some simple identity compareoptimizations.
|
||||
*
|
||||
*/
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
|
||||
const char COPYRIGHT[] =
|
||||
"Copyright (c) 1998-1999 Stephen Williams ([email protected])";
|
||||
"Copyright (c) 1998-2000 Stephen Williams ([email protected])";
|
||||
|
||||
/*
|
||||
* This source code is free software; you can redistribute it
|
||||
@@ -18,8 +18,8 @@ const char COPYRIGHT[] =
|
||||
* 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: main.cc,v 1.26 1999/11/29 17:02:21 steve Exp $"
|
||||
#if !defined(WINNT) && !defined(macintosh)
|
||||
#ident "$Id: main.cc,v 1.33 2000/05/08 05:29:43 steve Exp $"
|
||||
#endif
|
||||
|
||||
const char NOTICE[] =
|
||||
@@ -50,6 +50,7 @@ const char NOTICE[] =
|
||||
# include "pform.h"
|
||||
# include "netlist.h"
|
||||
# include "target.h"
|
||||
# include "compiler.h"
|
||||
|
||||
const char VERSION[] = "$Name: $ $State: Exp $";
|
||||
|
||||
@@ -58,6 +59,12 @@ string start_module = "";
|
||||
|
||||
map<string,string> flags;
|
||||
|
||||
/*
|
||||
* These are the warning enable flags.
|
||||
*/
|
||||
bool warn_implicit = false;
|
||||
|
||||
|
||||
static void parm_to_flagmap(const string&flag)
|
||||
{
|
||||
string key, value;
|
||||
@@ -81,12 +88,9 @@ extern Design* elaborate(const map<string,Module*>&modules,
|
||||
|
||||
extern void cprop(Design*des);
|
||||
extern void propinit(Design*des);
|
||||
extern void sigfold(Design*des);
|
||||
extern void synth(Design*des);
|
||||
extern void nobufz(Design*des);
|
||||
extern void nodangle(Design*des);
|
||||
extern void xnfio(Design*des);
|
||||
extern void xnfsyn(Design*des);
|
||||
|
||||
typedef void (*net_func)(Design*);
|
||||
static struct net_func_map {
|
||||
@@ -94,13 +98,10 @@ static struct net_func_map {
|
||||
void (*func)(Design*);
|
||||
} func_table[] = {
|
||||
{ "cprop", &cprop },
|
||||
{ "nobufz", &nobufz },
|
||||
{ "nodangle",&nodangle },
|
||||
{ "propinit",&propinit },
|
||||
{ "sigfold", &sigfold },
|
||||
{ "synth", &synth },
|
||||
{ "xnfio", &xnfio },
|
||||
{ "xnfsyn", &xnfsyn },
|
||||
{ 0, 0 }
|
||||
};
|
||||
|
||||
@@ -120,11 +121,14 @@ int main(int argc, char*argv[])
|
||||
const char* net_path = 0;
|
||||
const char* out_path = 0;
|
||||
const char* pf_path = 0;
|
||||
const char* warn_en = "";
|
||||
int opt;
|
||||
unsigned flag_errors = 0;
|
||||
queue<net_func> net_func_queue;
|
||||
|
||||
while ((opt = getopt(argc, argv, "F:f:hN:o:P:s:t:v")) != EOF) switch (opt) {
|
||||
flags["VPI_MODULE_LIST"] = "system";
|
||||
|
||||
while ((opt = getopt(argc, argv, "F:f:hm:N:o:P:s:t:vW:")) != EOF) switch (opt) {
|
||||
case 'F': {
|
||||
net_func tmp = name_to_net_func(optarg);
|
||||
if (tmp == 0) {
|
||||
@@ -142,6 +146,9 @@ int main(int argc, char*argv[])
|
||||
case 'h':
|
||||
help_flag = true;
|
||||
break;
|
||||
case 'm':
|
||||
flags["VPI_MODULE_LIST"] = flags["VPI_MODULE_LIST"]+","+optarg;
|
||||
break;
|
||||
case 'N':
|
||||
net_path = optarg;
|
||||
break;
|
||||
@@ -162,6 +169,9 @@ int main(int argc, char*argv[])
|
||||
cout << COPYRIGHT << endl;
|
||||
cout << endl << NOTICE << endl;
|
||||
return 0;
|
||||
case 'W':
|
||||
warn_en = optarg;
|
||||
break;
|
||||
default:
|
||||
flag_errors += 1;
|
||||
break;
|
||||
@@ -185,6 +195,15 @@ int main(int argc, char*argv[])
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Scan the warnings enable string for warning flags. */
|
||||
for (const char*cp = warn_en ; *cp ; cp += 1) switch (*cp) {
|
||||
case 'i':
|
||||
warn_implicit = true;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
/* Parse the input. Make the pform. */
|
||||
map<string,Module*> modules;
|
||||
map<string,PUdp*> primitives;
|
||||
@@ -284,6 +303,30 @@ int main(int argc, char*argv[])
|
||||
|
||||
/*
|
||||
* $Log: main.cc,v $
|
||||
* Revision 1.33 2000/05/08 05:29:43 steve
|
||||
* no need for nobufz functor.
|
||||
*
|
||||
* Revision 1.32 2000/05/03 22:14:31 steve
|
||||
* More features of ivl available through iverilog.
|
||||
*
|
||||
* Revision 1.31 2000/04/12 20:02:53 steve
|
||||
* Finally remove the NetNEvent and NetPEvent classes,
|
||||
* Get synthesis working with the NetEvWait class,
|
||||
* and get started supporting multiple events in a
|
||||
* wait in vvm.
|
||||
*
|
||||
* Revision 1.30 2000/03/17 21:50:25 steve
|
||||
* Switch to control warnings.
|
||||
*
|
||||
* Revision 1.29 2000/02/23 02:56:54 steve
|
||||
* Macintosh compilers do not support ident.
|
||||
*
|
||||
* Revision 1.28 2000/01/13 05:11:25 steve
|
||||
* Support for multiple VPI modules.
|
||||
*
|
||||
* Revision 1.27 1999/12/30 17:37:14 steve
|
||||
* Remove the now useless sigfold functor.
|
||||
*
|
||||
* Revision 1.26 1999/11/29 17:02:21 steve
|
||||
* include getopt if present.
|
||||
*
|
||||
|
||||
@@ -16,8 +16,8 @@
|
||||
* 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: mangle.cc,v 1.2 1999/02/15 05:52:50 steve Exp $"
|
||||
#if !defined(WINNT) && !defined(macintosh)
|
||||
#ident "$Id: mangle.cc,v 1.3 2000/02/23 02:56:54 steve Exp $"
|
||||
#endif
|
||||
|
||||
# include "target.h"
|
||||
@@ -63,6 +63,9 @@ string mangle(const string&str)
|
||||
|
||||
/*
|
||||
* $Log: mangle.cc,v $
|
||||
* Revision 1.3 2000/02/23 02:56:54 steve
|
||||
* Macintosh compilers do not support ident.
|
||||
*
|
||||
* Revision 1.2 1999/02/15 05:52:50 steve
|
||||
* Mangle that handles device instance numbers.
|
||||
*
|
||||
|
||||
@@ -0,0 +1,46 @@
|
||||
#ifndef __named_H
|
||||
#define __named_H
|
||||
/*
|
||||
* Copyright (c) 2000 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) && !defined(macintosh)
|
||||
#ident "$Id: named.h,v 1.2 2000/02/23 02:56:54 steve Exp $"
|
||||
#endif
|
||||
|
||||
# include <string>
|
||||
|
||||
/*
|
||||
* There are lots of places where names are attached to objects. This
|
||||
* simple template expresses the lot.
|
||||
*/
|
||||
|
||||
template <class T> struct named {
|
||||
string name;
|
||||
T parm;
|
||||
};
|
||||
|
||||
/*
|
||||
* $Log: named.h,v $
|
||||
* Revision 1.2 2000/02/23 02:56:54 steve
|
||||
* Macintosh compilers do not support ident.
|
||||
*
|
||||
* Revision 1.1 2000/01/09 05:50:49 steve
|
||||
* Support named parameter override lists.
|
||||
*
|
||||
*/
|
||||
#endif
|
||||
+530
@@ -0,0 +1,530 @@
|
||||
/*
|
||||
* Copyright (c) 2000Stephen 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) && !defined(macintosh)
|
||||
#ident "$Id: net_design.cc,v 1.8 2000/05/02 16:27:38 steve Exp $"
|
||||
#endif
|
||||
|
||||
/*
|
||||
* This source file contains all the implementations of the Design
|
||||
* class declared in netlist.h.
|
||||
*/
|
||||
|
||||
# include "netlist.h"
|
||||
# include "util.h"
|
||||
# include <strstream>
|
||||
|
||||
static string parse_last_name(string&path)
|
||||
{
|
||||
unsigned pos = path.rfind('.');
|
||||
if (pos > path.length()) {
|
||||
string res = path;
|
||||
path = "";
|
||||
return res;
|
||||
}
|
||||
|
||||
string res = path.substr(pos+1, path.length());
|
||||
path = path.substr(0, pos);
|
||||
return res;
|
||||
}
|
||||
|
||||
Design:: Design()
|
||||
: errors(0), root_scope_(0), nodes_(0), procs_(0), lcounter_(0)
|
||||
{
|
||||
}
|
||||
|
||||
Design::~Design()
|
||||
{
|
||||
}
|
||||
|
||||
string Design::local_symbol(const string&path)
|
||||
{
|
||||
strstream res;
|
||||
res << "_L" << (lcounter_++) << ends;
|
||||
|
||||
return path + "." + res.str();
|
||||
}
|
||||
|
||||
NetScope* Design::make_root_scope(const string&root)
|
||||
{
|
||||
assert(root_scope_ == 0);
|
||||
root_scope_ = new NetScope(root);
|
||||
return root_scope_;
|
||||
}
|
||||
|
||||
NetScope* Design::find_root_scope()
|
||||
{
|
||||
assert(root_scope_);
|
||||
return root_scope_;
|
||||
}
|
||||
|
||||
/*
|
||||
* This method locates a scope in the design, given its rooted
|
||||
* heirarchical name. Each component of the key is used to scan one
|
||||
* more step down the tree until the name runs out or the search
|
||||
* fails.
|
||||
*/
|
||||
NetScope* Design::find_scope(const string&key) const
|
||||
{
|
||||
if (key == root_scope_->name())
|
||||
return root_scope_;
|
||||
|
||||
string path = key;
|
||||
string root = parse_first_name(path);
|
||||
|
||||
NetScope*cur = root_scope_;
|
||||
if (root != cur->name())
|
||||
return 0;
|
||||
|
||||
while (cur) {
|
||||
string next = parse_first_name(path);
|
||||
cur = cur->child(next);
|
||||
if (path == "") return cur;
|
||||
}
|
||||
|
||||
return cur;
|
||||
}
|
||||
|
||||
/*
|
||||
* This is a relative lookup of a scope by name. The starting point is
|
||||
* the scope parameter is the place within which I start looking for
|
||||
* the scope. If I do not find the scope within the passed scope,
|
||||
* start looking in parent scopes until I find it, or I run out of
|
||||
* parent scopes.
|
||||
*/
|
||||
NetScope* Design::find_scope(NetScope*scope, const string&name) const
|
||||
{
|
||||
assert(scope);
|
||||
|
||||
for ( ; scope ; scope = scope->parent()) {
|
||||
string path = name;
|
||||
string key = parse_first_name(path);
|
||||
|
||||
NetScope*cur = scope;
|
||||
do {
|
||||
cur = cur->child(key);
|
||||
if (cur == 0) break;
|
||||
key = parse_first_name(path);
|
||||
} while (key != "");
|
||||
|
||||
if (cur) return cur;
|
||||
}
|
||||
|
||||
// Last chance. Look for the name starting at the root.
|
||||
return find_scope(name);
|
||||
}
|
||||
|
||||
/*
|
||||
* Find a parameter from within a specified context. If the name is
|
||||
* not here, keep looking up until I run out of up to look at. The
|
||||
* method works by scanning scopes, starting with the passed scope and
|
||||
* working up towards the root, looking for the named parameter. The
|
||||
* name in this case can be hierarchical, so there is an inner loop to
|
||||
* follow the scopes of the name down to to key.
|
||||
*/
|
||||
const NetExpr* Design::find_parameter(const NetScope*scope,
|
||||
const string&name) const
|
||||
{
|
||||
for ( ; scope ; scope = scope->parent()) {
|
||||
string path = name;
|
||||
string key = parse_first_name(path);
|
||||
|
||||
const NetScope*cur = scope;
|
||||
while (path != "") {
|
||||
cur = cur->child(key);
|
||||
if (cur == 0) break;
|
||||
key = parse_first_name(path);
|
||||
}
|
||||
|
||||
if (cur == 0) continue;
|
||||
|
||||
if (const NetExpr*res = cur->get_parameter(key))
|
||||
return res;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* This method runs through the scope, noticing the defparam
|
||||
* statements that were collected during the elaborate_scope pass and
|
||||
* applying them to the target parameters. The implementation actually
|
||||
* works by using a specialized method from the NetScope class that
|
||||
* does all the work for me.
|
||||
*/
|
||||
void Design::run_defparams()
|
||||
{
|
||||
root_scope_->run_defparams(this);
|
||||
}
|
||||
|
||||
void NetScope::run_defparams(Design*des)
|
||||
{
|
||||
NetScope*cur = sub_;
|
||||
while (cur) {
|
||||
cur->run_defparams(des);
|
||||
cur = cur->sib_;
|
||||
}
|
||||
|
||||
map<string,NetExpr*>::const_iterator pp;
|
||||
for (pp = defparams.begin() ; pp != defparams.end() ; pp ++ ) {
|
||||
NetExpr*val = (*pp).second;
|
||||
string path = (*pp).first;
|
||||
string name = parse_last_name(path);
|
||||
|
||||
NetScope*targ_scope = des->find_scope(this, path);
|
||||
if (targ_scope == 0) {
|
||||
cerr << val->get_line() << ": warning: scope of " <<
|
||||
path << "." << name << " not found." << endl;
|
||||
continue;
|
||||
}
|
||||
|
||||
val = targ_scope->set_parameter(name, val);
|
||||
if (val == 0) {
|
||||
cerr << val->get_line() << ": warning: parameter "
|
||||
<< name << " not found in " << targ_scope->name()
|
||||
<< "." << endl;
|
||||
} else {
|
||||
delete val;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Design::evaluate_parameters()
|
||||
{
|
||||
root_scope_->evaluate_parameters(this);
|
||||
}
|
||||
|
||||
void NetScope::evaluate_parameters(Design*des)
|
||||
{
|
||||
NetScope*cur = sub_;
|
||||
while (cur) {
|
||||
cur->evaluate_parameters(des);
|
||||
cur = cur->sib_;
|
||||
}
|
||||
|
||||
|
||||
// Evaluate the parameter values. The parameter expressions
|
||||
// have already been elaborated and replaced by the scope
|
||||
// scanning code. Now the parameter expression can be fully
|
||||
// evaluated, or it cannot be evaluated at all.
|
||||
|
||||
typedef map<string,NetExpr*>::iterator mparm_it_t;
|
||||
|
||||
for (mparm_it_t cur = parameters_.begin()
|
||||
; cur != parameters_.end() ; cur ++) {
|
||||
|
||||
// Get the NetExpr for the parameter.
|
||||
NetExpr*expr = (*cur).second;
|
||||
assert(expr);
|
||||
|
||||
// If it's already a NetEConst, then this parameter is done.
|
||||
if (dynamic_cast<const NetEConst*>(expr))
|
||||
continue;
|
||||
|
||||
// Try to evaluate the expression.
|
||||
NetExpr*nexpr = expr->eval_tree();
|
||||
if (nexpr == 0) {
|
||||
cerr << (*cur).second->get_line() << ": internal error: "
|
||||
"unable to evaluate parm expression: " <<
|
||||
*expr << endl;
|
||||
des->errors += 1;
|
||||
continue;
|
||||
}
|
||||
|
||||
// The evaluate worked, replace the old expression with
|
||||
// this constant value.
|
||||
assert(nexpr);
|
||||
delete expr;
|
||||
(*cur).second = nexpr;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
string Design::get_flag(const string&key) const
|
||||
{
|
||||
map<string,string>::const_iterator tmp = flags_.find(key);
|
||||
if (tmp == flags_.end())
|
||||
return "";
|
||||
else
|
||||
return (*tmp).second;
|
||||
}
|
||||
|
||||
/*
|
||||
* This method looks for a string given a current context as a
|
||||
* starting point.
|
||||
*/
|
||||
NetNet* Design::find_signal(NetScope*scope, const string&name)
|
||||
{
|
||||
assert(scope);
|
||||
|
||||
/* If the name has a path attached to it, parse it off and use
|
||||
that to locate the desired scope. */
|
||||
string path = name;
|
||||
string key = parse_last_name(path);
|
||||
if (path != "")
|
||||
scope = find_scope(scope, path);
|
||||
|
||||
while (scope) {
|
||||
|
||||
if (NetNet*net = scope->find_signal(key))
|
||||
return net;
|
||||
scope = scope->parent();
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
NetMemory* Design::find_memory(NetScope*scope, const string&name)
|
||||
{
|
||||
assert(scope);
|
||||
|
||||
/* If the name has a path attached to it, parse it off and use
|
||||
that to locate the desired scope. */
|
||||
string path = name;
|
||||
string key = parse_last_name(path);
|
||||
if (path != "")
|
||||
scope = find_scope(scope, path);
|
||||
|
||||
while (scope) {
|
||||
|
||||
if (NetMemory*mem = scope->find_memory(key))
|
||||
return mem;
|
||||
scope = scope->parent();
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void Design::find_symbol(NetScope*scope, const string&name,
|
||||
NetNet*&sig, NetMemory*&mem)
|
||||
{
|
||||
sig = 0;
|
||||
mem = 0;
|
||||
|
||||
|
||||
/* If the name has a path attached to it, parse it off and use
|
||||
that to locate the desired scope. Then locate the key
|
||||
within that scope. */
|
||||
string path = name;
|
||||
string key = parse_last_name(path);
|
||||
if (path != "")
|
||||
scope = find_scope(scope, path);
|
||||
|
||||
|
||||
/* If there is no path, then just search upwards for the key. */
|
||||
while (scope) {
|
||||
|
||||
if (NetNet*cur = scope->find_signal(key)) {
|
||||
sig = cur;
|
||||
return;
|
||||
}
|
||||
|
||||
if (NetMemory*cur = scope->find_memory(key)) {
|
||||
mem = cur;
|
||||
return;
|
||||
}
|
||||
|
||||
scope = scope->parent();
|
||||
}
|
||||
}
|
||||
|
||||
void Design::add_function(const string&key, NetFuncDef*def)
|
||||
{
|
||||
funcs_[key] = def;
|
||||
}
|
||||
|
||||
NetFuncDef* Design::find_function(const string&path, const string&name)
|
||||
{
|
||||
string root = path;
|
||||
for (;;) {
|
||||
string key = root + "." + name;
|
||||
map<string,NetFuncDef*>::const_iterator cur = funcs_.find(key);
|
||||
if (cur != funcs_.end())
|
||||
return (*cur).second;
|
||||
|
||||
unsigned pos = root.rfind('.');
|
||||
if (pos > root.length())
|
||||
break;
|
||||
|
||||
root = root.substr(0, pos);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
NetFuncDef* Design::find_function(const string&key)
|
||||
{
|
||||
map<string,NetFuncDef*>::const_iterator cur = funcs_.find(key);
|
||||
if (cur != funcs_.end())
|
||||
return (*cur).second;
|
||||
return 0;
|
||||
}
|
||||
|
||||
void Design::add_task(const string&key, NetTaskDef*def)
|
||||
{
|
||||
tasks_[key] = def;
|
||||
}
|
||||
|
||||
NetTaskDef* Design::find_task(const string&path, const string&name)
|
||||
{
|
||||
string root = path;
|
||||
for (;;) {
|
||||
string key = root + "." + name;
|
||||
map<string,NetTaskDef*>::const_iterator cur = tasks_.find(key);
|
||||
if (cur != tasks_.end())
|
||||
return (*cur).second;
|
||||
|
||||
unsigned pos = root.rfind('.');
|
||||
if (pos > root.length())
|
||||
break;
|
||||
|
||||
root = root.substr(0, pos);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
NetTaskDef* Design::find_task(const string&key)
|
||||
{
|
||||
map<string,NetTaskDef*>::const_iterator cur = tasks_.find(key);
|
||||
if (cur == tasks_.end())
|
||||
return 0;
|
||||
|
||||
return (*cur).second;
|
||||
}
|
||||
|
||||
void Design::add_node(NetNode*net)
|
||||
{
|
||||
assert(net->design_ == 0);
|
||||
if (nodes_ == 0) {
|
||||
net->node_next_ = net;
|
||||
net->node_prev_ = net;
|
||||
} else {
|
||||
net->node_next_ = nodes_->node_next_;
|
||||
net->node_prev_ = nodes_;
|
||||
net->node_next_->node_prev_ = net;
|
||||
net->node_prev_->node_next_ = net;
|
||||
}
|
||||
nodes_ = net;
|
||||
net->design_ = this;
|
||||
}
|
||||
|
||||
void Design::del_node(NetNode*net)
|
||||
{
|
||||
assert(net->design_ == this);
|
||||
if (nodes_ == net)
|
||||
nodes_ = net->node_prev_;
|
||||
|
||||
if (nodes_ == net) {
|
||||
nodes_ = 0;
|
||||
} else {
|
||||
net->node_next_->node_prev_ = net->node_prev_;
|
||||
net->node_prev_->node_next_ = net->node_next_;
|
||||
}
|
||||
|
||||
net->design_ = 0;
|
||||
}
|
||||
|
||||
void Design::add_process(NetProcTop*pro)
|
||||
{
|
||||
pro->next_ = procs_;
|
||||
procs_ = pro;
|
||||
}
|
||||
|
||||
void Design::delete_process(NetProcTop*top)
|
||||
{
|
||||
assert(top);
|
||||
if (procs_ == top) {
|
||||
procs_ = top->next_;
|
||||
|
||||
} else {
|
||||
NetProcTop*cur = procs_;
|
||||
while (cur->next_ != top) {
|
||||
assert(cur->next_);
|
||||
cur = cur->next_;
|
||||
}
|
||||
|
||||
cur->next_ = top->next_;
|
||||
}
|
||||
|
||||
if (procs_idx_ == top)
|
||||
procs_idx_ = top->next_;
|
||||
|
||||
delete top;
|
||||
}
|
||||
|
||||
void Design::clear_node_marks()
|
||||
{
|
||||
if (nodes_ == 0)
|
||||
return;
|
||||
|
||||
NetNode*cur = nodes_;
|
||||
do {
|
||||
cur->set_mark(false);
|
||||
cur = cur->node_next_;
|
||||
} while (cur != nodes_);
|
||||
}
|
||||
|
||||
NetNode* Design::find_node(bool (*func)(const NetNode*))
|
||||
{
|
||||
if (nodes_ == 0)
|
||||
return 0;
|
||||
|
||||
NetNode*cur = nodes_->node_next_;
|
||||
do {
|
||||
if ((cur->test_mark() == false) && func(cur))
|
||||
return cur;
|
||||
|
||||
cur = cur->node_next_;
|
||||
} while (cur != nodes_->node_next_);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* $Log: net_design.cc,v $
|
||||
* Revision 1.8 2000/05/02 16:27:38 steve
|
||||
* Move signal elaboration to a seperate pass.
|
||||
*
|
||||
* Revision 1.7 2000/05/02 03:13:31 steve
|
||||
* Move memories to the NetScope object.
|
||||
*
|
||||
* Revision 1.6 2000/05/02 00:58:12 steve
|
||||
* Move signal tables to the NetScope class.
|
||||
*
|
||||
* Revision 1.5 2000/04/28 16:50:53 steve
|
||||
* Catch memory word parameters to tasks.
|
||||
*
|
||||
* Revision 1.4 2000/04/10 05:26:06 steve
|
||||
* All events now use the NetEvent class.
|
||||
*
|
||||
* Revision 1.3 2000/03/11 03:25:52 steve
|
||||
* Locate scopes in statements.
|
||||
*
|
||||
* Revision 1.2 2000/03/10 06:20:48 steve
|
||||
* Handle defparam to partial hierarchical names.
|
||||
*
|
||||
* Revision 1.1 2000/03/08 04:36:53 steve
|
||||
* Redesign the implementation of scopes and parameters.
|
||||
* I now generate the scopes and notice the parameters
|
||||
* in a separate pass over the pform. Once the scopes
|
||||
* are generated, I can process overrides and evalutate
|
||||
* paremeters before elaboration begins.
|
||||
*
|
||||
*/
|
||||
|
||||
+263
@@ -0,0 +1,263 @@
|
||||
/*
|
||||
* Copyright (c) 2000 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) && !defined(macintosh)
|
||||
#ident "$Id: net_event.cc,v 1.6 2000/04/18 04:50:20 steve Exp $"
|
||||
#endif
|
||||
|
||||
# include "netlist.h"
|
||||
|
||||
NetEvent::NetEvent(const string&n)
|
||||
: name_(n)
|
||||
{
|
||||
scope_ = 0;
|
||||
snext_ = 0;
|
||||
probes_ = 0;
|
||||
trig_ = 0;
|
||||
waitref_ = 0;
|
||||
}
|
||||
|
||||
NetEvent::~NetEvent()
|
||||
{
|
||||
assert(waitref_ == 0);
|
||||
if (scope_) scope_->rem_event(this);
|
||||
while (probes_) {
|
||||
NetEvProbe*tmp = probes_->enext_;
|
||||
delete probes_;
|
||||
tmp = probes_;
|
||||
}
|
||||
}
|
||||
|
||||
string NetEvent::name() const
|
||||
{
|
||||
return name_;
|
||||
}
|
||||
|
||||
string NetEvent::full_name() const
|
||||
{
|
||||
assert(scope_);
|
||||
return scope_->name() + "." + name_;
|
||||
}
|
||||
|
||||
unsigned NetEvent::nprobe() const
|
||||
{
|
||||
unsigned cnt = 0;
|
||||
NetEvProbe*cur = probes_;
|
||||
while (cur) {
|
||||
cnt += 1;
|
||||
cur = cur->enext_;
|
||||
}
|
||||
|
||||
return cnt;
|
||||
}
|
||||
|
||||
NetEvProbe* NetEvent::probe(unsigned idx)
|
||||
{
|
||||
NetEvProbe*cur = probes_;
|
||||
while (cur && idx) {
|
||||
cur = cur->enext_;
|
||||
idx -= 1;
|
||||
}
|
||||
return cur;
|
||||
}
|
||||
|
||||
unsigned NetEvent::ntrig() const
|
||||
{
|
||||
unsigned cnt = 0;
|
||||
NetEvTrig*cur = trig_;
|
||||
while (cur) {
|
||||
cnt += 1;
|
||||
cur = cur->enext_;
|
||||
}
|
||||
|
||||
return cnt;
|
||||
}
|
||||
|
||||
unsigned NetEvent::nwait() const
|
||||
{
|
||||
return waitref_;
|
||||
}
|
||||
|
||||
NetEvTrig::NetEvTrig(NetEvent*ev)
|
||||
: event_(ev)
|
||||
{
|
||||
enext_ = event_->trig_;
|
||||
event_->trig_ = this;
|
||||
}
|
||||
|
||||
NetEvTrig::~NetEvTrig()
|
||||
{
|
||||
if (event_->trig_ == this) {
|
||||
event_->trig_ = enext_;
|
||||
|
||||
} else {
|
||||
NetEvTrig*cur = event_->trig_;
|
||||
while (cur->enext_ != this) {
|
||||
assert(cur->enext_);
|
||||
cur = cur->enext_;
|
||||
}
|
||||
|
||||
cur->enext_ = this->enext_;
|
||||
}
|
||||
}
|
||||
|
||||
const NetEvent* NetEvTrig::event() const
|
||||
{
|
||||
return event_;
|
||||
}
|
||||
|
||||
NetEvProbe::NetEvProbe(const string&n, NetEvent*tgt,
|
||||
edge_t t, unsigned p)
|
||||
: NetNode(n, p), event_(tgt), edge_(t)
|
||||
{
|
||||
for (unsigned idx = 0 ; idx < p ; idx += 1) {
|
||||
pin(idx).set_dir(Link::INPUT);
|
||||
pin(idx).set_name("P", idx);
|
||||
}
|
||||
|
||||
enext_ = event_->probes_;
|
||||
event_->probes_ = this;
|
||||
}
|
||||
|
||||
NetEvProbe::~NetEvProbe()
|
||||
{
|
||||
if (event_->probes_ == this) {
|
||||
event_->probes_ = enext_;
|
||||
|
||||
} else {
|
||||
NetEvProbe*cur = event_->probes_;
|
||||
while (cur->enext_ != this) {
|
||||
assert(cur->enext_);
|
||||
cur = cur->enext_;
|
||||
}
|
||||
|
||||
cur->enext_ = this->enext_;
|
||||
}
|
||||
}
|
||||
|
||||
NetEvProbe::edge_t NetEvProbe::edge() const
|
||||
{
|
||||
return edge_;
|
||||
}
|
||||
|
||||
const NetEvent* NetEvProbe::event() const
|
||||
{
|
||||
return event_;
|
||||
}
|
||||
|
||||
NetEvWait::NetEvWait(NetProc*pr)
|
||||
: statement_(pr), nevents_(0), events_(0)
|
||||
{
|
||||
}
|
||||
|
||||
NetEvWait::~NetEvWait()
|
||||
{
|
||||
if (events_) {
|
||||
for (unsigned idx = 0 ; idx < nevents_ ; idx += 1) {
|
||||
NetEvent*tgt = events_[idx];
|
||||
tgt->waitref_ -= 1;
|
||||
}
|
||||
delete[]events_;
|
||||
}
|
||||
delete statement_;
|
||||
}
|
||||
|
||||
void NetEvWait::add_event(NetEvent*tgt)
|
||||
{
|
||||
assert(tgt);
|
||||
if (nevents_ == 0) {
|
||||
events_ = new NetEvent*[1];
|
||||
|
||||
} else {
|
||||
NetEvent**tmp = new NetEvent*[nevents_+1];
|
||||
for (unsigned idx = 0 ; idx < nevents_ ; idx += 1) {
|
||||
tmp[idx] = events_[idx];
|
||||
assert(tmp[idx] != tgt);
|
||||
}
|
||||
delete[]events_;
|
||||
events_ = tmp;
|
||||
}
|
||||
|
||||
events_[nevents_] = tgt;
|
||||
nevents_ += 1;
|
||||
|
||||
// Remember to tell the NetEvent that there is someone
|
||||
// pointing to it.
|
||||
tgt->waitref_ += 1;
|
||||
}
|
||||
|
||||
unsigned NetEvWait::nevents() const
|
||||
{
|
||||
return nevents_;
|
||||
}
|
||||
|
||||
const NetEvent* NetEvWait::event(unsigned idx) const
|
||||
{
|
||||
assert(idx < nevents_);
|
||||
return events_[idx];
|
||||
}
|
||||
|
||||
NetEvent* NetEvWait::event(unsigned idx)
|
||||
{
|
||||
assert(idx < nevents_);
|
||||
return events_[idx];
|
||||
}
|
||||
|
||||
NetProc* NetEvWait::statement()
|
||||
{
|
||||
return statement_;
|
||||
}
|
||||
|
||||
/*
|
||||
* $Log: net_event.cc,v $
|
||||
* Revision 1.6 2000/04/18 04:50:20 steve
|
||||
* Clean up unneeded NetEvent objects.
|
||||
*
|
||||
* Revision 1.5 2000/04/16 23:32:18 steve
|
||||
* Synthesis of comparator in expressions.
|
||||
*
|
||||
* Connect the NetEvent and related classes
|
||||
* together better.
|
||||
*
|
||||
* Revision 1.4 2000/04/12 20:02:53 steve
|
||||
* Finally remove the NetNEvent and NetPEvent classes,
|
||||
* Get synthesis working with the NetEvWait class,
|
||||
* and get started supporting multiple events in a
|
||||
* wait in vvm.
|
||||
*
|
||||
* Revision 1.3 2000/04/12 04:23:58 steve
|
||||
* Named events really should be expressed with PEIdent
|
||||
* objects in the pform,
|
||||
*
|
||||
* Handle named events within the mix of net events
|
||||
* and edges. As a unified lot they get caught together.
|
||||
* wait statements are broken into more complex statements
|
||||
* that include a conditional.
|
||||
*
|
||||
* Do not generate NetPEvent or NetNEvent objects in
|
||||
* elaboration. NetEvent, NetEvWait and NetEvProbe
|
||||
* take over those functions in the netlist.
|
||||
*
|
||||
* Revision 1.2 2000/04/10 05:26:06 steve
|
||||
* All events now use the NetEvent class.
|
||||
*
|
||||
* Revision 1.1 2000/04/04 03:20:15 steve
|
||||
* Simulate named event trigger and waits.
|
||||
*
|
||||
*/
|
||||
|
||||
+125
@@ -0,0 +1,125 @@
|
||||
/*
|
||||
* Copyright (c) 2000 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.
|
||||
*
|
||||
* 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) && !defined(macintosh)
|
||||
#ident "$Id: net_force.cc,v 1.2 2000/05/12 01:22:41 steve Exp $"
|
||||
#endif
|
||||
|
||||
/*
|
||||
* This file contains implementatsion of the NetForce, NetRelease,
|
||||
* NetCAssign and NetDeassign classes. These are similar or related in
|
||||
* that they handle the procedural continuous assign and force
|
||||
* statements.
|
||||
*/
|
||||
|
||||
# include "netlist.h"
|
||||
# include <assert.h>
|
||||
|
||||
/*
|
||||
* Construct the procedural continuous assignment statement. This is a
|
||||
* bit different from a normal assignment because the the lval is only
|
||||
* intermittantly connected. The deassign in particular disconnects
|
||||
* the signals when they are not being assigned anymore. Because of
|
||||
* this, there is no other reference to the lval to make it stay put
|
||||
* so we increment the eref.
|
||||
*
|
||||
* XXXX I'm not sure this is the right way. Perhaps I should create
|
||||
* output pins to connect to the netlist? But that would cause the
|
||||
* link ring to grow, and that is not quite correct either. Hmm...
|
||||
*/
|
||||
NetCAssign::NetCAssign(const string&n, NetNet*l)
|
||||
: NetNode(n, l->pin_count()), lval_(l)
|
||||
{
|
||||
lval_->incr_eref();
|
||||
for (unsigned idx = 0 ; idx < pin_count() ; idx += 1) {
|
||||
pin(idx).set_dir(Link::INPUT);
|
||||
pin(idx).set_name("I", idx);
|
||||
}
|
||||
}
|
||||
|
||||
NetCAssign::~NetCAssign()
|
||||
{
|
||||
lval_->decr_eref();
|
||||
}
|
||||
|
||||
const Link& NetCAssign::lval_pin(unsigned idx) const
|
||||
{
|
||||
assert(idx < lval_->pin_count());
|
||||
return lval_->pin(idx);
|
||||
}
|
||||
|
||||
NetDeassign::NetDeassign(NetNet*l)
|
||||
: lval_(l)
|
||||
{
|
||||
lval_->incr_eref();
|
||||
}
|
||||
|
||||
NetDeassign::~NetDeassign()
|
||||
{
|
||||
lval_->decr_eref();
|
||||
}
|
||||
|
||||
const NetNet*NetDeassign::lval() const
|
||||
{
|
||||
return lval_;
|
||||
}
|
||||
|
||||
NetForce::NetForce(const string&n, NetNet*l)
|
||||
: NetNode(n, l->pin_count()), lval_(l)
|
||||
{
|
||||
for (unsigned idx = 0 ; idx < pin_count() ; idx += 1) {
|
||||
pin(idx).set_dir(Link::INPUT);
|
||||
pin(idx).set_name("I", idx);
|
||||
}
|
||||
}
|
||||
|
||||
NetForce::~NetForce()
|
||||
{
|
||||
}
|
||||
|
||||
const Link& NetForce::lval_pin(unsigned idx) const
|
||||
{
|
||||
assert(idx < lval_->pin_count());
|
||||
return lval_->pin(idx);
|
||||
}
|
||||
|
||||
NetRelease::NetRelease(NetNet*l)
|
||||
: lval_(l)
|
||||
{
|
||||
}
|
||||
|
||||
NetRelease::~NetRelease()
|
||||
{
|
||||
}
|
||||
|
||||
const NetNet*NetRelease::lval() const
|
||||
{
|
||||
return lval_;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* $Log: net_force.cc,v $
|
||||
* Revision 1.2 2000/05/12 01:22:41 steve
|
||||
* NetCAssign needs to incr_eref its lval to lock it down.
|
||||
*
|
||||
* Revision 1.1 2000/05/11 23:37:27 steve
|
||||
* Add support for procedural continuous assignment.
|
||||
*
|
||||
*/
|
||||
|
||||
+303
@@ -0,0 +1,303 @@
|
||||
/*
|
||||
* Copyright (c) 2000 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) && !defined(macintosh)
|
||||
#ident "$Id: net_scope.cc,v 1.6 2000/05/02 03:13:31 steve Exp $"
|
||||
#endif
|
||||
|
||||
# include "netlist.h"
|
||||
# include <strstream>
|
||||
|
||||
/*
|
||||
* The NetScope class keeps a scope tree organized. Each node of the
|
||||
* scope tree points to its parent, its right sibling and its leftmost
|
||||
* child. The root node has no parent or siblings. The node stores the
|
||||
* name of the scope. The complete hierarchical name of the scope is
|
||||
* formed by appending the path of scopes from the root to the scope
|
||||
* in question.
|
||||
*/
|
||||
NetScope::NetScope(const string&n)
|
||||
: type_(NetScope::MODULE), name_(n), up_(0), sib_(0), sub_(0)
|
||||
{
|
||||
memories_ = 0;
|
||||
signals_ = 0;
|
||||
events_ = 0;
|
||||
lcounter_ = 0;
|
||||
}
|
||||
|
||||
NetScope::NetScope(NetScope*up, const string&n, NetScope::TYPE t)
|
||||
: type_(t), name_(n), up_(up), sib_(0), sub_(0)
|
||||
{
|
||||
memories_ = 0;
|
||||
signals_ = 0;
|
||||
events_ = 0;
|
||||
sib_ = up_->sub_;
|
||||
up_->sub_ = this;
|
||||
}
|
||||
|
||||
NetScope::~NetScope()
|
||||
{
|
||||
assert(sib_ == 0);
|
||||
assert(sub_ == 0);
|
||||
lcounter_ = 0;
|
||||
}
|
||||
|
||||
NetExpr* NetScope::set_parameter(const string&key, NetExpr*expr)
|
||||
{
|
||||
NetExpr*&ref = parameters_[key];
|
||||
NetExpr* res = ref;
|
||||
ref = expr;
|
||||
return res;
|
||||
}
|
||||
|
||||
NetExpr* NetScope::set_localparam(const string&key, NetExpr*expr)
|
||||
{
|
||||
NetExpr*&ref = localparams_[key];
|
||||
NetExpr* res = ref;
|
||||
ref = expr;
|
||||
return res;
|
||||
}
|
||||
|
||||
const NetExpr* NetScope::get_parameter(const string&key) const
|
||||
{
|
||||
map<string,NetExpr*>::const_iterator idx;
|
||||
|
||||
idx = parameters_.find(key);
|
||||
if (idx != parameters_.end())
|
||||
return (*idx).second;
|
||||
|
||||
idx = localparams_.find(key);
|
||||
if (idx != localparams_.end())
|
||||
return (*idx).second;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
NetScope::TYPE NetScope::type() const
|
||||
{
|
||||
return type_;
|
||||
}
|
||||
|
||||
string NetScope::basename() const
|
||||
{
|
||||
return name_;
|
||||
}
|
||||
|
||||
string NetScope::name() const
|
||||
{
|
||||
if (up_)
|
||||
return up_->name() + "." + name_;
|
||||
else
|
||||
return name_;
|
||||
}
|
||||
|
||||
void NetScope::add_event(NetEvent*ev)
|
||||
{
|
||||
assert(ev->scope_ == 0);
|
||||
ev->scope_ = this;
|
||||
ev->snext_ = events_;
|
||||
events_ = ev;
|
||||
}
|
||||
|
||||
void NetScope::rem_event(NetEvent*ev)
|
||||
{
|
||||
assert(ev->scope_ == this);
|
||||
ev->scope_ = 0;
|
||||
if (events_ == ev) {
|
||||
events_ = ev->snext_;
|
||||
|
||||
} else {
|
||||
NetEvent*cur = events_;
|
||||
while (cur->snext_ != ev) {
|
||||
assert(cur->snext_);
|
||||
cur = cur->snext_;
|
||||
}
|
||||
cur->snext_ = ev->snext_;
|
||||
}
|
||||
|
||||
ev->snext_ = 0;
|
||||
}
|
||||
|
||||
|
||||
NetEvent* NetScope::find_event(const string&name)
|
||||
{
|
||||
for (NetEvent*cur = events_; cur ; cur = cur->snext_)
|
||||
if (cur->name() == name)
|
||||
return cur;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void NetScope::add_signal(NetNet*net)
|
||||
{
|
||||
if (signals_ == 0) {
|
||||
net->sig_next_ = net;
|
||||
net->sig_prev_ = net;
|
||||
} else {
|
||||
net->sig_next_ = signals_->sig_next_;
|
||||
net->sig_prev_ = signals_;
|
||||
net->sig_next_->sig_prev_ = net;
|
||||
net->sig_prev_->sig_next_ = net;
|
||||
}
|
||||
signals_ = net;
|
||||
}
|
||||
|
||||
void NetScope::rem_signal(NetNet*net)
|
||||
{
|
||||
assert(net->scope_ == this);
|
||||
if (signals_ == net)
|
||||
signals_ = net->sig_prev_;
|
||||
|
||||
if (signals_ == net) {
|
||||
signals_ = 0;
|
||||
} else {
|
||||
net->sig_prev_->sig_next_ = net->sig_next_;
|
||||
net->sig_next_->sig_prev_ = net->sig_prev_;
|
||||
}
|
||||
}
|
||||
|
||||
NetNet* NetScope::find_signal(const string&key)
|
||||
{
|
||||
if (signals_ == 0)
|
||||
return 0;
|
||||
|
||||
string fulname = name()+"."+key;
|
||||
NetNet*cur = signals_;
|
||||
do {
|
||||
if (cur->name() == fulname)
|
||||
return cur;
|
||||
cur = cur->sig_prev_;
|
||||
} while (cur != signals_);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void NetScope::add_memory(NetMemory*mem)
|
||||
{
|
||||
if (memories_ == 0) {
|
||||
mem->snext_ = mem;
|
||||
mem->sprev_ = mem;
|
||||
} else {
|
||||
mem->snext_ = memories_->snext_;
|
||||
mem->sprev_ = memories_;
|
||||
mem->snext_->sprev_ = mem;
|
||||
mem->sprev_->snext_ = mem;
|
||||
}
|
||||
memories_ = mem;
|
||||
mem->scope_ = this;
|
||||
}
|
||||
|
||||
void NetScope::rem_memory(NetMemory*mem)
|
||||
{
|
||||
assert(mem->scope_ == this);
|
||||
if (memories_ == mem)
|
||||
memories_ = mem->sprev_;
|
||||
|
||||
if (memories_ == mem) {
|
||||
memories_ = 0;
|
||||
} else {
|
||||
mem->sprev_->snext_ = mem->snext_;
|
||||
mem->snext_->sprev_ = mem->sprev_;
|
||||
}
|
||||
mem->scope_ = 0;
|
||||
}
|
||||
|
||||
NetMemory* NetScope::find_memory(const string&key)
|
||||
{
|
||||
if (memories_ == 0)
|
||||
return 0;
|
||||
|
||||
string fulname = name()+"."+key;
|
||||
NetMemory*cur = memories_;
|
||||
do {
|
||||
if (cur->name() == fulname)
|
||||
return cur;
|
||||
cur = cur->sprev_;
|
||||
} while (cur != memories_);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* This method locates a child scope by name. The name is the simple
|
||||
* name of the child, no heirarchy is searched.
|
||||
*/
|
||||
NetScope* NetScope::child(const string&name)
|
||||
{
|
||||
if (sub_ == 0) return 0;
|
||||
|
||||
NetScope*cur = sub_;
|
||||
while (cur->name_ != name) {
|
||||
if (cur->sib_ == 0) return 0;
|
||||
cur = cur->sib_;
|
||||
}
|
||||
|
||||
return cur;
|
||||
}
|
||||
|
||||
const NetScope* NetScope::child(const string&name) const
|
||||
{
|
||||
if (sub_ == 0) return 0;
|
||||
|
||||
NetScope*cur = sub_;
|
||||
while (cur->name_ != name) {
|
||||
if (cur->sib_ == 0) return 0;
|
||||
cur = cur->sib_;
|
||||
}
|
||||
|
||||
return cur;
|
||||
}
|
||||
|
||||
NetScope* NetScope::parent()
|
||||
{
|
||||
return up_;
|
||||
}
|
||||
|
||||
const NetScope* NetScope::parent() const
|
||||
{
|
||||
return up_;
|
||||
}
|
||||
|
||||
string NetScope::local_symbol()
|
||||
{
|
||||
strstream res;
|
||||
res << "_l" << (lcounter_++) << ends;
|
||||
return res.str();
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* $Log: net_scope.cc,v $
|
||||
* Revision 1.6 2000/05/02 03:13:31 steve
|
||||
* Move memories to the NetScope object.
|
||||
*
|
||||
* Revision 1.5 2000/05/02 00:58:12 steve
|
||||
* Move signal tables to the NetScope class.
|
||||
*
|
||||
* Revision 1.4 2000/04/18 04:50:20 steve
|
||||
* Clean up unneeded NetEvent objects.
|
||||
*
|
||||
* Revision 1.3 2000/04/10 05:26:06 steve
|
||||
* All events now use the NetEvent class.
|
||||
*
|
||||
* Revision 1.2 2000/04/09 17:04:56 steve
|
||||
* uninitialized event_ list.
|
||||
*
|
||||
* Revision 1.1 2000/04/04 03:20:15 steve
|
||||
* Simulate named event trigger and waits.
|
||||
*
|
||||
*/
|
||||
|
||||
+205
@@ -0,0 +1,205 @@
|
||||
/*
|
||||
* Copyright (c) 2000 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) && !defined(macintosh)
|
||||
#ident "$Id: net_udp.cc,v 1.1 2000/03/29 04:37:11 steve Exp $"
|
||||
#endif
|
||||
|
||||
# include "netlist.h"
|
||||
|
||||
NetUDP::NetUDP(const string&n, unsigned pins, bool sequ)
|
||||
: NetNode(n, pins), sequential_(sequ), init_('x')
|
||||
{
|
||||
pin(0).set_dir(Link::OUTPUT);
|
||||
for (unsigned idx = 1 ; idx < pins ; idx += 1)
|
||||
pin(idx).set_dir(Link::INPUT);
|
||||
|
||||
}
|
||||
|
||||
bool NetUDP::set_table(const string&input, char output)
|
||||
{
|
||||
assert((output == '0') || (output == '1') || (sequential_ &&
|
||||
(output == '-')));
|
||||
|
||||
if (sequential_) {
|
||||
assert(input.length() == pin_count());
|
||||
/* XXXX Need to check to make sure that the input vector
|
||||
contains a legal combination of characters. */
|
||||
return sequ_glob_(input, output);
|
||||
|
||||
} else {
|
||||
assert(input.length() == (pin_count()-1));
|
||||
/* XXXX Need to check to make sure that the input vector
|
||||
contains a legal combination of characters. In
|
||||
combinational UDPs, only 0, 1 and x are allowed. */
|
||||
cm_[input] = output;
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
void NetUDP::cleanup_table()
|
||||
{
|
||||
for (FSM_::iterator idx = fsm_.begin() ; idx != fsm_.end() ; idx++) {
|
||||
string str = (*idx).first;
|
||||
state_t_*st = (*idx).second;
|
||||
assert(str[0] == st->out);
|
||||
|
||||
for (unsigned pin = 0 ; pin < pin_count() ; pin += 1) {
|
||||
if (st->pins[pin].zer && st->pins[pin].zer->out == 'x')
|
||||
st->pins[pin].zer = 0;
|
||||
if (st->pins[pin].one && st->pins[pin].one->out == 'x')
|
||||
st->pins[pin].one = 0;
|
||||
if (st->pins[pin].xxx && st->pins[pin].xxx->out == 'x')
|
||||
st->pins[pin].xxx = 0;
|
||||
}
|
||||
}
|
||||
|
||||
for (FSM_::iterator idx = fsm_.begin() ; idx != fsm_.end() ; ) {
|
||||
FSM_::iterator cur = idx;
|
||||
idx ++;
|
||||
|
||||
state_t_*st = (*cur).second;
|
||||
|
||||
if (st->out != 'x')
|
||||
continue;
|
||||
|
||||
for (unsigned pin = 0 ; pin < pin_count() ; pin += 1) {
|
||||
if (st->pins[pin].zer)
|
||||
goto break_label;
|
||||
if (st->pins[pin].one)
|
||||
goto break_label;
|
||||
if (st->pins[pin].xxx)
|
||||
goto break_label;
|
||||
}
|
||||
|
||||
//delete st;
|
||||
fsm_.erase(cur);
|
||||
|
||||
break_label:;
|
||||
}
|
||||
}
|
||||
|
||||
char NetUDP::table_lookup(const string&from, char to, unsigned pin) const
|
||||
{
|
||||
assert(pin <= pin_count());
|
||||
assert(from.length() == pin_count());
|
||||
FSM_::const_iterator idx = fsm_.find(from);
|
||||
if (idx == fsm_.end())
|
||||
return 'x';
|
||||
|
||||
state_t_*next;
|
||||
switch (to) {
|
||||
case '0':
|
||||
next = (*idx).second->pins[pin].zer;
|
||||
break;
|
||||
case '1':
|
||||
next = (*idx).second->pins[pin].one;
|
||||
break;
|
||||
case 'x':
|
||||
next = (*idx).second->pins[pin].xxx;
|
||||
break;
|
||||
default:
|
||||
assert(0);
|
||||
next = 0;
|
||||
}
|
||||
|
||||
return next? next->out : 'x';
|
||||
}
|
||||
|
||||
void NetUDP::set_initial(char val)
|
||||
{
|
||||
assert(sequential_);
|
||||
assert((val == '0') || (val == '1') || (val == 'x'));
|
||||
init_ = val;
|
||||
}
|
||||
|
||||
NetUDP::state_t_* NetUDP::find_state_(const string&str)
|
||||
{
|
||||
map<string,state_t_*>::iterator cur = fsm_.find(str);
|
||||
if (cur != fsm_.end())
|
||||
return (*cur).second;
|
||||
|
||||
state_t_*st = fsm_[str];
|
||||
if (st == 0) {
|
||||
st = new state_t_(pin_count());
|
||||
st->out = str[0];
|
||||
fsm_[str] = st;
|
||||
}
|
||||
|
||||
return st;
|
||||
}
|
||||
|
||||
NetUDP_COMB::NetUDP_COMB(const string&n, unsigned pins)
|
||||
: NetNode(n, pins)
|
||||
{
|
||||
pin(0).set_dir(Link::OUTPUT);
|
||||
pin(0).set_name("O", 0);
|
||||
for (unsigned idx = 1 ; idx < pins ; idx += 1) {
|
||||
pin(idx).set_dir(Link::INPUT);
|
||||
pin(idx).set_name("I", idx-1);
|
||||
}
|
||||
}
|
||||
|
||||
void NetUDP_COMB::set_table(const string&input, char output)
|
||||
{
|
||||
assert((output == '0') || (output == '1'));
|
||||
|
||||
assert(input.length() == (pin_count()-1));
|
||||
/* XXXX Need to check to make sure that the input vector
|
||||
contains a legal combination of characters. In
|
||||
combinational UDPs, only 0, 1 and x are allowed. */
|
||||
cm_[input] = output;
|
||||
|
||||
}
|
||||
|
||||
void NetUDP_COMB::cleanup_table()
|
||||
{
|
||||
}
|
||||
|
||||
bool NetUDP_COMB::first(string&inp, char&out) const
|
||||
{
|
||||
idx_ = cm_.begin();
|
||||
if (idx_ == cm_.end())
|
||||
return false;
|
||||
|
||||
inp = (*idx_).first;
|
||||
out = (*idx_).second;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool NetUDP_COMB::next(string&inp, char&out) const
|
||||
{
|
||||
idx_ ++;
|
||||
if (idx_ == cm_.end())
|
||||
return false;
|
||||
|
||||
inp = (*idx_).first;
|
||||
out = (*idx_).second;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
* $Log: net_udp.cc,v $
|
||||
* Revision 1.1 2000/03/29 04:37:11 steve
|
||||
* New and improved combinational primitives.
|
||||
*
|
||||
*/
|
||||
|
||||
+720
-974
File diff suppressed because it is too large
Load Diff
+31
-1
@@ -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.7 1999/11/28 23:42:02 steve Exp $"
|
||||
#ident "$Id: netlist.txt,v 1.8 2000/03/08 04:36:54 steve Exp $"
|
||||
|
||||
|
||||
Note that the netlist.h header contains detailed descriptions of how
|
||||
@@ -229,6 +229,29 @@ can operate globally, with optimizations freely crossing module
|
||||
boundaries. This makes coding of netlist transform functions such as
|
||||
constant propagation more effective and easier to write.
|
||||
|
||||
|
||||
SCOPE REPRESENTATION IN NETLISTS
|
||||
|
||||
In spite of the literal flattening of the design, scope information is
|
||||
preserved in the netlist, with the NetScope class. The Design class
|
||||
keeps a single pointer to the root scope of the design. This is the
|
||||
scope of the root module. Scopes that are then created within that
|
||||
(or any nested) module are placed as children of the root scope, and
|
||||
those children can have further children, and so on.
|
||||
|
||||
Each scope in the tree carries its own name, and its relationship to
|
||||
its parent and children. This makes it possible to walk the tree of
|
||||
scopes. In practice, the walking of the scopes is handled by recursive
|
||||
methods.
|
||||
|
||||
Each scope also carries the parameters that are applicable to the
|
||||
scope itself. The parameter expression (possibly evaluated) can be
|
||||
located by name, given the scope object itself. The scan of the pform
|
||||
to generate scopes also places the parameters that are declared in the
|
||||
scope. Overrides are managed during the scan, and once the scan is
|
||||
complete, defparam overrides are applied.
|
||||
|
||||
|
||||
TASKS IN NETLISTS
|
||||
|
||||
The flattening of the design does not include tasks and named
|
||||
@@ -240,6 +263,13 @@ some task calls. C++ programmers recognize this as inlining a task.)
|
||||
|
||||
|
||||
$Log: netlist.txt,v $
|
||||
Revision 1.8 2000/03/08 04:36:54 steve
|
||||
Redesign the implementation of scopes and parameters.
|
||||
I now generate the scopes and notice the parameters
|
||||
in a separate pass over the pform. Once the scopes
|
||||
are generated, I can process overrides and evalutate
|
||||
paremeters before elaboration begins.
|
||||
|
||||
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.
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
#ifndef __netmisc_H
|
||||
#define __netmisc_H
|
||||
/*
|
||||
* Copyright (c) 1999 Stephen Williams (steve@icarus.com)
|
||||
* Copyright (c) 1999-2000 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
|
||||
@@ -18,8 +18,8 @@
|
||||
* 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 $"
|
||||
#if !defined(WINNT) && !defined(macintosh)
|
||||
#ident "$Id: netmisc.h,v 1.6 2000/05/07 04:37:56 steve Exp $"
|
||||
#endif
|
||||
|
||||
# include "netlist.h"
|
||||
@@ -31,10 +31,49 @@
|
||||
* enough.
|
||||
*/
|
||||
extern NetExpr*pad_to_width(NetExpr*expr, unsigned wid);
|
||||
extern NetNet*pad_to_width(Design*des, const string&p, NetNet*n, unsigned w);
|
||||
|
||||
/*
|
||||
* This function chooses a nexus name for the link. The algorithm is
|
||||
* such that any signal in the link will have the same nexus name, and
|
||||
* signals that are not connected together will have a different nexus
|
||||
* name.
|
||||
*/
|
||||
extern string nexus_from_link(const Link*lnk);
|
||||
|
||||
/*
|
||||
* Check to see if the link has a constant value driven to it. If
|
||||
* there is only a NetConst driving this pin, the return a pointer to
|
||||
* that NetConst object. Also, return the index of the bit in that
|
||||
* constant through the idx parameter.
|
||||
*/
|
||||
extern NetConst* link_const_value(Link&pin, unsigned&idx);
|
||||
|
||||
/*
|
||||
* $Log: netmisc.h,v $
|
||||
* Revision 1.6 2000/05/07 04:37:56 steve
|
||||
* Carry strength values from Verilog source to the
|
||||
* pform and netlist for gates.
|
||||
*
|
||||
* Change vvm constants to use the driver_t to drive
|
||||
* a constant value. This works better if there are
|
||||
* multiple drivers on a signal.
|
||||
*
|
||||
* Revision 1.5 2000/04/20 00:28:03 steve
|
||||
* Catch some simple identity compareoptimizations.
|
||||
*
|
||||
* Revision 1.4 2000/03/16 19:03:03 steve
|
||||
* Revise the VVM backend to use nexus objects so that
|
||||
* drivers and resolution functions can be used, and
|
||||
* the t-vvm module doesn't need to write a zillion
|
||||
* output functions.
|
||||
*
|
||||
* Revision 1.3 2000/02/23 02:56:55 steve
|
||||
* Macintosh compilers do not support ident.
|
||||
*
|
||||
* Revision 1.2 2000/02/16 03:58:27 steve
|
||||
* Fix up width matching in structural bitwise operators.
|
||||
*
|
||||
* Revision 1.1 1999/09/29 00:42:51 steve
|
||||
* Allow expanding of additive operators.
|
||||
*
|
||||
|
||||
@@ -0,0 +1,109 @@
|
||||
/*
|
||||
* Copyright (c) 2000 Stephen Williams (steve@.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) && !defined(macintosh)
|
||||
#ident "$Id: nexus_from_link.cc,v 1.4 2000/05/07 19:40:26 steve Exp $"
|
||||
#endif
|
||||
|
||||
# include "netmisc.h"
|
||||
# include <strstream>
|
||||
# include <string>
|
||||
# include <typeinfo>
|
||||
|
||||
string nexus_from_link(const Link*lnk)
|
||||
{
|
||||
const NetNet*sig = dynamic_cast<const NetNet*>(lnk->get_obj());
|
||||
unsigned pin = lnk->get_pin();
|
||||
|
||||
for (const 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();
|
||||
}
|
||||
|
||||
if (sig == 0) {
|
||||
const NetObj*obj = lnk->get_obj();
|
||||
pin = lnk->get_pin();
|
||||
cerr << "internal error: No signal for nexus of " <<
|
||||
obj->name() << " pin " << pin << "(" <<
|
||||
lnk->get_name() << "<" << lnk->get_inst() << ">)"
|
||||
" type=" << typeid(*obj).name() << "?" << endl;
|
||||
|
||||
}
|
||||
assert(sig);
|
||||
ostrstream tmp;
|
||||
tmp << sig->name();
|
||||
if (sig->pin_count() > 1)
|
||||
tmp << "<" << pin << ">";
|
||||
tmp << ends;
|
||||
|
||||
return tmp.str();
|
||||
}
|
||||
|
||||
/*
|
||||
* $Log: nexus_from_link.cc,v $
|
||||
* Revision 1.4 2000/05/07 19:40:26 steve
|
||||
* Fix connection of Direction of LMP_CLSHIFT
|
||||
* to constant values. Remember to add a signal
|
||||
* to the nexus and connect the receiver in vvm.
|
||||
*
|
||||
* Revision 1.3 2000/05/07 04:37:56 steve
|
||||
* Carry strength values from Verilog source to the
|
||||
* pform and netlist for gates.
|
||||
*
|
||||
* Change vvm constants to use the driver_t to drive
|
||||
* a constant value. This works better if there are
|
||||
* multiple drivers on a signal.
|
||||
*
|
||||
* Revision 1.2 2000/03/20 17:40:54 steve
|
||||
* More complete error message about no signal.
|
||||
*
|
||||
* Revision 1.1 2000/03/16 19:03:03 steve
|
||||
* Revise the VVM backend to use nexus objects so that
|
||||
* drivers and resolution functions can be used, and
|
||||
* the t-vvm module doesn't need to write a zillion
|
||||
* output functions.
|
||||
*
|
||||
*/
|
||||
|
||||
@@ -1,73 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 1998 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.
|
||||
*
|
||||
* 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: nobufz.cc,v 1.1 1998/12/02 04:37:13 steve Exp $"
|
||||
#endif
|
||||
|
||||
/* NOBUFZ Function
|
||||
* This function transforms the netlist by removing BUFZ nodes that
|
||||
* have no obvious effect. The assumption here is that the BUFZ node
|
||||
* transmits information perfectly in one direction, and not at all in
|
||||
* the other.
|
||||
*
|
||||
* A BUFZ will *not* be eliminated if the output link is connected to
|
||||
* other outputs. The BUFZ protects its input link from the
|
||||
* double-driving on its output, so the bufz is not meaningless and
|
||||
* cannot be removed.
|
||||
*/
|
||||
|
||||
# include "netlist.h"
|
||||
# include <assert.h>
|
||||
|
||||
static bool is_a_bufz_node(const NetNode*obj)
|
||||
{
|
||||
return dynamic_cast<const NetBUFZ*>(obj);
|
||||
}
|
||||
|
||||
void nobufz(Design*des)
|
||||
{
|
||||
des->clear_node_marks();
|
||||
while (NetNode*obj = des->find_node(&is_a_bufz_node)) {
|
||||
NetBUFZ*cur = dynamic_cast<NetBUFZ*>(obj);
|
||||
assert(cur);
|
||||
|
||||
/* If there are more output pins on the output size of
|
||||
the BUFZ, then the BUFZ has a real effect (it
|
||||
protects its input side) and cannot be eliminated. */
|
||||
if (count_outputs(cur->pin(0)) == 1) {
|
||||
connect(cur->pin(0), cur->pin(1));
|
||||
delete cur;
|
||||
} else {
|
||||
cur->set_mark();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* $Log: nobufz.cc,v $
|
||||
* Revision 1.1 1998/12/02 04:37:13 steve
|
||||
* Add the nobufz function to eliminate bufz objects,
|
||||
* Object links are marked with direction,
|
||||
* constant propagation is more careful will wide links,
|
||||
* Signal folding is aware of attributes, and
|
||||
* the XNF target can dump UDP objects based on LCA
|
||||
* attributes.
|
||||
*
|
||||
*/
|
||||
|
||||
+43
-5
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 1999Stephen Williams (steve@icarus.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
|
||||
@@ -16,8 +16,8 @@
|
||||
* 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 $"
|
||||
#if !defined(WINNT) && !defined(macintosh)
|
||||
#ident "$Id: nodangle.cc,v 1.6 2000/05/07 04:37:56 steve Exp $"
|
||||
#endif
|
||||
|
||||
/*
|
||||
@@ -31,9 +31,20 @@
|
||||
|
||||
class nodangle_f : public functor_t {
|
||||
public:
|
||||
void event(Design*des, NetEvent*ev);
|
||||
void signal(Design*des, NetNet*sig);
|
||||
};
|
||||
|
||||
void nodangle_f::event(Design*des, NetEvent*ev)
|
||||
{
|
||||
if (ev->nwait() != 0)
|
||||
return;
|
||||
|
||||
if (ev->ntrig() != 0)
|
||||
return;
|
||||
|
||||
delete ev;
|
||||
}
|
||||
|
||||
void nodangle_f::signal(Design*des, NetNet*sig)
|
||||
{
|
||||
@@ -42,12 +53,22 @@ void nodangle_f::signal(Design*des, NetNet*sig)
|
||||
if (sig->get_eref() > 0)
|
||||
return;
|
||||
|
||||
/* Look for a completely unconnected signal. */
|
||||
unsigned unlinked = 0;
|
||||
for (unsigned idx = 0 ; idx < sig->pin_count() ; idx += 1)
|
||||
if (! sig->pin(idx).is_linked()) unlinked += 1;
|
||||
|
||||
if (unlinked == sig->pin_count()) {
|
||||
delete sig;
|
||||
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()
|
||||
Link&lnk = sig->pin(idx);
|
||||
for (Link*cur = lnk.next_link()
|
||||
; cur != &lnk ; cur = cur->next_link()) {
|
||||
NetNet*cursig = dynamic_cast<NetNet*>(cur->get_obj());
|
||||
if (cursig == 0)
|
||||
@@ -73,6 +94,23 @@ void nodangle(Design*des)
|
||||
|
||||
/*
|
||||
* $Log: nodangle.cc,v $
|
||||
* Revision 1.6 2000/05/07 04:37:56 steve
|
||||
* Carry strength values from Verilog source to the
|
||||
* pform and netlist for gates.
|
||||
*
|
||||
* Change vvm constants to use the driver_t to drive
|
||||
* a constant value. This works better if there are
|
||||
* multiple drivers on a signal.
|
||||
*
|
||||
* Revision 1.5 2000/04/28 21:00:29 steve
|
||||
* Over agressive signal elimination in constant probadation.
|
||||
*
|
||||
* Revision 1.4 2000/04/18 04:50:20 steve
|
||||
* Clean up unneeded NetEvent objects.
|
||||
*
|
||||
* Revision 1.3 2000/02/23 02:56:55 steve
|
||||
* Macintosh compilers do not support ident.
|
||||
*
|
||||
* 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.
|
||||
|
||||
+40
-3
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 1999 Stephen Williams (steve@icarus.com)
|
||||
* Copyright (c) 1999-2000 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
|
||||
@@ -16,8 +16,8 @@
|
||||
* 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 $"
|
||||
#if !defined(WINNT) && !defined(macintosh)
|
||||
#ident "$Id: pad_to_width.cc,v 1.5 2000/05/02 00:58:12 steve Exp $"
|
||||
#endif
|
||||
|
||||
# include "netlist.h"
|
||||
@@ -34,7 +34,9 @@ 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);
|
||||
co->set_line(*expr);
|
||||
NetEConcat*cc = new NetEConcat(2);
|
||||
cc->set_line(*expr);
|
||||
cc->set(0, co);
|
||||
cc->set(1, expr);
|
||||
cc->set_width(wid);
|
||||
@@ -43,9 +45,44 @@ NetExpr*pad_to_width(NetExpr*expr, unsigned wid)
|
||||
return expr;
|
||||
}
|
||||
|
||||
NetNet*pad_to_width(Design*des, const string&path, NetNet*net, unsigned wid)
|
||||
{
|
||||
NetScope*scope = des->find_scope(path);
|
||||
assert(scope);
|
||||
|
||||
if (net->pin_count() >= wid)
|
||||
return net;
|
||||
|
||||
verinum pad(verinum::V0, wid - net->pin_count());
|
||||
NetConst*con = new NetConst(des->local_symbol(path), pad);
|
||||
des->add_node(con);
|
||||
|
||||
NetNet*tmp = new NetNet(scope, des->local_symbol(path),
|
||||
NetNet::WIRE, wid);
|
||||
tmp->local_flag(true);
|
||||
|
||||
for (unsigned idx = 0 ; idx < net->pin_count() ; idx += 1)
|
||||
connect(tmp->pin(idx), net->pin(idx));
|
||||
for (unsigned idx = net->pin_count() ; idx < wid ; idx += 1)
|
||||
connect(tmp->pin(idx), con->pin(idx-net->pin_count()));
|
||||
|
||||
return tmp;
|
||||
}
|
||||
|
||||
/*
|
||||
* $Log: pad_to_width.cc,v $
|
||||
* Revision 1.5 2000/05/02 00:58:12 steve
|
||||
* Move signal tables to the NetScope class.
|
||||
*
|
||||
* Revision 1.4 2000/02/23 02:56:55 steve
|
||||
* Macintosh compilers do not support ident.
|
||||
*
|
||||
* Revision 1.3 2000/02/16 03:58:27 steve
|
||||
* Fix up width matching in structural bitwise operators.
|
||||
*
|
||||
* Revision 1.2 2000/01/01 06:17:25 steve
|
||||
* Propogate line number information when expanding expressions.
|
||||
*
|
||||
* Revision 1.1 1999/09/29 00:42:51 steve
|
||||
* Allow expanding of additive operators.
|
||||
*
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
|
||||
%{
|
||||
/*
|
||||
* Copyright (c) 1998-1999 Stephen Williams ([email protected])
|
||||
* Copyright (c) 1998-2000 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
|
||||
@@ -18,8 +18,8 @@
|
||||
* 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: parse.y,v 1.76 1999/11/15 04:43:52 steve Exp $"
|
||||
#if !defined(WINNT) && !defined(macintosh)
|
||||
#ident "$Id: parse.y,v 1.96 2000/05/11 23:37:27 steve Exp $"
|
||||
#endif
|
||||
|
||||
# include "parse_misc.h"
|
||||
@@ -27,6 +27,13 @@
|
||||
|
||||
extern void lex_start_table();
|
||||
extern void lex_end_table();
|
||||
|
||||
/*
|
||||
* These are the strengths to use for net declaration
|
||||
* assignments. They are stored here so that scope that contains the
|
||||
* net_decl_assigns can change them during specific statements.
|
||||
*/
|
||||
static struct str_pair_t decl_strength = { PGate::STRONG, PGate::STRONG };
|
||||
%}
|
||||
|
||||
%union {
|
||||
@@ -34,6 +41,8 @@ extern void lex_end_table();
|
||||
char*text;
|
||||
list<string>*strings;
|
||||
|
||||
struct str_pair_t drive;
|
||||
|
||||
PCase::Item*citem;
|
||||
svector<PCase::Item*>*citems;
|
||||
|
||||
@@ -45,6 +54,7 @@ extern void lex_end_table();
|
||||
|
||||
portname_t*portname;
|
||||
svector<portname_t*>*portnames;
|
||||
struct parmvalue_t*parmvalue;
|
||||
|
||||
PExpr*expr;
|
||||
svector<PExpr*>*exprs;
|
||||
@@ -74,19 +84,20 @@ extern void lex_end_table();
|
||||
%token <number> NUMBER
|
||||
%token <realtime> REALTIME
|
||||
%token K_LE K_GE K_EG K_EQ K_NE K_CEQ K_CNE K_LS K_RS K_SG
|
||||
%token K_LOR K_LAND K_NAND K_NOR K_NXOR
|
||||
%token K_LOR K_LAND K_NAND K_NOR K_NXOR K_TRIGGER
|
||||
%token K_always K_and K_assign K_begin K_buf K_bufif0 K_bufif1 K_case
|
||||
%token K_casex K_casez K_cmos K_deassign K_default K_defparam K_disable
|
||||
%token K_edge K_else K_end K_endcase K_endfunction K_endmodule
|
||||
%token K_endprimitive K_endspecify K_endtable K_endtask K_event K_for
|
||||
%token K_force K_forever K_fork K_function K_highz0 K_highz1 K_if
|
||||
%token K_initial K_inout K_input K_integer K_join K_large K_macromodule
|
||||
%token K_initial K_inout K_input K_integer K_join K_large K_localparam
|
||||
%token K_macromodule
|
||||
%token K_medium K_module K_nand K_negedge K_nmos K_nor K_not K_notif0
|
||||
%token K_notif1 K_or K_output K_parameter K_pmos K_posedge K_primitive
|
||||
%token K_pull0 K_pull1 K_pulldown K_pullup K_rcmos K_real K_realtime
|
||||
%token K_reg K_release K_repeat
|
||||
%token K_rnmos K_rpmos K_rtran K_rtranif0 K_rtranif1 K_scalered
|
||||
%token K_small K_specify
|
||||
%token K_signed K_small K_specify
|
||||
%token K_specparam K_strong0 K_strong1 K_supply0 K_supply1 K_table K_task
|
||||
%token K_time K_tran K_tranif0 K_tranif1 K_tri K_tri0 K_tri1 K_triand
|
||||
%token K_trior K_trireg K_vectored K_wait K_wand K_weak0 K_weak1
|
||||
@@ -95,6 +106,7 @@ extern void lex_end_table();
|
||||
|
||||
%token KK_attribute
|
||||
|
||||
%type <drive> drive_strength drive_strength_opt dr_strength0 dr_strength1
|
||||
%type <letter> udp_input_sym udp_output_sym
|
||||
%type <text> udp_input_list udp_sequ_entry udp_comb_entry
|
||||
%type <strings> udp_entry_list udp_comb_entry_list udp_sequ_entry_list
|
||||
@@ -115,8 +127,8 @@ extern void lex_end_table();
|
||||
%type <wires> task_item task_item_list task_item_list_opt
|
||||
%type <wires> function_item function_item_list
|
||||
|
||||
%type <portname> port_name
|
||||
%type <portnames> port_name_list
|
||||
%type <portname> port_name parameter_value_byname
|
||||
%type <portnames> port_name_list parameter_value_byname_list
|
||||
|
||||
%type <citem> case_item
|
||||
%type <citems> case_items
|
||||
@@ -126,8 +138,8 @@ extern void lex_end_table();
|
||||
|
||||
%type <expr> expression expr_primary
|
||||
%type <expr> lavalue lpvalue
|
||||
%type <expr> delay_value
|
||||
%type <exprs> delay delay_opt delay_value_list
|
||||
%type <expr> delay_value delay_value_simple
|
||||
%type <exprs> delay1 delay3 delay3_opt
|
||||
%type <exprs> expression_list
|
||||
%type <exprs> assign assign_list
|
||||
|
||||
@@ -135,6 +147,7 @@ extern void lex_end_table();
|
||||
%type <nettype> net_type
|
||||
%type <gatetype> gatetype
|
||||
%type <porttype> port_type
|
||||
%type <parmvalue> parameter_value_opt
|
||||
|
||||
%type <task> task_body
|
||||
%type <function> func_body
|
||||
@@ -185,6 +198,16 @@ block_item_decl
|
||||
}
|
||||
| K_reg register_variable_list ';'
|
||||
{ delete $2; }
|
||||
| K_reg K_signed range register_variable_list ';'
|
||||
{ pform_set_net_range($4, $3);
|
||||
delete $3;
|
||||
delete $4;
|
||||
yyerror(@2, "sorry: signed reg not supported.");
|
||||
}
|
||||
| K_reg K_signed register_variable_list ';'
|
||||
{ delete $3;
|
||||
yyerror(@2, "sorry: signed reg not supported.");
|
||||
}
|
||||
| K_integer list_of_variables ';'
|
||||
{ pform_set_reg_integer($2);
|
||||
delete $2;
|
||||
@@ -259,9 +282,8 @@ defparam_assign
|
||||
delete tmp;
|
||||
tmp = 0;
|
||||
}
|
||||
yyerror(@1, "sorry: defparam assignments not supported.");
|
||||
pform_set_defparam($1, $3);
|
||||
delete $1;
|
||||
delete $3;
|
||||
}
|
||||
;
|
||||
|
||||
@@ -275,23 +297,67 @@ defparam_assign_list
|
||||
| defparam_assign_list ',' defparam_assign
|
||||
;
|
||||
|
||||
delay
|
||||
: '#' delay_value
|
||||
delay1
|
||||
: '#' delay_value_simple
|
||||
{ svector<PExpr*>*tmp = new svector<PExpr*>(1);
|
||||
(*tmp)[0] = $2;
|
||||
$$ = tmp;
|
||||
}
|
||||
| '#' '(' delay_value_list ')'
|
||||
{ $$ = $3;
|
||||
| '#' '(' delay_value ')'
|
||||
{ svector<PExpr*>*tmp = new svector<PExpr*>(1);
|
||||
(*tmp)[0] = $3;
|
||||
$$ = tmp;
|
||||
}
|
||||
;
|
||||
|
||||
delay_opt
|
||||
: delay { $$ = $1; }
|
||||
| { $$ = 0; }
|
||||
delay3
|
||||
: '#' delay_value_simple
|
||||
{ svector<PExpr*>*tmp = new svector<PExpr*>(1);
|
||||
(*tmp)[0] = $2;
|
||||
$$ = tmp;
|
||||
}
|
||||
| '#' '(' delay_value ')'
|
||||
{ svector<PExpr*>*tmp = new svector<PExpr*>(1);
|
||||
(*tmp)[0] = $3;
|
||||
$$ = tmp;
|
||||
}
|
||||
| '#' '(' delay_value ',' delay_value ')'
|
||||
{ svector<PExpr*>*tmp = new svector<PExpr*>(2);
|
||||
(*tmp)[0] = $3;
|
||||
(*tmp)[1] = $5;
|
||||
$$ = tmp;
|
||||
}
|
||||
| '#' '(' delay_value ',' delay_value ',' delay_value ')'
|
||||
{ svector<PExpr*>*tmp = new svector<PExpr*>(3);
|
||||
(*tmp)[0] = $3;
|
||||
(*tmp)[1] = $5;
|
||||
(*tmp)[1] = $7;
|
||||
$$ = tmp;
|
||||
}
|
||||
;
|
||||
|
||||
delay3_opt
|
||||
: delay3 { $$ = $1; }
|
||||
| { $$ = 0; }
|
||||
;
|
||||
|
||||
delay_value
|
||||
: expression
|
||||
{ PExpr*tmp = $1;
|
||||
if (! pform_expression_is_constant(tmp))
|
||||
yyerror(@1, "error: delay expression must "
|
||||
"be constant.");
|
||||
$$ = tmp;
|
||||
}
|
||||
| expression ':' expression ':' expression
|
||||
{ yyerror(@1, "sorry: (min:typ:max) not supported.");
|
||||
$$ = $3;
|
||||
delete $1;
|
||||
delete $5;
|
||||
}
|
||||
;
|
||||
|
||||
delay_value_simple
|
||||
: NUMBER
|
||||
{ verinum*tmp = $1;
|
||||
if (tmp == 0) {
|
||||
@@ -312,19 +378,6 @@ delay_value
|
||||
}
|
||||
;
|
||||
|
||||
delay_value_list
|
||||
: expression
|
||||
{ svector<PExpr*>*tmp = new svector<PExpr*>(1);
|
||||
(*tmp)[0] = $1;
|
||||
$$ = tmp;
|
||||
}
|
||||
| delay_value_list ',' expression
|
||||
{ svector<PExpr*>*tmp = new svector<PExpr*>(*$1, $3);
|
||||
delete $1;
|
||||
$$ = tmp;
|
||||
}
|
||||
;
|
||||
|
||||
description
|
||||
: module
|
||||
| udp_primitive
|
||||
@@ -338,25 +391,61 @@ description
|
||||
|
||||
drive_strength
|
||||
: '(' dr_strength0 ',' dr_strength1 ')'
|
||||
{ $$.str0 = $2.str0;
|
||||
$$.str1 = $4.str1;
|
||||
}
|
||||
| '(' dr_strength1 ',' dr_strength0 ')'
|
||||
{ $$.str0 = $4.str0;
|
||||
$$.str1 = $2.str1;
|
||||
}
|
||||
| '(' dr_strength0 ',' K_highz1 ')'
|
||||
{ $$.str0 = $2.str0;
|
||||
$$.str1 = PGate::HIGHZ;
|
||||
}
|
||||
| '(' dr_strength1 ',' K_highz0 ')'
|
||||
{ $$.str0 = PGate::HIGHZ;
|
||||
$$.str1 = $2.str1;
|
||||
}
|
||||
| '(' K_highz1 ',' dr_strength0 ')'
|
||||
{ $$.str0 = $4.str0;
|
||||
$$.str1 = PGate::HIGHZ;
|
||||
}
|
||||
| '(' K_highz0 ',' dr_strength1 ')'
|
||||
{ $$.str0 = PGate::HIGHZ;
|
||||
$$.str1 = $4.str1;
|
||||
}
|
||||
;
|
||||
|
||||
drive_strength_opt
|
||||
: drive_strength
|
||||
|
|
||||
: drive_strength { $$ = $1; }
|
||||
| { $$.str0 = PGate::STRONG; $$.str1 = PGate::STRONG; }
|
||||
;
|
||||
|
||||
dr_strength0 : K_supply0 | K_strong0 | K_pull0 | K_weak0 ;
|
||||
dr_strength1 : K_supply1 | K_strong1 | K_pull1 | K_weak1 ;
|
||||
dr_strength0
|
||||
: K_supply0 { $$.str0 = PGate::SUPPLY; }
|
||||
| K_strong0 { $$.str0 = PGate::STRONG; }
|
||||
| K_pull0 { $$.str0 = PGate::PULL; }
|
||||
| K_weak0 { $$.str0 = PGate::WEAK; }
|
||||
;
|
||||
|
||||
dr_strength1
|
||||
: K_supply1 { $$.str1 = PGate::SUPPLY; }
|
||||
| K_strong1 { $$.str1 = PGate::STRONG; }
|
||||
| K_pull1 { $$.str1 = PGate::PULL; }
|
||||
| K_weak1 { $$.str1 = PGate::WEAK; }
|
||||
;
|
||||
|
||||
event_control
|
||||
: '@' IDENTIFIER
|
||||
{ yyerror(@1, "sorry: event control not supported.");
|
||||
$$ = 0;
|
||||
{ PEIdent*tmpi = new PEIdent($2);
|
||||
tmpi->set_file(@2.text);
|
||||
tmpi->set_lineno(@2.first_line);
|
||||
delete[]$2;
|
||||
PEEvent*tmpe = new PEEvent(PEEvent::ANYEDGE, tmpi);
|
||||
PEventStatement*tmps = new PEventStatement(tmpe);
|
||||
tmps->set_file(@1.text);
|
||||
tmps->set_lineno(@1.first_line);
|
||||
$$ = tmps;
|
||||
}
|
||||
| '@' '(' event_expression_list ')'
|
||||
{ PEventStatement*tmp = new PEventStatement(*$3);
|
||||
@@ -380,11 +469,17 @@ event_expression_list
|
||||
delete $3;
|
||||
$$ = tmp;
|
||||
}
|
||||
| event_expression_list ',' 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);
|
||||
{ PEEvent*tmp = new PEEvent(PEEvent::POSEDGE, $2);
|
||||
tmp->set_file(@1.text);
|
||||
tmp->set_lineno(@1.first_line);
|
||||
svector<PEEvent*>*tl = new svector<PEEvent*>(1);
|
||||
@@ -392,7 +487,7 @@ event_expression
|
||||
$$ = tl;
|
||||
}
|
||||
| K_negedge expression
|
||||
{ PEEvent*tmp = new PEEvent(NetNEvent::NEGEDGE, $2);
|
||||
{ PEEvent*tmp = new PEEvent(PEEvent::NEGEDGE, $2);
|
||||
tmp->set_file(@1.text);
|
||||
tmp->set_lineno(@1.first_line);
|
||||
svector<PEEvent*>*tl = new svector<PEEvent*>(1);
|
||||
@@ -400,7 +495,7 @@ event_expression
|
||||
$$ = tl;
|
||||
}
|
||||
| expression
|
||||
{ PEEvent*tmp = new PEEvent(NetNEvent::ANYEDGE, $1);
|
||||
{ PEEvent*tmp = new PEEvent(PEEvent::ANYEDGE, $1);
|
||||
tmp->set_file(@1.text);
|
||||
tmp->set_lineno(@1.first_line);
|
||||
svector<PEEvent*>*tl = new svector<PEEvent*>(1);
|
||||
@@ -468,6 +563,16 @@ expression
|
||||
tmp->set_lineno(@2.first_line);
|
||||
$$ = tmp;
|
||||
}
|
||||
| '!' error %prec UNARY_PREC
|
||||
{ yyerror(@1, "error: Operand of unary ! "
|
||||
"is not a primary expression.");
|
||||
$$ = 0;
|
||||
}
|
||||
| '^' error %prec UNARY_PREC
|
||||
{ yyerror(@1, "error: Operand of reduction ^ "
|
||||
"is not a primary expression.");
|
||||
$$ = 0;
|
||||
}
|
||||
| expression '^' expression
|
||||
{ PEBinary*tmp = new PEBinary('^', $1, $3);
|
||||
tmp->set_file(@2.text);
|
||||
@@ -657,11 +762,11 @@ expr_primary
|
||||
delete $1;
|
||||
}
|
||||
| SYSTEM_IDENTIFIER
|
||||
{ PEIdent*tmp = new PEIdent($1);
|
||||
{ PECallFunction*tmp = new PECallFunction($1);
|
||||
tmp->set_file(@1.text);
|
||||
tmp->set_lineno(@1.first_line);
|
||||
$$ = tmp;
|
||||
delete $1;
|
||||
delete $1
|
||||
}
|
||||
| identifier '[' expression ']'
|
||||
{ PEIdent*tmp = new PEIdent($1);
|
||||
@@ -694,12 +799,6 @@ expr_primary
|
||||
}
|
||||
| '(' expression ')'
|
||||
{ $$ = $2; }
|
||||
| '(' expression ':' expression ':' expression ')'
|
||||
{ yyerror(@2, "sorry: (min:typ:max) not supported.");
|
||||
$$ = $4;
|
||||
delete $2;
|
||||
delete $6;
|
||||
}
|
||||
| '{' expression_list '}'
|
||||
{ PEConcat*tmp = new PEConcat(*$2);
|
||||
tmp->set_file(@2.text);
|
||||
@@ -854,8 +953,6 @@ gatetype
|
||||
| K_not { $$ = PGBuiltin::NOT; }
|
||||
| K_notif0 { $$ = PGBuiltin::NOTIF0; }
|
||||
| K_notif1 { $$ = PGBuiltin::NOTIF1; }
|
||||
| K_pulldown { $$ = PGBuiltin::PULLDOWN; }
|
||||
| K_pullup { $$ = PGBuiltin::PULLUP; }
|
||||
| K_nmos { $$ = PGBuiltin::NMOS; }
|
||||
| K_rnmos { $$ = PGBuiltin::RNMOS; }
|
||||
| K_pmos { $$ = PGBuiltin::PMOS; }
|
||||
@@ -1051,10 +1148,21 @@ module_item
|
||||
}
|
||||
delete $3;
|
||||
}
|
||||
| K_trireg charge_strength_opt range_opt delay_opt list_of_variables ';'
|
||||
| net_type drive_strength { decl_strength = $2;} net_decl_assigns ';'
|
||||
{ pform_makewire(@1, $4, $1);
|
||||
/* The strengths are handled in the
|
||||
net_decl_assigns using the decl_strength that I
|
||||
set in the rule. Right here, just restore the
|
||||
defaults for other rules. */
|
||||
decl_strength.str0 = PGate::STRONG;
|
||||
decl_strength.str1 = PGate::STRONG;
|
||||
delete $4;
|
||||
}
|
||||
| K_trireg charge_strength_opt range_opt delay3_opt list_of_variables ';'
|
||||
{ yyerror(@1, "sorry: trireg nets not supported.");
|
||||
delete $3;
|
||||
}
|
||||
|
||||
| port_type range_opt list_of_variables ';'
|
||||
{ pform_set_port_type($3, $1);
|
||||
if ($2) {
|
||||
@@ -1066,20 +1174,58 @@ module_item
|
||||
| block_item_decl
|
||||
| K_defparam defparam_assign_list ';'
|
||||
| K_event list_of_variables ';'
|
||||
{ yyerror(@1, "sorry: named events not supported.");
|
||||
{ pform_make_events($2, @1.text, @1.first_line);
|
||||
delete $2;
|
||||
}
|
||||
| K_parameter parameter_assign_list ';'
|
||||
| gatetype delay_opt gate_instance_list ';'
|
||||
{ pform_makegates($1, $2, $3);
|
||||
| K_localparam localparam_assign_list ';' { }
|
||||
|
||||
/* Most gate types have an optional drive strength and optional
|
||||
three-value delay. These rules handle the different cases. */
|
||||
|
||||
| gatetype gate_instance_list ';'
|
||||
{ pform_makegates($1, decl_strength, 0, $2);
|
||||
}
|
||||
| IDENTIFIER delay_opt gate_instance_list ';'
|
||||
|
||||
| gatetype delay3 gate_instance_list ';'
|
||||
{ pform_makegates($1, decl_strength, $2, $3);
|
||||
}
|
||||
|
||||
| gatetype drive_strength gate_instance_list ';'
|
||||
{ pform_makegates($1, $2, 0, $3);
|
||||
}
|
||||
|
||||
| gatetype drive_strength delay3 gate_instance_list ';'
|
||||
{ pform_makegates($1, $2, $3, $4);
|
||||
}
|
||||
|
||||
/* Pullup and pulldown devices cannot have delays, and their
|
||||
strengths are limited. */
|
||||
|
||||
| K_pullup gate_instance_list ';'
|
||||
{ pform_makegates(PGBuiltin::PULLUP, decl_strength, 0, $2);
|
||||
}
|
||||
| K_pulldown gate_instance_list ';'
|
||||
{ pform_makegates(PGBuiltin::PULLDOWN, decl_strength, 0, $2);
|
||||
}
|
||||
|
||||
/* This rule handles instantiations of modules and user defined
|
||||
primitives. These devices to not have delay lists or strengths,
|
||||
but then can have parameter lists. */
|
||||
|
||||
| IDENTIFIER parameter_value_opt gate_instance_list ';'
|
||||
{ pform_make_modgates($1, $2, $3);
|
||||
delete $1;
|
||||
}
|
||||
| K_assign drive_strength_opt delay_opt assign_list ';'
|
||||
{ pform_make_pgassign_list($4, $3, @1.text, @1.first_line); }
|
||||
|
||||
/* Continuous assignment can have an optional drive strength, then
|
||||
an optional delay3 that applies to all the assignments in the
|
||||
assign_list. */
|
||||
|
||||
| K_assign drive_strength_opt delay3_opt assign_list ';'
|
||||
{ pform_make_pgassign_list($4, $3, $2, @1.text, @1.first_line); }
|
||||
| K_assign error '=' expression ';'
|
||||
|
||||
| K_always statement
|
||||
{ PProcess*tmp = pform_make_behavior(PProcess::PR_ALWAYS, $2);
|
||||
tmp->set_file(@1.text);
|
||||
@@ -1090,6 +1236,12 @@ module_item
|
||||
tmp->set_file(@1.text);
|
||||
tmp->set_lineno(@1.first_line);
|
||||
}
|
||||
|
||||
/* The task declaration rule matches the task declaration
|
||||
header, then pushes the function scope. This causes the
|
||||
definitions in the task_body to take on the scope of the task
|
||||
instead of the module. */
|
||||
|
||||
| K_task IDENTIFIER ';'
|
||||
{ pform_push_scope($2); }
|
||||
task_body
|
||||
@@ -1101,6 +1253,12 @@ module_item
|
||||
pform_set_task($2, $5);
|
||||
delete $2;
|
||||
}
|
||||
|
||||
/* The function declaration rule matches the function declaration
|
||||
header, then pushes the function scope. This causes the
|
||||
definitions in the func_body to take on the scope of the function
|
||||
instead of the module. */
|
||||
|
||||
| K_function range_or_type_opt IDENTIFIER ';'
|
||||
{ pform_push_scope($3); }
|
||||
func_body
|
||||
@@ -1112,9 +1270,16 @@ module_item
|
||||
pform_set_function($3, $2, $6);
|
||||
delete $3;
|
||||
}
|
||||
|
||||
/* specify blocks are parsed but ignored. */
|
||||
|
||||
| K_specify specify_item_list K_endspecify
|
||||
{
|
||||
}
|
||||
|
||||
/* These rules are for the Icarus VErilog specific $attribute
|
||||
extensions. Then catch the parameters of the $attribute keyword. */
|
||||
|
||||
| KK_attribute '(' IDENTIFIER ',' STRING ',' STRING ')' ';'
|
||||
{ pform_set_attrib($3, $5, $7);
|
||||
delete $3;
|
||||
@@ -1125,6 +1290,7 @@ module_item
|
||||
{ yyerror(@1, "error: Misformed $attribute parameter list."); }
|
||||
;
|
||||
|
||||
|
||||
module_item_list
|
||||
: module_item_list module_item
|
||||
| module_item
|
||||
@@ -1136,14 +1302,15 @@ module_item_list
|
||||
net_decl_assign
|
||||
: IDENTIFIER '=' expression
|
||||
{ PEIdent*id = new PEIdent($1);
|
||||
PGAssign*tmp = pform_make_pgassign(id, $3, 0);
|
||||
PGAssign*tmp = pform_make_pgassign(id, $3, 0, decl_strength);
|
||||
tmp->set_file(@1.text);
|
||||
tmp->set_lineno(@1.first_line);
|
||||
$$ = $1;
|
||||
}
|
||||
| delay IDENTIFIER '=' expression
|
||||
| delay1 IDENTIFIER '=' expression
|
||||
{ PEIdent*id = new PEIdent($2);
|
||||
PGAssign*tmp = pform_make_pgassign(id, $4, $1);
|
||||
PGAssign*tmp = pform_make_pgassign(id, $4, $1,
|
||||
decl_strength);
|
||||
tmp->set_file(@2.text);
|
||||
tmp->set_lineno(@2.first_line);
|
||||
$$ = $2;
|
||||
@@ -1202,7 +1369,116 @@ parameter_assign_list
|
||||
| parameter_assign_list ',' parameter_assign
|
||||
;
|
||||
|
||||
/* The port (of a module) is a fairle complex item. Each port is
|
||||
|
||||
/* Localparam assignments and asignment lists are broken into
|
||||
separate BNF so that I can call slightly different paramter
|
||||
handling code. They parse the same as parameters, they just
|
||||
behave differently when someone tries to override them. */
|
||||
|
||||
localparam_assign
|
||||
: IDENTIFIER '=' expression
|
||||
{ PExpr*tmp = $3;
|
||||
if (!pform_expression_is_constant(tmp)) {
|
||||
yyerror(@3, "error: parameter value "
|
||||
"must be constant.");
|
||||
delete tmp;
|
||||
tmp = 0;
|
||||
}
|
||||
pform_set_localparam($1, tmp);
|
||||
delete $1;
|
||||
}
|
||||
;
|
||||
|
||||
localparam_assign_list
|
||||
: localparam_assign
|
||||
| range localparam_assign
|
||||
{ yywarn(@1, "Ranges in localparam definition "
|
||||
"are not supported.");
|
||||
delete $1;
|
||||
}
|
||||
| localparam_assign_list ',' localparam_assign
|
||||
;
|
||||
|
||||
|
||||
/* The parameters of a module instance can be overridden by writing
|
||||
a list of expressions in a syntax much line a delay list. (The
|
||||
difference being the list can have any length.) The pform that
|
||||
attaches the expression list to the module checks that the
|
||||
expressions are constant.
|
||||
|
||||
Although the BNF in IEEE1364-1995 implies that parameter value
|
||||
lists must be in parentheses, in practice most compilers will
|
||||
accept simple expressions outside of parentheses if there is only
|
||||
one value, so I'll accept simple numbers here.
|
||||
|
||||
The parameter value by name syntax is OVI enhancement BTF-B06 as
|
||||
approved by WG1364 on 6/28/1998. */
|
||||
|
||||
parameter_value_opt
|
||||
: '#' '(' expression_list ')'
|
||||
{ struct parmvalue_t*tmp = new struct parmvalue_t;
|
||||
tmp->by_order = $3;
|
||||
tmp->by_name = 0;
|
||||
$$ = tmp;
|
||||
}
|
||||
| '#' '(' parameter_value_byname_list ')'
|
||||
{ struct parmvalue_t*tmp = new struct parmvalue_t;
|
||||
tmp->by_order = 0;
|
||||
tmp->by_name = $3;
|
||||
$$ = tmp;
|
||||
}
|
||||
| '#' NUMBER
|
||||
{ assert($2);
|
||||
PENumber*tmp = new PENumber($2);
|
||||
tmp->set_file(@1.text);
|
||||
tmp->set_lineno(@1.first_line);
|
||||
|
||||
struct parmvalue_t*lst = new struct parmvalue_t;
|
||||
lst->by_order = new svector<PExpr*>(1);
|
||||
(*lst->by_order)[0] = tmp;
|
||||
lst->by_name = 0;
|
||||
$$ = lst;
|
||||
}
|
||||
| '#' error
|
||||
{ yyerror(@1, "error: syntax error in parameter value "
|
||||
"assignment list.");
|
||||
$$ = 0;
|
||||
}
|
||||
|
|
||||
{ $$ = 0; }
|
||||
;
|
||||
|
||||
parameter_value_byname
|
||||
: PORTNAME '(' expression ')'
|
||||
{ portname_t*tmp = new portname_t;
|
||||
tmp->name = $1;
|
||||
tmp->parm = $3;
|
||||
free($1);
|
||||
$$ = tmp;
|
||||
}
|
||||
| PORTNAME '(' ')'
|
||||
{ portname_t*tmp = new portname_t;
|
||||
tmp->name = $1;
|
||||
tmp->parm = 0;
|
||||
free($1);
|
||||
$$ = tmp;
|
||||
}
|
||||
;
|
||||
|
||||
parameter_value_byname_list
|
||||
: parameter_value_byname
|
||||
{ svector<portname_t*>*tmp = new svector<portname_t*>(1);
|
||||
(*tmp)[0] = $1;
|
||||
$$ = tmp;
|
||||
}
|
||||
| parameter_value_byname_list ',' parameter_value_byname
|
||||
{ svector<portname_t*>*tmp = new svector<portname_t*>(*$1,$3);
|
||||
delete $1;
|
||||
$$ = tmp;
|
||||
}
|
||||
;
|
||||
|
||||
/* The port (of a module) is a fairly complex item. Each port is
|
||||
handled as a Module::port_t object. A simple port reference has a
|
||||
name and a PWire object, but more complex constructs are possible
|
||||
where the name can be attached to a list of PWire objects.
|
||||
@@ -1390,8 +1666,10 @@ register_variable
|
||||
}
|
||||
| IDENTIFIER '=' expression
|
||||
{ pform_makewire(@1, $1, NetNet::REG);
|
||||
yyerror(@2, "error: net declaration assignment to reg/integer not allowed.");
|
||||
delete $3;
|
||||
if (! pform_expression_is_constant($3))
|
||||
yyerror(@3, "error: register declaration assignment"
|
||||
" value must be a constant expression.");
|
||||
pform_make_reginit(@1, $1, $3);
|
||||
$$ = $1;
|
||||
}
|
||||
| IDENTIFIER '[' expression ':' expression ']'
|
||||
@@ -1451,11 +1729,51 @@ specparam_list
|
||||
|
||||
spec_polarity: '+' | '-' | ;
|
||||
|
||||
|
||||
statement
|
||||
|
||||
/* assign and deassign statements are procedural code to do
|
||||
structural assignments, and to turn that structural assignment
|
||||
off. This stronger then any other assign, but weaker then the
|
||||
force assignments. */
|
||||
|
||||
: K_assign lavalue '=' expression ';'
|
||||
{ yyerror(@1, "sorry: procedural continuous assign not supported.");
|
||||
$$ = 0;
|
||||
{ PCAssign*tmp = new PCAssign($2, $4);
|
||||
tmp->set_file(@1.text);
|
||||
tmp->set_lineno(@1.first_line);
|
||||
$$ = tmp;
|
||||
}
|
||||
|
||||
| K_deassign lavalue';'
|
||||
{ PDeassign*tmp = new PDeassign($2);
|
||||
tmp->set_file(@1.text);
|
||||
tmp->set_lineno(@1.first_line);
|
||||
$$ = tmp;
|
||||
}
|
||||
|
||||
|
||||
/* Force and release statements are similar to assignments,
|
||||
syntactically, but they will be elaborated differently. */
|
||||
|
||||
| K_force lavalue '=' expression ';'
|
||||
{ PForce*tmp = new PForce($2, $4);
|
||||
tmp->set_file(@1.text);
|
||||
tmp->set_lineno(@1.first_line);
|
||||
$$ = tmp;
|
||||
}
|
||||
| K_release lavalue ';'
|
||||
{ PRelease*tmp = new PRelease($2);
|
||||
tmp->set_file(@1.text);
|
||||
tmp->set_lineno(@1.first_line);
|
||||
$$ = tmp;
|
||||
}
|
||||
|
||||
/* begin-end blocks come in a variety of forms, including named and
|
||||
anonymous. The named blocks can also carry their own reg
|
||||
variables, which are placed in the scope created by the block
|
||||
name. These are handled by pushing the scope name then matching
|
||||
the declarations. The scope is popped at the end of the block. */
|
||||
|
||||
| K_begin statement_list K_end
|
||||
{ PBlock*tmp = new PBlock(PBlock::BL_SEQ, *$2);
|
||||
tmp->set_file(@1.text);
|
||||
@@ -1489,32 +1807,12 @@ statement
|
||||
}
|
||||
| K_begin error K_end
|
||||
{ yyerrok; }
|
||||
| K_deassign lavalue';'
|
||||
{ yyerror(@1, "sorry:, deassign not supported.");
|
||||
$$ = 0;
|
||||
}
|
||||
| K_disable IDENTIFIER ';'
|
||||
{ yyerror(@1, "sorry: disable statements not supported.");
|
||||
delete $2;
|
||||
$$ = 0;
|
||||
}
|
||||
| K_force lavalue '=' expression ';'
|
||||
{ yyerror(@1, "sorry: procedural force assign not supported.");
|
||||
$$ = 0;
|
||||
}
|
||||
| K_forever statement
|
||||
{ PForever*tmp = new PForever($2);
|
||||
tmp->set_file(@1.text);
|
||||
tmp->set_lineno(@1.first_line);
|
||||
$$ = tmp;
|
||||
}
|
||||
| K_fork statement_list K_join
|
||||
{ PBlock*tmp = new PBlock(PBlock::BL_PAR, *$2);
|
||||
tmp->set_file(@1.text);
|
||||
tmp->set_lineno(@1.first_line);
|
||||
delete $2;
|
||||
$$ = tmp;
|
||||
}
|
||||
|
||||
/* fork-join blocks are very similar to begin-end blocks. In fact,
|
||||
from the parser's perspective there is no real difference. All we
|
||||
need to do is remember that this is a parallel block so that the
|
||||
code generator can do the right thing. */
|
||||
|
||||
| K_fork ':' IDENTIFIER
|
||||
{ pform_push_scope($3); }
|
||||
block_item_decls_opt
|
||||
@@ -1539,10 +1837,31 @@ statement
|
||||
tmp->set_lineno(@1.first_line);
|
||||
$$ = tmp;
|
||||
}
|
||||
| K_release lavalue ';'
|
||||
{ yyerror(@1, "sorry: release not supported.");
|
||||
|
||||
| K_disable IDENTIFIER ';'
|
||||
{ yyerror(@1, "sorry: disable statements not supported.");
|
||||
delete $2;
|
||||
$$ = 0;
|
||||
}
|
||||
| K_TRIGGER IDENTIFIER ';'
|
||||
{ PTrigger*tmp = new PTrigger($2);
|
||||
tmp->set_file(@2.text);
|
||||
tmp->set_lineno(@2.first_line);
|
||||
$$ = tmp;
|
||||
}
|
||||
| K_forever statement
|
||||
{ PForever*tmp = new PForever($2);
|
||||
tmp->set_file(@1.text);
|
||||
tmp->set_lineno(@1.first_line);
|
||||
$$ = tmp;
|
||||
}
|
||||
| K_fork statement_list K_join
|
||||
{ PBlock*tmp = new PBlock(PBlock::BL_PAR, *$2);
|
||||
tmp->set_file(@1.text);
|
||||
tmp->set_lineno(@1.first_line);
|
||||
delete $2;
|
||||
$$ = tmp;
|
||||
}
|
||||
| K_repeat '(' expression ')' statement
|
||||
{ PRepeat*tmp = new PRepeat($3, $5);
|
||||
tmp->set_file(@1.text);
|
||||
@@ -1622,10 +1941,9 @@ statement
|
||||
{ $$ = 0;
|
||||
yyerror(@3, "error: Error in while loop condition.");
|
||||
}
|
||||
| delay statement_opt
|
||||
| delay1 statement_opt
|
||||
{ PExpr*del = (*$1)[0];
|
||||
if ($1->count() != 1)
|
||||
yyerror(@1, "sorry: delay lists not supported here.");
|
||||
assert($1->count() == 1);
|
||||
PDelayStatement*tmp = new PDelayStatement(del, $2);
|
||||
tmp->set_file(@1.text);
|
||||
tmp->set_lineno(@1.first_line);
|
||||
@@ -1653,19 +1971,17 @@ statement
|
||||
tmp->set_lineno(@1.first_line);
|
||||
$$ = tmp;
|
||||
}
|
||||
| lpvalue '=' delay expression ';'
|
||||
{ PExpr*del = (*$3)[0];
|
||||
if ($3->count() != 1)
|
||||
yyerror(@1, "sorry: Delay lists not supported here.");
|
||||
| lpvalue '=' delay1 expression ';'
|
||||
{ assert($3->count() == 1);
|
||||
PExpr*del = (*$3)[0];
|
||||
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.");
|
||||
| lpvalue K_LE delay1 expression ';'
|
||||
{ assert($3->count() == 1);
|
||||
PExpr*del = (*$3)[0];
|
||||
PAssignNB*tmp = new PAssignNB($1,del,$4);
|
||||
tmp->set_file(@1.text);
|
||||
tmp->set_lineno(@1.first_line);
|
||||
@@ -1677,6 +1993,14 @@ statement
|
||||
tmp->set_lineno(@1.first_line);
|
||||
$$ = tmp;
|
||||
}
|
||||
| lpvalue '=' K_repeat '(' expression ')' event_control expression ';'
|
||||
{ PAssign*tmp = new PAssign($1,$7,$8);
|
||||
tmp->set_file(@1.text);
|
||||
tmp->set_lineno(@1.first_line);
|
||||
yyerror(@3, "sorry: repeat event control not supported.");
|
||||
delete $5;
|
||||
$$ = tmp;
|
||||
}
|
||||
| lpvalue K_LE event_control expression ';'
|
||||
{ yyerror(@1, "sorry: Event controls not supported here.");
|
||||
PAssignNB*tmp = new PAssignNB($1,$4);
|
||||
@@ -1684,9 +2008,17 @@ statement
|
||||
tmp->set_lineno(@1.first_line);
|
||||
$$ = tmp;
|
||||
}
|
||||
| lpvalue K_LE K_repeat '(' expression ')' event_control expression ';'
|
||||
{ yyerror(@1, "sorry: Event controls not supported here.");
|
||||
delete $5;
|
||||
PAssignNB*tmp = new PAssignNB($1,$8);
|
||||
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);
|
||||
PEEvent*etmp = new PEEvent(PEEvent::POSITIVE, $3);
|
||||
tmp = new PEventStatement(etmp);
|
||||
tmp->set_statement($5);
|
||||
$$ = tmp;
|
||||
@@ -1928,11 +2260,17 @@ udp_input_sym
|
||||
| '?' { $$ = '?'; }
|
||||
| 'b' { $$ = 'b'; }
|
||||
| '*' { $$ = '*'; }
|
||||
| '%' { $$ = '%'; }
|
||||
| 'f' { $$ = 'f'; }
|
||||
| 'F' { $$ = 'F'; }
|
||||
| 'r' { $$ = 'r'; }
|
||||
| 'R' { $$ = 'R'; }
|
||||
| 'n' { $$ = 'n'; }
|
||||
| 'N' { $$ = 'N'; }
|
||||
| 'p' { $$ = 'p'; }
|
||||
| 'P' { $$ = 'P'; }
|
||||
| '_' { $$ = '_'; }
|
||||
| '+' { $$ = '+'; }
|
||||
;
|
||||
|
||||
udp_output_sym
|
||||
|
||||
+6
-3
@@ -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
|
||||
@@ -16,8 +16,8 @@
|
||||
* 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: parse_misc.cc,v 1.3 1999/09/29 21:15:31 steve Exp $"
|
||||
#if !defined(WINNT) && !defined(macintosh)
|
||||
#ident "$Id: parse_misc.cc,v 1.4 2000/02/23 02:56:55 steve Exp $"
|
||||
#endif
|
||||
|
||||
# include "parse_misc.h"
|
||||
@@ -58,6 +58,9 @@ int VLwrap()
|
||||
|
||||
/*
|
||||
* $Log: parse_misc.cc,v $
|
||||
* Revision 1.4 2000/02/23 02:56:55 steve
|
||||
* Macintosh compilers do not support ident.
|
||||
*
|
||||
* Revision 1.3 1999/09/29 21:15:31 steve
|
||||
* Standardize formatting of warning messages.
|
||||
*
|
||||
|
||||
+6
-3
@@ -1,7 +1,7 @@
|
||||
#ifndef __parse_misc_H
|
||||
#define __parse_misc_H
|
||||
/*
|
||||
* Copyright (c) 1998 Stephen Williams (steve@icarus.com)
|
||||
* Copyright (c) 1998-2000 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
|
||||
@@ -18,8 +18,8 @@
|
||||
* 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: parse_misc.h,v 1.3 1999/07/10 01:03:18 steve Exp $"
|
||||
#if !defined(WINNT) && !defined(macintosh)
|
||||
#ident "$Id: parse_misc.h,v 1.4 2000/02/23 02:56:55 steve Exp $"
|
||||
#endif
|
||||
|
||||
# include <list>
|
||||
@@ -53,6 +53,9 @@ extern unsigned error_count, warn_count;
|
||||
|
||||
/*
|
||||
* $Log: parse_misc.h,v $
|
||||
* Revision 1.4 2000/02/23 02:56:55 steve
|
||||
* Macintosh compilers do not support ident.
|
||||
*
|
||||
* Revision 1.3 1999/07/10 01:03:18 steve
|
||||
* remove string from lexical phase.
|
||||
*
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 1998-1999 Stephen Williams (steve@icarus.com)
|
||||
* Copyright (c) 1998-2000 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
|
||||
@@ -16,13 +16,14 @@
|
||||
* 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: pform.cc,v 1.47 1999/11/23 01:04:57 steve Exp $"
|
||||
#if !defined(WINNT) && !defined(macintosh)
|
||||
#ident "$Id: pform.cc,v 1.59 2000/05/08 05:30:20 steve Exp $"
|
||||
#endif
|
||||
|
||||
# include "compiler.h"
|
||||
# include "pform.h"
|
||||
# include "parse_misc.h"
|
||||
# include "PEvent.h"
|
||||
# include "PUdp.h"
|
||||
# include <list>
|
||||
# include <map>
|
||||
@@ -265,12 +266,32 @@ void pform_make_udp(const char*name, list<string>*parms,
|
||||
delete init_expr;
|
||||
}
|
||||
|
||||
/*
|
||||
* This is invoked to make a named event. This is the declaration of
|
||||
* the event, and not necessarily the use of it.
|
||||
*/
|
||||
static void pform_make_event(const string&name, const string&fn, unsigned ln)
|
||||
{
|
||||
PEvent*event = new PEvent(name);
|
||||
event->set_file(fn);
|
||||
event->set_lineno(ln);
|
||||
pform_cur_module->events[name] = event;
|
||||
}
|
||||
|
||||
void pform_make_events(const list<string>*names, const string&fn, unsigned ln)
|
||||
{
|
||||
list<string>::const_iterator cur;
|
||||
for (cur = names->begin() ; cur != names->end() ; cur++)
|
||||
pform_make_event(*cur, fn, ln);
|
||||
}
|
||||
|
||||
/*
|
||||
* pform_makegates is called when a list of gates (with the same type)
|
||||
* are ready to be instantiated. The function runs through the list of
|
||||
* gates and calls the pform_makegate function to make the individual gate.
|
||||
*/
|
||||
void pform_makegate(PGBuiltin::Type type,
|
||||
struct str_pair_t str,
|
||||
svector<PExpr*>* delay,
|
||||
const lgate&info)
|
||||
{
|
||||
@@ -285,6 +306,8 @@ void pform_makegate(PGBuiltin::Type type,
|
||||
if (info.range[0])
|
||||
cur->set_range(info.range[0], info.range[1]);
|
||||
|
||||
cur->strength0(str.str0);
|
||||
cur->strength1(str.str1);
|
||||
cur->set_file(info.file);
|
||||
cur->set_lineno(info.lineno);
|
||||
|
||||
@@ -292,10 +315,12 @@ void pform_makegate(PGBuiltin::Type type,
|
||||
}
|
||||
|
||||
void pform_makegates(PGBuiltin::Type type,
|
||||
svector<PExpr*>*delay, svector<lgate>*gates)
|
||||
struct str_pair_t str,
|
||||
svector<PExpr*>*delay,
|
||||
svector<lgate>*gates)
|
||||
{
|
||||
for (unsigned idx = 0 ; idx < gates->count() ; idx += 1) {
|
||||
pform_makegate(type, delay, (*gates)[idx]);
|
||||
pform_makegate(type, str, delay, (*gates)[idx]);
|
||||
}
|
||||
|
||||
delete gates;
|
||||
@@ -303,12 +328,15 @@ void pform_makegates(PGBuiltin::Type type,
|
||||
|
||||
/*
|
||||
* A module is different from a gate in that there are different
|
||||
* constraints, and sometimes different syntax.
|
||||
* constraints, and sometimes different syntax. The X_modgate
|
||||
* functions handle the instantaions of modules (and UDP objects) by
|
||||
* making PGModule objects.
|
||||
*/
|
||||
static void pform_make_modgate(const string&type,
|
||||
const string&name,
|
||||
svector<PExpr*>*overrides,
|
||||
struct parmvalue_t*overrides,
|
||||
svector<PExpr*>*wires,
|
||||
PExpr*msb, PExpr*lsb,
|
||||
const string&fn, unsigned ln)
|
||||
{
|
||||
if (name == "") {
|
||||
@@ -318,16 +346,35 @@ static void pform_make_modgate(const string&type,
|
||||
return;
|
||||
}
|
||||
|
||||
PGate*cur = new PGModule(type, name, overrides, wires);
|
||||
PGModule*cur = new PGModule(type, name, wires);
|
||||
cur->set_file(fn);
|
||||
cur->set_lineno(ln);
|
||||
cur->set_range(msb,lsb);
|
||||
|
||||
if (overrides && overrides->by_name) {
|
||||
unsigned cnt = overrides->by_name->count();
|
||||
named<PExpr*>*byname = new named<PExpr*>[cnt];
|
||||
|
||||
for (unsigned idx = 0 ; idx < cnt ; idx += 1) {
|
||||
portname_t*curp = (*overrides->by_name)[idx];
|
||||
byname[idx].name = curp->name;
|
||||
byname[idx].parm = curp->parm;
|
||||
}
|
||||
|
||||
cur->set_parameters(byname, cnt);
|
||||
|
||||
} else if (overrides && overrides->by_order) {
|
||||
cur->set_parameters(overrides->by_order);
|
||||
}
|
||||
|
||||
pform_cur_module->add_gate(cur);
|
||||
}
|
||||
|
||||
static void pform_make_modgate(const string&type,
|
||||
const string&name,
|
||||
svector<PExpr*>*overrides,
|
||||
struct parmvalue_t*overrides,
|
||||
svector<portname_t*>*bind,
|
||||
PExpr*msb, PExpr*lsb,
|
||||
const string&fn, unsigned ln)
|
||||
{
|
||||
if (name == "") {
|
||||
@@ -338,37 +385,70 @@ static void pform_make_modgate(const string&type,
|
||||
}
|
||||
|
||||
unsigned npins = bind->count();
|
||||
PGModule::bind_t*pins = new PGModule::bind_t[npins];
|
||||
named<PExpr*>*pins = new named<PExpr*>[npins];
|
||||
for (unsigned idx = 0 ; idx < npins ; idx += 1) {
|
||||
portname_t*curp = (*bind)[idx];
|
||||
pins[idx].name = curp->name;
|
||||
pins[idx].parm = curp->parm;
|
||||
}
|
||||
|
||||
PGate*cur = new PGModule(type, name, overrides, pins, npins);
|
||||
PGModule*cur = new PGModule(type, name, pins, npins);
|
||||
cur->set_file(fn);
|
||||
cur->set_lineno(ln);
|
||||
cur->set_range(msb,lsb);
|
||||
|
||||
if (overrides && overrides->by_name) {
|
||||
unsigned cnt = overrides->by_name->count();
|
||||
named<PExpr*>*byname = new named<PExpr*>[cnt];
|
||||
|
||||
for (unsigned idx = 0 ; idx < cnt ; idx += 1) {
|
||||
portname_t*curp = (*overrides->by_name)[idx];
|
||||
byname[idx].name = curp->name;
|
||||
byname[idx].parm = curp->parm;
|
||||
}
|
||||
|
||||
cur->set_parameters(byname, cnt);
|
||||
|
||||
} else if (overrides && overrides->by_order) {
|
||||
|
||||
cur->set_parameters(overrides->by_order);
|
||||
}
|
||||
|
||||
pform_cur_module->add_gate(cur);
|
||||
}
|
||||
|
||||
void pform_make_modgates(const string&type,
|
||||
svector<PExpr*>*overrides,
|
||||
struct parmvalue_t*overrides,
|
||||
svector<lgate>*gates)
|
||||
{
|
||||
if (overrides && overrides->by_order)
|
||||
for (unsigned idx = 0 ; idx < overrides->by_order->count() ; idx += 1)
|
||||
if (! pform_expression_is_constant((*overrides->by_order)[idx])) {
|
||||
VLerror("error: Parameter override expression"
|
||||
" must be constant.");
|
||||
return;
|
||||
}
|
||||
|
||||
for (unsigned idx = 0 ; idx < gates->count() ; idx += 1) {
|
||||
lgate cur = (*gates)[idx];
|
||||
|
||||
if (cur.parms_by_name) {
|
||||
pform_make_modgate(type, cur.name, overrides, cur.parms_by_name,
|
||||
pform_make_modgate(type, cur.name, overrides,
|
||||
cur.parms_by_name,
|
||||
cur.range[0], cur.range[1],
|
||||
cur.file, cur.lineno);
|
||||
|
||||
} else if (cur.parms) {
|
||||
pform_make_modgate(type, cur.name, overrides, cur.parms, cur.file,
|
||||
cur.lineno);
|
||||
pform_make_modgate(type, cur.name, overrides,
|
||||
cur.parms,
|
||||
cur.range[0], cur.range[1],
|
||||
cur.file, cur.lineno);
|
||||
} else {
|
||||
svector<PExpr*>*wires = new svector<PExpr*>(0);
|
||||
pform_make_modgate(type, cur.name, overrides, wires, cur.file,
|
||||
cur.lineno);
|
||||
pform_make_modgate(type, cur.name, overrides,
|
||||
wires,
|
||||
cur.range[0], cur.range[1],
|
||||
cur.file, cur.lineno);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -376,7 +456,8 @@ void pform_make_modgates(const string&type,
|
||||
}
|
||||
|
||||
PGAssign* pform_make_pgassign(PExpr*lval, PExpr*rval,
|
||||
svector<PExpr*>*del)
|
||||
svector<PExpr*>*del,
|
||||
struct str_pair_t str)
|
||||
{
|
||||
svector<PExpr*>*wires = new svector<PExpr*>(2);
|
||||
(*wires)[0] = lval;
|
||||
@@ -389,24 +470,69 @@ PGAssign* pform_make_pgassign(PExpr*lval, PExpr*rval,
|
||||
else
|
||||
cur = new PGAssign(wires, del);
|
||||
|
||||
cur->strength0(str.str0);
|
||||
cur->strength1(str.str1);
|
||||
|
||||
pform_cur_module->add_gate(cur);
|
||||
return cur;
|
||||
}
|
||||
|
||||
void pform_make_pgassign_list(svector<PExpr*>*alist,
|
||||
svector<PExpr*>*del,
|
||||
struct str_pair_t str,
|
||||
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);
|
||||
(*alist)[2*idx+1],
|
||||
del, str);
|
||||
tmp->set_file(text);
|
||||
tmp->set_lineno(lineno);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* this function makes the initial assignment to a register as given
|
||||
* in the source. It handles the case where a reg variable is assigned
|
||||
* where it it declared:
|
||||
*
|
||||
* reg foo = <expr>;
|
||||
*
|
||||
* This is equivilent to the combination of statements:
|
||||
*
|
||||
* reg foo;
|
||||
* initital foo = <expr>;
|
||||
*
|
||||
* and that is how it is parsed. This syntax is not part of the
|
||||
* IEEE1364-1994 standard, but is approved by OVI as enhancement
|
||||
* BTF-B14.
|
||||
*/
|
||||
void pform_make_reginit(const struct vlltype&li,
|
||||
const string&name, PExpr*expr)
|
||||
{
|
||||
const string sname = scoped_name(name);
|
||||
PWire*cur = pform_cur_module->get_wire(sname);
|
||||
if (cur == 0) {
|
||||
VLerror(li, "internal error: reginit to non-register?");
|
||||
delete expr;
|
||||
return;
|
||||
}
|
||||
|
||||
PEIdent*lval = new PEIdent(sname);
|
||||
lval->set_file(li.text);
|
||||
lval->set_lineno(li.first_line);
|
||||
PAssign*ass = new PAssign(lval, expr);
|
||||
ass->set_file(li.text);
|
||||
ass->set_lineno(li.first_line);
|
||||
PProcess*top = new PProcess(PProcess::PR_INITIAL, ass);
|
||||
top->set_file(li.text);
|
||||
top->set_lineno(li.first_line);
|
||||
|
||||
pform_cur_module->add_behavior(top);
|
||||
}
|
||||
|
||||
void pform_makewire(const vlltype&li, const string&nm,
|
||||
NetNet::Type type)
|
||||
{
|
||||
@@ -416,7 +542,7 @@ void pform_makewire(const vlltype&li, const string&nm,
|
||||
if (cur->get_wire_type() != NetNet::IMPLICIT) {
|
||||
strstream msg;
|
||||
msg << name << " previously defined at " <<
|
||||
cur->get_line() << ".";
|
||||
cur->get_line() << "." << ends;
|
||||
VLerror(msg.str());
|
||||
} else {
|
||||
bool rc = cur->set_wire_type(type);
|
||||
@@ -555,8 +681,16 @@ void pform_set_function(const string&name, svector<PExpr*>*ra, PFunction *func)
|
||||
void pform_set_attrib(const string&name, const string&key, const string&value)
|
||||
{
|
||||
PWire*cur = pform_cur_module->get_wire(name);
|
||||
assert(cur);
|
||||
cur->attributes[key] = value;
|
||||
if (PWire*cur = pform_cur_module->get_wire(name)) {
|
||||
cur->attributes[key] = value;
|
||||
|
||||
} else if (PGate*cur = pform_cur_module->get_gate(name)) {
|
||||
cur->attributes[key] = value;
|
||||
|
||||
} else {
|
||||
VLerror("Unable to match name for setting attribute.");
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -624,10 +758,23 @@ void pform_set_net_range(list<string>*names, const svector<PExpr*>*range)
|
||||
|
||||
void pform_set_parameter(const string&name, PExpr*expr)
|
||||
{
|
||||
assert(expr);
|
||||
pform_cur_module->parameters[name] = expr;
|
||||
pform_cur_module->param_names.push_back(name);
|
||||
}
|
||||
|
||||
void pform_set_localparam(const string&name, PExpr*expr)
|
||||
{
|
||||
assert(expr);
|
||||
pform_cur_module->localparams[name] = expr;
|
||||
}
|
||||
|
||||
void pform_set_defparam(const string&name, PExpr*expr)
|
||||
{
|
||||
assert(expr);
|
||||
pform_cur_module->defparms[name] = expr;
|
||||
}
|
||||
|
||||
void pform_set_port_type(list<string>*names, NetNet::PortType pt)
|
||||
{
|
||||
for (list<string>::const_iterator cur = names->begin()
|
||||
@@ -717,6 +864,46 @@ int pform_parse(const char*path, map<string,Module*>&modules,
|
||||
|
||||
/*
|
||||
* $Log: pform.cc,v $
|
||||
* Revision 1.59 2000/05/08 05:30:20 steve
|
||||
* Deliver gate output strengths to the netlist.
|
||||
*
|
||||
* Revision 1.58 2000/05/06 15:41:57 steve
|
||||
* Carry assignment strength to pform.
|
||||
*
|
||||
* Revision 1.57 2000/04/01 19:31:57 steve
|
||||
* Named events as far as the pform.
|
||||
*
|
||||
* Revision 1.56 2000/03/12 17:09:41 steve
|
||||
* Support localparam.
|
||||
*
|
||||
* Revision 1.55 2000/03/08 04:36:54 steve
|
||||
* Redesign the implementation of scopes and parameters.
|
||||
* I now generate the scopes and notice the parameters
|
||||
* in a separate pass over the pform. Once the scopes
|
||||
* are generated, I can process overrides and evalutate
|
||||
* paremeters before elaboration begins.
|
||||
*
|
||||
* Revision 1.54 2000/02/23 02:56:55 steve
|
||||
* Macintosh compilers do not support ident.
|
||||
*
|
||||
* Revision 1.53 2000/02/18 05:15:03 steve
|
||||
* Catch module instantiation arrays.
|
||||
*
|
||||
* Revision 1.52 2000/01/09 05:50:49 steve
|
||||
* Support named parameter override lists.
|
||||
*
|
||||
* Revision 1.51 2000/01/02 01:59:28 steve
|
||||
* Forgot to handle no overrides at all.
|
||||
*
|
||||
* Revision 1.50 2000/01/01 23:47:58 steve
|
||||
* Fix module parameter override syntax.
|
||||
*
|
||||
* Revision 1.49 1999/12/30 19:06:14 steve
|
||||
* Support reg initial assignment syntax.
|
||||
*
|
||||
* Revision 1.48 1999/12/11 05:45:41 steve
|
||||
* Fix support for attaching attributes to primitive gates.
|
||||
*
|
||||
* Revision 1.47 1999/11/23 01:04:57 steve
|
||||
* A file name of - means standard input.
|
||||
*
|
||||
@@ -751,155 +938,5 @@ int pform_parse(const char*path, map<string,Module*>&modules,
|
||||
* Revision 1.37 1999/08/03 04:14:49 steve
|
||||
* Parse into pform arbitrarily complex module
|
||||
* port declarations.
|
||||
*
|
||||
* Revision 1.36 1999/08/01 16:34:50 steve
|
||||
* Parse and elaborate rise/fall/decay times
|
||||
* for gates, and handle the rules for partial
|
||||
* lists of times.
|
||||
*
|
||||
* Revision 1.35 1999/07/31 19:15:21 steve
|
||||
* misspelled comment.
|
||||
*
|
||||
* Revision 1.34 1999/07/31 19:14:47 steve
|
||||
* Add functions up to elaboration (Ed Carter)
|
||||
*
|
||||
* Revision 1.33 1999/07/24 02:11:20 steve
|
||||
* Elaborate task input ports.
|
||||
*
|
||||
* Revision 1.32 1999/07/10 01:03:18 steve
|
||||
* remove string from lexical phase.
|
||||
*
|
||||
* Revision 1.31 1999/07/03 02:12:52 steve
|
||||
* Elaborate user defined tasks.
|
||||
*
|
||||
* Revision 1.30 1999/06/24 04:24:18 steve
|
||||
* Handle expression widths for EEE and NEE operators,
|
||||
* add named blocks and scope handling,
|
||||
* add registers declared in named blocks.
|
||||
*
|
||||
* Revision 1.29 1999/06/21 01:02:16 steve
|
||||
* Fix merging of UDP port type in decls.
|
||||
*
|
||||
* Revision 1.28 1999/06/17 05:34:42 steve
|
||||
* Clean up interface of the PWire class,
|
||||
* Properly match wire ranges.
|
||||
*
|
||||
* Revision 1.27 1999/06/15 03:44:53 steve
|
||||
* Get rid of the STL vector template.
|
||||
*
|
||||
* Revision 1.26 1999/06/13 23:51:16 steve
|
||||
* l-value part select for procedural assignments.
|
||||
*
|
||||
* Revision 1.25 1999/06/12 20:35:27 steve
|
||||
* parse more verilog.
|
||||
*
|
||||
* Revision 1.24 1999/06/12 03:42:17 steve
|
||||
* Assert state of bit range expressions.
|
||||
*
|
||||
* Revision 1.23 1999/06/06 20:45:39 steve
|
||||
* Add parse and elaboration of non-blocking assignments,
|
||||
* Replace list<PCase::Item*> with an svector version,
|
||||
* Add integer support.
|
||||
*
|
||||
* Revision 1.22 1999/06/02 15:38:46 steve
|
||||
* Line information with nets.
|
||||
*
|
||||
* Revision 1.21 1999/05/31 15:45:59 steve
|
||||
* makegates infinite loop fixed.
|
||||
*
|
||||
* Revision 1.20 1999/05/29 02:36:17 steve
|
||||
* module parameter bind by name.
|
||||
*
|
||||
* Revision 1.19 1999/05/20 04:31:45 steve
|
||||
* Much expression parsing work,
|
||||
* mark continuous assigns with source line info,
|
||||
* replace some assertion failures with Sorry messages.
|
||||
*
|
||||
* Revision 1.18 1999/05/16 05:08:42 steve
|
||||
* Redo constant expression detection to happen
|
||||
* after parsing.
|
||||
*
|
||||
* Parse more operators and expressions.
|
||||
*
|
||||
* Revision 1.17 1999/05/10 00:16:58 steve
|
||||
* Parse and elaborate the concatenate operator
|
||||
* in structural contexts, Replace vector<PExpr*>
|
||||
* and list<PExpr*> with svector<PExpr*>, evaluate
|
||||
* constant expressions with parameters, handle
|
||||
* memories as lvalues.
|
||||
*
|
||||
* Parse task declarations, integer types.
|
||||
*
|
||||
* Revision 1.16 1999/05/08 20:19:20 steve
|
||||
* Parse more things.
|
||||
*
|
||||
* Revision 1.15 1999/05/07 04:26:49 steve
|
||||
* Parse more complex continuous assign lvalues.
|
||||
*
|
||||
* Revision 1.14 1999/05/06 04:37:17 steve
|
||||
* Get rid of list<lgate> types.
|
||||
*
|
||||
* Revision 1.13 1999/05/06 04:09:28 steve
|
||||
* Parse more constant expressions.
|
||||
*
|
||||
* Revision 1.12 1999/05/02 23:25:32 steve
|
||||
* Enforce module instance names.
|
||||
*
|
||||
* Revision 1.11 1999/04/19 01:59:37 steve
|
||||
* Add memories to the parse and elaboration phases.
|
||||
*
|
||||
* Revision 1.10 1999/02/21 17:01:57 steve
|
||||
* Add support for module parameters.
|
||||
*
|
||||
* Revision 1.9 1999/02/15 02:06:15 steve
|
||||
* Elaborate gate ranges.
|
||||
*
|
||||
* Revision 1.8 1999/01/25 05:45:56 steve
|
||||
* Add the LineInfo class to carry the source file
|
||||
* location of things. PGate, Statement and PProcess.
|
||||
*
|
||||
* elaborate handles module parameter mismatches,
|
||||
* missing or incorrect lvalues for procedural
|
||||
* assignment, and errors are propogated to the
|
||||
* top of the elaboration call tree.
|
||||
*
|
||||
* Attach line numbers to processes, gates and
|
||||
* assignment statements.
|
||||
*
|
||||
* Revision 1.7 1998/12/09 04:02:47 steve
|
||||
* Support the include directive.
|
||||
*
|
||||
* Revision 1.6 1998/12/01 00:42:14 steve
|
||||
* Elaborate UDP devices,
|
||||
* Support UDP type attributes, and
|
||||
* pass those attributes to nodes that
|
||||
* are instantiated by elaboration,
|
||||
* Put modules into a map instead of
|
||||
* a simple list.
|
||||
*
|
||||
* Revision 1.5 1998/11/25 02:35:53 steve
|
||||
* Parse UDP primitives all the way to pform.
|
||||
*
|
||||
* Revision 1.4 1998/11/23 00:20:23 steve
|
||||
* NetAssign handles lvalues as pin links
|
||||
* instead of a signal pointer,
|
||||
* Wire attributes added,
|
||||
* Ability to parse UDP descriptions added,
|
||||
* XNF generates EXT records for signals with
|
||||
* the PAD attribute.
|
||||
*
|
||||
* Revision 1.3 1998/11/11 00:01:51 steve
|
||||
* Check net ranges in declarations.
|
||||
*
|
||||
* Revision 1.2 1998/11/07 17:05:06 steve
|
||||
* Handle procedural conditional, and some
|
||||
* of the conditional expressions.
|
||||
*
|
||||
* Elaborate signals and identifiers differently,
|
||||
* allowing the netlist to hold signal information.
|
||||
*
|
||||
* Revision 1.1 1998/11/03 23:29:03 steve
|
||||
* Introduce verilog to CVS.
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
#ifndef __pform_H
|
||||
#define __pform_H
|
||||
/*
|
||||
* Copyright (c) 1998-1999 Stephen Williams (steve@icarus.com)
|
||||
* Copyright (c) 1998-2000 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
|
||||
@@ -18,11 +18,12 @@
|
||||
* 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: pform.h,v 1.31 1999/09/10 05:02:09 steve Exp $"
|
||||
#if !defined(WINNT) && !defined(macintosh)
|
||||
#ident "$Id: pform.h,v 1.40 2000/05/08 05:30:20 steve Exp $"
|
||||
#endif
|
||||
|
||||
# include "netlist.h"
|
||||
# include "named.h"
|
||||
# include "Module.h"
|
||||
# include "Statement.h"
|
||||
# include "PGate.h"
|
||||
@@ -65,11 +66,16 @@ struct vlltype;
|
||||
|
||||
/* This is information about port name information for named port
|
||||
connections. */
|
||||
struct portname_t {
|
||||
string name;
|
||||
PExpr*parm;
|
||||
|
||||
typedef struct named<PExpr*> portname_t;
|
||||
|
||||
struct parmvalue_t {
|
||||
svector<PExpr*>*by_order;
|
||||
svector<portname_t*>*by_name;
|
||||
};
|
||||
|
||||
struct str_pair_t { PGate::strength_t str0, str1; };
|
||||
|
||||
/* The lgate is gate instantiation information. */
|
||||
struct lgate {
|
||||
lgate(int =0)
|
||||
@@ -116,6 +122,8 @@ extern void pform_makewire(const struct vlltype&li, const string&name,
|
||||
NetNet::Type type = NetNet::IMPLICIT);
|
||||
extern void pform_makewire(const struct vlltype&li, const list<string>*names,
|
||||
NetNet::Type type);
|
||||
extern void pform_make_reginit(const struct vlltype&li,
|
||||
const string&name, PExpr*expr);
|
||||
extern void pform_set_port_type(list<string>*names, NetNet::PortType);
|
||||
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);
|
||||
@@ -127,29 +135,37 @@ extern void pform_set_attrib(const string&name, const string&key,
|
||||
extern void pform_set_type_attrib(const string&name, const string&key,
|
||||
const string&value);
|
||||
extern void pform_set_parameter(const string&name, PExpr*expr);
|
||||
extern void pform_set_localparam(const string&name, PExpr*expr);
|
||||
extern void pform_set_defparam(const string&name, PExpr*expr);
|
||||
extern PProcess* pform_make_behavior(PProcess::Type, Statement*);
|
||||
|
||||
extern svector<PWire*>* pform_make_udp_input_ports(list<string>*);
|
||||
|
||||
extern bool pform_expression_is_constant(const PExpr*);
|
||||
|
||||
extern void pform_make_events(const list<string>*names,
|
||||
const string&file, unsigned lineno);
|
||||
|
||||
/*
|
||||
* The makegate function creates a new gate (which need not have a
|
||||
* name) and connects it to the specified wires.
|
||||
*/
|
||||
extern void pform_makegates(PGBuiltin::Type type,
|
||||
struct str_pair_t str,
|
||||
svector<PExpr*>*delay,
|
||||
svector<lgate>*gates);
|
||||
|
||||
extern void pform_make_modgates(const string&type,
|
||||
svector<PExpr*>*overrides,
|
||||
struct parmvalue_t*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);
|
||||
svector<PExpr*>*delays,
|
||||
struct str_pair_t str);
|
||||
extern void pform_make_pgassign_list(svector<PExpr*>*alist,
|
||||
svector<PExpr*>*del,
|
||||
struct str_pair_t str,
|
||||
const string& text,
|
||||
unsigned lineno);
|
||||
|
||||
@@ -174,6 +190,37 @@ extern void pform_dump(ostream&out, Module*mod);
|
||||
|
||||
/*
|
||||
* $Log: pform.h,v $
|
||||
* Revision 1.40 2000/05/08 05:30:20 steve
|
||||
* Deliver gate output strengths to the netlist.
|
||||
*
|
||||
* Revision 1.39 2000/05/06 15:41:57 steve
|
||||
* Carry assignment strength to pform.
|
||||
*
|
||||
* Revision 1.38 2000/04/01 19:31:57 steve
|
||||
* Named events as far as the pform.
|
||||
*
|
||||
* Revision 1.37 2000/03/12 17:09:41 steve
|
||||
* Support localparam.
|
||||
*
|
||||
* Revision 1.36 2000/03/08 04:36:54 steve
|
||||
* Redesign the implementation of scopes and parameters.
|
||||
* I now generate the scopes and notice the parameters
|
||||
* in a separate pass over the pform. Once the scopes
|
||||
* are generated, I can process overrides and evalutate
|
||||
* paremeters before elaboration begins.
|
||||
*
|
||||
* Revision 1.35 2000/02/23 02:56:55 steve
|
||||
* Macintosh compilers do not support ident.
|
||||
*
|
||||
* Revision 1.34 2000/01/10 22:16:24 steve
|
||||
* minor type syntax fix for stubborn C++ compilers.
|
||||
*
|
||||
* Revision 1.33 2000/01/09 05:50:49 steve
|
||||
* Support named parameter override lists.
|
||||
*
|
||||
* Revision 1.32 1999/12/30 19:06:14 steve
|
||||
* Support reg initial assignment syntax.
|
||||
*
|
||||
* Revision 1.31 1999/09/10 05:02:09 steve
|
||||
* Handle integers at task parameters.
|
||||
*
|
||||
|
||||
+182
-15
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 1998 Stephen Williams (steve@icarus.com)
|
||||
* Copyright (c) 1998-2000 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
|
||||
@@ -16,8 +16,8 @@
|
||||
* 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: pform_dump.cc,v 1.45 1999/10/10 01:59:55 steve Exp $"
|
||||
#if !defined(WINNT) && !defined(macintosh)
|
||||
#ident "$Id: pform_dump.cc,v 1.58 2000/05/11 23:37:27 steve Exp $"
|
||||
#endif
|
||||
|
||||
/*
|
||||
@@ -27,6 +27,7 @@
|
||||
* module in question.
|
||||
*/
|
||||
# include "pform.h"
|
||||
# include "PEvent.h"
|
||||
# include <iostream>
|
||||
# include <iomanip>
|
||||
# include <typeinfo>
|
||||
@@ -43,6 +44,30 @@ ostream& operator << (ostream&o, const PDelays&d)
|
||||
return o;
|
||||
}
|
||||
|
||||
ostream& operator<< (ostream&o, PGate::strength_t str)
|
||||
{
|
||||
switch (str) {
|
||||
case PGate::HIGHZ:
|
||||
o << "highz";
|
||||
break;
|
||||
case PGate::WEAK:
|
||||
o << "weak";
|
||||
break;
|
||||
case PGate::PULL:
|
||||
o << "pull";
|
||||
break;
|
||||
case PGate::STRONG:
|
||||
o << "strong";
|
||||
break;
|
||||
case PGate::SUPPLY:
|
||||
o << "supply";
|
||||
break;
|
||||
default:
|
||||
assert(0);
|
||||
}
|
||||
return o;
|
||||
}
|
||||
|
||||
void PExpr::dump(ostream&out) const
|
||||
{
|
||||
out << typeid(*this).name();
|
||||
@@ -70,10 +95,13 @@ void PEConcat::dump(ostream&out) const
|
||||
void PECallFunction::dump(ostream &out) const
|
||||
{
|
||||
out << name_ << "(";
|
||||
parms_[0]->dump(out);
|
||||
for (unsigned idx = 1; idx < parms_.count(); ++idx) {
|
||||
out << ", ";
|
||||
parms_[idx]->dump(out);
|
||||
|
||||
if (parms_.count() > 0) {
|
||||
parms_[0]->dump(out);
|
||||
for (unsigned idx = 1; idx < parms_.count(); ++idx) {
|
||||
out << ", ";
|
||||
parms_[idx]->dump(out);
|
||||
}
|
||||
}
|
||||
out << ")";
|
||||
}
|
||||
@@ -81,19 +109,20 @@ void PECallFunction::dump(ostream &out) const
|
||||
void PEEvent::dump(ostream&out) const
|
||||
{
|
||||
switch (type_) {
|
||||
case NetNEvent::ANYEDGE:
|
||||
case PEEvent::ANYEDGE:
|
||||
break;
|
||||
case NetNEvent::POSEDGE:
|
||||
case PEEvent::POSEDGE:
|
||||
out << "posedge ";
|
||||
break;
|
||||
case NetNEvent::NEGEDGE:
|
||||
case PEEvent::NEGEDGE:
|
||||
out << "negedge ";
|
||||
break;
|
||||
case NetNEvent::POSITIVE:
|
||||
case PEEvent::POSITIVE:
|
||||
out << "positive ";
|
||||
break;
|
||||
}
|
||||
out << *expr_;
|
||||
|
||||
}
|
||||
|
||||
void PENumber::dump(ostream&out) const
|
||||
@@ -247,7 +276,7 @@ void PGate::dump(ostream&out) const
|
||||
|
||||
void PGAssign::dump(ostream&out) const
|
||||
{
|
||||
out << " assign ";
|
||||
out << " assign (" << strength0() << "0 " << strength1() << "1) ";
|
||||
dump_delays(out);
|
||||
out << " " << *pin(0) << " = " << *pin(1) << ";" << endl;
|
||||
}
|
||||
@@ -268,6 +297,7 @@ void PGBuiltin::dump(ostream&out) const
|
||||
out << " builtin gate ";
|
||||
}
|
||||
|
||||
out << "(" << strength0() << "0 " << strength1() << "1) ";
|
||||
dump_delays(out);
|
||||
out << " " << get_name();
|
||||
|
||||
@@ -283,7 +313,10 @@ void PGBuiltin::dump(ostream&out) const
|
||||
void PGModule::dump(ostream&out) const
|
||||
{
|
||||
out << " " << type_ << " ";
|
||||
|
||||
// If parameters are overridden by order, dump them.
|
||||
if (overrides_) {
|
||||
assert(parms_ == 0);
|
||||
out << "#(";
|
||||
out << *((*overrides_)[0]);
|
||||
for (unsigned idx = 1 ; idx < overrides_->count() ; idx += 1) {
|
||||
@@ -291,7 +324,31 @@ void PGModule::dump(ostream&out) const
|
||||
}
|
||||
out << ") ";
|
||||
}
|
||||
out << get_name() << "(";
|
||||
|
||||
// If parameters are overridden by name, dump them.
|
||||
if (parms_) {
|
||||
assert(overrides_ == 0);
|
||||
out << "#(";
|
||||
out << "." << parms_[0].name << "(" << *parms_[0].parm << ")";
|
||||
for (unsigned idx = 1 ; idx < nparms_ ; idx += 1) {
|
||||
out << ", ." << parms_[idx].name << "(" <<
|
||||
*parms_[idx].parm << ")";
|
||||
}
|
||||
out << ") ";
|
||||
}
|
||||
|
||||
out << get_name();
|
||||
|
||||
// If the module is arrayed, print the index expressions.
|
||||
if (msb_ || lsb_) {
|
||||
out << "[";
|
||||
if (msb_) out << *msb_;
|
||||
out << ":";
|
||||
if (lsb_) out << *lsb_;
|
||||
out << "]";
|
||||
}
|
||||
|
||||
out << "(";
|
||||
if (pins_) {
|
||||
out << "." << pins_[0].name << "(";
|
||||
if (pins_[0].parm) out << *pins_[0].parm;
|
||||
@@ -424,6 +481,18 @@ void PCondit::dump(ostream&out, unsigned ind) const
|
||||
}
|
||||
}
|
||||
|
||||
void PCAssign::dump(ostream&out, unsigned ind) const
|
||||
{
|
||||
out << setw(ind) << "" << "assign " << *lval_ << " = " << *expr_
|
||||
<< "; /* " << get_line() << " */" << endl;
|
||||
}
|
||||
|
||||
void PDeassign::dump(ostream&out, unsigned ind) const
|
||||
{
|
||||
out << setw(ind) << "" << "deassign " << *lval_ << "; /* "
|
||||
<< get_line() << " */" << endl;
|
||||
}
|
||||
|
||||
void PDelayStatement::dump(ostream&out, unsigned ind) const
|
||||
{
|
||||
out << setw(ind) << "" << "#" << *delay_ << " /* " <<
|
||||
@@ -454,6 +523,12 @@ void PEventStatement::dump(ostream&out, unsigned ind) const
|
||||
}
|
||||
}
|
||||
|
||||
void PForce::dump(ostream&out, unsigned ind) const
|
||||
{
|
||||
out << setw(ind) << "" << "force " << *lval_ << " = " << *expr_
|
||||
<< "; /* " << get_line() << " */" << endl;
|
||||
}
|
||||
|
||||
void PForever::dump(ostream&out, unsigned ind) const
|
||||
{
|
||||
out << setw(ind) << "" << "forever /* " << get_line() << " */" << endl;
|
||||
@@ -483,6 +558,12 @@ void PFunction::dump(ostream&out, unsigned ind) const
|
||||
out << setw(ind) << "" << "/* NOOP */" << endl;
|
||||
}
|
||||
|
||||
void PRelease::dump(ostream&out, unsigned ind) const
|
||||
{
|
||||
out << setw(ind) << "" << "release " << *lval_ << "; /* "
|
||||
<< get_line() << " */" << endl;
|
||||
}
|
||||
|
||||
void PRepeat::dump(ostream&out, unsigned ind) const
|
||||
{
|
||||
out << setw(ind) << "" << "repeat (" << *expr_ << ")" << endl;
|
||||
@@ -514,6 +595,10 @@ void PTask::dump(ostream&out, unsigned ind) const
|
||||
out << setw(ind) << "" << "/* NOOP */" << endl;
|
||||
}
|
||||
|
||||
void PTrigger::dump(ostream&out, unsigned ind) const
|
||||
{
|
||||
out << setw(ind) << "" << "-> " << event_ << ";" << endl;
|
||||
}
|
||||
|
||||
void PWhile::dump(ostream&out, unsigned ind) const
|
||||
{
|
||||
@@ -582,12 +667,37 @@ void Module::dump(ostream&out) const
|
||||
out << "/* ERROR */;" << endl;
|
||||
}
|
||||
|
||||
for (parm_iter_t cur = localparams.begin()
|
||||
; cur != localparams.end() ; cur ++) {
|
||||
out << " localparam " << (*cur).first << " = ";
|
||||
if ((*cur).second)
|
||||
out << *(*cur).second << ";" << endl;
|
||||
else
|
||||
out << "/* ERROR */;" << endl;
|
||||
}
|
||||
|
||||
for (parm_iter_t cur = defparms.begin()
|
||||
; cur != defparms.end() ; cur ++) {
|
||||
out << " defparam " << (*cur).first << " = ";
|
||||
if ((*cur).second)
|
||||
out << *(*cur).second << ";" << endl;
|
||||
else
|
||||
out << "/* ERROR */;" << endl;
|
||||
}
|
||||
|
||||
for (map<string,PEvent*>::const_iterator cur = events.begin()
|
||||
; cur != events.end() ; cur ++ ) {
|
||||
PEvent*ev = (*cur).second;
|
||||
out << " event " << ev->name() << "; // "
|
||||
<< ev->get_line() << endl;
|
||||
}
|
||||
|
||||
// Iterate through and display all the wires.
|
||||
for (list<PWire*>::const_iterator wire = wires_.begin()
|
||||
for (map<string,PWire*>::const_iterator wire = wires_.begin()
|
||||
; wire != wires_.end()
|
||||
; wire ++ ) {
|
||||
|
||||
(*wire)->dump(out);
|
||||
(*wire).second->dump(out);
|
||||
}
|
||||
|
||||
// Dump the task definitions.
|
||||
@@ -675,6 +785,63 @@ void PUdp::dump(ostream&out) const
|
||||
|
||||
/*
|
||||
* $Log: pform_dump.cc,v $
|
||||
* Revision 1.58 2000/05/11 23:37:27 steve
|
||||
* Add support for procedural continuous assignment.
|
||||
*
|
||||
* Revision 1.57 2000/05/06 15:41:57 steve
|
||||
* Carry assignment strength to pform.
|
||||
*
|
||||
* Revision 1.56 2000/05/04 03:37:59 steve
|
||||
* Add infrastructure for system functions, move
|
||||
* $time to that structure and add $random.
|
||||
*
|
||||
* Revision 1.55 2000/04/22 04:20:19 steve
|
||||
* Add support for force assignment.
|
||||
*
|
||||
* Revision 1.54 2000/04/12 20:02:53 steve
|
||||
* Finally remove the NetNEvent and NetPEvent classes,
|
||||
* Get synthesis working with the NetEvWait class,
|
||||
* and get started supporting multiple events in a
|
||||
* wait in vvm.
|
||||
*
|
||||
* Revision 1.53 2000/04/12 04:23:58 steve
|
||||
* Named events really should be expressed with PEIdent
|
||||
* objects in the pform,
|
||||
*
|
||||
* Handle named events within the mix of net events
|
||||
* and edges. As a unified lot they get caught together.
|
||||
* wait statements are broken into more complex statements
|
||||
* that include a conditional.
|
||||
*
|
||||
* Do not generate NetPEvent or NetNEvent objects in
|
||||
* elaboration. NetEvent, NetEvWait and NetEvProbe
|
||||
* take over those functions in the netlist.
|
||||
*
|
||||
* Revision 1.52 2000/04/01 19:31:57 steve
|
||||
* Named events as far as the pform.
|
||||
*
|
||||
* Revision 1.51 2000/03/12 17:09:41 steve
|
||||
* Support localparam.
|
||||
*
|
||||
* Revision 1.50 2000/03/08 04:36:54 steve
|
||||
* Redesign the implementation of scopes and parameters.
|
||||
* I now generate the scopes and notice the parameters
|
||||
* in a separate pass over the pform. Once the scopes
|
||||
* are generated, I can process overrides and evalutate
|
||||
* paremeters before elaboration begins.
|
||||
*
|
||||
* Revision 1.49 2000/02/23 02:56:55 steve
|
||||
* Macintosh compilers do not support ident.
|
||||
*
|
||||
* Revision 1.48 2000/02/18 05:15:03 steve
|
||||
* Catch module instantiation arrays.
|
||||
*
|
||||
* Revision 1.47 2000/01/09 20:37:57 steve
|
||||
* Careful with wires connected to multiple ports.
|
||||
*
|
||||
* Revision 1.46 2000/01/09 05:50:49 steve
|
||||
* Support named parameter override lists.
|
||||
*
|
||||
* Revision 1.45 1999/10/10 01:59:55 steve
|
||||
* Structural case equals device.
|
||||
*
|
||||
|
||||
+14
-3
@@ -16,8 +16,8 @@
|
||||
* 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: propinit.cc,v 1.1 1998/12/20 02:05:41 steve Exp $"
|
||||
#if !defined(WINNT) && !defined(macintosh)
|
||||
#ident "$Id: propinit.cc,v 1.3 2000/05/07 04:37:56 steve Exp $"
|
||||
#endif
|
||||
|
||||
/*
|
||||
@@ -61,7 +61,7 @@ static void prop_sequdp_output(NetUDP*udp)
|
||||
/* Take the output value and write it to all the NetNet pins
|
||||
that are connected to the output pin. */
|
||||
|
||||
for (NetObj::Link*lnk = udp->pin(0).next_link()
|
||||
for (Link*lnk = udp->pin(0).next_link()
|
||||
; (*lnk) != udp->pin(0) ; lnk = lnk->next_link()) {
|
||||
|
||||
if (NetNet*sig = dynamic_cast<NetNet*>(lnk->get_obj()))
|
||||
@@ -81,6 +81,17 @@ void propinit(Design*des)
|
||||
|
||||
/*
|
||||
* $Log: propinit.cc,v $
|
||||
* Revision 1.3 2000/05/07 04:37:56 steve
|
||||
* Carry strength values from Verilog source to the
|
||||
* pform and netlist for gates.
|
||||
*
|
||||
* Change vvm constants to use the driver_t to drive
|
||||
* a constant value. This works better if there are
|
||||
* multiple drivers on a signal.
|
||||
*
|
||||
* Revision 1.2 2000/02/23 02:56:55 steve
|
||||
* Macintosh compilers do not support ident.
|
||||
*
|
||||
* Revision 1.1 1998/12/20 02:05:41 steve
|
||||
* Function to calculate wire initial value.
|
||||
*
|
||||
|
||||
+77
-11
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 1999 Stephen Williams (steve@icarus.com)
|
||||
* Copyright (c) 1999-2000 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
|
||||
@@ -16,8 +16,8 @@
|
||||
* 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 $"
|
||||
#if !defined(WINNT) && !defined(macintosh)
|
||||
#ident "$Id: set_width.cc,v 1.13 2000/05/04 03:37:59 steve Exp $"
|
||||
#endif
|
||||
|
||||
/*
|
||||
@@ -126,10 +126,18 @@ bool NetEBBits::set_width(unsigned w)
|
||||
*/
|
||||
bool NetEBComp::set_width(unsigned w)
|
||||
{
|
||||
bool flag = true;
|
||||
return (w == 1);
|
||||
}
|
||||
|
||||
/*
|
||||
* There is nothing we can do to the operands of a division to make it
|
||||
* confirm to the requested width. Force the context to pad or truncate.
|
||||
*/
|
||||
bool NetEBDiv::set_width(unsigned w)
|
||||
{
|
||||
return w == expr_width();
|
||||
}
|
||||
|
||||
bool NetEBLogic::set_width(unsigned w)
|
||||
{
|
||||
bool flag;
|
||||
@@ -139,6 +147,15 @@ bool NetEBLogic::set_width(unsigned w)
|
||||
return (w == 1);
|
||||
}
|
||||
|
||||
/*
|
||||
* There is nothing we can do to the operands of a multiply to make it
|
||||
* confirm to the requested width. Force the context to pad or truncate.
|
||||
*/
|
||||
bool NetEBMult::set_width(unsigned w)
|
||||
{
|
||||
return w == expr_width();
|
||||
}
|
||||
|
||||
/*
|
||||
* The shift operator allows the shift amount to have its own
|
||||
* natural width. The width of the operator result is the width of the
|
||||
@@ -176,13 +193,34 @@ bool NetEConcat::set_width(unsigned w)
|
||||
|
||||
bool NetEConst::set_width(unsigned w)
|
||||
{
|
||||
if (w > value_.len())
|
||||
return false;
|
||||
if (w > value_.len()) {
|
||||
verinum tmp (verinum::V0, w);
|
||||
for (unsigned idx = 0 ; idx < value_.len() ; idx += 1)
|
||||
tmp.set(idx, value_[idx]);
|
||||
|
||||
assert(w <= value_.len());
|
||||
value_ = verinum(value_, w);
|
||||
expr_width(w);
|
||||
return true;
|
||||
value_ = tmp;
|
||||
|
||||
expr_width(w);
|
||||
return true;
|
||||
|
||||
} else {
|
||||
unsigned use_w = w;
|
||||
bool flag = true;
|
||||
|
||||
// Don't reduce a number too small to hold all the
|
||||
// significant bits.
|
||||
for (unsigned idx = w ; idx < value_.len() ; idx += 1)
|
||||
if (value_[idx] != verinum::V0)
|
||||
use_w = idx+1;
|
||||
|
||||
verinum tmp (verinum::V0, use_w);
|
||||
for (unsigned idx = 0 ; idx < use_w ; idx += 1)
|
||||
tmp.set(idx, value_[idx]);
|
||||
|
||||
value_ = tmp;
|
||||
expr_width(use_w);
|
||||
return use_w == w;
|
||||
}
|
||||
}
|
||||
|
||||
bool NetEMemory::set_width(unsigned w)
|
||||
@@ -199,6 +237,11 @@ bool NetEParam::set_width(unsigned)
|
||||
return false;
|
||||
}
|
||||
|
||||
bool NetESFunc::set_width(unsigned w)
|
||||
{
|
||||
return w == expr_width();
|
||||
}
|
||||
|
||||
/*
|
||||
* The signal should automatically pad with zeros to get to th desired
|
||||
* width. Do not allow signal bits to be truncated, however.
|
||||
@@ -244,18 +287,41 @@ bool NetEUnary::set_width(unsigned w)
|
||||
case '~':
|
||||
case '-':
|
||||
flag = expr_->set_width(w);
|
||||
expr_width(w);
|
||||
break;
|
||||
default:
|
||||
flag = expr_width() == w;
|
||||
break;
|
||||
}
|
||||
expr_width(w);
|
||||
|
||||
return flag;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* $Log: set_width.cc,v $
|
||||
* Revision 1.13 2000/05/04 03:37:59 steve
|
||||
* Add infrastructure for system functions, move
|
||||
* $time to that structure and add $random.
|
||||
*
|
||||
* Revision 1.12 2000/04/28 18:43:23 steve
|
||||
* integer division in expressions properly get width.
|
||||
*
|
||||
* Revision 1.11 2000/04/26 03:33:32 steve
|
||||
* Do not set width too small to hold significant bits.
|
||||
*
|
||||
* Revision 1.10 2000/04/21 02:46:42 steve
|
||||
* Many Unary operators have known widths.
|
||||
*
|
||||
* Revision 1.9 2000/02/23 02:56:55 steve
|
||||
* Macintosh compilers do not support ident.
|
||||
*
|
||||
* Revision 1.8 2000/01/13 03:35:35 steve
|
||||
* Multiplication all the way to simulation.
|
||||
*
|
||||
* Revision 1.7 2000/01/01 19:56:51 steve
|
||||
* Properly expand/shrink constants in expressions.
|
||||
*
|
||||
* Revision 1.6 1999/10/05 06:19:46 steve
|
||||
* Add support for reduction NOR.
|
||||
*
|
||||
|
||||
-189
@@ -1,189 +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: sigfold.cc,v 1.3 1999/11/06 04:51:11 steve Exp $"
|
||||
#endif
|
||||
|
||||
# include "netlist.h"
|
||||
|
||||
/*
|
||||
* Some targets require that a list of connections include exactly one
|
||||
* signal. This processing step deletes excess signals to meet that
|
||||
* requirement.
|
||||
*
|
||||
* If there is a ring that has more then one signal connected
|
||||
* together, the following heuristic is used to choose which signal to
|
||||
* keep:
|
||||
*
|
||||
* If the name of signal X is deeper in the design hierarchy then
|
||||
* signal Y, keep signal Y.
|
||||
*
|
||||
* Else, if X is a bus that is not as wide as Y, keep signal Y.
|
||||
*
|
||||
* The result of this should be that signals of enclosing modules will
|
||||
* be preferred over signals of instantiated modules, and bussed
|
||||
* signals (vectors) will be preferred over scaler signals.
|
||||
*
|
||||
* The presence of attributes modifies the folding process, by placing
|
||||
* restrictions on what is allowed.
|
||||
*
|
||||
* If two signals have an attribute key X, they can be folded
|
||||
* only if X has the same value for both signals.
|
||||
*
|
||||
* If signal A has attribute X and signal B does not, then
|
||||
* signals can be folded if B can take the attribute.
|
||||
*
|
||||
* All the pins in a vector have identical attributes.
|
||||
*/
|
||||
|
||||
static unsigned depth(const string&sym)
|
||||
{
|
||||
unsigned cnt = 0;
|
||||
for (unsigned idx = 0 ; idx < sym.length() ; idx += 1)
|
||||
if (sym[idx] == '.')
|
||||
cnt += 1;
|
||||
|
||||
return cnt;
|
||||
}
|
||||
|
||||
static bool is_any_signal(const NetNet*)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
static void clear_extra_signals(NetNet*net, unsigned npin)
|
||||
{
|
||||
const unsigned mydepth = depth(net->name());
|
||||
NetObj*cur = net;
|
||||
unsigned pin = npin;
|
||||
for (net->pin(pin).next_link(cur, pin) ; cur != net ; ) {
|
||||
|
||||
// sig is the node I am going to try to subsume.
|
||||
NetNet*sig = dynamic_cast<NetNet*>(cur);
|
||||
|
||||
// Skip the node if it isn't even a signal.
|
||||
if (sig == 0) {
|
||||
cur->pin(pin).next_link(cur, pin);
|
||||
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)) {
|
||||
|
||||
// SPECIAL CASE!
|
||||
if (sig->has_compat_attributes(*net)) {
|
||||
net->pin(npin).unlink();
|
||||
return;
|
||||
}
|
||||
|
||||
cur->pin(pin).next_link(cur, pin);
|
||||
continue;
|
||||
}
|
||||
|
||||
// Skip the node if it is higher up.
|
||||
if (depth(sig->name()) < mydepth) {
|
||||
cur->pin(pin).next_link(cur, pin);
|
||||
continue;
|
||||
}
|
||||
|
||||
// Skip the node if it is a larger vector.
|
||||
if (sig->pin_count() > net->pin_count()) {
|
||||
cur->pin(pin).next_link(cur, pin);
|
||||
continue;
|
||||
}
|
||||
|
||||
// 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;
|
||||
}
|
||||
}
|
||||
|
||||
static void delete_if_unconnected(NetNet*net)
|
||||
{
|
||||
for (unsigned idx = 0 ; idx < net->pin_count() ; idx += 1)
|
||||
if (net->pin(idx).is_linked())
|
||||
return;
|
||||
|
||||
delete net;
|
||||
}
|
||||
|
||||
void sigfold(Design*des)
|
||||
{
|
||||
des->clear_signal_marks();
|
||||
while (NetNet*obj = des->find_signal(&is_any_signal)) {
|
||||
for (unsigned idx = 0 ; idx < obj->pin_count() ; idx += 1)
|
||||
clear_extra_signals(obj, idx);
|
||||
obj->set_mark();
|
||||
}
|
||||
|
||||
// After the disconnect step, I may have signals that are not
|
||||
// connected to anything. Delete those.
|
||||
|
||||
des->clear_signal_marks();
|
||||
while (NetNet*obj = des->find_signal(&is_any_signal)) {
|
||||
obj->set_mark();
|
||||
delete_if_unconnected(obj);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* $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 with wide links,
|
||||
* Signal folding is aware of attributes, and
|
||||
* the XNF target can dump UDP objects based on LCA
|
||||
* attributes.
|
||||
*
|
||||
* Revision 1.1 1998/11/16 05:03:53 steve
|
||||
* Add the sigfold function that unlinks excess
|
||||
* signal nodes, and add the XNF target.
|
||||
*
|
||||
*/
|
||||
|
||||
@@ -1,164 +0,0 @@
|
||||
#ifndef __sref_H
|
||||
#define __sref_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. 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
|
||||
*/
|
||||
#if !defined(WINNT)
|
||||
#ident "$Id: sref.h,v 1.4 1999/08/05 04:58:17 steve Exp $"
|
||||
#endif
|
||||
|
||||
# include <assert.h>
|
||||
# include "svector.h"
|
||||
|
||||
/*
|
||||
* The sref class is a reference with automatic reference counting. It
|
||||
* implementes a many-to-one linkage where T1 is the many type and T2
|
||||
* is the one type.
|
||||
*/
|
||||
|
||||
template <class T1, class T2> class sref;
|
||||
template <class T1, class T2> class sref_back;
|
||||
|
||||
template <class T1, class T2> class sref_back {
|
||||
|
||||
friend class sref<T1,T2>;
|
||||
|
||||
public:
|
||||
sref_back() : sback_(0) { }
|
||||
~sref_back() { assert(sback_ == 0); }
|
||||
|
||||
svector<const T2*>* back_list() const;
|
||||
svector<T2*>* back_list();
|
||||
|
||||
private:
|
||||
void desert_(sref<T1,T2>*);
|
||||
sref<T1,T2>*sback_;
|
||||
};
|
||||
|
||||
template <class T1, class T2> class sref {
|
||||
|
||||
friend class sref_back<T1,T2>;
|
||||
|
||||
public:
|
||||
sref(T1*d) : dest_(d) { insert_(); }
|
||||
virtual ~sref() { dest_->desert_(this); }
|
||||
|
||||
T1*fore_ptr() { return dest_; }
|
||||
const T1*fore_ptr() const { return dest_; }
|
||||
|
||||
private:
|
||||
T1*dest_;
|
||||
sref<T1,T2>*next_;
|
||||
|
||||
void insert_()
|
||||
{ if (dest_->sback_ == 0) {
|
||||
next_ = this;
|
||||
dest_->sback_ = this;
|
||||
} else {
|
||||
next_ = dest_->sback_->next_;
|
||||
dest_->sback_->next_ = this;
|
||||
}
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
template <class T1,class T2>
|
||||
svector<const T2*>* sref_back<T1,T2>::back_list() const
|
||||
{
|
||||
if (sback_ == 0) return 0;
|
||||
unsigned cnt = 1;
|
||||
sref<T1,T2>*cur = sback_->next_;
|
||||
while (cur != sback_) {
|
||||
cnt += 1;
|
||||
cur = cur->next_;
|
||||
}
|
||||
|
||||
svector<const T2*>* result = new svector<const T2*>(cnt);
|
||||
(*result)[0] = dynamic_cast<const T2*>(sback_);
|
||||
cur = sback_->next_;
|
||||
cnt = 1;
|
||||
while (cur != sback_) {
|
||||
(*result)[cnt] = dynamic_cast<const T2*>(cur);
|
||||
cnt += 1;
|
||||
cur = cur->next_;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
template <class T1,class T2>
|
||||
svector<T2*>* sref_back<T1,T2>::back_list()
|
||||
{
|
||||
if (sback_ == 0) return 0;
|
||||
unsigned cnt = 1;
|
||||
sref<T1,T2>*cur = sback_->next_;
|
||||
while (cur != sback_) {
|
||||
cnt += 1;
|
||||
cur = cur->next_;
|
||||
}
|
||||
|
||||
svector<T2*>* result = new svector<T2*>(cnt);
|
||||
(*result)[0] = dynamic_cast<T2*>(sback_);
|
||||
cur = sback_->next_;
|
||||
cnt = 1;
|
||||
while (cur != sback_) {
|
||||
(*result)[cnt] = dynamic_cast<T2*>(cur);
|
||||
cnt += 1;
|
||||
cur = cur->next_;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
template <class T1, class T2> void sref_back<T1,T2>::desert_(sref<T1,T2>*item)
|
||||
{
|
||||
if (item == sback_)
|
||||
sback_ = item->next_;
|
||||
|
||||
if (item == sback_) {
|
||||
sback_ = 0;
|
||||
|
||||
} else {
|
||||
sref<T1,T2>*cur = sback_;
|
||||
while (cur->next_ != item) {
|
||||
assert(cur->next_);
|
||||
cur = cur->next_;
|
||||
}
|
||||
|
||||
cur->next_ = item->next_;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* $Log: sref.h,v $
|
||||
* Revision 1.4 1999/08/05 04:58:17 steve
|
||||
* Fix compile error with gcc 2.95
|
||||
*
|
||||
* Revision 1.3 1999/07/18 21:17:51 steve
|
||||
* Add support for CE input to XNF DFF, and do
|
||||
* complete cleanup of replaced design nodes.
|
||||
*
|
||||
* Revision 1.2 1999/07/18 05:52:47 steve
|
||||
* xnfsyn generates DFF objects for XNF output, and
|
||||
* properly rewrites the Design netlist in the process.
|
||||
*
|
||||
* Revision 1.1 1999/05/01 02:57:53 steve
|
||||
* Handle much more complex event expressions.
|
||||
*
|
||||
*/
|
||||
#endif
|
||||
@@ -20,8 +20,8 @@
|
||||
* 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: svector.h,v 1.4 1999/06/15 03:44:53 steve Exp $"
|
||||
#if !defined(WINNT) && !defined(macintosh)
|
||||
#ident "$Id: svector.h,v 1.5 2000/02/23 02:56:55 steve Exp $"
|
||||
#endif
|
||||
|
||||
# include <assert.h>
|
||||
@@ -97,6 +97,9 @@ template <class TYPE> class svector {
|
||||
|
||||
/*
|
||||
* $Log: svector.h,v $
|
||||
* Revision 1.5 2000/02/23 02:56:55 steve
|
||||
* Macintosh compilers do not support ident.
|
||||
*
|
||||
* Revision 1.4 1999/06/15 03:44:53 steve
|
||||
* Get rid of the STL vector template.
|
||||
*
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 1999 Stephen Williams (steve@icarus.com)
|
||||
* Copyright (c) 1999-2000 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
|
||||
@@ -16,8 +16,8 @@
|
||||
* 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 $"
|
||||
#if !defined(WINNT) && !defined(macintosh)
|
||||
#ident "$Id: synth.cc,v 1.9 2000/04/16 22:57:34 steve Exp $"
|
||||
#endif
|
||||
|
||||
/*
|
||||
@@ -30,6 +30,78 @@
|
||||
# include "functor.h"
|
||||
# include "netlist.h"
|
||||
|
||||
/*
|
||||
* This functor scans the behavioral code, looking for expressions to
|
||||
* synthesize. Although it uses the proc_match_t class, it doesn't
|
||||
* actually match anything, but transforms expressions into structural
|
||||
* netlists. The product of this should be a process where all the
|
||||
* expressions have been reduced to a signal ident, which references
|
||||
* the NetNet of the now synthesized expression.
|
||||
*/
|
||||
class do_expr : public proc_match_t {
|
||||
|
||||
public:
|
||||
do_expr(Design*d)
|
||||
: des_(d) { }
|
||||
|
||||
private:
|
||||
|
||||
Design*des_;
|
||||
|
||||
virtual int assign(NetAssign*);
|
||||
virtual int event_wait(NetEvWait*);
|
||||
//virtual int assign_mem(NetAssignMem*);
|
||||
virtual int condit(NetCondit*);
|
||||
};
|
||||
|
||||
|
||||
int do_expr::assign(NetAssign*stmt)
|
||||
{
|
||||
if (dynamic_cast<NetESignal*>(stmt->rval()))
|
||||
return 0;
|
||||
|
||||
NetNet*tmp = stmt->rval()->synthesize(des_);
|
||||
if (tmp == 0)
|
||||
return 0;
|
||||
|
||||
NetESignal*tmpe = new NetESignal(tmp);
|
||||
stmt->set_rval(tmpe);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int do_expr::condit(NetCondit*stmt)
|
||||
{
|
||||
/* synthesize the condition expression, if necessary. */
|
||||
if (! dynamic_cast<NetESignal*>(stmt->expr())) {
|
||||
NetNet*tmp = stmt->expr()->synthesize(des_);
|
||||
|
||||
if (tmp) {
|
||||
NetESignal*tmpe = new NetESignal(tmp);
|
||||
stmt->set_expr(tmpe);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/* Now recurse through the if and else clauses. */
|
||||
if (NetProc*tmp = stmt->if_clause())
|
||||
tmp->match_proc(this);
|
||||
|
||||
if (NetProc*tmp = stmt->else_clause())
|
||||
tmp->match_proc(this);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int do_expr::event_wait(NetEvWait*stmt)
|
||||
{
|
||||
NetProc*tmp = stmt->statement();
|
||||
if (tmp)
|
||||
return tmp->match_proc(this);
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* This transform recognizes the following patterns:
|
||||
*
|
||||
@@ -39,6 +111,14 @@
|
||||
* always @(posedge CLK) if (CE) Q = D;
|
||||
* always @(negedge CLK) if (CE) Q = D;
|
||||
*
|
||||
* These are memory assignments:
|
||||
*
|
||||
* always @(posedge CLK) M[a] = D
|
||||
* always @(negedge CLK) M[a] = D
|
||||
*
|
||||
* always @(posedge CLK) if (CE) M[a] = D;
|
||||
* always @(negedge CLK) if (CE) M[a] = 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.
|
||||
@@ -47,8 +127,8 @@ 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)
|
||||
: des_(d), top_(t), wclk_(0), eclk_(0), pclk_(0), con_(0), ce_(0),
|
||||
asn_(0), asm_(0), d_(0)
|
||||
{ }
|
||||
|
||||
~match_dff() { }
|
||||
@@ -56,18 +136,26 @@ class match_dff : public proc_match_t {
|
||||
void make_it();
|
||||
|
||||
private:
|
||||
void make_dff_();
|
||||
void make_ram_();
|
||||
|
||||
virtual int assign(NetAssign*);
|
||||
virtual int assign_mem(NetAssignMem*);
|
||||
virtual int condit(NetCondit*);
|
||||
virtual int pevent(NetPEvent*);
|
||||
virtual int event_wait(NetEvWait*);
|
||||
|
||||
Design*des_;
|
||||
NetProcTop*top_;
|
||||
NetPEvent*pclk_;
|
||||
NetNEvent*nclk_;
|
||||
|
||||
NetEvWait*wclk_;
|
||||
NetEvent *eclk_;
|
||||
NetEvProbe*pclk_;
|
||||
|
||||
NetCondit *con_;
|
||||
NetNet*ce_;
|
||||
|
||||
NetAssign *asn_;
|
||||
NetAssignMem*asm_;
|
||||
|
||||
NetNet*d_;
|
||||
};
|
||||
@@ -76,7 +164,7 @@ int match_dff::assign(NetAssign*as)
|
||||
{
|
||||
if (!pclk_)
|
||||
return 0;
|
||||
if (asn_)
|
||||
if (asn_ || asm_)
|
||||
return 0;
|
||||
|
||||
asn_ = as;
|
||||
@@ -87,11 +175,26 @@ int match_dff::assign(NetAssign*as)
|
||||
return 1;
|
||||
}
|
||||
|
||||
int match_dff::assign_mem(NetAssignMem*as)
|
||||
{
|
||||
if (!pclk_)
|
||||
return 0;
|
||||
if (asn_ || asm_)
|
||||
return 0;
|
||||
|
||||
asm_ = as;
|
||||
d_ = asm_->rval()->synthesize(des_);
|
||||
if (d_ == 0)
|
||||
return 0;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int match_dff::condit(NetCondit*co)
|
||||
{
|
||||
if (!pclk_)
|
||||
return 0;
|
||||
if (con_ || asn_)
|
||||
if (con_ || asn_ || asm_)
|
||||
return 0;
|
||||
|
||||
con_ = co;
|
||||
@@ -104,27 +207,34 @@ int match_dff::condit(NetCondit*co)
|
||||
return con_->if_clause()->match_proc(this);
|
||||
}
|
||||
|
||||
int match_dff::pevent(NetPEvent*pe)
|
||||
int match_dff::event_wait(NetEvWait*evw)
|
||||
{
|
||||
if (pclk_ || con_ || asn_)
|
||||
if (evw->nevents() != 1)
|
||||
return 0;
|
||||
|
||||
pclk_ = pe;
|
||||
wclk_ = evw;
|
||||
eclk_ = evw->event(0);
|
||||
|
||||
// ... there must be a single event source, ...
|
||||
svector<class NetNEvent*>*neb = pclk_->back_list();
|
||||
if (neb == 0)
|
||||
if (eclk_->nprobe() != 1)
|
||||
return 0;
|
||||
if (neb->count() != 1) {
|
||||
delete neb;
|
||||
return 0;
|
||||
}
|
||||
nclk_ = (*neb)[0];
|
||||
delete neb;
|
||||
return pclk_->statement()->match_proc(this);
|
||||
|
||||
pclk_ = eclk_->probe(0);
|
||||
|
||||
return wclk_->statement()->match_proc(this);
|
||||
}
|
||||
|
||||
void match_dff::make_it()
|
||||
{
|
||||
if (asn_) {
|
||||
assert(asm_ == 0);
|
||||
make_dff_();
|
||||
} else {
|
||||
assert(asm_);
|
||||
make_ram_();
|
||||
}
|
||||
}
|
||||
|
||||
void match_dff::make_dff_()
|
||||
{
|
||||
NetFF*ff = new NetFF(asn_->name(), asn_->pin_count());
|
||||
|
||||
@@ -133,16 +243,53 @@ void match_dff::make_it()
|
||||
connect(ff->pin_Q(idx), asn_->pin(idx));
|
||||
}
|
||||
|
||||
connect(ff->pin_Clock(), nclk_->pin(0));
|
||||
connect(ff->pin_Clock(), pclk_->pin(0));
|
||||
if (ce_) connect(ff->pin_Enable(), ce_->pin(0));
|
||||
|
||||
ff->attribute("LPM_FFType", "DFF");
|
||||
if (nclk_->type() == NetNEvent::NEGEDGE)
|
||||
if (pclk_->edge() == NetEvProbe::NEGEDGE)
|
||||
ff->attribute("Clock:LPM_Polarity", "INVERT");
|
||||
|
||||
des_->add_node(ff);
|
||||
}
|
||||
|
||||
void match_dff::make_ram_()
|
||||
{
|
||||
NetMemory*mem = asm_->memory();
|
||||
NetNet*adr = asm_->index();
|
||||
NetRamDq*ram = new NetRamDq(des_->local_symbol(mem->name()), mem,
|
||||
adr->pin_count());
|
||||
for (unsigned idx = 0 ; idx < adr->pin_count() ; idx += 1)
|
||||
connect(adr->pin(idx), ram->pin_Address(idx));
|
||||
|
||||
for (unsigned idx = 0 ; idx < ram->width() ; idx += 1)
|
||||
connect(ram->pin_Data(idx), d_->pin(idx));
|
||||
|
||||
if (ce_)
|
||||
connect(ram->pin_WE(), ce_->pin(0));
|
||||
|
||||
assert(pclk_->edge() == NetEvProbe::POSEDGE);
|
||||
connect(ram->pin_InClock(), pclk_->pin(0));
|
||||
|
||||
ram->absorb_partners();
|
||||
des_->add_node(ram);
|
||||
}
|
||||
|
||||
class match_block : public proc_match_t {
|
||||
|
||||
public:
|
||||
match_block(Design*d, NetProcTop*t)
|
||||
: des_(d), top_(t)
|
||||
{ }
|
||||
|
||||
~match_block() { }
|
||||
|
||||
private:
|
||||
|
||||
Design*des_;
|
||||
NetProcTop*top_;
|
||||
};
|
||||
|
||||
class synth_f : public functor_t {
|
||||
|
||||
public:
|
||||
@@ -174,12 +321,20 @@ void synth_f::process(class Design*des, class NetProcTop*top)
|
||||
*/
|
||||
void synth_f::proc_always_(class Design*des)
|
||||
{
|
||||
do_expr expr_pat(des);
|
||||
top_->statement()->match_proc(&expr_pat);
|
||||
|
||||
match_dff dff_pat(des, top_);
|
||||
if (top_->statement()->match_proc(&dff_pat)) {
|
||||
dff_pat.make_it();
|
||||
des->delete_process(top_);
|
||||
return;
|
||||
}
|
||||
|
||||
match_block block_pat(des, top_);
|
||||
if (top_->statement()->match_proc(&block_pat)) {
|
||||
cerr << "XXXX: recurse and return here" << endl;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -191,6 +346,27 @@ void synth(Design*des)
|
||||
|
||||
/*
|
||||
* $Log: synth.cc,v $
|
||||
* Revision 1.9 2000/04/16 22:57:34 steve
|
||||
* Catch expressions that are part of conditionals.
|
||||
*
|
||||
* Revision 1.8 2000/04/12 20:02:53 steve
|
||||
* Finally remove the NetNEvent and NetPEvent classes,
|
||||
* Get synthesis working with the NetEvWait class,
|
||||
* and get started supporting multiple events in a
|
||||
* wait in vvm.
|
||||
*
|
||||
* Revision 1.7 2000/04/02 04:26:07 steve
|
||||
* Remove the useless sref template.
|
||||
*
|
||||
* Revision 1.6 2000/02/23 02:56:55 steve
|
||||
* Macintosh compilers do not support ident.
|
||||
*
|
||||
* Revision 1.5 2000/02/13 04:35:43 steve
|
||||
* Include some block matching from Larry.
|
||||
*
|
||||
* Revision 1.4 1999/12/05 02:24:09 steve
|
||||
* Synthesize LPM_RAM_DQ for writes into memories.
|
||||
*
|
||||
* Revision 1.3 1999/12/01 06:06:16 steve
|
||||
* Redo synth to use match_proc_t scanner.
|
||||
*
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 1999 Stephen Williams (steve@icarus.com)
|
||||
* Copyright (c) 1999-2000 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
|
||||
@@ -16,8 +16,8 @@
|
||||
* 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: t-null.cc,v 1.8 1999/10/05 03:26:37 steve Exp $"
|
||||
#if !defined(WINNT) && !defined(macintosh)
|
||||
#ident "$Id: t-null.cc,v 1.11 2000/04/12 04:23:58 steve Exp $"
|
||||
#endif
|
||||
|
||||
# include "netlist.h"
|
||||
@@ -35,12 +35,11 @@ static class target_null_t : public target_t {
|
||||
void task_def(ostream&, const NetTaskDef*) { }
|
||||
void net_assign(ostream&os, const NetAssign*) { }
|
||||
void net_assign_nb(ostream&os, const NetAssignNB*) { }
|
||||
void net_const(ostream&, const NetConst*) { }
|
||||
void net_esignal(ostream&, const NetESignal*) { }
|
||||
void net_event(ostream&, const NetNEvent*) { }
|
||||
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*) { }
|
||||
@@ -51,6 +50,25 @@ static class target_null_t : public target_t {
|
||||
extern const struct target tgt_null = { "null", &target_null_obj };
|
||||
/*
|
||||
* $Log: t-null.cc,v $
|
||||
* Revision 1.11 2000/04/12 04:23:58 steve
|
||||
* Named events really should be expressed with PEIdent
|
||||
* objects in the pform,
|
||||
*
|
||||
* Handle named events within the mix of net events
|
||||
* and edges. As a unified lot they get caught together.
|
||||
* wait statements are broken into more complex statements
|
||||
* that include a conditional.
|
||||
*
|
||||
* Do not generate NetPEvent or NetNEvent objects in
|
||||
* elaboration. NetEvent, NetEvWait and NetEvProbe
|
||||
* take over those functions in the netlist.
|
||||
*
|
||||
* Revision 1.10 2000/02/23 02:56:55 steve
|
||||
* Macintosh compilers do not support ident.
|
||||
*
|
||||
* Revision 1.9 2000/02/14 06:04:52 steve
|
||||
* Unary reduction operators do not set their operand width
|
||||
*
|
||||
* Revision 1.8 1999/10/05 03:26:37 steve
|
||||
* null target ignore assignment nodes.
|
||||
*
|
||||
|
||||
+19
-33
@@ -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
|
||||
@@ -16,8 +16,8 @@
|
||||
* 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: t-verilog.cc,v 1.8 1999/09/22 16:57:24 steve Exp $"
|
||||
#if !defined(WINNT) && !defined(macintosh)
|
||||
#ident "$Id: t-verilog.cc,v 1.10 2000/04/12 04:23:58 steve Exp $"
|
||||
#endif
|
||||
|
||||
/*
|
||||
@@ -45,7 +45,6 @@ class target_verilog : public target_t {
|
||||
virtual void start_process(ostream&os, const NetProcTop*);
|
||||
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*);
|
||||
virtual void end_design(ostream&os, const Design*);
|
||||
private:
|
||||
@@ -192,35 +191,6 @@ void target_verilog::proc_delay(ostream&os, const NetPDelay*net)
|
||||
indent_ -= 4;
|
||||
}
|
||||
|
||||
void target_verilog::proc_event(ostream&os, const NetPEvent*net)
|
||||
{
|
||||
os << setw(indent_) << "" << "@";
|
||||
|
||||
#if 0
|
||||
unsigned sidx;
|
||||
const NetNet*sig = find_link_signal(net, 0, sidx);
|
||||
|
||||
switch (net->edge()) {
|
||||
case NetNEvent::ANYEDGE:
|
||||
os << mangle(sig->name()) << "[" << sidx << "]";
|
||||
break;
|
||||
case NetNEvent::POSEDGE:
|
||||
os << "(posedge " << mangle(sig->name()) << "[" << sidx << "])";
|
||||
break;
|
||||
case NetNEvent::NEGEDGE:
|
||||
os << "(negedge " << mangle(sig->name()) << "[" << sidx << "])";
|
||||
break;
|
||||
}
|
||||
#else
|
||||
os << endl;
|
||||
os << "#error \"proc_event temporarily out of order\"";
|
||||
#endif
|
||||
os << endl;
|
||||
|
||||
indent_ += 4;
|
||||
net->emit_proc_recurse(os, this);
|
||||
indent_ -= 4;
|
||||
}
|
||||
|
||||
static void vtask_parm(ostream&os, const NetExpr*ex)
|
||||
{
|
||||
@@ -272,6 +242,22 @@ const struct target tgt_verilog = {
|
||||
|
||||
/*
|
||||
* $Log: t-verilog.cc,v $
|
||||
* Revision 1.10 2000/04/12 04:23:58 steve
|
||||
* Named events really should be expressed with PEIdent
|
||||
* objects in the pform,
|
||||
*
|
||||
* Handle named events within the mix of net events
|
||||
* and edges. As a unified lot they get caught together.
|
||||
* wait statements are broken into more complex statements
|
||||
* that include a conditional.
|
||||
*
|
||||
* Do not generate NetPEvent or NetNEvent objects in
|
||||
* elaboration. NetEvent, NetEvWait and NetEvProbe
|
||||
* take over those functions in the netlist.
|
||||
*
|
||||
* Revision 1.9 2000/02/23 02:56:55 steve
|
||||
* Macintosh compilers do not support ident.
|
||||
*
|
||||
* Revision 1.8 1999/09/22 16:57:24 steve
|
||||
* Catch parallel blocks in vvm emit.
|
||||
*
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 1998 Stephen Williams (steve@icarus.com)
|
||||
* Copyright (c) 1998-2000 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
|
||||
@@ -16,14 +16,17 @@
|
||||
* 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: t-xnf.cc,v 1.18 1999/11/19 03:02:25 steve Exp $"
|
||||
#if !defined(WINNT) && !defined(macintosh)
|
||||
#ident "$Id: t-xnf.cc,v 1.28 2000/05/08 05:29:43 steve Exp $"
|
||||
#endif
|
||||
|
||||
/* XNF BACKEND
|
||||
* This target supports generating Xilinx Netlist Format netlists for
|
||||
* use by Xilinx tools, and other tools that accepts Xilinx designs.
|
||||
*
|
||||
* The code generator automatically detects ports to top level modules
|
||||
* and generates SIG records that make the XNF useable as a schematic.
|
||||
*
|
||||
* FLAGS
|
||||
* The XNF backend uses the following flags from the command line to
|
||||
* affect the generated file:
|
||||
@@ -77,11 +80,17 @@ class target_xnf : public target_t {
|
||||
public:
|
||||
void start_design(ostream&os, const Design*);
|
||||
void end_design(ostream&os, const Design*);
|
||||
void memory(ostream&os, const NetMemory*);
|
||||
void signal(ostream&os, const NetNet*);
|
||||
|
||||
void lpm_add_sub(ostream&os, const NetAddSub*);
|
||||
void lpm_compare(ostream&os, const NetCompare*);
|
||||
void lpm_compare_eq_(ostream&os, const NetCompare*);
|
||||
void lpm_compare_ge_(ostream&os, const NetCompare*);
|
||||
void lpm_compare_le_(ostream&os, const NetCompare*);
|
||||
void lpm_ff(ostream&os, const NetFF*);
|
||||
void lpm_mux(ostream&os, const NetMux*);
|
||||
void lpm_ram_dq(ostream&os, const NetRamDq*);
|
||||
|
||||
void net_const(ostream&os, const NetConst*);
|
||||
void logic(ostream&os, const NetLogic*);
|
||||
@@ -90,13 +99,13 @@ class target_xnf : public target_t {
|
||||
|
||||
private:
|
||||
static string mangle(const string&);
|
||||
static string choose_sig_name(const NetObj::Link*lnk);
|
||||
static string choose_sig_name(const Link*lnk);
|
||||
static void draw_pin(ostream&os, const string&name,
|
||||
const NetObj::Link&lnk);
|
||||
const 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 };
|
||||
enum adder_type {FORCE0, LOWER, DOUBLE, LOWER_W_CO, EXAMINE_CI };
|
||||
static void draw_carry(ostream&os, const NetAddSub*, unsigned idx,
|
||||
enum adder_type);
|
||||
|
||||
@@ -128,12 +137,13 @@ string target_xnf::mangle(const string&name)
|
||||
* nexus to decide which name to use if there are lots of attached
|
||||
* signals.
|
||||
*/
|
||||
string target_xnf::choose_sig_name(const NetObj::Link*lnk)
|
||||
string target_xnf::choose_sig_name(const Link*lnk)
|
||||
{
|
||||
assert(lnk->is_linked());
|
||||
const NetNet*sig = dynamic_cast<const NetNet*>(lnk->get_obj());
|
||||
unsigned pin = lnk->get_pin();
|
||||
|
||||
for (const NetObj::Link*cur = lnk->next_link()
|
||||
for (const Link*cur = lnk->next_link()
|
||||
; cur != lnk ; cur = cur->next_link()) {
|
||||
|
||||
const NetNet*cursig = dynamic_cast<const NetNet*>(cur->get_obj());
|
||||
@@ -176,7 +186,7 @@ string target_xnf::choose_sig_name(const NetObj::Link*lnk)
|
||||
}
|
||||
|
||||
void target_xnf::draw_pin(ostream&os, const string&name,
|
||||
const NetObj::Link&lnk)
|
||||
const Link&lnk)
|
||||
{
|
||||
bool inv = false;
|
||||
string use_name = name;
|
||||
@@ -187,11 +197,11 @@ void target_xnf::draw_pin(ostream&os, const string&name,
|
||||
|
||||
char type;
|
||||
switch (lnk.get_dir()) {
|
||||
case NetObj::Link::INPUT:
|
||||
case NetObj::Link::PASSIVE:
|
||||
case Link::INPUT:
|
||||
case Link::PASSIVE:
|
||||
type = 'I';
|
||||
break;
|
||||
case NetObj::Link::OUTPUT:
|
||||
case Link::OUTPUT:
|
||||
type = 'O';
|
||||
break;
|
||||
}
|
||||
@@ -295,6 +305,14 @@ void scrape_pad_info(string str, char&dir, unsigned&num)
|
||||
num = val;
|
||||
}
|
||||
|
||||
/*
|
||||
* Memories are handled by the lpm_ram_dq method, so there is nothing
|
||||
* to do here.
|
||||
*/
|
||||
void target_xnf::memory(ostream&, const NetMemory*)
|
||||
{
|
||||
}
|
||||
|
||||
/*
|
||||
* Look for signals that have attributes that are pertinent to XNF
|
||||
* files. The most obvious are those that have the PAD attribute.
|
||||
@@ -308,6 +326,37 @@ void scrape_pad_info(string str, char&dir, unsigned&num)
|
||||
*/
|
||||
void target_xnf::signal(ostream&os, const NetNet*net)
|
||||
{
|
||||
|
||||
/* Look for signals that are ports to the root module. If they
|
||||
are, the write a SIG record and generate a pin name so that
|
||||
this module can be used as a macro. */
|
||||
|
||||
if (const NetScope*scope = net->scope()) do {
|
||||
|
||||
if (scope->parent())
|
||||
break;
|
||||
|
||||
if (net->port_type() == NetNet::NOT_A_PORT)
|
||||
break;
|
||||
|
||||
string mname = mangle(net->name());
|
||||
string pname = mname.substr(mname.find('/')+1, mname.length());
|
||||
|
||||
if (net->pin_count() == 1) {
|
||||
os << "SIG, " << mangle(net->name()) << ", PIN="
|
||||
<< pname << endl;
|
||||
|
||||
} else for (unsigned idx = 0; idx < net->pin_count(); idx += 1) {
|
||||
os << "SIG, " << mangle(net->name()) << "<" << idx
|
||||
<< ">, PIN=" << pname << idx << endl;
|
||||
}
|
||||
|
||||
} while (0);
|
||||
|
||||
|
||||
/* Now look to see if a PAD attribute is attached, and if so
|
||||
write out PAD information to the XNF and the ncf files. */
|
||||
|
||||
string pad = net->attribute("PAD");
|
||||
if (pad == "")
|
||||
return;
|
||||
@@ -364,44 +413,43 @@ void target_xnf::draw_carry(ostream &os, const NetAddSub*gate, unsigned idx,
|
||||
"LIBVER=2.0.0" << endl;
|
||||
|
||||
// Less significant bit addends, if any
|
||||
if ( type == LOWER || type == DOUBLE ) {
|
||||
if ( type == LOWER || type == DOUBLE || type == LOWER_W_CO ) {
|
||||
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));
|
||||
if ( type == DOUBLE ) {
|
||||
draw_pin(os, "A1", gate->pin_DataA(idx+1));
|
||||
draw_pin(os, "B1", gate->pin_DataB(idx+1));
|
||||
}
|
||||
|
||||
// Carry input
|
||||
if ( type != FORCE0 && type != UPPER ) {
|
||||
os << " PIN, CIN, I, " << name_cout << "<" <<
|
||||
idx << ">" << endl;
|
||||
// All but FORCE0 cells have carry input
|
||||
if ( type != FORCE0 ) {
|
||||
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 ) {
|
||||
switch (type) {
|
||||
case LOWER:
|
||||
case DOUBLE:
|
||||
os << " PIN, COUT0, O, " << name_cout << "<" << (idx+1) <<
|
||||
">" << endl;
|
||||
break;
|
||||
case EXAMINE_CI:
|
||||
case LOWER_W_CO:
|
||||
draw_pin(os, "COUT0", gate->pin_Cout());
|
||||
break;
|
||||
}
|
||||
|
||||
// Connect the Cout, this will connect to the next Cin
|
||||
if ( type == FORCE0 || type == UPPER || type == DOUBLE ) {
|
||||
if ( type == FORCE0 || 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"
|
||||
@@ -409,26 +457,24 @@ void target_xnf::draw_carry(ostream &os, const NetAddSub*gate, unsigned idx,
|
||||
}
|
||||
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:
|
||||
case FORCE0:
|
||||
os << "CY4_37, CYMODE=FORCE-0" << endl;
|
||||
break;
|
||||
case LOWER:
|
||||
case LOWER:
|
||||
os << "CY4_01, CYMODE=ADD-F-CI" << endl;
|
||||
break;
|
||||
case UPPER:
|
||||
os << "CY4_03, CYMODE=ADD-G-F1" << endl;
|
||||
case LOWER_W_CO:
|
||||
os << "CY4_01, CYMODE=ADD-F-CI" << endl;
|
||||
break;
|
||||
case DOUBLE:
|
||||
case DOUBLE:
|
||||
os << "CY4_02, CYMODE=ADD-FG-CI" << endl;
|
||||
break;
|
||||
case EXAMINE_CI:
|
||||
os << "CY4_42, CYMODE-EXAMINE-CI" << endl;
|
||||
break;
|
||||
}
|
||||
for (unsigned cn = 0 ; cn < 8 ; cn += 1) {
|
||||
os << " PIN, C" << cn << ", O, " << name << "/C"
|
||||
@@ -454,33 +500,170 @@ 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
|
||||
/* Make the force-0 carry 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);
|
||||
}
|
||||
|
||||
draw_carry(os, gate, width+1, FORCE0);
|
||||
|
||||
|
||||
/* 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) {
|
||||
initializer and up. Save the tail bits for later. */
|
||||
for (unsigned idx = 0 ; idx < width-2 ; idx += 2)
|
||||
draw_carry(os, gate, idx, DOUBLE);
|
||||
|
||||
/* Always have one or two tail bits. The situation gets a
|
||||
little tricky if we want the carry output, so handle that
|
||||
here.
|
||||
|
||||
If the carry-out is connected, and there are an even number
|
||||
of data bits, we need to see the cout from the CLB. This is
|
||||
done by configuring the top CLB CY device as ADD-FG-CI (to
|
||||
activate cout) and create an extra CLB CY device on top of
|
||||
the carry chain configured EXAMINE-CI to put the carry into
|
||||
the G function block.
|
||||
|
||||
IF the carry-out is connected and there are an odd number
|
||||
of data bits, then the top CLB can be configured to carry
|
||||
the top bit in the F unit and deliver the carry out through
|
||||
the G unit.
|
||||
|
||||
If the carry-out is not connected, then configure this top
|
||||
CLB as ADD-F-CI. The draw_xor for the top bit will include
|
||||
the F carry if needed. */
|
||||
|
||||
if (gate->pin_Cout().is_linked()) {
|
||||
if (width%2 == 0) {
|
||||
draw_carry(os, gate, width-2, DOUBLE);
|
||||
draw_carry(os, gate, width, EXAMINE_CI);
|
||||
} else {
|
||||
draw_carry(os, gate, width-1, LOWER_W_CO);
|
||||
}
|
||||
|
||||
} else {
|
||||
if (width%2 == 0)
|
||||
draw_carry(os, gate, width-2, LOWER);
|
||||
else
|
||||
draw_carry(os, gate, width-1, LOWER);
|
||||
}
|
||||
|
||||
/* Always have a tail bit */
|
||||
draw_carry(os, gate, carry_width-1, LOWER);
|
||||
|
||||
for (unsigned idx = 0 ; idx < width ; ++idx) {
|
||||
/* Now draw all the single bit (plus carry in) adders from XOR
|
||||
gates. This puts the F and G units to use. */
|
||||
for (unsigned idx = 0 ; idx < width ; idx += 1)
|
||||
draw_xor(os, gate, idx);
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
* In XNF, comparators are done differently depending on the type of
|
||||
* comparator being implemented. So, here we dispatch to the correct
|
||||
* code generator.
|
||||
*/
|
||||
void target_xnf::lpm_compare(ostream&os, const NetCompare*dev)
|
||||
{
|
||||
if (dev->pin_AEB().is_linked()) {
|
||||
lpm_compare_eq_(os, dev);
|
||||
return;
|
||||
}
|
||||
|
||||
if (dev->pin_AGEB().is_linked()) {
|
||||
lpm_compare_ge_(os, dev);
|
||||
return;
|
||||
}
|
||||
|
||||
if (dev->pin_ALEB().is_linked()) {
|
||||
lpm_compare_le_(os, dev);
|
||||
return;
|
||||
}
|
||||
|
||||
assert(0);
|
||||
}
|
||||
|
||||
/*
|
||||
* To compare that vectors are equal (identity comparator) generate
|
||||
* XNOR gates to compare each pair of bits, then generate an AND gate
|
||||
* to combine the bitwise results. This is pretty much the best way to
|
||||
* do an identity compare in Xilinx CLBs.
|
||||
*/
|
||||
void target_xnf::lpm_compare_eq_(ostream&os, const NetCompare*dev)
|
||||
{
|
||||
string mname = mangle(dev->name());
|
||||
|
||||
/* Draw XNOR gates for each bit pair. These gates to the
|
||||
bitwise comparison. */
|
||||
for (unsigned idx = 0 ; idx < dev->width() ; idx += 1) {
|
||||
os << "SYM, " << mname << "/cmp<" << idx << ">, "
|
||||
<< "XNOR, LIBVER=2.0.0" << endl;
|
||||
os << " PIN, O, O, " << mname << "/bit<" << idx << ">"
|
||||
<< endl;
|
||||
draw_pin(os, "I0", dev->pin_DataA(idx));
|
||||
draw_pin(os, "I1", dev->pin_DataB(idx));
|
||||
os << "END" << endl;
|
||||
}
|
||||
|
||||
/* Now draw an AND gate to combine all the bitwise
|
||||
comparisons. If there are more the 5 bits of data, then we
|
||||
are going to have generate a nested AND to combine the
|
||||
results. */
|
||||
|
||||
if (dev->width() > 5) {
|
||||
for (unsigned idx = 0 ; idx < dev->width() ; idx += 5) {
|
||||
|
||||
if ((idx+1) >= dev->width()) break;
|
||||
os << "SYM, " << mname << "/nest<" << idx
|
||||
<< ">, AND, LIBVER=2.0.0" << endl;
|
||||
|
||||
os << " PIN, O, O, " << mname << "/nbit<" << idx
|
||||
<< ">" << endl;
|
||||
|
||||
os << " PIN, I0, I, " << mname << "/bit<" << idx+0
|
||||
<< ">" << endl;
|
||||
os << " PIN, I1, I, " << mname << "/bit<" << idx+1
|
||||
<< ">" << endl;
|
||||
if ((idx+2) >= dev->width()) goto gate_out;
|
||||
os << " PIN, I2, I, " << mname << "/bit<" << idx+2
|
||||
<< ">" << endl;
|
||||
if ((idx+3) >= dev->width()) goto gate_out;
|
||||
os << " PIN, I3, I, " << mname << "/bit<" << idx+3
|
||||
<< ">" << endl;
|
||||
if ((idx+4) >= dev->width()) goto gate_out;
|
||||
os << " PIN, I4, I, " << mname << "/bit<" << idx+4
|
||||
<< ">" << endl;
|
||||
gate_out:
|
||||
os << "END" << endl;
|
||||
}
|
||||
|
||||
os << "SYM, " << mname << ", AND, LIBVER=2.0.0" << endl;
|
||||
draw_pin(os, "O", dev->pin_AEB());
|
||||
for (unsigned idx = 0 ; idx < dev->width() ; idx += 5) {
|
||||
if ((idx+1) == dev->width())
|
||||
os << " PIN, I" << idx/5 << ", I " << mname
|
||||
<< "/bit<" << idx << ">" << endl;
|
||||
else
|
||||
os << " PIN, I" << idx/5 << ", I " << mname
|
||||
<< "/nbit<" << idx << ">" << endl;
|
||||
}
|
||||
os << "END" << endl;
|
||||
|
||||
} else {
|
||||
os << "SYM, " << mname << ", AND, LIBVER=2.0.0" << endl;
|
||||
draw_pin(os, "O", dev->pin_AEB());
|
||||
for (unsigned idx = 0 ; idx < dev->width() ; idx += 1) {
|
||||
os << " PIN, I" << idx << ", I, " << mname << "/bit<"
|
||||
<< idx << ">" << endl;
|
||||
}
|
||||
os << "END" << endl;
|
||||
}
|
||||
}
|
||||
|
||||
void target_xnf::lpm_compare_ge_(ostream&os, const NetCompare*dev)
|
||||
{
|
||||
cerr << "XXXX GE not supported yet" << endl;
|
||||
}
|
||||
|
||||
void target_xnf::lpm_compare_le_(ostream&os, const NetCompare*dev)
|
||||
{
|
||||
cerr << "XXXX LE not supported yet" << endl;
|
||||
}
|
||||
|
||||
void target_xnf::lpm_ff(ostream&os, const NetFF*net)
|
||||
@@ -545,17 +728,43 @@ void target_xnf::lpm_mux(ostream&os, const NetMux*net)
|
||||
|
||||
}
|
||||
|
||||
void target_xnf::lpm_ram_dq(ostream&os, const NetRamDq*ram)
|
||||
{
|
||||
assert(ram->count_partners() == 1);
|
||||
|
||||
const NetMemory*mem = ram->mem();
|
||||
|
||||
for (unsigned idx = 0 ; idx < ram->width() ; idx += 1) {
|
||||
os << "SYM, " << mangle(ram->name())
|
||||
<< "<" << idx << ">, RAMS" << endl;
|
||||
|
||||
draw_pin(os, "O", ram->pin_Q(idx));
|
||||
draw_pin(os, "D", ram->pin_Data(idx));
|
||||
draw_pin(os, "WE", ram->pin_WE());
|
||||
draw_pin(os, "WCLK", ram->pin_InClock());
|
||||
for (unsigned adr = 0 ; adr < ram->awidth() ; adr += 1) {
|
||||
strstream tmp;
|
||||
tmp << "A" << adr << ends;
|
||||
draw_pin(os, tmp.str(), ram->pin_Address(adr));
|
||||
}
|
||||
|
||||
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;
|
||||
for (unsigned idx = 0 ; idx < c->pin_count() ; idx += 1) {
|
||||
verinum::V v=c->value(idx);
|
||||
assert(v==verinum::V0 || v==verinum::V1);
|
||||
const Link& lnk = c->pin(idx);
|
||||
// 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;
|
||||
os << " PWR, " << v << ", " << choose_sig_name(&lnk) << endl;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -598,21 +807,46 @@ void target_xnf::logic(ostream&os, const NetLogic*net)
|
||||
case NetLogic::XOR:
|
||||
os << "XOR";
|
||||
break;
|
||||
case NetLogic::BUFIF0:
|
||||
case NetLogic::BUFIF1:
|
||||
os << "TBUF";
|
||||
break;
|
||||
default:
|
||||
cerr << "XNF: Unhandled logic type." << endl;
|
||||
cerr << "internal error: XNF: Unhandled logic type." << endl;
|
||||
break;
|
||||
}
|
||||
os << ", LIBVER=2.0.0" << endl;
|
||||
|
||||
/* All of these kinds of devices have an output on pin 0. */
|
||||
draw_pin(os, "O", net->pin(0));
|
||||
|
||||
if (net->pin_count() == 2) {
|
||||
/* Most devices have inputs called I<N> for all the remaining
|
||||
pins. The TBUF devices are slightly different, but
|
||||
essentially the same structure. */
|
||||
switch (net->type()) {
|
||||
|
||||
case NetLogic::BUFIF0:
|
||||
assert(net->pin_count() == 3);
|
||||
draw_pin(os, "I", net->pin(1));
|
||||
draw_pin(os, "~T", net->pin(2));
|
||||
break;
|
||||
|
||||
case NetLogic::BUFIF1:
|
||||
assert(net->pin_count() == 3);
|
||||
draw_pin(os, "I", net->pin(1));
|
||||
} else for (unsigned idx = 1 ; idx < net->pin_count() ; idx += 1) {
|
||||
string name = "I";
|
||||
assert(net->pin_count() <= 11);
|
||||
name += (char)('0'+idx-1);
|
||||
draw_pin(os, name, net->pin(idx));
|
||||
draw_pin(os, "T", net->pin(2));
|
||||
break;
|
||||
|
||||
default:
|
||||
if (net->pin_count() == 2) {
|
||||
draw_pin(os, "I", net->pin(1));
|
||||
} else for (unsigned idx = 1; idx < net->pin_count(); idx += 1) {
|
||||
string name = "I";
|
||||
assert(net->pin_count() <= 11);
|
||||
name += (char)('0'+idx-1);
|
||||
draw_pin(os, name, net->pin(idx));
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
os << "END" << endl;
|
||||
@@ -623,7 +857,7 @@ 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;
|
||||
<< endl;
|
||||
warned_once=1;
|
||||
}
|
||||
os << "SYM, " << mangle(net->name()) << ", BUF, LIBVER=2.0.0" << endl;
|
||||
@@ -653,6 +887,41 @@ extern const struct target tgt_xnf = { "xnf", &target_xnf_obj };
|
||||
|
||||
/*
|
||||
* $Log: t-xnf.cc,v $
|
||||
* Revision 1.28 2000/05/08 05:29:43 steve
|
||||
* no need for nobufz functor.
|
||||
*
|
||||
* Revision 1.27 2000/05/07 04:37:56 steve
|
||||
* Carry strength values from Verilog source to the
|
||||
* pform and netlist for gates.
|
||||
*
|
||||
* Change vvm constants to use the driver_t to drive
|
||||
* a constant value. This works better if there are
|
||||
* multiple drivers on a signal.
|
||||
*
|
||||
* Revision 1.26 2000/04/23 23:03:13 steve
|
||||
* automatically generate macro interface code.
|
||||
*
|
||||
* Revision 1.25 2000/04/23 21:15:07 steve
|
||||
* Emit code for the bufif devices.
|
||||
*
|
||||
* Revision 1.24 2000/04/20 02:34:47 steve
|
||||
* Generate code for identity compare. Use gates.
|
||||
*
|
||||
* Revision 1.23 2000/02/23 02:56:55 steve
|
||||
* Macintosh compilers do not support ident.
|
||||
*
|
||||
* Revision 1.22 1999/12/17 03:38:46 steve
|
||||
* NetConst can now hold wide constants.
|
||||
*
|
||||
* Revision 1.21 1999/12/16 18:54:32 steve
|
||||
* Capture the carry out of carry-chain addition.
|
||||
*
|
||||
* Revision 1.20 1999/12/16 02:42:15 steve
|
||||
* Simulate carry output on adders.
|
||||
*
|
||||
* Revision 1.19 1999/12/05 19:30:43 steve
|
||||
* Generate XNF RAMS from synthesized memories.
|
||||
*
|
||||
* 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
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 1998 Stephen Williams <steve@icarus.com>
|
||||
* Copyright (c) 1998-2000 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
|
||||
@@ -16,8 +16,8 @@
|
||||
* 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: target.cc,v 1.28 1999/11/28 23:42:03 steve Exp $"
|
||||
#if !defined(WINNT) && !defined(macintosh)
|
||||
#ident "$Id: target.cc,v 1.39 2000/05/11 23:37:27 steve Exp $"
|
||||
#endif
|
||||
|
||||
# include "target.h"
|
||||
@@ -35,6 +35,12 @@ void target_t::scope(ostream&, const NetScope*)
|
||||
{
|
||||
}
|
||||
|
||||
void target_t::event(ostream&, const NetEvent*ev)
|
||||
{
|
||||
cerr << ev->get_line() << ": error: target (" << typeid(*this).name()
|
||||
<< "): Unhandled event <" << ev->full_name() << ">." << endl;
|
||||
}
|
||||
|
||||
void target_t::signal(ostream&os, const NetNet*)
|
||||
{
|
||||
}
|
||||
@@ -73,6 +79,12 @@ void target_t::udp(ostream&os, const NetUDP*)
|
||||
"Unhandled UDP." << endl;
|
||||
}
|
||||
|
||||
void target_t::udp_comb(ostream&os, const NetUDP_COMB*)
|
||||
{
|
||||
cerr << "target (" << typeid(*this).name() << "): "
|
||||
"Unhandled combinational primitive." << endl;
|
||||
}
|
||||
|
||||
void target_t::lpm_add_sub(ostream&, const NetAddSub*)
|
||||
{
|
||||
cerr << "target (" << typeid(*this).name() << "): "
|
||||
@@ -91,12 +103,24 @@ void target_t::lpm_compare(ostream&, const NetCompare*)
|
||||
"Unhandled NetCompare." << endl;
|
||||
}
|
||||
|
||||
void target_t::lpm_divide(ostream&, const NetDivide*)
|
||||
{
|
||||
cerr << "target (" << typeid(*this).name() << "): "
|
||||
"Unhandled NetDivide." << endl;
|
||||
}
|
||||
|
||||
void target_t::lpm_ff(ostream&, const NetFF*)
|
||||
{
|
||||
cerr << "target (" << typeid(*this).name() << "): "
|
||||
"Unhandled NetFF." << endl;
|
||||
}
|
||||
|
||||
void target_t::lpm_mult(ostream&, const NetMult*)
|
||||
{
|
||||
cerr << "target (" << typeid(*this).name() << "): "
|
||||
"Unhandled NetMult." << endl;
|
||||
}
|
||||
|
||||
void target_t::lpm_mux(ostream&, const NetMux*)
|
||||
{
|
||||
cerr << "target (" << typeid(*this).name() << "): "
|
||||
@@ -125,16 +149,30 @@ void target_t::net_case_cmp(ostream&os, const NetCaseCmp*)
|
||||
"Unhandled case compare node." << endl;
|
||||
}
|
||||
|
||||
bool target_t::net_cassign(ostream&os, const NetCAssign*dev)
|
||||
{
|
||||
cerr << "target (" << typeid(*this).name() << "): "
|
||||
"Unhandled NetCAssign node." << endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
void target_t::net_const(ostream&os, const NetConst*)
|
||||
{
|
||||
cerr << "target (" << typeid(*this).name() << "): "
|
||||
"Unhandled CONSTANT node." << endl;
|
||||
}
|
||||
|
||||
void target_t::net_event(ostream&os, const NetNEvent*net)
|
||||
bool target_t::net_force(ostream&os, const NetForce*dev)
|
||||
{
|
||||
cerr << "target (" << typeid(*this).name() << "): "
|
||||
"Unhandled EVENT net node." << endl;
|
||||
"Unhandled NetForce node." << endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
void target_t::net_probe(ostream&os, const NetEvProbe*net)
|
||||
{
|
||||
cerr << "target (" << typeid(*this).name() << "): "
|
||||
"Unhandled probe trigger node" << endl;
|
||||
net->dump_node(cerr, 4);
|
||||
}
|
||||
|
||||
@@ -181,6 +219,13 @@ void target_t::proc_case(ostream&os, const NetCase*cur)
|
||||
cur->dump(cerr, 6);
|
||||
}
|
||||
|
||||
bool target_t::proc_cassign(ostream&os, const NetCAssign*dev)
|
||||
{
|
||||
cerr << "target (" << typeid(*this).name() << "): "
|
||||
"Unhandled proc_cassign." << endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
void target_t::proc_condit(ostream&os, const NetCondit*condit)
|
||||
{
|
||||
cerr << "target (" << typeid(*this).name() << "): "
|
||||
@@ -188,17 +233,25 @@ void target_t::proc_condit(ostream&os, const NetCondit*condit)
|
||||
condit->dump(cerr, 6);
|
||||
}
|
||||
|
||||
bool target_t::proc_deassign(ostream&os, const NetDeassign*dev)
|
||||
{
|
||||
cerr << dev->get_line() << ": internal error: "
|
||||
<< "target (" << typeid(*this).name() << "): "
|
||||
<< "Unhandled proc_deassign." << endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
void target_t::proc_delay(ostream&os, const NetPDelay*)
|
||||
{
|
||||
cerr << "target (" << typeid(*this).name() << "): "
|
||||
"Unhandled proc_delay." << endl;
|
||||
}
|
||||
|
||||
void target_t::proc_event(ostream&os, const NetPEvent*net)
|
||||
bool target_t::proc_force(ostream&os, const NetForce*dev)
|
||||
{
|
||||
cerr << "target (" << typeid(*this).name() << "): "
|
||||
"Unhandled proc_event." << endl;
|
||||
net->dump(cerr, 4);
|
||||
"Unhandled proc_force." << endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
void target_t::proc_forever(ostream&os, const NetForever*)
|
||||
@@ -207,12 +260,27 @@ void target_t::proc_forever(ostream&os, const NetForever*)
|
||||
"Unhandled proc_forever." << endl;
|
||||
}
|
||||
|
||||
bool target_t::proc_release(ostream&os, const NetRelease*dev)
|
||||
{
|
||||
cerr << dev->get_line() << ": internal error: "
|
||||
<< "target (" << typeid(*this).name() << "): "
|
||||
<< "Unhandled proc_release." << endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
void target_t::proc_repeat(ostream&os, const NetRepeat*)
|
||||
{
|
||||
cerr << "target (" << typeid(*this).name() << "): "
|
||||
"Unhandled proc_repeat." << endl;
|
||||
}
|
||||
|
||||
bool target_t::proc_trigger(ostream&os, const NetEvTrig*tr)
|
||||
{
|
||||
cerr << tr->get_line() << ": error: target (" << typeid(*this).name()
|
||||
<< "): Unhandled event trigger." << endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
void target_t::proc_stask(ostream&os, const NetSTask*)
|
||||
{
|
||||
cerr << "target (" << typeid(*this).name() << "): "
|
||||
@@ -225,6 +293,13 @@ void target_t::proc_utask(ostream&os, const NetUTask*)
|
||||
"Unhandled proc_utask." << endl;
|
||||
}
|
||||
|
||||
bool target_t::proc_wait(ostream&os, const NetEvWait*tr)
|
||||
{
|
||||
cerr << tr->get_line() << ": error: target (" << typeid(*this).name()
|
||||
<< "): Unhandled event wait." << endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
void target_t::proc_while(ostream&os, const NetWhile*net)
|
||||
{
|
||||
cerr << "target (" << typeid(*this).name() << "): "
|
||||
@@ -270,6 +345,12 @@ void expr_scan_t::expr_scope(const NetEScope*)
|
||||
"unhandled expr_scope." << endl;
|
||||
}
|
||||
|
||||
void expr_scan_t::expr_sfunc(const NetESFunc*)
|
||||
{
|
||||
cerr << "expr_scan_t (" << typeid(*this).name() << "): "
|
||||
"unhandled expr_sfunc." << endl;
|
||||
}
|
||||
|
||||
void expr_scan_t::expr_signal(const NetESignal*)
|
||||
{
|
||||
cerr << "expr_scan_t (" << typeid(*this).name() << "): "
|
||||
@@ -308,6 +389,50 @@ void expr_scan_t::expr_binary(const NetEBinary*ex)
|
||||
|
||||
/*
|
||||
* $Log: target.cc,v $
|
||||
* Revision 1.39 2000/05/11 23:37:27 steve
|
||||
* Add support for procedural continuous assignment.
|
||||
*
|
||||
* Revision 1.38 2000/05/04 03:37:59 steve
|
||||
* Add infrastructure for system functions, move
|
||||
* $time to that structure and add $random.
|
||||
*
|
||||
* Revision 1.37 2000/04/23 03:45:24 steve
|
||||
* Add support for the procedural release statement.
|
||||
*
|
||||
* Revision 1.36 2000/04/22 04:20:19 steve
|
||||
* Add support for force assignment.
|
||||
*
|
||||
* Revision 1.35 2000/04/12 04:23:58 steve
|
||||
* Named events really should be expressed with PEIdent
|
||||
* objects in the pform,
|
||||
*
|
||||
* Handle named events within the mix of net events
|
||||
* and edges. As a unified lot they get caught together.
|
||||
* wait statements are broken into more complex statements
|
||||
* that include a conditional.
|
||||
*
|
||||
* Do not generate NetPEvent or NetNEvent objects in
|
||||
* elaboration. NetEvent, NetEvWait and NetEvProbe
|
||||
* take over those functions in the netlist.
|
||||
*
|
||||
* Revision 1.34 2000/04/10 05:26:06 steve
|
||||
* All events now use the NetEvent class.
|
||||
*
|
||||
* Revision 1.33 2000/04/04 03:20:15 steve
|
||||
* Simulate named event trigger and waits.
|
||||
*
|
||||
* Revision 1.32 2000/04/01 21:40:23 steve
|
||||
* Add support for integer division.
|
||||
*
|
||||
* Revision 1.31 2000/03/29 04:37:11 steve
|
||||
* New and improved combinational primitives.
|
||||
*
|
||||
* Revision 1.30 2000/02/23 02:56:56 steve
|
||||
* Macintosh compilers do not support ident.
|
||||
*
|
||||
* Revision 1.29 2000/01/13 03:35:35 steve
|
||||
* Multiplication all the way to simulation.
|
||||
*
|
||||
* 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.
|
||||
|
||||
@@ -18,8 +18,8 @@
|
||||
* 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: target.h,v 1.27 1999/11/28 23:42:03 steve Exp $"
|
||||
#if !defined(WINNT) && !defined(macintosh)
|
||||
#ident "$Id: target.h,v 1.38 2000/05/11 23:37:27 steve Exp $"
|
||||
#endif
|
||||
|
||||
# include "netlist.h"
|
||||
@@ -59,6 +59,9 @@ struct target_t {
|
||||
anything else is called. */
|
||||
virtual void scope(ostream&os, const NetScope*);
|
||||
|
||||
/* Output an event object. Called for each named event in the scope. */
|
||||
virtual void event(ostream&os, const NetEvent*);
|
||||
|
||||
/* Output a signal (called for each signal) */
|
||||
virtual void signal(ostream&os, const NetNet*);
|
||||
|
||||
@@ -73,7 +76,9 @@ struct target_t {
|
||||
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_divide(ostream&os, const NetDivide*);
|
||||
virtual void lpm_ff(ostream&os, const NetFF*);
|
||||
virtual void lpm_mult(ostream&os, const NetMult*);
|
||||
virtual void lpm_mux(ostream&os, const NetMux*);
|
||||
virtual void lpm_ram_dq(ostream&os, const NetRamDq*);
|
||||
|
||||
@@ -81,11 +86,14 @@ struct target_t {
|
||||
virtual void logic(ostream&os, const NetLogic*);
|
||||
virtual void bufz(ostream&os, const NetBUFZ*);
|
||||
virtual void udp(ostream&os, const NetUDP*);
|
||||
virtual void udp_comb(ostream&os, const NetUDP_COMB*);
|
||||
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 bool net_cassign(ostream&os, const NetCAssign*);
|
||||
virtual void net_const(ostream&os, const NetConst*);
|
||||
virtual void net_event(ostream&os, const NetNEvent*);
|
||||
virtual bool net_force(ostream&os, const NetForce*);
|
||||
virtual void net_probe(ostream&os, const NetEvProbe*);
|
||||
|
||||
/* Output a process (called for each process). It is up to the
|
||||
target to recurse if desired. */
|
||||
@@ -98,14 +106,18 @@ struct target_t {
|
||||
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 bool proc_cassign(ostream&os, const NetCAssign*);
|
||||
virtual void proc_condit(ostream&os, const NetCondit*);
|
||||
virtual bool proc_deassign(ostream&os, const NetDeassign*);
|
||||
virtual bool proc_force(ostream&os, const NetForce*);
|
||||
virtual void proc_forever(ostream&os, const NetForever*);
|
||||
virtual bool proc_release(ostream&os, const NetRelease*);
|
||||
virtual void proc_repeat(ostream&os, const NetRepeat*);
|
||||
virtual bool proc_trigger(ostream&os, const NetEvTrig*);
|
||||
virtual void proc_stask(ostream&os, const NetSTask*);
|
||||
virtual void proc_utask(ostream&os, const NetUTask*);
|
||||
virtual bool proc_wait(ostream&os, const NetEvWait*);
|
||||
virtual void proc_while(ostream&os, const NetWhile*);
|
||||
|
||||
virtual void proc_event(ostream&os, const NetPEvent*);
|
||||
virtual void proc_delay(ostream&os, const NetPDelay*);
|
||||
|
||||
/* Done with the design. */
|
||||
@@ -121,6 +133,7 @@ struct expr_scan_t {
|
||||
virtual void expr_ident(const NetEIdent*);
|
||||
virtual void expr_memory(const NetEMemory*);
|
||||
virtual void expr_scope(const NetEScope*);
|
||||
virtual void expr_sfunc(const NetESFunc*);
|
||||
virtual void expr_signal(const NetESignal*);
|
||||
virtual void expr_subsignal(const NetESubSignal*);
|
||||
virtual void expr_ternary(const NetETernary*);
|
||||
@@ -146,119 +159,42 @@ extern const struct target *target_table[];
|
||||
|
||||
/*
|
||||
* $Log: target.h,v $
|
||||
* Revision 1.27 1999/11/28 23:42:03 steve
|
||||
* NetESignal object no longer need to be NetNode
|
||||
* objects. Let them keep a pointer to NetNet objects.
|
||||
* Revision 1.38 2000/05/11 23:37:27 steve
|
||||
* Add support for procedural continuous assignment.
|
||||
*
|
||||
* Revision 1.26 1999/11/27 19:07:58 steve
|
||||
* Support the creation of scopes.
|
||||
* Revision 1.37 2000/05/04 03:37:59 steve
|
||||
* Add infrastructure for system functions, move
|
||||
* $time to that structure and add $random.
|
||||
*
|
||||
* Revision 1.25 1999/11/21 00:13:09 steve
|
||||
* Support memories in continuous assignments.
|
||||
* Revision 1.36 2000/04/23 03:45:25 steve
|
||||
* Add support for the procedural release statement.
|
||||
*
|
||||
* Revision 1.24 1999/11/14 23:43:46 steve
|
||||
* Support combinatorial comparators.
|
||||
* Revision 1.35 2000/04/22 04:20:20 steve
|
||||
* Add support for force assignment.
|
||||
*
|
||||
* Revision 1.23 1999/11/14 20:24:28 steve
|
||||
* Add support for the LPM_CLSHIFT device.
|
||||
* Revision 1.34 2000/04/12 04:23:58 steve
|
||||
* Named events really should be expressed with PEIdent
|
||||
* objects in the pform,
|
||||
*
|
||||
* 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>.
|
||||
* Handle named events within the mix of net events
|
||||
* and edges. As a unified lot they get caught together.
|
||||
* wait statements are broken into more complex statements
|
||||
* that include a conditional.
|
||||
*
|
||||
* 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.
|
||||
* Do not generate NetPEvent or NetNEvent objects in
|
||||
* elaboration. NetEvent, NetEvWait and NetEvProbe
|
||||
* take over those functions in the netlist.
|
||||
*
|
||||
* Rewrite elaborate_net for the PETernary class to
|
||||
* also use the LPM_MUX device.
|
||||
* Revision 1.33 2000/04/10 05:26:06 steve
|
||||
* All events now use the NetEvent class.
|
||||
*
|
||||
* 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.32 2000/04/04 03:20:15 steve
|
||||
* Simulate named event trigger and waits.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* Revision 1.14 1999/07/17 03:39:11 steve
|
||||
* simplified process scan for targets.
|
||||
*
|
||||
* Revision 1.13 1999/07/03 02:12:52 steve
|
||||
* Elaborate user defined tasks.
|
||||
*
|
||||
* Revision 1.12 1999/06/19 21:06:16 steve
|
||||
* Elaborate and supprort to vvm the forever
|
||||
* and repeat statements.
|
||||
*
|
||||
* Revision 1.11 1999/06/09 03:00:06 steve
|
||||
* Add support for procedural concatenation expression.
|
||||
*
|
||||
* Revision 1.10 1999/06/06 20:45:39 steve
|
||||
* Add parse and elaboration of non-blocking assignments,
|
||||
* Replace list<PCase::Item*> with an svector version,
|
||||
* Add integer support.
|
||||
*
|
||||
* Revision 1.9 1999/05/12 04:03:20 steve
|
||||
* emit NetAssignMem objects in vvm target.
|
||||
*
|
||||
* Revision 1.8 1999/05/01 02:57:53 steve
|
||||
* Handle much more complex event expressions.
|
||||
*
|
||||
* Revision 1.7 1999/04/25 00:44:10 steve
|
||||
* Core handles subsignal expressions.
|
||||
*
|
||||
* Revision 1.6 1999/04/19 01:59:37 steve
|
||||
* Add memories to the parse and elaboration phases.
|
||||
*
|
||||
* Revision 1.5 1999/02/08 02:49:56 steve
|
||||
* Turn the NetESignal into a NetNode so
|
||||
* that it can connect to the netlist.
|
||||
* Implement the case statement.
|
||||
* Convince t-vvm to output code for
|
||||
* the case statement.
|
||||
*
|
||||
* Revision 1.4 1998/12/01 00:42:15 steve
|
||||
* Elaborate UDP devices,
|
||||
* Support UDP type attributes, and
|
||||
* pass those attributes to nodes that
|
||||
* are instantiated by elaboration,
|
||||
* Put modules into a map instead of
|
||||
* a simple list.
|
||||
*
|
||||
* Revision 1.3 1998/11/09 18:55:35 steve
|
||||
* Add procedural while loops,
|
||||
* Parse procedural for loops,
|
||||
* Add procedural wait statements,
|
||||
* Add constant nodes,
|
||||
* Add XNOR logic gate,
|
||||
* Make vvm output look a bit prettier.
|
||||
*
|
||||
* Revision 1.2 1998/11/07 17:05:06 steve
|
||||
* Handle procedural conditional, and some
|
||||
* of the conditional expressions.
|
||||
*
|
||||
* Elaborate signals and identifiers differently,
|
||||
* allowing the netlist to hold signal information.
|
||||
*
|
||||
* Revision 1.1 1998/11/03 23:29:06 steve
|
||||
* Introduce verilog to CVS.
|
||||
* Revision 1.31 2000/04/01 21:40:23 steve
|
||||
* Add support for integer division.
|
||||
*
|
||||
* Revision 1.30 2000/03/29 04:37:11 steve
|
||||
* New and improved combinational primitives.
|
||||
*/
|
||||
#endif
|
||||
|
||||
+5
-2
@@ -16,8 +16,8 @@
|
||||
* 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: targets.cc,v 1.4 1999/05/01 02:57:53 steve Exp $"
|
||||
#if !defined(WINNT) && !defined(macintosh)
|
||||
#ident "$Id: targets.cc,v 1.5 2000/02/23 02:56:56 steve Exp $"
|
||||
#endif
|
||||
|
||||
# include "target.h"
|
||||
@@ -37,6 +37,9 @@ const struct target *target_table[] = {
|
||||
|
||||
/*
|
||||
* $Log: targets.cc,v $
|
||||
* Revision 1.5 2000/02/23 02:56:56 steve
|
||||
* Macintosh compilers do not support ident.
|
||||
*
|
||||
* Revision 1.4 1999/05/01 02:57:53 steve
|
||||
* Handle much more complex event expressions.
|
||||
*
|
||||
|
||||
@@ -0,0 +1,45 @@
|
||||
/*
|
||||
* Copyright (c) 2000 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) && !defined(macintosh)
|
||||
#ident "$Id: util.cc,v 1.1 2000/04/28 16:50:53 steve Exp $"
|
||||
#endif
|
||||
|
||||
# include "util.h"
|
||||
|
||||
string parse_first_name(string&path)
|
||||
{
|
||||
unsigned pos = path.find('.');
|
||||
if (pos > path.length()) {
|
||||
string res = path;
|
||||
path = "";
|
||||
return res;
|
||||
}
|
||||
|
||||
string res = path.substr(0, pos);
|
||||
path = path.substr(pos+1, path.length());
|
||||
return res;
|
||||
}
|
||||
|
||||
/*
|
||||
* $Log: util.cc,v $
|
||||
* Revision 1.1 2000/04/28 16:50:53 steve
|
||||
* Catch memory word parameters to tasks.
|
||||
*
|
||||
*/
|
||||
|
||||
@@ -0,0 +1,40 @@
|
||||
#ifndef __util_H
|
||||
#define __util_H
|
||||
/*
|
||||
* Copyright (c) 2000 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) && !defined(macintosh)
|
||||
#ident "$Id: util.h,v 1.1 2000/04/29 04:53:44 steve Exp $"
|
||||
#endif
|
||||
|
||||
# include <string>
|
||||
|
||||
/*
|
||||
* This function returns the first name of a hierarchical path, and
|
||||
* sets the parameter to what's left. If there is no path, then the
|
||||
* parameter is set to "".
|
||||
*/
|
||||
extern string parse_first_name(string&path);
|
||||
|
||||
/*
|
||||
* $Log: util.h,v $
|
||||
* Revision 1.1 2000/04/29 04:53:44 steve
|
||||
* missing header file.
|
||||
*
|
||||
*/
|
||||
#endif
|
||||
@@ -31,6 +31,8 @@ Defines macro \fImacro\fP as \fIdefn\fP.
|
||||
.B -I\fIincludepath\fP
|
||||
Append path \fIincludepath\fP to list of paths searched for include files.
|
||||
.TP 8
|
||||
.B -m\fImodule\fP
|
||||
Add this module to the list of modules to be loaded by the simulation.
|
||||
.B -X
|
||||
Generate XNF files as output. Default is VVM-format.
|
||||
.TP 8
|
||||
|
||||
+4
-3
@@ -21,7 +21,7 @@
|
||||
# Added support for functors, especially for the XNF target. <[email protected]>
|
||||
|
||||
# Setup variables
|
||||
execPath=@bindir@
|
||||
execPath=@libdir@/ivl
|
||||
execIVLPP=${execPath}/ivlpp
|
||||
execIVL=${execPath}/ivl
|
||||
execCpp=@CXX@
|
||||
@@ -46,7 +46,7 @@ flags=""
|
||||
#fi
|
||||
|
||||
# Try to extract given parameters
|
||||
parameter=`getopt D:I:Xxf:o:s:t: "$@"`
|
||||
parameter=`getopt D:I:Xxf:m:o:s:t: "$@"`
|
||||
eval set -- "${parameter}"
|
||||
while true ; do
|
||||
|
||||
@@ -55,6 +55,7 @@ while true ; do
|
||||
-I) extIncPath="${extIncPath} -I $2" ; shift 2 ;;
|
||||
-X) target="xnf" ; shift ;;
|
||||
-f) flags="$flags -f$2" ; shift 2 ;;
|
||||
-m) flags="$flags -m$2" ; shift 2 ;;
|
||||
-o) outputFile=$2 ; shift 2 ;;
|
||||
-s) topModule="-s $2 " ; shift 2 ;;
|
||||
-t) target="$2" ; shift 2 ;;
|
||||
@@ -115,7 +116,7 @@ case "${target}" in
|
||||
|
||||
"xnf") mv ${tmpCCFile} ${outputFile} ;;
|
||||
|
||||
"vvm") ${execCpp} -rdynamic -I${includedir} -L${libdir} ${tmpCCFile} -o ${outputFile} -lvvm -ldl ;
|
||||
"vvm") ${execCpp} -rdynamic -I${includedir} -L${libdir} ${tmpCCFile} -o ${outputFile} -lvvm @dllib@ ;
|
||||
if test $? -ne 0 ; then
|
||||
echo "C++ compilation failed. Terminating compilation."
|
||||
rm -f ${tmpCCFile}
|
||||
|
||||
+28
-12
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 1998 Stephen Williams (steve@icarus.com)
|
||||
* Copyright (c) 1998-2000 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
|
||||
@@ -16,8 +16,8 @@
|
||||
* 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: verinum.cc,v 1.12 1999/11/06 16:00:17 steve Exp $"
|
||||
#if !defined(WINNT) && !defined(macintosh)
|
||||
#ident "$Id: verinum.cc,v 1.16 2000/02/23 04:43:43 steve Exp $"
|
||||
#endif
|
||||
|
||||
# include "verinum.h"
|
||||
@@ -25,12 +25,12 @@
|
||||
# include <cassert>
|
||||
|
||||
verinum::verinum()
|
||||
: bits_(0), nbits_(0), has_len_(false), string_flag_(false)
|
||||
: bits_(0), nbits_(0), has_len_(false), has_sign_(false), string_flag_(false)
|
||||
{
|
||||
}
|
||||
|
||||
verinum::verinum(const V*bits, unsigned nbits, bool has_len)
|
||||
: has_len_(has_len), string_flag_(false)
|
||||
: has_len_(has_len), has_sign_(false), string_flag_(false)
|
||||
{
|
||||
nbits_ = nbits;
|
||||
bits_ = new V [nbits];
|
||||
@@ -40,7 +40,7 @@ verinum::verinum(const V*bits, unsigned nbits, bool has_len)
|
||||
}
|
||||
|
||||
verinum::verinum(const string&str)
|
||||
: has_len_(true), string_flag_(true)
|
||||
: has_len_(true), has_sign_(false), string_flag_(true)
|
||||
{
|
||||
nbits_ = str.length() * 8;
|
||||
bits_ = new V [nbits_];
|
||||
@@ -61,7 +61,7 @@ verinum::verinum(const string&str)
|
||||
}
|
||||
|
||||
verinum::verinum(verinum::V val, unsigned n)
|
||||
: has_len_(true), string_flag_(false)
|
||||
: has_len_(true), has_sign_(false), string_flag_(false)
|
||||
{
|
||||
nbits_ = n;
|
||||
bits_ = new V[nbits_];
|
||||
@@ -70,7 +70,7 @@ verinum::verinum(verinum::V val, unsigned n)
|
||||
}
|
||||
|
||||
verinum::verinum(unsigned long val, unsigned n)
|
||||
: has_len_(true), string_flag_(false)
|
||||
: has_len_(true), has_sign_(false), string_flag_(false)
|
||||
{
|
||||
nbits_ = n;
|
||||
bits_ = new V[nbits_];
|
||||
@@ -86,6 +86,7 @@ verinum::verinum(const verinum&that)
|
||||
nbits_ = that.nbits_;
|
||||
bits_ = new V[nbits_];
|
||||
has_len_ = that.has_len_;
|
||||
has_sign_ = that.has_sign_;
|
||||
for (unsigned idx = 0 ; idx < nbits_ ; idx += 1)
|
||||
bits_[idx] = that.bits_[idx];
|
||||
}
|
||||
@@ -97,6 +98,7 @@ verinum::verinum(const verinum&that, unsigned nbits)
|
||||
nbits_ = nbits;
|
||||
bits_ = new V[nbits_];
|
||||
has_len_ = true;
|
||||
has_sign_ = false;
|
||||
for (unsigned idx = 0 ; idx < nbits_ ; idx += 1)
|
||||
bits_[idx] = that.bits_[idx];
|
||||
}
|
||||
@@ -116,6 +118,7 @@ verinum& verinum::operator= (const verinum&that)
|
||||
bits_[idx] = that.bits_[idx];
|
||||
|
||||
has_len_ = that.has_len_;
|
||||
has_sign_ = that.has_sign_;
|
||||
string_flag_ = that.string_flag_;
|
||||
return *this;
|
||||
}
|
||||
@@ -164,8 +167,9 @@ signed long verinum::as_long() const
|
||||
|
||||
signed long val = 0;
|
||||
|
||||
// Extend the sign bit to fill the long.
|
||||
if (bits_[nbits_-1] == V1)
|
||||
// Extend the sign bit to fill the long. (But only for signed
|
||||
// numbers.)
|
||||
if (has_sign_ && (bits_[nbits_-1] == V1))
|
||||
val = -1;
|
||||
|
||||
for (unsigned idx = nbits_ ; idx > 0 ; idx -= 1) {
|
||||
@@ -391,7 +395,7 @@ static verinum::V add_with_carry(verinum::V l, verinum::V r, verinum::V&c)
|
||||
return verinum::V0;
|
||||
}
|
||||
|
||||
verinum not(const verinum&left)
|
||||
verinum v_not(const verinum&left)
|
||||
{
|
||||
verinum val = left;
|
||||
for (unsigned idx = 0 ; idx < val.len() ; idx += 1)
|
||||
@@ -441,7 +445,7 @@ verinum operator + (const verinum&left, const verinum&right)
|
||||
|
||||
verinum operator - (const verinum&left, const verinum&r)
|
||||
{
|
||||
verinum right = not(r);
|
||||
verinum right = v_not(r);
|
||||
unsigned min = left.len();
|
||||
if (right.len() < min) min = right.len();
|
||||
|
||||
@@ -467,6 +471,18 @@ verinum operator - (const verinum&left, const verinum&r)
|
||||
|
||||
/*
|
||||
* $Log: verinum.cc,v $
|
||||
* Revision 1.16 2000/02/23 04:43:43 steve
|
||||
* Some compilers do not accept the not symbol.
|
||||
*
|
||||
* Revision 1.15 2000/02/23 02:56:56 steve
|
||||
* Macintosh compilers do not support ident.
|
||||
*
|
||||
* Revision 1.14 2000/01/07 03:45:49 steve
|
||||
* Initial support for signed constants.
|
||||
*
|
||||
* Revision 1.13 2000/01/06 05:57:06 steve
|
||||
* Only sign-extend unsized numbers.
|
||||
*
|
||||
* Revision 1.12 1999/11/06 16:00:17 steve
|
||||
* Put number constants into a static table.
|
||||
*
|
||||
|
||||
@@ -18,8 +18,8 @@
|
||||
* 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: verinum.h,v 1.8 1999/11/06 16:00:17 steve Exp $"
|
||||
#if !defined(WINNT) && !defined(macintosh)
|
||||
#ident "$Id: verinum.h,v 1.11 2000/02/23 04:43:43 steve Exp $"
|
||||
#endif
|
||||
|
||||
# include <string>
|
||||
@@ -56,6 +56,9 @@ class verinum {
|
||||
// in some way.
|
||||
bool has_len() const { return has_len_; }
|
||||
|
||||
bool has_sign(bool flag) { has_sign_ = flag; return has_sign_; }
|
||||
bool has_sign() const { return has_sign_; }
|
||||
|
||||
// A number is "defined" if there are no x or z bits in its value.
|
||||
bool is_defined() const;
|
||||
|
||||
@@ -82,6 +85,7 @@ class verinum {
|
||||
V* bits_;
|
||||
unsigned nbits_;
|
||||
bool has_len_;
|
||||
bool has_sign_;
|
||||
|
||||
// These are some convenience flags that help us do a better
|
||||
// job of pretty-printing values.
|
||||
@@ -98,8 +102,19 @@ 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);
|
||||
|
||||
extern verinum v_not(const verinum&left);
|
||||
|
||||
/*
|
||||
* $Log: verinum.h,v $
|
||||
* Revision 1.11 2000/02/23 04:43:43 steve
|
||||
* Some compilers do not accept the not symbol.
|
||||
*
|
||||
* Revision 1.10 2000/02/23 02:56:56 steve
|
||||
* Macintosh compilers do not support ident.
|
||||
*
|
||||
* Revision 1.9 2000/01/07 03:45:49 steve
|
||||
* Initial support for signed constants.
|
||||
*
|
||||
* Revision 1.8 1999/11/06 16:00:17 steve
|
||||
* Put number constants into a static table.
|
||||
*
|
||||
|
||||
+5
-2
@@ -16,8 +16,8 @@
|
||||
* 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: verireal.cc,v 1.1 1999/06/15 02:50:02 steve Exp $"
|
||||
#if !defined(WINNT) && !defined(macintosh)
|
||||
#ident "$Id: verireal.cc,v 1.2 2000/02/23 02:56:56 steve Exp $"
|
||||
#endif
|
||||
|
||||
# include "verireal.h"
|
||||
@@ -92,6 +92,9 @@ verireal::~verireal()
|
||||
|
||||
/*
|
||||
* $Log: verireal.cc,v $
|
||||
* Revision 1.2 2000/02/23 02:56:56 steve
|
||||
* Macintosh compilers do not support ident.
|
||||
*
|
||||
* Revision 1.1 1999/06/15 02:50:02 steve
|
||||
* Add lexical support for real numbers.
|
||||
*
|
||||
|
||||
+5
-2
@@ -18,8 +18,8 @@
|
||||
* 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: verireal.h,v 1.1 1999/06/15 02:50:02 steve Exp $"
|
||||
#if !defined(WINNT) && !defined(macintosh)
|
||||
#ident "$Id: verireal.h,v 1.2 2000/02/23 02:56:56 steve Exp $"
|
||||
#endif
|
||||
|
||||
class verireal {
|
||||
@@ -37,6 +37,9 @@ class verireal {
|
||||
|
||||
/*
|
||||
* $Log: verireal.h,v $
|
||||
* Revision 1.2 2000/02/23 02:56:56 steve
|
||||
* Macintosh compilers do not support ident.
|
||||
*
|
||||
* Revision 1.1 1999/06/15 02:50:02 steve
|
||||
* Add lexical support for real numbers.
|
||||
*
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
Makefile
|
||||
sys_readmem_lex.c
|
||||
system.vpi
|
||||
dep
|
||||
|
||||
+7
-3
@@ -18,7 +18,7 @@
|
||||
# 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 $"
|
||||
#ident "$Id: Makefile.in,v 1.10 2000/05/04 03:37:59 steve Exp $"
|
||||
#
|
||||
#
|
||||
SHELL = /bin/sh
|
||||
@@ -52,11 +52,15 @@ all: system.vpi
|
||||
$(CC) -Wall $(CPPFLAGS) -I$(srcdir) -MD -c $< -o $*.o
|
||||
mv $*.d dep
|
||||
|
||||
O = sys_table.o sys_display.o sys_finish.o sys_vcd.o
|
||||
O = sys_table.o sys_display.o sys_finish.o sys_random.o \
|
||||
sys_readmem.o sys_readmem_lex.o sys_vcd.o
|
||||
|
||||
system.vpi: $O
|
||||
$(CC) -shared -o $@ $O
|
||||
|
||||
sys_readmem_lex.c: sys_readmem_lex.lex
|
||||
flex -t -Preadmem sys_readmem_lex.lex > sys_readmem_lex.c
|
||||
|
||||
clean:
|
||||
rm -f *.o dep/*.d
|
||||
|
||||
@@ -64,7 +68,7 @@ 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
|
||||
$(INSTALL_DATA) ./system.vpi $(libdir)/ivl/system.vpi
|
||||
|
||||
$(includedir)/vpi_user.h: $(srcdir)/vpi_user.h
|
||||
$(INSTALL_DATA) $(srcdir)/vpi_user.h $(includedir)/vpi_user.h
|
||||
|
||||
+210
-39
@@ -16,8 +16,8 @@
|
||||
* 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 $"
|
||||
#if !defined(WINNT) && !defined(macintosh)
|
||||
#ident "$Id: sys_display.c,v 1.15 2000/05/09 00:02:29 steve Exp $"
|
||||
#endif
|
||||
|
||||
# include "vpi_user.h"
|
||||
@@ -55,7 +55,7 @@ static void array_from_iterator(struct strobe_cb_info*info, vpiHandle argv)
|
||||
* 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)
|
||||
static int format_str(unsigned int mcd, char*fmt, int argc, vpiHandle*argv)
|
||||
{
|
||||
s_vpi_value value;
|
||||
char buf[256];
|
||||
@@ -73,7 +73,7 @@ static int format_str(char*fmt, int argc, vpiHandle*argv)
|
||||
cnt = sizeof buf - 1;
|
||||
strncpy(buf, cp, cnt);
|
||||
buf[cnt] = 0;
|
||||
vpi_printf("%s", buf);
|
||||
vpi_mcd_printf(mcd, "%s", buf);
|
||||
cp += cnt;
|
||||
|
||||
} else if (*cp == '%') {
|
||||
@@ -90,27 +90,31 @@ static int format_str(char*fmt, int argc, vpiHandle*argv)
|
||||
case 'B':
|
||||
value.format = vpiBinStrVal;
|
||||
vpi_get_value(argv[idx++], &value);
|
||||
vpi_printf("%s", value.value.str);
|
||||
vpi_mcd_printf(mcd, "%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);
|
||||
vpi_mcd_printf(mcd, "%s", value.value.str);
|
||||
cp += 1;
|
||||
break;
|
||||
case 'h':
|
||||
case 'H':
|
||||
case 'x':
|
||||
case 'X':
|
||||
if (idx >= argc) {
|
||||
vpi_printf("%s", "\nRAN OUT OF VALUES\n");
|
||||
exit(1);
|
||||
}
|
||||
value.format = vpiHexStrVal;
|
||||
vpi_get_value(argv[idx++], &value);
|
||||
vpi_printf("%s", value.value.str);
|
||||
vpi_mcd_printf(mcd, "%s", value.value.str);
|
||||
cp += 1;
|
||||
break;
|
||||
case 'm':
|
||||
vpi_printf("%s", vpi_get_str(vpiFullName, argv[idx]));
|
||||
vpi_mcd_printf(mcd, "%s", vpi_get_str(vpiFullName, argv[idx]));
|
||||
idx += 1;
|
||||
cp += 1;
|
||||
break;
|
||||
@@ -118,22 +122,22 @@ static int format_str(char*fmt, int argc, vpiHandle*argv)
|
||||
case 'O':
|
||||
value.format = vpiOctStrVal;
|
||||
vpi_get_value(argv[idx++], &value);
|
||||
vpi_printf("%s", value.value.str);
|
||||
vpi_mcd_printf(mcd, "%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);
|
||||
vpi_mcd_printf(mcd, "%s", value.value.str);
|
||||
cp += 1;
|
||||
break;
|
||||
case '%':
|
||||
vpi_printf("%%");
|
||||
vpi_mcd_printf(mcd, "%%");
|
||||
cp += 1;
|
||||
break;
|
||||
default:
|
||||
vpi_printf("%c", *cp);
|
||||
vpi_mcd_printf(mcd, "%c", *cp);
|
||||
cp += 1;
|
||||
break;
|
||||
}
|
||||
@@ -145,11 +149,11 @@ static int format_str(char*fmt, int argc, vpiHandle*argv)
|
||||
case 0:
|
||||
break;
|
||||
case 'n':
|
||||
vpi_printf("\n");
|
||||
vpi_mcd_printf(mcd, "\n");
|
||||
cp += 1;
|
||||
break;
|
||||
default:
|
||||
vpi_printf("%c", *cp);
|
||||
vpi_mcd_printf(mcd, "%c", *cp);
|
||||
cp += 1;
|
||||
}
|
||||
}
|
||||
@@ -158,7 +162,7 @@ static int format_str(char*fmt, int argc, vpiHandle*argv)
|
||||
return idx;
|
||||
}
|
||||
|
||||
static void do_display(struct strobe_cb_info*info)
|
||||
static void do_display(unsigned int mcd, struct strobe_cb_info*info)
|
||||
{
|
||||
s_vpi_value value;
|
||||
int idx;
|
||||
@@ -169,38 +173,39 @@ static void do_display(struct strobe_cb_info*info)
|
||||
switch (vpi_get(vpiType, item)) {
|
||||
|
||||
case 0:
|
||||
vpi_printf(" ");
|
||||
vpi_mcd_printf(mcd, " ");
|
||||
break;
|
||||
|
||||
case vpiConstant:
|
||||
if (vpi_get(vpiConstType, item) == vpiStringConst) {
|
||||
value.format = vpiStringVal;
|
||||
vpi_get_value(item, &value);
|
||||
idx += format_str(value.value.str,
|
||||
idx += format_str(mcd, 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);
|
||||
vpi_mcd_printf(mcd, "%s", value.value.str);
|
||||
}
|
||||
break;
|
||||
|
||||
case vpiNet:
|
||||
case vpiReg:
|
||||
case vpiMemoryWord:
|
||||
value.format = vpiBinStrVal;
|
||||
vpi_get_value(item, &value);
|
||||
vpi_printf("%s", value.value.str);
|
||||
vpi_mcd_printf(mcd, "%s", value.value.str);
|
||||
break;
|
||||
|
||||
case vpiTimeVar:
|
||||
value.format = vpiTimeVal;
|
||||
vpi_get_value(item, &value);
|
||||
vpi_printf("%u", value.value.time->low);
|
||||
vpi_mcd_printf(mcd, "%u", value.value.time->low);
|
||||
break;
|
||||
|
||||
default:
|
||||
vpi_printf("?");
|
||||
vpi_mcd_printf(mcd, "?");
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -215,7 +220,7 @@ static int sys_display_calltf(char *name)
|
||||
|
||||
array_from_iterator(&info, argv);
|
||||
|
||||
do_display(&info);
|
||||
do_display(1, &info);
|
||||
|
||||
free(info.items);
|
||||
|
||||
@@ -237,7 +242,7 @@ static int strobe_cb(p_cb_data cb)
|
||||
{
|
||||
struct strobe_cb_info*info = (struct strobe_cb_info*)cb->user_data;
|
||||
|
||||
do_display(info);
|
||||
do_display(1, info);
|
||||
|
||||
vpi_printf("\n");
|
||||
|
||||
@@ -289,7 +294,7 @@ static vpiHandle *monitor_callbacks = 0;
|
||||
|
||||
static int monitor_cb_2(p_cb_data cb)
|
||||
{
|
||||
do_display(&monitor_info);
|
||||
do_display(1, &monitor_info);
|
||||
vpi_printf("\n");
|
||||
monitor_scheduled = 0;
|
||||
return 0;
|
||||
@@ -299,11 +304,14 @@ static int monitor_cb_1(p_cb_data cause)
|
||||
{
|
||||
struct t_cb_data cb;
|
||||
struct t_vpi_time time;
|
||||
/* The user_data of the callback is a pointer to the callback
|
||||
handle. I use this to reschedule the callback if needed. */
|
||||
vpiHandle*cbh = (vpiHandle*) (cause->user_data);
|
||||
|
||||
/* Reschedule this event so that it happens for the next
|
||||
trigger on this variable. */
|
||||
cb = *cause;
|
||||
vpi_register_cb(&cb);
|
||||
*cbh = vpi_register_cb(&cb);
|
||||
|
||||
if (monitor_scheduled) return 0;
|
||||
|
||||
@@ -362,6 +370,11 @@ static int sys_monitor_calltf(char*name)
|
||||
switch (vpi_get(vpiType, monitor_info.items[idx])) {
|
||||
case vpiNet:
|
||||
case vpiReg:
|
||||
/* Monitoring reg and net values involves setting
|
||||
a collback for value changes. pass the storage
|
||||
pointer for the callback itself as user_data so
|
||||
that the callback can refresh itself. */
|
||||
cb.user_data = (char*)(monitor_callbacks+idx);
|
||||
cb.obj = monitor_info.items[idx];
|
||||
monitor_callbacks[idx] = vpi_register_cb(&cb);
|
||||
break;
|
||||
@@ -372,6 +385,125 @@ static int sys_monitor_calltf(char*name)
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Implement the $fopen system function.
|
||||
*/
|
||||
static int sys_fopen_calltf(char *name)
|
||||
{
|
||||
s_vpi_value val, value;
|
||||
|
||||
vpiHandle call_handle = vpi_handle(vpiSysTfCall, 0);
|
||||
vpiHandle argv = vpi_iterate(vpiArgument, call_handle);
|
||||
vpiHandle item = vpi_scan(argv);
|
||||
|
||||
if (item == 0) {
|
||||
vpi_printf("%s: file name parameter missing.\n", name);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (vpi_get(vpiType, item) != vpiConstant) {
|
||||
vpi_printf("ERROR: %s parameter must be a constant\n", name);
|
||||
vpi_free_object(argv);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (vpi_get(vpiConstType, item) != vpiStringConst) {
|
||||
vpi_printf("ERROR: %s parameter must be a constant\n", name);
|
||||
vpi_free_object(argv);
|
||||
return 0;
|
||||
}
|
||||
|
||||
value.format = vpiStringVal;
|
||||
vpi_get_value(item, &value);
|
||||
|
||||
val.format = vpiIntVal;
|
||||
val.value.integer = vpi_mcd_open( value.value.str );
|
||||
|
||||
vpi_put_value(call_handle, &val, 0, vpiNoDelay);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int sys_fopen_sizetf(char*x)
|
||||
{
|
||||
return 32;
|
||||
}
|
||||
|
||||
/* Implement $fdisplay and $fwrite.
|
||||
* Perhaps this could be merged into sys_display_calltf.
|
||||
*/
|
||||
static int sys_fdisplay_calltf(char *name)
|
||||
{
|
||||
struct strobe_cb_info info;
|
||||
unsigned int mcd;
|
||||
int type;
|
||||
s_vpi_value value;
|
||||
vpiHandle sys = vpi_handle(vpiSysTfCall, 0);
|
||||
vpiHandle argv = vpi_iterate(vpiArgument, sys);
|
||||
vpiHandle item = vpi_scan(argv);
|
||||
|
||||
if (item == 0) {
|
||||
vpi_printf("%s: mcd parameter missing.\n", name);
|
||||
return 0;
|
||||
}
|
||||
|
||||
type = vpi_get(vpiType, item);
|
||||
if (type != vpiReg && type != vpiReadVal) {
|
||||
vpi_printf("ERROR: %s mcd parameter must be of integral, got vpiType=%d\n",
|
||||
name, type);
|
||||
vpi_free_object(argv);
|
||||
return 0;
|
||||
}
|
||||
|
||||
value.format = vpiIntVal;
|
||||
vpi_get_value(item, &value);
|
||||
mcd = value.value.integer;
|
||||
|
||||
array_from_iterator(&info, argv);
|
||||
do_display(mcd, &info);
|
||||
free(info.items);
|
||||
|
||||
if (strcmp(name,"$fdisplay") == 0)
|
||||
vpi_mcd_printf(mcd, "\n");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Implement $fclose system function
|
||||
*/
|
||||
static int sys_fclose_calltf(char *name)
|
||||
{
|
||||
unsigned int mcd;
|
||||
int type;
|
||||
s_vpi_value value;
|
||||
|
||||
vpiHandle sys = vpi_handle(vpiSysTfCall, 0);
|
||||
vpiHandle argv = vpi_iterate(vpiArgument, sys);
|
||||
vpiHandle item = vpi_scan(argv);
|
||||
|
||||
if (item == 0) {
|
||||
vpi_printf("%s: mcd parameter missing.\n", name);
|
||||
return 0;
|
||||
}
|
||||
type = vpi_get(vpiType, item);
|
||||
if (type != vpiReg && type != vpiReadVal) {
|
||||
vpi_printf("ERROR: %s mcd parameter must be of integral type, got vpiType=%d\n",
|
||||
name, type);
|
||||
vpi_free_object(argv);
|
||||
return 0;
|
||||
}
|
||||
|
||||
value.format = vpiIntVal;
|
||||
vpi_get_value(item, &value);
|
||||
mcd = value.value.integer;
|
||||
|
||||
vpi_mcd_close(mcd);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
void sys_display_register()
|
||||
{
|
||||
s_vpi_systf_data tf_data;
|
||||
@@ -407,11 +539,64 @@ void sys_display_register()
|
||||
tf_data.sizetf = 0;
|
||||
tf_data.user_data = "$monitor";
|
||||
vpi_register_systf(&tf_data);
|
||||
|
||||
tf_data.type = vpiSysFunc;
|
||||
tf_data.tfname = "$fopen";
|
||||
tf_data.calltf = sys_fopen_calltf;
|
||||
tf_data.compiletf = 0;
|
||||
tf_data.sizetf = sys_fopen_sizetf;
|
||||
tf_data.user_data = "$fopen";
|
||||
vpi_register_systf(&tf_data);
|
||||
|
||||
tf_data.type = vpiSysTask;
|
||||
tf_data.tfname = "$fclose";
|
||||
tf_data.calltf = sys_fclose_calltf;
|
||||
tf_data.compiletf = 0;
|
||||
tf_data.sizetf = 0;
|
||||
tf_data.user_data = "$fclose";
|
||||
vpi_register_systf(&tf_data);
|
||||
|
||||
tf_data.type = vpiSysTask;
|
||||
tf_data.tfname = "$fdisplay";
|
||||
tf_data.calltf = sys_fdisplay_calltf;
|
||||
tf_data.compiletf = 0;
|
||||
tf_data.sizetf = 0;
|
||||
tf_data.user_data = "$fdisplay";
|
||||
vpi_register_systf(&tf_data);
|
||||
|
||||
tf_data.type = vpiSysTask;
|
||||
tf_data.tfname = "$fwrite";
|
||||
tf_data.calltf = sys_fdisplay_calltf;
|
||||
tf_data.compiletf = 0;
|
||||
tf_data.sizetf = 0;
|
||||
tf_data.user_data = "$fwrite";
|
||||
vpi_register_systf(&tf_data);
|
||||
|
||||
vpi_mcd_init();
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* $Log: sys_display.c,v $
|
||||
* Revision 1.15 2000/05/09 00:02:29 steve
|
||||
* Remove test print.
|
||||
*
|
||||
* Revision 1.14 2000/05/07 18:20:07 steve
|
||||
* Import MCD support from Stephen Tell, and add
|
||||
* system function parameter support to the IVL core.
|
||||
*
|
||||
* Revision 1.13 2000/04/21 02:00:35 steve
|
||||
* exit if hex value is missing.
|
||||
*
|
||||
* Revision 1.12 2000/03/31 07:08:39 steve
|
||||
* allow cancelling of cbValueChange events.
|
||||
*
|
||||
* Revision 1.11 2000/02/23 02:56:56 steve
|
||||
* Macintosh compilers do not support ident.
|
||||
*
|
||||
* Revision 1.10 2000/02/13 19:18:27 steve
|
||||
* Accept memory words as parameter to $display.
|
||||
*
|
||||
* Revision 1.9 1999/11/07 02:25:07 steve
|
||||
* Add the $monitor implementation.
|
||||
*
|
||||
@@ -429,19 +614,5 @@ void sys_display_register()
|
||||
* 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.
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
+5
-2
@@ -16,8 +16,8 @@
|
||||
* 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 $"
|
||||
#if !defined(WINNT) && !defined(macintosh)
|
||||
#ident "$Id: sys_finish.c,v 1.4 2000/02/23 02:56:56 steve Exp $"
|
||||
#endif
|
||||
|
||||
# include "vpi_user.h"
|
||||
@@ -42,6 +42,9 @@ void sys_finish_register()
|
||||
|
||||
/*
|
||||
* $Log: sys_finish.c,v $
|
||||
* Revision 1.4 2000/02/23 02:56:56 steve
|
||||
* Macintosh compilers do not support ident.
|
||||
*
|
||||
* Revision 1.3 1999/08/28 02:10:44 steve
|
||||
* Call the right vpiFinish code.
|
||||
*
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user