mirror of
https://github.com/steveicarus/iverilog.git
synced 2026-08-26 15:56:24 +02:00
Compare commits
151
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
d1daf6733f | ||
|
|
007056d671 | ||
|
|
2dcb1514a2 | ||
|
|
d71a1cb9c1 | ||
|
|
4c3d764a86 | ||
|
|
3189efacbc | ||
|
|
96ec4b7eba | ||
|
|
07c8fce530 | ||
|
|
9a00829ee4 | ||
|
|
680d3c8a3e | ||
|
|
6632e4c33b | ||
|
|
42913e46b8 | ||
|
|
e2ad59466a | ||
|
|
0cd946a7af | ||
|
|
102cbb67b4 | ||
|
|
3113392594 | ||
|
|
72b4256872 | ||
|
|
ca880c73fc | ||
|
|
cef0d0071b | ||
|
|
2934ceb548 | ||
|
|
6b908aeec3 | ||
|
|
a6dd97a5a6 | ||
|
|
2b4f7f8aed | ||
|
|
add84b153c | ||
|
|
3c5bf034ca | ||
|
|
84a7efdb4f | ||
|
|
dfb7bf5211 | ||
|
|
a33619a0f5 | ||
|
|
a1495bb007 | ||
|
|
8e1f22cd82 | ||
|
|
db10de1a6a | ||
|
|
bbed408d68 | ||
|
|
ba3660b948 | ||
|
|
73dcace781 | ||
|
|
fd3ca037aa | ||
|
|
2d068ca89f | ||
|
|
dea1161c7e | ||
|
|
3a61b94e98 | ||
|
|
3a8a6976e1 | ||
|
|
6cc244766c | ||
|
|
6e3ec755e2 | ||
|
|
ca517b5519 | ||
|
|
10ab5cf698 | ||
|
|
523de1b69c | ||
|
|
3e591f730e | ||
|
|
34e90bb3a6 | ||
|
|
4f8b91e65c | ||
|
|
e91243e1c6 | ||
|
|
5484ee1732 | ||
|
|
a43f336c6c | ||
|
|
cc7187c172 | ||
|
|
d60df2d75b | ||
|
|
6d433364ac | ||
|
|
bbc80a84a6 | ||
|
|
c993fb8325 | ||
|
|
f662d76b2e | ||
|
|
0c29e540ea | ||
|
|
1a8be6d28c | ||
|
|
6491c5d43c | ||
|
|
a319939573 | ||
|
|
9db9aa4ccb | ||
|
|
cb5260b2ce | ||
|
|
c0d3bb370f | ||
|
|
b99206ac8e | ||
|
|
149bfa05d8 | ||
|
|
86a4025b58 | ||
|
|
2a5948d704 | ||
|
|
f5263c9447 | ||
|
|
f95a6fed14 | ||
|
|
436e2fca13 | ||
|
|
64c92f9fdd | ||
|
|
603ca0f2de | ||
|
|
efba4bfd09 | ||
|
|
785aad94c5 | ||
|
|
ffbf37b06b | ||
|
|
c3ac01d31b | ||
|
|
81e12bf7f6 | ||
|
|
abaab602bc | ||
|
|
bd170d05ad | ||
|
|
7b81eb3494 | ||
|
|
b775d178d2 | ||
|
|
10ea9904f1 | ||
|
|
e7d463704c | ||
|
|
c38e8182c2 | ||
|
|
7b705a0212 | ||
|
|
5ddd35565f | ||
|
|
a12a6d925a | ||
|
|
5ab0c20a7d | ||
|
|
35e511d0c0 | ||
|
|
935c3dc02d | ||
|
|
6d2ef15951 | ||
|
|
40fd07d46e | ||
|
|
5e30016910 | ||
|
|
33466250f5 | ||
|
|
bdab7698d2 | ||
|
|
54918cf5b9 | ||
|
|
844447b995 | ||
|
|
6eb9825ab7 | ||
|
|
23e60aa381 | ||
|
|
373123af6b | ||
|
|
54cf66d8b4 | ||
|
|
dffe1be819 | ||
|
|
d41f8fe52b | ||
|
|
6ca53c6810 | ||
|
|
9bb8e8146f | ||
|
|
321114e4db | ||
|
|
ef3aacfe36 | ||
|
|
bfb33230aa | ||
|
|
44767d8f70 | ||
|
|
fecd941a28 | ||
|
|
2be8534021 | ||
|
|
8cece424d1 | ||
|
|
e2dfeac86c | ||
|
|
a914eda5ef | ||
|
|
ba8a41ca28 | ||
|
|
a67d573ae6 | ||
|
|
f5418fe337 | ||
|
|
7035ded57a | ||
|
|
ad3a73f74f | ||
|
|
43e8a08c97 | ||
|
|
208c6a349d | ||
|
|
640231bbfa | ||
|
|
bdc48135e5 | ||
|
|
f7e840cd0a | ||
|
|
3c1e7c4260 | ||
|
|
5a1ec9b958 | ||
|
|
1bc56fcc93 | ||
|
|
13958cf374 | ||
|
|
b5b5a9935c | ||
|
|
bb14ac1fe0 | ||
|
|
04e8623ed6 | ||
|
|
225fcf6bf0 | ||
|
|
8c1cca423d | ||
|
|
7bc9742710 | ||
|
|
12f8af645f | ||
|
|
259e4294e3 | ||
|
|
ea74eb771e | ||
|
|
32b115d8fe | ||
|
|
14e3a886bd | ||
|
|
140fd45460 | ||
|
|
5b2f249dcc | ||
|
|
01eb298228 | ||
|
|
48990d8e2d | ||
|
|
77722a62c2 | ||
|
|
a2ea980a7a | ||
|
|
86301be3d2 | ||
|
|
bbb488f730 | ||
|
|
13d4a7352c | ||
|
|
d26ae866f8 | ||
|
|
8e6c2652ab | ||
|
|
9b1baea6da |
+45
-24
@@ -57,7 +57,7 @@ CXXFLAGS = -Wall @CXXFLAGS@
|
||||
PICFLAGS = @PICFLAG@
|
||||
LDFLAGS = @rdynamic@ @LDFLAGS@
|
||||
|
||||
all: dep ivl@EXEEXT@
|
||||
all: dep version.h ivl@EXEEXT@
|
||||
for dir in $(SUBDIRS); do (cd $$dir ; $(MAKE) $@); done
|
||||
for dir in ivlpp ; \
|
||||
do (cd $$dir ; $(MAKE) $@); done
|
||||
@@ -124,9 +124,9 @@ ifeq (@WIN32@,yes)
|
||||
# The first step makes an ivl.exe that dlltool can use to make an
|
||||
# export and import library, and the last link makes a, ivl.exe
|
||||
# that really exports the things that the import library imports.
|
||||
ivl@EXEEXT@: $O ivl.def
|
||||
ivl@EXEEXT@: $O $(srcdir)/ivl.def
|
||||
$(CXX) -o ivl@EXEEXT@ $O $(dllib) @EXTRALIBS@
|
||||
dlltool --dllname ivl@EXEEXT@ --def ivl.def \
|
||||
dlltool --dllname ivl@EXEEXT@ --def $(srcdir)/ivl.def \
|
||||
--output-lib libivl.a --output-exp ivl.exp
|
||||
$(CXX) $(LDFLAGS) -o ivl@EXEEXT@ ivl.exp $O $(dllib) @EXTRALIBS@
|
||||
else
|
||||
@@ -182,6 +182,24 @@ iverilog-vpi.ps: $(srcdir)/iverilog-vpi.man
|
||||
iverilog-vpi.pdf: iverilog-vpi.ps
|
||||
ps2pdf iverilog-vpi.ps iverilog-vpi.pdf
|
||||
|
||||
# For VERSION_TAG in driver/main.c, first try git-describe, then look for a
|
||||
# version.h file in the source tree (included in snapshots and releases), and
|
||||
# finally use nothing.
|
||||
.PHONY: version.h
|
||||
version.h:
|
||||
@if test -d $(srcdir)/.git; then \
|
||||
echo "Using git-describe for VERSION_TAG"; \
|
||||
tmp=`git --git-dir $(srcdir)/.git describe \
|
||||
| sed -e 's;\(.*\);#define VERSION_TAG "\1";'`; \
|
||||
echo "$$tmp" | diff - $@ > /dev/null 2>&1 || echo "$$tmp" > $@ || exit 1; \
|
||||
elif test -r $(srcdir)/$@; then \
|
||||
echo "Using $(srcdir)/$@ for VERSION_TAG"; \
|
||||
diff $(srcdir)/$@ $@ > /dev/null 2>&1 || cp $(srcdir)/$@ $@; \
|
||||
else \
|
||||
echo "Using empty VERSION_TAG"; \
|
||||
echo '#define VERSION_TAG ""' > $@; \
|
||||
fi
|
||||
|
||||
ifeq (@MING32@,yes)
|
||||
INSTALL_DOC = $(prefix)/iverilog-vpi.pdf $(mandir)/man1/iverilog-vpi.1
|
||||
INSTALL_DOCDIR = $(mandir)/man1
|
||||
@@ -199,43 +217,46 @@ endif
|
||||
|
||||
XNF_INSTALL = $(libdir)/ivl/xnf.conf $(libdir)/ivl/xnf-s.conf
|
||||
|
||||
install: all installdirs $(libdir)/ivl/ivl@EXEEXT@ $(includedir)/ivl_target.h $(includedir)/_pli_types.h $(includedir)/vpi_user.h $(includedir)/acc_user.h $(includedir)/veriuser.h $(WIN32_INSTALL) $(INSTALL_DOC)
|
||||
install: all installdirs $(libdir)/ivl/ivl@EXEEXT@ $(libdir)/ivl/include/constants.vams $(includedir)/ivl_target.h $(includedir)/_pli_types.h $(includedir)/vpi_user.h $(includedir)/acc_user.h $(includedir)/veriuser.h $(WIN32_INSTALL) $(INSTALL_DOC)
|
||||
for dir in $(SUBDIRS); do (cd $$dir ; $(MAKE) $@); done
|
||||
for dir in vpi ivlpp driver; \
|
||||
do (cd $$dir ; $(MAKE) $@); done
|
||||
|
||||
$(bindir)/iverilog-vpi: ./iverilog-vpi
|
||||
$(INSTALL_SCRIPT) ./iverilog-vpi $(bindir)/iverilog-vpi
|
||||
$(INSTALL_SCRIPT) ./iverilog-vpi $(DESTDIR)$(bindir)/iverilog-vpi
|
||||
|
||||
$(libdir)/ivl/ivl@EXEEXT@: ./ivl@EXEEXT@
|
||||
$(INSTALL_PROGRAM) ./ivl@EXEEXT@ $(libdir)/ivl/ivl@EXEEXT@
|
||||
$(INSTALL_PROGRAM) ./ivl@EXEEXT@ $(DESTDIR)$(libdir)/ivl/ivl@EXEEXT@
|
||||
|
||||
$(libdir)/ivl/include/constants.vams: $(srcdir)/constants.vams
|
||||
$(INSTALL_DATA) $(srcdir)/constants.vams $@
|
||||
|
||||
$(libdir)/ivl/xnf-s.conf: $(srcdir)/xnf-s.conf
|
||||
$(INSTALL_DATA) $(srcdir)/xnf-s.conf $(libdir)/ivl/xnf-s.conf
|
||||
$(INSTALL_DATA) $(srcdir)/xnf-s.conf $(DESTDIR)$(libdir)/ivl/xnf-s.conf
|
||||
|
||||
$(libdir)/ivl/xnf.conf: $(srcdir)/xnf.conf
|
||||
$(INSTALL_DATA) $(srcdir)/xnf.conf $(libdir)/ivl/xnf.conf
|
||||
$(INSTALL_DATA) $(srcdir)/xnf.conf $(DESTDIR)$(libdir)/ivl/xnf.conf
|
||||
|
||||
$(includedir)/ivl_target.h: $(srcdir)/ivl_target.h
|
||||
$(INSTALL_DATA) $(srcdir)/ivl_target.h $(includedir)/ivl_target.h
|
||||
$(INSTALL_DATA) $(srcdir)/ivl_target.h $(DESTDIR)$(includedir)/ivl_target.h
|
||||
|
||||
$(includedir)/_pli_types.h: _pli_types.h
|
||||
$(INSTALL_DATA) $< $(includedir)/_pli_types.h
|
||||
$(INSTALL_DATA) $< $(DESTDIR)$(includedir)/_pli_types.h
|
||||
|
||||
$(includedir)/vpi_user.h: $(srcdir)/vpi_user.h
|
||||
$(INSTALL_DATA) $(srcdir)/vpi_user.h $(includedir)/vpi_user.h
|
||||
$(INSTALL_DATA) $(srcdir)/vpi_user.h $(DESTDIR)$(includedir)/vpi_user.h
|
||||
|
||||
$(includedir)/acc_user.h: $(srcdir)/acc_user.h
|
||||
$(INSTALL_DATA) $(srcdir)/acc_user.h $(includedir)/acc_user.h
|
||||
$(INSTALL_DATA) $(srcdir)/acc_user.h $(DESTDIR)$(includedir)/acc_user.h
|
||||
|
||||
$(includedir)/veriuser.h: $(srcdir)/veriuser.h
|
||||
$(INSTALL_DATA) $(srcdir)/veriuser.h $(includedir)/veriuser.h
|
||||
$(INSTALL_DATA) $(srcdir)/veriuser.h $(DESTDIR)$(includedir)/veriuser.h
|
||||
|
||||
$(mandir)/man1/iverilog-vpi.1: $(srcdir)/iverilog-vpi.man
|
||||
$(INSTALL_DATA) $(srcdir)/iverilog-vpi.man $(mandir)/man1/iverilog-vpi.1
|
||||
$(INSTALL_DATA) $(srcdir)/iverilog-vpi.man $(DESTDIR)$(mandir)/man1/iverilog-vpi.1
|
||||
|
||||
$(prefix)/iverilog-vpi.pdf: iverilog-vpi.pdf
|
||||
$(INSTALL_DATA) iverilog-vpi.pdf $(prefix)/iverilog-vpi.pdf
|
||||
$(INSTALL_DATA) iverilog-vpi.pdf $(DESTDIR)$(prefix)/iverilog-vpi.pdf
|
||||
|
||||
# In windows installations, put a few examples and the quick_start
|
||||
# into the destination directory.
|
||||
@@ -258,22 +279,22 @@ $(prefix)/QUICK_START.txt: $(srcdir)/QUICK_START.txt
|
||||
endif
|
||||
|
||||
installdirs: mkinstalldirs
|
||||
$(srcdir)/mkinstalldirs $(bindir) $(includedir) $(libdir)/ivl \
|
||||
$(libdir)/ivl/include $(mandir) $(mandir)/man1
|
||||
$(srcdir)/mkinstalldirs $(DESTDIR)$(bindir) $(DESTDIR)$(includedir) $(DESTDIR)$(libdir)/ivl \
|
||||
$(DESTDIR)$(libdir)/ivl/include $(DESTDIR)$(mandir) $(DESTDIR)$(mandir)/man1
|
||||
|
||||
uninstall:
|
||||
for dir in $(SUBDIRS); do (cd $$dir ; $(MAKE) $@); done
|
||||
for dir in vpi ivlpp driver; \
|
||||
do (cd $$dir ; $(MAKE) $@); done
|
||||
for f in xnf.conf xnf-s.conf ivl@EXEEXT@; \
|
||||
do rm -f $(libdir)/ivl/$$f; done
|
||||
-rmdir $(libdir)/ivl/include
|
||||
-rmdir $(libdir)/ivl
|
||||
for f in xnf.conf xnf-s.conf ivl@EXEEXT@ include/constants.vams; \
|
||||
do rm -f $(DESTDIR)$(libdir)/ivl/$$f; done
|
||||
-rmdir $(DESTDIR)$(libdir)/ivl/include
|
||||
-rmdir $(DESTDIR)$(libdir)/ivl
|
||||
for f in verilog iverilog-vpi gverilog@EXEEXT@; \
|
||||
do rm -f $(bindir)/$$f; done
|
||||
do rm -f $(DESTDIR)$(bindir)/$$f; done
|
||||
for f in ivl_target.h vpi_user.h _pli_types.h acc_user.h veriuser.h; \
|
||||
do rm -f $(includedir)/$$f; done
|
||||
rm -f $(mandir)/man1/iverilog-vpi.1 $(prefix)/iverilog-vpi.pdf
|
||||
do rm -f $(DESTDIR)$(includedir)/$$f; done
|
||||
rm -f $(DESTDIR)$(mandir)/man1/iverilog-vpi.1 $(DESTDIR)$(prefix)/iverilog-vpi.pdf
|
||||
|
||||
|
||||
-include $(patsubst %.o, dep/%.d, $O)
|
||||
|
||||
@@ -82,6 +82,8 @@ class Module : public PScope, public LineInfo {
|
||||
PExpr*expr;
|
||||
PExpr*msb;
|
||||
PExpr*lsb;
|
||||
perm_string file;
|
||||
unsigned lineno;
|
||||
bool signed_flag;
|
||||
};
|
||||
map<perm_string,param_expr_t>parameters;
|
||||
@@ -119,7 +121,7 @@ class Module : public PScope, public LineInfo {
|
||||
|
||||
/* The module has a list of genvars that may be used in
|
||||
various generate schemes. */
|
||||
list<perm_string> genvars;
|
||||
map<perm_string,LineInfo*> genvars;
|
||||
|
||||
/* the module has a list of generate schemes that appear in
|
||||
the module definition. These are used at elaboration time. */
|
||||
@@ -156,7 +158,8 @@ class Module : public PScope, public LineInfo {
|
||||
map<perm_string,PFunction*> funcs_;
|
||||
|
||||
static void elaborate_parm_item_(perm_string name, const param_expr_t&cur,
|
||||
Design*des, NetScope*scope);
|
||||
Design*des, NetScope*scope,
|
||||
perm_string file, unsigned lineno);
|
||||
|
||||
private: // Not implemented
|
||||
Module(const Module&);
|
||||
|
||||
@@ -43,7 +43,7 @@ bool PExpr::is_constant(Module*) const
|
||||
return false;
|
||||
}
|
||||
|
||||
NetNet* PExpr::elaborate_lnet(Design*des, NetScope*, bool) const
|
||||
NetNet* PExpr::elaborate_lnet(Design*des, NetScope*) const
|
||||
{
|
||||
cerr << get_fileline() << ": error: expression not valid in assign l-value: "
|
||||
<< *this << endl;
|
||||
@@ -191,7 +191,7 @@ PEIdent::~PEIdent()
|
||||
|
||||
/*
|
||||
* An identifier can be in a constant expression if (and only if) it is
|
||||
* a parameter.
|
||||
* a parameter or genvar.
|
||||
*
|
||||
* NOTE: This test does not work if the name is hierarchical!
|
||||
*/
|
||||
@@ -212,6 +212,11 @@ bool PEIdent::is_constant(Module*mod) const
|
||||
if (cur != mod->localparams.end()) return true;
|
||||
}
|
||||
|
||||
{ map<perm_string,LineInfo*>::const_iterator cur;
|
||||
cur = mod->genvars.find(tmp);
|
||||
if (cur != mod->genvars.end()) return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
@@ -74,6 +74,10 @@ class PExpr : public LineInfo {
|
||||
unsigned min, unsigned lval,
|
||||
bool&unsized_flag) const;
|
||||
|
||||
// During the elaborate_sig phase, we may need to scan
|
||||
// expressions to find implicit net declarations.
|
||||
virtual bool elaborate_sig(Design*des, NetScope*scope) const;
|
||||
|
||||
// Procedural elaboration of the expression. The expr_width is
|
||||
// the width of the context of the expression (i.e. the
|
||||
// l-value width of an assignment),
|
||||
@@ -107,8 +111,7 @@ class PExpr : public LineInfo {
|
||||
|
||||
// This method elaborates the expression as gates, but
|
||||
// restricted for use as l-values of continuous assignments.
|
||||
virtual NetNet* elaborate_lnet(Design*des, NetScope*scope,
|
||||
bool implicit_net_ok =false) const;
|
||||
virtual NetNet* elaborate_lnet(Design*des, NetScope*scope) const;
|
||||
|
||||
// This is similar to elaborate_lnet, except that the
|
||||
// expression is evaluated to be bi-directional. This is
|
||||
@@ -157,8 +160,8 @@ class PEConcat : public PExpr {
|
||||
virtual verinum* eval_const(Design*des, NetScope*sc) const;
|
||||
virtual void dump(ostream&) const;
|
||||
|
||||
virtual NetNet* elaborate_lnet(Design*des, NetScope*scope,
|
||||
bool implicit_net_ok =false) const;
|
||||
virtual bool elaborate_sig(Design*des, NetScope*scope) const;
|
||||
virtual NetNet* elaborate_lnet(Design*des, NetScope*scope) const;
|
||||
virtual NetNet* elaborate_bi_net(Design*des, NetScope*scope) const;
|
||||
virtual NetNet* elaborate_net(Design*des, NetScope*scope,
|
||||
unsigned width,
|
||||
@@ -177,7 +180,6 @@ class PEConcat : public PExpr {
|
||||
|
||||
private:
|
||||
NetNet* elaborate_lnet_common_(Design*des, NetScope*scope,
|
||||
bool implicit_net_ok,
|
||||
bool bidirectional_flag) const;
|
||||
private:
|
||||
svector<PExpr*>parms_;
|
||||
@@ -264,9 +266,10 @@ class PEIdent : public PExpr {
|
||||
unsigned min, unsigned lval,
|
||||
bool&unsized_flag) const;
|
||||
|
||||
virtual bool elaborate_sig(Design*des, NetScope*scope) const;
|
||||
|
||||
// Identifiers are allowed (with restrictions) is assign l-values.
|
||||
virtual NetNet* elaborate_lnet(Design*des, NetScope*scope,
|
||||
bool implicit_net_ok =false) const;
|
||||
virtual NetNet* elaborate_lnet(Design*des, NetScope*scope) const;
|
||||
|
||||
virtual NetNet* elaborate_bi_net(Design*des, NetScope*scope) const;
|
||||
|
||||
@@ -379,13 +382,12 @@ class PEIdent : public PExpr {
|
||||
|
||||
private:
|
||||
NetNet* elaborate_lnet_common_(Design*des, NetScope*scope,
|
||||
bool implicit_net_ok,
|
||||
bool bidirectional_flag) const;
|
||||
|
||||
NetNet*make_implicit_net_(Design*des, NetScope*scope) const;
|
||||
|
||||
bool eval_part_select_(Design*des, NetScope*scope, NetNet*sig,
|
||||
unsigned&midx, unsigned&lidx) const;
|
||||
long&midx, long&lidx) const;
|
||||
NetNet*process_select_(Design*des, NetScope*scope, NetNet*sig) const;
|
||||
|
||||
};
|
||||
@@ -472,6 +474,8 @@ class PEUnary : public PExpr {
|
||||
|
||||
virtual void dump(ostream&out) const;
|
||||
|
||||
virtual bool elaborate_sig(Design*des, NetScope*scope) const;
|
||||
|
||||
virtual NetNet* elaborate_net(Design*des, NetScope*scope,
|
||||
unsigned width,
|
||||
const NetExpr* rise,
|
||||
@@ -531,6 +535,8 @@ class PEBinary : public PExpr {
|
||||
unsigned min, unsigned lval,
|
||||
bool&unsized_flag) const;
|
||||
|
||||
virtual bool elaborate_sig(Design*des, NetScope*scope) const;
|
||||
|
||||
virtual NetNet* elaborate_net(Design*des, NetScope*scope,
|
||||
unsigned width,
|
||||
const NetExpr* rise,
|
||||
@@ -538,7 +544,7 @@ class PEBinary : public PExpr {
|
||||
const NetExpr* decay,
|
||||
Link::strength_t drive0,
|
||||
Link::strength_t drive1) const;
|
||||
virtual NetEBinary*elaborate_expr(Design*des, NetScope*,
|
||||
virtual NetExpr*elaborate_expr(Design*des, NetScope*,
|
||||
int expr_width, bool sys_task_arg) const;
|
||||
virtual NetExpr*elaborate_pexpr(Design*des, NetScope*sc) const;
|
||||
virtual verinum* eval_const(Design*des, NetScope*sc) const;
|
||||
@@ -548,8 +554,8 @@ class PEBinary : public PExpr {
|
||||
PExpr*left_;
|
||||
PExpr*right_;
|
||||
|
||||
NetEBinary*elaborate_expr_base_(Design*, NetExpr*lp, NetExpr*rp, int use_wid) const;
|
||||
NetEBinary*elaborate_eval_expr_base_(Design*, NetExpr*lp, NetExpr*rp, int use_wid) const;
|
||||
NetExpr*elaborate_expr_base_(Design*, NetExpr*lp, NetExpr*rp, int use_wid) const;
|
||||
NetExpr*elaborate_eval_expr_base_(Design*, NetExpr*lp, NetExpr*rp, int use_wid) const;
|
||||
|
||||
static void suppress_operand_sign_if_needed_(NetExpr*lp, NetExpr*rp);
|
||||
|
||||
@@ -615,8 +621,8 @@ class PEBComp : public PEBinary {
|
||||
unsigned min, unsigned lval,
|
||||
bool&flag) const;
|
||||
|
||||
NetEBinary* elaborate_expr(Design*des, NetScope*scope,
|
||||
int expr_width, bool sys_task_arg) const;
|
||||
NetExpr* elaborate_expr(Design*des, NetScope*scope,
|
||||
int expr_width, bool sys_task_arg) const;
|
||||
};
|
||||
|
||||
class PEBShift : public PEBinary {
|
||||
@@ -646,6 +652,8 @@ class PETernary : public PExpr {
|
||||
unsigned min, unsigned lval,
|
||||
bool&unsized_flag) const;
|
||||
|
||||
virtual bool elaborate_sig(Design*des, NetScope*scope) const;
|
||||
|
||||
virtual NetNet* elaborate_net(Design*des, NetScope*scope,
|
||||
unsigned width,
|
||||
const NetExpr* rise,
|
||||
|
||||
@@ -129,6 +129,7 @@ class PGAssign : public PGate {
|
||||
|
||||
void dump(ostream&out, unsigned ind =4) const;
|
||||
virtual void elaborate(Design*des, NetScope*scope) const;
|
||||
virtual bool elaborate_sig(Design*des, NetScope*scope) const;
|
||||
|
||||
private:
|
||||
};
|
||||
@@ -166,6 +167,7 @@ class PGBuiltin : public PGate {
|
||||
|
||||
virtual void dump(ostream&out, unsigned ind =4) const;
|
||||
virtual void elaborate(Design*, NetScope*scope) const;
|
||||
virtual bool elaborate_sig(Design*des, NetScope*scope) const;
|
||||
|
||||
private:
|
||||
Type type_;
|
||||
@@ -234,6 +236,7 @@ class PGModule : public PGate {
|
||||
void elaborate_udp_(Design*, PUdp *udp, NetScope*scope) const;
|
||||
void elaborate_scope_mod_(Design*des, Module*mod, NetScope*sc) const;
|
||||
bool elaborate_sig_mod_(Design*des, NetScope*scope, Module*mod) const;
|
||||
bool elaborate_sig_udp_(Design*des, NetScope*scope, PUdp*udp) const;
|
||||
|
||||
NetNet*resize_net_to_port_(Design*des, NetScope*scope,
|
||||
NetNet*sig, unsigned port_wid,
|
||||
|
||||
+3
-93
@@ -1,7 +1,7 @@
|
||||
#ifndef __Statement_H
|
||||
#define __Statement_H
|
||||
/*
|
||||
* Copyright (c) 1998-2000 Stephen Williams ([email protected])
|
||||
* Copyright (c) 1998-2008 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,9 +18,6 @@
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
|
||||
*/
|
||||
#ifdef HAVE_CVS_IDENT
|
||||
#ident "$Id: Statement.h,v 1.44 2007/05/24 04:07:11 steve Exp $"
|
||||
#endif
|
||||
|
||||
# include <string>
|
||||
# include "svector.h"
|
||||
@@ -417,6 +414,7 @@ class PRepeat : public Statement {
|
||||
|
||||
virtual NetProc* elaborate(Design*des, NetScope*scope) const;
|
||||
virtual void elaborate_scope(Design*des, NetScope*scope) const;
|
||||
virtual void elaborate_sig(Design*des, NetScope*scope) const;
|
||||
virtual void dump(ostream&out, unsigned ind) const;
|
||||
|
||||
private:
|
||||
@@ -462,6 +460,7 @@ class PWhile : public Statement {
|
||||
|
||||
virtual NetProc* elaborate(Design*des, NetScope*scope) const;
|
||||
virtual void elaborate_scope(Design*des, NetScope*scope) const;
|
||||
virtual void elaborate_sig(Design*des, NetScope*scope) const;
|
||||
virtual void dump(ostream&out, unsigned ind) const;
|
||||
|
||||
private:
|
||||
@@ -469,93 +468,4 @@ class PWhile : public Statement {
|
||||
Statement*statement_;
|
||||
};
|
||||
|
||||
/*
|
||||
* $Log: Statement.h,v $
|
||||
* Revision 1.44 2007/05/24 04:07:11 steve
|
||||
* Rework the heirarchical identifier parse syntax and pform
|
||||
* to handle more general combinations of heirarch and bit selects.
|
||||
*
|
||||
* Revision 1.43 2007/03/05 05:59:10 steve
|
||||
* Handle processes within generate loops.
|
||||
*
|
||||
* Revision 1.42 2005/12/05 21:21:18 steve
|
||||
* Fixes for stubborn compilers.
|
||||
*
|
||||
* Revision 1.41 2004/12/11 02:31:25 steve
|
||||
* Rework of internals to carry vectors through nexus instead
|
||||
* of single bits. Make the ivl, tgt-vvp and vvp initial changes
|
||||
* down this path.
|
||||
*
|
||||
* Revision 1.40 2004/02/20 18:53:33 steve
|
||||
* Addtrbute keys are perm_strings.
|
||||
*
|
||||
* Revision 1.39 2004/02/18 17:11:54 steve
|
||||
* Use perm_strings for named langiage items.
|
||||
*
|
||||
* Revision 1.38 2003/05/19 02:50:58 steve
|
||||
* Implement the wait statement behaviorally instead of as nets.
|
||||
*
|
||||
* Revision 1.37 2003/01/30 16:23:07 steve
|
||||
* Spelling fixes.
|
||||
*
|
||||
* Revision 1.36 2002/08/12 01:34:58 steve
|
||||
* conditional ident string using autoconfig.
|
||||
*
|
||||
* Revision 1.35 2002/06/04 05:38:44 steve
|
||||
* Add support for memory words in l-value of
|
||||
* blocking assignments, and remove the special
|
||||
* NetAssignMem class.
|
||||
*
|
||||
* Revision 1.34 2002/05/26 01:39:02 steve
|
||||
* Carry Verilog 2001 attributes with processes,
|
||||
* all the way through to the ivl_target API.
|
||||
*
|
||||
* Divide signal reference counts between rval
|
||||
* and lval references.
|
||||
*
|
||||
* Revision 1.33 2002/04/21 22:31:02 steve
|
||||
* Redo handling of assignment internal delays.
|
||||
* Leave it possible for them to be calculated
|
||||
* at run time.
|
||||
*
|
||||
* Revision 1.32 2002/04/21 04:59:07 steve
|
||||
* Add support for conbinational events by finding
|
||||
* the inputs to expressions and some statements.
|
||||
* Get case and assignment statements working.
|
||||
*
|
||||
* Revision 1.31 2001/12/03 04:47:14 steve
|
||||
* Parser and pform use hierarchical names as hname_t
|
||||
* objects instead of encoded strings.
|
||||
*
|
||||
* Revision 1.30 2001/11/22 06:20:59 steve
|
||||
* Use NetScope instead of string for scope path.
|
||||
*
|
||||
* Revision 1.29 2000/09/09 15:21:26 steve
|
||||
* move lval elaboration to PExpr virtual methods.
|
||||
*
|
||||
* Revision 1.28 2000/09/03 17:58:35 steve
|
||||
* Change elaborate_lval to return NetAssign_ objects.
|
||||
*
|
||||
* Revision 1.27 2000/07/26 05:08:07 steve
|
||||
* Parse disable statements to pform.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
#endif
|
||||
|
||||
+24
-5
@@ -1,7 +1,7 @@
|
||||
#ifndef __compiler_H
|
||||
#define __compiler_H
|
||||
/*
|
||||
* Copyright (c) 1999-2007 Stephen Williams ([email protected])
|
||||
* Copyright (c) 1999-2008 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
|
||||
@@ -76,6 +76,9 @@ extern bool warn_timescale;
|
||||
/* Warn about legal but questionable module port bindings. */
|
||||
extern bool warn_portbinding;
|
||||
|
||||
/* Warn about structures that may have infinite loops. */
|
||||
extern bool warn_inf_loop;
|
||||
|
||||
/* This is true if verbose output is requested. */
|
||||
extern bool verbose_flag;
|
||||
|
||||
@@ -97,26 +100,42 @@ extern int build_library_index(const char*path, bool key_case_sensitive);
|
||||
enum generation_t {
|
||||
GN_VER1995 = 1,
|
||||
GN_VER2001 = 2,
|
||||
GN_VER2001X = 3,
|
||||
GN_VER2005 = 3,
|
||||
GN_DEFAULT = 3
|
||||
};
|
||||
|
||||
extern generation_t generation_flag;
|
||||
|
||||
/* If this flag is true, enable extended types support. */
|
||||
extern bool gn_cadence_types_flag;
|
||||
|
||||
/* These functions test that specific features are enabled. */
|
||||
inline bool gn_cadence_types_enabled()
|
||||
{ return gn_cadence_types_flag && generation_flag==GN_VER2001X; }
|
||||
/* If this flag is true, enable miscellaneous extensions. */
|
||||
extern bool gn_icarus_misc_flag;
|
||||
|
||||
/* If this flag is true, then elaborate specify blocks. If this flag
|
||||
is false, then skip elaboration of specify behavior. */
|
||||
extern bool gn_specify_blocks_flag;
|
||||
|
||||
/* If this flag is true, then support/elaborate Verilog-AMS. */
|
||||
extern bool gn_verilog_ams_flag;
|
||||
|
||||
/* If this flag is false a warning is printed when the port declaration
|
||||
is scalar and the net/register definition is vectored. */
|
||||
extern bool gn_io_range_error_flag;
|
||||
|
||||
/* The bits of these GN_KEYWORDS_* constants define non-intersecting
|
||||
sets of keywords. The compiler enables groups of keywords by setting
|
||||
lexor_keyword_mask with the OR of the bits for the keywords to be
|
||||
enabled. */
|
||||
enum { GN_KEYWORDS_1364_1995 = 0x0001,
|
||||
GN_KEYWORDS_1364_2001 = 0x0002,
|
||||
GN_KEYWORDS_1364_2001_CONFIG = 0x0004,
|
||||
GN_KEYWORDS_1364_2005 = 0x0008,
|
||||
GN_KEYWORDS_VAMS_2_3 = 0x0010,
|
||||
GN_KEYWORDS_ICARUS = 0x8000
|
||||
};
|
||||
extern int lexor_keyword_mask;
|
||||
|
||||
/* This is the string to use to invoke the preprocessor. */
|
||||
extern char*ivlpp_string;
|
||||
|
||||
|
||||
@@ -0,0 +1,43 @@
|
||||
// Mathematical and physical constants
|
||||
|
||||
`ifdef CONSTANTS_VAMS
|
||||
`else
|
||||
`define CONSTANTS_VAMS 1
|
||||
|
||||
// M_ is a mathematical constant
|
||||
`define M_E 2.7182818284590452354
|
||||
`define M_LOG2E 1.4426950408889634074
|
||||
`define M_LOG10E 0.43429448190325182765
|
||||
`define M_LN2 0.69314718055994530942
|
||||
`define M_LN10 2.30258509299404568402
|
||||
`define M_PI 3.14159265358979323846
|
||||
`define M_TWO_PI 6.28318530717958647693
|
||||
`define M_PI_2 1.57079632679489661923
|
||||
`define M_PI_4 0.78539816339744830962
|
||||
`define M_1_PI 0.31830988618379067154
|
||||
`define M_2_PI 0.63661977236758134308
|
||||
`define M_2_SQRTPI 1.12837916709551257390
|
||||
`define M_SQRT2 1.41421356237309504880
|
||||
`define M_SQRT1_2 0.70710678118654752440
|
||||
|
||||
/*
|
||||
* Do we need these? For now they are not available.
|
||||
*
|
||||
// The following constants have been taken from http://physics.nist.gov
|
||||
// P_ is a physical constant
|
||||
// charge of electron in coulombs
|
||||
`define P_Q 1.602176462e-19
|
||||
// speed of light in vacuum in meters/sec
|
||||
`define P_C 2.99792458e8
|
||||
// Boltzmann's constant in joules/kelvin
|
||||
`define P_K 1.3806503e-23
|
||||
// Planck's constant in joules*sec
|
||||
`define P_H 6.62606876e-34
|
||||
// permittivity of vacuum in farads/meter
|
||||
`define P_EPS0 8.854187817e-12
|
||||
// permeability of vacuum in henrys/meter
|
||||
`define P_U0 (4.0e-7 * `M_PI)
|
||||
// zero celsius in kelvin
|
||||
`define P_CELSIUS0 273.15
|
||||
*/
|
||||
`endif
|
||||
+59
-3
@@ -112,6 +112,10 @@ void NetDelaySrc::dump(ostream&o, unsigned ind) const
|
||||
o << setw(ind) << "" << "specify delay";
|
||||
if (posedge_) o << " posedge";
|
||||
if (negedge_) o << " negedge";
|
||||
if (is_condit()) {
|
||||
if (has_condit()) o << " if";
|
||||
else o << " ifnone";
|
||||
}
|
||||
o << " src "
|
||||
<< "(" << transition_delays_[IVL_PE_01]
|
||||
<< "," << transition_delays_[IVL_PE_10]
|
||||
@@ -243,6 +247,15 @@ void NetObj::dump_obj_attr(ostream&o, unsigned ind) const
|
||||
}
|
||||
}
|
||||
|
||||
void NetAbs::dump_node(ostream&o, unsigned ind) const
|
||||
{
|
||||
o << setw(ind) << "" << "Absolute value (NetAbs): " << name()
|
||||
<< " width=" << width() << " pin_count=" << pin_count()
|
||||
<< endl;
|
||||
dump_node_pins(o, ind+4);
|
||||
dump_obj_attr(o, ind+4);
|
||||
}
|
||||
|
||||
void NetAddSub::dump_node(ostream&o, unsigned ind) const
|
||||
{
|
||||
o << setw(ind) << "" << "Adder (NetAddSub): " << name()
|
||||
@@ -840,9 +853,35 @@ void NetForever::dump(ostream&o, unsigned ind) const
|
||||
void NetFuncDef::dump(ostream&o, unsigned ind) const
|
||||
{
|
||||
o << setw(ind) << "" << "function definition for " << scope_path(scope_) << endl;
|
||||
if (result_sig_)
|
||||
o << setw(ind+2) << "" << "Return signal: "
|
||||
<< result_sig_->name() << endl;
|
||||
if (result_sig_) {
|
||||
o << setw(ind+2) << "" << "Return signal: ";
|
||||
if (result_sig_->get_signed()) o << "+";
|
||||
o << result_sig_->name() << "[" << result_sig_->msb() << ":"
|
||||
<< result_sig_->lsb() << "]" << endl;
|
||||
}
|
||||
o << setw(ind+2) << "" << "Arguments: ";
|
||||
if (port_count() == 0) o << "<none>";
|
||||
o << endl;
|
||||
for (unsigned idx = 0; idx < port_count(); idx += 1) {
|
||||
o << setw(ind+4) << "" << "Arg[" << idx+1 << "] = ";
|
||||
switch (port(idx)->port_type()) {
|
||||
default:
|
||||
o << "implicit-port? ";
|
||||
break;
|
||||
case NetNet::PINPUT:
|
||||
o << "input ";
|
||||
break;
|
||||
case NetNet::POUTPUT:
|
||||
o << "output ";
|
||||
break;
|
||||
case NetNet::PINOUT:
|
||||
o << "inout ";
|
||||
break;
|
||||
}
|
||||
if (port(idx)->get_signed()) o << "+";
|
||||
o << port(idx)->name() << "[" << port(idx)->msb() << ":"
|
||||
<< port(idx)->lsb() << "]" << endl;
|
||||
}
|
||||
if (statement_)
|
||||
statement_->dump(o, ind+2);
|
||||
else
|
||||
@@ -1052,6 +1091,20 @@ void NetExpr::dump(ostream&o) const
|
||||
|
||||
void NetEBinary::dump(ostream&o) const
|
||||
{
|
||||
if (op_ == 'm' || op_ == 'M') {
|
||||
if (op_ == 'm')
|
||||
o << "min";
|
||||
else
|
||||
o << "max";
|
||||
|
||||
o << "(";
|
||||
left_->dump(o);
|
||||
o << ", ";
|
||||
right_->dump(o);
|
||||
o << ")";
|
||||
return;
|
||||
}
|
||||
|
||||
o << "(";
|
||||
left_->dump(o);
|
||||
o << ")";
|
||||
@@ -1237,6 +1290,9 @@ void NetEUFunc::dump(ostream&o) const
|
||||
void NetEUnary::dump(ostream&o) const
|
||||
{
|
||||
switch (op_) {
|
||||
case 'm':
|
||||
o << "abs";
|
||||
break;
|
||||
case 'N':
|
||||
o << "~|";
|
||||
break;
|
||||
|
||||
+2
-2
@@ -21,7 +21,7 @@
|
||||
#
|
||||
SHELL = /bin/sh
|
||||
|
||||
VERSION = 0.8
|
||||
VERSION = 0.9.devel
|
||||
|
||||
prefix = @prefix@
|
||||
exec_prefix = @exec_prefix@
|
||||
@@ -68,7 +68,7 @@ cfparse.h cfparse.c: cfparse.y
|
||||
bison --verbose -t -d -o cfparse.c --name-prefix=cf $(srcdir)/cfparse.y
|
||||
|
||||
|
||||
main.o: main.c globals.h
|
||||
main.o: main.c globals.h ../version.h
|
||||
$(CC) $(CPPFLAGS) $(CFLAGS) -c -DIVL_ROOT='"@libdir@/ivl"' -DIVL_INC='"@includedir@"' -DIVL_LIB='"@libdir@"' -DDLLIB='"@DLLIB@"' $(srcdir)/main.c
|
||||
|
||||
build_string.o: build_string.c globals.h
|
||||
|
||||
+29
-6
@@ -1,11 +1,11 @@
|
||||
.TH iverilog 1 "$Date: 2007/06/05 01:56:12 $" Version "$Date: 2007/06/05 01:56:12 $"
|
||||
.TH iverilog 1 "April 22nd, 2008" Version "0.9.devel"
|
||||
.SH NAME
|
||||
iverilog - Icarus Verilog compiler
|
||||
|
||||
.SH SYNOPSIS
|
||||
.B iverilog
|
||||
[-ESVv] [-Bpath] [-ccmdfile|-fcmdfile] [-Dmacro[=defn]] [-pflag=value]
|
||||
[-dname] [-g1|-g2|-g2x|-gspecify|-gxtypes|-gio-range-error]
|
||||
[-dname] [-g1995|-g2001|-g2005|-g<feature>]
|
||||
[-Iincludedir] [-mmodule] [-Mfile] [-Nfile] [-ooutputfilename]
|
||||
[-stopmodule] [-ttype] [-Tmin/typ/max] [-Wclass] [-ypath] sourcefile
|
||||
|
||||
@@ -55,15 +55,18 @@ 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 -g1\fI|\fP-g2\fI|\fP-g2x
|
||||
.B -g1995\fI|\fP-g2001\fI|\fP-g2005
|
||||
Select the Verilog language \fIgeneration\fP to support in the
|
||||
compiler. This selects between \fIIEEE1364-1995\fP(1),
|
||||
\fIIEEE1364-2001\fP(2), or \fIVerilog with extension\fP(2x). Normally,
|
||||
compiler. This selects between \fIIEEE1364-1995\fP,
|
||||
\fIIEEE1364-2001\fP(2), or \fIIEEE1364-2005\fP. Normally,
|
||||
Icarus Verilog defaults to the latest known generation of the
|
||||
language. This flag is most useful to restrict the language to a set
|
||||
supported by tools of specific generations, for compatibility with
|
||||
other tools.
|
||||
.TP 8
|
||||
.B -gverilog-ams\fI|-fP-gno-verilog-ams
|
||||
Enable or disable (default) support for Verilog-AMS.
|
||||
.TP 8
|
||||
.B -gspecify\fI|\fP-gno-specify
|
||||
Enable (default) or disable specify block support. When enabled,
|
||||
specify block code is elaborated. When disabled, specify blocks are
|
||||
@@ -251,6 +254,21 @@ inherit timescale from another file. Both probably mean that
|
||||
timescales are inconsistent, and simulation timing can be confusing
|
||||
and dependent on compilation order.
|
||||
|
||||
.TP 8
|
||||
.B infloop
|
||||
This enables warnings for \fRalways\fP statements that may have runtime
|
||||
infinite loops (has paths with no or zero delay). This class of warnings
|
||||
is not included in \fB-Wall\fP and hence does not have a \fBno-\fP variant.
|
||||
A fatal error message will always be printed when the compiler can
|
||||
determine that there will definitely be an infinite loop (all paths have
|
||||
no or zero delay).
|
||||
|
||||
When you suspect an always statement is producing a runtime infinite loop
|
||||
use this flag to find the always statements that need to have their logic
|
||||
verified. It is expected that many of the warnings will be false
|
||||
positives, since the code treats the value of all variables and signals
|
||||
as indeterminate.
|
||||
|
||||
.SH "SYSTEM FUNCTION TABLE FILES"
|
||||
If the source file name as a \fB.sft\fP suffix, then it is taken to be
|
||||
a system function table file. A System function table file is used to
|
||||
@@ -369,9 +387,14 @@ from preprocessor defines elsewhere in the file or the command line.
|
||||
|
||||
.SH PREDEFINED MACROS
|
||||
|
||||
The following macro is predefined by the compiler:
|
||||
The following macros are predefined by the compiler:
|
||||
.TP 8
|
||||
.B __ICARUS__ = 1\fP
|
||||
This is defined always when compiling with Icarus Verilog.
|
||||
|
||||
.TP 8
|
||||
.B __VAMS_ENABLE__ = 1\fp
|
||||
This is defined if Verilog-AMS is enabled.
|
||||
|
||||
.SH EXAMPLES
|
||||
These examples assume that you have a Verilog source file called hello.v in
|
||||
|
||||
+65
-15
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2000-2007 Stephen Williams ([email protected])
|
||||
* Copyright (c) 2000-2008 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,6 +18,7 @@
|
||||
*/
|
||||
|
||||
# include "config.h"
|
||||
# include "version.h"
|
||||
|
||||
const char NOTICE[] =
|
||||
" This program is free software; you can redistribute it and/or modify\n"
|
||||
@@ -108,7 +109,9 @@ const char*depfile = 0;
|
||||
const char*generation = "2x";
|
||||
const char*gen_specify = "specify";
|
||||
const char*gen_xtypes = "xtypes";
|
||||
const char*gen_icarus = "icarus-misc";
|
||||
const char*gen_io_range_error = "io-range-error";
|
||||
const char*gen_verilog_ams = "no-verilog-ams";
|
||||
|
||||
/* Boolean: true means use a default include dir, false means don't */
|
||||
int gen_std_include = 1;
|
||||
@@ -357,6 +360,11 @@ static void process_warning_switch(const char*name)
|
||||
} else if (strcmp(name,"timescale") == 0) {
|
||||
if (! strchr(warning_flags, 't'))
|
||||
strcat(warning_flags, "t");
|
||||
/* Since the infinite loop check is not part of 'all' it
|
||||
* does not have a no- version. */
|
||||
} else if (strcmp(name,"infloop") == 0) {
|
||||
if (! strchr(warning_flags, 'l'))
|
||||
strcat(warning_flags, "l");
|
||||
} else if (strcmp(name,"no-implicit") == 0) {
|
||||
char*cp = strchr(warning_flags, 'i');
|
||||
if (cp) while (*cp) {
|
||||
@@ -424,21 +432,42 @@ void process_file_name(const char*name, int lib_flag)
|
||||
|
||||
int process_generation(const char*name)
|
||||
{
|
||||
if (strcmp(name,"1") == 0)
|
||||
generation = "1";
|
||||
if (strcmp(name,"1995") == 0)
|
||||
generation = "1995";
|
||||
|
||||
else if (strcmp(name,"2") == 0)
|
||||
generation = "2";
|
||||
else if (strcmp(name,"2001") == 0)
|
||||
generation = "2001";
|
||||
|
||||
else if (strcmp(name,"2x") == 0)
|
||||
generation = "2x";
|
||||
else if (strcmp(name,"2005") == 0)
|
||||
generation = "2005";
|
||||
|
||||
else if (strcmp(name,"xtypes") == 0)
|
||||
else if (strcmp(name,"1") == 0) { /* Deprecated: use 1995 */
|
||||
generation = "1995";
|
||||
gen_xtypes = "no-xtypes";
|
||||
gen_icarus = "no-icarus-misc";
|
||||
|
||||
} else if (strcmp(name,"2") == 0) { /* Deprecated: use 2001 */
|
||||
generation = "2001";
|
||||
gen_xtypes = "no-xtypes";
|
||||
gen_icarus = "no-icarus-misc";
|
||||
|
||||
} else if (strcmp(name,"2x") == 0) { /* Deprecated: use 2005/xtypes */
|
||||
generation = "2005";
|
||||
gen_xtypes = "xtypes";
|
||||
gen_icarus = "icarus-misc";
|
||||
|
||||
} else if (strcmp(name,"xtypes") == 0)
|
||||
gen_xtypes = "xtypes";
|
||||
|
||||
else if (strcmp(name,"no-xtypes") == 0)
|
||||
gen_xtypes = "no-xtypes";
|
||||
|
||||
else if (strcmp(name,"icarus-misc") == 0)
|
||||
gen_icarus = "icarus-misc";
|
||||
|
||||
else if (strcmp(name,"no-icarus-misc") == 0)
|
||||
gen_icarus = "no-icarus-misc";
|
||||
|
||||
else if (strcmp(name,"specify") == 0)
|
||||
gen_specify = "specify";
|
||||
|
||||
@@ -457,17 +486,25 @@ int process_generation(const char*name)
|
||||
else if (strcmp(name,"no-io-range-error") == 0)
|
||||
gen_io_range_error = "no-io-range-error";
|
||||
|
||||
else if (strcmp(name,"verilog-ams") == 0)
|
||||
gen_verilog_ams = "verilog-ams";
|
||||
|
||||
else if (strcmp(name,"no-verilog-ams") == 0)
|
||||
gen_verilog_ams = "no-verilog-ams";
|
||||
|
||||
else {
|
||||
fprintf(stderr, "Unknown/Unsupported Language generation "
|
||||
"%s\n\n", name);
|
||||
fprintf(stderr, "Supported generations are:\n");
|
||||
fprintf(stderr, " 1 -- IEEE1364-1995 (Verilog 1)\n"
|
||||
" 2 -- IEEE1364-2001 (Verilog 2001)\n"
|
||||
" 2x -- Verilog with extensions\n"
|
||||
fprintf(stderr, " 1995 -- IEEE1364-1995\n"
|
||||
" 2001 -- IEEE1364-2001\n"
|
||||
" 2005 -- IEEE1364-2005\n"
|
||||
"Other generation flags:\n"
|
||||
" specify | no-specify\n"
|
||||
" verilog-ams | no-verinlog-ams\n"
|
||||
" std-include | no-std-include\n"
|
||||
" xtypes | no-xtypes\n"
|
||||
" icarus-misc | no-icarus-misc\n"
|
||||
" io-range-error | no-io-range-error\n");
|
||||
return 1;
|
||||
}
|
||||
@@ -557,6 +594,8 @@ int main(int argc, char **argv)
|
||||
}
|
||||
|
||||
fprintf(defines_file, "D:__ICARUS__=1\n");
|
||||
if (strcmp(gen_verilog_ams,"verilog-ams") == 0)
|
||||
fprintf(defines_file, "D:__VAMS_ENABLE__=1\n");
|
||||
|
||||
/* Create another temporary file for passing configuration
|
||||
information to ivl. */
|
||||
@@ -701,8 +740,8 @@ int main(int argc, char **argv)
|
||||
pbase = base;
|
||||
|
||||
if (version_flag || verbose_flag) {
|
||||
printf("Icarus Verilog version " VERSION " ($Name: $)\n\n");
|
||||
printf("Copyright 1998-2007 Stephen Williams\n");
|
||||
printf("Icarus Verilog version " VERSION " (" VERSION_TAG ")\n\n");
|
||||
printf("Copyright 1998-2008 Stephen Williams\n");
|
||||
puts(NOTICE);
|
||||
|
||||
if (version_flag)
|
||||
@@ -721,11 +760,20 @@ int main(int argc, char **argv)
|
||||
how to handle them. */
|
||||
fprintf(iconfig_file, "sys_func:%s%csystem.sft\n", base, sep);
|
||||
|
||||
/* If verilog-ams is enabled, then include the va_math module
|
||||
as well. */
|
||||
if (strcmp(gen_verilog_ams,"verilog-ams") == 0) {
|
||||
fprintf(iconfig_file, "sys_func:%s%cva_math.sft\n", base, sep);
|
||||
fprintf(iconfig_file, "module:va_math\n");
|
||||
}
|
||||
|
||||
if (mtm != 0) fprintf(iconfig_file, "-T:%s\n", mtm);
|
||||
fprintf(iconfig_file, "generation:%s\n", generation);
|
||||
fprintf(iconfig_file, "generation:%s\n", gen_specify);
|
||||
fprintf(iconfig_file, "generation:%s\n", gen_xtypes);
|
||||
fprintf(iconfig_file, "generation:%s\n", gen_io_range_error);
|
||||
fprintf(iconfig_file, "generation:%s\n", gen_verilog_ams);
|
||||
fprintf(iconfig_file, "generation:%s\n", gen_icarus);
|
||||
fprintf(iconfig_file, "warnings:%s\n", warning_flags);
|
||||
fprintf(iconfig_file, "out:%s\n", opath);
|
||||
if (depfile) fprintf(iconfig_file, "depfile:%s\n", depfile);
|
||||
@@ -806,8 +854,11 @@ int main(int argc, char **argv)
|
||||
rc = system(cmd);
|
||||
remove(source_path);
|
||||
fclose(iconfig_file);
|
||||
if ( ! getenv("IVERILOG_ICONFIG"))
|
||||
if ( ! getenv("IVERILOG_ICONFIG")) {
|
||||
remove(iconfig_path);
|
||||
remove(defines_path);
|
||||
remove(compiled_defines_path);
|
||||
}
|
||||
|
||||
if (rc != 0) {
|
||||
if (WIFEXITED(rc)) {
|
||||
@@ -837,4 +888,3 @@ int main(int argc, char **argv)
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
+135
-25
@@ -96,7 +96,7 @@ unsigned PEBinary::test_width(Design*des, NetScope*scope,
|
||||
* and right sides, and creating one of a variety of different NetExpr
|
||||
* types.
|
||||
*/
|
||||
NetEBinary* PEBinary::elaborate_expr(Design*des, NetScope*scope,
|
||||
NetExpr* PEBinary::elaborate_expr(Design*des, NetScope*scope,
|
||||
int expr_wid, bool) const
|
||||
{
|
||||
assert(left_);
|
||||
@@ -110,7 +110,7 @@ NetEBinary* PEBinary::elaborate_expr(Design*des, NetScope*scope,
|
||||
return 0;
|
||||
}
|
||||
|
||||
NetEBinary*tmp = elaborate_eval_expr_base_(des, lp, rp, expr_wid);
|
||||
NetExpr*tmp = elaborate_eval_expr_base_(des, lp, rp, expr_wid);
|
||||
return tmp;
|
||||
}
|
||||
|
||||
@@ -128,7 +128,7 @@ void PEBinary::suppress_operand_sign_if_needed_(NetExpr*lp, NetExpr*rp)
|
||||
lp->cast_signed(false);
|
||||
}
|
||||
|
||||
NetEBinary* PEBinary::elaborate_eval_expr_base_(Design*des,
|
||||
NetExpr* PEBinary::elaborate_eval_expr_base_(Design*des,
|
||||
NetExpr*lp,
|
||||
NetExpr*rp,
|
||||
int expr_wid) const
|
||||
@@ -146,7 +146,7 @@ NetEBinary* PEBinary::elaborate_eval_expr_base_(Design*des,
|
||||
* 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* PEBinary::elaborate_expr_base_(Design*des,
|
||||
NetExpr*lp, NetExpr*rp,
|
||||
int expr_wid) const
|
||||
{
|
||||
@@ -157,7 +157,7 @@ NetEBinary* PEBinary::elaborate_expr_base_(Design*des,
|
||||
<< *this << " expr_wid=" << expr_wid << endl;
|
||||
}
|
||||
|
||||
NetEBinary*tmp;
|
||||
NetExpr*tmp;
|
||||
|
||||
switch (op_) {
|
||||
default:
|
||||
@@ -167,6 +167,8 @@ NetEBinary* PEBinary::elaborate_expr_base_(Design*des,
|
||||
|
||||
case 'a':
|
||||
case 'o':
|
||||
lp = condition_reduce(lp);
|
||||
rp = condition_reduce(rp);
|
||||
tmp = new NetEBLogic(op_, lp, rp);
|
||||
tmp->set_line(*this);
|
||||
break;
|
||||
@@ -185,7 +187,7 @@ NetEBinary* PEBinary::elaborate_expr_base_(Design*des,
|
||||
/* The % operator does not support real arguments in
|
||||
baseline Verilog. But we allow it in our extended
|
||||
form of Verilog. */
|
||||
if (generation_flag < GN_VER2001X) {
|
||||
if (! gn_icarus_misc_flag) {
|
||||
if (lp->expr_type()==IVL_VT_REAL ||
|
||||
rp->expr_type()==IVL_VT_REAL) {
|
||||
cerr << get_fileline() << ": error: Modulus operator "
|
||||
@@ -200,6 +202,56 @@ NetEBinary* PEBinary::elaborate_expr_base_(Design*des,
|
||||
break;
|
||||
|
||||
case 'l': // <<
|
||||
if (NetEConst*lpc = dynamic_cast<NetEConst*> (lp)) {
|
||||
if (NetEConst*rpc = dynamic_cast<NetEConst*> (rp)) {
|
||||
// Handle the super-special case that both
|
||||
// operands are constants. Precalculate the
|
||||
// entire value here.
|
||||
verinum lpval = lpc->value();
|
||||
unsigned shift = rpc->value().as_ulong();
|
||||
verinum result = lpc->value() << shift;
|
||||
// If the l-value has explicit size, or
|
||||
// there is a context determined size, use that.
|
||||
if (lpval.has_len() || expr_wid > 0) {
|
||||
int use_len = lpval.len();
|
||||
if (expr_wid < use_len)
|
||||
use_len = expr_wid;
|
||||
result = verinum(result, lpval.len());
|
||||
}
|
||||
|
||||
tmp = new NetEConst(result);
|
||||
if (debug_elaborate)
|
||||
cerr << get_fileline() << ": debug: "
|
||||
<< "Precalculate " << *this
|
||||
<< " to constant " << *tmp << endl;
|
||||
|
||||
} else {
|
||||
// Handle the special case that the left
|
||||
// operand is constant. If it is unsized, we
|
||||
// may have to expand it to an integer width.
|
||||
verinum lpval = lpc->value();
|
||||
if (lpval.len() < integer_width && !lpval.has_len()) {
|
||||
lpval = verinum(lpval, integer_width);
|
||||
lpc = new NetEConst(lpval);
|
||||
lpc->set_line(*lp);
|
||||
}
|
||||
|
||||
tmp = new NetEBShift(op_, lpc, rp);
|
||||
if (debug_elaborate)
|
||||
cerr << get_fileline() << ": debug: "
|
||||
<< "Adjust " << *this
|
||||
<< " to this " << *tmp
|
||||
<< " to allow for integer widths." << endl;
|
||||
}
|
||||
|
||||
} else {
|
||||
// Left side is not constant, so handle it the
|
||||
// default way.
|
||||
tmp = new NetEBShift(op_, lp, rp);
|
||||
}
|
||||
tmp->set_line(*this);
|
||||
break;
|
||||
|
||||
case 'r': // >>
|
||||
case 'R': // >>>
|
||||
tmp = new NetEBShift(op_, lp, rp);
|
||||
@@ -259,6 +311,12 @@ NetEBinary* PEBinary::elaborate_expr_base_(Design*des,
|
||||
des->errors += 1;
|
||||
}
|
||||
break;
|
||||
|
||||
case 'm': // min(l,r)
|
||||
case 'M': // max(l,r)
|
||||
tmp = new NetEBMinMax(op_, lp, rp);
|
||||
tmp->set_line(*this);
|
||||
break;
|
||||
}
|
||||
|
||||
return tmp;
|
||||
@@ -269,8 +327,8 @@ unsigned PEBComp::test_width(Design*, NetScope*,unsigned, unsigned, bool&) const
|
||||
return 1;
|
||||
}
|
||||
|
||||
NetEBinary* PEBComp::elaborate_expr(Design*des, NetScope*scope,
|
||||
int expr_width, bool sys_task_arg) const
|
||||
NetExpr* PEBComp::elaborate_expr(Design*des, NetScope*scope,
|
||||
int expr_width, bool sys_task_arg) const
|
||||
{
|
||||
assert(left_);
|
||||
assert(right_);
|
||||
@@ -628,10 +686,13 @@ NetExpr* PECallFunction::elaborate_expr(Design*des, NetScope*scope,
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Keep track of the concatenation/repeat depth.
|
||||
static int concat_depth = 0;
|
||||
|
||||
NetExpr* PEConcat::elaborate_expr(Design*des, NetScope*scope,
|
||||
int expr_wid, bool) const
|
||||
{
|
||||
concat_depth += 1;
|
||||
NetExpr* repeat = 0;
|
||||
|
||||
if (debug_elaborate) {
|
||||
@@ -655,6 +716,23 @@ NetExpr* PEConcat::elaborate_expr(Design*des, NetScope*scope,
|
||||
des->errors += 1;
|
||||
}
|
||||
|
||||
if (rep->value().is_negative()) {
|
||||
cerr << get_fileline() << ": error: Concatenation repeat "
|
||||
<< "may not be negative (" << rep->value().as_long()
|
||||
<< ")." << endl;
|
||||
des->errors += 1;
|
||||
concat_depth -= 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (rep->value().is_zero() && concat_depth < 2) {
|
||||
cerr << get_fileline() << ": error: Concatenation repeat "
|
||||
<< "may not be zero in this context." << endl;
|
||||
des->errors += 1;
|
||||
concat_depth -= 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
repeat = rep;
|
||||
}
|
||||
|
||||
@@ -692,6 +770,15 @@ NetExpr* PEConcat::elaborate_expr(Design*des, NetScope*scope,
|
||||
|
||||
tmp->set_width(wid_sum * tmp->repeat());
|
||||
|
||||
if (wid_sum == 0 && concat_depth < 2) {
|
||||
cerr << get_fileline() << ": error: Concatenation may not "
|
||||
<< "have zero width in this context." << endl;
|
||||
des->errors += 1;
|
||||
concat_depth -= 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
concat_depth -= 1;
|
||||
return tmp;
|
||||
}
|
||||
|
||||
@@ -1128,6 +1215,13 @@ NetExpr* PEIdent::elaborate_expr_param(Design*des,
|
||||
ivl_assert(*this, index_tail.msb);
|
||||
ivl_assert(*this, !index_tail.lsb);
|
||||
|
||||
const NetEConst*par_me =dynamic_cast<const NetEConst*>(par_msb);
|
||||
const NetEConst*par_le =dynamic_cast<const NetEConst*>(par_lsb);
|
||||
|
||||
ivl_assert(*this, par_me || !par_msb);
|
||||
ivl_assert(*this, par_le || !par_lsb);
|
||||
ivl_assert(*this, par_me || !par_le);
|
||||
|
||||
/* Handle the case where a parameter has a bit
|
||||
select attached to it. Generate a NetESelect
|
||||
object to select the bit as desired. */
|
||||
@@ -1149,7 +1243,20 @@ NetExpr* PEIdent::elaborate_expr_param(Design*des,
|
||||
verinum rv = re->value();
|
||||
verinum::V rb = verinum::Vx;
|
||||
|
||||
long par_mv = lv.len()-1;
|
||||
long par_lv = 0;
|
||||
if (par_me) {
|
||||
par_mv = par_me->value().as_long();
|
||||
par_lv = par_le->value().as_long();
|
||||
}
|
||||
/* Convert the index to cannonical bit address. */
|
||||
long ridx = rv.as_long();
|
||||
if (par_mv >= par_lv) {
|
||||
ridx -= par_lv;
|
||||
} else {
|
||||
ridx = par_mv - ridx + par_lv;
|
||||
}
|
||||
|
||||
if ((ridx >= 0) && ((unsigned long) ridx < lv.len())) {
|
||||
rb = lv[ridx];
|
||||
|
||||
@@ -1167,13 +1274,6 @@ NetExpr* PEIdent::elaborate_expr_param(Design*des,
|
||||
|
||||
} else {
|
||||
|
||||
const NetEConst*par_me =dynamic_cast<const NetEConst*>(par_msb);
|
||||
const NetEConst*par_le =dynamic_cast<const NetEConst*>(par_lsb);
|
||||
|
||||
assert(par_me || !par_msb);
|
||||
assert(par_le || !par_lsb);
|
||||
assert(par_me || !par_le);
|
||||
|
||||
if (par_me) {
|
||||
long par_mv = par_me->value().as_long();
|
||||
long par_lv = par_le->value().as_long();
|
||||
@@ -1349,7 +1449,7 @@ NetExpr* PEIdent::elaborate_expr_net_part_(Design*des, NetScope*scope,
|
||||
}
|
||||
|
||||
|
||||
if (net->sig()->sb_to_idx(msv) >= net->vector_width()) {
|
||||
if (net->sig()->sb_to_idx(msv) >= (signed) net->vector_width()) {
|
||||
cerr << get_fileline() << ": error: part select ["
|
||||
<< msv << ":" << lsv << "] out of range." << endl;
|
||||
des->errors += 1;
|
||||
@@ -1458,7 +1558,8 @@ NetExpr* PEIdent::elaborate_expr_net_idx_do_(Design*des, NetScope*scope,
|
||||
// If the part select covers exactly the entire
|
||||
// vector, then do not bother with it. Return the
|
||||
// signal itself.
|
||||
if (net->sig()->sb_to_idx(lsv) == (wid-1) && wid == net->vector_width())
|
||||
if (net->sig()->sb_to_idx(lsv) == (signed) (wid-1) &&
|
||||
wid == net->vector_width())
|
||||
return net;
|
||||
|
||||
// Otherwise, make a part select that covers the right range.
|
||||
@@ -1735,13 +1836,23 @@ NetETernary*PETernary::elaborate_expr(Design*des, NetScope*scope,
|
||||
NetExpr* PEUnary::elaborate_expr(Design*des, NetScope*scope,
|
||||
int expr_wid, bool) const
|
||||
{
|
||||
/* Reduction operators and ! always have a self determined width. */
|
||||
switch (op_) {
|
||||
case '!':
|
||||
case '&': // Reduction AND
|
||||
case '|': // Reduction OR
|
||||
case '^': // Reduction XOR
|
||||
case 'A': // Reduction NAND (~&)
|
||||
case 'N': // Reduction NOR (~|)
|
||||
case 'X': // Reduction NXOR (~^)
|
||||
expr_wid = -1;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
NetExpr*ip = expr_->elaborate_expr(des, scope, expr_wid, false);
|
||||
if (ip == 0) return 0;
|
||||
|
||||
/* Should we evaluate expressions ahead of time,
|
||||
* just like in PEBinary::elaborate_expr() ?
|
||||
*/
|
||||
|
||||
NetExpr*tmp;
|
||||
switch (op_) {
|
||||
default:
|
||||
@@ -1756,16 +1867,15 @@ NetExpr* PEUnary::elaborate_expr(Design*des, NetScope*scope,
|
||||
if (expr_wid > 0)
|
||||
val = pad_to_width(val, expr_wid);
|
||||
|
||||
/* When taking the - of a number, turn it into a
|
||||
signed expression and extend it one bit to
|
||||
accommodate a possible sign bit. */
|
||||
/* When taking the - of a number, extend it one
|
||||
bit to accommodate a possible sign bit. */
|
||||
verinum zero (verinum::V0, val.len()+1, val.has_len());
|
||||
zero.has_sign(val.has_sign());
|
||||
verinum nval = zero - val;
|
||||
|
||||
if (val.has_len())
|
||||
nval = verinum(nval, val.len());
|
||||
nval.has_sign(true);
|
||||
nval.has_sign(val.has_sign());
|
||||
tmp = new NetEConst(nval);
|
||||
tmp->set_line(*this);
|
||||
delete ip;
|
||||
|
||||
+253
-77
@@ -808,7 +808,7 @@ NetNet* PEBinary::elaborate_net_mod_(Design*des, NetScope*scope,
|
||||
|
||||
/* The % operator does not support real arguments in baseline
|
||||
Verilog. But we allow it in our extended form of Verilog. */
|
||||
if (generation_flag < GN_VER2001X && lsig->data_type() == IVL_VT_REAL) {
|
||||
if (gn_icarus_misc_flag==false && lsig->data_type() == IVL_VT_REAL) {
|
||||
cerr << get_fileline() << ": error: Modulus operator may not "
|
||||
"have REAL operands." << endl;
|
||||
des->errors += 1;
|
||||
@@ -1578,12 +1578,20 @@ NetNet* PEConcat::elaborate_net(Design*des, NetScope*scope,
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (erep->value().is_negative()) {
|
||||
cerr << get_fileline() << ": error: Concatenation repeat "
|
||||
<< "may not be negative (" << erep->value().as_long()
|
||||
<< ")." << endl;
|
||||
des->errors += 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
repeat = erep->value().as_ulong();
|
||||
delete etmp;
|
||||
|
||||
if (repeat == 0) {
|
||||
cerr << get_fileline() << ": error: Concatenation repeat "
|
||||
"may not be 0."
|
||||
"may not be zero."
|
||||
<< endl;
|
||||
des->errors += 1;
|
||||
return 0;
|
||||
@@ -1681,7 +1689,6 @@ NetNet* PEConcat::elaborate_net(Design*des, NetScope*scope,
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
osig->local_flag(true);
|
||||
return osig;
|
||||
}
|
||||
@@ -1764,7 +1771,9 @@ NetNet* PEIdent::elaborate_net(Design*des, NetScope*scope,
|
||||
const NetExpr*par = 0;
|
||||
NetEvent* eve = 0;
|
||||
|
||||
symbol_search(des, scope, path_, sig, par, eve);
|
||||
const NetExpr*id_msb;
|
||||
const NetExpr*id_lsb;
|
||||
symbol_search(des, scope, path_, sig, par, eve, id_msb, id_lsb);
|
||||
|
||||
/* If this is a parameter name, then create a constant node
|
||||
that connects to a signal with the correct name. */
|
||||
@@ -1774,11 +1783,27 @@ NetNet* PEIdent::elaborate_net(Design*des, NetScope*scope,
|
||||
assert(pc);
|
||||
verinum pvalue = pc->value();
|
||||
|
||||
/* If the desired lwidth is more than the width of the
|
||||
constant value, extend the value to fit the desired
|
||||
output. */
|
||||
if (lwidth > pvalue.len()) {
|
||||
verinum tmp ((uint64_t)0, lwidth);
|
||||
/* If the parameter has declared dimensions, then apply
|
||||
those to the dimensions of the net that we create. */
|
||||
long msb = pvalue.len()-1;
|
||||
long lsb = 0;
|
||||
if (id_msb || id_lsb) {
|
||||
assert(id_msb && id_lsb);
|
||||
const NetEConst*tmp = dynamic_cast<const NetEConst*>(id_msb);
|
||||
ivl_assert(*this, tmp);
|
||||
msb = tmp->value().as_long();
|
||||
|
||||
tmp = dynamic_cast<const NetEConst*>(id_lsb);
|
||||
ivl_assert(*this, tmp);
|
||||
lsb = tmp->value().as_long();
|
||||
}
|
||||
|
||||
/* If the constant is smaller than its defined width extend
|
||||
the value. If needed this will be padded later to fit
|
||||
the real signal width. */
|
||||
unsigned pwidth = msb > lsb ? msb - lsb : lsb - msb;
|
||||
if (pwidth > pvalue.len()) {
|
||||
verinum tmp ((uint64_t)0, pwidth);
|
||||
for (unsigned idx = 0 ; idx < pvalue.len() ; idx += 1)
|
||||
tmp.set(idx, pvalue.get(idx));
|
||||
|
||||
@@ -1786,9 +1811,10 @@ NetNet* PEIdent::elaborate_net(Design*des, NetScope*scope,
|
||||
}
|
||||
|
||||
sig = new NetNet(scope, scope->local_symbol(),
|
||||
NetNet::IMPLICIT, pvalue.len());
|
||||
NetNet::IMPLICIT, msb, lsb);
|
||||
sig->set_line(*this);
|
||||
sig->data_type(IVL_VT_LOGIC);
|
||||
sig->local_flag(true);
|
||||
NetConst*cp = new NetConst(scope, scope->local_symbol(),
|
||||
pvalue);
|
||||
cp->set_line(*this);
|
||||
@@ -1868,10 +1894,11 @@ NetNet* PEIdent::process_select_(Design*des, NetScope*scope,
|
||||
// dimensions, then treat them as word part selects. For
|
||||
// example, if this is a memory array, then array dimensions
|
||||
// is the first and part select the remainder.
|
||||
unsigned midx, lidx;
|
||||
long midx, lidx;
|
||||
if (! eval_part_select_(des, scope, sig, midx, lidx))
|
||||
return sig;
|
||||
|
||||
ivl_assert(*this, lidx >= 0);
|
||||
unsigned part_count = midx-lidx+1;
|
||||
|
||||
// Maybe this is a full-width constant part select? If
|
||||
@@ -1937,12 +1964,70 @@ NetNet* PEIdent::elaborate_net_net_(Design*des, NetScope*scope,
|
||||
delete mval;
|
||||
}
|
||||
|
||||
unsigned midx, lidx;
|
||||
long midx, lidx;
|
||||
if (! eval_part_select_(des, scope, sig, midx, lidx))
|
||||
return 0;
|
||||
|
||||
unsigned part_count = midx-lidx+1;
|
||||
unsigned output_width = part_count;
|
||||
|
||||
/* Detect and handle the special case that the entire part
|
||||
select is outside the range of the signal. Return a
|
||||
constant xxx. */
|
||||
if (midx < 0 || lidx >= (long)sig->vector_width()) {
|
||||
ivl_assert(*this, sig->data_type() == IVL_VT_LOGIC);
|
||||
verinum xxx (verinum::Vx, part_count);
|
||||
NetConst*con = new NetConst(scope, scope->local_symbol(), xxx);
|
||||
con->set_line(*sig);
|
||||
des->add_node(con);
|
||||
|
||||
NetNet*tmp = new NetNet(scope, scope->local_symbol(),
|
||||
NetNet::WIRE, part_count-1, 0);
|
||||
tmp->data_type( sig->data_type() );
|
||||
tmp->local_flag(true);
|
||||
connect(tmp->pin(0), con->pin(0));
|
||||
return tmp;
|
||||
}
|
||||
|
||||
NetNet*below = 0;
|
||||
if (lidx < 0) {
|
||||
ivl_assert(*this, sig->data_type() == IVL_VT_LOGIC);
|
||||
unsigned xxx_wid = 0-lidx;
|
||||
verinum xxx (verinum::Vx, xxx_wid);
|
||||
NetConst*con = new NetConst(scope, scope->local_symbol(), xxx);
|
||||
con->set_line(*sig);
|
||||
des->add_node(con);
|
||||
|
||||
below = new NetNet(scope, scope->local_symbol(),
|
||||
NetNet::WIRE, xxx_wid);
|
||||
below->data_type( sig->data_type() );
|
||||
below->local_flag(true);
|
||||
connect(below->pin(0), con->pin(0));
|
||||
|
||||
lidx = 0;
|
||||
part_count = midx-lidx+1;
|
||||
}
|
||||
|
||||
NetNet*above = 0;
|
||||
if (midx >= (long)sig->vector_width()) {
|
||||
ivl_assert(*this, sig->data_type() == IVL_VT_LOGIC);
|
||||
unsigned xxx_wid = midx - sig->vector_width() + 1;
|
||||
verinum xxx (verinum::Vx, xxx_wid);
|
||||
NetConst*con = new NetConst(scope, scope->local_symbol(), xxx);
|
||||
con->set_line(*sig);
|
||||
des->add_node(con);
|
||||
|
||||
above = new NetNet(scope, scope->local_symbol(),
|
||||
NetNet::WIRE, xxx_wid);
|
||||
above->data_type( sig->data_type() );
|
||||
above->local_flag(true);
|
||||
connect(above->pin(0), con->pin(0));
|
||||
|
||||
midx = sig->vector_width()-1;
|
||||
part_count = midx-lidx+1;
|
||||
}
|
||||
|
||||
ivl_assert(*this, lidx >= 0);
|
||||
if (part_count != sig->vector_width()) {
|
||||
if (debug_elaborate) {
|
||||
cerr << get_fileline() << ": debug: Elaborate part select "
|
||||
@@ -1964,7 +2049,36 @@ NetNet* PEIdent::elaborate_net_net_(Design*des, NetScope*scope,
|
||||
sig = tmp;
|
||||
}
|
||||
|
||||
unsigned segment_count = 1;
|
||||
if (below) segment_count += 1;
|
||||
if (above) segment_count += 1;
|
||||
if (segment_count > 1) {
|
||||
NetConcat*cc = new NetConcat(scope, scope->local_symbol(),
|
||||
output_width, segment_count);
|
||||
cc->set_line(*sig);
|
||||
des->add_node(cc);
|
||||
|
||||
NetNet*tmp = new NetNet(scope, scope->local_symbol(),
|
||||
NetNet::WIRE, output_width);
|
||||
tmp->data_type( sig->data_type() );
|
||||
tmp->local_flag(true);
|
||||
connect(tmp->pin(0), cc->pin(0));
|
||||
|
||||
unsigned pdx = 1;
|
||||
if (below) {
|
||||
connect(cc->pin(pdx), below->pin(0));
|
||||
pdx += 1;
|
||||
}
|
||||
connect(cc->pin(pdx), sig->pin(0));
|
||||
pdx += 1;
|
||||
if (above) {
|
||||
connect(cc->pin(pdx), above->pin(0));
|
||||
pdx += 1;
|
||||
}
|
||||
ivl_assert(*sig, segment_count == pdx-1);
|
||||
|
||||
sig = tmp;
|
||||
}
|
||||
|
||||
return sig;
|
||||
}
|
||||
@@ -2188,7 +2302,6 @@ NetNet* PEIdent::elaborate_net_array_(Design*des, NetScope*scope,
|
||||
* make the l-value connections.
|
||||
*/
|
||||
NetNet* PEConcat::elaborate_lnet_common_(Design*des, NetScope*scope,
|
||||
bool implicit_net_ok,
|
||||
bool bidirectional_flag) const
|
||||
{
|
||||
assert(scope);
|
||||
@@ -2222,8 +2335,7 @@ NetNet* PEConcat::elaborate_lnet_common_(Design*des, NetScope*scope,
|
||||
if (bidirectional_flag) {
|
||||
nets[idx] = parms_[idx]->elaborate_bi_net(des, scope);
|
||||
} else {
|
||||
nets[idx] = parms_[idx]->elaborate_lnet(des, scope,
|
||||
implicit_net_ok);
|
||||
nets[idx] = parms_[idx]->elaborate_lnet(des, scope);
|
||||
}
|
||||
if (nets[idx] == 0)
|
||||
errors += 1;
|
||||
@@ -2284,15 +2396,14 @@ NetNet* PEConcat::elaborate_lnet_common_(Design*des, NetScope*scope,
|
||||
return osig;
|
||||
}
|
||||
|
||||
NetNet* PEConcat::elaborate_lnet(Design*des, NetScope*scope,
|
||||
bool implicit_net_ok) const
|
||||
NetNet* PEConcat::elaborate_lnet(Design*des, NetScope*scope) const
|
||||
{
|
||||
return elaborate_lnet_common_(des, scope, implicit_net_ok, false);
|
||||
return elaborate_lnet_common_(des, scope, false);
|
||||
}
|
||||
|
||||
NetNet* PEConcat::elaborate_bi_net(Design*des, NetScope*scope) const
|
||||
{
|
||||
return elaborate_lnet_common_(des, scope, true, true);
|
||||
return elaborate_lnet_common_(des, scope, true);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -2337,25 +2448,18 @@ NetNet* PEFNumber::elaborate_net(Design*des, NetScope*scope,
|
||||
NetNet* PEIdent::make_implicit_net_(Design*des, NetScope*scope) const
|
||||
{
|
||||
NetNet::Type nettype = scope->default_nettype();
|
||||
NetNet*sig = 0;
|
||||
assert(nettype != NetNet::NONE);
|
||||
|
||||
if (!error_implicit && nettype!=NetNet::NONE) {
|
||||
sig = new NetNet(scope, peek_tail_name(path_),
|
||||
NetNet::IMPLICIT, 1);
|
||||
/* Implicit nets are always scalar logic. */
|
||||
sig->data_type(IVL_VT_LOGIC);
|
||||
NetNet*sig = new NetNet(scope, peek_tail_name(path_),
|
||||
NetNet::IMPLICIT, 1);
|
||||
sig->set_line(*this);
|
||||
/* Implicit nets are always scalar logic. */
|
||||
sig->data_type(IVL_VT_LOGIC);
|
||||
|
||||
if (warn_implicit) {
|
||||
cerr << get_fileline() << ": warning: implicit "
|
||||
"definition of wire logic " << scope_path(scope)
|
||||
<< "." << peek_tail_name(path_) << "." << endl;
|
||||
}
|
||||
|
||||
} else {
|
||||
cerr << get_fileline() << ": error: Net " << path_
|
||||
<< " is not defined in this context." << endl;
|
||||
des->errors += 1;
|
||||
return 0;
|
||||
if (warn_implicit) {
|
||||
cerr << get_fileline() << ": warning: implicit "
|
||||
"definition of wire logic " << scope_path(scope)
|
||||
<< "." << peek_tail_name(path_) << "." << endl;
|
||||
}
|
||||
|
||||
return sig;
|
||||
@@ -2369,7 +2473,7 @@ NetNet* PEIdent::make_implicit_net_(Design*des, NetScope*scope) const
|
||||
* anything in between. The values are in canonical indices.
|
||||
*/
|
||||
bool PEIdent::eval_part_select_(Design*des, NetScope*scope, NetNet*sig,
|
||||
unsigned&midx, unsigned&lidx) const
|
||||
long&midx, long&lidx) const
|
||||
{
|
||||
const name_component_t&name_tail = path_.back();
|
||||
// Only treat as part/bit selects any index that is beyond the
|
||||
@@ -2433,31 +2537,36 @@ bool PEIdent::eval_part_select_(Design*des, NetScope*scope, NetNet*sig,
|
||||
long msb, lsb;
|
||||
/* bool flag = */ calculate_parts_(des, scope, msb, lsb);
|
||||
|
||||
lidx = sig->sb_to_idx(lsb);
|
||||
midx = sig->sb_to_idx(msb);
|
||||
long lidx_tmp = sig->sb_to_idx(lsb);
|
||||
long midx_tmp = sig->sb_to_idx(msb);
|
||||
/* Detect reversed indices of a part select. */
|
||||
if (lidx > midx) {
|
||||
if (lidx_tmp > midx_tmp) {
|
||||
cerr << get_fileline() << ": error: Part select "
|
||||
<< sig->name() << "[" << msb << ":"
|
||||
<< lsb << "] indices reversed." << endl;
|
||||
cerr << get_fileline() << ": : Did you mean "
|
||||
<< sig->name() << "[" << lsb << ":"
|
||||
<< msb << "]?" << endl;
|
||||
unsigned tmp = midx;
|
||||
midx = lidx;
|
||||
lidx = tmp;
|
||||
long tmp = midx_tmp;
|
||||
midx_tmp = lidx_tmp;
|
||||
lidx_tmp = tmp;
|
||||
des->errors += 1;
|
||||
}
|
||||
|
||||
/* Detect a part select out of range. */
|
||||
if (midx >= sig->vector_width()) {
|
||||
cerr << get_fileline() << ": error: Part select "
|
||||
if (midx_tmp >= (long)sig->vector_width() || lidx_tmp < 0) {
|
||||
cerr << get_fileline() << ": warning: Part select "
|
||||
<< sig->name() << "[" << msb << ":"
|
||||
<< lsb << "] out of range." << endl;
|
||||
midx = sig->vector_width() - 1;
|
||||
lidx = 0;
|
||||
#if 0
|
||||
midx_tmp = sig->vector_width() - 1;
|
||||
lidx_tmp = 0;
|
||||
des->errors += 1;
|
||||
#endif
|
||||
}
|
||||
|
||||
midx = midx_tmp;
|
||||
lidx = lidx_tmp;
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -2478,7 +2587,7 @@ bool PEIdent::eval_part_select_(Design*des, NetScope*scope, NetNet*sig,
|
||||
assert(mval);
|
||||
|
||||
midx = sig->sb_to_idx(mval->as_long());
|
||||
if (midx >= sig->vector_width()) {
|
||||
if (midx >= (long)sig->vector_width()) {
|
||||
cerr << get_fileline() << ": error: Index " << sig->name()
|
||||
<< "[" << mval->as_long() << "] out of range."
|
||||
<< endl;
|
||||
@@ -2506,7 +2615,6 @@ bool PEIdent::eval_part_select_(Design*des, NetScope*scope, NetNet*sig,
|
||||
* so most of the work for both is done here.
|
||||
*/
|
||||
NetNet* PEIdent::elaborate_lnet_common_(Design*des, NetScope*scope,
|
||||
bool implicit_net_ok,
|
||||
bool bidirectional_flag) const
|
||||
{
|
||||
assert(scope);
|
||||
@@ -2526,19 +2634,10 @@ NetNet* PEIdent::elaborate_lnet_common_(Design*des, NetScope*scope,
|
||||
}
|
||||
|
||||
if (sig == 0) {
|
||||
|
||||
if (implicit_net_ok) {
|
||||
|
||||
sig = make_implicit_net_(des, scope);
|
||||
if (sig == 0)
|
||||
return 0;
|
||||
|
||||
} else {
|
||||
cerr << get_fileline() << ": error: Net " << path_
|
||||
<< " is not defined in this context." << endl;
|
||||
des->errors += 1;
|
||||
return 0;
|
||||
}
|
||||
cerr << get_fileline() << ": error: Net " << path_
|
||||
<< " is not defined in this context." << endl;
|
||||
des->errors += 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
assert(sig);
|
||||
@@ -2604,12 +2703,21 @@ NetNet* PEIdent::elaborate_lnet_common_(Design*des, NetScope*scope,
|
||||
|
||||
/* The array has a part/bit select at the end. */
|
||||
if (name_tail.index.size() > sig->array_dimensions()) {
|
||||
if (! eval_part_select_(des, scope, sig, midx, lidx))
|
||||
long midx_tmp, lidx_tmp;
|
||||
if (! eval_part_select_(des, scope, sig, midx_tmp, lidx_tmp))
|
||||
return 0;
|
||||
ivl_assert(*this, lidx_tmp >= 0);
|
||||
midx = midx_tmp;
|
||||
lidx = lidx_tmp;
|
||||
}
|
||||
} else if (!name_tail.index.empty()) {
|
||||
if (! eval_part_select_(des, scope, sig, midx, lidx))
|
||||
long midx_tmp, lidx_tmp;
|
||||
if (! eval_part_select_(des, scope, sig, midx_tmp, lidx_tmp))
|
||||
return 0;
|
||||
|
||||
ivl_assert(*this, lidx_tmp >= 0);
|
||||
midx = midx_tmp;
|
||||
lidx = lidx_tmp;
|
||||
}
|
||||
|
||||
unsigned subnet_wid = midx-lidx+1;
|
||||
@@ -2671,15 +2779,14 @@ NetNet* PEIdent::elaborate_lnet_common_(Design*des, NetScope*scope,
|
||||
* Identifiers in continuous assignment l-values are limited to wires
|
||||
* and that ilk. Detect registers and memories here and report errors.
|
||||
*/
|
||||
NetNet* PEIdent::elaborate_lnet(Design*des, NetScope*scope,
|
||||
bool implicit_net_ok) const
|
||||
NetNet* PEIdent::elaborate_lnet(Design*des, NetScope*scope) const
|
||||
{
|
||||
return elaborate_lnet_common_(des, scope, implicit_net_ok, false);
|
||||
return elaborate_lnet_common_(des, scope, false);
|
||||
}
|
||||
|
||||
NetNet* PEIdent::elaborate_bi_net(Design*des, NetScope*scope) const
|
||||
{
|
||||
return elaborate_lnet_common_(des, scope, true, true);
|
||||
return elaborate_lnet_common_(des, scope, true);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -2732,8 +2839,8 @@ NetNet* PEIdent::elaborate_port(Design*des, NetScope*scope) const
|
||||
return 0;
|
||||
}
|
||||
|
||||
unsigned midx;
|
||||
unsigned lidx;
|
||||
long midx;
|
||||
long lidx;
|
||||
|
||||
/* Evaluate the part/bit select expressions, to get the part
|
||||
select of the signal that attaches to the port. Also handle
|
||||
@@ -2907,6 +3014,30 @@ NetNet* PEString::elaborate_net(Design*des, NetScope*scope,
|
||||
return net;
|
||||
}
|
||||
|
||||
/* Common processing for the case when a single argument is always
|
||||
* selected in a ternary operator. */
|
||||
static void process_single_ternary(Design*des, const PExpr*base,
|
||||
unsigned width, NetNet*&sig)
|
||||
{
|
||||
/* We must have a type for the signal. */
|
||||
if (sig->data_type() == IVL_VT_NO_TYPE) {
|
||||
cerr << base->get_fileline() << ": internal error: constant "
|
||||
<< "selected ternary clause has NO TYPE." << endl;
|
||||
des->errors += 1;
|
||||
sig = 0;
|
||||
}
|
||||
|
||||
/* Use the signal width if one is not provided.
|
||||
* Pad or crop as needed. */
|
||||
if (width == 0) width = sig->vector_width();
|
||||
|
||||
if (sig->vector_width() < width) sig = pad_to_width(des, sig, width);
|
||||
|
||||
if (width < sig->vector_width()) sig = crop_to_width(des, sig, width);
|
||||
|
||||
sig->set_line(*base);
|
||||
}
|
||||
|
||||
/*
|
||||
* Elaborate the ternary operator in a netlist by creating a LPM_MUX
|
||||
* with width matching the result, size == 2 and 1 select input. These
|
||||
@@ -2939,18 +3070,24 @@ NetNet* PETernary::elaborate_net(Design*des, NetScope*scope,
|
||||
case C_0:
|
||||
fal_sig = fal_->elaborate_net(des, scope, width, 0, 0, 0);
|
||||
if (fal_sig == 0) return 0;
|
||||
tru_sig = tru_->elaborate_net(des, scope, width, 0, 0, 0);
|
||||
process_single_ternary(des, this, width, fal_sig);
|
||||
return fal_sig;
|
||||
break;
|
||||
|
||||
case C_1:
|
||||
tru_sig = tru_->elaborate_net(des, scope, width, 0, 0, 0);
|
||||
if (tru_sig == 0) return 0;
|
||||
fal_sig = fal_->elaborate_net(des, scope, width, 0, 0, 0);
|
||||
process_single_ternary(des, this, width, tru_sig);
|
||||
return tru_sig;
|
||||
break;
|
||||
|
||||
default:
|
||||
tru_sig = tru_->elaborate_net(des, scope, width, 0, 0, 0);
|
||||
fal_sig = fal_->elaborate_net(des, scope, width, 0, 0, 0);
|
||||
/* We should really see if these are constant values and
|
||||
* mix them as needed so we can omit the MUX? below, but
|
||||
* since this is a very uncommon case, I'm going to pass
|
||||
* on this for now. */
|
||||
break;
|
||||
}
|
||||
expr_sig = expr->synthesize(des);
|
||||
@@ -3108,10 +3245,6 @@ NetNet* PEUnary::elaborate_net(Design*des, NetScope*scope,
|
||||
Link::strength_t drive0,
|
||||
Link::strength_t drive1) const
|
||||
{
|
||||
NetExpr*expr = elab_and_eval(des, scope, expr_, width);
|
||||
if (expr == 0)
|
||||
return 0;
|
||||
|
||||
// Some unary operands allow the operand to be
|
||||
// self-determined, and some do not.
|
||||
unsigned owidth = 0;
|
||||
@@ -3122,6 +3255,9 @@ NetNet* PEUnary::elaborate_net(Design*des, NetScope*scope,
|
||||
break;
|
||||
}
|
||||
|
||||
NetExpr*expr = elab_and_eval(des, scope, expr_, owidth);
|
||||
if (expr == 0) return 0;
|
||||
|
||||
NetNet* sig = 0;
|
||||
NetLogic*gate;
|
||||
|
||||
@@ -3178,6 +3314,33 @@ NetNet* PEUnary::elaborate_net(Design*des, NetScope*scope,
|
||||
connect(gate->pin(0), sig->pin(0));
|
||||
break;
|
||||
|
||||
case 'm': // abs(sub_sig)
|
||||
// If this expression is self determined, get its width
|
||||
// from the sub_expression.
|
||||
if (owidth == 0)
|
||||
owidth = sub_sig->vector_width();
|
||||
|
||||
if (sub_sig->vector_width() < owidth)
|
||||
sub_sig = pad_to_width(des, sub_sig, owidth);
|
||||
|
||||
sig = new NetNet(scope, scope->local_symbol(),
|
||||
NetNet::WIRE, owidth);
|
||||
sig->set_line(*this);
|
||||
sig->data_type(sub_sig->data_type());
|
||||
sig->local_flag(true);
|
||||
|
||||
{ NetAbs*tmp = new NetAbs(scope, scope->local_symbol(), sub_sig->vector_width());
|
||||
tmp->set_line(*this);
|
||||
des->add_node(tmp);
|
||||
tmp->rise_time(rise);
|
||||
tmp->fall_time(fall);
|
||||
tmp->decay_time(decay);
|
||||
|
||||
connect(tmp->pin(1), sub_sig->pin(0));
|
||||
connect(tmp->pin(0), sig->pin(0));
|
||||
}
|
||||
break;
|
||||
|
||||
case 'N': // Reduction NOR
|
||||
case '!': // Reduction NOT
|
||||
reduction=true; rtype = NetUReduce::NOR; break;
|
||||
@@ -3256,7 +3419,7 @@ NetNet* PEUnary::elaborate_net(Design*des, NetScope*scope,
|
||||
break;
|
||||
|
||||
default:
|
||||
cerr << "internal error: Unhandled UNARY '" << op_ << "'" << endl;
|
||||
cerr << get_fileline() << ": internal error: Unhandled UNARY '" << op_ << "'" << endl;
|
||||
sig = 0;
|
||||
}
|
||||
|
||||
@@ -3431,6 +3594,19 @@ NetNet* PEUnary::elab_net_unary_real_(Design*des, NetScope*scope,
|
||||
des->errors += 1;
|
||||
break;
|
||||
|
||||
case 'm': { // abs()
|
||||
NetAbs*tmp = new NetAbs(scope, scope->local_symbol(), 1);
|
||||
tmp->set_line(*this);
|
||||
tmp->rise_time(rise);
|
||||
tmp->fall_time(fall);
|
||||
tmp->decay_time(decay);
|
||||
des->add_node(tmp);
|
||||
|
||||
connect(tmp->pin(0), sig->pin(0));
|
||||
connect(tmp->pin(1), sub_sig->pin(0));
|
||||
break;
|
||||
}
|
||||
|
||||
case '-':
|
||||
NetAddSub*sub = new NetAddSub(scope, scope->local_symbol(), 1);
|
||||
sub->attribute(perm_string::literal("LPM_Direction"),
|
||||
|
||||
+6
-1
@@ -53,7 +53,7 @@ NetExpr*PEBinary::elaborate_pexpr (Design*des, NetScope*scope) const
|
||||
return 0;
|
||||
}
|
||||
|
||||
NetEBinary*tmp = elaborate_expr_base_(des, lp, rp, -2);
|
||||
NetExpr*tmp = elaborate_expr_base_(des, lp, rp, -2);
|
||||
return tmp;
|
||||
}
|
||||
|
||||
@@ -193,6 +193,11 @@ NetExpr*PEIdent::elaborate_pexpr(Design*des, NetScope*scope) const
|
||||
delete res;
|
||||
return 0;
|
||||
}
|
||||
if (debug_elaborate)
|
||||
cerr << get_fileline() << ": debug: "
|
||||
<< "Bit select [" << *tmp << "]"
|
||||
<< " in parameter expression." << endl;
|
||||
|
||||
res = new NetESelect(res, tmp, 1);
|
||||
res->set_line(*this);
|
||||
break;
|
||||
|
||||
+41
-8
@@ -45,7 +45,8 @@
|
||||
# include <assert.h>
|
||||
|
||||
void Module::elaborate_parm_item_(perm_string name, const param_expr_t&cur,
|
||||
Design*des, NetScope*scope)
|
||||
Design*des, NetScope*scope,
|
||||
perm_string file, unsigned lineno)
|
||||
{
|
||||
PExpr*ex = cur.expr;
|
||||
assert(ex);
|
||||
@@ -81,7 +82,7 @@ void Module::elaborate_parm_item_(perm_string name, const param_expr_t&cur,
|
||||
}
|
||||
|
||||
val = scope->set_parameter(name, val,
|
||||
msb, lsb, signed_flag);
|
||||
msb, lsb, signed_flag, file, lineno);
|
||||
assert(val);
|
||||
delete val;
|
||||
}
|
||||
@@ -119,7 +120,8 @@ bool Module::elaborate_scope(Design*des, NetScope*scope,
|
||||
tmp->set_line(*((*cur).second.expr));
|
||||
tmp->cast_signed( (*cur).second.signed_flag );
|
||||
|
||||
scope->set_parameter((*cur).first, tmp, 0, 0, false);
|
||||
scope->set_parameter((*cur).first, tmp, 0, 0, false,
|
||||
(*cur).second.file, (*cur).second.lineno);
|
||||
}
|
||||
|
||||
for (mparm_it_t cur = localparams.begin()
|
||||
@@ -130,7 +132,8 @@ bool Module::elaborate_scope(Design*des, NetScope*scope,
|
||||
if ((*cur).second.msb)
|
||||
tmp->cast_signed( (*cur).second.signed_flag );
|
||||
|
||||
scope->set_parameter((*cur).first, tmp, 0, 0, false);
|
||||
scope->set_parameter((*cur).first, tmp, 0, 0, false,
|
||||
(*cur).second.file, (*cur).second.lineno);
|
||||
}
|
||||
|
||||
|
||||
@@ -142,7 +145,8 @@ bool Module::elaborate_scope(Design*des, NetScope*scope,
|
||||
for (mparm_it_t cur = parameters.begin()
|
||||
; cur != parameters.end() ; cur ++) {
|
||||
|
||||
elaborate_parm_item_((*cur).first, (*cur).second, des, scope);
|
||||
elaborate_parm_item_((*cur).first, (*cur).second, des, scope,
|
||||
(*cur).second.file, (*cur).second.lineno);
|
||||
}
|
||||
|
||||
/* run parameter replacements that were collected from the
|
||||
@@ -174,7 +178,8 @@ bool Module::elaborate_scope(Design*des, NetScope*scope,
|
||||
for (mparm_it_t cur = localparams.begin()
|
||||
; cur != localparams.end() ; cur ++) {
|
||||
|
||||
elaborate_parm_item_((*cur).first, (*cur).second, des, scope);
|
||||
elaborate_parm_item_((*cur).first, (*cur).second, des, scope,
|
||||
(*cur).second.file, (*cur).second.lineno);
|
||||
}
|
||||
|
||||
// Run through the defparams for this module, elaborate the
|
||||
@@ -240,6 +245,7 @@ bool Module::elaborate_scope(Design*des, NetScope*scope,
|
||||
}
|
||||
NetScope*task_scope = new NetScope(scope, use_name,
|
||||
NetScope::TASK);
|
||||
task_scope->set_line((*cur).second);
|
||||
(*cur).second->elaborate_scope(des, task_scope);
|
||||
}
|
||||
|
||||
@@ -263,6 +269,7 @@ bool Module::elaborate_scope(Design*des, NetScope*scope,
|
||||
}
|
||||
NetScope*func_scope = new NetScope(scope, use_name,
|
||||
NetScope::FUNC);
|
||||
func_scope->set_line((*cur).second);
|
||||
(*cur).second->elaborate_scope(des, func_scope);
|
||||
}
|
||||
|
||||
@@ -337,6 +344,11 @@ bool PGenerate::generate_scope(Design*des, NetScope*container)
|
||||
*/
|
||||
bool PGenerate::generate_scope_loop_(Design*des, NetScope*container)
|
||||
{
|
||||
// Check that the loop_index variable was declared in a
|
||||
// genvar statement.
|
||||
|
||||
// MISSING CODE!
|
||||
|
||||
// We're going to need a genvar...
|
||||
int genvar;
|
||||
|
||||
@@ -352,12 +364,24 @@ bool PGenerate::generate_scope_loop_(Design*des, NetScope*container)
|
||||
return false;
|
||||
}
|
||||
|
||||
// Since we will be adding the genvar value as a local parameter
|
||||
// to each instances scope. We need to make sure a parameter does
|
||||
// not already exist.
|
||||
const NetExpr*tmsb;
|
||||
const NetExpr*tlsb;
|
||||
const NetExpr*texpr = container->get_parameter(loop_index, tmsb, tlsb);
|
||||
if (texpr != 0) {
|
||||
cerr << get_fileline() << ": error: Cannot have a genvar "
|
||||
<< "and parameter with the same name: " << loop_index << endl;
|
||||
des->errors += 1;
|
||||
return false;
|
||||
}
|
||||
|
||||
genvar = init->value().as_long();
|
||||
delete init_ex;
|
||||
|
||||
if (debug_scopes)
|
||||
cerr << get_fileline() << ": debug: genvar init = " << genvar << endl;
|
||||
|
||||
container->genvar_tmp = loop_index;
|
||||
container->genvar_tmp_val = genvar;
|
||||
NetExpr*test_ex = elab_and_eval(des, container, loop_test, -1);
|
||||
@@ -383,6 +407,7 @@ bool PGenerate::generate_scope_loop_(Design*des, NetScope*container)
|
||||
|
||||
NetScope*scope = new NetScope(container, use_name,
|
||||
NetScope::GENBLOCK);
|
||||
scope->set_line(get_file(), get_lineno());
|
||||
|
||||
// Set in the scope a localparam for the value of the
|
||||
// genvar within this instance of the generate
|
||||
@@ -394,7 +419,10 @@ bool PGenerate::generate_scope_loop_(Design*des, NetScope*container)
|
||||
NetEConstParam*gp = new NetEConstParam(scope,
|
||||
loop_index,
|
||||
genvar_verinum);
|
||||
scope->set_localparam(loop_index, gp);
|
||||
// The file and line information should really come
|
||||
// from the genvar statement, not the for loop.
|
||||
scope->set_localparam(loop_index, gp, get_file(),
|
||||
get_lineno());
|
||||
|
||||
if (debug_scopes)
|
||||
cerr << get_fileline() << ": debug: "
|
||||
@@ -463,6 +491,7 @@ bool PGenerate::generate_scope_condit_(Design*des, NetScope*container, bool else
|
||||
|
||||
NetScope*scope = new NetScope(container, use_name,
|
||||
NetScope::GENBLOCK);
|
||||
scope->set_line(get_file(), get_lineno());
|
||||
|
||||
elaborate_subscope_(des, scope);
|
||||
|
||||
@@ -529,6 +558,7 @@ bool PGenerate::generate_scope_case_(Design*des, NetScope*container)
|
||||
|
||||
NetScope*scope = new NetScope(container, use_name,
|
||||
NetScope::GENBLOCK);
|
||||
scope->set_line(get_file(), get_lineno());
|
||||
item->elaborate_subscope_(des, scope);
|
||||
|
||||
return true;
|
||||
@@ -661,6 +691,8 @@ void PGModule::elaborate_scope_mod_(Design*des, Module*mod, NetScope*sc) const
|
||||
|
||||
// Create the new scope as a MODULE with my name.
|
||||
NetScope*my_scope = new NetScope(sc, use_name, NetScope::MODULE);
|
||||
my_scope->set_line(get_file(), mod->get_file(),
|
||||
get_lineno(), mod->get_lineno());
|
||||
my_scope->set_module_name(mod->mod_name());
|
||||
my_scope->default_nettype(mod->default_nettype);
|
||||
|
||||
@@ -811,6 +843,7 @@ void PBlock::elaborate_scope(Design*des, NetScope*scope) const
|
||||
my_scope = new NetScope(scope, use_name, bl_type_==BL_PAR
|
||||
? NetScope::FORK_JOIN
|
||||
: NetScope::BEGIN_END);
|
||||
my_scope->set_line(get_file(), get_lineno());
|
||||
}
|
||||
|
||||
for (unsigned idx = 0 ; idx < list_.count() ; idx += 1)
|
||||
|
||||
+169
-2
@@ -230,11 +230,129 @@ bool Module::elaborate_sig(Design*des, NetScope*scope) const
|
||||
return flag;
|
||||
}
|
||||
|
||||
bool PExpr::elaborate_sig(Design*des, NetScope*scope) const
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
bool PEConcat::elaborate_sig(Design*des, NetScope*scope) const
|
||||
{
|
||||
bool flag = true;
|
||||
for (unsigned idx = 0 ; idx < parms_.count() ; idx += 1)
|
||||
flag = parms_[idx]->elaborate_sig(des, scope) && flag;
|
||||
|
||||
return flag;
|
||||
}
|
||||
|
||||
bool PEIdent::elaborate_sig(Design*des, NetScope*scope) const
|
||||
{
|
||||
NetNet* sig = 0;
|
||||
const NetExpr*par = 0;
|
||||
NetEvent* eve = 0;
|
||||
|
||||
// If implicit net creation is turned off, then stop now.
|
||||
if (scope->default_nettype() == NetNet::NONE)
|
||||
return true;
|
||||
if (error_implicit)
|
||||
return true;
|
||||
|
||||
symbol_search(des, scope, path_, sig, par, eve);
|
||||
|
||||
if (eve != 0)
|
||||
return false;
|
||||
|
||||
if (par != 0)
|
||||
return true;
|
||||
|
||||
if (sig == 0)
|
||||
sig = make_implicit_net_(des, scope);
|
||||
|
||||
return sig != 0;
|
||||
}
|
||||
|
||||
bool PEBinary::elaborate_sig(Design*des, NetScope*scope) const
|
||||
{
|
||||
bool flag = true;
|
||||
|
||||
flag = left_->elaborate_sig(des, scope) && flag;
|
||||
flag = right_->elaborate_sig(des, scope) && flag;
|
||||
return flag;
|
||||
}
|
||||
|
||||
bool PETernary::elaborate_sig(Design*des, NetScope*scope) const
|
||||
{
|
||||
bool flag = true;
|
||||
flag = tru_->elaborate_sig(des, scope) && flag;
|
||||
flag = fal_->elaborate_sig(des, scope) && flag;
|
||||
return flag;
|
||||
}
|
||||
|
||||
bool PEUnary::elaborate_sig(Design*des, NetScope*scope) const
|
||||
{
|
||||
return expr_->elaborate_sig(des, scope);
|
||||
}
|
||||
|
||||
bool PGate::elaborate_sig(Design*des, NetScope*scope) const
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
bool PGBuiltin::elaborate_sig(Design*des, NetScope*scope) const
|
||||
{
|
||||
bool flag = true;
|
||||
|
||||
for (unsigned idx = 0 ; idx < pin_count() ; idx += 1) {
|
||||
const PExpr* pin_expr = pin(idx);
|
||||
if (pin_expr == 0) {
|
||||
// If there is no pin expression for this port,
|
||||
// then skip it. Do not bother generating an error
|
||||
// message here, that will be done during
|
||||
// elaboration where these semantic details are tested.
|
||||
continue;
|
||||
}
|
||||
ivl_assert(*this, pin_expr);
|
||||
flag = pin_expr->elaborate_sig(des, scope) && flag;
|
||||
}
|
||||
|
||||
return flag;
|
||||
}
|
||||
|
||||
bool PGAssign::elaborate_sig(Design*des, NetScope*scope) const
|
||||
{
|
||||
/* Normally, l-values to continuous assignments are NOT allowed
|
||||
to implicitly declare nets. However, so many tools do allow
|
||||
it that Icarus Verilog will allow it, at least if extensions
|
||||
are enabled. */
|
||||
if (gn_icarus_misc_flag)
|
||||
return pin(0)->elaborate_sig(des, scope);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool PGModule::elaborate_sig_mod_(Design*des, NetScope*scope,
|
||||
Module*rmod) const
|
||||
{
|
||||
bool flag = true;
|
||||
|
||||
// First, elaborate the signals that may be created implicitly
|
||||
// by ports to this module instantiation. Handle the case that
|
||||
// the ports are passed by name (pins_ != 0) or position.
|
||||
if (pins_)
|
||||
for (unsigned idx = 0 ; idx < npins_ ; idx += 1) {
|
||||
const PExpr*tmp = pins_[idx].parm;
|
||||
if (tmp == 0)
|
||||
continue;
|
||||
flag = tmp->elaborate_sig(des, scope) && flag;
|
||||
}
|
||||
else
|
||||
for (unsigned idx = 0 ; idx < pin_count() ; idx += 1) {
|
||||
const PExpr*tmp = pin(idx);
|
||||
if (tmp == 0)
|
||||
continue;
|
||||
flag = tmp->elaborate_sig(des, scope) && flag;
|
||||
}
|
||||
|
||||
|
||||
NetScope::scope_vec_t instance = scope->instance_arrays[get_name()];
|
||||
|
||||
for (unsigned idx = 0 ; idx < instance.count() ; idx += 1) {
|
||||
@@ -260,6 +378,28 @@ bool PGModule::elaborate_sig_mod_(Design*des, NetScope*scope,
|
||||
return flag;
|
||||
}
|
||||
|
||||
bool PGModule::elaborate_sig_udp_(Design*des, NetScope*scope, PUdp*udp) const
|
||||
{
|
||||
bool flag = true;
|
||||
|
||||
if (pins_)
|
||||
for (unsigned idx = 0 ; idx < npins_ ; idx += 1) {
|
||||
const PExpr*tmp = pins_[idx].parm;
|
||||
if (tmp == 0)
|
||||
continue;
|
||||
flag = tmp->elaborate_sig(des, scope) && flag;
|
||||
}
|
||||
else
|
||||
for (unsigned idx = 0 ; idx < pin_count() ; idx += 1) {
|
||||
const PExpr*tmp = pin(idx);
|
||||
if (tmp == 0)
|
||||
continue;
|
||||
flag = tmp->elaborate_sig(des, scope) && flag;
|
||||
}
|
||||
|
||||
return flag;
|
||||
}
|
||||
|
||||
bool PGenerate::elaborate_sig(Design*des, NetScope*container) const
|
||||
{
|
||||
bool flag = true;
|
||||
@@ -453,6 +593,8 @@ void PFunction::elaborate_sig(Design*des, NetScope*scope) const
|
||||
perm_string pname = (*ports_)[idx]->basename();
|
||||
|
||||
NetNet*tmp = scope->find_signal(pname);
|
||||
ports[idx] = 0;
|
||||
|
||||
if (tmp == 0) {
|
||||
cerr << get_fileline() << ": internal error: function "
|
||||
<< scope_path(scope) << " is missing port "
|
||||
@@ -460,9 +602,27 @@ void PFunction::elaborate_sig(Design*des, NetScope*scope) const
|
||||
scope->dump(cerr);
|
||||
cerr << get_fileline() << ": Continuing..." << endl;
|
||||
des->errors += 1;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (tmp->port_type() == NetNet::NOT_A_PORT) {
|
||||
cerr << get_fileline() << ": internal error: function "
|
||||
<< scope_path(scope) << " port " << pname
|
||||
<< " is a port but is not a port?" << endl;
|
||||
des->errors += 1;
|
||||
scope->dump(cerr);
|
||||
continue;
|
||||
}
|
||||
|
||||
ports[idx] = tmp;
|
||||
if (tmp->port_type() != NetNet::PINPUT) {
|
||||
cerr << tmp->get_fileline() << ": error: function "
|
||||
<< scope_path(scope) << " port " << pname
|
||||
<< " is not an input port." << endl;
|
||||
cerr << tmp->get_fileline() << ": : Function arguments "
|
||||
<< "must be input ports." << endl;
|
||||
des->errors += 1;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -598,9 +758,16 @@ void PForStatement::elaborate_sig(Design*des, NetScope*scope) const
|
||||
statement_->elaborate_sig(des, scope);
|
||||
}
|
||||
|
||||
bool PGate::elaborate_sig(Design*des, NetScope*scope) const
|
||||
void PRepeat::elaborate_sig(Design*des, NetScope*scope) const
|
||||
{
|
||||
return true;
|
||||
if (statement_)
|
||||
statement_->elaborate_sig(des, scope);
|
||||
}
|
||||
|
||||
void PWhile::elaborate_sig(Design*des, NetScope*scope) const
|
||||
{
|
||||
if (statement_)
|
||||
statement_->elaborate_sig(des, scope);
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
+60
-37
@@ -85,16 +85,8 @@ void PGAssign::elaborate(Design*des, NetScope*scope) const
|
||||
assert(pin(0));
|
||||
assert(pin(1));
|
||||
|
||||
/* Normally, l-values to continuous assignments are NOT allowed
|
||||
to implicitly declare nets. However, so many tools do allow
|
||||
it that Icarus Verilog will allow it, at least if extensions
|
||||
are enabled. */
|
||||
bool implicit_lval_ok = false;
|
||||
if (generation_flag == GN_VER2001X)
|
||||
implicit_lval_ok = true;
|
||||
|
||||
/* Elaborate the l-value. */
|
||||
NetNet*lval = pin(0)->elaborate_lnet(des, scope, implicit_lval_ok);
|
||||
NetNet*lval = pin(0)->elaborate_lnet(des, scope);
|
||||
if (lval == 0) {
|
||||
return;
|
||||
}
|
||||
@@ -410,7 +402,7 @@ void PGBuiltin::elaborate(Design*des, NetScope*scope) const
|
||||
des->errors += 1;
|
||||
return;
|
||||
}
|
||||
NetNet*lval_sig = pin(0)->elaborate_lnet(des, scope, true);
|
||||
NetNet*lval_sig = pin(0)->elaborate_lnet(des, scope);
|
||||
assert(lval_sig);
|
||||
|
||||
/* Detect the special case that the l-value width exactly
|
||||
@@ -1140,7 +1132,7 @@ void PGModule::elaborate_mod_(Design*des, Module*rmod, NetScope*scope) const
|
||||
assignment, as the port will continuous assign
|
||||
into the port. */
|
||||
|
||||
sig = pins[idx]->elaborate_lnet(des, scope, true);
|
||||
sig = pins[idx]->elaborate_lnet(des, scope);
|
||||
if (sig == 0) {
|
||||
cerr << pins[idx]->get_fileline() << ": error: "
|
||||
<< "Output port expression must support "
|
||||
@@ -1475,7 +1467,7 @@ void PGModule::elaborate_udp_(Design*des, PUdp*udp, NetScope*scope) const
|
||||
<< endl;
|
||||
|
||||
} else {
|
||||
NetNet*sig = pins[0]->elaborate_lnet(des, scope, true);
|
||||
NetNet*sig = pins[0]->elaborate_lnet(des, scope);
|
||||
if (sig == 0) {
|
||||
cerr << get_fileline() << ": error: "
|
||||
<< "Output port expression is not valid." << endl;
|
||||
@@ -1517,6 +1509,10 @@ bool PGModule::elaborate_sig(Design*des, NetScope*scope) const
|
||||
if (mod != pform_modules.end())
|
||||
return elaborate_sig_mod_(des, scope, (*mod).second);
|
||||
|
||||
map<perm_string,PUdp*>::const_iterator udp = pform_primitives.find(type_);
|
||||
if (udp != pform_primitives.end())
|
||||
return elaborate_sig_udp_(des, scope, (*udp).second);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -1715,7 +1711,7 @@ NetProc* PAssign::elaborate(Design*des, NetScope*scope) const
|
||||
netlist. The compound statement is exactly equivalent. */
|
||||
|
||||
if (delay || event_) {
|
||||
unsigned wid = lv->lwidth();
|
||||
unsigned wid = count_lval_width(lv);
|
||||
|
||||
rv->set_width(wid);
|
||||
rv = pad_to_width(rv, wid);
|
||||
@@ -2049,14 +2045,8 @@ NetProc* PCondit::elaborate(Design*des, NetScope*scope) const
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (expr->expr_width() > 1) {
|
||||
assert(expr->expr_width() > 1);
|
||||
verinum zero (verinum::V0, expr->expr_width());
|
||||
NetEConst*ezero = new NetEConst(zero);
|
||||
ezero->set_width(expr->expr_width());
|
||||
NetEBComp*cmp = new NetEBComp('n', expr, ezero);
|
||||
expr = cmp;
|
||||
}
|
||||
// Make sure the condition expression evaluates to a condition.
|
||||
expr = condition_reduce(expr);
|
||||
|
||||
// Well, I actually need to generate code to handle the
|
||||
// conditional, so elaborate.
|
||||
@@ -2947,6 +2937,15 @@ NetProc* PForStatement::elaborate(Design*des, NetScope*scope) const
|
||||
assert(etmp->expr_width() >= lv->lwidth());
|
||||
}
|
||||
|
||||
/* Based on the specific type of the l-value, do cleanup
|
||||
processing on the r-value. */
|
||||
if (etmp->expr_type() != IVL_VT_REAL) {
|
||||
unsigned wid = count_lval_width(lv);
|
||||
etmp->set_width(wid);
|
||||
etmp = pad_to_width(etmp, wid);
|
||||
assert(etmp->expr_width() >= wid);
|
||||
}
|
||||
|
||||
NetAssign*init = new NetAssign(lv, etmp);
|
||||
init->set_line(*this);
|
||||
|
||||
@@ -3272,6 +3271,29 @@ bool PProcess::elaborate(Design*des, NetScope*scope) const
|
||||
verinum(1));
|
||||
} while (0);
|
||||
|
||||
/* If this is an always block and we have no or zero delay then
|
||||
* a runtime infinite loop will happen. If we possible have some
|
||||
* delay then print a warning that an infinite loop is possible.
|
||||
*/
|
||||
if (type() == PProcess::PR_ALWAYS) {
|
||||
DelayType dly_type = top->statement()->delay_type();
|
||||
|
||||
if (dly_type == NO_DELAY || dly_type == ZERO_DELAY) {
|
||||
cerr << get_fileline() << ": error: always statement"
|
||||
<< " does not have any delay." << endl;
|
||||
cerr << get_fileline() << ": : A runtime infinite"
|
||||
<< " loop will occur." << endl;
|
||||
des->errors += 1;
|
||||
return false;
|
||||
|
||||
} else if (dly_type == POSSIBLE_DELAY && warn_inf_loop) {
|
||||
cerr << get_fileline() << ": warning: always statement"
|
||||
<< " may not have any delay." << endl;
|
||||
cerr << get_fileline() << ": : A runtime infinite"
|
||||
<< " loop may be possible." << endl;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -3285,16 +3307,6 @@ void PSpecPath::elaborate(Design*des, NetScope*scope) const
|
||||
if (!gn_specify_blocks_flag)
|
||||
return;
|
||||
|
||||
/* Check for various path types that are not supported. */
|
||||
if (conditional && !condition) {
|
||||
cerr << get_fileline() << ": sorry: ifnone specify paths"
|
||||
<< " are not supported." << endl;
|
||||
cerr << get_fileline() << ": : Use -g no-specify to ignore"
|
||||
<< " specify blocks." << endl;
|
||||
des->errors += 1;
|
||||
return;
|
||||
}
|
||||
|
||||
ivl_assert(*this, conditional || (condition==0));
|
||||
|
||||
ndelays = delays.size();
|
||||
@@ -3326,7 +3338,7 @@ void PSpecPath::elaborate(Design*des, NetScope*scope) const
|
||||
delete cur;
|
||||
}
|
||||
|
||||
switch (ndelays) {
|
||||
switch (delays.size()) {
|
||||
case 1:
|
||||
case 2:
|
||||
case 3:
|
||||
@@ -3335,15 +3347,14 @@ void PSpecPath::elaborate(Design*des, NetScope*scope) const
|
||||
break;
|
||||
default:
|
||||
cerr << get_fileline() << ": error: Incorrect delay configuration."
|
||||
<< endl;
|
||||
<< " Given " << delays.size() << " delay expressions." << endl;
|
||||
ndelays = 1;
|
||||
des->errors += 1;
|
||||
break;
|
||||
}
|
||||
|
||||
NetNet*condit_sig = 0;
|
||||
if (conditional) {
|
||||
ivl_assert(*this, condition);
|
||||
if (conditional && condition) {
|
||||
|
||||
NetExpr*tmp = elab_and_eval(des, scope, condition, -1);
|
||||
ivl_assert(*condition, tmp);
|
||||
@@ -3364,7 +3375,9 @@ void PSpecPath::elaborate(Design*des, NetScope*scope) const
|
||||
cerr << get_fileline() << ": debug: Path to " << (*cur);
|
||||
if (condit_sig)
|
||||
cerr << " if " << condit_sig->name();
|
||||
cerr << endl;
|
||||
else if (conditional)
|
||||
cerr << " ifnone";
|
||||
cerr << " from ";
|
||||
}
|
||||
|
||||
NetNet*dst_sig = scope->find_signal(*cur);
|
||||
@@ -3384,7 +3397,8 @@ void PSpecPath::elaborate(Design*des, NetScope*scope) const
|
||||
}
|
||||
|
||||
NetDelaySrc*path = new NetDelaySrc(scope, scope->local_symbol(),
|
||||
src.size(), condit_sig);
|
||||
src.size(), condit_sig,
|
||||
conditional);
|
||||
path->set_line(*this);
|
||||
|
||||
// The presence of the data_source_expression indicates
|
||||
@@ -3427,6 +3441,11 @@ void PSpecPath::elaborate(Design*des, NetScope*scope) const
|
||||
NetNet*src_sig = scope->find_signal(*cur_src);
|
||||
assert(src_sig);
|
||||
|
||||
if (debug_elaborate) {
|
||||
if (cur_src != src.begin()) cerr << " and ";
|
||||
cerr << src_sig->name();
|
||||
}
|
||||
|
||||
if ( (src_sig->port_type() != NetNet::PINPUT)
|
||||
&& (src_sig->port_type() != NetNet::PINOUT) ) {
|
||||
|
||||
@@ -3439,6 +3458,9 @@ void PSpecPath::elaborate(Design*des, NetScope*scope) const
|
||||
connect(src_sig->pin(0), path->pin(idx));
|
||||
idx += 1;
|
||||
}
|
||||
if (debug_elaborate) {
|
||||
cerr << endl;
|
||||
}
|
||||
|
||||
if (condit_sig)
|
||||
connect(condit_sig->pin(0), path->pin(idx));
|
||||
@@ -3685,6 +3707,7 @@ Design* elaborate(list<perm_string>roots)
|
||||
|
||||
// Make the root scope.
|
||||
NetScope*scope = des->make_root_scope(*root);
|
||||
scope->set_line(rmod);
|
||||
scope->time_unit(rmod->time_unit);
|
||||
scope->time_precision(rmod->time_precision);
|
||||
scope->default_nettype(rmod->default_nettype);
|
||||
|
||||
@@ -49,6 +49,12 @@ bool NetUDP::emit_node(struct target_t*tgt) const
|
||||
return true;
|
||||
}
|
||||
|
||||
bool NetAbs::emit_node(struct target_t*tgt) const
|
||||
{
|
||||
tgt->lpm_abs(this);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool NetAddSub::emit_node(struct target_t*tgt) const
|
||||
{
|
||||
tgt->lpm_add_sub(this);
|
||||
|
||||
+32
-10
@@ -95,12 +95,14 @@ NetExpr* NetEBAdd::eval_tree(int prune_to_width)
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (debug_eval_tree) {
|
||||
cerr << get_fileline() << ": debug: Evaluate expr=" << *this
|
||||
<< " --- prune=" << prune_to_width
|
||||
<< " has_width=" << (has_width()? "true" : "false") << endl;
|
||||
}
|
||||
|
||||
/* Result might have known width. */
|
||||
if (has_width()) {
|
||||
if (debug_eval_tree) {
|
||||
cerr << get_fileline() << ": debug: Evaluate expr=" << *this
|
||||
<< " --- prune=" << prune_to_width << endl;
|
||||
}
|
||||
unsigned lwid = lc->expr_width();
|
||||
unsigned rwid = rc->expr_width();
|
||||
unsigned wid = (rwid > lwid) ? rwid : lwid;
|
||||
@@ -108,6 +110,10 @@ NetExpr* NetEBAdd::eval_tree(int prune_to_width)
|
||||
wid += 1;
|
||||
verinum val2=verinum(val,wid);
|
||||
val=val2;
|
||||
} else {
|
||||
/* No fixed width, so trim the bits losslessly. */
|
||||
verinum val2 = trim_vnum(val);
|
||||
val = val2;
|
||||
}
|
||||
|
||||
return new NetEConst(val);
|
||||
@@ -808,13 +814,18 @@ NetExpr* NetEBDiv::eval_tree(int prune_to_width)
|
||||
verinum lval = lc->value();
|
||||
verinum rval = rc->value();
|
||||
|
||||
NetExpr*tmp = 0;
|
||||
switch (op_) {
|
||||
case '/':
|
||||
return new NetEConst(lval / rval);
|
||||
|
||||
tmp = new NetEConst(lval / rval);
|
||||
break;
|
||||
case '%':
|
||||
return new NetEConst(lval % rval);
|
||||
tmp = new NetEConst(lval % rval);
|
||||
break;
|
||||
}
|
||||
ivl_assert(*this, tmp);
|
||||
tmp->set_line(*this);
|
||||
return tmp;
|
||||
}
|
||||
|
||||
return 0;
|
||||
@@ -919,7 +930,13 @@ NetExpr* NetEBMult::eval_tree(int prune_to_width)
|
||||
verinum lval = lc->value();
|
||||
verinum rval = rc->value();
|
||||
|
||||
return new NetEConst(lval * rval);
|
||||
NetEConst*tmp = new NetEConst(lval * rval);
|
||||
|
||||
if (debug_eval_tree)
|
||||
cerr << get_fileline() << ": debug: Evaluate "
|
||||
<< lval << " * " << rval << " --> " << *tmp << endl;
|
||||
|
||||
return tmp;
|
||||
}
|
||||
|
||||
NetExpr* NetEBPow::eval_tree_real_()
|
||||
@@ -1148,7 +1165,7 @@ NetExpr* NetEParam::eval_tree(int prune_to_width)
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (debug_elaborate) {
|
||||
if (debug_eval_tree) {
|
||||
cerr << get_fileline() << ": debug: evaluating expression: "
|
||||
<< *this << endl;
|
||||
}
|
||||
@@ -1200,7 +1217,12 @@ NetExpr* NetEParam::eval_tree(int prune_to_width)
|
||||
|
||||
// The result can be saved as the value of the parameter for
|
||||
// future reference, and return a copy to the caller.
|
||||
scope_->replace_parameter(name_, res);
|
||||
bool flag = scope_->replace_parameter(name_, res);
|
||||
if (!flag) {
|
||||
cerr << get_fileline() << ": internal error: Could not "
|
||||
<< "replace parameter expression for " << name_ << endl;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Return as a result a NetEConstParam or NetECRealParam
|
||||
object, depending on the type of the expression. */
|
||||
|
||||
+20
-20
@@ -157,46 +157,39 @@ NetNet* NetEBBits::synthesize(Design*des)
|
||||
NetScope*scope = lsig->scope();
|
||||
assert(scope);
|
||||
|
||||
if (lsig->vector_width() != rsig->vector_width()) {
|
||||
cerr << get_fileline() << ": internal error: bitwise (" << op_
|
||||
<< ") widths do not match: " << lsig->vector_width()
|
||||
<< " != " << rsig->vector_width() << endl;
|
||||
cerr << get_fileline() << ": : width="
|
||||
<< lsig->vector_width() << ": " << *left_ << endl;
|
||||
cerr << get_fileline() << ": : width="
|
||||
<< rsig->vector_width() << ": " << *right_ << endl;
|
||||
des->errors += 1;
|
||||
return 0;
|
||||
}
|
||||
unsigned width = lsig->vector_width();
|
||||
if (rsig->vector_width() > width) width = rsig->vector_width();
|
||||
|
||||
lsig = pad_to_width(des, lsig, width);
|
||||
rsig = pad_to_width(des, rsig, width);
|
||||
|
||||
assert(lsig->vector_width() == rsig->vector_width());
|
||||
NetNet*osig = new NetNet(scope, scope->local_symbol(),
|
||||
NetNet::IMPLICIT, lsig->vector_width());
|
||||
NetNet::IMPLICIT, width);
|
||||
osig->local_flag(true);
|
||||
osig->data_type(expr_type());
|
||||
|
||||
perm_string oname = scope->local_symbol();
|
||||
unsigned wid = lsig->vector_width();
|
||||
NetLogic*gate;
|
||||
|
||||
switch (op()) {
|
||||
case '&':
|
||||
gate = new NetLogic(scope, oname, 3, NetLogic::AND, wid);
|
||||
gate = new NetLogic(scope, oname, 3, NetLogic::AND, width);
|
||||
break;
|
||||
case 'A':
|
||||
gate = new NetLogic(scope, oname, 3, NetLogic::NAND, wid);
|
||||
gate = new NetLogic(scope, oname, 3, NetLogic::NAND, width);
|
||||
break;
|
||||
case '|':
|
||||
gate = new NetLogic(scope, oname, 3, NetLogic::OR, wid);
|
||||
gate = new NetLogic(scope, oname, 3, NetLogic::OR, width);
|
||||
break;
|
||||
case '^':
|
||||
gate = new NetLogic(scope, oname, 3, NetLogic::XOR, wid);
|
||||
gate = new NetLogic(scope, oname, 3, NetLogic::XOR, width);
|
||||
break;
|
||||
case 'O':
|
||||
gate = new NetLogic(scope, oname, 3, NetLogic::NOR, wid);
|
||||
gate = new NetLogic(scope, oname, 3, NetLogic::NOR, width);
|
||||
break;
|
||||
case 'X':
|
||||
gate = new NetLogic(scope, oname, 3, NetLogic::XNOR, wid);
|
||||
gate = new NetLogic(scope, oname, 3, NetLogic::XNOR, width);
|
||||
break;
|
||||
default:
|
||||
assert(0);
|
||||
@@ -242,6 +235,8 @@ NetNet* NetEBComp::synthesize(Design*des)
|
||||
osig->local_flag(true);
|
||||
osig->data_type(IVL_VT_LOGIC);
|
||||
|
||||
bool signed_compare = lsig->get_signed() && rsig->get_signed();
|
||||
|
||||
/* 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')) && !real_args) {
|
||||
@@ -281,9 +276,11 @@ NetNet* NetEBComp::synthesize(Design*des)
|
||||
switch (op_) {
|
||||
case '<':
|
||||
connect(dev->pin_ALB(), osig->pin(0));
|
||||
dev->set_signed(signed_compare);
|
||||
break;
|
||||
case '>':
|
||||
connect(dev->pin_AGB(), osig->pin(0));
|
||||
dev->set_signed(signed_compare);
|
||||
break;
|
||||
case 'E': // === ?
|
||||
if (real_args) {
|
||||
@@ -297,9 +294,11 @@ NetNet* NetEBComp::synthesize(Design*des)
|
||||
break;
|
||||
case 'G': // >=
|
||||
connect(dev->pin_AGEB(), osig->pin(0));
|
||||
dev->set_signed(signed_compare);
|
||||
break;
|
||||
case 'L': // <=
|
||||
connect(dev->pin_ALEB(), osig->pin(0));
|
||||
dev->set_signed(signed_compare);
|
||||
break;
|
||||
case 'N': // !==
|
||||
if (real_args) {
|
||||
@@ -439,7 +438,7 @@ NetNet* NetEBDiv::synthesize(Design*des)
|
||||
case '%': {
|
||||
/* Baseline Verilog does not support the % operator with
|
||||
real arguments, but we allow it in our extended form. */
|
||||
if (real_args && generation_flag < GN_VER2001X) {
|
||||
if (real_args && !gn_icarus_misc_flag) {
|
||||
cerr << get_fileline() << ": error: Modulus operator "
|
||||
"may not have REAL operands." << endl;
|
||||
des->errors += 1;
|
||||
@@ -930,6 +929,7 @@ NetNet* NetESelect::synthesize(Design *des)
|
||||
|
||||
connect(pad->pin(1), sub->pin(0));
|
||||
connect(pad->pin(0), net->pin(0));
|
||||
net->set_signed(true);
|
||||
|
||||
} else {
|
||||
|
||||
|
||||
@@ -40,6 +40,10 @@ void functor_t::process(class Design*, class NetProcTop*)
|
||||
{
|
||||
}
|
||||
|
||||
void functor_t::lpm_abs(class Design*, class NetAbs*)
|
||||
{
|
||||
}
|
||||
|
||||
void functor_t::lpm_add_sub(class Design*, class NetAddSub*)
|
||||
{
|
||||
}
|
||||
@@ -174,6 +178,11 @@ void NetNode::functor_node(Design*, functor_t*)
|
||||
{
|
||||
}
|
||||
|
||||
void NetAbs::functor_node(Design*des, functor_t*fun)
|
||||
{
|
||||
fun->lpm_abs(des, this);
|
||||
}
|
||||
|
||||
void NetAddSub::functor_node(Design*des, functor_t*fun)
|
||||
{
|
||||
fun->lpm_add_sub(des, this);
|
||||
|
||||
@@ -48,6 +48,9 @@ struct functor_t {
|
||||
/* This method is called for each process in the design. */
|
||||
virtual void process(class Design*des, class NetProcTop*);
|
||||
|
||||
/* This method is called for each structural abs(). */
|
||||
virtual void lpm_abs(class Design*des, class NetAbs*);
|
||||
|
||||
/* This method is called for each structural adder. */
|
||||
virtual void lpm_add_sub(class Design*des, class NetAddSub*);
|
||||
|
||||
|
||||
@@ -118,9 +118,12 @@ ivl_nexus_ptr_sig
|
||||
|
||||
ivl_parameter_basename
|
||||
ivl_parameter_expr
|
||||
ivl_parameter_file
|
||||
ivl_parameter_lineno
|
||||
|
||||
ivl_path_condit
|
||||
ivl_path_delay
|
||||
ivl_path_is_condit
|
||||
ivl_path_scope
|
||||
ivl_path_source
|
||||
ivl_path_source_negedge
|
||||
@@ -131,8 +134,12 @@ ivl_scope_attr_val
|
||||
ivl_scope_basename
|
||||
ivl_scope_children
|
||||
ivl_scope_def
|
||||
ivl_scope_def_file
|
||||
ivl_scope_def_lineno
|
||||
ivl_scope_event
|
||||
ivl_scope_events
|
||||
ivl_scope_file
|
||||
ivl_scope_lineno
|
||||
ivl_scope_logs
|
||||
ivl_scope_log
|
||||
ivl_scope_lpms
|
||||
@@ -158,7 +165,9 @@ ivl_signal_attr_val
|
||||
ivl_signal_basename
|
||||
ivl_signal_data_type
|
||||
ivl_signal_dimensions
|
||||
ivl_signal_file
|
||||
ivl_signal_integer
|
||||
ivl_signal_lineno
|
||||
ivl_signal_local
|
||||
ivl_signal_lsb
|
||||
ivl_signal_msb
|
||||
|
||||
@@ -228,6 +228,7 @@ typedef enum ivl_logic_e {
|
||||
|
||||
/* This is the type of an LPM object. */
|
||||
typedef enum ivl_lpm_type_e {
|
||||
IVL_LPM_ABS = 32,
|
||||
IVL_LPM_ADD = 0,
|
||||
IVL_LPM_ARRAY = 30,
|
||||
IVL_LPM_CONCAT = 16,
|
||||
@@ -395,6 +396,8 @@ typedef const struct ivl_attribute_s*ivl_attribute_t;
|
||||
* ivl_path_condit
|
||||
* This returns the nexus that tracks the condition for the
|
||||
* delay. If the delay path is unconditional, this returns nil.
|
||||
* ivl_path_is_condit
|
||||
* Is this a conditional structure? Needed for ifnone.
|
||||
*
|
||||
* ivl_path_source_posedge
|
||||
* ivl_path_source_negedge
|
||||
@@ -404,6 +407,7 @@ extern ivl_scope_t ivl_path_scope(ivl_delaypath_t obj);
|
||||
extern ivl_nexus_t ivl_path_source(ivl_delaypath_t obj);
|
||||
extern uint64_t ivl_path_delay(ivl_delaypath_t obj, ivl_path_edge_t pt);
|
||||
extern ivl_nexus_t ivl_path_condit(ivl_delaypath_t obj);
|
||||
extern int ivl_path_is_condit(ivl_delaypath_t obj);
|
||||
|
||||
extern int ivl_path_source_posedge(ivl_delaypath_t obj);
|
||||
extern int ivl_path_source_negedge(ivl_delaypath_t obj);
|
||||
@@ -1336,11 +1340,18 @@ extern ivl_signal_t ivl_nexus_ptr_sig(ivl_nexus_ptr_t net);
|
||||
* ivl_parameter_expr
|
||||
* Return the value of the parameter. This should be a simple
|
||||
* constant expression, an IVL_EX_STRING or IVL_EX_NUMBER.
|
||||
*
|
||||
* ivl_parameter_file
|
||||
* ivl_parameter_lineno
|
||||
* Returns the file and line where this parameter is define
|
||||
*/
|
||||
extern const char* ivl_parameter_basename(ivl_parameter_t net);
|
||||
extern ivl_scope_t ivl_parameter_scope(ivl_parameter_t net);
|
||||
extern ivl_expr_t ivl_parameter_expr(ivl_parameter_t net);
|
||||
|
||||
extern const char* ivl_parameter_file(ivl_parameter_t net);
|
||||
extern unsigned ivl_parameter_lineno(ivl_parameter_t net);
|
||||
|
||||
|
||||
/* SCOPE
|
||||
* Scopes of various sort have these properties. Use these methods to
|
||||
@@ -1388,10 +1399,18 @@ extern ivl_expr_t ivl_parameter_expr(ivl_parameter_t net);
|
||||
* ivl_scope_def function must return a statement for scopes that
|
||||
* are type FUNCTION or TASK, and must return nil otherwise.
|
||||
*
|
||||
* ivl_scope_def_file
|
||||
* ivl_scope_def_lineno
|
||||
* Returns the file and line where this scope is defined.
|
||||
*
|
||||
* ivl_scope_event
|
||||
* ivl_scope_events
|
||||
* Scopes have 0 or more event objects in them.
|
||||
*
|
||||
* ivl_scope_file
|
||||
* ivl_scope_lineno
|
||||
* Returns the instantiation file and line for this scope.
|
||||
*
|
||||
* ivl_scope_var
|
||||
* ivl_scope_vars
|
||||
* REMOVED
|
||||
@@ -1462,9 +1481,13 @@ extern int ivl_scope_children(ivl_scope_t net,
|
||||
ivl_scope_f func, void*cd);
|
||||
|
||||
extern ivl_statement_t ivl_scope_def(ivl_scope_t net);
|
||||
extern const char* ivl_scope_def_file(ivl_scope_t net);
|
||||
extern unsigned ivl_scope_def_lineno(ivl_scope_t net);
|
||||
|
||||
extern unsigned ivl_scope_events(ivl_scope_t net);
|
||||
extern ivl_event_t ivl_scope_event(ivl_scope_t net, unsigned idx);
|
||||
extern const char* ivl_scope_file(ivl_scope_t net);
|
||||
extern unsigned ivl_scope_lineno(ivl_scope_t net);
|
||||
extern unsigned ivl_scope_logs(ivl_scope_t net);
|
||||
extern ivl_net_logic_t ivl_scope_log(ivl_scope_t net, unsigned idx);
|
||||
extern unsigned ivl_scope_lpms(ivl_scope_t net);
|
||||
@@ -1571,6 +1594,10 @@ extern int ivl_scope_time_units(ivl_scope_t net);
|
||||
* the attribute value (a string) associated with a key. This
|
||||
* function returns the attribute value for the given key. If the
|
||||
* key does not exist, the function returns 0.
|
||||
*
|
||||
* ivl_signal_file
|
||||
* ivl_signal_lineno
|
||||
* Returns the file and line where this signal is defined.
|
||||
*/
|
||||
|
||||
extern ivl_nexus_t ivl_signal_nex(ivl_signal_t net, unsigned word);
|
||||
@@ -1592,6 +1619,9 @@ extern const char* ivl_signal_name(ivl_signal_t net);
|
||||
extern const char* ivl_signal_basename(ivl_signal_t net);
|
||||
extern const char* ivl_signal_attr(ivl_signal_t net, const char*key);
|
||||
|
||||
extern const char* ivl_signal_file(ivl_signal_t net);
|
||||
extern unsigned ivl_signal_lineno(ivl_signal_t net);
|
||||
|
||||
extern unsigned ivl_signal_attr_cnt(ivl_signal_t net);
|
||||
extern ivl_attribute_t ivl_signal_attr_val(ivl_signal_t net, unsigned idx);
|
||||
|
||||
|
||||
+68
-25
@@ -1,6 +1,6 @@
|
||||
%{
|
||||
/*
|
||||
* Copyright (c) 1999-2007 Stephen Williams ([email protected])
|
||||
* Copyright (c) 1999-2008 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
|
||||
@@ -42,7 +42,7 @@ static void do_define();
|
||||
static int def_is_done();
|
||||
static int is_defined(const char*name);
|
||||
|
||||
static int macro_needs_args();
|
||||
static int macro_needs_args(const char*name);
|
||||
static void macro_start_args();
|
||||
static void macro_add_to_arg();
|
||||
static void macro_finish_arg();
|
||||
@@ -72,6 +72,8 @@ struct include_stack_t
|
||||
*/
|
||||
int ebs;
|
||||
|
||||
int stringify_flag;
|
||||
|
||||
unsigned lineno;
|
||||
YY_BUFFER_STATE yybs;
|
||||
|
||||
@@ -86,6 +88,8 @@ static void emit_pathline(struct include_stack_t* isp);
|
||||
*/
|
||||
static struct include_stack_t* file_queue = 0;
|
||||
|
||||
static int do_expand_stringify_flag = 0;
|
||||
|
||||
/*
|
||||
* The istack is the inclusion stack.
|
||||
*/
|
||||
@@ -245,7 +249,7 @@ keywords (include|define|undef|ifdef|ifndef|else|elseif|endif)
|
||||
}
|
||||
|
||||
<PCOMENT>`[a-zA-Z][a-zA-Z0-9_$]* {
|
||||
if (macro_needs_args()) yy_push_state(MA_START); else do_expand(0);
|
||||
if (macro_needs_args(yytext+1)) yy_push_state(MA_START); else do_expand(0);
|
||||
}
|
||||
|
||||
/* Strings do not contain preprocessor directives, but can expand
|
||||
@@ -262,21 +266,6 @@ keywords (include|define|undef|ifdef|ifndef|else|elseif|endif)
|
||||
<CSTRING>\" { BEGIN(string_enter); ECHO; }
|
||||
<CSTRING>. { ECHO; }
|
||||
|
||||
<CSTRING>`{keywords} {
|
||||
emit_pathline(istack);
|
||||
error_count += 1;
|
||||
fprintf
|
||||
(
|
||||
stderr,
|
||||
"error: macro names cannot be directive keywords ('%s'); replaced with nothing.\n",
|
||||
yytext
|
||||
);
|
||||
}
|
||||
|
||||
<CSTRING>`[a-zA-Z][a-zA-Z0-9_$]* {
|
||||
if (macro_needs_args()) yy_push_state(MA_START); else do_expand(0);
|
||||
}
|
||||
|
||||
/* This set of patterns matches the include directive and the name
|
||||
* that follows it. when the directive ends, the do_include function
|
||||
* performs the include operation.
|
||||
@@ -295,7 +284,7 @@ keywords (include|define|undef|ifdef|ifndef|else|elseif|endif)
|
||||
}
|
||||
|
||||
<PPINCLUDE>`[a-zA-Z][a-zA-Z0-9_]* {
|
||||
if (macro_needs_args()) yy_push_state(MA_START); else do_expand(0);
|
||||
if (macro_needs_args(yytext+1)) yy_push_state(MA_START); else do_expand(0);
|
||||
}
|
||||
|
||||
<PPINCLUDE>\"[^\"]*\" { include_filename(); }
|
||||
@@ -551,12 +540,23 @@ keywords (include|define|undef|ifdef|ifndef|else|elseif|endif)
|
||||
|
||||
/* This pattern notices macros and arranges for them to be replaced. */
|
||||
`[a-zA-Z_][a-zA-Z0-9_$]* {
|
||||
if (macro_needs_args())
|
||||
if (macro_needs_args(yytext+1))
|
||||
yy_push_state(MA_START);
|
||||
else
|
||||
do_expand(0);
|
||||
}
|
||||
|
||||
/* Stringified version of macro expansion. */
|
||||
``[a-zA-Z_][a-zA-Z0-9_$]* {
|
||||
assert(do_expand_stringify_flag == 0);
|
||||
do_expand_stringify_flag = 1;
|
||||
fputc('"', yyout);
|
||||
if (macro_needs_args(yytext+2))
|
||||
yy_push_state(MA_START);
|
||||
else
|
||||
do_expand(0);
|
||||
}
|
||||
|
||||
<MA_START>\( { BEGIN(MA_ADD); macro_start_args(); }
|
||||
|
||||
<MA_START>{W} {}
|
||||
@@ -849,6 +849,34 @@ static int define_continue_flag = 0;
|
||||
#define _STR1(x) #x
|
||||
#define _STR2(x) _STR1(x)
|
||||
|
||||
/*
|
||||
* Find an argument, but only if it is not directly preceded by something
|
||||
* that would make it part of another simple identifier ([a-zA-Z0-9_$]).
|
||||
*/
|
||||
static char *find_arg(char*ptr, char*head, char*arg)
|
||||
{
|
||||
char *cp = ptr;
|
||||
|
||||
while (1) {
|
||||
/* Look for a candidate match, just return if none is found. */
|
||||
cp = strstr(cp, arg);
|
||||
if (!cp) break;
|
||||
|
||||
/* If we are not at the start of the string verify that this
|
||||
* match is not in the middle of another identifier.
|
||||
*/
|
||||
if (cp != head &&
|
||||
(isalnum(*(cp-1)) || *(cp-1) == '_' || *(cp-1) == '$')) {
|
||||
cp++;
|
||||
continue;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
return cp;
|
||||
}
|
||||
|
||||
/*
|
||||
* Collect the definition. Normally, this returns 0. If there is a
|
||||
* continuation, then return 1 and this function may be called again
|
||||
@@ -968,7 +996,7 @@ static void do_define()
|
||||
{
|
||||
int argl = def_argl[arg];
|
||||
|
||||
cp = strstr(head, def_argv(arg));
|
||||
cp = find_arg(head, head, def_argv(arg));
|
||||
|
||||
while (cp && *cp)
|
||||
{
|
||||
@@ -994,7 +1022,7 @@ static void do_define()
|
||||
|
||||
*cp++ = ARG_MARK;
|
||||
*cp++ = arg;
|
||||
cp = strstr(cp, def_argv(arg));
|
||||
cp = find_arg(cp, head, def_argv(arg));
|
||||
}
|
||||
}
|
||||
define_cnt += added_cnt;
|
||||
@@ -1143,16 +1171,16 @@ static void def_undefine()
|
||||
*/
|
||||
static struct define_t* cur_macro = 0;
|
||||
|
||||
static int macro_needs_args()
|
||||
static int macro_needs_args(const char*text)
|
||||
{
|
||||
cur_macro = def_lookup(yytext+1);
|
||||
cur_macro = def_lookup(text);
|
||||
|
||||
if (cur_macro)
|
||||
return (cur_macro->argc > 1);
|
||||
else
|
||||
{
|
||||
emit_pathline(istack);
|
||||
fprintf(stderr, "warning: macro %s undefined (and assumed null) at this point.\n", yytext);
|
||||
fprintf(stderr, "warning: macro %s undefined (and assumed null) at this point.\n", text);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
@@ -1320,6 +1348,8 @@ static void do_expand(int use_args)
|
||||
|
||||
isp = (struct include_stack_t*) calloc(1, sizeof(struct include_stack_t));
|
||||
|
||||
isp->stringify_flag = do_expand_stringify_flag;
|
||||
do_expand_stringify_flag = 0;
|
||||
if (use_args)
|
||||
{
|
||||
isp->str = &exp_buf[head];
|
||||
@@ -1336,6 +1366,11 @@ static void do_expand(int use_args)
|
||||
istack = isp;
|
||||
|
||||
yy_switch_to_buffer(yy_create_buffer(istack->file, YY_BUF_SIZE));
|
||||
} else {
|
||||
if (do_expand_stringify_flag) {
|
||||
do_expand_stringify_flag = 0;
|
||||
fputc('"', yyout);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1436,6 +1471,7 @@ static void do_include()
|
||||
fprintf(yyout, "\n`line %u \"%s\" 1\n", istack->lineno+1, standby->path);
|
||||
|
||||
standby->next = istack;
|
||||
standby->stringify_flag = 0;
|
||||
|
||||
istack->yybs = YY_CURRENT_BUFFER;
|
||||
istack = standby;
|
||||
@@ -1509,6 +1545,10 @@ static int load_next_input()
|
||||
exp_buf_free += isp->ebs;
|
||||
}
|
||||
|
||||
if (isp->stringify_flag) {
|
||||
fputc('"', yyout);
|
||||
}
|
||||
|
||||
free(isp);
|
||||
|
||||
/* If I am out of include stack, the main input is
|
||||
@@ -1607,6 +1647,8 @@ void load_precompiled_defines(FILE* src)
|
||||
|
||||
name = cp;
|
||||
|
||||
*cp++ = ch;
|
||||
|
||||
while ((ch = fgetc(src)) != EOF && ch != ':')
|
||||
*cp++ = ch;
|
||||
|
||||
@@ -1669,6 +1711,7 @@ void reset_lexor(FILE* out, char* paths[])
|
||||
isp->str = 0;
|
||||
isp->ebs = 0;
|
||||
isp->lineno = 0;
|
||||
isp->stringify_flag = 0;
|
||||
|
||||
if (isp->file == 0)
|
||||
{
|
||||
|
||||
+22
-18
@@ -1,5 +1,5 @@
|
||||
const char COPYRIGHT[] =
|
||||
"Copyright (c) 1999-2007 Stephen Williams ([email protected])";
|
||||
"Copyright (c) 1999-2008 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
|
||||
@@ -202,23 +202,27 @@ int main(int argc, char*argv[])
|
||||
FILE*precomp_out = NULL;
|
||||
|
||||
/* Define preprocessor keywords that I plan to just pass. */
|
||||
define_macro("celldefine", "`celldefine", 1, 0);
|
||||
define_macro("default_nettype", "`default_nettype", 1, 0);
|
||||
define_macro("delay_mode_distributed", "`delay_mode_distributed", 1, 0);
|
||||
define_macro("delay_mode_unit", "`delay_mode_unit", 1, 0);
|
||||
define_macro("delay_mode_path", "`delay_mode_path", 1, 0);
|
||||
define_macro("disable_portfaults", "`disable_portfaults", 1, 0);
|
||||
define_macro("enable_portfaults", "`enable_portfaults", 1, 0);
|
||||
define_macro("endcelldefine", "`endcelldefine", 1, 0);
|
||||
define_macro("endprotect", "`endprotect", 1, 0);
|
||||
define_macro("nosuppress_faults", "`nosuppress_faults", 1, 0);
|
||||
define_macro("nounconnected_drive", "`nounconnected_drive", 1, 0);
|
||||
define_macro("protect", "`protect", 1, 0);
|
||||
define_macro("resetall", "`resetall", 1, 0);
|
||||
define_macro("suppress_faults", "`suppress_faults", 1, 0);
|
||||
define_macro("timescale", "`timescale", 1, 0);
|
||||
define_macro("unconnected_drive", "`unconnected_drive", 1, 0);
|
||||
define_macro("uselib", "`uselib", 1, 0);
|
||||
define_macro("celldefine", "`celldefine", 1, 0);
|
||||
define_macro("default_decay_time", "`default_decay_time", 1, 0);
|
||||
define_macro("default_nettype", "`default_nettype", 1, 0);
|
||||
define_macro("default_trireg_strength", "`default_trireg_strength", 1, 0);
|
||||
define_macro("delay_mode_distributed", "`delay_mode_distributed", 1, 0);
|
||||
define_macro("delay_mode_unit", "`delay_mode_unit", 1, 0);
|
||||
define_macro("delay_mode_path", "`delay_mode_path", 1, 0);
|
||||
define_macro("delay_mode_zero", "`delay_mode_zero", 1, 0);
|
||||
define_macro("disable_portfaults", "`disable_portfaults", 1, 0);
|
||||
define_macro("enable_portfaults", "`enable_portfaults", 1, 0);
|
||||
define_macro("endcelldefine", "`endcelldefine", 1, 0);
|
||||
define_macro("endprotect", "`endprotect", 1, 0);
|
||||
define_macro("line", "`line", 1, 0);
|
||||
define_macro("nosuppress_faults", "`nosuppress_faults", 1, 0);
|
||||
define_macro("nounconnected_drive", "`nounconnected_drive", 1, 0);
|
||||
define_macro("protect", "`protect", 1, 0);
|
||||
define_macro("resetall", "`resetall", 1, 0);
|
||||
define_macro("suppress_faults", "`suppress_faults", 1, 0);
|
||||
define_macro("timescale", "`timescale", 1, 0);
|
||||
define_macro("unconnected_drive", "`unconnected_drive", 1, 0);
|
||||
define_macro("uselib", "`uselib", 1, 0);
|
||||
|
||||
include_cnt = 2;
|
||||
include_dir = malloc(include_cnt*sizeof(char*));
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
|
||||
%{
|
||||
/*
|
||||
* Copyright (c) 1998-2007 Stephen Williams ([email protected])
|
||||
* Copyright (c) 1998-2008 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
|
||||
@@ -34,7 +34,7 @@
|
||||
# include <ctype.h>
|
||||
# include <string.h>
|
||||
# include "lexor_keyword.h"
|
||||
|
||||
# include <list>
|
||||
|
||||
# define YY_USER_INIT reset_lexor();
|
||||
# define yylval VLlval
|
||||
@@ -48,6 +48,11 @@
|
||||
*/
|
||||
extern YYLTYPE yylloc;
|
||||
|
||||
static char* strdupnew(char const *str)
|
||||
{
|
||||
return str ? strcpy(new char [strlen(str)+1], str) : 0;
|
||||
}
|
||||
|
||||
static const char* set_file_name(char*text)
|
||||
{
|
||||
perm_string path = filename_strings.make(text);
|
||||
@@ -78,6 +83,8 @@ static int dec_buf_div2(char *buf);
|
||||
|
||||
static void process_timescale(const char*txt);
|
||||
|
||||
static list<int> keyword_mask_stack;
|
||||
|
||||
static int comment_enter;
|
||||
%}
|
||||
|
||||
@@ -88,10 +95,14 @@ static int comment_enter;
|
||||
%s UDPTABLE
|
||||
%x PPTIMESCALE
|
||||
%x PPDEFAULT_NETTYPE
|
||||
%x PPBEGIN_KEYWORDS
|
||||
%s EDGES
|
||||
%x REAL_SCALE
|
||||
|
||||
W [ \t\b\f\r]+
|
||||
|
||||
S [afpnumkKMGT]
|
||||
|
||||
%%
|
||||
|
||||
^"#line"[ ]+\"[^\"]*\"[ ]+[0-9]+.* { line_directive(); }
|
||||
@@ -205,22 +216,11 @@ W [ \t\b\f\r]+
|
||||
int rc = lexor_keyword_code(yytext, yyleng);
|
||||
switch (rc) {
|
||||
case IDENTIFIER:
|
||||
yylval.text = strdup(yytext);
|
||||
yylval.text = strdupnew(yytext);
|
||||
if (strncmp(yylval.text,"PATHPULSE$", 10) == 0)
|
||||
rc = PATHPULSE_IDENTIFIER;
|
||||
break;
|
||||
|
||||
case K_bool:
|
||||
case K_logic:
|
||||
case K_wone:
|
||||
if (! gn_cadence_types_enabled()) {
|
||||
yylval.text = strdup(yytext);
|
||||
rc = IDENTIFIER;
|
||||
} else {
|
||||
yylval.text = 0;
|
||||
}
|
||||
break;
|
||||
|
||||
case K_edge:
|
||||
BEGIN(EDGES);
|
||||
break;
|
||||
@@ -235,7 +235,7 @@ W [ \t\b\f\r]+
|
||||
|
||||
|
||||
\\[^ \t\b\f\r\n]+ {
|
||||
yylval.text = strdup(yytext+1);
|
||||
yylval.text = strdupnew(yytext+1);
|
||||
return IDENTIFIER; }
|
||||
|
||||
\$([a-zA-Z0-9$_]+) {
|
||||
@@ -255,7 +255,7 @@ W [ \t\b\f\r]+
|
||||
return K_Ssetup;
|
||||
if (strcmp(yytext,"$width") == 0)
|
||||
return K_Swidth;
|
||||
yylval.text = strdup(yytext);
|
||||
yylval.text = strdupnew(yytext);
|
||||
return SYSTEM_IDENTIFIER; }
|
||||
|
||||
|
||||
@@ -275,6 +275,46 @@ W [ \t\b\f\r]+
|
||||
based_size = yylval.number->as_ulong();
|
||||
return DEC_NUMBER; }
|
||||
|
||||
/* These rules handle the scaled real literals from Verilog-AMS. The
|
||||
value is a number with a single letter scale factor. If
|
||||
verilog-ams is not enabled, then reject this rule. If it is
|
||||
enabled, then collect the scale and use it to scale the value. */
|
||||
[0-9][0-9_]*\.[0-9][0-9_]*/{S} {
|
||||
if (!gn_verilog_ams_flag) REJECT;
|
||||
BEGIN(REAL_SCALE);
|
||||
yymore(); }
|
||||
|
||||
[0-9][0-9_]*/{S} {
|
||||
if (!gn_verilog_ams_flag) REJECT;
|
||||
BEGIN(REAL_SCALE);
|
||||
yymore(); }
|
||||
|
||||
<REAL_SCALE>{S} {
|
||||
size_t token_len = strlen(yytext);
|
||||
char*tmp = new char[token_len + 5];
|
||||
int scale = 0;
|
||||
strcpy(tmp, yytext);
|
||||
switch (tmp[token_len-1]) {
|
||||
case 'a': scale = -18; break; /* atto- */
|
||||
case 'f': scale = -15; break; /* femto- */
|
||||
case 'p': scale = -12; break; /* pico- */
|
||||
case 'n': scale = -9; break; /* nano- */
|
||||
case 'u': scale = -6; break; /* micro- */
|
||||
case 'm': scale = -3; break; /* milli- */
|
||||
case 'k': scale = 3; break; /* kilo- */
|
||||
case 'K': scale = 3; break; /* kilo- */
|
||||
case 'M': scale = 6; break; /* mega- */
|
||||
case 'G': scale = 9; break; /* giga- */
|
||||
case 'T': scale = 12; break; /* tera- */
|
||||
default: assert(0); break;
|
||||
}
|
||||
snprintf(tmp+token_len-1, 5, "e%d", scale);
|
||||
yylval.realtime = new verireal(tmp);
|
||||
delete[]tmp;
|
||||
|
||||
BEGIN(0);
|
||||
return REALTIME; }
|
||||
|
||||
[0-9][0-9_]*\.[0-9][0-9_]*([Ee][+-]?[0-9][0-9_]*)? {
|
||||
yylval.realtime = new verireal(yytext);
|
||||
return REALTIME; }
|
||||
@@ -296,21 +336,76 @@ W [ \t\b\f\r]+
|
||||
/* These are directives that I do not yet support. I think that IVL
|
||||
should handle these, not an external preprocessor. */
|
||||
|
||||
^{W}?`celldefine{W}?.* { }
|
||||
^{W}?`celldefine{W}?.* { }
|
||||
^{W}?`default_decay_time{W}?.* { }
|
||||
^{W}?`default_trireg_strength{W}?.* { }
|
||||
^{W}?`delay_mode_distributed{W}?.* { }
|
||||
^{W}?`delay_mode_unit{W}?.* { }
|
||||
^{W}?`delay_mode_path{W}?.* { }
|
||||
^{W}?`disable_portfaults{W}?.* { }
|
||||
^{W}?`enable_portfaults{W}?.* { }
|
||||
^{W}?`endcelldefine{W}?.* { }
|
||||
`endprotect { }
|
||||
^{W}?`nosuppress_faults{W}?.* { }
|
||||
^{W}?`nounconnected_drive{W}?.* { }
|
||||
`protect { }
|
||||
^{W}?`resetall{W}?.* { }
|
||||
^{W}?`suppress_faults{W}?.* { }
|
||||
^{W}?`unconnected_drive{W}?.* { }
|
||||
^{W}?`uselib{W}?.* { }
|
||||
^{W}?`delay_mode_unit{W}?.* { }
|
||||
^{W}?`delay_mode_path{W}?.* { }
|
||||
^{W}?`delay_mode_zero{W}?.* { }
|
||||
^{W}?`disable_portfaults{W}?.* { }
|
||||
^{W}?`enable_portfaults{W}?.* { }
|
||||
^{W}?`endcelldefine{W}?.* { }
|
||||
`endprotect { }
|
||||
^{W}?`line{W}?.* { }
|
||||
^{W}?`nosuppress_faults{W}?.* { }
|
||||
^{W}?`nounconnected_drive{W}?.* { }
|
||||
`protect { }
|
||||
^{W}?`resetall{W}?.* { }
|
||||
^{W}?`suppress_faults{W}?.* { }
|
||||
^{W}?`unconnected_drive{W}?.* { }
|
||||
^{W}?`uselib{W}?.* { }
|
||||
|
||||
^{W}?`begin_keywords{W}? { BEGIN(PPBEGIN_KEYWORDS); }
|
||||
|
||||
<PPBEGIN_KEYWORDS>\"[a-zA-Z0-9 -]*\".* {
|
||||
keyword_mask_stack.push_front(lexor_keyword_mask);
|
||||
|
||||
char*word = yytext+1;
|
||||
char*tail = strchr(word, '"');
|
||||
tail[0] = 0;
|
||||
if (strcmp(word,"1364-1995") == 0) {
|
||||
lexor_keyword_mask = GN_KEYWORDS_1364_1995;
|
||||
} else if (strcmp(word,"1364-2001") == 0) {
|
||||
lexor_keyword_mask = GN_KEYWORDS_1364_1995
|
||||
|GN_KEYWORDS_1364_2001
|
||||
|GN_KEYWORDS_1364_2001_CONFIG;
|
||||
} else if (strcmp(word,"1364-2001-noconfig") == 0) {
|
||||
lexor_keyword_mask = GN_KEYWORDS_1364_1995
|
||||
|GN_KEYWORDS_1364_2001;
|
||||
} else if (strcmp(word,"1364-2005") == 0) {
|
||||
lexor_keyword_mask = GN_KEYWORDS_1364_1995
|
||||
|GN_KEYWORDS_1364_2001
|
||||
|GN_KEYWORDS_1364_2001_CONFIG
|
||||
|GN_KEYWORDS_1364_2005;
|
||||
} else if (strcmp(word,"VAMS-2.3") == 0) {
|
||||
lexor_keyword_mask = GN_KEYWORDS_1364_1995
|
||||
|GN_KEYWORDS_1364_2001
|
||||
|GN_KEYWORDS_1364_2001_CONFIG
|
||||
|GN_KEYWORDS_1364_2005
|
||||
|GN_KEYWORDS_VAMS_2_3;
|
||||
} else {
|
||||
fprintf(stderr, "%s:%d: Ignoring unknown keywords string: %s\n",
|
||||
yylloc.text, yylloc.first_line, word);
|
||||
}
|
||||
BEGIN(0);
|
||||
}
|
||||
|
||||
<PPBEGIN_KEYWORDS>.* {
|
||||
fprintf(stderr, "%s:%d: Malformed keywords specification: %s\n",
|
||||
yylloc.text, yylloc.first_line, yytext);
|
||||
BEGIN(0);
|
||||
}
|
||||
|
||||
^{W}?`end_keywords{W}?.* {
|
||||
if (!keyword_mask_stack.empty()) {
|
||||
lexor_keyword_mask = keyword_mask_stack.front();
|
||||
keyword_mask_stack.pop_front();
|
||||
} else {
|
||||
fprintf(stderr, "%s:%d: Mismatched end_keywords directive\n",
|
||||
yylloc.text, yylloc.first_line);
|
||||
}
|
||||
}
|
||||
|
||||
/* Notice and handle the default_nettype directive. The lexor
|
||||
detects the default_nettype keyword, and the second part of the
|
||||
@@ -978,5 +1073,5 @@ void reset_lexor()
|
||||
yylloc.first_line = 1;
|
||||
|
||||
/* Announce the first file name. */
|
||||
yylloc.text = set_file_name(strdup(vl_file.c_str()));
|
||||
yylloc.text = set_file_name(strdupnew(vl_file.c_str()));
|
||||
}
|
||||
|
||||
+140
-111
@@ -6,127 +6,156 @@
|
||||
#include "parse.h"
|
||||
#include <string.h>
|
||||
#include "lexor_keyword.h"
|
||||
#include "compiler.h"
|
||||
|
||||
%}
|
||||
struct lexor_keyword { const char*name; int tokenType; };
|
||||
struct lexor_keyword { const char*name; int mask; int tokenType; };
|
||||
%%
|
||||
always, K_always
|
||||
and, K_and
|
||||
assign, K_assign
|
||||
begin, K_begin
|
||||
bool, K_bool
|
||||
buf, K_buf
|
||||
bufif0, K_bufif0
|
||||
bufif1, K_bufif1
|
||||
case, K_case
|
||||
casex, K_casex
|
||||
casez, K_casez
|
||||
cmos, K_cmos
|
||||
deassign, K_deassign
|
||||
default, K_default
|
||||
defparam, K_defparam
|
||||
disable, K_disable
|
||||
edge, K_edge
|
||||
else, K_else
|
||||
end, K_end
|
||||
endcase, K_endcase
|
||||
endfunction, K_endfunction
|
||||
endgenerate, K_endgenerate
|
||||
endmodule, K_endmodule
|
||||
endprimitive, K_endprimitive
|
||||
endspecify, K_endspecify
|
||||
endtable, K_endtable
|
||||
endtask, K_endtask
|
||||
event, K_event
|
||||
for, K_for
|
||||
force, K_force
|
||||
forever, K_forever
|
||||
fork, K_fork
|
||||
function, K_function
|
||||
generate, K_generate
|
||||
genvar, K_genvar
|
||||
highz0, K_highz0
|
||||
highz1, K_highz1
|
||||
if, K_if
|
||||
ifnone, K_ifnone
|
||||
initial, K_initial
|
||||
inout, K_inout
|
||||
input, K_input
|
||||
integer, K_integer
|
||||
join, K_join
|
||||
large, K_large
|
||||
localparam, K_localparam
|
||||
logic, K_logic
|
||||
macromodule, K_macromodule
|
||||
medium, K_medium
|
||||
module, K_module
|
||||
nand, K_nand
|
||||
negedge, K_negedge
|
||||
nmos, K_nmos
|
||||
nor, K_nor
|
||||
not, K_not
|
||||
notif0, K_notif0
|
||||
notif1, K_notif1
|
||||
or, K_or
|
||||
output, K_output
|
||||
parameter, K_parameter
|
||||
pmos, K_pmos
|
||||
posedge, K_posedge
|
||||
primitive, K_primitive
|
||||
pull0, K_pull0
|
||||
pull1, K_pull1
|
||||
pulldown, K_pulldown
|
||||
pullup, K_pullup
|
||||
rcmos, K_rcmos
|
||||
real, K_real
|
||||
realtime, K_realtime
|
||||
reg, K_reg
|
||||
release, K_release
|
||||
repeat, K_repeat
|
||||
rnmos, K_rnmos
|
||||
rpmos, K_rpmos
|
||||
rtran, K_rtran
|
||||
rtranif0, K_rtranif0
|
||||
rtranif1, K_rtranif1
|
||||
scalared, K_scalared
|
||||
signed, K_signed
|
||||
small, K_small
|
||||
specify, K_specify
|
||||
specparam, K_specparam
|
||||
strong0, K_strong0
|
||||
strong1, K_strong1
|
||||
supply0, K_supply0
|
||||
supply1, K_supply1
|
||||
table, K_table
|
||||
task, K_task
|
||||
time, K_time
|
||||
tran, K_tran
|
||||
tranif0, K_tranif0
|
||||
tranif1, K_tranif1
|
||||
tri, K_tri
|
||||
tri0, K_tri0
|
||||
tri1, K_tri1
|
||||
triand, K_triand
|
||||
trior, K_trior
|
||||
trireg, K_trireg
|
||||
vectored, K_vectored
|
||||
wait, K_wait
|
||||
wand, K_wand
|
||||
weak0, K_weak0
|
||||
weak1, K_weak1
|
||||
while, K_while
|
||||
wire, K_wire
|
||||
wone, K_wone
|
||||
wor, K_wor
|
||||
xnor, K_xnor
|
||||
xor, K_xor
|
||||
abs, GN_KEYWORDS_VAMS_2_3, K_abs
|
||||
acos, GN_KEYWORDS_VAMS_2_3, K_acos
|
||||
acosh, GN_KEYWORDS_VAMS_2_3, K_acosh
|
||||
always, GN_KEYWORDS_1364_1995, K_always
|
||||
and, GN_KEYWORDS_1364_1995, K_and
|
||||
asin, GN_KEYWORDS_VAMS_2_3, K_asin
|
||||
asinh, GN_KEYWORDS_VAMS_2_3, K_asinh
|
||||
assign, GN_KEYWORDS_1364_1995, K_assign
|
||||
atan, GN_KEYWORDS_VAMS_2_3, K_atan
|
||||
atan2, GN_KEYWORDS_VAMS_2_3, K_atan2
|
||||
atanh, GN_KEYWORDS_VAMS_2_3, K_atanh
|
||||
begin, GN_KEYWORDS_1364_1995, K_begin
|
||||
bool, GN_KEYWORDS_ICARUS, K_bool
|
||||
buf, GN_KEYWORDS_1364_1995, K_buf
|
||||
bufif0, GN_KEYWORDS_1364_1995, K_bufif0
|
||||
bufif1, GN_KEYWORDS_1364_1995, K_bufif1
|
||||
case, GN_KEYWORDS_1364_1995, K_case
|
||||
casex, GN_KEYWORDS_1364_1995, K_casex
|
||||
casez, GN_KEYWORDS_1364_1995, K_casez
|
||||
ceil, GN_KEYWORDS_VAMS_2_3, K_ceil
|
||||
cmos, GN_KEYWORDS_1364_1995, K_cmos
|
||||
cos, GN_KEYWORDS_VAMS_2_3, K_cos
|
||||
cosh, GN_KEYWORDS_VAMS_2_3, K_cosh
|
||||
deassign, GN_KEYWORDS_1364_1995, K_deassign
|
||||
default, GN_KEYWORDS_1364_1995, K_default
|
||||
defparam, GN_KEYWORDS_1364_1995, K_defparam
|
||||
disable, GN_KEYWORDS_1364_1995, K_disable
|
||||
edge, GN_KEYWORDS_1364_1995, K_edge
|
||||
else, GN_KEYWORDS_1364_1995, K_else
|
||||
end, GN_KEYWORDS_1364_1995, K_end
|
||||
endcase, GN_KEYWORDS_1364_1995, K_endcase
|
||||
endfunction, GN_KEYWORDS_1364_1995, K_endfunction
|
||||
endgenerate, GN_KEYWORDS_1364_1995, K_endgenerate
|
||||
endmodule, GN_KEYWORDS_1364_1995, K_endmodule
|
||||
endprimitive, GN_KEYWORDS_1364_1995, K_endprimitive
|
||||
endspecify, GN_KEYWORDS_1364_1995, K_endspecify
|
||||
endtable, GN_KEYWORDS_1364_1995, K_endtable
|
||||
endtask, GN_KEYWORDS_1364_1995, K_endtask
|
||||
event, GN_KEYWORDS_1364_1995, K_event
|
||||
exp, GN_KEYWORDS_VAMS_2_3, K_exp
|
||||
floor, GN_KEYWORDS_VAMS_2_3, K_floor
|
||||
for, GN_KEYWORDS_1364_1995, K_for
|
||||
force, GN_KEYWORDS_1364_1995, K_force
|
||||
forever, GN_KEYWORDS_1364_1995, K_forever
|
||||
fork, GN_KEYWORDS_1364_1995, K_fork
|
||||
function, GN_KEYWORDS_1364_1995, K_function
|
||||
generate, GN_KEYWORDS_1364_2001, K_generate
|
||||
genvar, GN_KEYWORDS_1364_2001, K_genvar
|
||||
highz0, GN_KEYWORDS_1364_1995, K_highz0
|
||||
highz1, GN_KEYWORDS_1364_1995, K_highz1
|
||||
hypot, GN_KEYWORDS_VAMS_2_3, K_hypot
|
||||
if, GN_KEYWORDS_1364_1995, K_if
|
||||
ifnone, GN_KEYWORDS_1364_1995, K_ifnone
|
||||
initial, GN_KEYWORDS_1364_1995, K_initial
|
||||
inout, GN_KEYWORDS_1364_1995, K_inout
|
||||
input, GN_KEYWORDS_1364_1995, K_input
|
||||
integer, GN_KEYWORDS_1364_1995, K_integer
|
||||
join, GN_KEYWORDS_1364_1995, K_join
|
||||
large, GN_KEYWORDS_1364_1995, K_large
|
||||
ln, GN_KEYWORDS_VAMS_2_3, K_ln
|
||||
localparam, GN_KEYWORDS_1364_2001, K_localparam
|
||||
log, GN_KEYWORDS_VAMS_2_3, K_log
|
||||
logic, GN_KEYWORDS_ICARUS, K_logic
|
||||
macromodule, GN_KEYWORDS_1364_1995, K_macromodule
|
||||
max, GN_KEYWORDS_VAMS_2_3, K_max
|
||||
medium, GN_KEYWORDS_1364_1995, K_medium
|
||||
min, GN_KEYWORDS_VAMS_2_3, K_min
|
||||
module, GN_KEYWORDS_1364_1995, K_module
|
||||
nand, GN_KEYWORDS_1364_1995, K_nand
|
||||
negedge, GN_KEYWORDS_1364_1995, K_negedge
|
||||
nmos, GN_KEYWORDS_1364_1995, K_nmos
|
||||
nor, GN_KEYWORDS_1364_1995, K_nor
|
||||
not, GN_KEYWORDS_1364_1995, K_not
|
||||
notif0, GN_KEYWORDS_1364_1995, K_notif0
|
||||
notif1, GN_KEYWORDS_1364_1995, K_notif1
|
||||
or, GN_KEYWORDS_1364_1995, K_or
|
||||
output, GN_KEYWORDS_1364_1995, K_output
|
||||
parameter, GN_KEYWORDS_1364_1995, K_parameter
|
||||
pmos, GN_KEYWORDS_1364_1995, K_pmos
|
||||
posedge, GN_KEYWORDS_1364_1995, K_posedge
|
||||
pow, GN_KEYWORDS_VAMS_2_3, K_pow
|
||||
primitive, GN_KEYWORDS_1364_1995, K_primitive
|
||||
pull0, GN_KEYWORDS_1364_1995, K_pull0
|
||||
pull1, GN_KEYWORDS_1364_1995, K_pull1
|
||||
pulldown, GN_KEYWORDS_1364_1995, K_pulldown
|
||||
pullup, GN_KEYWORDS_1364_1995, K_pullup
|
||||
rcmos, GN_KEYWORDS_1364_1995, K_rcmos
|
||||
real, GN_KEYWORDS_1364_1995, K_real
|
||||
realtime, GN_KEYWORDS_1364_1995, K_realtime
|
||||
reg, GN_KEYWORDS_1364_1995, K_reg
|
||||
release, GN_KEYWORDS_1364_1995, K_release
|
||||
repeat, GN_KEYWORDS_1364_1995, K_repeat
|
||||
rnmos, GN_KEYWORDS_1364_1995, K_rnmos
|
||||
rpmos, GN_KEYWORDS_1364_1995, K_rpmos
|
||||
rtran, GN_KEYWORDS_1364_1995, K_rtran
|
||||
rtranif0, GN_KEYWORDS_1364_1995, K_rtranif0
|
||||
rtranif1, GN_KEYWORDS_1364_1995, K_rtranif1
|
||||
scalared, GN_KEYWORDS_1364_1995, K_scalared
|
||||
signed, GN_KEYWORDS_1364_2001, K_signed
|
||||
sin, GN_KEYWORDS_VAMS_2_3, K_sin
|
||||
sinh, GN_KEYWORDS_VAMS_2_3, K_sinh
|
||||
small, GN_KEYWORDS_1364_1995, K_small
|
||||
specify, GN_KEYWORDS_1364_1995, K_specify
|
||||
specparam, GN_KEYWORDS_1364_1995, K_specparam
|
||||
sqrt, GN_KEYWORDS_VAMS_2_3, K_sqrt
|
||||
strong0, GN_KEYWORDS_1364_1995, K_strong0
|
||||
strong1, GN_KEYWORDS_1364_1995, K_strong1
|
||||
supply0, GN_KEYWORDS_1364_1995, K_supply0
|
||||
supply1, GN_KEYWORDS_1364_1995, K_supply1
|
||||
table, GN_KEYWORDS_1364_1995, K_table
|
||||
tan, GN_KEYWORDS_VAMS_2_3, K_tan
|
||||
tanh, GN_KEYWORDS_VAMS_2_3, K_tanh
|
||||
task, GN_KEYWORDS_1364_1995, K_task
|
||||
time, GN_KEYWORDS_1364_1995, K_time
|
||||
tran, GN_KEYWORDS_1364_1995, K_tran
|
||||
tranif0, GN_KEYWORDS_1364_1995, K_tranif0
|
||||
tranif1, GN_KEYWORDS_1364_1995, K_tranif1
|
||||
tri, GN_KEYWORDS_1364_1995, K_tri
|
||||
tri0, GN_KEYWORDS_1364_1995, K_tri0
|
||||
tri1, GN_KEYWORDS_1364_1995, K_tri1
|
||||
triand, GN_KEYWORDS_1364_1995, K_triand
|
||||
trior, GN_KEYWORDS_1364_1995, K_trior
|
||||
trireg, GN_KEYWORDS_1364_1995, K_trireg
|
||||
vectored, GN_KEYWORDS_1364_1995, K_vectored
|
||||
wait, GN_KEYWORDS_1364_1995, K_wait
|
||||
wand, GN_KEYWORDS_1364_1995, K_wand
|
||||
weak0, GN_KEYWORDS_1364_1995, K_weak0
|
||||
weak1, GN_KEYWORDS_1364_1995, K_weak1
|
||||
while, GN_KEYWORDS_1364_1995, K_while
|
||||
wire, GN_KEYWORDS_1364_1995, K_wire
|
||||
wone, GN_KEYWORDS_1364_1995, K_wone
|
||||
wor, GN_KEYWORDS_1364_1995, K_wor
|
||||
xnor, GN_KEYWORDS_1364_1995, K_xnor
|
||||
xor, GN_KEYWORDS_1364_1995, K_xor
|
||||
%%
|
||||
|
||||
int lexor_keyword_mask = 0;
|
||||
|
||||
int lexor_keyword_code(const char*str, unsigned nstr)
|
||||
{
|
||||
const struct lexor_keyword*rc = check_identifier(str, nstr);
|
||||
if (rc == 0)
|
||||
return IDENTIFIER;
|
||||
else if ((rc->mask & lexor_keyword_mask) == 0)
|
||||
return IDENTIFIER;
|
||||
else
|
||||
return rc->tokenType;
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2003 Stephen Williams (steve@icarus.com)
|
||||
* Copyright (c) 2003-2008 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,9 +16,6 @@
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
|
||||
*/
|
||||
#ifdef HAVE_CVS_IDENT
|
||||
#ident "$Id: a_fetch_value.c,v 1.5 2003/06/17 16:55:07 steve Exp $"
|
||||
#endif
|
||||
|
||||
# include <acc_user.h>
|
||||
# include <vpi_user.h>
|
||||
@@ -104,7 +101,8 @@ static char* fetch_strength_value(handle obj)
|
||||
val.format = vpiStrengthVal;
|
||||
vpi_get_value(obj, &val);
|
||||
|
||||
vpip_format_strength(str, &val);
|
||||
/* Should this iterate over the bits? It now matches the old code. */
|
||||
vpip_format_strength(str, &val, 0);
|
||||
|
||||
if (pli_trace) {
|
||||
fprintf(pli_trace, "acc_fetch_value(<%s>, \"%%v\") --> %s\n",
|
||||
@@ -125,30 +123,3 @@ char* acc_fetch_value(handle obj, const char*fmt, s_acc_value*value)
|
||||
vpi_printf("XXXX acc_fetch_value(..., \"%s\", ...)\n", fmt);
|
||||
return "<acc_fetch_value>";
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* $Log: a_fetch_value.c,v $
|
||||
* Revision 1.5 2003/06/17 16:55:07 steve
|
||||
* 1) setlinebuf() for vpi_trace
|
||||
* 2) Addes error checks for trace file opens
|
||||
* 3) removes now extraneous flushes
|
||||
* 4) fixes acc_next() bug
|
||||
*
|
||||
* Revision 1.4 2003/05/18 00:16:35 steve
|
||||
* Add PLI_TRACE tracing of PLI1 modules.
|
||||
*
|
||||
* Add tf_isetdelay and friends, and add
|
||||
* callback return values for acc_vcl support.
|
||||
*
|
||||
* Revision 1.3 2003/04/24 02:02:37 steve
|
||||
* Clean up some simple warnings.
|
||||
*
|
||||
* Revision 1.2 2003/04/20 02:49:07 steve
|
||||
* acc_fetch_value support for %v format.
|
||||
*
|
||||
* Revision 1.1 2003/04/12 18:57:14 steve
|
||||
* More acc_ function stubs.
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
|
||||
const char COPYRIGHT[] =
|
||||
"Copyright (c) 1998-2005 Stephen Williams ([email protected])";
|
||||
"Copyright (c) 1998-2008 Stephen Williams ([email protected])";
|
||||
|
||||
/*
|
||||
* This source code is free software; you can redistribute it
|
||||
@@ -18,9 +18,6 @@ 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
|
||||
*/
|
||||
#ifdef HAVE_CVS_IDENT
|
||||
#ident "$Id: main.cc,v 1.95 2007/04/19 02:52:53 steve Exp $"
|
||||
#endif
|
||||
|
||||
# include "config.h"
|
||||
|
||||
@@ -88,9 +85,11 @@ const char*target = "null";
|
||||
* is a major mode, and the gn_* flags control specific sub-features.
|
||||
*/
|
||||
generation_t generation_flag = GN_DEFAULT;
|
||||
bool gn_icarus_misc_flag = true;
|
||||
bool gn_cadence_types_flag = true;
|
||||
bool gn_specify_blocks_flag = true;
|
||||
bool gn_io_range_error_flag = true;
|
||||
bool gn_verilog_ams_flag = false;
|
||||
|
||||
map<string,const char*> flags;
|
||||
char*vpi_module_list = 0;
|
||||
@@ -113,6 +112,7 @@ FILE *depend_file = NULL;
|
||||
bool warn_implicit = false;
|
||||
bool warn_timescale = false;
|
||||
bool warn_portbinding = false;
|
||||
bool warn_inf_loop = false;
|
||||
|
||||
bool error_implicit = false;
|
||||
|
||||
@@ -199,14 +199,30 @@ const char *net_func_to_name(const net_func func)
|
||||
|
||||
static void process_generation_flag(const char*gen)
|
||||
{
|
||||
if (strcmp(gen,"1") == 0) {
|
||||
if (strcmp(gen,"1") == 0) { // FIXME: Deprecated for 1995
|
||||
generation_flag = GN_VER1995;
|
||||
|
||||
} else if (strcmp(gen,"2") == 0) {
|
||||
} else if (strcmp(gen,"2") == 0) { // FIXME: Deprecated for 2001
|
||||
generation_flag = GN_VER2001;
|
||||
|
||||
} else if (strcmp(gen,"2x") == 0) {
|
||||
generation_flag = GN_VER2001X;
|
||||
} else if (strcmp(gen,"2x") == 0) { // FIXME: Deprecated for 2001
|
||||
generation_flag = GN_VER2001;
|
||||
gn_icarus_misc_flag = true;
|
||||
|
||||
} else if (strcmp(gen,"1995") == 0) {
|
||||
generation_flag = GN_VER1995;
|
||||
|
||||
} else if (strcmp(gen,"2001") == 0) {
|
||||
generation_flag = GN_VER2001;
|
||||
|
||||
} else if (strcmp(gen,"2005") == 0) {
|
||||
generation_flag = GN_VER2005;
|
||||
|
||||
} else if (strcmp(gen,"icarus-misc") == 0) {
|
||||
gn_icarus_misc_flag = true;
|
||||
|
||||
} else if (strcmp(gen,"no-icarus-misc") == 0) {
|
||||
gn_icarus_misc_flag = false;
|
||||
|
||||
} else if (strcmp(gen,"xtypes") == 0) {
|
||||
gn_cadence_types_flag = true;
|
||||
@@ -220,6 +236,12 @@ static void process_generation_flag(const char*gen)
|
||||
} else if (strcmp(gen,"no-specify") == 0) {
|
||||
gn_specify_blocks_flag = false;
|
||||
|
||||
} else if (strcmp(gen,"verilog-ams") == 0) {
|
||||
gn_verilog_ams_flag = true;
|
||||
|
||||
} else if (strcmp(gen,"no-verilog-ams") == 0) {
|
||||
gn_verilog_ams_flag = false;
|
||||
|
||||
} else if (strcmp(gen,"io-range-error") == 0) {
|
||||
gn_io_range_error_flag = true;
|
||||
|
||||
@@ -434,6 +456,9 @@ static void read_iconfig_file(const char*ipath)
|
||||
case 'i':
|
||||
warn_implicit = true;
|
||||
break;
|
||||
case 'l':
|
||||
warn_inf_loop = true;
|
||||
break;
|
||||
case 'p':
|
||||
warn_portbinding = true;
|
||||
break;
|
||||
@@ -591,6 +616,29 @@ int main(int argc, char*argv[])
|
||||
}
|
||||
}
|
||||
|
||||
lexor_keyword_mask = 0;
|
||||
switch (generation_flag) {
|
||||
case GN_VER1995:
|
||||
lexor_keyword_mask |= GN_KEYWORDS_1364_1995;
|
||||
break;
|
||||
case GN_VER2001:
|
||||
lexor_keyword_mask |= GN_KEYWORDS_1364_1995;
|
||||
lexor_keyword_mask |= GN_KEYWORDS_1364_2001;
|
||||
lexor_keyword_mask |= GN_KEYWORDS_1364_2001_CONFIG;
|
||||
break;
|
||||
case GN_VER2005:
|
||||
lexor_keyword_mask |= GN_KEYWORDS_1364_1995;
|
||||
lexor_keyword_mask |= GN_KEYWORDS_1364_2001;
|
||||
lexor_keyword_mask |= GN_KEYWORDS_1364_2001_CONFIG;
|
||||
lexor_keyword_mask |= GN_KEYWORDS_1364_2005;
|
||||
break;
|
||||
}
|
||||
|
||||
if (gn_cadence_types_flag)
|
||||
lexor_keyword_mask |= GN_KEYWORDS_ICARUS;
|
||||
|
||||
if (gn_verilog_ams_flag)
|
||||
lexor_keyword_mask |= GN_KEYWORDS_VAMS_2_3;
|
||||
|
||||
if (verbose_flag) {
|
||||
if (times_flag)
|
||||
@@ -604,11 +652,14 @@ int main(int argc, char*argv[])
|
||||
case GN_VER2001:
|
||||
cout << "IEEE1364-2001";
|
||||
break;
|
||||
case GN_VER2001X:
|
||||
cout << "IEEE1364-2001+Extensions";
|
||||
case GN_VER2005:
|
||||
cout << "IEEE1364-2005";
|
||||
break;
|
||||
}
|
||||
|
||||
if (gn_verilog_ams_flag)
|
||||
cout << ",verilog-ams";
|
||||
|
||||
if (gn_specify_blocks_flag)
|
||||
cout << ",specify";
|
||||
else
|
||||
@@ -619,6 +670,11 @@ int main(int argc, char*argv[])
|
||||
else
|
||||
cout << ",no-xtypes";
|
||||
|
||||
if (gn_icarus_misc_flag)
|
||||
cout << ",icarus-misc";
|
||||
else
|
||||
cout << ",no-icarus-misc";
|
||||
|
||||
cout << endl << "PARSING INPUT" << endl;
|
||||
}
|
||||
|
||||
@@ -830,103 +886,3 @@ int main(int argc, char*argv[])
|
||||
|
||||
return des? des->errors : 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* $Log: main.cc,v $
|
||||
* Revision 1.95 2007/04/19 02:52:53 steve
|
||||
* Add support for -v flag in command file.
|
||||
*
|
||||
* Revision 1.94 2007/03/07 04:24:59 steve
|
||||
* Make integer width controllable.
|
||||
*
|
||||
* Revision 1.93 2006/09/28 04:35:18 steve
|
||||
* Support selective control of specify and xtypes features.
|
||||
*
|
||||
* Revision 1.92 2005/07/14 23:38:43 steve
|
||||
* Display as version 0.9.devel
|
||||
*
|
||||
* Revision 1.91 2005/07/07 16:22:49 steve
|
||||
* Generalize signals to carry types.
|
||||
*
|
||||
* Revision 1.90 2005/06/28 04:25:55 steve
|
||||
* Remove reference to SystemVerilog.
|
||||
*
|
||||
* Revision 1.89 2005/04/24 23:44:02 steve
|
||||
* Update DFF support to new data flow.
|
||||
*
|
||||
* Revision 1.88 2005/01/22 01:06:55 steve
|
||||
* Change case compare from logic to an LPM node.
|
||||
*
|
||||
* Revision 1.87 2004/12/11 02:31:26 steve
|
||||
* Rework of internals to carry vectors through nexus instead
|
||||
* of single bits. Make the ivl, tgt-vvp and vvp initial changes
|
||||
* down this path.
|
||||
*
|
||||
* Revision 1.86 2004/10/04 01:10:53 steve
|
||||
* Clean up spurious trailing white space.
|
||||
*
|
||||
* Revision 1.85 2004/09/25 01:58:44 steve
|
||||
* Add a debug_elaborate flag
|
||||
*
|
||||
* Revision 1.84 2004/09/10 23:51:42 steve
|
||||
* Fix the evaluation of constant ternary expressions.
|
||||
*
|
||||
* Revision 1.83 2004/09/05 17:44:42 steve
|
||||
* Add support for module instance arrays.
|
||||
*
|
||||
* Revision 1.82 2004/03/10 04:51:24 steve
|
||||
* Add support for system function table files.
|
||||
*
|
||||
* Revision 1.81 2004/02/18 17:11:56 steve
|
||||
* Use perm_strings for named langiage items.
|
||||
*
|
||||
* Revision 1.80 2004/02/15 00:19:29 steve
|
||||
* Report elaboration errors without crashing.
|
||||
*
|
||||
* Revision 1.79 2003/11/26 01:37:14 steve
|
||||
* Properly initialize vpi_module_list with system.
|
||||
*
|
||||
* Revision 1.78 2003/11/13 05:55:33 steve
|
||||
* Move the DLL= flag to target config files.
|
||||
*
|
||||
* Revision 1.77 2003/11/13 04:09:49 steve
|
||||
* Pass flags through the temporary config file.
|
||||
*
|
||||
* Revision 1.76 2003/11/13 03:10:38 steve
|
||||
* ivl -F and -t flags are onpassed throught the -C file.
|
||||
*
|
||||
* Revision 1.75 2003/11/10 20:59:03 steve
|
||||
* Design::get_flag returns const char* instead of string.
|
||||
*
|
||||
* Revision 1.74 2003/11/01 04:22:30 steve
|
||||
* Accept functors in the config file.
|
||||
*
|
||||
* Revision 1.73 2003/10/26 22:43:42 steve
|
||||
* Improve -V messages,
|
||||
*
|
||||
* Revision 1.72 2003/09/26 02:17:14 steve
|
||||
* Delete pform when done with it.
|
||||
*
|
||||
* Revision 1.71 2003/09/25 00:25:14 steve
|
||||
* Summary list of missing modules.
|
||||
*
|
||||
* Revision 1.70 2003/09/23 05:57:36 steve
|
||||
* Pass -m flag from driver via iconfig file.
|
||||
*
|
||||
* Revision 1.69 2003/09/22 01:12:08 steve
|
||||
* Pass more ivl arguments through the iconfig file.
|
||||
*
|
||||
* Revision 1.68 2003/06/20 00:53:19 steve
|
||||
* Module attributes from the parser
|
||||
* through to elaborated form.
|
||||
*
|
||||
* Revision 1.67 2003/04/24 05:25:27 steve
|
||||
* Dump design even on errors.
|
||||
*
|
||||
* Revision 1.66 2003/03/01 06:25:30 steve
|
||||
* Add the lex_strings string handler, and put
|
||||
* scope names and system task/function names
|
||||
* into this table. Also, permallocate event
|
||||
* names from the beginning.
|
||||
*/
|
||||
|
||||
|
||||
@@ -47,6 +47,8 @@ critical, but these are the versions I use.
|
||||
msys-1.0 <http://www.mingw/org>
|
||||
msysDTK-1.0 <http://www.mingw.org>
|
||||
Mingw32-5.x <http://www.mingw.org>
|
||||
... including the sub-packages binutils, gcc-core and gcc-g++
|
||||
if you are given the option.
|
||||
readline-4.2-20010727.zip <http://mingwrep.sourceforge.net>
|
||||
bzip2-1.0.3 <http://gnuwin32.sourceforge.net>
|
||||
zlib-1.2.3 <http://gnuwin32.sourceforge.net>
|
||||
|
||||
+3
-5
@@ -377,10 +377,6 @@ void NetScope::evaluate_parameters(Design*des)
|
||||
assert(nexpr);
|
||||
delete expr;
|
||||
(*cur).second.expr = nexpr;
|
||||
|
||||
// Set the signedness flag.
|
||||
(*cur).second.expr
|
||||
->cast_signed( (*cur).second.signed_flag );
|
||||
}
|
||||
break;
|
||||
|
||||
@@ -393,7 +389,9 @@ void NetScope::evaluate_parameters(Design*des)
|
||||
}
|
||||
|
||||
/* If the parameter has range information, then make
|
||||
sure the value is set right. */
|
||||
sure the value is set right. Note that if the
|
||||
parameter doesn't have an explicit range, then it
|
||||
will get the signedness from the expression itself. */
|
||||
if (range_flag) {
|
||||
unsigned long wid = (msb >= lsb)? msb - lsb : lsb - msb;
|
||||
wid += 1;
|
||||
|
||||
+22
-2
@@ -81,6 +81,7 @@ NetEBAdd::NetEBAdd(char op, NetExpr*l, NetExpr*r, bool lossless_flag)
|
||||
}
|
||||
|
||||
unsigned pad_width = lossless_flag? 1 : 0;
|
||||
cast_signed(l->has_sign() && r->has_sign());
|
||||
|
||||
/* Now that we have the operand sizes the way we like, or as
|
||||
good as we are going to get them, set the size of myself. */
|
||||
@@ -91,8 +92,6 @@ NetEBAdd::NetEBAdd(char op, NetExpr*l, NetExpr*r, bool lossless_flag)
|
||||
} else {
|
||||
expr_width(l->expr_width() + pad_width);
|
||||
}
|
||||
|
||||
cast_signed(l->has_sign() && r->has_sign());
|
||||
}
|
||||
|
||||
NetEBAdd::~NetEBAdd()
|
||||
@@ -219,6 +218,27 @@ ivl_variable_type_t NetEBDiv::expr_type() const
|
||||
return IVL_VT_LOGIC;
|
||||
}
|
||||
|
||||
NetEBMinMax::NetEBMinMax(char op, NetExpr*l, NetExpr*r)
|
||||
: NetEBinary(op, l, r)
|
||||
{
|
||||
expr_width( max(l->expr_width(), r->expr_width()) );
|
||||
cast_signed(l->has_sign() || r->has_sign());
|
||||
}
|
||||
|
||||
NetEBMinMax::~NetEBMinMax()
|
||||
{
|
||||
}
|
||||
|
||||
ivl_variable_type_t NetEBMinMax::expr_type() const
|
||||
{
|
||||
if (left_->expr_type() == IVL_VT_REAL)
|
||||
return IVL_VT_REAL;
|
||||
if (right_->expr_type() == IVL_VT_REAL)
|
||||
return IVL_VT_REAL;
|
||||
|
||||
return IVL_VT_LOGIC;
|
||||
}
|
||||
|
||||
NetEBMult::NetEBMult(char op, NetExpr*l, NetExpr*r)
|
||||
: NetEBinary(op, l, r)
|
||||
{
|
||||
|
||||
+2
-85
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2000 Stephen Williams (steve@icarus.com)
|
||||
* Copyright (c) 2000-2008 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,9 +16,6 @@
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
|
||||
*/
|
||||
#ifdef HAVE_CVS_IDENT
|
||||
#ident "$Id: net_link.cc,v 1.21 2007/06/02 03:42:13 steve Exp $"
|
||||
#endif
|
||||
|
||||
# include "config.h"
|
||||
|
||||
@@ -431,7 +428,7 @@ NexusSet::~NexusSet()
|
||||
{
|
||||
if (nitems_ > 0) {
|
||||
assert(items_ != 0);
|
||||
delete[] items_;
|
||||
free(items_);
|
||||
} else {
|
||||
assert(items_ == 0);
|
||||
}
|
||||
@@ -541,83 +538,3 @@ bool NexusSet::intersect(const NexusSet&that) const
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/*
|
||||
* $Log: net_link.cc,v $
|
||||
* Revision 1.21 2007/06/02 03:42:13 steve
|
||||
* Properly evaluate scope path expressions.
|
||||
*
|
||||
* Revision 1.20 2007/03/26 18:17:50 steve
|
||||
* Remove pretense of general use for t_cookie.
|
||||
*
|
||||
* Revision 1.19 2006/02/02 02:43:58 steve
|
||||
* Allow part selects of memory words in l-values.
|
||||
*
|
||||
* Revision 1.18 2005/09/25 23:40:11 steve
|
||||
* Simplify NexusSet set handling.
|
||||
*
|
||||
* Revision 1.17 2005/06/13 23:22:37 steve
|
||||
* Fix compile errors.
|
||||
*
|
||||
* Revision 1.16 2005/04/24 23:44:02 steve
|
||||
* Update DFF support to new data flow.
|
||||
*
|
||||
* Revision 1.15 2005/01/09 20:16:01 steve
|
||||
* Use PartSelect/PV and VP to handle part selects through ports.
|
||||
*
|
||||
* Revision 1.14 2004/02/18 17:11:56 steve
|
||||
* Use perm_strings for named langiage items.
|
||||
*
|
||||
* Revision 1.13 2003/01/14 21:16:18 steve
|
||||
* Move strstream to ostringstream for compatibility.
|
||||
*
|
||||
* Revision 1.12 2002/10/21 01:42:08 steve
|
||||
* Synthesizer support for synchronous begin-end blocks.
|
||||
*
|
||||
* Revision 1.11 2002/08/18 22:07:16 steve
|
||||
* Detect temporaries in sequential block synthesis.
|
||||
*
|
||||
* Revision 1.10 2002/08/12 01:34:59 steve
|
||||
* conditional ident string using autoconfig.
|
||||
*
|
||||
* Revision 1.9 2002/07/03 03:08:47 steve
|
||||
* Clear drive cache on link or unlink.
|
||||
*
|
||||
* Revision 1.8 2002/06/30 02:21:31 steve
|
||||
* Add structure for asynchronous logic synthesis.
|
||||
*
|
||||
* Revision 1.7 2002/06/24 01:49:39 steve
|
||||
* Make link_drive_constant cache its results in
|
||||
* the Nexus, to improve cprop performance.
|
||||
*
|
||||
* Revision 1.6 2002/04/21 04:59:08 steve
|
||||
* Add support for conbinational events by finding
|
||||
* the inputs to expressions and some statements.
|
||||
* Get case and assignment statements working.
|
||||
*
|
||||
* Revision 1.5 2001/07/25 03:10:49 steve
|
||||
* Create a config.h.in file to hold all the config
|
||||
* junk, and support gcc 3.0. (Stephan Boettcher)
|
||||
*
|
||||
* Revision 1.4 2000/10/06 23:46:50 steve
|
||||
* ivl_target updates, including more complete
|
||||
* handling of ivl_nexus_t objects. Much reduced
|
||||
* dependencies on pointers to netlist objects.
|
||||
*
|
||||
* Revision 1.3 2000/08/26 00:54:03 steve
|
||||
* Get at gate information for ivl_target interface.
|
||||
*
|
||||
* Revision 1.2 2000/07/14 06:12:57 steve
|
||||
* Move inital value handling from NetNet to Nexus
|
||||
* objects. This allows better propogation of inital
|
||||
* values.
|
||||
*
|
||||
* Clean up constant propagation a bit to account
|
||||
* for regs that are not really values.
|
||||
*
|
||||
* Revision 1.1 2000/06/25 19:59:42 steve
|
||||
* Redesign Links to include the Nexus class that
|
||||
* carries properties of the connected set of links.
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
+48
-19
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2000 Stephen Williams (steve@icarus.com)
|
||||
* Copyright (c) 2000-2008 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,9 +16,6 @@
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
|
||||
*/
|
||||
#ifdef HAVE_CVS_IDENT
|
||||
#ident "$Id: net_scope.cc,v 1.38 2007/06/02 03:42:13 steve Exp $"
|
||||
#endif
|
||||
|
||||
# include "config.h"
|
||||
# include "compiler.h"
|
||||
@@ -44,11 +41,13 @@ NetScope::NetScope(NetScope*up, const hname_t&n, NetScope::TYPE t)
|
||||
lcounter_ = 0;
|
||||
|
||||
if (up) {
|
||||
default_nettype_ = up->default_nettype();
|
||||
time_unit_ = up->time_unit();
|
||||
time_prec_ = up->time_precision();
|
||||
sib_ = up_->sub_;
|
||||
up_->sub_ = this;
|
||||
} else {
|
||||
default_nettype_ = NetNet::NONE;
|
||||
time_unit_ = 0;
|
||||
time_prec_ = 0;
|
||||
assert(t == MODULE);
|
||||
@@ -79,8 +78,34 @@ NetScope::~NetScope()
|
||||
/* name_ and module_name_ are perm-allocated. */
|
||||
}
|
||||
|
||||
void NetScope::set_line(const LineInfo*info)
|
||||
{
|
||||
file_ = info->get_file();
|
||||
def_file_ = file_;
|
||||
lineno_ = info->get_lineno();
|
||||
def_lineno_ = lineno_;
|
||||
}
|
||||
|
||||
void NetScope::set_line(perm_string file, unsigned lineno)
|
||||
{
|
||||
file_ = file;
|
||||
def_file_ = file;
|
||||
lineno_ = lineno;
|
||||
def_lineno_ = lineno;
|
||||
}
|
||||
|
||||
void NetScope::set_line(perm_string file, perm_string def_file,
|
||||
unsigned lineno, unsigned def_lineno)
|
||||
{
|
||||
file_ = file;
|
||||
def_file_ = def_file;
|
||||
lineno_ = lineno;
|
||||
def_lineno_ = def_lineno;
|
||||
}
|
||||
|
||||
NetExpr* NetScope::set_parameter(perm_string key, NetExpr*expr,
|
||||
NetExpr*msb, NetExpr*lsb, bool signed_flag)
|
||||
NetExpr*msb, NetExpr*lsb, bool signed_flag,
|
||||
perm_string file, unsigned lineno)
|
||||
{
|
||||
param_expr_t&ref = parameters[key];
|
||||
NetExpr* res = ref.expr;
|
||||
@@ -88,6 +113,8 @@ NetExpr* NetScope::set_parameter(perm_string key, NetExpr*expr,
|
||||
ref.msb = msb;
|
||||
ref.lsb = lsb;
|
||||
ref.signed_flag = signed_flag;
|
||||
ref.file = file;
|
||||
ref.lineno = lineno;
|
||||
return res;
|
||||
}
|
||||
|
||||
@@ -110,29 +137,30 @@ bool NetScope::auto_name(const char*prefix, char pad, const char* suffix)
|
||||
}
|
||||
|
||||
/*
|
||||
* Return false if this creates a new parameter.
|
||||
* Return false if the parameter does not already exist.
|
||||
* A parameter is not automatically created.
|
||||
*/
|
||||
bool NetScope::replace_parameter(perm_string key, NetExpr*expr)
|
||||
{
|
||||
bool flag = true;
|
||||
param_expr_t&ref = parameters[key];
|
||||
bool flag = false;
|
||||
|
||||
NetExpr* res = ref.expr;
|
||||
if (parameters.find(key) != parameters.end()) {
|
||||
param_expr_t&ref = parameters[key];
|
||||
|
||||
if (res) {
|
||||
delete res;
|
||||
} else {
|
||||
flag = false;
|
||||
ref.msb = 0;
|
||||
ref.lsb = 0;
|
||||
ref.signed_flag = false;
|
||||
delete ref.expr;
|
||||
ref.expr = expr;
|
||||
flag = true;
|
||||
}
|
||||
|
||||
ref.expr = expr;
|
||||
return flag;
|
||||
}
|
||||
|
||||
NetExpr* NetScope::set_localparam(perm_string key, NetExpr*expr)
|
||||
/*
|
||||
* This is not really complete (msb, lsb, sign). It is currently only
|
||||
* used to add a genver to the local parameter list.
|
||||
*/
|
||||
NetExpr* NetScope::set_localparam(perm_string key, NetExpr*expr,
|
||||
perm_string file, unsigned lineno)
|
||||
{
|
||||
param_expr_t&ref = localparams[key];
|
||||
NetExpr* res = ref.expr;
|
||||
@@ -140,6 +168,8 @@ NetExpr* NetScope::set_localparam(perm_string key, NetExpr*expr)
|
||||
ref.msb = 0;
|
||||
ref.lsb = 0;
|
||||
ref.signed_flag = false;
|
||||
ref.file = file;
|
||||
ref.lineno = lineno;
|
||||
return res;
|
||||
}
|
||||
|
||||
@@ -403,4 +433,3 @@ string NetScope::local_hsymbol()
|
||||
return string(name()) + "." + string(local_symbol());
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
+237
-8
@@ -235,11 +235,12 @@ NetBus::~NetBus()
|
||||
{
|
||||
}
|
||||
|
||||
NetDelaySrc::NetDelaySrc(NetScope*s, perm_string n,
|
||||
unsigned npins, bool condit_src)
|
||||
NetDelaySrc::NetDelaySrc(NetScope*s, perm_string n, unsigned npins,
|
||||
bool condit_src, bool conditional)
|
||||
: NetObj(s, n, npins + (condit_src?1:0))
|
||||
{
|
||||
condit_flag_ = false;
|
||||
conditional_ = conditional;
|
||||
posedge_ = false;
|
||||
negedge_ = false;
|
||||
for (unsigned idx = 0 ; idx < npins ; idx += 1) {
|
||||
@@ -379,6 +380,11 @@ const Link& NetDelaySrc::src_pin(unsigned idx) const
|
||||
}
|
||||
|
||||
bool NetDelaySrc::is_condit() const
|
||||
{
|
||||
return conditional_;
|
||||
}
|
||||
|
||||
bool NetDelaySrc::has_condit() const
|
||||
{
|
||||
return condit_flag_;
|
||||
}
|
||||
@@ -398,8 +404,8 @@ const Link& NetDelaySrc::condit_pin() const
|
||||
NetNet::NetNet(NetScope*s, perm_string n, Type t, unsigned npins)
|
||||
: NetObj(s, n, 1), sig_next_(0), sig_prev_(0),
|
||||
type_(t), port_type_(NOT_A_PORT), data_type_(IVL_VT_NO_TYPE),
|
||||
signed_(false), msb_(npins-1), lsb_(0), dimensions_(0), s0_(0), e0_(0),
|
||||
local_flag_(false), eref_count_(0), lref_count_(0)
|
||||
signed_(false), isint_(false), msb_(npins-1), lsb_(0), dimensions_(0),
|
||||
s0_(0), e0_(0), local_flag_(false), eref_count_(0), lref_count_(0)
|
||||
{
|
||||
assert(s);
|
||||
assert(npins>0);
|
||||
@@ -438,7 +444,7 @@ NetNet::NetNet(NetScope*s, perm_string n, Type t,
|
||||
: NetObj(s, n, 1),
|
||||
sig_next_(0), sig_prev_(0), type_(t),
|
||||
port_type_(NOT_A_PORT), data_type_(IVL_VT_NO_TYPE), signed_(false),
|
||||
msb_(ms), lsb_(ls), dimensions_(0), s0_(0), e0_(0),
|
||||
isint_(false), msb_(ms), lsb_(ls), dimensions_(0), s0_(0), e0_(0),
|
||||
local_flag_(false), eref_count_(0), lref_count_(0)
|
||||
{
|
||||
assert(s);
|
||||
@@ -484,8 +490,8 @@ static unsigned calculate_count(long s, long e)
|
||||
NetNet::NetNet(NetScope*s, perm_string n, Type t,
|
||||
long ms, long ls, long array_s, long array_e)
|
||||
: NetObj(s, n, calculate_count(array_s, array_e)),
|
||||
sig_next_(0), sig_prev_(0), type_(t),
|
||||
port_type_(NOT_A_PORT), data_type_(IVL_VT_NO_TYPE), signed_(false),
|
||||
sig_next_(0), sig_prev_(0), type_(t), port_type_(NOT_A_PORT),
|
||||
data_type_(IVL_VT_NO_TYPE), signed_(false), isint_(false),
|
||||
msb_(ms), lsb_(ls), dimensions_(1), s0_(array_s), e0_(array_e),
|
||||
local_flag_(false), eref_count_(0), lref_count_(0)
|
||||
{
|
||||
@@ -642,7 +648,7 @@ bool NetNet::sb_is_valid(long sb) const
|
||||
return (sb <= lsb_) && (sb >= msb_);
|
||||
}
|
||||
|
||||
unsigned NetNet::sb_to_idx(long sb) const
|
||||
long NetNet::sb_to_idx(long sb) const
|
||||
{
|
||||
if (msb_ >= lsb_)
|
||||
return sb - lsb_;
|
||||
@@ -1040,6 +1046,24 @@ const verinum& NetFF::sset_value() const
|
||||
}
|
||||
|
||||
|
||||
NetAbs::NetAbs(NetScope*s, perm_string n, unsigned w)
|
||||
: NetNode(s, n, 2), width_(w)
|
||||
{
|
||||
pin(0).set_dir(Link::OUTPUT);
|
||||
pin(0).set_name(perm_string::literal("Result"), 0);
|
||||
pin(1).set_dir(Link::INPUT);
|
||||
pin(1).set_name(perm_string::literal("DataA"), 0);
|
||||
}
|
||||
|
||||
NetAbs::~NetAbs()
|
||||
{
|
||||
}
|
||||
|
||||
unsigned NetAbs::width() const
|
||||
{
|
||||
return width_;
|
||||
}
|
||||
|
||||
/*
|
||||
* The NetAddSub class represents an LPM_ADD_SUB device. The pinout is
|
||||
* assigned like so:
|
||||
@@ -2288,6 +2312,7 @@ NetEUnary::NetEUnary(char op, NetExpr*ex)
|
||||
switch (op_) {
|
||||
case '-':
|
||||
case '+':
|
||||
case 'm': // abs()
|
||||
cast_signed(ex->has_sign());
|
||||
break;
|
||||
default:
|
||||
@@ -2417,3 +2442,207 @@ const NetProc*NetTaskDef::proc() const
|
||||
{
|
||||
return proc_;
|
||||
}
|
||||
|
||||
/*
|
||||
* These are the delay_type() functions. They are used to determine
|
||||
* the type of delay for the given object.
|
||||
*/
|
||||
|
||||
/*
|
||||
* This function implements the following table:
|
||||
*
|
||||
* in_A in_B out
|
||||
* NO NO NO
|
||||
* NO ZERO ZERO
|
||||
* NO POS POS
|
||||
* NO DEF POS
|
||||
* ZERO NO ZERO
|
||||
* ZERO ZERO ZERO
|
||||
* ZERO POS POS
|
||||
* ZERO DEF POS
|
||||
* POS NO POS
|
||||
* POS ZERO POS
|
||||
* POS POS POS
|
||||
* POS DEF POS
|
||||
* DEF NO POS
|
||||
* DEF ZERO POS
|
||||
* DEF POS POS
|
||||
* DEF DEF DEF
|
||||
*
|
||||
* It is used to combine two delay values.
|
||||
*/
|
||||
static DelayType combine_delays(const DelayType a, const DelayType b)
|
||||
{
|
||||
/* The default is POSSIBLE_DELAY. */
|
||||
DelayType result = POSSIBLE_DELAY;
|
||||
|
||||
/* If both are no or zero delay then we return ZERO_DELAY. */
|
||||
if ((a == NO_DELAY || a == ZERO_DELAY) &&
|
||||
(b == NO_DELAY || b == ZERO_DELAY)) {
|
||||
result = ZERO_DELAY;
|
||||
}
|
||||
|
||||
/* Except if both are no delay then we return NO_DELAY. */
|
||||
if (a == NO_DELAY && b == NO_DELAY) {
|
||||
result = NO_DELAY;
|
||||
}
|
||||
|
||||
/* If both are definite delay then we return DEFINITE_DELAY. */
|
||||
if (a == DEFINITE_DELAY && b == DEFINITE_DELAY) {
|
||||
result = DEFINITE_DELAY;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/*
|
||||
* This is used to see what we can find out about the delay when it
|
||||
* is given as an expression. We also use this for loop expressions.
|
||||
*/
|
||||
static DelayType delay_type_from_expr(const NetExpr*expr)
|
||||
{
|
||||
DelayType result = POSSIBLE_DELAY;
|
||||
|
||||
if (const NetEConst*e = dynamic_cast<const NetEConst*>(expr)) {
|
||||
if (e->value().is_zero()) result = ZERO_DELAY;
|
||||
else result = DEFINITE_DELAY;
|
||||
}
|
||||
|
||||
if (const NetECReal*e = dynamic_cast<const NetECReal*>(expr)) {
|
||||
if (e->value().as_double() == 0.0) result = ZERO_DELAY;
|
||||
else result = DEFINITE_DELAY;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/*
|
||||
* The looping structures can use the same basic code so put it here
|
||||
* instead of duplicating it for each one (repeat and while).
|
||||
*/
|
||||
static DelayType get_loop_delay_type(const NetExpr*expr, const NetProc*proc)
|
||||
{
|
||||
DelayType result;
|
||||
|
||||
switch (delay_type_from_expr(expr)) {
|
||||
/* We have a constant false expression so the body never runs. */
|
||||
case ZERO_DELAY:
|
||||
result = NO_DELAY;
|
||||
break;
|
||||
/* We have a constant true expression so the body always runs. */
|
||||
case DEFINITE_DELAY:
|
||||
result = proc->delay_type();
|
||||
break;
|
||||
/* We don't know if the body will run so reduce a DEFINITE_DELAY
|
||||
* to a POSSIBLE_DELAY. All other stay the same. */
|
||||
case POSSIBLE_DELAY:
|
||||
result = combine_delays(NO_DELAY, proc->delay_type());
|
||||
break;
|
||||
/* This should never happen since delay_type_from_expr() only
|
||||
* returns three different values. */
|
||||
default:
|
||||
assert(0);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/* The default object does not have any delay. */
|
||||
DelayType NetProc::delay_type() const
|
||||
{
|
||||
return NO_DELAY;
|
||||
}
|
||||
|
||||
DelayType NetBlock::delay_type() const
|
||||
{
|
||||
DelayType result = NO_DELAY;
|
||||
|
||||
for (const NetProc*cur = proc_first(); cur; cur = proc_next(cur)) {
|
||||
DelayType dt = cur->delay_type();
|
||||
if (dt > result) result = dt;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
DelayType NetCase::delay_type() const
|
||||
{
|
||||
DelayType result = NO_DELAY;
|
||||
bool def_stmt = false;
|
||||
unsigned nstmts = nitems();
|
||||
|
||||
for (unsigned idx = 0; idx < nstmts; idx += 1) {
|
||||
if (!expr(idx)) def_stmt = true;
|
||||
if (idx == 0) {
|
||||
result = stat(idx)->delay_type();
|
||||
} else {
|
||||
result = combine_delays(result, stat(idx)->delay_type());
|
||||
}
|
||||
}
|
||||
|
||||
/* If we don't have a default statement we don't know for sure
|
||||
* that we have a delay. */
|
||||
if (!def_stmt) result = combine_delays(NO_DELAY, result);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
DelayType NetCondit::delay_type() const
|
||||
{
|
||||
DelayType result;
|
||||
|
||||
if (else_) {
|
||||
result = combine_delays(if_->delay_type(), else_->delay_type());
|
||||
} else {
|
||||
result = if_->delay_type();
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
DelayType NetEvWait::delay_type() const
|
||||
{
|
||||
return DEFINITE_DELAY;
|
||||
}
|
||||
|
||||
DelayType NetForever::delay_type() const
|
||||
{
|
||||
return statement_->delay_type();
|
||||
}
|
||||
|
||||
DelayType NetPDelay::delay_type() const
|
||||
{
|
||||
if (expr_) {
|
||||
return delay_type_from_expr(expr_);
|
||||
} else {
|
||||
if (delay() > 0) {
|
||||
return DEFINITE_DELAY;
|
||||
} else {
|
||||
if (statement_) {
|
||||
return statement_->delay_type();
|
||||
} else {
|
||||
return NO_DELAY;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
DelayType NetRepeat::delay_type() const
|
||||
{
|
||||
return get_loop_delay_type(expr_, statement_);
|
||||
}
|
||||
|
||||
DelayType NetTaskDef::delay_type() const
|
||||
{
|
||||
return proc_->delay_type();
|
||||
}
|
||||
|
||||
DelayType NetUTask::delay_type() const
|
||||
{
|
||||
return task()->task_def()->delay_type();
|
||||
}
|
||||
|
||||
DelayType NetWhile::delay_type() const
|
||||
{
|
||||
return get_loop_delay_type(cond_, proc_);
|
||||
}
|
||||
|
||||
@@ -382,8 +382,8 @@ class NetNode : public NetObj {
|
||||
class NetDelaySrc : public NetObj {
|
||||
|
||||
public:
|
||||
explicit NetDelaySrc(NetScope*s, perm_string n,
|
||||
unsigned nsrc, bool condit_src);
|
||||
explicit NetDelaySrc(NetScope*s, perm_string n, unsigned nsrc,
|
||||
bool condit_src, bool conditional);
|
||||
~NetDelaySrc();
|
||||
|
||||
// These functions set the delays from the values in the
|
||||
@@ -415,6 +415,7 @@ class NetDelaySrc : public NetObj {
|
||||
const Link&src_pin(unsigned) const;
|
||||
|
||||
bool is_condit() const;
|
||||
bool has_condit() const;
|
||||
Link&condit_pin();
|
||||
const Link&condit_pin() const;
|
||||
|
||||
@@ -423,6 +424,7 @@ class NetDelaySrc : public NetObj {
|
||||
private:
|
||||
uint64_t transition_delays_[12];
|
||||
bool condit_flag_;
|
||||
bool conditional_;
|
||||
bool posedge_;
|
||||
bool negedge_;
|
||||
|
||||
@@ -508,7 +510,7 @@ class NetNet : public NetObj {
|
||||
/* This method converts a signed index (the type that might be
|
||||
found in the Verilog source) to a pin number. It accounts
|
||||
for variation in the definition of the reg/wire/whatever. */
|
||||
unsigned sb_to_idx(long sb) const;
|
||||
long sb_to_idx(long sb) const;
|
||||
|
||||
/* This method checks that the signed index is valid for this
|
||||
signal. If it is, the above sb_to_idx can be used to get
|
||||
@@ -576,6 +578,27 @@ class NetNet : public NetObj {
|
||||
vector<class NetDelaySrc*> delay_paths_;
|
||||
};
|
||||
|
||||
/*
|
||||
* This class implements the LPM_ABS component. The node has a single
|
||||
* input, a signe expression, that it converts to the absolute
|
||||
* value. The gate is simple: pin(0) is the output and pin(1) is the input.
|
||||
*/
|
||||
class NetAbs : public NetNode {
|
||||
|
||||
public:
|
||||
NetAbs(NetScope*s, perm_string n, unsigned width);
|
||||
~NetAbs();
|
||||
|
||||
unsigned width() const;
|
||||
|
||||
virtual void dump_node(ostream&, unsigned ind) const;
|
||||
virtual bool emit_node(struct target_t*) const;
|
||||
virtual void functor_node(Design*des, functor_t*fun);
|
||||
|
||||
private:
|
||||
unsigned width_;
|
||||
};
|
||||
|
||||
/*
|
||||
* This class implements the LPM_ADD_SUB component as described in the
|
||||
* EDIF LPM Version 2 1 0 standard. It is used as a structural
|
||||
@@ -1640,6 +1663,7 @@ class NetUDP : public NetNode {
|
||||
PUdp *udp;
|
||||
};
|
||||
|
||||
enum DelayType { NO_DELAY, ZERO_DELAY, POSSIBLE_DELAY, DEFINITE_DELAY };
|
||||
|
||||
/* =========
|
||||
* A process is a behavioral-model description. A process is a
|
||||
@@ -1689,6 +1713,9 @@ class NetProc : public virtual LineInfo {
|
||||
|
||||
virtual void dump(ostream&, unsigned ind) const;
|
||||
|
||||
// Recursively checks to see if there is delay in this element.
|
||||
virtual DelayType delay_type() const;
|
||||
|
||||
private:
|
||||
friend class NetBlock;
|
||||
NetProc*next_;
|
||||
@@ -1896,6 +1923,7 @@ class NetBlock : public NetProc {
|
||||
virtual bool emit_proc(struct target_t*) const;
|
||||
virtual int match_proc(struct proc_match_t*);
|
||||
virtual void dump(ostream&, unsigned ind) const;
|
||||
virtual DelayType delay_type() const;
|
||||
|
||||
private:
|
||||
const Type type_;
|
||||
@@ -1939,6 +1967,7 @@ class NetCase : public NetProc {
|
||||
|
||||
virtual bool emit_proc(struct target_t*) const;
|
||||
virtual void dump(ostream&, unsigned ind) const;
|
||||
virtual DelayType delay_type() const;
|
||||
|
||||
private:
|
||||
|
||||
@@ -2012,6 +2041,7 @@ class NetCondit : public NetProc {
|
||||
virtual bool emit_proc(struct target_t*) const;
|
||||
virtual int match_proc(struct proc_match_t*);
|
||||
virtual void dump(ostream&, unsigned ind) const;
|
||||
virtual DelayType delay_type() const;
|
||||
|
||||
private:
|
||||
NetExpr* expr_;
|
||||
@@ -2229,6 +2259,7 @@ class NetEvWait : public NetProc {
|
||||
const svector<NetEvProbe*>&events);
|
||||
|
||||
virtual void dump(ostream&, unsigned ind) const;
|
||||
virtual DelayType delay_type() const;
|
||||
|
||||
private:
|
||||
NetProc*statement_;
|
||||
@@ -2296,6 +2327,7 @@ class NetForever : public NetProc {
|
||||
virtual NexusSet* nex_input(bool rem_out = true);
|
||||
virtual bool emit_proc(struct target_t*) const;
|
||||
virtual void dump(ostream&, unsigned ind) const;
|
||||
virtual DelayType delay_type() const;
|
||||
|
||||
private:
|
||||
NetProc*statement_;
|
||||
@@ -2368,6 +2400,7 @@ class NetPDelay : public NetProc {
|
||||
|
||||
virtual bool emit_proc(struct target_t*) const;
|
||||
virtual void dump(ostream&, unsigned ind) const;
|
||||
virtual DelayType delay_type() const;
|
||||
|
||||
bool emit_proc_recurse(struct target_t*) const;
|
||||
|
||||
@@ -2392,6 +2425,7 @@ class NetRepeat : public NetProc {
|
||||
virtual NexusSet* nex_input(bool rem_out = true);
|
||||
virtual bool emit_proc(struct target_t*) const;
|
||||
virtual void dump(ostream&, unsigned ind) const;
|
||||
virtual DelayType delay_type() const;
|
||||
|
||||
private:
|
||||
NetExpr*expr_;
|
||||
@@ -2473,6 +2507,7 @@ class NetTaskDef {
|
||||
NetNet*port(unsigned idx);
|
||||
|
||||
void dump(ostream&, unsigned) const;
|
||||
DelayType delay_type() const;
|
||||
|
||||
private:
|
||||
NetScope*scope_;
|
||||
@@ -2541,6 +2576,7 @@ class NetUTask : public NetProc {
|
||||
virtual void nex_output(NexusSet&);
|
||||
virtual bool emit_proc(struct target_t*) const;
|
||||
virtual void dump(ostream&, unsigned ind) const;
|
||||
virtual DelayType delay_type() const;
|
||||
|
||||
private:
|
||||
NetScope*task_;
|
||||
@@ -2565,6 +2601,7 @@ class NetWhile : public NetProc {
|
||||
virtual void nex_output(NexusSet&);
|
||||
virtual bool emit_proc(struct target_t*) const;
|
||||
virtual void dump(ostream&, unsigned ind) const;
|
||||
virtual DelayType delay_type() const;
|
||||
|
||||
private:
|
||||
NetExpr* cond_;
|
||||
@@ -2648,6 +2685,8 @@ class NetProcTop : public LineInfo, public Attrib {
|
||||
* r -- Right shift (>>)
|
||||
* R -- signed right shift (>>>)
|
||||
* X -- Bitwise exclusive NOR (~^)
|
||||
* m -- min(a,b)
|
||||
* M -- max(a,b)
|
||||
*/
|
||||
class NetEBinary : public NetExpr {
|
||||
|
||||
@@ -2815,6 +2854,24 @@ class NetEBLogic : public NetEBinary {
|
||||
private:
|
||||
};
|
||||
|
||||
/*
|
||||
* Support the binary min(l,r) and max(l,r) operators. The opcodes
|
||||
* supported are:
|
||||
*
|
||||
* m -- min
|
||||
* M -- max
|
||||
*/
|
||||
class NetEBMinMax : public NetEBinary {
|
||||
|
||||
public:
|
||||
NetEBMinMax(char op, NetExpr*l, NetExpr*r);
|
||||
~NetEBMinMax();
|
||||
|
||||
virtual ivl_variable_type_t expr_type() const;
|
||||
|
||||
private:
|
||||
|
||||
};
|
||||
|
||||
/*
|
||||
* Support the binary multiplication (*) operator.
|
||||
@@ -3127,6 +3184,7 @@ class NetETernary : public NetExpr {
|
||||
* A -- Reduction NAND (~&)
|
||||
* N -- Reduction NOR (~|)
|
||||
* X -- Reduction NXOR (~^ or ^~)
|
||||
* m -- abs(x) (i.e. "magnitude")
|
||||
*/
|
||||
class NetEUnary : public NetExpr {
|
||||
|
||||
@@ -3257,8 +3315,10 @@ class NetScope : public Attrib {
|
||||
previous expression, if there was one. */
|
||||
|
||||
NetExpr* set_parameter(perm_string name, NetExpr*val,
|
||||
NetExpr*msb, NetExpr*lsb, bool signed_flag);
|
||||
NetExpr* set_localparam(perm_string name, NetExpr*val);
|
||||
NetExpr*msb, NetExpr*lsb, bool signed_flag,
|
||||
perm_string file, unsigned lineno);
|
||||
NetExpr* set_localparam(perm_string name, NetExpr*val,
|
||||
perm_string file, unsigned lineno);
|
||||
|
||||
const NetExpr*get_parameter(const char* name,
|
||||
const NetExpr*&msb,
|
||||
@@ -3303,6 +3363,15 @@ class NetScope : public Attrib {
|
||||
NetTaskDef* task_def();
|
||||
NetFuncDef* func_def();
|
||||
|
||||
void set_line(perm_string file, perm_string def_file,
|
||||
unsigned lineno, unsigned def_lineno);
|
||||
void set_line(perm_string file, unsigned lineno);
|
||||
void set_line(const LineInfo *info);
|
||||
perm_string get_file() const { return file_; };
|
||||
perm_string get_def_file() const { return def_file_; };
|
||||
unsigned get_lineno() const { return lineno_; };
|
||||
unsigned get_def_lineno() const { return def_lineno_; };
|
||||
|
||||
bool in_func();
|
||||
|
||||
const NetTaskDef* task_def() const;
|
||||
@@ -3364,6 +3433,8 @@ class NetScope : public Attrib {
|
||||
NetExpr*expr;
|
||||
NetExpr*msb;
|
||||
NetExpr*lsb;
|
||||
perm_string file;
|
||||
unsigned lineno;
|
||||
bool signed_flag;
|
||||
};
|
||||
map<perm_string,param_expr_t>parameters;
|
||||
@@ -3393,6 +3464,11 @@ class NetScope : public Attrib {
|
||||
TYPE type_;
|
||||
hname_t name_;
|
||||
|
||||
perm_string file_;
|
||||
perm_string def_file_;
|
||||
unsigned lineno_;
|
||||
unsigned def_lineno_;
|
||||
|
||||
signed char time_unit_, time_prec_;
|
||||
NetNet::Type default_nettype_;
|
||||
|
||||
|
||||
+19
@@ -123,6 +123,25 @@ NetExpr* make_sub_expr(long val, NetExpr*expr)
|
||||
return res;
|
||||
}
|
||||
|
||||
NetExpr* condition_reduce(NetExpr*expr)
|
||||
{
|
||||
if (expr->expr_width() == 1)
|
||||
return expr;
|
||||
|
||||
verinum zero (verinum::V0, expr->expr_width());
|
||||
|
||||
NetEConst*ezero = new NetEConst(zero);
|
||||
ezero->cast_signed(expr->has_sign());
|
||||
ezero->set_line(*expr);
|
||||
ezero->set_width(expr->expr_width());
|
||||
|
||||
NetEBComp*cmp = new NetEBComp('n', expr, ezero);
|
||||
cmp->cast_signed(false);
|
||||
cmp->set_line(*expr);
|
||||
|
||||
return cmp;
|
||||
}
|
||||
|
||||
NetExpr* elab_and_eval(Design*des, NetScope*scope,
|
||||
const PExpr*pe, int expr_wid, int prune_width)
|
||||
{
|
||||
|
||||
@@ -64,6 +64,13 @@ extern NetNet*pad_to_width(Design*des, NetNet*n, unsigned w);
|
||||
|
||||
extern NetNet*pad_to_width_signed(Design*des, NetNet*n, unsigned w);
|
||||
|
||||
/*
|
||||
* Take the input expression and return a variation that assures that
|
||||
* the expression is 1-bit wide and logical. This reflects the needs
|
||||
* of conditions i.e. for "if" statements or logical operators.
|
||||
*/
|
||||
extern NetExpr*condition_reduce(NetExpr*expr);
|
||||
|
||||
/*
|
||||
* This function transforms an expression by cropping the high bits
|
||||
* off with a part select. The result has the width w passed in. This
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 1998-2007 Stephen Williams (steve@icarus.com)
|
||||
* Copyright (c) 1998-2008 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
|
||||
@@ -350,8 +350,8 @@ void pform_endmodule(const char*name)
|
||||
msg << "Module " << name << " was already declared here: "
|
||||
<< (*test).second->get_fileline() << endl;
|
||||
VLerror(msg.str().c_str());
|
||||
pform_cur_module = 0;
|
||||
return;
|
||||
} else {
|
||||
pform_modules[mod_name] = pform_cur_module;
|
||||
}
|
||||
|
||||
// The current lexical scope should be this module by now, and
|
||||
@@ -360,15 +360,16 @@ void pform_endmodule(const char*name)
|
||||
lexical_scope = pform_cur_module->pscope_parent();
|
||||
ivl_assert(*pform_cur_module, lexical_scope == 0);
|
||||
|
||||
pform_modules[mod_name] = pform_cur_module;
|
||||
pform_cur_module = 0;
|
||||
}
|
||||
|
||||
void pform_genvars(list<perm_string>*names)
|
||||
void pform_genvars(const struct vlltype&li, list<perm_string>*names)
|
||||
{
|
||||
list<perm_string>::const_iterator cur;
|
||||
for (cur = names->begin(); cur != names->end() ; *cur++) {
|
||||
pform_cur_module->genvars.push_back( *cur );
|
||||
LineInfo*lni = new LineInfo();
|
||||
FILE_NAME(lni, li);
|
||||
pform_cur_module->genvars[*cur] = lni;
|
||||
}
|
||||
|
||||
delete names;
|
||||
@@ -1640,7 +1641,8 @@ void pform_set_reg_idx(perm_string name, PExpr*l, PExpr*r)
|
||||
}
|
||||
|
||||
void pform_set_parameter(perm_string name, bool signed_flag,
|
||||
svector<PExpr*>*range, PExpr*expr)
|
||||
svector<PExpr*>*range, PExpr*expr,
|
||||
const char*file, unsigned lineno)
|
||||
{
|
||||
assert(expr);
|
||||
pform_cur_module->parameters[name].expr = expr;
|
||||
@@ -1656,12 +1658,15 @@ void pform_set_parameter(perm_string name, bool signed_flag,
|
||||
pform_cur_module->parameters[name].lsb = 0;
|
||||
}
|
||||
pform_cur_module->parameters[name].signed_flag = signed_flag;
|
||||
pform_cur_module->parameters[name].file = filename_strings.make(file);
|
||||
pform_cur_module->parameters[name].lineno = lineno;
|
||||
|
||||
pform_cur_module->param_names.push_back(name);
|
||||
}
|
||||
|
||||
void pform_set_localparam(perm_string name, bool signed_flag,
|
||||
svector<PExpr*>*range, PExpr*expr)
|
||||
svector<PExpr*>*range, PExpr*expr,
|
||||
const char*file, unsigned lineno)
|
||||
{
|
||||
assert(expr);
|
||||
pform_cur_module->localparams[name].expr = expr;
|
||||
@@ -1677,6 +1682,8 @@ void pform_set_localparam(perm_string name, bool signed_flag,
|
||||
pform_cur_module->localparams[name].lsb = 0;
|
||||
}
|
||||
pform_cur_module->localparams[name].signed_flag = signed_flag;
|
||||
pform_cur_module->localparams[name].file = filename_strings.make(file);
|
||||
pform_cur_module->localparams[name].lineno = lineno;
|
||||
}
|
||||
|
||||
void pform_set_specparam(perm_string name, PExpr*expr)
|
||||
@@ -1926,4 +1933,3 @@ void pform_error_nested_modules()
|
||||
cerr << pform_cur_module->get_fileline() << ": error: original module "
|
||||
"(" << pform_cur_module->mod_name() << ") defined here." << endl;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
#ifndef __pform_H
|
||||
#define __pform_H
|
||||
/*
|
||||
* Copyright (c) 1998-2000 Stephen Williams (steve@icarus.com)
|
||||
* Copyright (c) 1998-2008 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,9 +18,6 @@
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
|
||||
*/
|
||||
#ifdef HAVE_CVS_IDENT
|
||||
#ident "$Id: pform.h,v 1.91 2007/05/24 04:07:12 steve Exp $"
|
||||
#endif
|
||||
|
||||
# include "netlist.h"
|
||||
# include "HName.h"
|
||||
@@ -175,13 +172,13 @@ extern PBlock*pform_push_block_scope(char*name, PBlock::BL_TYPE tt);
|
||||
|
||||
|
||||
extern verinum* pform_verinum_with_size(verinum*s, verinum*val,
|
||||
const char*file, unsigned loneno);
|
||||
const char*file, unsigned lineno);
|
||||
|
||||
/*
|
||||
* This function takes the list of names as new genvars to declare in
|
||||
* the current module scope.
|
||||
*/
|
||||
extern void pform_genvars(list<perm_string>*names);
|
||||
extern void pform_genvars(const struct vlltype&li, list<perm_string>*names);
|
||||
|
||||
extern void pform_start_generate_for(const struct vlltype&li,
|
||||
char*ident1,
|
||||
@@ -263,11 +260,13 @@ extern void pform_set_type_attrib(perm_string name, const string&key,
|
||||
extern void pform_set_parameter(perm_string name,
|
||||
bool signed_flag,
|
||||
svector<PExpr*>*range,
|
||||
PExpr*expr);
|
||||
PExpr*expr,
|
||||
const char*file, unsigned lineno);
|
||||
extern void pform_set_localparam(perm_string name,
|
||||
bool signed_flag,
|
||||
svector<PExpr*>*range,
|
||||
PExpr*expr);
|
||||
bool signed_flag,
|
||||
svector<PExpr*>*range,
|
||||
PExpr*expr,
|
||||
const char*file, unsigned lineno);
|
||||
extern void pform_set_defparam(const pform_name_t&name, PExpr*expr);
|
||||
|
||||
/*
|
||||
|
||||
+23
-5
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 1998-2006 Stephen Williams (steve@icarus.com)
|
||||
* Copyright (c) 1998-2008 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
|
||||
@@ -215,11 +215,30 @@ void PETernary::dump(ostream&out) const
|
||||
|
||||
void PEUnary::dump(ostream&out) const
|
||||
{
|
||||
out << op_ << "(" << *expr_ << ")";
|
||||
switch (op_) {
|
||||
case 'm':
|
||||
out << "abs";
|
||||
break;
|
||||
default:
|
||||
out << op_;
|
||||
break;
|
||||
}
|
||||
out << "(" << *expr_ << ")";
|
||||
}
|
||||
|
||||
void PEBinary::dump(ostream&out) const
|
||||
{
|
||||
/* Handle some special cases, where the operators are written
|
||||
in function notation. */
|
||||
if (op_ == 'm') {
|
||||
out << "min(" << *left_ << "," << *right_ << ")";
|
||||
return;
|
||||
}
|
||||
if (op_ == 'M') {
|
||||
out << "min(" << *left_ << "," << *right_ << ")";
|
||||
return;
|
||||
}
|
||||
|
||||
out << "(" << *left_ << ")";
|
||||
switch (op_) {
|
||||
case 'a':
|
||||
@@ -976,10 +995,10 @@ void Module::dump(ostream&out) const
|
||||
out << "/* ERROR */;" << endl;
|
||||
}
|
||||
|
||||
typedef list<perm_string>::const_iterator genvar_iter_t;
|
||||
typedef map<perm_string,LineInfo*>::const_iterator genvar_iter_t;
|
||||
for (genvar_iter_t cur = genvars.begin()
|
||||
; cur != genvars.end() ; cur++) {
|
||||
out << " genvar " << (*cur) << ";" << endl;
|
||||
out << " genvar " << ((*cur).first) << ";" << endl;
|
||||
}
|
||||
|
||||
typedef list<PGenerate*>::const_iterator genscheme_iter_t;
|
||||
@@ -1104,4 +1123,3 @@ void PUdp::dump(ostream&out) const
|
||||
|
||||
out << "endprimitive" << endl;
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,63 @@
|
||||
#!/bin/sh
|
||||
|
||||
# This script makes snapshots from a git repository. The input is
|
||||
# the number for a snapshot and the path to a temporary directory.
|
||||
# for example:
|
||||
#
|
||||
# sh scripts/MAKE_SNAPSHOT.sh 20080428 ~/tmp
|
||||
#
|
||||
# The above assumes that there is a tag "s20080428" at the point
|
||||
# to be snaphot. (The tag has the "s", but the argument to this
|
||||
# script does not have the "s"). This script extracts based on the
|
||||
# tag, uses the temporary directory to stage intermediate results,
|
||||
# and finally creates a file called verilog-20080428.tar.gz that
|
||||
# contains the snapshot ready to go.
|
||||
#
|
||||
# The complete steps to make a snapshot YYYYMMDD generally are:
|
||||
#
|
||||
# git tag -a sYYYYMMDD
|
||||
# (Make the tag in the local git repository.)
|
||||
#
|
||||
# sh scripts/MAKE_SNAPSHOT.sh YYYYMMDD ~/tmp
|
||||
# (Make the snapshot bundle verilog-YYYYMMDD.tar.gz)
|
||||
#
|
||||
# git push --tags
|
||||
# (Publish the tag to the repository.)
|
||||
#
|
||||
id=$1
|
||||
destdir=$2
|
||||
|
||||
# The git tag to use is the snapshot id with a prepended "s".
|
||||
tag="s$id"
|
||||
|
||||
# The prefix is the directory that contains the extracted files
|
||||
# of the bundle. This is also the name of the bundle file itself.
|
||||
prefix="verilog-$id"
|
||||
|
||||
if [ ! -d $destdir ]; then
|
||||
echo "ERROR: Directory $destdir does not exist."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [ -e $destdir/$prefix ]; then
|
||||
echo "ERROR: $destdir/$prefix already exists."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "Exporting $tag to $destdir/$prefix..."
|
||||
git-archive --prefix="$prefix/" $tag | ( cd "$destdir" && tar xf - )
|
||||
|
||||
versionh="$destdir/$prefix/version.h"
|
||||
echo "Create $versionh ..."
|
||||
echo "#define VERSION_TAG \"$tag\"" > $versionh
|
||||
|
||||
echo "Running autoconf.sh..."
|
||||
( cd $destdir/$prefix && sh autoconf.sh )
|
||||
|
||||
echo "Making bundle $prefix.tar.gz..."
|
||||
tar czf $prefix.tar.gz --exclude=autom4te.cache -C "$destdir" $prefix
|
||||
|
||||
echo "Removing temporary $destdir/$prefix..."
|
||||
rm -rf "$destdir/$prefix"
|
||||
|
||||
echo done
|
||||
+4
-2
@@ -413,8 +413,10 @@ bool NetETernary::set_width(unsigned w, bool last_chance)
|
||||
*/
|
||||
bool NetEUFunc::set_width(unsigned wid, bool)
|
||||
{
|
||||
expr_width(wid);
|
||||
return true;
|
||||
if (result_sig_->expr_width() == wid)
|
||||
return true;
|
||||
else
|
||||
return false;
|
||||
}
|
||||
|
||||
bool NetEUnary::set_width(unsigned w, bool)
|
||||
|
||||
+4
-1
@@ -1,7 +1,7 @@
|
||||
|
||||
%{
|
||||
/*
|
||||
* Copyright (c) 2000-2005 Stephen Williams ([email protected])
|
||||
* Copyright (c) 2000-2007 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
|
||||
@@ -263,6 +263,9 @@ struct tokenize : public proc_match_t {
|
||||
last_->next_ = cur;
|
||||
last_ = cur;
|
||||
|
||||
/* Because synthesis is broken this is needed to prevent
|
||||
* a seg. fault. */
|
||||
if (!dev->if_clause()) return 0;
|
||||
dev -> if_clause() -> match_proc(this);
|
||||
|
||||
if (dev->else_clause()) {
|
||||
|
||||
@@ -864,6 +864,10 @@ extern "C" ivl_nexus_t ivl_lpm_data(ivl_lpm_t net, unsigned idx)
|
||||
{
|
||||
assert(net);
|
||||
switch (net->type) {
|
||||
case IVL_LPM_ABS:
|
||||
assert(idx == 0);
|
||||
return net->u_.arith.a;
|
||||
|
||||
case IVL_LPM_ADD:
|
||||
case IVL_LPM_CMP_EEQ:
|
||||
case IVL_LPM_CMP_EQ:
|
||||
@@ -1002,6 +1006,7 @@ extern "C" ivl_nexus_t ivl_lpm_q(ivl_lpm_t net, unsigned idx)
|
||||
assert(net);
|
||||
|
||||
switch (net->type) {
|
||||
case IVL_LPM_ABS:
|
||||
case IVL_LPM_ADD:
|
||||
case IVL_LPM_DIVIDE:
|
||||
case IVL_LPM_MOD:
|
||||
@@ -1118,6 +1123,7 @@ extern "C" int ivl_lpm_signed(ivl_lpm_t net)
|
||||
case IVL_LPM_FF:
|
||||
case IVL_LPM_MUX:
|
||||
return 0;
|
||||
case IVL_LPM_ABS:
|
||||
case IVL_LPM_ADD:
|
||||
case IVL_LPM_CMP_EEQ:
|
||||
case IVL_LPM_CMP_EQ:
|
||||
@@ -1344,6 +1350,18 @@ extern "C" ivl_expr_t ivl_parameter_expr(ivl_parameter_t net)
|
||||
return net->value;
|
||||
}
|
||||
|
||||
extern "C" const char* ivl_parameter_file(ivl_parameter_t net)
|
||||
{
|
||||
assert(net);
|
||||
return net->file.str();
|
||||
}
|
||||
|
||||
extern "C" unsigned ivl_parameter_lineno(ivl_parameter_t net)
|
||||
{
|
||||
assert(net);
|
||||
return net->lineno;
|
||||
}
|
||||
|
||||
extern "C" ivl_scope_t ivl_parameter_scope(ivl_parameter_t net)
|
||||
{
|
||||
assert(net);
|
||||
@@ -1356,6 +1374,12 @@ extern "C" ivl_nexus_t ivl_path_condit(ivl_delaypath_t obj)
|
||||
return obj->condit;
|
||||
}
|
||||
|
||||
extern "C" int ivl_path_is_condit(ivl_delaypath_t obj)
|
||||
{
|
||||
assert(obj);
|
||||
return obj->conditional ? 1 : 0;
|
||||
}
|
||||
|
||||
extern uint64_t ivl_path_delay(ivl_delaypath_t obj, ivl_path_edge_t edg)
|
||||
{
|
||||
assert(obj);
|
||||
@@ -1450,6 +1474,18 @@ extern "C" ivl_statement_t ivl_scope_def(ivl_scope_t net)
|
||||
return net->def;
|
||||
}
|
||||
|
||||
extern "C" const char*ivl_scope_def_file(ivl_scope_t net)
|
||||
{
|
||||
assert(net);
|
||||
return net->def_file.str();
|
||||
}
|
||||
|
||||
extern "C" unsigned ivl_scope_def_lineno(ivl_scope_t net)
|
||||
{
|
||||
assert(net);
|
||||
return net->def_lineno;
|
||||
}
|
||||
|
||||
extern "C" unsigned ivl_scope_events(ivl_scope_t net)
|
||||
{
|
||||
assert(net);
|
||||
@@ -1463,6 +1499,18 @@ extern "C" ivl_event_t ivl_scope_event(ivl_scope_t net, unsigned idx)
|
||||
return net->event_[idx];
|
||||
}
|
||||
|
||||
extern "C" const char*ivl_scope_file(ivl_scope_t net)
|
||||
{
|
||||
assert(net);
|
||||
return net->file.str();
|
||||
}
|
||||
|
||||
extern "C" unsigned ivl_scope_lineno(ivl_scope_t net)
|
||||
{
|
||||
assert(net);
|
||||
return net->lineno;
|
||||
}
|
||||
|
||||
extern "C" unsigned ivl_scope_logs(ivl_scope_t net)
|
||||
{
|
||||
assert(net);
|
||||
@@ -1709,6 +1757,18 @@ extern "C" int ivl_signal_signed(ivl_signal_t net)
|
||||
return net->signed_;
|
||||
}
|
||||
|
||||
extern "C" const char* ivl_signal_file(ivl_signal_t net)
|
||||
{
|
||||
assert(net);
|
||||
return net->file.str();
|
||||
}
|
||||
|
||||
extern "C" unsigned ivl_signal_lineno(ivl_signal_t net)
|
||||
{
|
||||
assert(net);
|
||||
return net->lineno;
|
||||
}
|
||||
|
||||
extern "C" int ivl_signal_integer(ivl_signal_t net)
|
||||
{
|
||||
return net->isint_;
|
||||
|
||||
+2
-2
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2000-2007 Stephen Williams (steve@icarus.com)
|
||||
* Copyright (c) 2000-2008 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
|
||||
@@ -183,6 +183,7 @@ void dll_target::expr_concat(const NetEConcat*net)
|
||||
cur->type_ = IVL_EX_CONCAT;
|
||||
cur->value_ = IVL_VT_VECTOR;
|
||||
cur->width_ = net->expr_width();
|
||||
cur->signed_ = 0;
|
||||
|
||||
cur->u_.concat_.rept = net->repeat();
|
||||
cur->u_.concat_.parms = net->nparms();
|
||||
@@ -474,4 +475,3 @@ void dll_target::expr_unary(const NetEUnary*net)
|
||||
expr_->u_.unary_.op_ = net->op();
|
||||
expr_->u_.unary_.sub_ = sub;
|
||||
}
|
||||
|
||||
|
||||
@@ -470,6 +470,8 @@ void dll_target::make_scope_parameters(ivl_scope_t scope, const NetScope*net)
|
||||
ivl_parameter_t cur_par = scope->param_ + idx;
|
||||
cur_par->basename = (*cur_pit).first;
|
||||
cur_par->scope = scope;
|
||||
cur_par->file = (*cur_pit).second.file;
|
||||
cur_par->lineno = (*cur_pit).second.lineno;
|
||||
|
||||
NetExpr*etmp = (*cur_pit).second.expr;
|
||||
make_scope_param_expr(cur_par, etmp);
|
||||
@@ -482,6 +484,8 @@ void dll_target::make_scope_parameters(ivl_scope_t scope, const NetScope*net)
|
||||
ivl_parameter_t cur_par = scope->param_ + idx;
|
||||
cur_par->basename = (*cur_pit).first;
|
||||
cur_par->scope = scope;
|
||||
cur_par->file = (*cur_pit).second.file;
|
||||
cur_par->lineno = (*cur_pit).second.lineno;
|
||||
|
||||
NetExpr*etmp = (*cur_pit).second.expr;
|
||||
make_scope_param_expr(cur_par, etmp);
|
||||
@@ -525,6 +529,7 @@ void dll_target::add_root(ivl_design_s &des_, const NetScope *s)
|
||||
ivl_scope_t root_ = new struct ivl_scope_s;
|
||||
perm_string name = s->basename();
|
||||
root_->name_ = name;
|
||||
FILE_NAME(root_, s);
|
||||
root_->child_ = 0;
|
||||
root_->sibling_ = 0;
|
||||
root_->parent = 0;
|
||||
@@ -1246,6 +1251,8 @@ void dll_target::udp(const NetUDP*net)
|
||||
u->sequ = net->is_sequential();
|
||||
if (u->sequ)
|
||||
u->init = net->get_initial();
|
||||
else
|
||||
u->init = 'x';
|
||||
u->name = net->udp_name();
|
||||
string inp;
|
||||
char out;
|
||||
@@ -1300,6 +1307,38 @@ void dll_target::udp(const NetUDP*net)
|
||||
scope_add_logic(scope, obj);
|
||||
}
|
||||
|
||||
void dll_target::lpm_abs(const NetAbs*net)
|
||||
{
|
||||
ivl_lpm_t obj = new struct ivl_lpm_s;
|
||||
obj->type = IVL_LPM_ABS;
|
||||
obj->name = net->name(); // NetAddSub names are permallocated.
|
||||
assert(net->scope());
|
||||
obj->scope = find_scope(des_, net->scope());
|
||||
assert(obj->scope);
|
||||
|
||||
obj->u_.arith.signed_flag = 0;
|
||||
obj->width = net->width();
|
||||
|
||||
const Nexus*nex;
|
||||
/* the output is pin(0) */
|
||||
nex = net->pin(0).nexus();
|
||||
assert(nex->t_cookie());
|
||||
|
||||
obj->u_.arith.q = nex->t_cookie();
|
||||
nexus_lpm_add(obj->u_.arith.q, obj, 0, IVL_DR_STRONG, IVL_DR_STRONG);
|
||||
|
||||
nex = net->pin(1).nexus();
|
||||
assert(nex->t_cookie());
|
||||
|
||||
/* pin(1) is the input data. */
|
||||
obj->u_.arith.a = nex->t_cookie();
|
||||
nexus_lpm_add(obj->u_.arith.a, obj, 0, IVL_DR_HiZ, IVL_DR_HiZ);
|
||||
|
||||
make_lpm_delays_(obj, net);
|
||||
|
||||
scope_add_lpm(obj->scope, obj);
|
||||
}
|
||||
|
||||
void dll_target::lpm_add_sub(const NetAddSub*net)
|
||||
{
|
||||
ivl_lpm_t obj = new struct ivl_lpm_s;
|
||||
@@ -2140,6 +2179,7 @@ void dll_target::scope(const NetScope*net)
|
||||
perm_string sname = make_scope_name(net->fullname());
|
||||
scope = new struct ivl_scope_s;
|
||||
scope->name_ = sname;
|
||||
FILE_NAME(scope, net);
|
||||
scope->child_ = 0;
|
||||
scope->sibling_ = 0;
|
||||
scope->parent = find_scope(des_, net->parent());
|
||||
@@ -2212,6 +2252,8 @@ void dll_target::signal(const NetNet*net)
|
||||
object, or creating the sigs_ array if this is the first
|
||||
signal. */
|
||||
obj->scope_ = find_scope(des_, net->scope());
|
||||
obj->file = perm_string::literal("N/A");
|
||||
obj->lineno = 0;
|
||||
assert(obj->scope_);
|
||||
|
||||
if (obj->scope_->nsigs_ == 0) {
|
||||
@@ -2380,7 +2422,7 @@ bool dll_target::signal_paths(const NetNet*net)
|
||||
|
||||
/* If this path has a condition, then hook it up. */
|
||||
ivl_nexus_t path_condit = 0;
|
||||
if (src->is_condit()) {
|
||||
if (src->has_condit()) {
|
||||
const Nexus*nt = src->condit_pin().nexus();
|
||||
path_condit = nt->t_cookie();
|
||||
}
|
||||
@@ -2397,6 +2439,7 @@ bool dll_target::signal_paths(const NetNet*net)
|
||||
obj->path[ptr].scope = lookup_scope_(src->scope());
|
||||
obj->path[ptr].src = nex->t_cookie();
|
||||
obj->path[ptr].condit = path_condit;
|
||||
obj->path[ptr].conditional = src->is_condit();
|
||||
obj->path[ptr].posedge = src->is_posedge();
|
||||
obj->path[ptr].negedge = src->is_negedge();
|
||||
for (unsigned pe = 0 ; pe < 12 ; pe += 1) {
|
||||
|
||||
@@ -70,6 +70,7 @@ struct dll_target : public target_t, public expr_scan_t {
|
||||
bool ureduce(const NetUReduce*);
|
||||
void net_case_cmp(const NetCaseCmp*);
|
||||
void udp(const NetUDP*);
|
||||
void lpm_abs(const NetAbs*);
|
||||
void lpm_add_sub(const NetAddSub*);
|
||||
bool lpm_array_dq(const NetArrayDq*);
|
||||
void lpm_clshift(const NetCLShift*);
|
||||
@@ -178,6 +179,7 @@ struct ivl_delaypath_s {
|
||||
ivl_scope_t scope;
|
||||
ivl_nexus_t src;
|
||||
ivl_nexus_t condit;
|
||||
bool conditional;
|
||||
bool posedge;
|
||||
bool negedge;
|
||||
uint64_t delay[12];
|
||||
@@ -508,6 +510,8 @@ struct ivl_parameter_s {
|
||||
perm_string basename;
|
||||
ivl_scope_t scope;
|
||||
ivl_expr_t value;
|
||||
perm_string file;
|
||||
unsigned lineno;
|
||||
};
|
||||
/*
|
||||
* All we know about a process it its type (initial or always) and the
|
||||
@@ -536,6 +540,10 @@ struct ivl_scope_s {
|
||||
|
||||
perm_string name_;
|
||||
perm_string tname_;
|
||||
perm_string file;
|
||||
perm_string def_file;
|
||||
unsigned lineno;
|
||||
unsigned def_lineno;
|
||||
ivl_scope_type_t type_;
|
||||
|
||||
unsigned nsigs_;
|
||||
@@ -576,6 +584,8 @@ struct ivl_signal_s {
|
||||
ivl_signal_type_t type_;
|
||||
ivl_signal_port_t port_;
|
||||
ivl_variable_type_t data_type;
|
||||
perm_string file;
|
||||
unsigned lineno;
|
||||
|
||||
unsigned width_;
|
||||
unsigned signed_ : 1;
|
||||
@@ -712,4 +722,12 @@ static inline void FILE_NAME(ivl_lpm_t lpm, const LineInfo*info)
|
||||
lpm->lineno = info->get_lineno();
|
||||
}
|
||||
|
||||
static inline void FILE_NAME(ivl_scope_t scope, const NetScope*info)
|
||||
{
|
||||
scope->file = info->get_file();
|
||||
scope->def_file = info->get_def_file();
|
||||
scope->lineno = info->get_lineno();
|
||||
scope->def_lineno = info->get_def_lineno();
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
@@ -81,6 +81,12 @@ bool target_t::ureduce(const NetUReduce*)
|
||||
return false;
|
||||
}
|
||||
|
||||
void target_t::lpm_abs(const NetAbs*)
|
||||
{
|
||||
cerr << "target (" << typeid(*this).name() << "): "
|
||||
"Unhandled NetAbs." << endl;
|
||||
}
|
||||
|
||||
void target_t::lpm_add_sub(const NetAddSub*)
|
||||
{
|
||||
cerr << "target (" << typeid(*this).name() << "): "
|
||||
|
||||
@@ -68,6 +68,7 @@ struct target_t {
|
||||
virtual bool func_def(const NetScope*);
|
||||
|
||||
/* LPM style components are handled here. */
|
||||
virtual void lpm_abs(const NetAbs*);
|
||||
virtual void lpm_add_sub(const NetAddSub*);
|
||||
virtual bool lpm_array_dq(const NetArrayDq*);
|
||||
virtual void lpm_clshift(const NetCLShift*);
|
||||
|
||||
+26
-5
@@ -82,8 +82,9 @@ static void show_function_call(ivl_expr_t net, unsigned ind)
|
||||
const char*vt = vt_type_string(net);
|
||||
unsigned idx;
|
||||
|
||||
fprintf(out, "%*s<%s %s function %s with %u arguments>\n", ind, "",
|
||||
vt, sign, ivl_scope_name(def), ivl_expr_parms(net));
|
||||
fprintf(out, "%*s<%s %s function %s with %u arguments (width=%u)>\n",
|
||||
ind, "", vt, sign, ivl_scope_name(def), ivl_expr_parms(net),
|
||||
ivl_expr_width(net));
|
||||
|
||||
for (idx = 0 ; idx < ivl_expr_parms(net) ; idx += 1)
|
||||
show_expression(ivl_expr_parm(net,idx), ind+4);
|
||||
@@ -160,6 +161,28 @@ static void show_ternary_expression(ivl_expr_t net, unsigned ind)
|
||||
}
|
||||
}
|
||||
|
||||
void show_unary_expression(ivl_expr_t net, unsigned ind)
|
||||
{
|
||||
unsigned width = ivl_expr_width(net);
|
||||
const char*sign = ivl_expr_signed(net)? "signed" : "unsigned";
|
||||
const char*vt = vt_type_string(net);
|
||||
|
||||
char name[8];
|
||||
switch (ivl_expr_opcode(net)) {
|
||||
default:
|
||||
snprintf(name, sizeof name, "%c", ivl_expr_opcode(net));
|
||||
break;
|
||||
|
||||
case 'm':
|
||||
snprintf(name, sizeof name, "abs()");
|
||||
break;
|
||||
}
|
||||
|
||||
fprintf(out, "%*s<unary \"%s\" width=%u, %s, type=%s>\n", ind, "",
|
||||
name, width, sign, vt);
|
||||
show_expression(ivl_expr_oper1(net), ind+4);
|
||||
}
|
||||
|
||||
void show_expression(ivl_expr_t net, unsigned ind)
|
||||
{
|
||||
unsigned idx;
|
||||
@@ -252,9 +275,7 @@ void show_expression(ivl_expr_t net, unsigned ind)
|
||||
break;
|
||||
|
||||
case IVL_EX_UNARY:
|
||||
fprintf(out, "%*s<unary \"%c\" width=%u, %s, type=%s>\n", ind, "",
|
||||
ivl_expr_opcode(net), width, sign, vt);
|
||||
show_expression(ivl_expr_oper1(net), ind+4);
|
||||
show_unary_expression(net, ind);
|
||||
break;
|
||||
|
||||
case IVL_EX_UFUNC:
|
||||
|
||||
+32
-5
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2000-2005 Stephen Williams (steve@icarus.com)
|
||||
* Copyright (c) 2000-2008 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,9 +16,6 @@
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
|
||||
*/
|
||||
#ifdef HAVE_CVS_IDENT
|
||||
#ident "$Id: stub.c,v 1.148 2007/06/12 02:23:40 steve Exp $"
|
||||
#endif
|
||||
|
||||
/*
|
||||
* This is a sample target module. All this does is write to the
|
||||
@@ -178,6 +175,32 @@ static void show_lpm_arithmetic_pins(ivl_lpm_t net)
|
||||
fprintf(out, " DataB: %s\n", nex? ivl_nexus_name(nex) : "");
|
||||
}
|
||||
|
||||
static void show_lpm_abs(ivl_lpm_t net)
|
||||
{
|
||||
unsigned width = ivl_lpm_width(net);
|
||||
|
||||
fprintf(out, " LPM_ABS %s: <width=%u>\n",
|
||||
ivl_lpm_basename(net), width);
|
||||
|
||||
ivl_nexus_t nex;
|
||||
nex = ivl_lpm_q(net, 0);
|
||||
fprintf(out, " Q: %s\n", ivl_nexus_name(ivl_lpm_q(net, 0)));
|
||||
|
||||
nex = ivl_lpm_data(net, 0);
|
||||
fprintf(out, " D: %s\n", nex? ivl_nexus_name(nex) : "");
|
||||
if (nex == 0) {
|
||||
fprintf(out, " ERROR: missing input\n");
|
||||
stub_errors += 1;
|
||||
return;
|
||||
}
|
||||
|
||||
if (width_of_nexus(nex) != width) {
|
||||
fprintf(out, " ERROR: D width (%d) is wrong\n",
|
||||
width_of_nexus(nex));
|
||||
stub_errors += 1;
|
||||
}
|
||||
}
|
||||
|
||||
static void show_lpm_add(ivl_lpm_t net)
|
||||
{
|
||||
unsigned width = ivl_lpm_width(net);
|
||||
@@ -799,6 +822,10 @@ static void show_lpm(ivl_lpm_t net)
|
||||
|
||||
switch (ivl_lpm_type(net)) {
|
||||
|
||||
case IVL_LPM_ABS:
|
||||
show_lpm_abs(net);
|
||||
break;
|
||||
|
||||
case IVL_LPM_ADD:
|
||||
show_lpm_add(net);
|
||||
break;
|
||||
@@ -1166,6 +1193,7 @@ static void show_signal(ivl_signal_t net)
|
||||
if (posedge) fprintf(out, " posedge");
|
||||
if (negedge) fprintf(out, " negedge");
|
||||
if (con) fprintf(out, " (if %s)", ivl_nexus_name(con));
|
||||
else if (ivl_path_is_condit(path)) fprintf(out, " (ifnone)");
|
||||
fprintf(out, " %" PRIu64 ",%" PRIu64 ",%" PRIu64
|
||||
" %" PRIu64 ",%" PRIu64 ",%" PRIu64
|
||||
" %" PRIu64 ",%" PRIu64 ",%" PRIu64
|
||||
@@ -1549,4 +1577,3 @@ int target_design(ivl_design_t des)
|
||||
|
||||
return stub_errors;
|
||||
}
|
||||
|
||||
|
||||
+7
-3
@@ -57,10 +57,14 @@ static void draw_lpm_mux_ab(ivl_lpm_t net, const char*muxz)
|
||||
get_number_immediate(d_rise), net);
|
||||
}
|
||||
|
||||
const char* input[3];
|
||||
input[0] = draw_net_input(ivl_lpm_data(net,0));
|
||||
input[1] = draw_net_input(ivl_lpm_data(net,1));
|
||||
input[2] = draw_net_input(ivl_lpm_select(net));
|
||||
fprintf(vvp_out, "L_%p%s .functor %s %u", net, dly, muxz, width);
|
||||
fprintf(vvp_out, ", %s", draw_input_from_net(ivl_lpm_data(net,0)));
|
||||
fprintf(vvp_out, ", %s", draw_input_from_net(ivl_lpm_data(net,1)));
|
||||
fprintf(vvp_out, ", %s", draw_input_from_net(ivl_lpm_select(net)));
|
||||
fprintf(vvp_out, ", %s", input[0]);
|
||||
fprintf(vvp_out, ", %s", input[1]);
|
||||
fprintf(vvp_out, ", %s", input[2]);
|
||||
fprintf(vvp_out, ", C4<>;\n");
|
||||
}
|
||||
|
||||
|
||||
@@ -112,6 +112,15 @@ struct vector_info draw_ufunc_expr(ivl_expr_t exp, unsigned wid)
|
||||
|
||||
res.base = allocate_vector(wid);
|
||||
res.wid = wid;
|
||||
if (res.base == 0) {
|
||||
fprintf(stderr, "%s:%u: vvp.tgt error: "
|
||||
"Unable to allocate %u thread bits for function result.\n",
|
||||
ivl_expr_file(exp), ivl_expr_lineno(exp), wid);
|
||||
vvp_errors += 1;
|
||||
return res;
|
||||
}
|
||||
|
||||
assert(res.base != 0);
|
||||
|
||||
unsigned load_wid = swid;
|
||||
if (load_wid > ivl_signal_width(retval))
|
||||
|
||||
+116
-136
@@ -52,9 +52,12 @@ static int is_fixed_memory_word(ivl_expr_t net)
|
||||
|
||||
sig = ivl_expr_signal(net);
|
||||
|
||||
if (ivl_signal_array_count(sig) == 1)
|
||||
if (ivl_signal_dimensions(sig) == 0)
|
||||
return 1;
|
||||
|
||||
if (ivl_signal_type(sig) == IVL_SIT_REG)
|
||||
return 0;
|
||||
|
||||
if (number_is_immediate(ivl_expr_oper1(net), 8*sizeof(unsigned)))
|
||||
return 1;
|
||||
|
||||
@@ -69,9 +72,14 @@ static void draw_vpi_taskfunc_args(const char*call_string,
|
||||
unsigned parm_count = tnet
|
||||
? ivl_stmt_parm_count(tnet)
|
||||
: ivl_expr_parms(fnet);
|
||||
struct vector_info *vec = 0x0;
|
||||
unsigned int vecs= 0;
|
||||
unsigned int veci= 0;
|
||||
|
||||
struct args_info {
|
||||
char*text;
|
||||
int vec_flag; /* True if the vec must be released. */
|
||||
struct vector_info vec;
|
||||
} *args = calloc(parm_count, sizeof(struct args_info));
|
||||
|
||||
char buffer[4096];
|
||||
|
||||
ivl_parameter_t par;
|
||||
|
||||
@@ -89,17 +97,56 @@ static void draw_vpi_taskfunc_args(const char*call_string,
|
||||
with VPI handles of their own. Therefore, skip
|
||||
them in the process of evaluating expressions. */
|
||||
case IVL_EX_NONE:
|
||||
args[idx].text = strdup("\" \"");
|
||||
continue;
|
||||
|
||||
case IVL_EX_ARRAY:
|
||||
case IVL_EX_NUMBER:
|
||||
snprintf(buffer, sizeof buffer,
|
||||
"v%p", ivl_expr_signal(expr));
|
||||
args[idx].text = strdup(buffer);
|
||||
continue;
|
||||
|
||||
case IVL_EX_NUMBER: {
|
||||
unsigned bit, wid = ivl_expr_width(expr);
|
||||
const char*bits = ivl_expr_bits(expr);
|
||||
char*dp;
|
||||
|
||||
snprintf(buffer, sizeof buffer,
|
||||
"%u'%sb", wid, ivl_expr_signed(expr)? "s" : "");
|
||||
dp = buffer + strlen(buffer);
|
||||
for (bit = wid ; bit > 0 ; bit -= 1)
|
||||
*dp++ = bits[bit-1];
|
||||
*dp++ = 0;
|
||||
assert(dp - buffer <= sizeof buffer);
|
||||
args[idx].text = strdup(buffer);
|
||||
continue;
|
||||
}
|
||||
|
||||
case IVL_EX_STRING:
|
||||
if (( par = ivl_expr_parameter(expr) )) {
|
||||
snprintf(buffer, sizeof buffer, "P_%p", par);
|
||||
|
||||
} else {
|
||||
snprintf(buffer, sizeof buffer, "\"%s\"", ivl_expr_string(expr));
|
||||
}
|
||||
args[idx].text = strdup(buffer);
|
||||
continue;
|
||||
|
||||
case IVL_EX_EVENT:
|
||||
snprintf(buffer, sizeof buffer, "E_%p", ivl_expr_event(expr));
|
||||
args[idx].text = strdup(buffer);
|
||||
continue;
|
||||
case IVL_EX_SCOPE:
|
||||
snprintf(buffer, sizeof buffer, "S_%p", ivl_expr_scope(expr));
|
||||
args[idx].text = strdup(buffer);
|
||||
continue;
|
||||
|
||||
case IVL_EX_SFUNC:
|
||||
if (is_magic_sfunc(ivl_expr_name(expr)))
|
||||
if (is_magic_sfunc(ivl_expr_name(expr))) {
|
||||
snprintf(buffer, sizeof buffer, "%s", ivl_expr_name(expr));
|
||||
args[idx].text = strdup(buffer);
|
||||
continue;
|
||||
|
||||
}
|
||||
break;
|
||||
|
||||
case IVL_EX_SIGNAL:
|
||||
@@ -122,21 +169,47 @@ static void draw_vpi_taskfunc_args(const char*call_string,
|
||||
} else if (ivl_expr_signed(expr) !=
|
||||
ivl_signal_signed(ivl_expr_signal(expr))) {
|
||||
break;
|
||||
} else if (! is_fixed_memory_word(expr)){
|
||||
break;
|
||||
} else {
|
||||
/* Some array selects need to be evaluated. */
|
||||
} else if (is_fixed_memory_word(expr)) {
|
||||
/* This is a word of a non-array, or a word
|
||||
of a net array, so we can address the
|
||||
word directly. */
|
||||
ivl_signal_t sig = ivl_expr_signal(expr);
|
||||
unsigned use_word = 0;
|
||||
ivl_expr_t word_ex = ivl_expr_oper1(expr);
|
||||
if (word_ex && !number_is_immediate(word_ex,
|
||||
8*sizeof(unsigned))) {
|
||||
break;
|
||||
if (word_ex) {
|
||||
/* Some array select have been evaluated. */
|
||||
if (number_is_immediate(word_ex, 8*sizeof(unsigned))) {
|
||||
use_word = get_number_immediate(word_ex);
|
||||
word_ex = 0;
|
||||
}
|
||||
}
|
||||
if (word_ex)
|
||||
break;
|
||||
|
||||
assert(word_ex == 0);
|
||||
snprintf(buffer, sizeof buffer, "v%p_%u", sig, use_word);
|
||||
args[idx].text = strdup(buffer);
|
||||
continue;
|
||||
}
|
||||
|
||||
} else {
|
||||
/* What's left, this is the work of a var
|
||||
array. Create the right code to handle
|
||||
it. */
|
||||
ivl_signal_t sig = ivl_expr_signal(expr);
|
||||
unsigned use_word = 0;
|
||||
ivl_expr_t word_ex = ivl_expr_oper1(expr);
|
||||
if (word_ex) {
|
||||
/* Some array select have been evaluated. */
|
||||
if (number_is_immediate(word_ex, 8*sizeof(unsigned))) {
|
||||
use_word = get_number_immediate(word_ex);
|
||||
word_ex = 0;
|
||||
}
|
||||
}
|
||||
if (word_ex)
|
||||
break;
|
||||
|
||||
case IVL_EX_MEMORY:
|
||||
if (!ivl_expr_oper1(expr)) {
|
||||
snprintf(buffer, sizeof buffer, "&A<v%p, %u>", sig, use_word);
|
||||
args[idx].text = strdup(buffer);
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -146,143 +219,43 @@ static void draw_vpi_taskfunc_args(const char*call_string,
|
||||
break;
|
||||
}
|
||||
|
||||
vec = (struct vector_info *)
|
||||
realloc(vec, (vecs+1)*sizeof(struct vector_info));
|
||||
|
||||
switch (ivl_expr_value(expr)) {
|
||||
case IVL_VT_LOGIC:
|
||||
case IVL_VT_BOOL:
|
||||
vec[vecs] = draw_eval_expr(expr, 0);
|
||||
args[idx].vec_flag = 1;
|
||||
args[idx].vec = draw_eval_expr(expr, 0);
|
||||
snprintf(buffer, sizeof buffer,
|
||||
"T<%u,%u,%s>", args[idx].vec.base, args[idx].vec.wid,
|
||||
ivl_expr_signed(expr)? "s" : "u");
|
||||
break;
|
||||
case IVL_VT_REAL:
|
||||
vec[vecs].base = draw_eval_real(expr);
|
||||
vec[vecs].wid = 0;
|
||||
args[idx].vec_flag = 1;
|
||||
args[idx].vec.base = draw_eval_real(expr);
|
||||
args[idx].vec.wid = 0;
|
||||
snprintf(buffer, sizeof buffer,
|
||||
"W<%u,r>", args[idx].vec.base);
|
||||
break;
|
||||
default:
|
||||
assert(0);
|
||||
}
|
||||
vecs++;
|
||||
args[idx].text = strdup(buffer);
|
||||
}
|
||||
|
||||
fprintf(vvp_out, "%s", call_string);
|
||||
|
||||
for (idx = 0 ; idx < parm_count ; idx += 1) {
|
||||
ivl_expr_t expr = tnet
|
||||
? ivl_stmt_parm(tnet, idx)
|
||||
: ivl_expr_parm(fnet, idx);
|
||||
|
||||
switch (ivl_expr_type(expr)) {
|
||||
case IVL_EX_NONE:
|
||||
fprintf(vvp_out, ", \" \"");
|
||||
continue;
|
||||
|
||||
case IVL_EX_ARRAY:
|
||||
fprintf(vvp_out, ", v%p", ivl_expr_signal(expr));
|
||||
continue;
|
||||
|
||||
case IVL_EX_NUMBER: {
|
||||
unsigned bit, wid = ivl_expr_width(expr);
|
||||
const char*bits = ivl_expr_bits(expr);
|
||||
|
||||
fprintf(vvp_out, ", %u'%sb", wid,
|
||||
ivl_expr_signed(expr)? "s" : "");
|
||||
for (bit = wid ; bit > 0 ; bit -= 1)
|
||||
fputc(bits[bit-1], vvp_out);
|
||||
continue;
|
||||
}
|
||||
|
||||
case IVL_EX_SIGNAL:
|
||||
/* If this is a part select, then the value was
|
||||
calculated above. Otherwise, just pass the
|
||||
signal. */
|
||||
if (ivl_expr_width(expr) !=
|
||||
ivl_signal_width(ivl_expr_signal(expr))) {
|
||||
break;
|
||||
|
||||
} else if (ivl_expr_signed(expr) !=
|
||||
ivl_signal_signed(ivl_expr_signal(expr))) {
|
||||
break;
|
||||
|
||||
} else if (! is_fixed_memory_word(expr)){
|
||||
break;
|
||||
|
||||
} else {
|
||||
ivl_signal_t sig = ivl_expr_signal(expr);
|
||||
unsigned use_word = 0;
|
||||
ivl_expr_t word_ex = ivl_expr_oper1(expr);
|
||||
if (word_ex) {
|
||||
/* Some array select have been evaluated. */
|
||||
if (!number_is_immediate(word_ex,
|
||||
8*sizeof(unsigned))) {
|
||||
break;
|
||||
}
|
||||
use_word = get_number_immediate(word_ex);
|
||||
}
|
||||
fprintf(vvp_out, ", v%p_%u", sig, use_word);
|
||||
continue;
|
||||
}
|
||||
assert(0);
|
||||
continue;
|
||||
|
||||
case IVL_EX_STRING:
|
||||
if (( par = ivl_expr_parameter(expr) )) {
|
||||
fprintf(vvp_out, ", P_%p", par);
|
||||
|
||||
} else {
|
||||
fprintf(vvp_out, ", \"%s\"",
|
||||
ivl_expr_string(expr));
|
||||
}
|
||||
continue;
|
||||
|
||||
case IVL_EX_EVENT:
|
||||
fprintf(vvp_out, ", E_%p", ivl_expr_event(expr));
|
||||
continue;
|
||||
|
||||
case IVL_EX_SCOPE:
|
||||
fprintf(vvp_out, ", S_%p", ivl_expr_scope(expr));
|
||||
continue;
|
||||
|
||||
case IVL_EX_SFUNC:
|
||||
if (is_magic_sfunc(ivl_expr_name(expr))) {
|
||||
fprintf(vvp_out, ", %s", ivl_expr_name(expr));
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
fprintf(vvp_out, ", %s", args[idx].text);
|
||||
free(args[idx].text);
|
||||
if (args[idx].vec_flag) {
|
||||
if (args[idx].vec.wid > 0)
|
||||
clr_vector(args[idx].vec);
|
||||
else
|
||||
clr_word(args[idx].vec.base);
|
||||
}
|
||||
assert(veci < vecs);
|
||||
|
||||
switch (ivl_expr_value(expr)) {
|
||||
|
||||
case IVL_VT_LOGIC:
|
||||
case IVL_VT_BOOL:
|
||||
fprintf(vvp_out, ", T<%u,%u,%s>", vec[veci].base,
|
||||
vec[veci].wid, ivl_expr_signed(expr)? "s" : "u");
|
||||
break;
|
||||
|
||||
case IVL_VT_REAL:
|
||||
fprintf(vvp_out, ", W<%u,r>", vec[veci].base);
|
||||
break;
|
||||
|
||||
default:
|
||||
assert(0);
|
||||
}
|
||||
veci++;
|
||||
}
|
||||
|
||||
assert(veci == vecs);
|
||||
|
||||
if (vecs) {
|
||||
for (idx = 0; idx < vecs; idx++) {
|
||||
if (vec[idx].wid > 0)
|
||||
clr_vector(vec[idx]);
|
||||
else if (vec[idx].wid == 0)
|
||||
clr_word(vec[idx].base);
|
||||
}
|
||||
free(vec);
|
||||
}
|
||||
free(args);
|
||||
|
||||
fprintf(vvp_out, ";\n");
|
||||
}
|
||||
@@ -303,6 +276,13 @@ struct vector_info draw_vpi_func_call(ivl_expr_t fnet, unsigned wid)
|
||||
|
||||
res.base = allocate_vector(wid);
|
||||
res.wid = wid;
|
||||
if (res.base == 0) {
|
||||
fprintf(stderr, "%s:%u: vvp.tgt error: "
|
||||
"Unable to allocate %u thread bits for system function result.\n",
|
||||
ivl_expr_file(fnet), ivl_expr_lineno(fnet), wid);
|
||||
vvp_errors += 1;
|
||||
}
|
||||
|
||||
sprintf(call_string, " %%vpi_func %u %u \"%s\", %u, %u",
|
||||
ivl_file_table_index(ivl_expr_file(fnet)),
|
||||
ivl_expr_lineno(fnet), ivl_expr_name(fnet), res.base, res.wid);
|
||||
|
||||
+246
-31
@@ -138,8 +138,22 @@ static void eval_logic_into_integer(ivl_expr_t expr, unsigned ix)
|
||||
|
||||
case IVL_EX_SIGNAL: {
|
||||
ivl_signal_t sig = ivl_expr_signal(expr);
|
||||
|
||||
unsigned word = 0;
|
||||
if (ivl_signal_array_count(sig) > 1) {
|
||||
if (ivl_signal_dimensions(sig) > 0) {
|
||||
|
||||
/* Detect the special case that this is a
|
||||
variable array. In this case, the ix/getv
|
||||
will not work, so do it the hard way. */
|
||||
if (ivl_signal_type(sig) == IVL_SIT_REG) {
|
||||
struct vector_info rv;
|
||||
rv = draw_eval_expr(expr, 0);
|
||||
fprintf(vvp_out, " %%ix/get %u, %u, %u;\n",
|
||||
ix, rv.base, rv.wid);
|
||||
clr_vector(rv);
|
||||
break;
|
||||
}
|
||||
|
||||
ivl_expr_t ixe = ivl_expr_oper1(expr);
|
||||
if (number_is_immediate(ixe, 8*sizeof(unsigned long)))
|
||||
word = get_number_immediate(ixe);
|
||||
@@ -277,6 +291,14 @@ static struct vector_info draw_eq_immediate(ivl_expr_t exp, unsigned ewid,
|
||||
expressions. */
|
||||
if (lv.base < 8) {
|
||||
unsigned base = allocate_vector(ewid);
|
||||
if (base == 0) {
|
||||
fprintf(stderr, "%s:%u: vvp.tgt error: "
|
||||
"Unable to allocate %u thread bits "
|
||||
"for result of equality compare.\n",
|
||||
ivl_expr_file(exp), ivl_expr_lineno(exp), wid);
|
||||
vvp_errors += 1;
|
||||
}
|
||||
|
||||
fprintf(vvp_out, " %%mov %u, %u, 1;\n", base, lv.base);
|
||||
lv.base = base;
|
||||
lv.wid = ewid;
|
||||
@@ -285,6 +307,14 @@ static struct vector_info draw_eq_immediate(ivl_expr_t exp, unsigned ewid,
|
||||
|
||||
} else if (lv.wid < ewid) {
|
||||
unsigned base = allocate_vector(ewid);
|
||||
if (base == 0) {
|
||||
fprintf(stderr, "%s:%u: vvp.tgt error: "
|
||||
"Unable to allocate %u thread bits "
|
||||
"for result of equality compare.\n",
|
||||
ivl_expr_file(exp), ivl_expr_lineno(exp), wid);
|
||||
vvp_errors += 1;
|
||||
}
|
||||
|
||||
if (lv.base >= 8)
|
||||
clr_vector(lv);
|
||||
fprintf(vvp_out, " %%mov %u, %u, %u;\n", base,
|
||||
@@ -309,6 +339,7 @@ static struct vector_info draw_binary_expr_eq_real(ivl_expr_t exp)
|
||||
|
||||
res.base = allocate_vector(1);
|
||||
res.wid = 1;
|
||||
assert(res.base);
|
||||
|
||||
lword = draw_eval_real(ivl_expr_oper1(exp));
|
||||
rword = draw_eval_real(ivl_expr_oper2(exp));
|
||||
@@ -441,6 +472,14 @@ static struct vector_info draw_binary_expr_eq(ivl_expr_t exp,
|
||||
uses. This is because that bit may be clobbered by other
|
||||
expressions. */
|
||||
{ unsigned base = allocate_vector(ewid);
|
||||
if (base == 0) {
|
||||
fprintf(stderr, "%s:%u: vvp.tgt error: "
|
||||
"Unable to allocate %u thread bits "
|
||||
"for result of equality compare.\n",
|
||||
ivl_expr_file(exp), ivl_expr_lineno(exp), wid);
|
||||
vvp_errors += 1;
|
||||
}
|
||||
|
||||
fprintf(vvp_out, " %%mov %u, %u, 1;\n", base, lv.base);
|
||||
lv.base = base;
|
||||
lv.wid = ewid;
|
||||
@@ -467,6 +506,7 @@ static struct vector_info draw_binary_expr_land(ivl_expr_t exp, unsigned wid)
|
||||
clr_vector(lv);
|
||||
tmp.base = allocate_vector(1);
|
||||
tmp.wid = 1;
|
||||
assert(tmp.base);
|
||||
fprintf(vvp_out, " %%or/r %u, %u, %u;\n", tmp.base,
|
||||
lv.base, lv.wid);
|
||||
lv = tmp;
|
||||
@@ -478,6 +518,7 @@ static struct vector_info draw_binary_expr_land(ivl_expr_t exp, unsigned wid)
|
||||
clr_vector(rv);
|
||||
tmp.base = allocate_vector(1);
|
||||
tmp.wid = 1;
|
||||
assert(tmp.base);
|
||||
fprintf(vvp_out, " %%or/r %u, %u, %u;\n", tmp.base,
|
||||
rv.base, rv.wid);
|
||||
rv = tmp;
|
||||
@@ -514,6 +555,14 @@ static struct vector_info draw_binary_expr_land(ivl_expr_t exp, unsigned wid)
|
||||
|
||||
/* Write the result into a zero-padded result. */
|
||||
{ unsigned base = allocate_vector(wid);
|
||||
if (base == 0) {
|
||||
fprintf(stderr, "%s:%u: vvp.tgt error: "
|
||||
"Unable to allocate %u thread bits "
|
||||
"for result of padded logical AND.\n",
|
||||
ivl_expr_file(exp), ivl_expr_lineno(exp), wid);
|
||||
vvp_errors += 1;
|
||||
}
|
||||
|
||||
fprintf(vvp_out, " %%mov %u, %u, 1;\n", base, lv.base);
|
||||
clr_vector(lv);
|
||||
lv.base = base;
|
||||
@@ -541,6 +590,7 @@ static struct vector_info draw_binary_expr_lor(ivl_expr_t exp, unsigned wid)
|
||||
clr_vector(lv);
|
||||
tmp.base = allocate_vector(1);
|
||||
tmp.wid = 1;
|
||||
assert(tmp.base);
|
||||
fprintf(vvp_out, " %%or/r %u, %u, %u;\n", tmp.base,
|
||||
lv.base, lv.wid);
|
||||
lv = tmp;
|
||||
@@ -555,6 +605,7 @@ static struct vector_info draw_binary_expr_lor(ivl_expr_t exp, unsigned wid)
|
||||
clr_vector(rv);
|
||||
tmp.base = allocate_vector(1);
|
||||
tmp.wid = 1;
|
||||
assert(tmp.base);
|
||||
fprintf(vvp_out, " %%or/r %u, %u, %u;\n", tmp.base,
|
||||
rv.base, rv.wid);
|
||||
rv = tmp;
|
||||
@@ -592,6 +643,14 @@ static struct vector_info draw_binary_expr_lor(ivl_expr_t exp, unsigned wid)
|
||||
|
||||
/* Write the result into a zero-padded result. */
|
||||
{ unsigned base = allocate_vector(wid);
|
||||
if (base == 0) {
|
||||
fprintf(stderr, "%s:%u: vvp.tgt error: "
|
||||
"Unable to allocate %u thread bits "
|
||||
"for result of padded logical OR.\n",
|
||||
ivl_expr_file(exp), ivl_expr_lineno(exp), wid);
|
||||
vvp_errors += 1;
|
||||
}
|
||||
|
||||
fprintf(vvp_out, " %%mov %u, %u, 1;\n", base, lv.base);
|
||||
clr_vector(lv);
|
||||
lv.base = base;
|
||||
@@ -615,6 +674,8 @@ static struct vector_info draw_binary_expr_le_real(ivl_expr_t exp)
|
||||
res.base = allocate_vector(1);
|
||||
res.wid = 1;
|
||||
|
||||
assert(res.base);
|
||||
|
||||
clr_word(lword);
|
||||
clr_word(rword);
|
||||
|
||||
@@ -695,6 +756,14 @@ static struct vector_info draw_binary_expr_le_bool(ivl_expr_t exp,
|
||||
uses. This is because that bit may be clobbered by other
|
||||
expressions. */
|
||||
{ unsigned base = allocate_vector(wid);
|
||||
if (base == 0) {
|
||||
fprintf(stderr, "%s:%u: vvp.tgt error: "
|
||||
"Unable to allocate %u thread bits "
|
||||
"for result of padded inequality compare.\n",
|
||||
ivl_expr_file(exp), ivl_expr_lineno(exp), wid);
|
||||
vvp_errors += 1;
|
||||
}
|
||||
|
||||
fprintf(vvp_out, " %%mov %u, 5, 1;\n", base);
|
||||
tmp.base = base;
|
||||
tmp.wid = wid;
|
||||
@@ -822,6 +891,14 @@ static struct vector_info draw_binary_expr_le(ivl_expr_t exp,
|
||||
uses. This is because that bit may be clobbered by other
|
||||
expressions. */
|
||||
{ unsigned base = allocate_vector(wid);
|
||||
if (base == 0) {
|
||||
fprintf(stderr, "%s:%u: vvp.tgt error: "
|
||||
"Unable to allocate %u thread bits "
|
||||
"for result of padded inequality compare.\n",
|
||||
ivl_expr_file(exp), ivl_expr_lineno(exp), wid);
|
||||
vvp_errors += 1;
|
||||
}
|
||||
|
||||
fprintf(vvp_out, " %%mov %u, 5, 1;\n", base);
|
||||
lv.base = base;
|
||||
lv.wid = wid;
|
||||
@@ -858,6 +935,14 @@ static struct vector_info draw_binary_expr_logic(ivl_expr_t exp,
|
||||
struct vector_info tmp;
|
||||
tmp.base = allocate_vector(lv.wid);
|
||||
tmp.wid = lv.wid;
|
||||
if (tmp.base == 0) {
|
||||
fprintf(stderr, "%s:%u: vvp.tgt error: "
|
||||
"Unable to allocate %u thread bits "
|
||||
"for result of binary logic.\n",
|
||||
ivl_expr_file(exp), ivl_expr_lineno(exp), wid);
|
||||
vvp_errors += 1;
|
||||
}
|
||||
|
||||
fprintf(vvp_out, " %%mov %u, %u, %u;\n",
|
||||
tmp.base, lv.base, tmp.wid);
|
||||
lv = tmp;
|
||||
@@ -867,17 +952,17 @@ static struct vector_info draw_binary_expr_logic(ivl_expr_t exp,
|
||||
switch (ivl_expr_opcode(exp)) {
|
||||
|
||||
case '&':
|
||||
fprintf(vvp_out, " %%and %u, %u, %u;\n",
|
||||
fprintf(vvp_out, " %%and %u, %u, %u;\n",
|
||||
lv.base, rv.base, wid);
|
||||
break;
|
||||
|
||||
case '|':
|
||||
fprintf(vvp_out, " %%or %u, %u, %u;\n",
|
||||
fprintf(vvp_out, " %%or %u, %u, %u;\n",
|
||||
lv.base, rv.base, wid);
|
||||
break;
|
||||
|
||||
case '^':
|
||||
fprintf(vvp_out, " %%xor %u, %u, %u;\n",
|
||||
fprintf(vvp_out, " %%xor %u, %u, %u;\n",
|
||||
lv.base, rv.base, wid);
|
||||
break;
|
||||
|
||||
@@ -933,6 +1018,14 @@ static struct vector_info draw_binary_expr_lrs(ivl_expr_t exp, unsigned wid)
|
||||
struct vector_info tmp;
|
||||
tmp.base = allocate_vector(lv.wid);
|
||||
tmp.wid = lv.wid;
|
||||
if (tmp.base == 0) {
|
||||
fprintf(stderr, "%s:%u: vvp.tgt error: "
|
||||
"Unable to allocate %u thread bits "
|
||||
"for result of left shift (<<).\n",
|
||||
ivl_expr_file(exp), ivl_expr_lineno(exp), wid);
|
||||
vvp_errors += 1;
|
||||
}
|
||||
|
||||
fprintf(vvp_out, " %%mov %u, %u, %u;\n",
|
||||
tmp.base, lv.base, lv.wid);
|
||||
lv = tmp;
|
||||
@@ -960,6 +1053,14 @@ static struct vector_info draw_binary_expr_lrs(ivl_expr_t exp, unsigned wid)
|
||||
struct vector_info tmp;
|
||||
tmp.base = allocate_vector(lv.wid);
|
||||
tmp.wid = lv.wid;
|
||||
if (tmp.base == 0) {
|
||||
fprintf(stderr, "%s:%u: vvp.tgt error: "
|
||||
"Unable to allocate %u thread bits "
|
||||
"for result of right shift (>>).\n",
|
||||
ivl_expr_file(exp), ivl_expr_lineno(exp), lv.wid);
|
||||
vvp_errors += 1;
|
||||
}
|
||||
|
||||
fprintf(vvp_out, " %%mov %u, %u, %u;\n",
|
||||
tmp.base, lv.base, lv.wid);
|
||||
lv = tmp;
|
||||
@@ -992,6 +1093,14 @@ static struct vector_info draw_binary_expr_lrs(ivl_expr_t exp, unsigned wid)
|
||||
struct vector_info tmp;
|
||||
tmp.base = allocate_vector(lv.wid);
|
||||
tmp.wid = lv.wid;
|
||||
if (tmp.base == 0) {
|
||||
fprintf(stderr, "%s:%u: vvp.tgt error: "
|
||||
"Unable to allocate %u thread bits "
|
||||
"for result of right shift (>>>).\n",
|
||||
ivl_expr_file(exp), ivl_expr_lineno(exp), lv.wid);
|
||||
vvp_errors += 1;
|
||||
}
|
||||
|
||||
fprintf(vvp_out, " %%mov %u, %u, %u;\n",
|
||||
tmp.base, lv.base, lv.wid);
|
||||
lv = tmp;
|
||||
@@ -1030,6 +1139,13 @@ static struct vector_info draw_load_add_immediate(ivl_expr_t le,
|
||||
imm = get_number_immediate(re);
|
||||
lv.base = allocate_vector(wid);
|
||||
lv.wid = wid;
|
||||
if (lv.base == 0) {
|
||||
fprintf(stderr, "%s:%u: vvp.tgt error: "
|
||||
"Unable to allocate %u thread bits "
|
||||
"for result of addition.\n",
|
||||
ivl_expr_file(le), ivl_expr_lineno(le), wid);
|
||||
vvp_errors += 1;
|
||||
}
|
||||
|
||||
/* Load the signal value with a %load that adds the index
|
||||
register to the value being loaded. */
|
||||
@@ -1093,6 +1209,14 @@ static struct vector_info draw_sub_immediate(ivl_expr_t le,
|
||||
case 0:
|
||||
case 1:
|
||||
tmp = allocate_vector(wid);
|
||||
if (tmp == 0) {
|
||||
fprintf(stderr, "%s:%u: vvp.tgt error: "
|
||||
"Unable to allocate %u thread bits "
|
||||
"for result of subtraction.\n",
|
||||
ivl_expr_file(le), ivl_expr_lineno(le), wid);
|
||||
vvp_errors += 1;
|
||||
}
|
||||
|
||||
fprintf(vvp_out, " %%mov %u, %u, %u;\n", tmp, lv.base, wid);
|
||||
lv.base = tmp;
|
||||
fprintf(vvp_out, " %%subi %u, %lu, %u;\n", lv.base, imm, wid);
|
||||
@@ -1136,7 +1260,7 @@ static struct vector_info draw_binary_expr_arith(ivl_expr_t exp, unsigned wid)
|
||||
struct vector_info lv;
|
||||
struct vector_info rv;
|
||||
|
||||
const char*sign_string = ivl_expr_signed(exp)? "/s" : "";
|
||||
const char*sign_string = ivl_expr_signed(le) && ivl_expr_signed(re)? "/s" : "";
|
||||
|
||||
if ((ivl_expr_opcode(exp) == '+')
|
||||
&& (ivl_expr_type(le) == IVL_EX_SIGNAL)
|
||||
@@ -1205,6 +1329,14 @@ static struct vector_info draw_binary_expr_arith(ivl_expr_t exp, unsigned wid)
|
||||
|
||||
tmp.base = allocate_vector(wid);
|
||||
tmp.wid = wid;
|
||||
if (tmp.base == 0) {
|
||||
fprintf(stderr, "%s:%u: vvp.tgt error: "
|
||||
"Unable to allocate %u thread bits "
|
||||
"for result of arithmetic expression.\n",
|
||||
ivl_expr_file(exp), ivl_expr_lineno(exp), wid);
|
||||
vvp_errors += 1;
|
||||
}
|
||||
|
||||
fprintf(vvp_out, " %%mov %u, %u, %u;\n", tmp.base,
|
||||
lv.base, wid);
|
||||
lv = tmp;
|
||||
@@ -1343,6 +1475,14 @@ static struct vector_info draw_concat_expr(ivl_expr_t exp, unsigned wid,
|
||||
/* Allocate a vector to hold the result. */
|
||||
res.base = allocate_vector(wid);
|
||||
res.wid = wid;
|
||||
if (res.base == 0) {
|
||||
fprintf(stderr, "%s:%u: vvp.tgt error: "
|
||||
"Unable to allocate %u thread bits "
|
||||
"for result of concatenation.\n",
|
||||
ivl_expr_file(exp), ivl_expr_lineno(exp), wid);
|
||||
vvp_errors += 1;
|
||||
}
|
||||
|
||||
|
||||
/* Get the repeat count. This must be a constant that has been
|
||||
evaluated at compile time. The operands will be repeated to
|
||||
@@ -1464,6 +1604,13 @@ static struct vector_info draw_number_expr(ivl_expr_t exp, unsigned wid)
|
||||
vector. Allocate the vector and use %mov instructions to
|
||||
load the constant bit values. */
|
||||
res.base = allocate_vector(wid);
|
||||
if (res.base == 0) {
|
||||
fprintf(stderr, "%s:%u: vvp.tgt error: "
|
||||
"Unable to allocate %u thread bits "
|
||||
"for number value.\n",
|
||||
ivl_expr_file(exp), ivl_expr_lineno(exp), wid);
|
||||
vvp_errors += 1;
|
||||
}
|
||||
|
||||
if ((!number_is_unknown(exp)) && number_is_immediate(exp, 16)) {
|
||||
int val = get_number_immediate(exp);
|
||||
@@ -1490,7 +1637,7 @@ static struct vector_info draw_number_expr(ivl_expr_t exp, unsigned wid)
|
||||
break;
|
||||
}
|
||||
|
||||
for (cnt = 1 ; idx+cnt < wid ; cnt += 1)
|
||||
for (cnt = 1 ; idx+cnt < nwid ; cnt += 1)
|
||||
if (bits[idx+cnt] != bits[idx])
|
||||
break;
|
||||
|
||||
@@ -1546,6 +1693,13 @@ static struct vector_info draw_pad_expr(ivl_expr_t exp, unsigned wid)
|
||||
|
||||
res.base = allocate_vector(wid);
|
||||
res.wid = wid;
|
||||
if (res.base == 0) {
|
||||
fprintf(stderr, "%s:%u: vvp.tgt error: "
|
||||
"Unable to allocate %u thread bits "
|
||||
"to pad expression.\n",
|
||||
ivl_expr_file(exp), ivl_expr_lineno(exp), wid);
|
||||
vvp_errors += 1;
|
||||
}
|
||||
|
||||
fprintf(vvp_out, " %%mov %u, %u, %u;\n",
|
||||
res.base, subv.base, subv.wid);
|
||||
@@ -1580,6 +1734,7 @@ static struct vector_info draw_realnum_expr(ivl_expr_t exp, unsigned wid)
|
||||
|
||||
res.base = allocate_vector(wid);
|
||||
res.wid = wid;
|
||||
assert(res.base);
|
||||
|
||||
addr = res.base;
|
||||
run = 1;
|
||||
@@ -1620,7 +1775,7 @@ static char *process_octal_codes(const char *in, unsigned width)
|
||||
return out;
|
||||
}
|
||||
|
||||
while (idx < str_len) {
|
||||
while (ridx < str_len) {
|
||||
/* An octal constant always has three digits. */
|
||||
if (in[ridx] == '\\') {
|
||||
out[idx] = (in[ridx+1]-'0')*64 + (in[ridx+2]-'0')*8 +
|
||||
@@ -1666,6 +1821,13 @@ static struct vector_info draw_string_expr(ivl_expr_t exp, unsigned wid)
|
||||
vector. Allocate the vector and use %mov instructions to
|
||||
load the constant bit values. */
|
||||
res.base = allocate_vector(wid);
|
||||
if (res.base == 0) {
|
||||
fprintf(stderr, "%s:%u: vvp.tgt error: "
|
||||
"Unable to allocate %u thread bits "
|
||||
"for string value.\n",
|
||||
ivl_expr_file(exp), ivl_expr_lineno(exp), wid);
|
||||
vvp_errors += 1;
|
||||
}
|
||||
|
||||
/* Since this is a string, we know that all the bits are
|
||||
defined and each character represents exactly 8 bits. Use
|
||||
@@ -1746,28 +1908,23 @@ static void draw_signal_dest(ivl_expr_t exp, struct vector_info res,
|
||||
|
||||
/* If this is an access to an array, handle that by emitting a
|
||||
load/av instruction. */
|
||||
if (ivl_signal_array_count(sig) > 1) {
|
||||
if (ivl_signal_dimensions(sig) > 0) {
|
||||
ivl_expr_t ix = ivl_expr_oper1(exp);
|
||||
if (!number_is_immediate(ix, 8*sizeof(unsigned long))) {
|
||||
draw_eval_expr_into_integer(ix, 3);
|
||||
if (add_index < 0) {
|
||||
fprintf(vvp_out, " %%load/av %u, v%p, %u;\n",
|
||||
res.base, sig, swid);
|
||||
} else {
|
||||
assert(add_index == 0);
|
||||
|
||||
/* Add an immediate value to an array value. */
|
||||
fprintf(vvp_out, " %%ix/load 0, %lu;\n", immediate);
|
||||
fprintf(vvp_out, " %%load/avp0 %u, v%p, %u;\n",
|
||||
res.base, sig, swid);
|
||||
}
|
||||
pad_expr_in_place(exp, res, swid);
|
||||
return;
|
||||
draw_eval_expr_into_integer(ix, 3);
|
||||
if (add_index < 0) {
|
||||
fprintf(vvp_out, " %%load/av %u, v%p, %u;\n",
|
||||
res.base, sig, swid);
|
||||
} else {
|
||||
assert(add_index == 0);
|
||||
|
||||
/* Add an immediate value to an array value. */
|
||||
fprintf(vvp_out, " %%ix/load 0, %lu;\n", immediate);
|
||||
fprintf(vvp_out, " %%load/avp0 %u, v%p, %u;\n",
|
||||
res.base, sig, swid);
|
||||
}
|
||||
|
||||
/* The index is constant, so we can return to direct
|
||||
readout with the specific word selected. */
|
||||
word = get_number_immediate(ix);
|
||||
pad_expr_in_place(exp, res, swid);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
@@ -1819,6 +1976,14 @@ static struct vector_info draw_signal_expr(ivl_expr_t exp, unsigned wid,
|
||||
|
||||
res.base = allocate_vector(wid);
|
||||
res.wid = wid;
|
||||
if (res.base == 0) {
|
||||
fprintf(stderr, "%s:%u: vvp.tgt error: "
|
||||
"Unable to allocate %u thread bits "
|
||||
"to load variable/wire.\n",
|
||||
ivl_expr_file(exp), ivl_expr_lineno(exp), wid);
|
||||
vvp_errors += 1;
|
||||
}
|
||||
|
||||
save_expression_lookaside(res.base, exp, wid);
|
||||
|
||||
draw_signal_dest(exp, res, -1, 0L);
|
||||
@@ -1846,6 +2011,13 @@ static struct vector_info draw_select_array(ivl_expr_t sube,
|
||||
|
||||
res.base = allocate_vector(wid);
|
||||
res.wid = wid;
|
||||
if (res.base == 0) {
|
||||
fprintf(stderr, "%s:%u: vvp.tgt error: "
|
||||
"Unable to allocate %u thread bits "
|
||||
"to hold selected value.\n",
|
||||
ivl_expr_file(sube), ivl_expr_lineno(sube), wid);
|
||||
vvp_errors += 1;
|
||||
}
|
||||
|
||||
for (idx = 0 ; idx < wid ; idx += 1) {
|
||||
fprintf(vvp_out, " %%load/avx.p %u, v%p, 0;\n", res.base+idx, sig);
|
||||
@@ -1867,14 +2039,16 @@ static struct vector_info draw_select_signal(ivl_expr_t sube,
|
||||
unsigned use_word = 0;
|
||||
|
||||
/* If this is an access to an array, try to get the index as a
|
||||
constant. If it is, then this reduces to a signal access
|
||||
and we stay here. If it is not constant, then give up and
|
||||
do an array index in front of this part select. */
|
||||
constant. If it is (and the array is not a reg array then
|
||||
this reduces to a signal access and we stay here. If it is
|
||||
not constant, then give up and do an array index in front
|
||||
of this part select. */
|
||||
|
||||
if (ivl_signal_array_count(sig) > 1) {
|
||||
if (ivl_signal_dimensions(sig) > 0) {
|
||||
ivl_expr_t ix = ivl_expr_oper1(sube);
|
||||
|
||||
if (!number_is_immediate(ix, 8*sizeof(unsigned long)))
|
||||
if (ivl_signal_type(sig)==IVL_SIT_REG
|
||||
|| !number_is_immediate(ix, 8*sizeof(unsigned long)))
|
||||
return draw_select_array(sube, bit_idx, bit_wid, wid);
|
||||
|
||||
/* The index is constant, so we can return to direct
|
||||
@@ -1891,6 +2065,7 @@ static struct vector_info draw_select_signal(ivl_expr_t sube,
|
||||
|
||||
res.base = allocate_vector(wid);
|
||||
res.wid = wid;
|
||||
assert(res.base);
|
||||
fprintf(vvp_out, " %%load/v %u, v%p_%u, %u; Only need %u of %u bits\n",
|
||||
res.base, sig, use_word, bit_wid, bit_wid, ivl_expr_width(sube));
|
||||
|
||||
@@ -1907,6 +2082,7 @@ static struct vector_info draw_select_signal(ivl_expr_t sube,
|
||||
/* Alas, do it the hard way. */
|
||||
res.base = allocate_vector(wid);
|
||||
res.wid = wid;
|
||||
assert(res.base);
|
||||
|
||||
for (idx = 0 ; idx < res.wid ; idx += 1) {
|
||||
if (idx >= bit_wid) {
|
||||
@@ -1981,6 +2157,7 @@ static struct vector_info draw_select_expr(ivl_expr_t exp, unsigned wid,
|
||||
if (subv.base < 4) {
|
||||
res.base = allocate_vector(subv.wid);
|
||||
res.wid = subv.wid;
|
||||
assert(res.base);
|
||||
fprintf(vvp_out, " %%mov %u, %u, %u;\n", res.base,
|
||||
subv.base, res.wid);
|
||||
subv = res;
|
||||
@@ -2051,6 +2228,7 @@ static struct vector_info draw_ternary_expr(ivl_expr_t exp, unsigned wid)
|
||||
struct vector_info tmp;
|
||||
tmp.base = allocate_vector(wid);
|
||||
tmp.wid = wid;
|
||||
assert(tmp.base);
|
||||
fprintf(vvp_out, " %%mov %u, %u, %u;\n",
|
||||
tmp.base, tru.base, wid);
|
||||
tru = tmp;
|
||||
@@ -2108,6 +2286,7 @@ static struct vector_info draw_sfunc_expr(ivl_expr_t exp, unsigned wid)
|
||||
|| ivl_expr_value(exp) == IVL_VT_BOOL);
|
||||
res.base = allocate_vector(wid);
|
||||
res.wid = wid;
|
||||
assert(res.base);
|
||||
fprintf(vvp_out, " %%vpi_func %u %u \"%s\", %u, %u;\n",
|
||||
ivl_file_table_index(ivl_expr_file(exp)),
|
||||
ivl_expr_lineno(exp), ivl_expr_name(exp),
|
||||
@@ -2221,6 +2400,14 @@ static struct vector_info draw_unary_expr(ivl_expr_t exp, unsigned wid)
|
||||
struct vector_info tmp;
|
||||
tmp.base = allocate_vector(wid);
|
||||
tmp.wid = wid;
|
||||
if (tmp.base == 0) {
|
||||
fprintf(stderr, "%s:%u: vvp.tgt error: "
|
||||
"Unable to allocate %u thread bits "
|
||||
"to pad unary expression result.\n",
|
||||
ivl_expr_file(exp), ivl_expr_lineno(exp), wid);
|
||||
vvp_errors += 1;
|
||||
}
|
||||
|
||||
fprintf(vvp_out, " %%mov %u, %u, %u;\n",
|
||||
tmp.base, res.base, res.wid);
|
||||
fprintf(vvp_out, " %%mov %u, 0, %u;\n",
|
||||
@@ -2246,6 +2433,7 @@ static struct vector_info draw_unary_expr(ivl_expr_t exp, unsigned wid)
|
||||
if (res.base < 4) {
|
||||
tmp.base = allocate_vector(res.wid);
|
||||
tmp.wid = res.wid;
|
||||
assert(res.base);
|
||||
fprintf(vvp_out, " %%mov %u, %u, %u;\n",
|
||||
tmp.base, res.base, res.wid);
|
||||
res = tmp;
|
||||
@@ -2269,6 +2457,7 @@ static struct vector_info draw_unary_expr(ivl_expr_t exp, unsigned wid)
|
||||
struct vector_info tmp;
|
||||
tmp.base = allocate_vector(wid);
|
||||
tmp.wid = wid;
|
||||
assert(res.base);
|
||||
fprintf(vvp_out, " %%mov %u, %u, %u;\n",
|
||||
tmp.base, res.base, res.wid);
|
||||
fprintf(vvp_out, " %%mov %u, 0, %u;\n",
|
||||
@@ -2278,6 +2467,32 @@ static struct vector_info draw_unary_expr(ivl_expr_t exp, unsigned wid)
|
||||
}
|
||||
break;
|
||||
|
||||
case 'm': /* abs() */
|
||||
res = draw_eval_expr_wid(sub, wid, 0);
|
||||
|
||||
if (!ivl_expr_signed(sub))
|
||||
break;
|
||||
|
||||
if (res.base == 0 || res.base == 2 || res.base == 3)
|
||||
break;
|
||||
|
||||
/* Handle the special case of a -1 constant. Make the
|
||||
result a 1. */
|
||||
if (res.base == 1) {
|
||||
res.base = allocate_vector(wid);
|
||||
fprintf(vvp_out, " %%movi %d, 1, %u;\n",
|
||||
res.base, res.wid);
|
||||
break;
|
||||
}
|
||||
|
||||
fprintf(vvp_out, " %%cmpi/s %d, 0, %u;\n", res.base, res.wid);
|
||||
fprintf(vvp_out, " %%jmp/0xz T_%u.%u, 5;\n", thread_count, local_count);
|
||||
fprintf(vvp_out, " %%inv %d, %u;\n", res.base, res.wid);
|
||||
fprintf(vvp_out, " %%addi %d, 1, %u;\n", res.base, res.wid);
|
||||
fprintf(vvp_out, "T_%u.%u ;\n", thread_count, local_count);
|
||||
local_count += 1;
|
||||
break;
|
||||
|
||||
default:
|
||||
fprintf(stderr, "vvp error: unhandled unary: %c\n",
|
||||
ivl_expr_opcode(exp));
|
||||
|
||||
+88
-1
@@ -51,11 +51,40 @@ void clr_word(int res)
|
||||
word_alloc_mask &= ~ (1U << res);
|
||||
}
|
||||
|
||||
|
||||
static int draw_binary_real(ivl_expr_t exp)
|
||||
{
|
||||
int l, r = -1;
|
||||
|
||||
/* If the opcode is a vector only opcode then the sub expression
|
||||
* must not be a real expression, so use vector evaluation and
|
||||
* then convert that result to a real value. */
|
||||
switch (ivl_expr_opcode(exp)) {
|
||||
case 'E':
|
||||
case 'N':
|
||||
case 'l':
|
||||
case 'r':
|
||||
case 'R':
|
||||
case '&':
|
||||
case '|':
|
||||
case '^':
|
||||
case 'A':
|
||||
case 'O':
|
||||
case 'X':
|
||||
{
|
||||
struct vector_info vi;
|
||||
vi = draw_eval_expr(exp, STUFF_OK_XZ);
|
||||
int res = allocate_word();
|
||||
const char*sign_flag = ivl_expr_signed(exp)? "/s" : "";
|
||||
fprintf(vvp_out, " %%ix/get%s %d, %u, %u;\n",
|
||||
sign_flag, res, vi.base, vi.wid);
|
||||
|
||||
fprintf(vvp_out, " %%cvt/ri %d, %d;\n", res, res);
|
||||
|
||||
clr_vector(vi);
|
||||
return res;
|
||||
}
|
||||
}
|
||||
|
||||
l = draw_eval_real(ivl_expr_oper1(exp));
|
||||
r = draw_eval_real(ivl_expr_oper2(exp));
|
||||
|
||||
@@ -83,6 +112,42 @@ static int draw_binary_real(ivl_expr_t exp)
|
||||
case 'p':
|
||||
fprintf(vvp_out, " %%pow/wr %d, %d;\n", l, r);
|
||||
break;
|
||||
|
||||
case 'm': { // min(l,r)
|
||||
int lab_out = local_count++;
|
||||
int lab_r = local_count++;
|
||||
/* If r is NaN, the go out and accept l as result. */
|
||||
fprintf(vvp_out, " %%cmp/wr %d, %d; Is NaN?\n", r, r);
|
||||
fprintf(vvp_out, " %%jmp/0xz T_%d.%d, 4;\n", thread_count, lab_out);
|
||||
/* If l is NaN, the go out and accept r as result. */
|
||||
fprintf(vvp_out, " %%cmp/wr %d, %d; Is NaN?\n", l, l);
|
||||
fprintf(vvp_out, " %%jmp/0xz T_%d.%d, 4;\n", thread_count, lab_r);
|
||||
/* If l <= r then go out. */
|
||||
fprintf(vvp_out, " %%cmp/wr %d, %d;\n", r, l);
|
||||
fprintf(vvp_out, " %%jmp/0xz T_%d.%d, 5;\n", thread_count, lab_out);
|
||||
/* At this point we know we want r as the result. */
|
||||
fprintf(vvp_out, "T_%d.%d %%mov/wr %d, %d;\n", thread_count, lab_r, l, r);
|
||||
fprintf(vvp_out, "T_%d.%d ;\n", thread_count, lab_out);
|
||||
break;
|
||||
}
|
||||
|
||||
case 'M': { // max(l,r)
|
||||
int lab_out = local_count++;
|
||||
int lab_r = local_count++;
|
||||
/* If r is NaN, the go out and accept l as result. */
|
||||
fprintf(vvp_out, " %%cmp/wr %d, %d; Is NaN?\n", r, r);
|
||||
fprintf(vvp_out, " %%jmp/0xz T_%d.%d, 4;\n", thread_count, lab_out);
|
||||
/* If l is NaN, the go out and accept r as result. */
|
||||
fprintf(vvp_out, " %%cmp/wr %d, %d; Is NaN?\n", l, l);
|
||||
fprintf(vvp_out, " %%jmp/0xz T_%d.%d, 4;\n", thread_count, lab_r);
|
||||
/* if l >= r then go out. */
|
||||
fprintf(vvp_out, " %%cmp/wr %d, %d;\n", l, r);
|
||||
fprintf(vvp_out, " %%jmp/0xz T_%d.%d, 5;\n", thread_count, lab_out);
|
||||
|
||||
fprintf(vvp_out, "T_%d.%d %%mov/wr %d, %d;\n", thread_count, lab_r, l, r);
|
||||
fprintf(vvp_out, "T_%d.%d ;\n", thread_count, lab_out);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
fprintf(stderr, "XXXX draw_binary_real(%c)\n",
|
||||
ivl_expr_opcode(exp));
|
||||
@@ -359,6 +424,23 @@ static int draw_ternary_real(ivl_expr_t exp)
|
||||
|
||||
static int draw_unary_real(ivl_expr_t exp)
|
||||
{
|
||||
/* If the opcode is a ~ then the sub expression must not be a
|
||||
* real expression, so use vector evaluation and then convert
|
||||
* that result to a real value. */
|
||||
if (ivl_expr_opcode(exp) == '~') {
|
||||
struct vector_info vi;
|
||||
vi = draw_eval_expr(exp, STUFF_OK_XZ);
|
||||
int res = allocate_word();
|
||||
const char*sign_flag = ivl_expr_signed(exp)? "/s" : "";
|
||||
fprintf(vvp_out, " %%ix/get%s %d, %u, %u;\n",
|
||||
sign_flag, res, vi.base, vi.wid);
|
||||
|
||||
fprintf(vvp_out, " %%cvt/ri %d, %d;\n", res, res);
|
||||
|
||||
clr_vector(vi);
|
||||
return res;
|
||||
}
|
||||
|
||||
ivl_expr_t sube = ivl_expr_oper1(exp);
|
||||
int sub = draw_eval_real(sube);
|
||||
|
||||
@@ -374,6 +456,11 @@ static int draw_unary_real(ivl_expr_t exp)
|
||||
return res;
|
||||
}
|
||||
|
||||
if (ivl_expr_opcode(exp) == 'm') { /* abs(sube) */
|
||||
fprintf(vvp_out, " %%abs/wr %d, %d;\n", sub, sub);
|
||||
return sub;
|
||||
}
|
||||
|
||||
fprintf(vvp_out, "; XXXX unary (%c)\n", ivl_expr_opcode(exp));
|
||||
fprintf(stderr, "XXXX evaluate unary (%c)\n", ivl_expr_opcode(exp));
|
||||
return 0;
|
||||
|
||||
+2
-1
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2007 Stephen Williams (steve@icarus.com)
|
||||
* Copyright (c) 2007-2008 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
|
||||
@@ -68,6 +68,7 @@ static void draw_modpath_record(const char*label, const char*driver,
|
||||
src_drivers[idx] = draw_net_input(src);
|
||||
|
||||
if (con) con_drivers[idx] = draw_net_input(con);
|
||||
else if (ivl_path_is_condit(path)) con_drivers[idx] = "";
|
||||
else con_drivers[idx] = 0;
|
||||
}
|
||||
|
||||
|
||||
@@ -91,6 +91,9 @@ static unsigned allocate_vector_no_lookaside(unsigned wid, int skip_lookaside)
|
||||
unsigned idx = 0;
|
||||
|
||||
while (idx < wid) {
|
||||
if (base+idx >= MAX_VEC)
|
||||
return 0;
|
||||
|
||||
assert((base + idx) < MAX_VEC);
|
||||
if ((allocation_map[base+idx].alloc > 0)
|
||||
|| (skip_lookaside && peek_exp(base+idx))) {
|
||||
@@ -121,6 +124,9 @@ static unsigned allocate_vector_no_lookaside(unsigned wid, int skip_lookaside)
|
||||
* again without worrying about trashing lookaside results. This
|
||||
* should lead to preferentially allocating new bits instead of
|
||||
* constantly overwriting intermediate results.
|
||||
*
|
||||
* If there is no space for a vector of the given width, then give up
|
||||
* and return 0.
|
||||
*/
|
||||
unsigned allocate_vector(unsigned wid)
|
||||
{
|
||||
|
||||
+4
-1
@@ -27,6 +27,7 @@
|
||||
# include <sys/stat.h>
|
||||
|
||||
FILE*vvp_out = 0;
|
||||
int vvp_errors = 0;
|
||||
|
||||
inline static void draw_execute_header(ivl_design_t des)
|
||||
{
|
||||
@@ -79,6 +80,8 @@ int target_design(ivl_design_t des)
|
||||
return -1;
|
||||
}
|
||||
|
||||
vvp_errors = 0;
|
||||
|
||||
draw_execute_header(des);
|
||||
|
||||
{ int pre = ivl_design_time_precision(des);
|
||||
@@ -113,6 +116,6 @@ int target_design(ivl_design_t des)
|
||||
|
||||
fclose(vvp_out);
|
||||
|
||||
return rc;
|
||||
return rc + vvp_errors;
|
||||
}
|
||||
|
||||
|
||||
@@ -29,6 +29,11 @@
|
||||
*/
|
||||
extern FILE* vvp_out;
|
||||
|
||||
/*
|
||||
* Keep a count of errors that would render the output unusable.
|
||||
*/
|
||||
extern int vvp_errors;
|
||||
|
||||
struct vector_info {
|
||||
unsigned base;
|
||||
unsigned wid;
|
||||
|
||||
+224
-42
@@ -99,7 +99,7 @@ static void set_to_lvariable(ivl_lval_t lval,
|
||||
if (ivl_lval_mux(lval))
|
||||
part_off_ex = ivl_lval_mux(lval);
|
||||
|
||||
if (part_off_ex) {
|
||||
if (part_off_ex && ivl_signal_dimensions(sig) == 0) {
|
||||
unsigned skip_set = transient_id++;
|
||||
|
||||
/* There is a mux expression, so this must be a write to
|
||||
@@ -118,6 +118,39 @@ static void set_to_lvariable(ivl_lval_t lval,
|
||||
lookaside. */
|
||||
save_signal_lookaside(bit, sig, use_word, 0);
|
||||
|
||||
} else if (part_off_ex && ivl_signal_dimensions(sig) > 0) {
|
||||
|
||||
/* Here we have a part select write into an array word. */
|
||||
unsigned skip_set = transient_id++;
|
||||
if (word_ix) {
|
||||
draw_eval_expr_into_integer(word_ix, 3);
|
||||
fprintf(vvp_out, " %%jmp/1 t_%u, 4;\n", skip_set);
|
||||
} else {
|
||||
fprintf(vvp_out, " %%ix/load 3, %lu;\n", use_word);
|
||||
}
|
||||
draw_eval_expr_into_integer(part_off_ex, 1);
|
||||
fprintf(vvp_out, " %%jmp/1 t_%u, 4;\n", skip_set);
|
||||
fprintf(vvp_out, " %%set/av v%p, %u, %u;\n",
|
||||
sig, bit, wid);
|
||||
fprintf(vvp_out, "t_%u ;\n", skip_set);
|
||||
|
||||
} else if ((part_off>0 || ivl_lval_width(lval)!=ivl_signal_width(sig))
|
||||
&& ivl_signal_dimensions(sig) > 0) {
|
||||
|
||||
/* Here we have a part select write into an array word. */
|
||||
unsigned skip_set = transient_id++;
|
||||
if (word_ix) {
|
||||
draw_eval_expr_into_integer(word_ix, 3);
|
||||
fprintf(vvp_out, " %%jmp/1 t_%u, 4;\n", skip_set);
|
||||
} else {
|
||||
fprintf(vvp_out, " %%ix/load 3, %lu;\n", use_word);
|
||||
}
|
||||
fprintf(vvp_out, " %%ix/load 1, %u;\n", part_off);
|
||||
fprintf(vvp_out, " %%set/av v%p, %u, %u;\n",
|
||||
sig, bit, wid);
|
||||
if (word_ix) /* Only need this label if word_ix is set. */
|
||||
fprintf(vvp_out, "t_%u ;\n", skip_set);
|
||||
|
||||
} else if (part_off>0 || ivl_lval_width(lval)!=ivl_signal_width(sig)) {
|
||||
/* There is no mux expression, but a constant part
|
||||
offset. Load that into index x0 and generate a
|
||||
@@ -145,14 +178,16 @@ static void set_to_lvariable(ivl_lval_t lval,
|
||||
lookaside. */
|
||||
save_signal_lookaside(bit, sig, use_word, 0);
|
||||
|
||||
} else if (ivl_signal_array_count(sig) > 1) {
|
||||
} else if (ivl_signal_dimensions(sig) > 0) {
|
||||
|
||||
/* If the word index is a constant, then we can write
|
||||
directly to the word and save the index calculation. */
|
||||
if (word_ix == 0) {
|
||||
if (use_word < ivl_signal_array_count(sig)) {
|
||||
fprintf(vvp_out, " %%set/v v%p_%lu, %u, %u;\n",
|
||||
sig, use_word, bit, wid);
|
||||
fprintf(vvp_out, " %%ix/load 1, 0;\n");
|
||||
fprintf(vvp_out, " %%ix/load 3, %lu;\n", use_word);
|
||||
fprintf(vvp_out, " %%set/av v%p, %u, %u;\n",
|
||||
sig, bit, wid);
|
||||
} else {
|
||||
fprintf(vvp_out, " ; %%set/v v%p_%lu, %u, %u "
|
||||
"OUT OF BOUNDS\n", sig, use_word, bit, wid);
|
||||
@@ -174,29 +209,79 @@ static void set_to_lvariable(ivl_lval_t lval,
|
||||
|
||||
|
||||
} else {
|
||||
save_signal_lookaside(bit, sig, use_word, wid);
|
||||
fprintf(vvp_out, " %%set/v v%p_%lu, %u, %u;\n",
|
||||
sig, use_word, bit, wid);
|
||||
/* save_signal width of 0 CLEARS the signal from the
|
||||
lookaside. */
|
||||
save_signal_lookaside(bit, sig, use_word, 0);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
static void assign_to_array_word(ivl_signal_t lsig, ivl_expr_t word_ix,
|
||||
unsigned bit, unsigned delay, unsigned width)
|
||||
unsigned bit, unsigned delay, ivl_expr_t dexp,
|
||||
ivl_expr_t part_off_ex, unsigned width)
|
||||
{
|
||||
unsigned skip_assign = transient_id++;
|
||||
|
||||
/* Calculate array word index into index register 3 */
|
||||
draw_eval_expr_into_integer(word_ix, 3);
|
||||
/* Skip assignment if word expression is not defined. */
|
||||
fprintf(vvp_out, " %%jmp/1 t_%u, 4;\n", skip_assign);
|
||||
unsigned part_off = 0;
|
||||
if (part_off_ex == 0) {
|
||||
part_off = 0;
|
||||
} else if (number_is_immediate(part_off_ex, 64)) {
|
||||
part_off = get_number_immediate(part_off_ex);
|
||||
part_off_ex = 0;
|
||||
}
|
||||
|
||||
/* Store expression width into index word 0 */
|
||||
fprintf(vvp_out, " %%ix/load 0, %u; // word width\n", width);
|
||||
/* Store constant (0) word part select into index 1 */
|
||||
fprintf(vvp_out, " %%ix/load 1, 0;\n");
|
||||
if (dexp == 0) {
|
||||
/* Constant delay... */
|
||||
if (number_is_immediate(word_ix, 64)) {
|
||||
fprintf(vvp_out, " %%ix/load 3, %lu; address\n",
|
||||
get_number_immediate(word_ix));
|
||||
} else {
|
||||
/* Calculate array word index into index register 3 */
|
||||
draw_eval_expr_into_integer(word_ix, 3);
|
||||
/* Skip assignment if word expression is not defined. */
|
||||
fprintf(vvp_out, " %%jmp/1 t_%u, 4;\n", skip_assign);
|
||||
}
|
||||
/* Store expression width into index word 0 */
|
||||
fprintf(vvp_out, " %%ix/load 0, %u; word width\n", width);
|
||||
if (part_off_ex) {
|
||||
draw_eval_expr_into_integer(part_off_ex, 1);
|
||||
/* If the index expression has XZ bits, skip the assign. */
|
||||
fprintf(vvp_out, " %%jmp/1 t_%u, 4;\n", skip_assign);
|
||||
} else {
|
||||
/* Store word part select base into index 1 */
|
||||
fprintf(vvp_out, " %%ix/load 1, %u; part base\n", part_off);
|
||||
}
|
||||
fprintf(vvp_out, " %%assign/av v%p, %u, %u;\n", lsig,
|
||||
delay, bit);
|
||||
} else {
|
||||
/* Calculated delay... */
|
||||
int delay_index = allocate_word();
|
||||
draw_eval_expr_into_integer(dexp, delay_index);
|
||||
if (number_is_immediate(word_ix, 64)) {
|
||||
fprintf(vvp_out, " %%ix/load 3, %lu; address\n",
|
||||
get_number_immediate(word_ix));
|
||||
} else {
|
||||
/* Calculate array word index into index register 3 */
|
||||
draw_eval_expr_into_integer(word_ix, 3);
|
||||
/* Skip assignment if word expression is not defined. */
|
||||
fprintf(vvp_out, " %%jmp/1 t_%u, 4;\n", skip_assign);
|
||||
}
|
||||
/* Store expression width into index word 0 */
|
||||
fprintf(vvp_out, " %%ix/load 0, %u; word width\n", width);
|
||||
if (part_off_ex) {
|
||||
draw_eval_expr_into_integer(part_off_ex, 1);
|
||||
/* If the index expression has XZ bits, skip the assign. */
|
||||
fprintf(vvp_out, " %%jmp/1 t_%u, 4;\n", skip_assign);
|
||||
} else {
|
||||
/* Store word part select into index 1 */
|
||||
fprintf(vvp_out, " %%ix/load 1, %u; part off\n", part_off);
|
||||
}
|
||||
fprintf(vvp_out, " %%assign/av/d v%p, %d, %u;\n", lsig,
|
||||
delay_index, bit);
|
||||
}
|
||||
|
||||
fprintf(vvp_out, " %%assign/av v%p, %u, %u;\n", lsig, delay, bit);
|
||||
fprintf(vvp_out, "t_%u ;\n", skip_assign);
|
||||
|
||||
clear_expression_lookaside();
|
||||
@@ -211,17 +296,12 @@ static void assign_to_lvector(ivl_lval_t lval, unsigned bit,
|
||||
unsigned part_off = 0;
|
||||
|
||||
ivl_expr_t word_ix = ivl_lval_idx(lval);
|
||||
unsigned long use_word = 0;
|
||||
const unsigned long use_word = 0;
|
||||
|
||||
if (ivl_signal_array_count(sig) > 1) {
|
||||
assert(word_ix);
|
||||
if (! number_is_immediate(word_ix, 8*sizeof(use_word))) {
|
||||
assert(!dexp);
|
||||
assign_to_array_word(sig, word_ix, bit, delay, width);
|
||||
return;
|
||||
}
|
||||
|
||||
use_word = get_number_immediate(word_ix);
|
||||
assign_to_array_word(sig, word_ix, bit, delay, dexp, part_off_ex, width);
|
||||
return;
|
||||
}
|
||||
|
||||
if (part_off_ex == 0) {
|
||||
@@ -278,7 +358,7 @@ static void assign_to_lvector(ivl_lval_t lval, unsigned bit,
|
||||
draw_eval_expr_into_integer(dexp, delay_index);
|
||||
fprintf(vvp_out, " %%ix/load 0, %u;\n", width);
|
||||
fprintf(vvp_out, " %%ix/load 1, %u;\n", part_off);
|
||||
fprintf(vvp_out, " %%assign/v0/x1/d v%p_%lu, %u, %u;\n",
|
||||
fprintf(vvp_out, " %%assign/v0/x1/d v%p_%lu, %d, %u;\n",
|
||||
sig, use_word, delay_index, bit);
|
||||
clr_word(delay_index);
|
||||
}
|
||||
@@ -351,6 +431,14 @@ static int show_stmt_assign_vector(ivl_statement_t net)
|
||||
vec.base = allocate_vector(wid);
|
||||
vec.wid = wid;
|
||||
|
||||
if (vec.base == 0) {
|
||||
fprintf(stderr, "%s:%u: vvp.tgt error: "
|
||||
"Unable to allocate %u thread bits for "
|
||||
"r-value expression.\n", ivl_expr_file(rval),
|
||||
ivl_expr_lineno(rval), wid);
|
||||
vvp_errors += 1;
|
||||
}
|
||||
|
||||
fprintf(vvp_out, " %%cvt/vr %u, %d, %u;\n",
|
||||
vec.base, word, vec.wid);
|
||||
|
||||
@@ -581,6 +669,7 @@ static int show_stmt_block_named(ivl_statement_t net, ivl_scope_t scope)
|
||||
|
||||
static int show_stmt_case(ivl_statement_t net, ivl_scope_t sscope)
|
||||
{
|
||||
int rc = 0;
|
||||
ivl_expr_t exp = ivl_stmt_cond_expr(net);
|
||||
struct vector_info cond = draw_eval_expr(exp, 0);
|
||||
unsigned count = ivl_stmt_case_count(net);
|
||||
@@ -665,7 +754,7 @@ static int show_stmt_case(ivl_statement_t net, ivl_scope_t sscope)
|
||||
/* Emit code for the default case. */
|
||||
if (default_case < count) {
|
||||
ivl_statement_t cst = ivl_stmt_case_stmt(net, default_case);
|
||||
show_statement(cst, sscope);
|
||||
rc += show_statement(cst, sscope);
|
||||
}
|
||||
|
||||
/* Jump to the out of the case. */
|
||||
@@ -680,7 +769,7 @@ static int show_stmt_case(ivl_statement_t net, ivl_scope_t sscope)
|
||||
|
||||
fprintf(vvp_out, "T_%d.%d ;\n", thread_count, local_base+idx);
|
||||
clear_expression_lookaside();
|
||||
show_statement(cst, sscope);
|
||||
rc += show_statement(cst, sscope);
|
||||
|
||||
fprintf(vvp_out, " %%jmp T_%d.%d;\n", thread_count,
|
||||
local_base+count);
|
||||
@@ -692,11 +781,12 @@ static int show_stmt_case(ivl_statement_t net, ivl_scope_t sscope)
|
||||
fprintf(vvp_out, "T_%d.%d ;\n", thread_count, local_base+count);
|
||||
clear_expression_lookaside();
|
||||
|
||||
return 0;
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int show_stmt_case_r(ivl_statement_t net, ivl_scope_t sscope)
|
||||
{
|
||||
int rc = 0;
|
||||
ivl_expr_t exp = ivl_stmt_cond_expr(net);
|
||||
int cond = draw_eval_real(exp);
|
||||
unsigned count = ivl_stmt_case_count(net);
|
||||
@@ -739,7 +829,7 @@ static int show_stmt_case_r(ivl_statement_t net, ivl_scope_t sscope)
|
||||
fall through to this statement. */
|
||||
if (default_case < count) {
|
||||
ivl_statement_t cst = ivl_stmt_case_stmt(net, default_case);
|
||||
show_statement(cst, sscope);
|
||||
rc += show_statement(cst, sscope);
|
||||
}
|
||||
|
||||
/* Jump to the out of the case. */
|
||||
@@ -754,7 +844,7 @@ static int show_stmt_case_r(ivl_statement_t net, ivl_scope_t sscope)
|
||||
|
||||
fprintf(vvp_out, "T_%d.%d ;\n", thread_count, local_base+idx);
|
||||
clear_expression_lookaside();
|
||||
show_statement(cst, sscope);
|
||||
rc += show_statement(cst, sscope);
|
||||
|
||||
fprintf(vvp_out, " %%jmp T_%d.%d;\n", thread_count,
|
||||
local_base+count);
|
||||
@@ -768,6 +858,37 @@ static int show_stmt_case_r(ivl_statement_t net, ivl_scope_t sscope)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void force_real_to_lval(ivl_statement_t net, int res)
|
||||
{
|
||||
const char*command_name;
|
||||
|
||||
switch (ivl_statement_type(net)) {
|
||||
case IVL_ST_CASSIGN:
|
||||
command_name = "%cassign/wr";
|
||||
break;
|
||||
case IVL_ST_FORCE:
|
||||
command_name = "%force/wr";
|
||||
break;
|
||||
default:
|
||||
command_name = "ERROR";
|
||||
assert(0);
|
||||
break;
|
||||
}
|
||||
|
||||
assert(ivl_stmt_lvals(net) == 1);
|
||||
ivl_lval_t lval = ivl_stmt_lval(net, 0);
|
||||
ivl_signal_t lsig = ivl_lval_sig(lval);
|
||||
|
||||
assert(ivl_lval_width(lval) == 1);
|
||||
assert(ivl_lval_part_off(lval) == 0);
|
||||
assert(ivl_lval_idx(lval) == 0);
|
||||
/* L-Value must be a signal: reg or wire */
|
||||
assert(lsig != 0);
|
||||
|
||||
fprintf(vvp_out, " %s v%p_0, %d;\n", command_name, lsig, res);
|
||||
|
||||
}
|
||||
|
||||
static void force_vector_to_lval(ivl_statement_t net, struct vector_info rvec)
|
||||
{
|
||||
unsigned lidx;
|
||||
@@ -779,7 +900,7 @@ static void force_vector_to_lval(ivl_statement_t net, struct vector_info rvec)
|
||||
switch (ivl_statement_type(net)) {
|
||||
case IVL_ST_CASSIGN:
|
||||
command_name = "%cassign/v";
|
||||
command_name_x0 = "ERROR";
|
||||
command_name_x0 = "%cassign/x0";
|
||||
break;
|
||||
case IVL_ST_FORCE:
|
||||
command_name = "%force/v";
|
||||
@@ -903,16 +1024,28 @@ static void force_link_rval(ivl_statement_t net, ivl_expr_t rval)
|
||||
static int show_stmt_cassign(ivl_statement_t net)
|
||||
{
|
||||
ivl_expr_t rval;
|
||||
struct vector_info rvec;
|
||||
ivl_signal_t sig;
|
||||
|
||||
rval = ivl_stmt_rval(net);
|
||||
assert(rval);
|
||||
|
||||
rvec = draw_eval_expr(rval, STUFF_OK_47);
|
||||
sig = ivl_lval_sig(ivl_stmt_lval(net, 0));
|
||||
if (sig && ivl_signal_data_type(sig) == IVL_VT_REAL) {
|
||||
int res;
|
||||
|
||||
/* Write out initial continuous assign instructions to assign
|
||||
the expression value to the l-value. */
|
||||
force_vector_to_lval(net, rvec);
|
||||
res = draw_eval_real(ivl_stmt_rval(net));
|
||||
clr_word(res);
|
||||
|
||||
force_real_to_lval(net, res);
|
||||
} else {
|
||||
struct vector_info rvec;
|
||||
|
||||
rvec = draw_eval_expr(rval, STUFF_OK_47);
|
||||
|
||||
/* Write out initial continuous assign instructions to assign
|
||||
the expression value to the l-value. */
|
||||
force_vector_to_lval(net, rvec);
|
||||
}
|
||||
|
||||
force_link_rval(net, rval);
|
||||
|
||||
@@ -926,6 +1059,18 @@ static int show_stmt_cassign(ivl_statement_t net)
|
||||
*/
|
||||
static int show_stmt_deassign(ivl_statement_t net)
|
||||
{
|
||||
ivl_signal_t sig = ivl_lval_sig(ivl_stmt_lval(net, 0));
|
||||
if (sig && ivl_signal_data_type(sig) == IVL_VT_REAL) {
|
||||
assert(ivl_stmt_lvals(net) == 1);
|
||||
ivl_lval_t lval = ivl_stmt_lval(net, 0);
|
||||
assert(ivl_lval_width(lval) == 1);
|
||||
assert(ivl_lval_part_off(lval) == 0);
|
||||
assert(ivl_lval_idx(lval) == 0);
|
||||
|
||||
fprintf(vvp_out, " %%deassign/wr v%p_0;\n", sig);
|
||||
return 0;
|
||||
}
|
||||
|
||||
unsigned lidx;
|
||||
|
||||
for (lidx = 0 ; lidx < ivl_stmt_lvals(net) ; lidx += 1) {
|
||||
@@ -937,7 +1082,14 @@ static int show_stmt_deassign(ivl_statement_t net)
|
||||
|
||||
assert(lsig != 0);
|
||||
assert(ivl_lval_mux(lval) == 0);
|
||||
assert(ivl_lval_part_off(lval) == 0);
|
||||
|
||||
unsigned use_wid = ivl_lval_width(lval);
|
||||
ivl_expr_t part_off_ex = ivl_lval_part_off(lval);
|
||||
unsigned part_off = 0;
|
||||
if (part_off_ex != 0) {
|
||||
assert(number_is_immediate(part_off_ex, 64));
|
||||
part_off = get_number_immediate(part_off_ex);
|
||||
}
|
||||
|
||||
if (word_idx != 0) {
|
||||
assert(number_is_immediate(word_idx, 8*sizeof(use_word)));
|
||||
@@ -945,7 +1097,8 @@ static int show_stmt_deassign(ivl_statement_t net)
|
||||
}
|
||||
|
||||
|
||||
fprintf(vvp_out, " %%deassign v%p_%lu;\n", lsig, use_word);
|
||||
fprintf(vvp_out, " %%deassign v%p_%lu, %u, %u;\n",
|
||||
lsig, use_word, part_off, use_wid);
|
||||
}
|
||||
|
||||
return 0;
|
||||
@@ -1074,16 +1227,28 @@ static int show_stmt_disable(ivl_statement_t net, ivl_scope_t sscope)
|
||||
static int show_stmt_force(ivl_statement_t net)
|
||||
{
|
||||
ivl_expr_t rval;
|
||||
struct vector_info rvec;
|
||||
ivl_signal_t sig;
|
||||
|
||||
rval = ivl_stmt_rval(net);
|
||||
assert(rval);
|
||||
|
||||
rvec = draw_eval_expr(rval, STUFF_OK_47);
|
||||
sig = ivl_lval_sig(ivl_stmt_lval(net, 0));
|
||||
if (sig && ivl_signal_data_type(sig) == IVL_VT_REAL) {
|
||||
int res;
|
||||
|
||||
/* Write out initial continuous assign instructions to assign
|
||||
the expression value to the l-value. */
|
||||
force_vector_to_lval(net, rvec);
|
||||
res = draw_eval_real(ivl_stmt_rval(net));
|
||||
clr_word(res);
|
||||
|
||||
force_real_to_lval(net, res);
|
||||
} else {
|
||||
struct vector_info rvec;
|
||||
|
||||
rvec = draw_eval_expr(rval, STUFF_OK_47);
|
||||
|
||||
/* Write out initial continuous assign instructions to assign
|
||||
the expression value to the l-value. */
|
||||
force_vector_to_lval(net, rvec);
|
||||
}
|
||||
|
||||
force_link_rval(net, rval);
|
||||
|
||||
@@ -1172,6 +1337,22 @@ static int show_stmt_noop(ivl_statement_t net)
|
||||
|
||||
static int show_stmt_release(ivl_statement_t net)
|
||||
{
|
||||
ivl_signal_t sig = ivl_lval_sig(ivl_stmt_lval(net, 0));
|
||||
if (sig && ivl_signal_data_type(sig) == IVL_VT_REAL) {
|
||||
unsigned type = 0;
|
||||
|
||||
assert(ivl_stmt_lvals(net) == 1);
|
||||
ivl_lval_t lval = ivl_stmt_lval(net, 0);
|
||||
assert(ivl_lval_width(lval) == 1);
|
||||
assert(ivl_lval_part_off(lval) == 0);
|
||||
assert(ivl_lval_idx(lval) == 0);
|
||||
|
||||
if (ivl_signal_type(sig) == IVL_SIT_REG) type = 1;
|
||||
|
||||
fprintf(vvp_out, " %%release/wr v%p_0, %u;\n", sig, type);
|
||||
return 0;
|
||||
}
|
||||
|
||||
unsigned lidx;
|
||||
|
||||
for (lidx = 0 ; lidx < ivl_stmt_lvals(net) ; lidx += 1) {
|
||||
@@ -1313,6 +1494,7 @@ static struct vector_info reduction_or(struct vector_info cvec)
|
||||
clr_vector(cvec);
|
||||
result.base = allocate_vector(1);
|
||||
result.wid = 1;
|
||||
assert(result.base);
|
||||
fprintf(vvp_out, " %%or/r %u, %u, %u;\n", result.base,
|
||||
cvec.base, cvec.wid);
|
||||
break;
|
||||
|
||||
+69
-19
@@ -469,11 +469,10 @@ static char* draw_C8_to_string(ivl_net_const_t cptr,
|
||||
return result;
|
||||
}
|
||||
|
||||
static char* draw_Cr_to_string(ivl_net_const_t cptr)
|
||||
static char* draw_Cr_to_string(double value)
|
||||
{
|
||||
char tmp[256];
|
||||
|
||||
double value = ivl_const_real(cptr);
|
||||
uint64_t mant = 0;
|
||||
|
||||
if (isinf(value)) {
|
||||
@@ -616,6 +615,12 @@ static char* draw_net_input_drive(ivl_nexus_t nex, ivl_nexus_ptr_t nptr)
|
||||
/* Input is a .var. This device may be a non-zero pin
|
||||
because it may be an array of reg vectors. */
|
||||
snprintf(tmp, sizeof tmp, "v%p_%u", sptr, nptr_pin);
|
||||
|
||||
if (ivl_signal_array_count(sptr) > 1) {
|
||||
fprintf(vvp_out, "v%p_%u .array/port v%p, %u;\n",
|
||||
sptr, nptr_pin, sptr, nptr_pin);
|
||||
}
|
||||
|
||||
return strdup(tmp);
|
||||
}
|
||||
|
||||
@@ -641,7 +646,7 @@ static char* draw_net_input_drive(ivl_nexus_t nex, ivl_nexus_ptr_t nptr)
|
||||
break;
|
||||
|
||||
case IVL_VT_REAL:
|
||||
result = draw_Cr_to_string(cptr);
|
||||
result = draw_Cr_to_string(ivl_const_real(cptr));
|
||||
break;
|
||||
|
||||
default:
|
||||
@@ -680,6 +685,7 @@ static char* draw_net_input_drive(ivl_nexus_t nex, ivl_nexus_ptr_t nptr)
|
||||
if (lpm) switch (ivl_lpm_type(lpm)) {
|
||||
|
||||
case IVL_LPM_FF:
|
||||
case IVL_LPM_ABS:
|
||||
case IVL_LPM_ADD:
|
||||
case IVL_LPM_ARRAY:
|
||||
case IVL_LPM_CONCAT:
|
||||
@@ -988,6 +994,8 @@ const char*draw_input_from_net(ivl_nexus_t nex)
|
||||
ivl_signal_t sig = signal_of_nexus(nex, &word);
|
||||
if (sig == 0)
|
||||
return draw_net_input(nex);
|
||||
if (ivl_signal_type(sig)==IVL_SIT_REG && ivl_signal_dimensions(sig)>0)
|
||||
return draw_net_input(nex);
|
||||
|
||||
snprintf(result, sizeof result, "v%p_%u", sig, word);
|
||||
return result;
|
||||
@@ -1121,19 +1129,31 @@ static void draw_net_in_scope(ivl_signal_t sig)
|
||||
discover that the entire array can be collapsed,
|
||||
so the word count for the signal and the alias
|
||||
*must* match. */
|
||||
assert(word_count == ivl_signal_array_count(nex_data->net));
|
||||
|
||||
if (iword == 0) {
|
||||
fprintf(vvp_out, "v%p .array \"%s\", v%p; Alias to %s\n",
|
||||
sig, vvp_mangle_name(ivl_signal_basename(sig)),
|
||||
nex_data->net, ivl_signal_basename(nex_data->net));
|
||||
if (word_count == ivl_signal_array_count(nex_data->net)) {
|
||||
if (iword == 0) {
|
||||
fprintf(vvp_out, "v%p .array \"%s\", v%p; Alias to %s\n",
|
||||
sig, vvp_mangle_name(ivl_signal_basename(sig)),
|
||||
nex_data->net,
|
||||
ivl_signal_basename(nex_data->net));
|
||||
}
|
||||
/* An alias for an individual word. */
|
||||
} else {
|
||||
if (iword == 0) {
|
||||
int first = ivl_signal_array_base(sig);
|
||||
int last = first + word_count-1;
|
||||
fprintf(vvp_out, "v%p .array \"%s\", %d %d;\n",
|
||||
sig,
|
||||
vvp_mangle_name(ivl_signal_basename(sig)),
|
||||
last, first);
|
||||
}
|
||||
|
||||
fprintf(vvp_out, "v%p_%u .alias%s v%p %u, %d %d, "
|
||||
"v%p_%u; Alias to %s\n", sig, iword,
|
||||
datatype_flag, sig, iword, msb, lsb,
|
||||
nex_data->net, nex_data->net_word,
|
||||
ivl_signal_basename(nex_data->net));
|
||||
}
|
||||
/* An alias for the individual words? */
|
||||
#if 0
|
||||
fprintf(vvp_out, "v%p_%u .alias%s v%p, %d %d, v%p_%u;\n",
|
||||
sig, iword, datatype_flag, sig,
|
||||
msb, lsb, nex_data->net, nex_data->net_word);
|
||||
#endif
|
||||
} else {
|
||||
/* Finally, we may have an alias that is a word
|
||||
connected to another word. Again, this is a
|
||||
@@ -1682,6 +1702,17 @@ static const char* draw_lpm_output_delay(ivl_lpm_t net)
|
||||
return dly;
|
||||
}
|
||||
|
||||
static void draw_lpm_abs(ivl_lpm_t net)
|
||||
{
|
||||
const char*src_table[1];
|
||||
draw_lpm_data_inputs(net, 0, 1, src_table);
|
||||
|
||||
const char*dly = draw_lpm_output_delay(net);
|
||||
|
||||
fprintf(vvp_out, "L_%p%s .abs %s;\n",
|
||||
net, dly, src_table[0]);
|
||||
}
|
||||
|
||||
static void draw_lpm_add(ivl_lpm_t net)
|
||||
{
|
||||
const char*src_table[2];
|
||||
@@ -2327,6 +2358,10 @@ static void draw_lpm_in_scope(ivl_lpm_t net)
|
||||
{
|
||||
switch (ivl_lpm_type(net)) {
|
||||
|
||||
case IVL_LPM_ABS:
|
||||
draw_lpm_abs(net);
|
||||
return;
|
||||
|
||||
case IVL_LPM_ADD:
|
||||
case IVL_LPM_SUB:
|
||||
case IVL_LPM_MULT:
|
||||
@@ -2433,12 +2468,15 @@ int draw_scope(ivl_scope_t net, ivl_scope_t parent)
|
||||
default: type = "?"; assert(0);
|
||||
}
|
||||
|
||||
fprintf(vvp_out, "S_%p .scope %s, \"%s\" \"%s\"",
|
||||
fprintf(vvp_out, "S_%p .scope %s, \"%s\" \"%s\" %d %d",
|
||||
net, type, vvp_mangle_name(ivl_scope_basename(net)),
|
||||
ivl_scope_tname(net));
|
||||
ivl_scope_tname(net), ivl_file_table_index(ivl_scope_file(net)),
|
||||
ivl_scope_lineno(net));
|
||||
|
||||
if (parent) {
|
||||
fprintf(vvp_out, ", S_%p;\n", parent);
|
||||
fprintf(vvp_out, ", %d %d, S_%p;\n",
|
||||
ivl_file_table_index(ivl_scope_def_file(net)),
|
||||
ivl_scope_def_lineno(net), parent);
|
||||
} else {
|
||||
|
||||
fprintf(vvp_out, ";\n");
|
||||
@@ -2452,13 +2490,17 @@ int draw_scope(ivl_scope_t net, ivl_scope_t parent)
|
||||
ivl_expr_t pex = ivl_parameter_expr(par);
|
||||
switch (ivl_expr_type(pex)) {
|
||||
case IVL_EX_STRING:
|
||||
fprintf(vvp_out, "P_%p .param/str \"%s\", \"%s\";\n",
|
||||
fprintf(vvp_out, "P_%p .param/str \"%s\" %d %d, \"%s\";\n",
|
||||
par, ivl_parameter_basename(par),
|
||||
ivl_file_table_index(ivl_parameter_file(par)),
|
||||
ivl_parameter_lineno(par),
|
||||
ivl_expr_string(pex));
|
||||
break;
|
||||
case IVL_EX_NUMBER:
|
||||
fprintf(vvp_out, "P_%p .param/l \"%s\", %sC4<",
|
||||
fprintf(vvp_out, "P_%p .param/l \"%s\" %d %d, %sC4<",
|
||||
par, ivl_parameter_basename(par),
|
||||
ivl_file_table_index(ivl_parameter_file(par)),
|
||||
ivl_parameter_lineno(par),
|
||||
ivl_expr_signed(pex)? "+":"");
|
||||
{ const char*bits = ivl_expr_bits(pex);
|
||||
unsigned nbits = ivl_expr_width(pex);
|
||||
@@ -2468,6 +2510,14 @@ int draw_scope(ivl_scope_t net, ivl_scope_t parent)
|
||||
}
|
||||
fprintf(vvp_out, ">;\n");
|
||||
break;
|
||||
case IVL_EX_REALNUM:
|
||||
fprintf(vvp_out, "P_%p .param/real \"%s\" %d %d, %s; value=%g\n",
|
||||
par, ivl_parameter_basename(par),
|
||||
ivl_file_table_index(ivl_parameter_file(par)),
|
||||
ivl_parameter_lineno(par),
|
||||
draw_Cr_to_string(ivl_expr_dvalue(pex)),
|
||||
ivl_expr_dvalue(pex));
|
||||
break;
|
||||
default:
|
||||
fprintf(vvp_out, "; parameter type %d unsupported\n",
|
||||
ivl_expr_type(pex));
|
||||
|
||||
+115
@@ -0,0 +1,115 @@
|
||||
|
||||
The following is from the README.va_math that was included with the
|
||||
initial contribution of the va_math module. I've removed the parts
|
||||
that are obviously not applicable, i.e. how to compile the library, to
|
||||
this bundled version of the library.
|
||||
|
||||
--------
|
||||
License.
|
||||
--------
|
||||
|
||||
Verilog-A math library built for Icarus Verilog
|
||||
http://www.icarus.com/eda/verilog/
|
||||
|
||||
Copyright (C) 2007-2008 Cary R. ([email protected])
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along
|
||||
with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
|
||||
|
||||
------------------------------------------
|
||||
Standard Verilog-A Mathematical Functions.
|
||||
------------------------------------------
|
||||
|
||||
The va_math VPI module implements all the standard math functions provided
|
||||
by Verilog-A as Verilog-D system functions. The names are the same except
|
||||
like all Verilog-D system functions the name must be prefixed with a '$'.
|
||||
For reference the functions are:
|
||||
|
||||
$ln(x) -- Natural logarithm
|
||||
$log(x) -- Decimal logarithm
|
||||
$exp(x) -- Exponential
|
||||
$sqrt(x) -- Square root
|
||||
$min(x,y) -- Minimum
|
||||
$max(x,y) -- Maximum
|
||||
$abs(x) -- Absolute value
|
||||
$floor(x) -- Floor
|
||||
$ceil(x) -- Ceiling
|
||||
$pow(x,y) -- Power (x**y)
|
||||
$sin(x) -- Sine
|
||||
$cos(x) -- Cosine
|
||||
$tan(x) -- Tangent
|
||||
$asin(x) -- Arc-sine
|
||||
$acos(x) -- Arc-cosine
|
||||
$atan(x) -- Arc-tangent
|
||||
$atan2(y,x) -- Arc-tangent of y/x
|
||||
$hypot(x,y) -- Hypotenuse (sqrt(x**2 + y**2))
|
||||
$sinh(x) -- Hyperbolic sine
|
||||
$cosh(x) -- Hyperbolic cosine
|
||||
$tanh(x) -- Hyperbolic tangent
|
||||
$asinh(x) -- Arc-hyperbolic sine
|
||||
$acosh(x) -- Arc-hyperbolic cosine
|
||||
$atanh(x) -- Arc-hyperbolic tangent
|
||||
|
||||
The only limit placed on the x and y arguments by the library is that they
|
||||
must be numbers (not constant strings). The underlying C library controls
|
||||
any other limits placed on the arguments. Most libraries return +-Inf or
|
||||
NaN for results that cannot be represented with real numbers. All functions
|
||||
return a real result.
|
||||
|
||||
|
||||
------------------------------------------
|
||||
Standard Verilog-A Mathematical Constants.
|
||||
------------------------------------------
|
||||
|
||||
The Verilog-A mathematical constants can be accessed by including the
|
||||
"constants.vams" header file. It is located in the standard include
|
||||
directory. Recent version of Icarus Verilog (0.9.devel) automatically
|
||||
add this directory to the end of the list used to find include files.
|
||||
For reference the mathematical constants are:
|
||||
|
||||
`M_PI -- Pi
|
||||
`M_TWO_PI -- 2*Pi
|
||||
`M_PI_2 -- Pi/2
|
||||
`M_PI_4 -- Pi/4
|
||||
`M_1_PI -- 1/Pi
|
||||
`M_2_PI -- 2/Pi
|
||||
`M_2_SQRTPI -- 2/sqrt(Pi)
|
||||
`M_E -- e
|
||||
`M_LOG2E -- log base 2 of e
|
||||
`M_LOG10E -- log base 10 of e
|
||||
`M_LN2 -- log base e of 2
|
||||
`M_LN10 -- log base e of 10
|
||||
`M_SQRT2 -- sqrt(2)
|
||||
`M_SQRT1_2 -- 1/sqrt(2)
|
||||
|
||||
|
||||
------------------
|
||||
Using the Library.
|
||||
------------------
|
||||
|
||||
Just add "-m va_math" to your iverilog command line/command file and
|
||||
`include the "constants.vams" file as needed.
|
||||
|
||||
------
|
||||
Thanks
|
||||
------
|
||||
|
||||
I would like to thank Larry Doolittle for his suggestions and
|
||||
Stephen Williams for developing Icarus Verilog.
|
||||
|
||||
|
||||
--------
|
||||
The End.
|
||||
--------
|
||||
+40
-35
@@ -1,10 +1,15 @@
|
||||
#norootforbuild
|
||||
#
|
||||
%define rev_date 20080429
|
||||
#
|
||||
#
|
||||
Summary: Icarus Verilog
|
||||
Name: verilog
|
||||
Version: 0.9.0.20080314
|
||||
Version: 0.9.0.%{rev_date}
|
||||
Release: 0
|
||||
License: GPL
|
||||
Group: Productivity/Scientific/Electronics
|
||||
Source: verilog-20080314.tar.gz
|
||||
Source: verilog-%{rev_date}.tar.gz
|
||||
URL: http://www.icarus.com/eda/verilog/index.html
|
||||
Packager: Stephen Williams <[email protected]>
|
||||
|
||||
@@ -22,14 +27,14 @@ engineering formats, including simulation. It strives to be true
|
||||
to the IEEE-1364 standard.
|
||||
|
||||
%prep
|
||||
%setup -n verilog-20080314
|
||||
%setup -n verilog-%{rev_date}
|
||||
|
||||
%build
|
||||
./configure --prefix=/usr --mandir='$(prefix)/share/man'
|
||||
%{configure}
|
||||
make CXXFLAGS=-O
|
||||
|
||||
%install
|
||||
make prefix=$RPM_BUILD_ROOT/usr install
|
||||
%{makeinstall}
|
||||
|
||||
%clean
|
||||
rm -rf $RPM_BUILD_ROOT
|
||||
@@ -39,35 +44,35 @@ rm -rf $RPM_BUILD_ROOT
|
||||
%attr(-,root,root) %doc COPYING README.txt BUGS.txt QUICK_START.txt ieee1364-notes.txt mingw.txt swift.txt netlist.txt t-dll.txt vpi.txt xnf.txt tgt-fpga/fpga.txt cadpli/cadpli.txt xilinx-hint.txt
|
||||
%attr(-,root,root) %doc examples/*
|
||||
|
||||
%attr(-,root,root) /usr/share/man/man1/iverilog.1.gz
|
||||
%attr(-,root,root) %{_mandir}/man1/iverilog.1.gz
|
||||
#%attr(-,root,root) /usr/man/man1/iverilog-fpga.1.gz
|
||||
%attr(-,root,root) /usr/share/man/man1/iverilog-vpi.1.gz
|
||||
%attr(-,root,root) /usr/share/man/man1/vvp.1.gz
|
||||
%attr(-,root,root) %{_mandir}/man1/iverilog-vpi.1.gz
|
||||
%attr(-,root,root) %{_mandir}/man1/vvp.1.gz
|
||||
|
||||
%attr(-,root,root) /usr/bin/iverilog
|
||||
%attr(-,root,root) /usr/bin/iverilog-vpi
|
||||
%attr(-,root,root) /usr/bin/vvp
|
||||
%attr(-,root,root) /usr/lib/ivl/ivl
|
||||
%attr(-,root,root) /usr/lib/ivl/ivlpp
|
||||
%attr(-,root,root) /usr/lib/ivl/null.tgt
|
||||
%attr(-,root,root) /usr/lib/ivl/null.conf
|
||||
%attr(-,root,root) /usr/lib/ivl/null-s.conf
|
||||
%attr(-,root,root) /usr/lib/ivl/stub.tgt
|
||||
%attr(-,root,root) /usr/lib/ivl/stub.conf
|
||||
%attr(-,root,root) /usr/lib/ivl/stub-s.conf
|
||||
%attr(-,root,root) /usr/lib/ivl/vvp.tgt
|
||||
%attr(-,root,root) /usr/lib/ivl/vvp.conf
|
||||
%attr(-,root,root) /usr/lib/ivl/vvp-s.conf
|
||||
#%attr(-,root,root) /usr/lib/ivl/fpga.tgt
|
||||
#%attr(-,root,root) /usr/lib/ivl/fpga.conf
|
||||
#%attr(-,root,root) /usr/lib/ivl/fpga-s.conf
|
||||
#%attr(-,root,root) /usr/lib/ivl/xnf.conf
|
||||
#%attr(-,root,root) /usr/lib/ivl/xnf-s.conf
|
||||
%attr(-,root,root) /usr/lib/ivl/system.sft
|
||||
%attr(-,root,root) /usr/lib/ivl/system.vpi
|
||||
%attr(-,root,root) /usr/lib/ivl/cadpli.vpl
|
||||
%attr(-,root,root) /usr/lib/libvpi.a
|
||||
%attr(-,root,root) /usr/lib/libveriuser.a
|
||||
%attr(-,root,root) %{_bindir}/iverilog
|
||||
%attr(-,root,root) %{_bindir}/iverilog-vpi
|
||||
%attr(-,root,root) %{_bindir}/vvp
|
||||
%attr(-,root,root) %{_libdir}/ivl/ivl
|
||||
%attr(-,root,root) %{_libdir}/ivl/ivlpp
|
||||
%attr(-,root,root) %{_libdir}/ivl/null.tgt
|
||||
%attr(-,root,root) %{_libdir}/ivl/null.conf
|
||||
%attr(-,root,root) %{_libdir}/ivl/null-s.conf
|
||||
%attr(-,root,root) %{_libdir}/ivl/stub.tgt
|
||||
%attr(-,root,root) %{_libdir}/ivl/stub.conf
|
||||
%attr(-,root,root) %{_libdir}/ivl/stub-s.conf
|
||||
%attr(-,root,root) %{_libdir}/ivl/vvp.tgt
|
||||
%attr(-,root,root) %{_libdir}/ivl/vvp.conf
|
||||
%attr(-,root,root) %{_libdir}/ivl/vvp-s.conf
|
||||
#%attr(-,root,root) %{_libdir}/ivl/fpga.tgt
|
||||
#%attr(-,root,root) %{_libdir}/ivl/fpga.conf
|
||||
#%attr(-,root,root) %{_libdir}/ivl/fpga-s.conf
|
||||
#%attr(-,root,root) %{_libdir}/ivl/xnf.conf
|
||||
#%attr(-,root,root) %{_libdir}/ivl/xnf-s.conf
|
||||
%attr(-,root,root) %{_libdir}/ivl/system.sft
|
||||
%attr(-,root,root) %{_libdir}/ivl/system.vpi
|
||||
%attr(-,root,root) %{_libdir}/ivl/cadpli.vpl
|
||||
%attr(-,root,root) %{_libdir}/libvpi.a
|
||||
%attr(-,root,root) %{_libdir}/libveriuser.a
|
||||
%attr(-,root,root) /usr/include/ivl_target.h
|
||||
%attr(-,root,root) /usr/include/vpi_user.h
|
||||
%attr(-,root,root) /usr/include/acc_user.h
|
||||
@@ -75,8 +80,8 @@ rm -rf $RPM_BUILD_ROOT
|
||||
%attr(-,root,root) /usr/include/_pli_types.h
|
||||
|
||||
%changelog -n verilog
|
||||
* Sun Feb 28 2007 - [email protected]
|
||||
- Added formatting suitable for openSUSE packaging.
|
||||
|
||||
* Fri Jan 25 2008 - [email protected]
|
||||
- Removed vvp32 support for x86_64 build.
|
||||
|
||||
* Sun Feb 28 2007 - [email protected]
|
||||
- Added formatting suitable for openSUSE packaging.
|
||||
|
||||
+25
-8
@@ -429,6 +429,11 @@ bool verinum::is_zero() const
|
||||
return true;
|
||||
}
|
||||
|
||||
bool verinum::is_negative() const
|
||||
{
|
||||
return (bits_[nbits_-1] == V1) && has_sign();
|
||||
}
|
||||
|
||||
verinum pad_to_width(const verinum&that, unsigned width)
|
||||
{
|
||||
if (that.len() >= width)
|
||||
@@ -443,7 +448,7 @@ verinum pad_to_width(const verinum&that, unsigned width)
|
||||
verinum::V pad = that[that.len()-1];
|
||||
if (pad==verinum::V1 && !that.has_sign())
|
||||
pad = verinum::V0;
|
||||
if (that.has_len()) {
|
||||
if (that.has_len() && !that.has_sign()) {
|
||||
if (pad==verinum::Vx)
|
||||
pad = verinum::V0;
|
||||
if (pad==verinum::Vz)
|
||||
@@ -500,12 +505,20 @@ verinum trim_vnum(const verinum&that)
|
||||
unsigned top = that.len()-1;
|
||||
while ((top > 0) && (that.get(top) == verinum::V0))
|
||||
top -= 1;
|
||||
|
||||
/* Now top is the index of the highest non-zero bit. If
|
||||
that turns out to the highest bit in the vector, then
|
||||
tere is no trimming possible. */
|
||||
if (top+1 == that.len())
|
||||
return that;
|
||||
|
||||
/* Make tlen wide enough to include the highest non-zero
|
||||
bit, plus one extra 0 bit. */
|
||||
tlen = top+2;
|
||||
|
||||
/* This can only happen when the verinum is all zeros,
|
||||
so make it a single bit wide. */
|
||||
if (that.get(top) == verinum::V0) tlen -= 1;
|
||||
|
||||
}
|
||||
|
||||
verinum tmp (verinum::V0, tlen, false);
|
||||
@@ -881,14 +894,18 @@ verinum operator * (const verinum&left, const verinum&right)
|
||||
verinum result(verinum::V0, left.len() + right.len(), has_len_flag);
|
||||
result.has_sign(left.has_sign() || right.has_sign());
|
||||
|
||||
for (unsigned rdx = 0 ; rdx < right.len() ; rdx += 1) {
|
||||
verinum::V r_sign = sign_bit(right);
|
||||
for (unsigned rdx = 0 ; rdx < result.len() ; rdx += 1) {
|
||||
|
||||
if (right.get(rdx) == verinum::V0)
|
||||
verinum::V r_bit = rdx < right.len()? right.get(rdx) : r_sign;
|
||||
if (r_bit == verinum::V0)
|
||||
continue;
|
||||
|
||||
verinum::V l_sign = sign_bit(left);
|
||||
verinum::V carry = verinum::V0;
|
||||
for (unsigned ldx = 0 ; ldx < left.len() ; ldx += 1) {
|
||||
result.set(ldx+rdx, add_with_carry(left[ldx],
|
||||
for (unsigned ldx = 0 ; ldx < result.len()-rdx ; ldx += 1) {
|
||||
verinum::V l_bit = ldx < left.len()? left[ldx] : l_sign;
|
||||
result.set(ldx+rdx, add_with_carry(l_bit,
|
||||
result[rdx+ldx],
|
||||
carry));
|
||||
}
|
||||
@@ -1221,9 +1238,9 @@ verinum::V operator & (verinum::V l, verinum::V r)
|
||||
verinum::V operator ^ (verinum::V l, verinum::V r)
|
||||
{
|
||||
if (l == verinum::V0)
|
||||
return r;
|
||||
return bit4_z2x(r);
|
||||
if (r == verinum::V0)
|
||||
return l;
|
||||
return bit4_z2x(l);
|
||||
if ((l == verinum::V1) && (r == verinum::V1))
|
||||
return verinum::V0;
|
||||
|
||||
|
||||
@@ -71,6 +71,7 @@ class verinum {
|
||||
// A number is "defined" if there are no x or z bits in its value.
|
||||
bool is_defined() const;
|
||||
bool is_zero() const;
|
||||
bool is_negative() const;
|
||||
|
||||
// A number is "a string" if its value came directly from
|
||||
// an ASCII description instead of a number value.
|
||||
@@ -104,6 +105,19 @@ class verinum {
|
||||
bool string_flag_;
|
||||
};
|
||||
|
||||
/*
|
||||
* This returns the sign bit of the verinum value. If the value is
|
||||
* unsigned, then return an implicit sign bit of 0. Otherwise, return
|
||||
* the high bit.
|
||||
*/
|
||||
inline verinum::V sign_bit(const verinum&val)
|
||||
{
|
||||
if (val.has_sign())
|
||||
return val.get(val.len()-1);
|
||||
else
|
||||
return verinum::V0;
|
||||
}
|
||||
|
||||
/* Return a verinum that has the same value as the input, but is at
|
||||
least as wide as the requested width. This may involve sign
|
||||
extension, if the value is signed. */
|
||||
@@ -116,6 +130,9 @@ extern verinum trim_vnum(const verinum&);
|
||||
extern ostream& operator<< (ostream&, const verinum&);
|
||||
extern ostream& operator<< (ostream&, verinum::V);
|
||||
|
||||
inline verinum::V bit4_z2x(verinum::V bit)
|
||||
{ return bit<2? bit : verinum::Vx; /* Relies on V0 and V1 being <2 */}
|
||||
|
||||
extern verinum::V operator ~ (verinum::V l);
|
||||
extern verinum::V operator | (verinum::V l, verinum::V r);
|
||||
extern verinum::V operator & (verinum::V l, verinum::V r);
|
||||
|
||||
+24
-4
@@ -46,7 +46,7 @@ CPPFLAGS = @ident_support@ -I. -I$(srcdir)/.. -I$(srcdir) -I.. @file64_support@
|
||||
CFLAGS = -Wall @CFLAGS@
|
||||
LDFLAGS = @LDFLAGS@
|
||||
|
||||
all: dep system.vpi $(ALL32)
|
||||
all: dep system.vpi va_math.vpi $(ALL32)
|
||||
|
||||
dep:
|
||||
mkdir dep
|
||||
@@ -55,8 +55,9 @@ dep:
|
||||
$(CC) $(CPPFLAGS) $(CFLAGS) -MD -c $< -o $*.o
|
||||
mv $*.d dep
|
||||
|
||||
# Object files for system.vpi
|
||||
O = sys_table.o sys_convert.o sys_deposit.o sys_display.o sys_fileio.o \
|
||||
sys_finish.o sys_plusargs.o sys_random.o sys_random_mti.o \
|
||||
sys_finish.o sys_icarus.o sys_plusargs.o sys_random.o sys_random_mti.o \
|
||||
sys_readmem.o sys_readmem_lex.o sys_scanf.o sys_sdf.o \
|
||||
sys_time.o sys_vcd.o sys_vcdoff.o vcd_priv.o \
|
||||
mt19937int.o priv.o sdf_lexor.o sdf_parse.o stringheap.o
|
||||
@@ -68,10 +69,15 @@ endif
|
||||
O += sys_lxt2.o lxt2_write.o
|
||||
endif
|
||||
|
||||
# Object files for va_math.vpi
|
||||
V = va_math.o
|
||||
|
||||
LIBS = @LIBS@
|
||||
SYSTEM_VPI_LDFLAGS = $(LIBS)
|
||||
VA_MATH_LDFLAGS =
|
||||
ifeq (@MING32@,yes)
|
||||
SYSTEM_VPI_LDFLAGS += @EXTRALIBS@
|
||||
VA_MATH_LDFLAGS += @EXTRALIBS@
|
||||
endif
|
||||
|
||||
system.vpi: $O ../vvp/libvpi.a
|
||||
@@ -88,8 +94,11 @@ sdf_lexor.c: sdf_lexor.lex
|
||||
sdf_parse.c sdf_parse.h: $(srcdir)/sdf_parse.y
|
||||
$(YACC) --verbose -d -p sdf -o sdf_parse.c $(srcdir)/sdf_parse.y
|
||||
|
||||
va_math.vpi: $V ../vvp/libvpi.a
|
||||
$(CC) @shared@ -o $@ $V -L../vvp $(LDFLAGS) -lvpi $(VA_MATH_VPI_LDFLAGS)
|
||||
|
||||
clean:
|
||||
rm -rf *.o sys_readmem_lex.c dep system.vpi bin32
|
||||
rm -rf *.o sys_readmem_lex.c dep system.vpi va_math.vpi bin32
|
||||
rm -f sdf_lexor.c sdf_parse.c sdf_parse.output sdf_parse.h
|
||||
|
||||
distclean: clean
|
||||
@@ -97,7 +106,10 @@ distclean: clean
|
||||
|
||||
check: all
|
||||
|
||||
install: all installdirs $(vpidir)/system.vpi $(libdir)/ivl/system.sft
|
||||
install: all installdirs \
|
||||
$(vpidir)/system.vpi $(libdir)/ivl/system.sft \
|
||||
$(vpidir)/va_math.vpi $(libdir)/ivl/va_math.sft \
|
||||
$(vpidir)/include/
|
||||
|
||||
$(vpidir)/system.vpi: ./system.vpi
|
||||
$(INSTALL_PROGRAM) ./system.vpi $(vpidir)/system.vpi
|
||||
@@ -105,12 +117,20 @@ $(vpidir)/system.vpi: ./system.vpi
|
||||
$(libdir)/ivl/system.sft: system.sft
|
||||
$(INSTALL_DATA) $< $@
|
||||
|
||||
$(vpidir)/va_math.vpi: ./va_math.vpi
|
||||
$(INSTALL_PROGRAM) ./va_math.vpi $(vpidir)/va_math.vpi
|
||||
|
||||
$(libdir)/ivl/va_math.sft: va_math.sft
|
||||
$(INSTALL_DATA) $< $@
|
||||
|
||||
installdirs: ../mkinstalldirs
|
||||
$(srcdir)/../mkinstalldirs $(vpidir)
|
||||
|
||||
uninstall:
|
||||
rm -f $(vpidir)/system.vpi
|
||||
rm -f $(libdir)/ivl/system.sft
|
||||
rm -f $(vpidir)/va_math.vpi
|
||||
rm -f $(libdir)/ivl/va_math.sft
|
||||
|
||||
|
||||
-include $(patsubst %.o, dep/%.d, $O)
|
||||
|
||||
+2
-12
@@ -45,18 +45,8 @@ AC_CHECK_LIB(bz2, BZ2_bzdopen, HAVE_LIBBZ2=yes, HAVE_LIBBZ2=no)
|
||||
fi
|
||||
AC_SUBST(HAVE_LIBBZ2)
|
||||
|
||||
# --
|
||||
# Look for a dl library to use. First look for the standard dlopen
|
||||
# functions, and failing that look for the HP specific shl_load function.
|
||||
|
||||
AC_CHECK_HEADERS(dlfcn.h dl.h, break)
|
||||
|
||||
DLLIB=''
|
||||
AC_CHECK_LIB(dl,dlopen,[DLLIB=-ldl])
|
||||
if test -z "$DLLIB" ; then
|
||||
AC_CHECK_LIB(dld,shl_load,[DLLIB=-ldld])
|
||||
fi
|
||||
AC_SUBST(DLLIB)
|
||||
# fmin and fmax are needed by va_math.vpi
|
||||
AC_CHECK_FUNCS(fmin fmax)
|
||||
|
||||
AC_PROG_INSTALL
|
||||
|
||||
|
||||
+4
-1
@@ -215,7 +215,10 @@ static PLI_INT32 sys_rtoi_calltf(PLI_BYTE8*user)
|
||||
vpi_get_value(arg, &value);
|
||||
|
||||
/* convert */
|
||||
res.aval = (unsigned)value.value.real;
|
||||
if (value.value.real >= 0.0)
|
||||
res.aval = (unsigned)value.value.real;
|
||||
else
|
||||
res.aval = - (unsigned)-value.value.real;
|
||||
res.bval = 0;
|
||||
|
||||
value.format = vpiVectorVal;
|
||||
|
||||
+52
-29
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 1999 Stephen Williams (steve@icarus.com)
|
||||
* Copyright (c) 1999-2008 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,9 +16,6 @@
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
|
||||
*/
|
||||
#ifdef HAVE_CVS_IDENT
|
||||
#ident "$Id: sys_display.c,v 1.79 2007/04/18 02:40:20 steve Exp $"
|
||||
#endif
|
||||
|
||||
# include "vpi_config.h"
|
||||
|
||||
@@ -320,11 +317,17 @@ static void format_time_real(unsigned mcd, int fsize,
|
||||
}
|
||||
|
||||
|
||||
static void format_strength(unsigned int mcd, s_vpi_value*value)
|
||||
static void format_strength(unsigned int mcd, s_vpi_value*value,
|
||||
unsigned size)
|
||||
{
|
||||
char str[4];
|
||||
vpip_format_strength(str, value);
|
||||
my_mcd_printf(mcd, "%s", str);
|
||||
int bit;
|
||||
|
||||
for (bit = size-1; bit >= 0; bit -= 1) {
|
||||
vpip_format_strength(str, value, (unsigned) bit);
|
||||
my_mcd_printf(mcd, "%s", str);
|
||||
if (bit > 0) my_mcd_printf(mcd, "_");
|
||||
}
|
||||
}
|
||||
|
||||
static void format_error_msg(const char*msg, int leading_zero,
|
||||
@@ -695,7 +698,7 @@ static int format_str_char(vpiHandle scope, unsigned int mcd,
|
||||
return 1;
|
||||
}
|
||||
|
||||
format_strength(mcd, &value);
|
||||
format_strength(mcd, &value, vpi_get(vpiSize, argv[idx]));
|
||||
|
||||
use_count = 1;
|
||||
break;
|
||||
@@ -1119,6 +1122,7 @@ static PLI_INT32 sys_monitor_calltf(PLI_BYTE8*name)
|
||||
case vpiReg:
|
||||
case vpiIntegerVar:
|
||||
case vpiRealVar:
|
||||
case vpiMemoryWord:
|
||||
/* Monitoring reg and net values involves setting
|
||||
a callback for value changes. Pass the storage
|
||||
pointer for the callback itself as user_data so
|
||||
@@ -1322,12 +1326,16 @@ static unsigned int get_format_char(char **rtn, int ljust, int plus,
|
||||
s_vpi_value value;
|
||||
char *result, *fmtb;
|
||||
unsigned int size;
|
||||
unsigned int max_size = 256; /* The initial size of the buffer. */
|
||||
unsigned int ini_size = 256; /* The initial size of the buffer. */
|
||||
|
||||
/* Make sure the width fits in the initial buffer. */
|
||||
if (width+1 > ini_size) ini_size = width + 1;
|
||||
|
||||
/* The default return value is the full format. */
|
||||
result = malloc(max_size*sizeof(char));
|
||||
result = malloc(ini_size*sizeof(char));
|
||||
fmtb = format_as_string(ljust, plus, ld_zero, width, prec, fmt);
|
||||
strcpy(result, fmtb);
|
||||
size = strlen(result) + 1; /* fallback value if errors */
|
||||
switch (fmt) {
|
||||
|
||||
case '%':
|
||||
@@ -1386,13 +1394,13 @@ static unsigned int get_format_char(char **rtn, int ljust, int plus,
|
||||
}
|
||||
/* If the default buffer is too small, make it big enough. */
|
||||
size = strlen(cp) + 1;
|
||||
if (size > max_size) result = realloc(result, size*sizeof(char));
|
||||
if (size > ini_size) result = realloc(result, size*sizeof(char));
|
||||
|
||||
if (ljust == 0) sprintf(result, "%*s", width, cp);
|
||||
else sprintf(result, "%-*s", width, cp);
|
||||
size = strlen(result) + 1;
|
||||
}
|
||||
}
|
||||
size = strlen(result) + 1;
|
||||
break;
|
||||
|
||||
case 'c':
|
||||
@@ -1416,9 +1424,9 @@ static unsigned int get_format_char(char **rtn, int ljust, int plus,
|
||||
value.value.str[strlen(value.value.str)-1]);
|
||||
else sprintf(result, "%-*c", width,
|
||||
value.value.str[strlen(value.value.str)-1]);
|
||||
size = strlen(result) + 1;
|
||||
}
|
||||
}
|
||||
size = strlen(result) + 1;
|
||||
break;
|
||||
|
||||
case 'd':
|
||||
@@ -1451,13 +1459,13 @@ static unsigned int get_format_char(char **rtn, int ljust, int plus,
|
||||
strcpy(&tbuf[1], value.value.str);
|
||||
} else strcpy(&tbuf[0], value.value.str);
|
||||
/* If the default buffer is too small make it big enough. */
|
||||
if (size > max_size) result = realloc(result, size*sizeof(char));
|
||||
if (size > ini_size) result = realloc(result, size*sizeof(char));
|
||||
if (ljust == 0) sprintf(result, "%*s", width, tbuf);
|
||||
else sprintf(result, "%-*s", width, tbuf);
|
||||
free(tbuf);
|
||||
size = strlen(result) + 1;
|
||||
}
|
||||
}
|
||||
size = strlen(result) + 1;
|
||||
break;
|
||||
|
||||
case 'e':
|
||||
@@ -1485,9 +1493,9 @@ static unsigned int get_format_char(char **rtn, int ljust, int plus,
|
||||
while (*cp != '>') cp++;
|
||||
*cp = '\0';
|
||||
sprintf(result, fmtb+1, value.value.real);
|
||||
size = strlen(result) + 1;
|
||||
}
|
||||
}
|
||||
size = strlen(result) + 1;
|
||||
break;
|
||||
|
||||
/* This Verilog format specifier is not currently supported!
|
||||
@@ -1496,7 +1504,6 @@ static unsigned int get_format_char(char **rtn, int ljust, int plus,
|
||||
case 'L':
|
||||
vpi_printf("WARNING: %%%c currently unsupported %s%s.\n", fmt,
|
||||
info->name, fmtb);
|
||||
size = strlen(result) + 1;
|
||||
break;
|
||||
|
||||
case 'm':
|
||||
@@ -1532,12 +1539,12 @@ static unsigned int get_format_char(char **rtn, int ljust, int plus,
|
||||
if (width == -1) width = 0;
|
||||
/* If the default buffer is too small make it big enough. */
|
||||
size = strlen(value.value.str) + 1;
|
||||
if (size > max_size) result = realloc(result, size*sizeof(char));
|
||||
if (size > ini_size) result = realloc(result, size*sizeof(char));
|
||||
if (ljust == 0) sprintf(result, "%*s", width, value.value.str);
|
||||
else sprintf(result, "%-*s", width, value.value.str);
|
||||
size = strlen(result) + 1;
|
||||
}
|
||||
}
|
||||
size = strlen(result) + 1;
|
||||
break;
|
||||
|
||||
case 't':
|
||||
@@ -1570,6 +1577,7 @@ static unsigned int get_format_char(char **rtn, int ljust, int plus,
|
||||
get_time_real(tbuf, value.value.real, prec, time_units);
|
||||
if (ljust == 0) sprintf(result, "%*s", width, tbuf);
|
||||
else sprintf(result, "%-*s", width, tbuf);
|
||||
size = strlen(result) + 1;
|
||||
}
|
||||
} else {
|
||||
value.format = vpiDecStrVal;
|
||||
@@ -1581,16 +1589,15 @@ static unsigned int get_format_char(char **rtn, int ljust, int plus,
|
||||
get_time(tbuf, value.value.str, prec, time_units);
|
||||
if (ljust == 0) sprintf(result, "%*s", width, tbuf);
|
||||
else sprintf(result, "%-*s", width, tbuf);
|
||||
size = strlen(result) + 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
size = strlen(result) + 1;
|
||||
break;
|
||||
|
||||
case 'u':
|
||||
case 'U':
|
||||
*idx += 1;
|
||||
size = 0; /* fallback value if errors */
|
||||
if (ljust != 0 || plus != 0 || ld_zero != 0 || width != -1 ||
|
||||
prec != -1) {
|
||||
vpi_printf("WARNING: invalid format %s%s.\n", info->name, fmtb);
|
||||
@@ -1610,7 +1617,7 @@ static unsigned int get_format_char(char **rtn, int ljust, int plus,
|
||||
veclen = (vpi_get(vpiSize, info->items[*idx])+31)/32;
|
||||
size = veclen * 4 + 1;
|
||||
/* If the default buffer is too small, make it big enough. */
|
||||
if (size > max_size) result = realloc(result, size*sizeof(char));
|
||||
if (size > ini_size) result = realloc(result, size*sizeof(char));
|
||||
cp = result;
|
||||
for (word = 0; word < veclen; word += 1) {
|
||||
bits = value.value.vector[word].aval &
|
||||
@@ -1647,22 +1654,38 @@ static unsigned int get_format_char(char **rtn, int ljust, int plus,
|
||||
vpi_printf("WARNING: incompatible value for %s%s.\n", info->name,
|
||||
fmtb);
|
||||
} else {
|
||||
char tbuf[4];
|
||||
char tbuf[4], *rbuf;
|
||||
PLI_INT32 nbits;
|
||||
unsigned rsize;
|
||||
int bit;
|
||||
|
||||
/* If a width was not given use a width of zero. */
|
||||
if (width == -1) width = 0;
|
||||
vpip_format_strength(tbuf, &value);
|
||||
if (ljust == 0) sprintf(result, "%*s", width, tbuf);
|
||||
else sprintf(result, "%-*s", width, tbuf);
|
||||
nbits = vpi_get(vpiSize, info->items[*idx]);
|
||||
/* This is 4 chars for all but the last bit (strenght + "_")
|
||||
* which only needs three chars (strength), but then you need
|
||||
* space for the EOS '\0', so it is just number of bits * 4. */
|
||||
rsize = nbits*4;
|
||||
rbuf = malloc(rsize*sizeof(char));
|
||||
if (rsize > ini_size) result = realloc(result, rsize*sizeof(char));
|
||||
strcpy(rbuf, "");
|
||||
for (bit = nbits-1; bit >= 0; bit -= 1) {
|
||||
vpip_format_strength(tbuf, &value, bit);
|
||||
strcat(rbuf, tbuf);
|
||||
if (bit > 0) strcat(rbuf, "_");
|
||||
}
|
||||
if (ljust == 0) sprintf(result, "%*s", width, rbuf);
|
||||
else sprintf(result, "%-*s", width, rbuf);
|
||||
free(rbuf);
|
||||
size = strlen(result) + 1;
|
||||
}
|
||||
}
|
||||
size = strlen(result) + 1;
|
||||
break;
|
||||
|
||||
case 'z':
|
||||
case 'Z':
|
||||
*idx += 1;
|
||||
size = 0; /* fallback value if errors */
|
||||
size = strlen(result) + 1; /* fallback value if errors */
|
||||
if (ljust != 0 || plus != 0 || ld_zero != 0 || width != -1 ||
|
||||
prec != -1) {
|
||||
vpi_printf("WARNING: invalid format %s%s.\n", info->name, fmtb);
|
||||
@@ -1682,7 +1705,7 @@ static unsigned int get_format_char(char **rtn, int ljust, int plus,
|
||||
veclen = (vpi_get(vpiSize, info->items[*idx])+31)/32;
|
||||
size = 2 * veclen * 4 + 1;
|
||||
/* If the default buffer is too small, make it big enough. */
|
||||
if (size > max_size) result = realloc(result, size*sizeof(char));
|
||||
if (size > ini_size) result = realloc(result, size*sizeof(char));
|
||||
cp = result;
|
||||
for (word = 0; word < veclen; word += 1) {
|
||||
/* Write the aval followed by the bval in endian order. */
|
||||
|
||||
+31
-16
@@ -480,23 +480,40 @@ static PLI_INT32 sys_ungetc_compiletf(PLI_BYTE8*name)
|
||||
vpiHandle item = vpi_scan(argv);
|
||||
|
||||
if (item == 0) {
|
||||
vpi_printf("%s: mcd parameter missing.\n", name);
|
||||
vpi_printf("%s: character parameter missing.\n", name);
|
||||
return 0;
|
||||
}
|
||||
|
||||
type = vpi_get(vpiType, item);
|
||||
switch (type) {
|
||||
case vpiReg:
|
||||
case vpiRealVal:
|
||||
case vpiRealVal: // Is this correct?
|
||||
case vpiIntegerVar:
|
||||
break;
|
||||
default:
|
||||
vpi_printf("ERROR: %s mcd parameter must be of integral", name);
|
||||
vpi_printf(", got vpiType=%d\n", type);
|
||||
vpi_printf("ERROR: %s character parameter must be ", name);
|
||||
vpi_printf("integral, got vpiType=%d\n", type);
|
||||
vpi_free_object(argv);
|
||||
return 0;
|
||||
}
|
||||
|
||||
item = vpi_scan(argv);
|
||||
type = vpi_get(vpiType, item);
|
||||
switch (type) {
|
||||
case vpiReg:
|
||||
case vpiRealVal: // Is this correct?
|
||||
case vpiIntegerVar:
|
||||
break;
|
||||
default:
|
||||
vpi_printf("ERROR: %s mcd parameter must be integral, ", name);
|
||||
vpi_printf("got vpiType=%d\n", type);
|
||||
vpi_free_object(argv);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* That should be all the arguments. */
|
||||
item = vpi_scan(argv);
|
||||
assert(item == 0);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -504,7 +521,7 @@ static PLI_INT32 sys_ungetc_calltf(PLI_BYTE8*name)
|
||||
{
|
||||
unsigned int mcd;
|
||||
unsigned char x;
|
||||
s_vpi_value value, xvalue, rval;
|
||||
s_vpi_value val, rval;
|
||||
vpiHandle sys = vpi_handle(vpiSysTfCall, 0);
|
||||
vpiHandle argv = vpi_iterate(vpiArgument, sys);
|
||||
vpiHandle item = vpi_scan(argv);
|
||||
@@ -512,11 +529,15 @@ static PLI_INT32 sys_ungetc_calltf(PLI_BYTE8*name)
|
||||
|
||||
rval.format = vpiIntVal;
|
||||
|
||||
assert(item);
|
||||
val.format = vpiIntVal;
|
||||
vpi_get_value(item, &val);
|
||||
x = val.value.integer;
|
||||
|
||||
value.format = vpiIntVal;
|
||||
vpi_get_value(item, &value);
|
||||
mcd = value.value.integer;
|
||||
item = vpi_scan(argv);
|
||||
|
||||
val.format = vpiIntVal;
|
||||
vpi_get_value(item, &val);
|
||||
mcd = val.value.integer;
|
||||
|
||||
if (IS_MCD(mcd)) {
|
||||
rval.value.integer = EOF;
|
||||
@@ -524,12 +545,6 @@ static PLI_INT32 sys_ungetc_calltf(PLI_BYTE8*name)
|
||||
return 0;
|
||||
}
|
||||
|
||||
item = vpi_scan(argv);
|
||||
|
||||
xvalue.format = vpiIntVal;
|
||||
vpi_get_value(item, &xvalue);
|
||||
x = xvalue.value.integer;
|
||||
|
||||
fp = vpi_get_file(mcd);
|
||||
if ( !fp ) {
|
||||
rval.value.integer = EOF;
|
||||
|
||||
@@ -0,0 +1,67 @@
|
||||
/*
|
||||
* Copyright (C) 2008 Cary R. (cygcary@yahoo.com)
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*/
|
||||
|
||||
#include "vpi_config.h"
|
||||
#include <assert.h>
|
||||
#include <vpi_user.h>
|
||||
|
||||
|
||||
/*
|
||||
* Routine to return the width in bits of a CPU word (long).
|
||||
*/
|
||||
static PLI_INT32 vvp_cpu_wordsize_calltf(PLI_BYTE8* ud)
|
||||
{
|
||||
vpiHandle callh = vpi_handle(vpiSysTfCall, 0);
|
||||
assert(callh != 0);
|
||||
s_vpi_value val;
|
||||
(void) ud; /* Not used! */
|
||||
|
||||
/* Calculate the result */
|
||||
val.format = vpiIntVal;
|
||||
val.value.integer = 8*sizeof(long);
|
||||
|
||||
/* Return the result */
|
||||
vpi_put_value(callh, &val, 0, vpiNoDelay);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static PLI_INT32 size_32(PLI_BYTE8* ud)
|
||||
{
|
||||
(void) ud; /* Not used! */
|
||||
|
||||
return 32;
|
||||
}
|
||||
|
||||
/*
|
||||
* Register the function with Verilog.
|
||||
*/
|
||||
void sys_special_register(void)
|
||||
{
|
||||
s_vpi_systf_data tf_data;
|
||||
|
||||
/* Register the single argument functions. */
|
||||
tf_data.type = vpiSysFunc;
|
||||
tf_data.sysfunctype = vpiIntFunc;
|
||||
tf_data.calltf = vvp_cpu_wordsize_calltf;
|
||||
tf_data.compiletf = 0;
|
||||
tf_data.sizetf = size_32;
|
||||
tf_data.tfname = "$vvp_cpu_wordsize";
|
||||
tf_data.user_data = 0;
|
||||
vpi_register_systf(&tf_data);
|
||||
}
|
||||
+8
-3
@@ -187,7 +187,7 @@ long rtl_dist_uniform(long *seed, long start, long end)
|
||||
if (r >= 0) {
|
||||
i = (unsigned long) r;
|
||||
} else {
|
||||
i = (unsigned long) (r - 1);
|
||||
i = - ( (unsigned long) (-(r - 1)) );
|
||||
}
|
||||
if (i < start) i = start;
|
||||
if (i >= end) i = end - 1;
|
||||
@@ -197,7 +197,7 @@ long rtl_dist_uniform(long *seed, long start, long end)
|
||||
if (r >= 0) {
|
||||
i = (unsigned long) r;
|
||||
} else {
|
||||
i = (unsigned long) (r - 1);
|
||||
i = - ( (unsigned long) (-(r - 1)) );
|
||||
}
|
||||
if (i <= start) i = start + 1;
|
||||
if (i > end) i = end;
|
||||
@@ -208,7 +208,12 @@ long rtl_dist_uniform(long *seed, long start, long end)
|
||||
if (r >= 0) {
|
||||
i = (unsigned long) r;
|
||||
} else {
|
||||
i = (unsigned long) (r - 1);
|
||||
/* At least some compilers will notice that (r-1)
|
||||
is <0 when castling to unsigned long and
|
||||
replace the result with a zero. This causes
|
||||
much wrongness, so do the casting to the
|
||||
positive version and invert it back. */
|
||||
i = - ( (unsigned long) (-(r - 1)) );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+1
-9
@@ -109,7 +109,6 @@ static PLI_INT32 sys_readmem_calltf(PLI_BYTE8*name)
|
||||
FILE*file;
|
||||
unsigned addr;
|
||||
s_vpi_value value;
|
||||
vpiHandle words;
|
||||
vpiHandle sys = vpi_handle(vpiSysTfCall, 0);
|
||||
vpiHandle argv = vpi_iterate(vpiArgument, sys);
|
||||
vpiHandle item = vpi_scan(argv);
|
||||
@@ -283,11 +282,7 @@ static PLI_INT32 sys_readmem_calltf(PLI_BYTE8*name)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
words = vpi_iterate(vpiMemoryWord, mitem);
|
||||
assert(words);
|
||||
|
||||
item = vpi_scan(words);
|
||||
item = vpi_handle_by_index(mitem,min_addr);
|
||||
wwid = vpi_get(vpiSize, item);
|
||||
|
||||
/* variable that will be uses by the lexer to pass values
|
||||
@@ -347,9 +342,6 @@ static PLI_INT32 sys_readmem_calltf(PLI_BYTE8*name)
|
||||
|
||||
bailout:
|
||||
free(value.value.vector);
|
||||
|
||||
if (item)
|
||||
vpi_free_object(words);
|
||||
free(path);
|
||||
fclose(file);
|
||||
return 0;
|
||||
|
||||
+3
-5
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 1999 Stephen Williams (steve@icarus.com)
|
||||
* Copyright (c) 1999-2008 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,9 +16,6 @@
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
|
||||
*/
|
||||
#ifdef HAVE_CVS_IDENT
|
||||
#ident "$Id: sys_table.c,v 1.26 2006/08/03 05:06:04 steve Exp $"
|
||||
#endif
|
||||
|
||||
# include "vpi_config.h"
|
||||
# include "vpi_user.h"
|
||||
@@ -40,6 +37,7 @@ extern void sys_sdf_register();
|
||||
extern void sys_time_register();
|
||||
extern void sys_vcd_register();
|
||||
extern void sys_vcdoff_register();
|
||||
extern void sys_special_register();
|
||||
|
||||
#ifdef HAVE_LIBZ
|
||||
#ifdef HAVE_LIBBZ2
|
||||
@@ -181,6 +179,6 @@ void (*vlog_startup_routines[])() = {
|
||||
sys_time_register,
|
||||
sys_lxt_or_vcd_register,
|
||||
sys_sdf_register,
|
||||
sys_special_register,
|
||||
0
|
||||
};
|
||||
|
||||
|
||||
@@ -14,3 +14,4 @@ $dist_poisson vpiSysFuncInt
|
||||
$dist_chi_square vpiSysFuncInt
|
||||
$dist_t vpiSysFuncInt
|
||||
$dist_erlang vpiSysFuncInt
|
||||
$vvp_cpu_wordsize vpiSysFuncInt
|
||||
|
||||
+372
@@ -0,0 +1,372 @@
|
||||
/*
|
||||
* Verilog-A math library for Icarus Verilog
|
||||
* http://www.icarus.com/eda/verilog/
|
||||
*
|
||||
* Copyright (C) 2007-2008 Cary R. (cygcary@yahoo.com)
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*/
|
||||
|
||||
#include "vpi_config.h"
|
||||
#include <assert.h>
|
||||
#include <math.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <vpi_user.h>
|
||||
|
||||
/*
|
||||
* Compile time options: (set in the Makefile.)
|
||||
*
|
||||
* The functions fmax() and fmin() may not be available in pre-c99
|
||||
* libraries, so if they are not available you need to uncomment the
|
||||
* -DUSE_MY_FMAX_AND_FMIN in the Makefile.
|
||||
*/
|
||||
|
||||
|
||||
/*
|
||||
* These are functionally equivalent fmax() and fmin() implementations
|
||||
* that can be used when needed.
|
||||
*/
|
||||
#ifndef HAVE_FMIN
|
||||
static double va_fmin(const double x, const double y)
|
||||
{
|
||||
if (x != x) {return y;} /* x is NaN so return y. */
|
||||
if (y != y) {return x;} /* y is NaN so return x. */
|
||||
|
||||
return (x < y) ? x : y;
|
||||
}
|
||||
#endif
|
||||
#ifndef HAVE_FMAX
|
||||
static double va_fmax(const double x, const double y)
|
||||
{
|
||||
if (x != x) {return y;} /* x is NaN so return y. */
|
||||
if (y != y) {return x;} /* y is NaN so return x. */
|
||||
|
||||
return (x > y) ? x : y;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
/* Single argument functions. */
|
||||
typedef struct s_single_data {
|
||||
const char *name;
|
||||
double (*func)(double);
|
||||
} t_single_data;
|
||||
|
||||
static t_single_data va_single_data[]= {
|
||||
{"$sqrt", sqrt},
|
||||
{"$ln", log},
|
||||
{"$log", log10}, /* FIXME: The $log function is replaced by the
|
||||
$log10 function to eliminate confusion with
|
||||
the natural log. In C, "log" is ln and log10
|
||||
is log-base-10. The $log is being left in for
|
||||
compatibility. */
|
||||
{"$log10", log10},
|
||||
{"$exp", exp},
|
||||
{"$abs", fabs},
|
||||
{"$ceil", ceil},
|
||||
{"$floor", floor},
|
||||
{"$sin", sin},
|
||||
{"$cos", cos},
|
||||
{"$tan", tan},
|
||||
{"$asin", asin},
|
||||
{"$acos", acos},
|
||||
{"$atan", atan},
|
||||
{"$sinh", sinh},
|
||||
{"$cosh", cosh},
|
||||
{"$tanh", tanh},
|
||||
{"$asinh", asinh},
|
||||
{"$acosh", acosh},
|
||||
{"$atanh", atanh},
|
||||
{0, 0} /* Must be NULL terminated! */
|
||||
};
|
||||
|
||||
|
||||
/* Double argument functions. */
|
||||
typedef struct s_double_data {
|
||||
const char *name;
|
||||
double (*func)(double, double);
|
||||
} t_double_data;
|
||||
|
||||
static t_double_data va_double_data[]= {
|
||||
#ifdef HAVE_FMAX
|
||||
{"$max", fmax},
|
||||
#else
|
||||
{"$max", va_fmax},
|
||||
#endif
|
||||
#ifdef HAVE_FMIN
|
||||
{"$min", fmin},
|
||||
#else
|
||||
{"$min", va_fmin},
|
||||
#endif
|
||||
{"$pow", pow},
|
||||
{"$atan2", atan2},
|
||||
{"$hypot", hypot},
|
||||
{0, 0} /* Must be NULL terminated! */
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
* This structure holds the single argument information.
|
||||
*/
|
||||
typedef struct {
|
||||
vpiHandle arg;
|
||||
double (*func)(double);
|
||||
} va_single_t;
|
||||
|
||||
|
||||
/*
|
||||
* This structure holds the double argument information.
|
||||
*/
|
||||
typedef struct {
|
||||
vpiHandle arg1;
|
||||
vpiHandle arg2;
|
||||
double (*func)(double, double);
|
||||
} va_double_t;
|
||||
|
||||
|
||||
/*
|
||||
* Standard error message routine. The format string must take one
|
||||
* string argument (the name of the function).
|
||||
*/
|
||||
static void va_error_message(vpiHandle callh, const char* format,
|
||||
const char* name) {
|
||||
vpi_printf("%s:%d: error: ", vpi_get_str(vpiFile, callh),
|
||||
(int)vpi_get(vpiLineNo, callh));
|
||||
vpi_printf(format, name);
|
||||
vpi_control(vpiFinish, 1);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Process an argument.
|
||||
*/
|
||||
vpiHandle va_process_argument(vpiHandle callh, const char* name,
|
||||
vpiHandle arg, const char* post) {
|
||||
PLI_INT32 type;
|
||||
|
||||
if (arg == NULL) return 0;
|
||||
type = vpi_get(vpiType, arg);
|
||||
/* Math function cannot do anything with a string. */
|
||||
if ((type == vpiConstant || type == vpiParameter) &&
|
||||
(vpi_get(vpiConstType, arg) == vpiStringConst)) {
|
||||
const char* basemsg = "%s cannot process strings";
|
||||
char* msg = malloc(strlen(basemsg)+strlen(post)+3);
|
||||
strcpy(msg, basemsg);
|
||||
strcat(msg, post);
|
||||
strcat(msg, ".\n");
|
||||
va_error_message(callh, msg, name);
|
||||
free(msg);
|
||||
return 0;
|
||||
}
|
||||
return arg;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Routine to check all the single argument math functions.
|
||||
*/
|
||||
static PLI_INT32 va_single_argument_compiletf(PLI_BYTE8* ud)
|
||||
{
|
||||
assert(ud != 0);
|
||||
vpiHandle callh = vpi_handle(vpiSysTfCall, 0);
|
||||
assert(callh != 0);
|
||||
vpiHandle argv = vpi_iterate(vpiArgument, callh);
|
||||
vpiHandle arg;
|
||||
t_single_data *data = (t_single_data *) ud;
|
||||
const char *name = data->name;
|
||||
|
||||
va_single_t* fun_data = malloc(sizeof(va_single_t));
|
||||
|
||||
/* Check that malloc gave use some memory. */
|
||||
if (fun_data == 0) {
|
||||
va_error_message(callh, "%s failed to allocate memory.\n", name);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Check that there are arguments. */
|
||||
if (argv == 0) {
|
||||
va_error_message(callh, "%s requires one argument.\n", name);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* In Icarus if we have an argv we have at least one argument. */
|
||||
arg = vpi_scan(argv);
|
||||
fun_data->arg = va_process_argument(callh, name, arg, "");
|
||||
|
||||
/* These functions only take one argument. */
|
||||
arg = vpi_scan(argv);
|
||||
if (arg != 0) {
|
||||
va_error_message(callh, "%s takes only one argument.\n", name);
|
||||
}
|
||||
|
||||
/* Get the function that is to be used by the calltf routine. */
|
||||
fun_data->func = data->func;
|
||||
|
||||
vpi_put_userdata(callh, fun_data);
|
||||
|
||||
/* vpi_scan() returning 0 (NULL) has already freed argv. */
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Routine to implement the single argument math functions.
|
||||
*/
|
||||
static PLI_INT32 va_single_argument_calltf(PLI_BYTE8* ud)
|
||||
{
|
||||
vpiHandle callh = vpi_handle(vpiSysTfCall, 0);
|
||||
s_vpi_value val;
|
||||
(void) ud; /* Not used! */
|
||||
|
||||
/* Retrieve the function and argument data. */
|
||||
va_single_t* fun_data = vpi_get_userdata(callh);
|
||||
|
||||
/* Calculate the result */
|
||||
val.format = vpiRealVal;
|
||||
vpi_get_value(fun_data->arg, &val);
|
||||
val.value.real = (fun_data->func)(val.value.real);
|
||||
|
||||
/* Return the result */
|
||||
vpi_put_value(callh, &val, 0, vpiNoDelay);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Routine to check all the double argument math functions.
|
||||
*/
|
||||
static PLI_INT32 va_double_argument_compiletf(PLI_BYTE8* ud)
|
||||
{
|
||||
assert(ud != 0);
|
||||
vpiHandle callh = vpi_handle(vpiSysTfCall, 0);
|
||||
assert(callh != 0);
|
||||
vpiHandle argv = vpi_iterate(vpiArgument, callh);
|
||||
vpiHandle arg;
|
||||
t_double_data *data = (t_double_data *) ud;
|
||||
const char *name = data->name;
|
||||
|
||||
va_double_t* fun_data = malloc(sizeof(va_double_t));
|
||||
|
||||
/* Check that malloc gave use some memory. */
|
||||
if (fun_data == 0) {
|
||||
va_error_message(callh, "%s failed to allocate memory.\n", name);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Check that there are arguments. */
|
||||
if (argv == 0) {
|
||||
va_error_message(callh, "%s requires two arguments.\n", name);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* In Icarus if we have an argv we have at least one argument. */
|
||||
arg = vpi_scan(argv);
|
||||
fun_data->arg1 = va_process_argument(callh, name, arg, " (arg1)");
|
||||
|
||||
/* Check that there are at least two arguments. */
|
||||
arg = vpi_scan(argv);
|
||||
if (arg == 0) {
|
||||
va_error_message(callh, "%s requires two arguments.\n", name);
|
||||
}
|
||||
fun_data->arg2 = va_process_argument(callh, name, arg, " (arg2)");
|
||||
|
||||
/* These functions only take two arguments. */
|
||||
arg = vpi_scan(argv);
|
||||
if (arg != 0) {
|
||||
va_error_message(callh, "%s takes only two arguments.\n", name);
|
||||
}
|
||||
|
||||
/* Get the function that is to be used by the calltf routine. */
|
||||
fun_data->func = data->func;
|
||||
|
||||
vpi_put_userdata(callh, fun_data);
|
||||
|
||||
/* vpi_scan() returning 0 (NULL) has already freed argv. */
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Routine to implement the double argument math functions.
|
||||
*/
|
||||
static PLI_INT32 va_double_argument_calltf(PLI_BYTE8 *ud)
|
||||
{
|
||||
vpiHandle callh = vpi_handle(vpiSysTfCall, 0);
|
||||
s_vpi_value val;
|
||||
double first_arg;
|
||||
(void) ud; /* Not used! */
|
||||
|
||||
/* Retrieve the function and argument data. */
|
||||
va_double_t* fun_data = vpi_get_userdata(callh);
|
||||
|
||||
/* Calculate the result */
|
||||
val.format = vpiRealVal;
|
||||
vpi_get_value(fun_data->arg1, &val);
|
||||
first_arg = val.value.real;
|
||||
vpi_get_value(fun_data->arg2, &val);
|
||||
val.value.real = (fun_data->func)(first_arg, val.value.real);
|
||||
|
||||
/* Return the result */
|
||||
vpi_put_value(callh, &val, 0, vpiNoDelay);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Register all the functions with Verilog.
|
||||
*/
|
||||
static void va_math_register(void)
|
||||
{
|
||||
s_vpi_systf_data tf_data;
|
||||
unsigned idx;
|
||||
|
||||
/* Register the single argument functions. */
|
||||
tf_data.type = vpiSysFunc;
|
||||
tf_data.sysfunctype = vpiRealFunc;
|
||||
tf_data.calltf = va_single_argument_calltf;
|
||||
tf_data.compiletf = va_single_argument_compiletf;
|
||||
tf_data.sizetf = 0;
|
||||
|
||||
for (idx=0; va_single_data[idx].name != 0; idx++) {
|
||||
tf_data.tfname = va_single_data[idx].name;
|
||||
tf_data.user_data = (PLI_BYTE8 *) &va_single_data[idx];
|
||||
vpi_register_systf(&tf_data);
|
||||
}
|
||||
|
||||
/* Register the double argument functions. */
|
||||
tf_data.type = vpiSysFunc;
|
||||
tf_data.sysfunctype = vpiRealFunc;
|
||||
tf_data.calltf = va_double_argument_calltf;
|
||||
tf_data.compiletf = va_double_argument_compiletf;
|
||||
tf_data.sizetf = 0;
|
||||
|
||||
for (idx=0; va_double_data[idx].name != 0; idx++) {
|
||||
tf_data.tfname = va_double_data[idx].name;
|
||||
tf_data.user_data = (PLI_BYTE8 *) &va_double_data[idx];
|
||||
vpi_register_systf(&tf_data);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Hook to get Icarus Verilog to find the registration function.
|
||||
*/
|
||||
void (*vlog_startup_routines[])(void) = {
|
||||
va_math_register,
|
||||
0
|
||||
};
|
||||
@@ -0,0 +1,32 @@
|
||||
#
|
||||
# This is the system function descriptor table for the
|
||||
# Verilog-A math functions.
|
||||
#
|
||||
|
||||
# Single argument functions.
|
||||
$sqrt vpiSysFuncReal
|
||||
$ln vpiSysFuncReal
|
||||
$log vpiSysFuncReal
|
||||
$log10 vpiSysFuncReal
|
||||
$exp vpiSysFuncReal
|
||||
$abs vpiSysFuncReal
|
||||
$ceil vpiSysFuncReal
|
||||
$floor vpiSysFuncReal
|
||||
$sin vpiSysFuncReal
|
||||
$cos vpiSysFuncReal
|
||||
$tan vpiSysFuncReal
|
||||
$asin vpiSysFuncReal
|
||||
$acos vpiSysFuncReal
|
||||
$atan vpiSysFuncReal
|
||||
$sinh vpiSysFuncReal
|
||||
$cosh vpiSysFuncReal
|
||||
$tanh vpiSysFuncReal
|
||||
$asinh vpiSysFuncReal
|
||||
$acosh vpiSysFuncReal
|
||||
$atanh vpiSysFuncReal
|
||||
# Double argument functions.
|
||||
$min vpiSysFuncReal
|
||||
$max vpiSysFuncReal
|
||||
$pow vpiSysFuncReal
|
||||
$atan2 vpiSysFuncReal
|
||||
$hypot vpiSysFuncReal
|
||||
+4
-16
@@ -1,7 +1,7 @@
|
||||
#ifndef __vpi_config_H
|
||||
#define __config_H
|
||||
#define __vpi_config_H
|
||||
/*
|
||||
* Copyright (c) 2004 Stephen Williams ([email protected])
|
||||
* Copyright (c) 2004-2008 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,13 @@
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
|
||||
*/
|
||||
#ifdef HAVE_CVS_IDENT
|
||||
#ident "$Id: vpi_config.h.in,v 1.2 2004/01/26 21:52:46 steve Exp $"
|
||||
#endif
|
||||
|
||||
# undef HAVE_LIBIBERTY_H
|
||||
# undef HAVE_MALLOC_H
|
||||
# undef HAVE_DLFCN_H
|
||||
# undef HAVE_DL_H
|
||||
# undef HAVE_LIBZ
|
||||
# undef HAVE_LIBBZ2
|
||||
# undef HAVE_FMIN
|
||||
# undef HAVE_FMAX
|
||||
# undef WORDS_BIGENDIAN
|
||||
|
||||
# undef _LARGEFILE_SOURCE
|
||||
@@ -35,13 +32,4 @@
|
||||
# define _FILE_OFFSET_BITS 64
|
||||
#endif
|
||||
|
||||
/*
|
||||
* $Log: vpi_config.h.in,v $
|
||||
* Revision 1.2 2004/01/26 21:52:46 steve
|
||||
* Make sure file64 support is on cc -D flags.
|
||||
*
|
||||
* Revision 1.1 2004/01/21 01:22:53 steve
|
||||
* Give the vip directory its own configure and vpi_config.h
|
||||
*
|
||||
*/
|
||||
#endif // __config_H
|
||||
|
||||
+4
-2
@@ -1,7 +1,7 @@
|
||||
#ifndef __vpi_user_H
|
||||
#define __vpi_user_H
|
||||
/*
|
||||
* Copyright (c) 1999-2007 Stephen Williams (steve@icarus.com)
|
||||
* Copyright (c) 1999-2008 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
|
||||
@@ -312,6 +312,8 @@ typedef struct t_vpi_delay {
|
||||
#define vpiDefName 9
|
||||
#define vpiTimeUnit 11
|
||||
#define vpiTimePrecision 12
|
||||
#define vpiDefFile 15
|
||||
#define vpiDefLineNo 16
|
||||
#define vpiNetType 22
|
||||
# define vpiWire 1
|
||||
#define vpiArray 28
|
||||
@@ -560,7 +562,7 @@ extern DLLEXPORT void (*vlog_startup_routines[])();
|
||||
|
||||
/* Format a scalar a la %v. The str points to a 4byte character
|
||||
buffer. The value must be a vpiStrengthVal. */
|
||||
extern void vpip_format_strength(char*str, s_vpi_value*value);
|
||||
extern void vpip_format_strength(char*str, s_vpi_value*value, unsigned bit);
|
||||
|
||||
EXTERN_C_END
|
||||
|
||||
|
||||
+4
-4
@@ -70,14 +70,14 @@ check: all
|
||||
|
||||
V = vpi_modules.o vpi_callback.o vpi_const.o vpi_event.o vpi_iter.o vpi_mcd.o \
|
||||
vpi_priv.o vpi_scope.o vpi_real.o vpi_signal.o vpi_tasks.o vpi_time.o \
|
||||
vpi_memory.o vpi_vthr_vector.o vpip_bin.o vpip_hex.o vpip_oct.o \
|
||||
vpi_vthr_vector.o vpip_bin.o vpip_hex.o vpip_oct.o \
|
||||
vpip_to_dec.o vpip_format.o vvp_vpi.o
|
||||
|
||||
O = main.o parse.o parse_misc.o lexor.o arith.o array.o bufif.o compile.o \
|
||||
concat.o \
|
||||
dff.o extend.o npmos.o part.o reduce.o resolv.o sfunc.o stop.o symbols.o \
|
||||
ufunc.o codes.o \
|
||||
vthread.o schedule.o statistics.o tables.o udp.o vvp_net.o memory.o \
|
||||
vthread.o schedule.o statistics.o tables.o udp.o vvp_net.o \
|
||||
event.o logic.o delay.o words.o $V
|
||||
|
||||
ifeq (@WIN32@,yes)
|
||||
@@ -85,9 +85,9 @@ ifeq (@WIN32@,yes)
|
||||
# The first step makes an ivl.exe that dlltool can use to make an
|
||||
# export and import library, and the last link makes a, ivl.exe
|
||||
# that really exports the things that the import library imports.
|
||||
vvp@EXEEXT@ libvpi.a: $O vvp.def
|
||||
vvp@EXEEXT@ libvpi.a: $O $(srcdir)/vvp.def
|
||||
$(CXX) -o vvp@EXEEXT@ $(LDFLAGS) $O $(dllib) $(LIBS)
|
||||
dlltool --dllname vvp@EXEEXT@ --def vvp.def \
|
||||
dlltool --dllname vvp@EXEEXT@ --def $(srcdir)/vvp.def \
|
||||
--output-lib libvpi.a --output-exp vvp.exp
|
||||
$(CXX) $(LDFLAGS) -o vvp@EXEEXT@ vvp.exp $(LDFLAGS) $O $(dllib) $(LIBS)
|
||||
else
|
||||
|
||||
@@ -55,6 +55,41 @@ void vvp_arith_::dispatch_operand_(vvp_net_ptr_t ptr, vvp_vector4_t bit)
|
||||
}
|
||||
|
||||
|
||||
vvp_arith_abs::vvp_arith_abs()
|
||||
{
|
||||
}
|
||||
|
||||
vvp_arith_abs::~vvp_arith_abs()
|
||||
{
|
||||
}
|
||||
|
||||
void vvp_arith_abs::recv_vec4(vvp_net_ptr_t ptr, const vvp_vector4_t&bit)
|
||||
{
|
||||
vvp_vector4_t out (bit.size(), BIT4_0);;
|
||||
|
||||
vvp_bit4_t cmp = compare_gtge_signed(bit, out, BIT4_1);
|
||||
switch (cmp) {
|
||||
case BIT4_1: // bit >= 0
|
||||
out = bit;
|
||||
break;
|
||||
case BIT4_0: // bit < 0
|
||||
out = ~bit;
|
||||
out += 1;
|
||||
break;
|
||||
default: // There's an X.
|
||||
out = vvp_vector4_t(bit.size(), BIT4_X);
|
||||
break;
|
||||
}
|
||||
|
||||
vvp_send_vec4(ptr.ptr()->out, out);
|
||||
}
|
||||
|
||||
void vvp_arith_abs::recv_real(vvp_net_ptr_t ptr, double bit)
|
||||
{
|
||||
double out = fabs(bit);
|
||||
vvp_send_real(ptr.ptr()->out, out);
|
||||
}
|
||||
|
||||
// Division
|
||||
|
||||
vvp_arith_div::vvp_arith_div(unsigned wid, bool signed_flag)
|
||||
|
||||
+11
@@ -49,6 +49,17 @@ class vvp_arith_ : public vvp_net_fun_t {
|
||||
vvp_vector4_t x_val_;
|
||||
};
|
||||
|
||||
class vvp_arith_abs : public vvp_net_fun_t {
|
||||
public:
|
||||
explicit vvp_arith_abs();
|
||||
~vvp_arith_abs();
|
||||
|
||||
void recv_vec4(vvp_net_ptr_t ptr, const vvp_vector4_t&bit);
|
||||
void recv_real(vvp_net_ptr_t ptr, double bit);
|
||||
|
||||
private:
|
||||
};
|
||||
|
||||
class vvp_arith_div : public vvp_arith_ {
|
||||
|
||||
public:
|
||||
|
||||
+440
-51
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2007 Stephen Williams (steve@icarus.com)
|
||||
* Copyright (c) 2007-2008 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,9 +16,6 @@
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
|
||||
*/
|
||||
#ifdef HAVE_CVS_IDENT
|
||||
#ident "$Id: array.cc,v 1.2 2007/04/10 01:26:16 steve Exp $"
|
||||
#endif
|
||||
|
||||
# include "array.h"
|
||||
#include "symbols.h"
|
||||
@@ -38,7 +35,7 @@ static symbol_table_t array_table =0;
|
||||
class vvp_fun_arrayport;
|
||||
static void array_attach_port(vvp_array_t, vvp_fun_arrayport*);
|
||||
|
||||
vvp_array_t array_find(char*label)
|
||||
vvp_array_t array_find(const char*label)
|
||||
{
|
||||
if (array_table == 0)
|
||||
return 0;
|
||||
@@ -58,9 +55,15 @@ struct __vpiArray {
|
||||
unsigned array_count;
|
||||
struct __vpiDecConst first_addr;
|
||||
struct __vpiDecConst last_addr;
|
||||
vpiHandle*words;
|
||||
// If this is a net array, nets lists the handles.
|
||||
vpiHandle*nets;
|
||||
// If this is a var array, then these are used instead of nets.
|
||||
vvp_vector4_t *vals;
|
||||
unsigned vals_width;
|
||||
struct __vpiArrayWord*vals_words;
|
||||
|
||||
class vvp_fun_arrayport*ports_;
|
||||
struct __vpiCallback *vpi_callbacks;
|
||||
};
|
||||
|
||||
struct __vpiArrayIterator {
|
||||
@@ -75,6 +78,36 @@ struct __vpiArrayIndex {
|
||||
unsigned done;
|
||||
};
|
||||
|
||||
struct __vpiArrayVthrA {
|
||||
struct __vpiHandle base;
|
||||
struct __vpiArray*array;
|
||||
unsigned address;
|
||||
};
|
||||
|
||||
/*
|
||||
* The vpiArrayWord is magic. It is used as the handle to return when
|
||||
* vpi code tries to index or scan an array of variable words. The
|
||||
* array word handle contains no actual data. It is just a hook for
|
||||
* the vpi methods and to point to the parent.
|
||||
*
|
||||
* How the point to the parent works is tricky. The vpiArrayWord
|
||||
* objects for an array are themselves allocated as an array. All the
|
||||
* ArrayWord objects in the array have a word0 that points to the base
|
||||
* of the array. Thus, the position into the array (and the index into
|
||||
* the memory) is calculated by subtracting word0 from the ArrayWord
|
||||
* pointer.
|
||||
*
|
||||
* To then get to the parent, use word0[-1].parent.
|
||||
*/
|
||||
struct __vpiArrayWord {
|
||||
struct __vpiHandle base;
|
||||
union {
|
||||
struct __vpiArray*parent;
|
||||
struct __vpiArrayWord*word0;
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
static int vpi_array_get(int code, vpiHandle ref);
|
||||
static char*vpi_array_get_str(int code, vpiHandle ref);
|
||||
static vpiHandle vpi_array_get_handle(int code, vpiHandle ref);
|
||||
@@ -87,6 +120,14 @@ static int array_iterator_free_object(vpiHandle ref);
|
||||
static vpiHandle array_index_scan(vpiHandle ref, int);
|
||||
static int array_index_free_object(vpiHandle ref);
|
||||
|
||||
static int vpi_array_var_word_get(int code, vpiHandle);
|
||||
static void vpi_array_var_word_get_value(vpiHandle, p_vpi_value);
|
||||
static vpiHandle vpi_array_var_word_put_value(vpiHandle, p_vpi_value, int);
|
||||
|
||||
static int vpi_array_vthr_A_get(int code, vpiHandle);
|
||||
static void vpi_array_vthr_A_get_value(vpiHandle, p_vpi_value);
|
||||
static vpiHandle vpi_array_vthr_A_put_value(vpiHandle, p_vpi_value, int);
|
||||
|
||||
static const struct __vpirt vpip_arraymem_rt = {
|
||||
vpiMemory,
|
||||
vpi_array_get,
|
||||
@@ -125,14 +166,86 @@ static const struct __vpirt vpip_array_index_rt = {
|
||||
array_index_free_object
|
||||
};
|
||||
|
||||
static const struct __vpirt vpip_array_var_word_rt = {
|
||||
vpiMemoryWord,
|
||||
&vpi_array_var_word_get,
|
||||
0,
|
||||
&vpi_array_var_word_get_value,
|
||||
&vpi_array_var_word_put_value,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0
|
||||
};
|
||||
|
||||
static const struct __vpirt vpip_array_vthr_A_rt = {
|
||||
vpiMemoryWord,
|
||||
&vpi_array_vthr_A_get,
|
||||
0,
|
||||
&vpi_array_vthr_A_get_value,
|
||||
&vpi_array_vthr_A_put_value,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0
|
||||
};
|
||||
|
||||
# define ARRAY_HANDLE(ref) (assert(ref->vpi_type->type_code==vpiMemory), \
|
||||
(struct __vpiArray*)ref)
|
||||
|
||||
static struct __vpiArrayWord* array_var_word_from_handle(vpiHandle ref)
|
||||
{
|
||||
if (ref == 0)
|
||||
return 0;
|
||||
if (ref->vpi_type != &vpip_array_var_word_rt)
|
||||
return 0;
|
||||
|
||||
return (struct __vpiArrayWord*) ref;
|
||||
}
|
||||
|
||||
static struct __vpiArrayVthrA* array_vthr_a_from_handle(vpiHandle ref)
|
||||
{
|
||||
if (ref == 0)
|
||||
return 0;
|
||||
if (ref->vpi_type != &vpip_array_vthr_A_rt)
|
||||
return 0;
|
||||
|
||||
return (struct __vpiArrayVthrA*) ref;
|
||||
}
|
||||
|
||||
static void array_make_vals_words(struct __vpiArray*parent)
|
||||
{
|
||||
assert(parent->vals_words == 0);
|
||||
parent->vals_words = new struct __vpiArrayWord[parent->array_count + 1];
|
||||
|
||||
// Make word[-1] point to the parent.
|
||||
parent->vals_words->parent = parent;
|
||||
// Now point to word-0
|
||||
parent->vals_words += 1;
|
||||
|
||||
struct __vpiArrayWord*words = parent->vals_words;
|
||||
for (unsigned idx = 0 ; idx < parent->array_count ; idx += 1) {
|
||||
words[idx].base.vpi_type = &vpip_array_var_word_rt;
|
||||
words[idx].word0 = words;
|
||||
}
|
||||
}
|
||||
|
||||
static unsigned decode_array_word_pointer(struct __vpiArrayWord*word,
|
||||
struct __vpiArray*&parent)
|
||||
{
|
||||
struct __vpiArrayWord*word0 = word->word0;
|
||||
parent = (word0 - 1) -> parent;
|
||||
return word - word0;
|
||||
}
|
||||
|
||||
static int vpi_array_get(int code, vpiHandle ref)
|
||||
{
|
||||
struct __vpiArray*obj = ARRAY_HANDLE(ref);
|
||||
|
||||
switch (code) {
|
||||
case vpiLineNo:
|
||||
return 0; // Not implemented for now!
|
||||
|
||||
case vpiSize:
|
||||
return (int) obj->array_count;
|
||||
|
||||
@@ -145,6 +258,10 @@ static char*vpi_array_get_str(int code, vpiHandle ref)
|
||||
{
|
||||
struct __vpiArray*obj = ARRAY_HANDLE(ref);
|
||||
|
||||
if (code == vpiFile) { // Not implemented for now!
|
||||
return simple_set_rbuf_str(file_names[0]);
|
||||
}
|
||||
|
||||
return generic_get_str(code, &obj->scope->base, obj->name, NULL);
|
||||
}
|
||||
|
||||
@@ -201,7 +318,56 @@ static vpiHandle vpi_array_index(vpiHandle ref, int index)
|
||||
if (index < 0)
|
||||
return 0;
|
||||
|
||||
return obj->words[index];
|
||||
if (obj->nets != 0) {
|
||||
return obj->nets[index];
|
||||
}
|
||||
|
||||
if (obj->vals_words == 0)
|
||||
array_make_vals_words(obj);
|
||||
|
||||
return &(obj->vals_words[index].base);
|
||||
}
|
||||
|
||||
static int vpi_array_var_word_get(int code, vpiHandle ref)
|
||||
{
|
||||
struct __vpiArrayWord*obj = array_var_word_from_handle(ref);
|
||||
struct __vpiArray*parent;
|
||||
|
||||
assert(obj);
|
||||
decode_array_word_pointer(obj, parent);
|
||||
|
||||
switch (code) {
|
||||
case vpiSize:
|
||||
return (int) parent->vals_width;
|
||||
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
static void vpi_array_var_word_get_value(vpiHandle ref, p_vpi_value value)
|
||||
{
|
||||
struct __vpiArrayWord*obj = array_var_word_from_handle(ref);
|
||||
struct __vpiArray*parent;
|
||||
|
||||
assert(obj);
|
||||
unsigned index = decode_array_word_pointer(obj, parent);
|
||||
|
||||
vpip_vec4_get_value(parent->vals[index], parent->vals_width,
|
||||
false, value);
|
||||
}
|
||||
|
||||
static vpiHandle vpi_array_var_word_put_value(vpiHandle ref, p_vpi_value vp, int flags)
|
||||
{
|
||||
struct __vpiArrayWord*obj = array_var_word_from_handle(ref);
|
||||
struct __vpiArray*parent;
|
||||
|
||||
assert(obj);
|
||||
unsigned index = decode_array_word_pointer(obj, parent);
|
||||
|
||||
vvp_vector4_t val = vec4_from_vpi_value(vp, parent->vals_width);
|
||||
array_set_word(parent, index, 0, val);
|
||||
return ref;
|
||||
}
|
||||
|
||||
# define ARRAY_ITERATOR(ref) (assert(ref->vpi_type->type_code==vpiIterator), \
|
||||
@@ -216,9 +382,18 @@ static vpiHandle array_iterator_scan(vpiHandle ref, int)
|
||||
return 0;
|
||||
}
|
||||
|
||||
vpiHandle res = obj->array->words[obj->next];
|
||||
unsigned use_index = obj->next;
|
||||
obj->next += 1;
|
||||
return res;
|
||||
|
||||
if (obj->array->nets)
|
||||
return obj->array->nets[obj->next];
|
||||
|
||||
assert(obj->array->vals);
|
||||
|
||||
if (obj->array->vals_words == 0)
|
||||
array_make_vals_words(obj->array);
|
||||
|
||||
return &(obj->array->vals_words[use_index].base);
|
||||
}
|
||||
|
||||
static int array_iterator_free_object(vpiHandle ref)
|
||||
@@ -267,6 +442,56 @@ static int array_index_free_object(vpiHandle ref)
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int vpi_array_vthr_A_get(int code, vpiHandle ref)
|
||||
{
|
||||
struct __vpiArrayVthrA*obj = array_vthr_a_from_handle(ref);
|
||||
assert(obj);
|
||||
struct __vpiArray*parent = obj->array;
|
||||
|
||||
switch (code) {
|
||||
case vpiLineNo:
|
||||
return 0; // Not implemented for now!
|
||||
|
||||
case vpiSize:
|
||||
assert(parent->vals);
|
||||
return parent->vals_width;
|
||||
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
static void vpi_array_vthr_A_get_value(vpiHandle ref, p_vpi_value value)
|
||||
{
|
||||
struct __vpiArrayVthrA*obj = array_vthr_a_from_handle(ref);
|
||||
assert(obj);
|
||||
struct __vpiArray*parent = obj->array;
|
||||
|
||||
assert(parent);
|
||||
assert(parent->vals);
|
||||
assert(obj->address < parent->array_count);
|
||||
|
||||
vpip_vec4_get_value(parent->vals[obj->address],
|
||||
parent->vals_width, false, value);
|
||||
}
|
||||
|
||||
static vpiHandle vpi_array_vthr_A_put_value(vpiHandle ref, p_vpi_value vp, int)
|
||||
{
|
||||
struct __vpiArrayVthrA*obj = array_vthr_a_from_handle(ref);
|
||||
assert(obj);
|
||||
struct __vpiArray*parent = obj->array;
|
||||
|
||||
unsigned index = obj->address;
|
||||
|
||||
assert(parent);
|
||||
assert(obj->address < parent->array_count);
|
||||
|
||||
vvp_vector4_t val = vec4_from_vpi_value(vp, parent->vals_width);
|
||||
array_set_word(parent, index, 0, val);
|
||||
|
||||
return ref;
|
||||
}
|
||||
|
||||
|
||||
void array_set_word(vvp_array_t arr,
|
||||
unsigned address,
|
||||
unsigned part_off,
|
||||
@@ -275,22 +500,61 @@ void array_set_word(vvp_array_t arr,
|
||||
if (address >= arr->array_count)
|
||||
return;
|
||||
|
||||
if (arr->vals) {
|
||||
assert(arr->nets == 0);
|
||||
if (part_off != 0 || val.size() != arr->vals_width) {
|
||||
if (arr->vals[address].size() == 0)
|
||||
arr->vals[address] = vvp_vector4_t(arr->vals_width, BIT4_X);
|
||||
if ((part_off + val.size()) > arr->vals[address].size()) {
|
||||
cerr << "part_off=" << part_off
|
||||
<< " val.size()=" << val.size()
|
||||
<< " arr->vals[address].size()=" << arr->vals[address].size()
|
||||
<< " arr->vals_width=" << arr->vals_width << endl;
|
||||
assert(0);
|
||||
}
|
||||
arr->vals[address].set_vec(part_off, val);
|
||||
} else {
|
||||
arr->vals[address] = val;
|
||||
}
|
||||
array_word_change(arr, address);
|
||||
return;
|
||||
}
|
||||
|
||||
assert(arr->nets != 0);
|
||||
|
||||
// Select the word of the array that we affect.
|
||||
vpiHandle word = arr->words[address];
|
||||
vpiHandle word = arr->nets[address];
|
||||
struct __vpiSignal*vsig = vpip_signal_from_handle(word);
|
||||
assert(vsig);
|
||||
|
||||
vvp_net_ptr_t ptr (vsig->node, 0);
|
||||
vvp_send_vec4_pv(ptr, val, part_off, val.size(), vpip_size(vsig));
|
||||
array_word_change(arr, address);
|
||||
}
|
||||
|
||||
vvp_vector4_t array_get_word(vvp_array_t arr, unsigned address)
|
||||
{
|
||||
if (arr->vals) {
|
||||
assert(arr->nets == 0);
|
||||
|
||||
vvp_vector4_t tmp;
|
||||
if (address < arr->array_count)
|
||||
tmp = arr->vals[address];
|
||||
|
||||
if (tmp.size() == 0)
|
||||
tmp = vvp_vector4_t(arr->vals_width, BIT4_X);
|
||||
|
||||
return tmp;
|
||||
}
|
||||
|
||||
assert(arr->vals == 0);
|
||||
assert(arr->nets != 0);
|
||||
|
||||
if (address >= arr->array_count) {
|
||||
// Reading outside the array. Return X's but get the
|
||||
// width by looking at a word that we know is present.
|
||||
assert(arr->array_count > 0);
|
||||
vpiHandle word = arr->words[0];
|
||||
vpiHandle word = arr->nets[0];
|
||||
struct __vpiSignal*vsig = vpip_signal_from_handle(word);
|
||||
assert(vsig);
|
||||
vvp_fun_signal_vec*sig = dynamic_cast<vvp_fun_signal_vec*> (vsig->node->fun);
|
||||
@@ -298,7 +562,7 @@ vvp_vector4_t array_get_word(vvp_array_t arr, unsigned address)
|
||||
return vvp_vector4_t(sig->size(), BIT4_X);
|
||||
}
|
||||
|
||||
vpiHandle word = arr->words[address];
|
||||
vpiHandle word = arr->nets[address];
|
||||
struct __vpiSignal*vsig = vpip_signal_from_handle(word);
|
||||
assert(vsig);
|
||||
vvp_fun_signal_vec*sig = dynamic_cast<vvp_fun_signal_vec*> (vsig->node->fun);
|
||||
@@ -328,10 +592,15 @@ static vpiHandle vpip_make_array(char*label, const char*name,
|
||||
vpip_make_dec_const(&obj->first_addr, first_addr);
|
||||
vpip_make_dec_const(&obj->last_addr, last_addr);
|
||||
|
||||
obj->words = (vpiHandle*)calloc(array_count, sizeof(vpiHandle));
|
||||
// Start off now knowing if we are nets or variables.
|
||||
obj->nets = 0;
|
||||
obj->vals = 0;
|
||||
obj->vals_width = 0;
|
||||
obj->vals_words = 0;
|
||||
|
||||
// Initialize (clear) the read-ports list.
|
||||
obj->ports_ = 0;
|
||||
obj->vpi_callbacks = 0;
|
||||
|
||||
/* Add this symbol to the array_symbols table for later lookup. */
|
||||
if (!array_table)
|
||||
@@ -342,13 +611,29 @@ static vpiHandle vpip_make_array(char*label, const char*name,
|
||||
v.ptr = obj;
|
||||
sym_set_value(array_table, label, v);
|
||||
|
||||
/* Add this into the table of VPI objects. This is used for
|
||||
contexts that try to look up VPI objects in
|
||||
general. (i.e. arguments to vpi_task calls.) */
|
||||
compile_vpi_symbol(label, &(obj->base));
|
||||
|
||||
/* Blindly attach to the scope as an object. */
|
||||
vpip_attach_to_current_scope(&(obj->base));
|
||||
|
||||
return &(obj->base);
|
||||
}
|
||||
|
||||
void array_alias_word(vvp_array_t array, unsigned long addr, vpiHandle word)
|
||||
{
|
||||
assert(addr < array->array_count);
|
||||
assert(array->nets);
|
||||
array->nets[addr] = word;
|
||||
}
|
||||
|
||||
void array_attach_word(vvp_array_t array, unsigned long addr, vpiHandle word)
|
||||
{
|
||||
assert(addr < array->array_count);
|
||||
array->words[addr] = word;
|
||||
assert(array->nets);
|
||||
array->nets[addr] = word;
|
||||
|
||||
if (struct __vpiSignal*sig = vpip_signal_from_handle(word)) {
|
||||
vvp_net_t*net = sig->node;
|
||||
@@ -361,33 +646,16 @@ void array_attach_word(vvp_array_t array, unsigned long addr, vpiHandle word)
|
||||
}
|
||||
}
|
||||
|
||||
static vpiHandle common_array_build(char*label, char*name, int last, int first)
|
||||
{
|
||||
vpiHandle obj = vpip_make_array(label, name, first, last);
|
||||
/* Add this into the table of VPI objects. This is used for
|
||||
contexts that try to look up VPI objects in
|
||||
general. (i.e. arguments to vpi_task calls.) */
|
||||
compile_vpi_symbol(label, obj);
|
||||
/* Blindly attach to the scope as an object. */
|
||||
vpip_attach_to_current_scope(obj);
|
||||
|
||||
return obj;
|
||||
}
|
||||
|
||||
void compile_var_array(char*label, char*name, int last, int first,
|
||||
int msb, int lsb, char signed_flag)
|
||||
{
|
||||
vpiHandle obj = common_array_build(label, name, last, first);
|
||||
vpiHandle obj = vpip_make_array(label, name, first, last);
|
||||
|
||||
struct __vpiArray*arr = ARRAY_HANDLE(obj);
|
||||
vvp_array_t array = array_find(label);
|
||||
|
||||
/* Make the words. */
|
||||
for (unsigned idx = 0 ; idx < arr->array_count ; idx += 1) {
|
||||
char buf[64];
|
||||
snprintf(buf, sizeof buf, "%s_%u", label, idx);
|
||||
compile_variablew(strdup(buf), array, idx, msb, lsb, signed_flag);
|
||||
}
|
||||
arr->vals = new vvp_vector4_t[arr->array_count];
|
||||
arr->vals_width = labs(msb-lsb) + 1;
|
||||
|
||||
free(label);
|
||||
free(name);
|
||||
@@ -396,7 +664,7 @@ void compile_var_array(char*label, char*name, int last, int first,
|
||||
void compile_real_array(char*label, char*name, int last, int first,
|
||||
int msb, int lsb)
|
||||
{
|
||||
vpiHandle obj = common_array_build(label, name, last, first);
|
||||
vpiHandle obj = vpip_make_array(label, name, first, last);
|
||||
|
||||
struct __vpiArray*arr = ARRAY_HANDLE(obj);
|
||||
vvp_array_t array = array_find(label);
|
||||
@@ -414,7 +682,10 @@ void compile_real_array(char*label, char*name, int last, int first,
|
||||
|
||||
void compile_net_array(char*label, char*name, int last, int first)
|
||||
{
|
||||
/* vpiHandle obj = */ common_array_build(label, name, last, first);
|
||||
vpiHandle obj = vpip_make_array(label, name, first, last);
|
||||
|
||||
struct __vpiArray*arr = ARRAY_HANDLE(obj);
|
||||
arr->nets = (vpiHandle*)calloc(arr->array_count, sizeof(vpiHandle));
|
||||
|
||||
free(label);
|
||||
free(name);
|
||||
@@ -424,6 +695,7 @@ class vvp_fun_arrayport : public vvp_net_fun_t {
|
||||
|
||||
public:
|
||||
explicit vvp_fun_arrayport(vvp_array_t mem, vvp_net_t*net);
|
||||
explicit vvp_fun_arrayport(vvp_array_t mem, vvp_net_t*net, long addr);
|
||||
~vvp_fun_arrayport();
|
||||
|
||||
void check_word_change(unsigned long addr);
|
||||
@@ -446,6 +718,12 @@ vvp_fun_arrayport::vvp_fun_arrayport(vvp_array_t mem, vvp_net_t*net)
|
||||
next_ = 0;
|
||||
}
|
||||
|
||||
vvp_fun_arrayport::vvp_fun_arrayport(vvp_array_t mem, vvp_net_t*net, long addr)
|
||||
: arr_(mem), net_(net), addr_(addr)
|
||||
{
|
||||
next_ = 0;
|
||||
}
|
||||
|
||||
vvp_fun_arrayport::~vvp_fun_arrayport()
|
||||
{
|
||||
}
|
||||
@@ -489,26 +767,121 @@ void array_word_change(vvp_array_t array, unsigned long addr)
|
||||
{
|
||||
for (vvp_fun_arrayport*cur = array->ports_; cur; cur = cur->next_)
|
||||
cur->check_word_change(addr);
|
||||
|
||||
// Run callbacks attatched to the array itself.
|
||||
struct __vpiCallback *next = array->vpi_callbacks;
|
||||
struct __vpiCallback *prev = 0;
|
||||
|
||||
while (next) {
|
||||
struct __vpiCallback*cur = next;
|
||||
next = cur->next;
|
||||
|
||||
// Skip callbacks for callbacks not for me.
|
||||
if (cur->extra_data != (long)addr) {
|
||||
prev = cur;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (cur->cb_data.cb_rtn != 0) {
|
||||
if (cur->cb_data.value)
|
||||
vpip_vec4_get_value(array->vals[addr], array->vals_width,
|
||||
false, cur->cb_data.value);
|
||||
|
||||
callback_execute(cur);
|
||||
prev = cur;
|
||||
|
||||
} else if (prev == 0) {
|
||||
|
||||
array->vpi_callbacks = next;
|
||||
cur->next = 0;
|
||||
delete_vpi_callback(cur);
|
||||
|
||||
} else {
|
||||
assert(prev->next == cur);
|
||||
prev->next = next;
|
||||
cur->next = 0;
|
||||
delete_vpi_callback(cur);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class array_port_resolv_list_t : public resolv_list_s {
|
||||
|
||||
public:
|
||||
explicit array_port_resolv_list_t(char*label) : resolv_list_s(label) { }
|
||||
|
||||
vvp_net_t*ptr;
|
||||
bool use_addr;
|
||||
long addr;
|
||||
bool resolve(bool mes);
|
||||
|
||||
private:
|
||||
};
|
||||
|
||||
bool array_port_resolv_list_t::resolve(bool mes)
|
||||
{
|
||||
vvp_array_t mem = array_find(label());
|
||||
if (mem == 0) {
|
||||
assert(mem || !mes);
|
||||
return false;
|
||||
}
|
||||
|
||||
vvp_fun_arrayport*fun;
|
||||
if (use_addr)
|
||||
fun = new vvp_fun_arrayport(mem, ptr, addr);
|
||||
else
|
||||
fun = new vvp_fun_arrayport(mem, ptr);
|
||||
ptr->fun = fun;
|
||||
|
||||
array_attach_port(mem, fun);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void vpip_array_word_change(struct __vpiCallback*cb, vpiHandle obj)
|
||||
{
|
||||
struct __vpiArray*parent = 0;
|
||||
if (struct __vpiArrayWord*word = array_var_word_from_handle(obj)) {
|
||||
unsigned addr = decode_array_word_pointer(word, parent);
|
||||
cb->extra_data = addr;
|
||||
|
||||
} else if (struct __vpiArrayVthrA*word = array_vthr_a_from_handle(obj)) {
|
||||
parent = word->array;
|
||||
cb->extra_data = word->address;
|
||||
}
|
||||
|
||||
assert(parent);
|
||||
cb->next = parent->vpi_callbacks;
|
||||
parent->vpi_callbacks = cb;
|
||||
}
|
||||
|
||||
void compile_array_port(char*label, char*array, char*addr)
|
||||
{
|
||||
vvp_array_t mem = array_find(array);
|
||||
assert(mem);
|
||||
|
||||
vvp_net_t*ptr = new vvp_net_t;
|
||||
vvp_fun_arrayport*fun = new vvp_fun_arrayport(mem, ptr);
|
||||
ptr->fun = fun;
|
||||
|
||||
define_functor_symbol(label, ptr);
|
||||
// Connect the port-0 input as the address.
|
||||
input_connect(ptr, 0, addr);
|
||||
|
||||
array_attach_port(mem, fun);
|
||||
array_port_resolv_list_t*resolv_mem
|
||||
= new array_port_resolv_list_t(array);
|
||||
|
||||
resolv_mem->ptr = new vvp_net_t;
|
||||
resolv_mem->use_addr = false;
|
||||
define_functor_symbol(label, resolv_mem->ptr);
|
||||
free(label);
|
||||
free(array);
|
||||
// The input_connect arranges for the array string to be free'ed.
|
||||
// Connect the port-0 input as the address.
|
||||
input_connect(resolv_mem->ptr, 0, addr);
|
||||
|
||||
resolv_submit(resolv_mem);
|
||||
}
|
||||
|
||||
void compile_array_port(char*label, char*array, long addr)
|
||||
{
|
||||
array_port_resolv_list_t*resolv_mem
|
||||
= new array_port_resolv_list_t(array);
|
||||
|
||||
resolv_mem->ptr = new vvp_net_t;
|
||||
resolv_mem->use_addr = true;
|
||||
resolv_mem->addr = addr;
|
||||
define_functor_symbol(label, resolv_mem->ptr);
|
||||
free(label);
|
||||
|
||||
resolv_submit(resolv_mem);
|
||||
}
|
||||
|
||||
void compile_array_alias(char*label, char*name, char*src)
|
||||
@@ -529,7 +902,8 @@ void compile_array_alias(char*label, char*name, char*src)
|
||||
vpip_make_dec_const(&obj->last_addr, mem->last_addr.value);
|
||||
|
||||
// Share the words with the source array.
|
||||
obj->words = mem->words;
|
||||
obj->nets = mem->nets;
|
||||
obj->vals = mem->vals;
|
||||
|
||||
obj->ports_ = 0;
|
||||
|
||||
@@ -547,3 +921,18 @@ void compile_array_alias(char*label, char*name, char*src)
|
||||
free(src);
|
||||
}
|
||||
|
||||
vpiHandle vpip_make_vthr_A(char*label, unsigned addr)
|
||||
{
|
||||
struct __vpiArrayVthrA*obj = (struct __vpiArrayVthrA*)
|
||||
malloc(sizeof (struct __vpiArrayVthrA));
|
||||
|
||||
obj->base.vpi_type = &vpip_array_vthr_A_rt;
|
||||
|
||||
obj->array = array_find(label);
|
||||
assert(obj->array);
|
||||
|
||||
obj->address = addr;
|
||||
assert(addr < obj->array->array_count);
|
||||
|
||||
return &(obj->base);
|
||||
}
|
||||
|
||||
+11
-6
@@ -1,7 +1,7 @@
|
||||
#ifndef __array_H // -*- c++ -*-
|
||||
#define __array_H
|
||||
/*
|
||||
* Copyright (c) 2007 Stephen Williams (steve@icarus.com)
|
||||
* Copyright (c) 2007-2008 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,9 +18,6 @@
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
|
||||
*/
|
||||
#ifdef HAVE_CVS_IDENT
|
||||
#ident "$Id: array.h,v 1.2 2007/04/10 01:26:16 steve Exp $"
|
||||
#endif
|
||||
|
||||
#include "vvp_net.h"
|
||||
#include "vpi_user.h"
|
||||
@@ -31,12 +28,15 @@ typedef struct __vpiArray* vvp_array_t;
|
||||
* This function tries to find the array (by label) in the global
|
||||
* table of all the arrays in the design.
|
||||
*/
|
||||
extern vvp_array_t array_find(char*label);
|
||||
extern vvp_array_t array_find(const char*label);
|
||||
extern vpiHandle array_index_iterate(int code, vpiHandle ref);
|
||||
|
||||
extern void array_word_change(vvp_array_t array, unsigned long addr);
|
||||
|
||||
extern void array_attach_word(vvp_array_t array, unsigned long addr, vpiHandle word);
|
||||
extern void array_attach_word(vvp_array_t array, unsigned long addr,
|
||||
vpiHandle word);
|
||||
extern void array_alias_word(vvp_array_t array, unsigned long addr,
|
||||
vpiHandle word);
|
||||
|
||||
extern void array_set_word(vvp_array_t arr,
|
||||
unsigned idx,
|
||||
@@ -45,6 +45,11 @@ extern void array_set_word(vvp_array_t arr,
|
||||
|
||||
extern vvp_vector4_t array_get_word(vvp_array_t array, unsigned adddress);
|
||||
|
||||
/* VPI hooks */
|
||||
|
||||
extern void vpip_array_word_change(struct __vpiCallback*cb, vpiHandle word);
|
||||
|
||||
/* Compile hooks */
|
||||
extern void compile_variablew(char*label, vvp_array_t array,
|
||||
unsigned long array_addr,
|
||||
int msb, int lsb, char signed_flag);
|
||||
|
||||
+7
-3
@@ -32,12 +32,14 @@ typedef bool (*vvp_code_fun)(vthread_t thr, vvp_code_t code);
|
||||
* implementation lives in the vthread.cc file so that they have
|
||||
* access to the thread context.
|
||||
*/
|
||||
extern bool of_ABS_WR(vthread_t thr, vvp_code_t code);
|
||||
extern bool of_ADD(vthread_t thr, vvp_code_t code);
|
||||
extern bool of_ADD_WR(vthread_t thr, vvp_code_t code);
|
||||
extern bool of_ADDI(vthread_t thr, vvp_code_t code);
|
||||
extern bool of_AND(vthread_t thr, vvp_code_t code);
|
||||
extern bool of_ANDR(vthread_t thr, vvp_code_t code);
|
||||
extern bool of_ASSIGN_AV(vthread_t thr, vvp_code_t code);
|
||||
extern bool of_ASSIGN_AVD(vthread_t thr, vvp_code_t code);
|
||||
extern bool of_ASSIGN_D(vthread_t thr, vvp_code_t code);
|
||||
extern bool of_ASSIGN_MV(vthread_t thr, vvp_code_t code);
|
||||
extern bool of_ASSIGN_V0(vthread_t thr, vvp_code_t code);
|
||||
@@ -51,6 +53,8 @@ extern bool of_BLEND_WR(vthread_t thr, vvp_code_t code);
|
||||
extern bool of_BREAKPOINT(vthread_t thr, vvp_code_t code);
|
||||
extern bool of_CASSIGN_LINK(vthread_t thr, vvp_code_t code);
|
||||
extern bool of_CASSIGN_V(vthread_t thr, vvp_code_t code);
|
||||
extern bool of_CASSIGN_WR(vthread_t thr, vvp_code_t code);
|
||||
extern bool of_CASSIGN_X0(vthread_t thr, vvp_code_t code);
|
||||
extern bool of_CMPIS(vthread_t thr, vvp_code_t code);
|
||||
extern bool of_CMPIU(vthread_t thr, vvp_code_t code);
|
||||
extern bool of_CMPS(vthread_t thr, vvp_code_t code);
|
||||
@@ -64,6 +68,7 @@ extern bool of_CVT_IR(vthread_t thr, vvp_code_t code);
|
||||
extern bool of_CVT_RI(vthread_t thr, vvp_code_t code);
|
||||
extern bool of_CVT_VR(vthread_t thr, vvp_code_t code);
|
||||
extern bool of_DEASSIGN(vthread_t thr, vvp_code_t code);
|
||||
extern bool of_DEASSIGN_WR(vthread_t thr, vvp_code_t code);
|
||||
extern bool of_DELAY(vthread_t thr, vvp_code_t code);
|
||||
extern bool of_DELAYX(vthread_t thr, vvp_code_t code);
|
||||
extern bool of_DISABLE(vthread_t thr, vvp_code_t code);
|
||||
@@ -73,6 +78,7 @@ extern bool of_DIV_WR(vthread_t thr, vvp_code_t code);
|
||||
extern bool of_END(vthread_t thr, vvp_code_t code);
|
||||
extern bool of_FORCE_LINK(vthread_t thr, vvp_code_t code);
|
||||
extern bool of_FORCE_V(vthread_t thr, vvp_code_t code);
|
||||
extern bool of_FORCE_WR(vthread_t thr, vvp_code_t code);
|
||||
extern bool of_FORCE_X0(vthread_t thr, vvp_code_t code);
|
||||
extern bool of_FORK(vthread_t thr, vvp_code_t code);
|
||||
extern bool of_INV(vthread_t thr, vvp_code_t code);
|
||||
@@ -91,7 +97,6 @@ extern bool of_JOIN(vthread_t thr, vvp_code_t code);
|
||||
extern bool of_LOAD_AV(vthread_t thr, vvp_code_t code);
|
||||
extern bool of_LOAD_AVP0(vthread_t thr, vvp_code_t code);
|
||||
extern bool of_LOAD_AVX_P(vthread_t thr, vvp_code_t code);
|
||||
extern bool of_LOAD_MV(vthread_t thr, vvp_code_t code);
|
||||
extern bool of_LOAD_NX(vthread_t thr, vvp_code_t code);
|
||||
extern bool of_LOAD_VEC(vthread_t thr, vvp_code_t code);
|
||||
extern bool of_LOAD_VP0(vthread_t thr, vvp_code_t code);
|
||||
@@ -119,8 +124,8 @@ extern bool of_POW(vthread_t thr, vvp_code_t code);
|
||||
extern bool of_POW_WR(vthread_t thr, vvp_code_t code);
|
||||
extern bool of_RELEASE_NET(vthread_t thr, vvp_code_t code);
|
||||
extern bool of_RELEASE_REG(vthread_t thr, vvp_code_t code);
|
||||
extern bool of_RELEASE_WR(vthread_t thr, vvp_code_t code);
|
||||
extern bool of_SET_AV(vthread_t thr, vvp_code_t code);
|
||||
extern bool of_SET_MV(vthread_t thr, vvp_code_t code);
|
||||
extern bool of_SET_VEC(vthread_t thr, vvp_code_t code);
|
||||
extern bool of_SET_WORDR(vthread_t thr, vvp_code_t code);
|
||||
extern bool of_SET_X0(vthread_t thr, vvp_code_t code);
|
||||
@@ -155,7 +160,6 @@ struct vvp_code_s {
|
||||
unsigned long number;
|
||||
vvp_net_t *net;
|
||||
vvp_code_t cptr;
|
||||
vvp_memory_t mem;
|
||||
vvp_array_t array;
|
||||
struct __vpiHandle*handle;
|
||||
struct __vpiScope*scope;
|
||||
|
||||
+146
-235
@@ -22,7 +22,6 @@
|
||||
# include "logic.h"
|
||||
# include "resolv.h"
|
||||
# include "udp.h"
|
||||
# include "memory.h"
|
||||
# include "symbols.h"
|
||||
# include "codes.h"
|
||||
# include "schedule.h"
|
||||
@@ -67,8 +66,6 @@ enum operand_e {
|
||||
OA_FUNC_PTR,
|
||||
/* The operand is a second functor pointer */
|
||||
OA_FUNC_PTR2,
|
||||
/* The operand is a pointer to a memory */
|
||||
OA_MEM_PTR,
|
||||
/* The operand is a VPI handle */
|
||||
OA_VPI_PTR,
|
||||
};
|
||||
@@ -82,13 +79,14 @@ struct opcode_table_s {
|
||||
};
|
||||
|
||||
const static struct opcode_table_s opcode_table[] = {
|
||||
{ "%abs/wr", of_ABS_WR, 2, {OA_BIT1, OA_BIT2, OA_NONE} },
|
||||
{ "%add", of_ADD, 3, {OA_BIT1, OA_BIT2, OA_NUMBER} },
|
||||
{ "%add/wr", of_ADD_WR, 2, {OA_BIT1, OA_BIT2, OA_NONE} },
|
||||
{ "%addi", of_ADDI, 3, {OA_BIT1, OA_BIT2, OA_NUMBER} },
|
||||
{ "%and", of_AND, 3, {OA_BIT1, OA_BIT2, OA_NUMBER} },
|
||||
{ "%and/r", of_ANDR, 3, {OA_BIT1, OA_BIT2, OA_NUMBER} },
|
||||
{ "%assign/av",of_ASSIGN_AV,3,{OA_ARR_PTR,OA_BIT1, OA_BIT2} },
|
||||
{ "%assign/mv",of_ASSIGN_MV,3,{OA_MEM_PTR,OA_BIT1, OA_BIT2} },
|
||||
{ "%assign/av/d",of_ASSIGN_AVD,3,{OA_ARR_PTR,OA_BIT1, OA_BIT2} },
|
||||
{ "%assign/v0",of_ASSIGN_V0,3,{OA_FUNC_PTR,OA_BIT1, OA_BIT2} },
|
||||
{ "%assign/v0/d",of_ASSIGN_V0D,3,{OA_FUNC_PTR,OA_BIT1, OA_BIT2} },
|
||||
{ "%assign/v0/x1",of_ASSIGN_V0X1,3,{OA_FUNC_PTR,OA_BIT1,OA_BIT2} },
|
||||
@@ -100,6 +98,8 @@ const static struct opcode_table_s opcode_table[] = {
|
||||
{ "%breakpoint", of_BREAKPOINT, 0, {OA_NONE, OA_NONE, OA_NONE} },
|
||||
{ "%cassign/link",of_CASSIGN_LINK,2,{OA_FUNC_PTR,OA_FUNC_PTR2,OA_NONE} },
|
||||
{ "%cassign/v",of_CASSIGN_V,3,{OA_FUNC_PTR,OA_BIT1, OA_BIT2} },
|
||||
{ "%cassign/wr",of_CASSIGN_WR,2,{OA_FUNC_PTR,OA_BIT1, OA_NONE} },
|
||||
{ "%cassign/x0",of_CASSIGN_X0,3,{OA_FUNC_PTR,OA_BIT1, OA_BIT2} },
|
||||
{ "%cmp/s", of_CMPS, 3, {OA_BIT1, OA_BIT2, OA_NUMBER} },
|
||||
{ "%cmp/u", of_CMPU, 3, {OA_BIT1, OA_BIT2, OA_NUMBER} },
|
||||
{ "%cmp/wr", of_CMPWR, 2, {OA_BIT1, OA_BIT2, OA_NONE} },
|
||||
@@ -112,7 +112,8 @@ const static struct opcode_table_s opcode_table[] = {
|
||||
{ "%cvt/ir", of_CVT_IR, 2, {OA_BIT1, OA_BIT2, OA_NONE} },
|
||||
{ "%cvt/ri", of_CVT_RI, 2, {OA_BIT1, OA_BIT2, OA_NONE} },
|
||||
{ "%cvt/vr", of_CVT_VR, 3, {OA_BIT1, OA_BIT2, OA_NUMBER} },
|
||||
{ "%deassign",of_DEASSIGN,1,{OA_FUNC_PTR, OA_NONE, OA_NONE} },
|
||||
{ "%deassign",of_DEASSIGN,3,{OA_FUNC_PTR, OA_BIT1, OA_BIT2} },
|
||||
{ "%deassign/wr",of_DEASSIGN_WR,1,{OA_FUNC_PTR, OA_NONE, OA_NONE} },
|
||||
{ "%delay", of_DELAY, 2, {OA_BIT1, OA_BIT2, OA_NONE} },
|
||||
{ "%delayx", of_DELAYX, 1, {OA_NUMBER, OA_NONE, OA_NONE} },
|
||||
{ "%div", of_DIV, 3, {OA_BIT1, OA_BIT2, OA_NUMBER} },
|
||||
@@ -121,6 +122,7 @@ const static struct opcode_table_s opcode_table[] = {
|
||||
{ "%end", of_END, 0, {OA_NONE, OA_NONE, OA_NONE} },
|
||||
{ "%force/link",of_FORCE_LINK,2,{OA_FUNC_PTR,OA_FUNC_PTR2,OA_NONE} },
|
||||
{ "%force/v",of_FORCE_V,3, {OA_FUNC_PTR, OA_BIT1, OA_BIT2} },
|
||||
{ "%force/wr",of_FORCE_WR,2, {OA_FUNC_PTR, OA_BIT1, OA_NONE} },
|
||||
{ "%force/x0",of_FORCE_X0,3,{OA_FUNC_PTR, OA_BIT1, OA_BIT2} },
|
||||
{ "%inv", of_INV, 2, {OA_BIT1, OA_BIT2, OA_NONE} },
|
||||
{ "%ix/add", of_IX_ADD, 2, {OA_BIT1, OA_NUMBER, OA_NONE} },
|
||||
@@ -138,7 +140,6 @@ const static struct opcode_table_s opcode_table[] = {
|
||||
{ "%load/av",of_LOAD_AV,3, {OA_BIT1, OA_ARR_PTR, OA_BIT2} },
|
||||
{ "%load/avp0",of_LOAD_AVP0,3, {OA_BIT1, OA_ARR_PTR, OA_BIT2} },
|
||||
{ "%load/avx.p",of_LOAD_AVX_P,3,{OA_BIT1, OA_ARR_PTR, OA_BIT2} },
|
||||
{ "%load/mv",of_LOAD_MV,3, {OA_BIT1, OA_MEM_PTR, OA_BIT2} },
|
||||
{ "%load/nx",of_LOAD_NX,3, {OA_BIT1, OA_VPI_PTR, OA_BIT2} },
|
||||
{ "%load/v", of_LOAD_VEC,3, {OA_BIT1, OA_FUNC_PTR, OA_BIT2} },
|
||||
{ "%load/vp0",of_LOAD_VP0,3,{OA_BIT1, OA_FUNC_PTR, OA_BIT2} },
|
||||
@@ -166,8 +167,8 @@ const static struct opcode_table_s opcode_table[] = {
|
||||
{ "%pow/wr", of_POW_WR, 2, {OA_BIT1, OA_BIT2, OA_NONE} },
|
||||
{ "%release/net",of_RELEASE_NET,3,{OA_FUNC_PTR,OA_BIT1,OA_BIT2} },
|
||||
{ "%release/reg",of_RELEASE_REG,3,{OA_FUNC_PTR,OA_BIT1,OA_BIT2} },
|
||||
{ "%release/wr",of_RELEASE_WR,2,{OA_FUNC_PTR,OA_BIT1,OA_NONE} },
|
||||
{ "%set/av", of_SET_AV, 3, {OA_ARR_PTR, OA_BIT1, OA_BIT2} },
|
||||
{ "%set/mv", of_SET_MV, 3, {OA_MEM_PTR, OA_BIT1, OA_BIT2} },
|
||||
{ "%set/v", of_SET_VEC,3, {OA_FUNC_PTR, OA_BIT1, OA_BIT2} },
|
||||
{ "%set/wr", of_SET_WORDR,2,{OA_VPI_PTR, OA_BIT1, OA_NONE} },
|
||||
{ "%set/x0", of_SET_X0, 3, {OA_FUNC_PTR, OA_BIT1, OA_BIT2} },
|
||||
@@ -247,6 +248,13 @@ static vvp_net_t*lookup_functor_symbol(const char*label)
|
||||
return val.net;
|
||||
}
|
||||
|
||||
vpiHandle vvp_lookup_handle(const char*label)
|
||||
{
|
||||
symbol_value_t val = sym_get_value(sym_vpi, label);
|
||||
if (val.ptr) return (vpiHandle) val.ptr;
|
||||
return 0;
|
||||
}
|
||||
|
||||
vvp_net_t* vvp_net_lookup(const char*label)
|
||||
{
|
||||
/* First, look to see if the symbol is a vpi object of some
|
||||
@@ -307,13 +315,12 @@ vvp_net_t* vvp_net_lookup(const char*label)
|
||||
*/
|
||||
static struct resolv_list_s*resolv_list = 0;
|
||||
|
||||
struct resolv_list_s {
|
||||
virtual ~resolv_list_s() { }
|
||||
struct resolv_list_s*next;
|
||||
virtual bool resolve(bool mes = false) = 0;
|
||||
};
|
||||
resolv_list_s::~resolv_list_s()
|
||||
{
|
||||
free(label_);
|
||||
}
|
||||
|
||||
static void resolv_submit(struct resolv_list_s*cur)
|
||||
void resolv_submit(struct resolv_list_s*cur)
|
||||
{
|
||||
if (cur->resolve()) {
|
||||
delete cur;
|
||||
@@ -332,8 +339,8 @@ static void resolv_submit(struct resolv_list_s*cur)
|
||||
* put net->port[port] into the fan-out list for that node.
|
||||
*/
|
||||
struct vvp_net_resolv_list_s: public resolv_list_s {
|
||||
// node to locate
|
||||
char*source;
|
||||
|
||||
vvp_net_resolv_list_s(char*l) : resolv_list_s(l) { }
|
||||
// port to be driven by the located node.
|
||||
vvp_net_ptr_t port;
|
||||
virtual bool resolve(bool mes);
|
||||
@@ -341,20 +348,18 @@ struct vvp_net_resolv_list_s: public resolv_list_s {
|
||||
|
||||
bool vvp_net_resolv_list_s::resolve(bool mes)
|
||||
{
|
||||
vvp_net_t*tmp = vvp_net_lookup(source);
|
||||
vvp_net_t*tmp = vvp_net_lookup(label());
|
||||
|
||||
if (tmp) {
|
||||
// Link the input port to the located output.
|
||||
vvp_net_t*net = port.ptr();
|
||||
net->port[port.port()] = tmp->out;
|
||||
tmp->out = port;
|
||||
|
||||
free(source);
|
||||
return true;
|
||||
}
|
||||
|
||||
if (mes)
|
||||
fprintf(stderr, "unresolved vvp_net reference: %s\n", source);
|
||||
fprintf(stderr, "unresolved vvp_net reference: %s\n", label());
|
||||
|
||||
return false;
|
||||
}
|
||||
@@ -362,10 +367,8 @@ bool vvp_net_resolv_list_s::resolve(bool mes)
|
||||
inline static
|
||||
void postpone_functor_input(vvp_net_ptr_t port, char*lab)
|
||||
{
|
||||
struct vvp_net_resolv_list_s*res = new struct vvp_net_resolv_list_s;
|
||||
|
||||
struct vvp_net_resolv_list_s*res = new struct vvp_net_resolv_list_s(lab);
|
||||
res->port = port;
|
||||
res->source = lab;
|
||||
|
||||
resolv_submit(res);
|
||||
}
|
||||
@@ -376,24 +379,22 @@ void postpone_functor_input(vvp_net_ptr_t port, char*lab)
|
||||
*/
|
||||
|
||||
struct functor_gen_resolv_list_s: public resolv_list_s {
|
||||
char*source;
|
||||
explicit functor_gen_resolv_list_s(char*txt) : resolv_list_s(txt) { }
|
||||
vvp_net_t**ref;
|
||||
virtual bool resolve(bool mes);
|
||||
};
|
||||
|
||||
bool functor_gen_resolv_list_s::resolve(bool mes)
|
||||
{
|
||||
vvp_net_t*tmp = vvp_net_lookup(source);
|
||||
vvp_net_t*tmp = vvp_net_lookup(label());
|
||||
|
||||
if (tmp) {
|
||||
*ref = tmp;
|
||||
|
||||
free(source);
|
||||
return true;
|
||||
}
|
||||
|
||||
if (mes)
|
||||
fprintf(stderr, "unresolved functor reference: %s\n", source);
|
||||
fprintf(stderr, "unresolved functor reference: %s\n", label());
|
||||
|
||||
return false;
|
||||
}
|
||||
@@ -401,10 +402,9 @@ bool functor_gen_resolv_list_s::resolve(bool mes)
|
||||
void functor_ref_lookup(vvp_net_t**ref, char*lab)
|
||||
{
|
||||
struct functor_gen_resolv_list_s*res =
|
||||
new struct functor_gen_resolv_list_s;
|
||||
new struct functor_gen_resolv_list_s(lab);
|
||||
|
||||
res->ref = ref;
|
||||
res->source = lab;
|
||||
|
||||
resolv_submit(res);
|
||||
}
|
||||
@@ -414,27 +414,27 @@ void functor_ref_lookup(vvp_net_t**ref, char*lab)
|
||||
*/
|
||||
|
||||
struct vpi_handle_resolv_list_s: public resolv_list_s {
|
||||
vpiHandle *handle;
|
||||
char *label;
|
||||
explicit vpi_handle_resolv_list_s(char*label) : resolv_list_s(label) { }
|
||||
virtual bool resolve(bool mes);
|
||||
vpiHandle *handle;
|
||||
};
|
||||
|
||||
bool vpi_handle_resolv_list_s::resolve(bool mes)
|
||||
{
|
||||
symbol_value_t val = sym_get_value(sym_vpi, label);
|
||||
symbol_value_t val = sym_get_value(sym_vpi, label());
|
||||
if (!val.ptr) {
|
||||
// check for thread vector T<base,wid>
|
||||
unsigned base, wid;
|
||||
unsigned n = 0;
|
||||
char ss[32];
|
||||
if (2 <= sscanf(label, "T<%u,%u>%n", &base, &wid, &n)
|
||||
&& n == strlen(label)) {
|
||||
if (2 <= sscanf(label(), "T<%u,%u>%n", &base, &wid, &n)
|
||||
&& n == strlen(label())) {
|
||||
val.ptr = vpip_make_vthr_vector(base, wid, false);
|
||||
sym_set_value(sym_vpi, label, val);
|
||||
sym_set_value(sym_vpi, label(), val);
|
||||
|
||||
} else if (3 <= sscanf(label, "T<%u,%u,%[su]>%n", &base,
|
||||
} else if (3 <= sscanf(label(), "T<%u,%u,%[su]>%n", &base,
|
||||
&wid, ss, &n)
|
||||
&& n == strlen(label)) {
|
||||
&& n == strlen(label())) {
|
||||
|
||||
bool signed_flag = false;
|
||||
for (char*fp = ss ; *fp ; fp += 1) switch (*fp) {
|
||||
@@ -449,13 +449,13 @@ bool vpi_handle_resolv_list_s::resolve(bool mes)
|
||||
}
|
||||
|
||||
val.ptr = vpip_make_vthr_vector(base, wid, signed_flag);
|
||||
sym_set_value(sym_vpi, label, val);
|
||||
sym_set_value(sym_vpi, label(), val);
|
||||
|
||||
} else if (2 == sscanf(label, "W<%u,%[r]>%n", &base, ss, &n)
|
||||
&& n == strlen(label)) {
|
||||
} else if (2 == sscanf(label(), "W<%u,%[r]>%n", &base, ss, &n)
|
||||
&& n == strlen(label())) {
|
||||
|
||||
val.ptr = vpip_make_vthr_word(base, ss);
|
||||
sym_set_value(sym_vpi, label, val);
|
||||
sym_set_value(sym_vpi, label(), val);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -466,12 +466,11 @@ bool vpi_handle_resolv_list_s::resolve(bool mes)
|
||||
|
||||
if (val.ptr) {
|
||||
*handle = (vpiHandle) val.ptr;
|
||||
free(label);
|
||||
return true;
|
||||
}
|
||||
|
||||
if (mes)
|
||||
fprintf(stderr, "unresolved vpi name lookup: %s\n", label);
|
||||
fprintf(stderr, "unresolved vpi name lookup: %s\n", label());
|
||||
|
||||
return false;
|
||||
}
|
||||
@@ -503,10 +502,9 @@ void compile_vpi_lookup(vpiHandle *handle, char*label)
|
||||
}
|
||||
|
||||
struct vpi_handle_resolv_list_s*res
|
||||
= new struct vpi_handle_resolv_list_s;
|
||||
= new struct vpi_handle_resolv_list_s(label);
|
||||
|
||||
res->handle = handle;
|
||||
res->label = label;
|
||||
resolv_submit(res);
|
||||
}
|
||||
|
||||
@@ -515,27 +513,24 @@ void compile_vpi_lookup(vpiHandle *handle, char*label)
|
||||
*/
|
||||
|
||||
struct code_label_resolv_list_s: public resolv_list_s {
|
||||
code_label_resolv_list_s(char*label) : resolv_list_s(label) { }
|
||||
struct vvp_code_s *code;
|
||||
char *label;
|
||||
virtual bool resolve(bool mes);
|
||||
};
|
||||
|
||||
bool code_label_resolv_list_s::resolve(bool mes)
|
||||
{
|
||||
symbol_value_t val = sym_get_value(sym_codespace, label);
|
||||
symbol_value_t val = sym_get_value(sym_codespace, label());
|
||||
if (val.num) {
|
||||
if (code->opcode == of_FORK)
|
||||
code->cptr2 = reinterpret_cast<vvp_code_t>(val.ptr);
|
||||
else
|
||||
code->cptr = reinterpret_cast<vvp_code_t>(val.ptr);
|
||||
free(label);
|
||||
return true;
|
||||
}
|
||||
|
||||
if (mes)
|
||||
fprintf(stderr,
|
||||
"unresolved code label: %s\n",
|
||||
label);
|
||||
fprintf(stderr, "unresolved code label: %s\n", label());
|
||||
|
||||
return false;
|
||||
}
|
||||
@@ -543,75 +538,38 @@ bool code_label_resolv_list_s::resolve(bool mes)
|
||||
void code_label_lookup(struct vvp_code_s *code, char *label)
|
||||
{
|
||||
struct code_label_resolv_list_s *res
|
||||
= new struct code_label_resolv_list_s;
|
||||
= new struct code_label_resolv_list_s(label);
|
||||
|
||||
res->code = code;
|
||||
res->label = label;
|
||||
|
||||
resolv_submit(res);
|
||||
}
|
||||
|
||||
/*
|
||||
* Lookup memories.
|
||||
*/
|
||||
struct memory_resolv_list_s: public resolv_list_s {
|
||||
struct code_array_resolv_list_s: public resolv_list_s {
|
||||
code_array_resolv_list_s(char*label) : resolv_list_s(label) { }
|
||||
struct vvp_code_s *code;
|
||||
char *label;
|
||||
virtual bool resolve(bool mes);
|
||||
};
|
||||
|
||||
bool memory_resolv_list_s::resolve(bool mes)
|
||||
bool code_array_resolv_list_s::resolve(bool mes)
|
||||
{
|
||||
code->mem = memory_find(label);
|
||||
if (code->mem != 0) {
|
||||
free(label);
|
||||
return true;
|
||||
}
|
||||
|
||||
if (mes)
|
||||
fprintf(stderr, "Memory unresolved: %s\n", label);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static void compile_mem_lookup(struct vvp_code_s *code, char *label)
|
||||
{
|
||||
struct memory_resolv_list_s *res
|
||||
= new struct memory_resolv_list_s;
|
||||
|
||||
res->code = code;
|
||||
res->label = label;
|
||||
|
||||
resolv_submit(res);
|
||||
}
|
||||
|
||||
struct array_resolv_list_s: public resolv_list_s {
|
||||
struct vvp_code_s *code;
|
||||
char *label;
|
||||
virtual bool resolve(bool mes);
|
||||
};
|
||||
|
||||
bool array_resolv_list_s::resolve(bool mes)
|
||||
{
|
||||
code->array = array_find(label);
|
||||
code->array = array_find(label());
|
||||
if (code->array != 0) {
|
||||
free(label);
|
||||
return true;
|
||||
}
|
||||
|
||||
if (mes)
|
||||
fprintf(stderr, "Array unresolved: %s\n", label);
|
||||
fprintf(stderr, "Array unresolved: %s\n", label());
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static void compile_array_lookup(struct vvp_code_s*code, char*label)
|
||||
{
|
||||
struct array_resolv_list_s *res
|
||||
= new struct array_resolv_list_s;
|
||||
struct code_array_resolv_list_s *res
|
||||
= new struct code_array_resolv_list_s(label);
|
||||
|
||||
res->code = code;
|
||||
res->label = label;
|
||||
|
||||
resolv_submit(res);
|
||||
}
|
||||
@@ -737,6 +695,47 @@ void compile_vpi_time_precision(long pre)
|
||||
vpip_set_time_precision(pre);
|
||||
}
|
||||
|
||||
/*
|
||||
* Convert a Cr string value to double.
|
||||
*
|
||||
* The format is broken into mantissa and exponent.
|
||||
* The exponent in turn includes a sign bit.
|
||||
*
|
||||
* The mantissa is a 64bit integer value (encoded in hex).
|
||||
*
|
||||
* The exponent included the sign bit (0x4000) and the binary
|
||||
* exponent offset by 0x1000. The actual exponent is the
|
||||
* encoded exponent - 0x1000.
|
||||
*
|
||||
* The real value is sign * (mant ** exp).
|
||||
*/
|
||||
double crstring_to_double(char*label)
|
||||
{
|
||||
char*cp = label+3;
|
||||
assert(*cp == 'm');
|
||||
cp += 1;
|
||||
uint64_t mant = strtoull(cp, &cp, 16);
|
||||
assert(*cp == 'g');
|
||||
cp += 1;
|
||||
int exp = strtoul(cp, 0, 16);
|
||||
|
||||
double tmp;
|
||||
if (mant == 0 && exp == 0x3fff) {
|
||||
tmp = INFINITY;
|
||||
} else if (mant == 0 && exp == 0x7fff) {
|
||||
tmp = -INFINITY;
|
||||
} else if (exp == 0x3fff) {
|
||||
tmp = nan("");
|
||||
} else {
|
||||
double sign = (exp & 0x4000)? -1.0 : 1.0;
|
||||
exp &= 0x1fff;
|
||||
|
||||
tmp = sign * ldexp((double)mant, exp - 0x1000);
|
||||
}
|
||||
|
||||
return tmp;
|
||||
}
|
||||
|
||||
/*
|
||||
* Run through the arguments looking for the nodes that are
|
||||
* connected to my input ports. For each source functor that I
|
||||
@@ -819,42 +818,13 @@ void input_connect(vvp_net_t*fdx, unsigned port, char*label)
|
||||
}
|
||||
|
||||
/* Handle the Cr<> constant driver, which is a real-value
|
||||
driver. The format is broken into mantissa and
|
||||
exponent. The exponent in turn includes a sign bit.
|
||||
|
||||
The mantissa is a 64bit integer value (encoded in hex).
|
||||
|
||||
The exponent included the sign bit (0x4000) and the binary
|
||||
exponent offset by 0x1000. The actual exponent is the
|
||||
encoded exponent - 0x1000.
|
||||
|
||||
The real value is sign * (mant ** exp). */
|
||||
driver. */
|
||||
if ((strncmp(label, "Cr<", 3) == 0)
|
||||
&& ((tp = strchr(label,'>')))
|
||||
&& (tp[1] == 0)
|
||||
&& (strspn(label+3, "0123456789abcdefmg")+3 == (unsigned)(tp-label))) {
|
||||
|
||||
char*cp = label+3;
|
||||
assert(*cp == 'm');
|
||||
cp += 1;
|
||||
uint64_t mant = strtoull(cp, &cp, 16);
|
||||
assert(*cp == 'g');
|
||||
cp += 1;
|
||||
int exp = strtoul(cp, 0, 16);
|
||||
|
||||
double tmp;
|
||||
if (mant == 0 && exp == 0x3fff) {
|
||||
tmp = INFINITY;
|
||||
} else if (mant == 0 && exp == 0x7fff) {
|
||||
tmp = -INFINITY;
|
||||
} else if (exp == 0x3fff) {
|
||||
tmp = nan("");
|
||||
} else {
|
||||
double sign = (exp & 0x4000)? -1.0 : 1.0;
|
||||
exp &= 0x1fff;
|
||||
|
||||
tmp = sign * ldexp((double)mant, exp - 0x1000);
|
||||
}
|
||||
double tmp = crstring_to_double(label);
|
||||
|
||||
schedule_set_vector(ifdx, tmp);
|
||||
free(label);
|
||||
@@ -916,6 +886,21 @@ template <class T_> void make_arith(T_ *arith, char*label,
|
||||
free(argv);
|
||||
}
|
||||
|
||||
void compile_arith_abs(char*label, unsigned argc, struct symb_s*argv)
|
||||
{
|
||||
vvp_arith_abs*arith = new vvp_arith_abs;
|
||||
|
||||
vvp_net_t* ptr = new vvp_net_t;
|
||||
ptr->fun = arith;
|
||||
|
||||
define_functor_symbol(label, ptr);
|
||||
free(label);
|
||||
|
||||
assert(argc == 1);
|
||||
inputs_connect(ptr, argc, argv);
|
||||
free(argv);
|
||||
}
|
||||
|
||||
void compile_arith_div(char*label, long wid, bool signed_flag,
|
||||
unsigned argc, struct symb_s*argv)
|
||||
{
|
||||
@@ -1299,7 +1284,8 @@ struct __vpiModPath* compile_modpath(char*label, struct symb_s drv,
|
||||
static struct __vpiModPathSrc*make_modpath_src(struct __vpiModPath*path,
|
||||
char edge,
|
||||
struct symb_s src,
|
||||
struct numbv_s vals)
|
||||
struct numbv_s vals,
|
||||
bool ifnone)
|
||||
{
|
||||
vvp_fun_modpath*dst = path->modpath;
|
||||
|
||||
@@ -1352,7 +1338,7 @@ static struct __vpiModPathSrc*make_modpath_src(struct __vpiModPath*path,
|
||||
/* Save the vpiEdge directory into the input path term. */
|
||||
srcobj->path_term_in.edge = vpi_edge;
|
||||
input_connect(net, 0, src.text);
|
||||
dst->add_modpath_src(obj);
|
||||
dst->add_modpath_src(obj, ifnone);
|
||||
|
||||
return srcobj;
|
||||
}
|
||||
@@ -1363,7 +1349,8 @@ void compile_modpath_src(struct __vpiModPath*dst, char edge,
|
||||
struct symb_s condit_src,
|
||||
struct symb_s path_term_in)
|
||||
{
|
||||
struct __vpiModPathSrc*obj = make_modpath_src(dst, edge, src, vals);
|
||||
struct __vpiModPathSrc*obj =
|
||||
make_modpath_src(dst, edge, src, vals, false);
|
||||
input_connect(obj->net, 1, condit_src.text);
|
||||
compile_vpi_lookup(&obj->path_term_in.expr, path_term_in.text);
|
||||
}
|
||||
@@ -1372,10 +1359,12 @@ void compile_modpath_src(struct __vpiModPath*dst, char edge,
|
||||
struct symb_s src,
|
||||
struct numbv_s vals,
|
||||
int condit_src,
|
||||
struct symb_s path_term_in)
|
||||
struct symb_s path_term_in,
|
||||
bool ifnone)
|
||||
{
|
||||
assert(condit_src == 0);
|
||||
struct __vpiModPathSrc*obj = make_modpath_src(dst, edge, src, vals);
|
||||
struct __vpiModPathSrc*obj =
|
||||
make_modpath_src(dst, edge, src, vals, ifnone);
|
||||
compile_vpi_lookup(&obj->path_term_in.expr, path_term_in.text);
|
||||
}
|
||||
|
||||
@@ -1419,10 +1408,10 @@ void compile_resolver(char*label, char*type, unsigned argc, struct symb_s*argv)
|
||||
obj = new resolv_functor(vvp_scalar_t(BIT4_1, 5));
|
||||
|
||||
} else if (strcmp(type,"triand") == 0) {
|
||||
obj = new table_functor_s(ft_TRIAND);
|
||||
obj = new resolv_triand;
|
||||
|
||||
} else if (strcmp(type,"trior") == 0) {
|
||||
obj = new table_functor_s(ft_TRIOR);
|
||||
obj = new resolv_trior;
|
||||
|
||||
} else {
|
||||
fprintf(stderr, "invalid resolver type: %s\n", type);
|
||||
@@ -1477,90 +1466,6 @@ char **compile_udp_table(char **table, char *row)
|
||||
return table;
|
||||
}
|
||||
|
||||
/*
|
||||
* Take the detailed parse items from a .mem statement and generate
|
||||
* the necessary internal structures.
|
||||
*
|
||||
* <label> .mem <name>, <msb>, <lsb>, <idxs...> ;
|
||||
*
|
||||
*/
|
||||
void compile_memory(char *label, char *name, int msb, int lsb,
|
||||
unsigned narg, long *args)
|
||||
{
|
||||
/* Create an empty memory in the symbol table. */
|
||||
vvp_memory_t mem = memory_create(label);
|
||||
|
||||
assert( narg > 0 && narg%2 == 0 );
|
||||
|
||||
struct memory_address_range*ranges
|
||||
= new struct memory_address_range[narg/2];
|
||||
|
||||
for (unsigned idx = 0 ; idx < narg ; idx += 2) {
|
||||
ranges[idx/2].msb = args[idx+0];
|
||||
ranges[idx/2].lsb = args[idx+1];
|
||||
}
|
||||
|
||||
memory_configure(mem, msb, lsb, narg/2, ranges);
|
||||
|
||||
delete[]ranges;
|
||||
|
||||
vpiHandle obj = vpip_make_memory(mem, name);
|
||||
compile_vpi_symbol(label, obj);
|
||||
vpip_attach_to_current_scope(obj);
|
||||
|
||||
free(label);
|
||||
free(name);
|
||||
}
|
||||
|
||||
void compile_memory_port(char *label, char *memid,
|
||||
unsigned argc, struct symb_s *argv)
|
||||
{
|
||||
vvp_memory_t mem = memory_find(memid);
|
||||
free(memid);
|
||||
assert(mem);
|
||||
|
||||
vvp_net_t*ptr = new vvp_net_t;
|
||||
vvp_fun_memport*fun = new vvp_fun_memport(mem, ptr);
|
||||
ptr->fun = fun;
|
||||
|
||||
define_functor_symbol(label, ptr);
|
||||
free(label);
|
||||
|
||||
inputs_connect(ptr, argc, argv);
|
||||
free(argv);
|
||||
}
|
||||
|
||||
/*
|
||||
* The parser calls this multiple times to parse a .mem/init
|
||||
* statement. The first call includes a memid label and is used to
|
||||
* select the memory and the start address. Subsequent calls contain
|
||||
* only the word value to assign.
|
||||
*/
|
||||
void compile_memory_init(char *memid, unsigned i, long val)
|
||||
{
|
||||
static vvp_memory_t current_mem = 0;
|
||||
static unsigned current_word;
|
||||
|
||||
if (memid) {
|
||||
current_mem = memory_find(memid);
|
||||
free(memid);
|
||||
current_word = i;
|
||||
return;
|
||||
}
|
||||
|
||||
assert(current_mem);
|
||||
|
||||
unsigned word_wid = memory_word_width(current_mem);
|
||||
|
||||
vvp_vector4_t val4 (word_wid);
|
||||
for (unsigned idx = 0 ; idx < word_wid ; idx += 1) {
|
||||
vvp_bit4_t bit = val & 1 ? BIT4_1 : BIT4_0;
|
||||
val4.set_bit(idx, bit);
|
||||
}
|
||||
|
||||
memory_init_word(current_mem, current_word, val4);
|
||||
current_word += 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* The parser uses this function to compile and link an executable
|
||||
@@ -1676,15 +1581,6 @@ void compile_code(char*label, char*mnem, comp_operands_t opa)
|
||||
code->number = opa->argv[idx].numb;
|
||||
break;
|
||||
|
||||
case OA_MEM_PTR:
|
||||
if (opa->argv[idx].ltype != L_SYMB) {
|
||||
yyerror("operand format");
|
||||
break;
|
||||
}
|
||||
|
||||
compile_mem_lookup(code, opa->argv[idx].symb.text);
|
||||
break;
|
||||
|
||||
case OA_VPI_PTR:
|
||||
/* The operand is a functor. Resolve the label to
|
||||
a functor pointer, or postpone the resolution
|
||||
@@ -1752,7 +1648,7 @@ void compile_fork(char*label, struct symb_s dest, struct symb_s scope)
|
||||
}
|
||||
|
||||
void compile_vpi_call(char*label, char*name,
|
||||
long file_idx, long line_no,
|
||||
long file_idx, long lineno,
|
||||
unsigned argc, vpiHandle*argv)
|
||||
{
|
||||
if (label)
|
||||
@@ -1765,7 +1661,7 @@ void compile_vpi_call(char*label, char*name,
|
||||
/* Create a vpiHandle that bundles the call information, and
|
||||
store that handle in the instruction. */
|
||||
code->handle = vpip_build_vpi_call(name, 0, 0, 0, argc, argv,
|
||||
file_idx, line_no);
|
||||
file_idx, lineno);
|
||||
if (code->handle == 0)
|
||||
compile_errors += 1;
|
||||
|
||||
@@ -1775,7 +1671,7 @@ void compile_vpi_call(char*label, char*name,
|
||||
|
||||
void compile_vpi_func_call(char*label, char*name,
|
||||
unsigned vbit, int vwid,
|
||||
long file_idx, long line_no,
|
||||
long file_idx, long lineno,
|
||||
unsigned argc, vpiHandle*argv)
|
||||
{
|
||||
if (label)
|
||||
@@ -1788,7 +1684,7 @@ void compile_vpi_func_call(char*label, char*name,
|
||||
/* Create a vpiHandle that bundles the call information, and
|
||||
store that handle in the instruction. */
|
||||
code->handle = vpip_build_vpi_call(name, vbit, vwid, 0, argc, argv,
|
||||
file_idx, line_no);
|
||||
file_idx, lineno);
|
||||
if (code->handle == 0)
|
||||
compile_errors += 1;
|
||||
|
||||
@@ -1823,10 +1719,12 @@ void compile_thread(char*start_sym, char*flag)
|
||||
free(flag);
|
||||
}
|
||||
|
||||
void compile_param_logic(char*label, char*name, char*value, bool signed_flag)
|
||||
void compile_param_logic(char*label, char*name, char*value, bool signed_flag,
|
||||
long file_idx, long lineno)
|
||||
{
|
||||
vvp_vector4_t value4 = c4string_to_vector4(value);
|
||||
vpiHandle obj = vpip_make_binary_param(name, value4, signed_flag);
|
||||
vpiHandle obj = vpip_make_binary_param(name, value4, signed_flag,
|
||||
file_idx, lineno);
|
||||
compile_vpi_symbol(label, obj);
|
||||
vpip_attach_to_current_scope(obj);
|
||||
|
||||
@@ -1834,11 +1732,24 @@ void compile_param_logic(char*label, char*name, char*value, bool signed_flag)
|
||||
free(value);
|
||||
}
|
||||
|
||||
void compile_param_string(char*label, char*name, char*value)
|
||||
void compile_param_string(char*label, char*name, char*value,
|
||||
long file_idx, long lineno)
|
||||
{
|
||||
vpiHandle obj = vpip_make_string_param(name, value);
|
||||
vpiHandle obj = vpip_make_string_param(name, value, file_idx, lineno);
|
||||
compile_vpi_symbol(label, obj);
|
||||
vpip_attach_to_current_scope(obj);
|
||||
|
||||
free(label);
|
||||
}
|
||||
|
||||
void compile_param_real(char*label, char*name, char*value,
|
||||
long file_idx, long lineno)
|
||||
{
|
||||
double dvalue = crstring_to_double(value);
|
||||
vpiHandle obj = vpip_make_real_param(name, dvalue, file_idx, lineno);
|
||||
compile_vpi_symbol(label, obj);
|
||||
vpip_attach_to_current_scope(obj);
|
||||
|
||||
free(label);
|
||||
free(value);
|
||||
}
|
||||
|
||||
+58
-15
@@ -72,6 +72,7 @@ extern void wide_inputs_connect(vvp_wide_fun_core*core,
|
||||
unsigned argc, struct symb_s*argv);
|
||||
|
||||
extern vvp_net_t* vvp_net_lookup(const char*label);
|
||||
extern vpiHandle vvp_lookup_handle(const char*label);
|
||||
|
||||
/*
|
||||
* Add a functor to the symbol table
|
||||
@@ -148,6 +149,8 @@ extern void compile_part_select_var(char*label, char*src,
|
||||
*/
|
||||
extern void compile_arith_pow(char*label, long width, bool signed_flag,
|
||||
unsigned argc, struct symb_s*argv);
|
||||
extern void compile_arith_abs(char*label,
|
||||
unsigned argc, struct symb_s*argv);
|
||||
extern void compile_arith_div(char*label, long width, bool signed_flag,
|
||||
unsigned argc, struct symb_s*argv);
|
||||
extern void compile_arith_mod(char*label, long width,
|
||||
@@ -198,7 +201,8 @@ extern void compile_modpath_src(__vpiModPath*dst,
|
||||
struct symb_s input,
|
||||
struct numbv_s d,
|
||||
int condit_input, /* match with '0' */
|
||||
struct symb_s path_term_input);
|
||||
struct symb_s path_term_input,
|
||||
bool ifnone);
|
||||
extern void compile_modpath_src(__vpiModPath*dst,
|
||||
char edge,
|
||||
struct symb_s input,
|
||||
@@ -216,7 +220,7 @@ extern void compile_reduce_xnor(char*label, struct symb_s arg);
|
||||
extern void compile_extend_signed(char*label, long width, struct symb_s arg);
|
||||
|
||||
extern void compile_sfunc(char*label, char*name, char*format_string,
|
||||
long file_idx, long line_no,
|
||||
long file_idx, long lineno,
|
||||
unsigned argc, struct symb_s*argv);
|
||||
extern void compile_repeat(char*label, long width, long repeat,
|
||||
struct symb_s arg);
|
||||
@@ -231,9 +235,48 @@ extern void compile_timescale(long units, long precision);
|
||||
extern void compile_vpi_symbol(const char*label, vpiHandle obj);
|
||||
extern void compile_vpi_lookup(vpiHandle *objref, char*label);
|
||||
|
||||
extern void compile_param_string(char*label, char*name, char*value);
|
||||
extern void compile_param_string(char*label, char*name, char*value,
|
||||
long file_idx, long lineno);
|
||||
extern void compile_param_logic(char*label, char*name, char*value,
|
||||
bool signed_flag);
|
||||
bool signed_flag,
|
||||
long file_idx, long lineno);
|
||||
extern void compile_param_real(char*label, char*name, char*value,
|
||||
long file_idx, long lineno);
|
||||
|
||||
/*
|
||||
* The resolv_list_s is the base class for a symbol resolve
|
||||
* action. Some function creates an instance of a resolv_list_s object
|
||||
* that contains the data pertinent to that resolution request, and
|
||||
* executes it with the resolv_submit function. If the operation can
|
||||
* complete, then the resolv_submit deletes the object. Otherwise, it
|
||||
* pushes it onto the resolv_list for later processing.
|
||||
*
|
||||
* Derived classes implement the resolve function to perform the
|
||||
* actual binding or resolution that the instance requires. If the
|
||||
* function succeeds, the resolve method returns true and the object
|
||||
* can be deleted any time.
|
||||
*
|
||||
* The mes parameter of the resolve method tells the resolver that
|
||||
* this call is its last chance. If it cannot complete the operation,
|
||||
* it must print an error message and return false.
|
||||
*/
|
||||
class resolv_list_s {
|
||||
|
||||
public:
|
||||
explicit resolv_list_s(char*lab) : label_(lab) { }
|
||||
virtual ~resolv_list_s();
|
||||
virtual bool resolve(bool mes = false) = 0;
|
||||
|
||||
protected:
|
||||
const char*label() const { return label_; }
|
||||
|
||||
private:
|
||||
friend void ::resolv_submit(struct resolv_list_s*cur);
|
||||
friend void ::compile_cleanup(void);
|
||||
|
||||
char*label_;
|
||||
struct resolv_list_s*next;
|
||||
};
|
||||
|
||||
/*
|
||||
* This function schedules a lookup of an indexed label. The ref
|
||||
@@ -287,15 +330,10 @@ extern void compile_net_array(char*label, char*name,
|
||||
int last, int first);
|
||||
extern void compile_array_alias(char*label, char*name, char*src);
|
||||
|
||||
/* Index is a net. */
|
||||
extern void compile_array_port(char*label, char*name, char*addr);
|
||||
|
||||
extern void compile_memory(char *label, char *name, int lsb, int msb,
|
||||
unsigned idxs, long *idx);
|
||||
|
||||
extern void compile_memory_port(char *label, char *memid,
|
||||
unsigned argc, struct symb_s *argv);
|
||||
|
||||
extern void compile_memory_init(char *memid, unsigned idx, long val);
|
||||
/* Index is a constant address */
|
||||
extern void compile_array_port(char*label, char*name, long addr);
|
||||
|
||||
/*
|
||||
* Compile the .ufunc statement.
|
||||
@@ -346,7 +384,7 @@ extern void compile_code(char*label, char*mnem, comp_operands_t opa);
|
||||
extern void compile_disable(char*label, struct symb_s symb);
|
||||
|
||||
extern void compile_vpi_call(char*label, char*name,
|
||||
long file_idx, long line_no,
|
||||
long file_idx, long lineno,
|
||||
unsigned argc, vpiHandle*argv);
|
||||
|
||||
/* Compile a function call. The vbit and vwid encode the return
|
||||
@@ -355,7 +393,7 @@ extern void compile_vpi_call(char*label, char*name,
|
||||
code that represents the function type. */
|
||||
extern void compile_vpi_func_call(char*label, char*name,
|
||||
unsigned vbit, int vwid,
|
||||
long file_idx, long line_no,
|
||||
long file_idx, long lineno,
|
||||
unsigned argc, vpiHandle*argv);
|
||||
|
||||
extern void compile_fork(char*label, struct symb_s targ_s,
|
||||
@@ -366,7 +404,9 @@ extern void compile_codelabel(char*label);
|
||||
* The parser uses these functions to compile .scope statements.
|
||||
* The implementations of these live in the vpi_scope.cc file.
|
||||
*/
|
||||
extern void compile_scope_decl(char*typ, char*lab, char*nam,const char*tnam,char*par);
|
||||
extern void compile_scope_decl(char*typ, char*lab, char*nam,const char*tnam,
|
||||
char*par, long file_idx, long lineno,
|
||||
long def_file_idx, long def_lineno);
|
||||
extern void compile_scope_recall(char*sym);
|
||||
|
||||
/*
|
||||
@@ -407,5 +447,8 @@ extern void compile_alias(char*label, char*name,
|
||||
extern void compile_alias_real(char*label, char*name,
|
||||
int msb, int lsb,
|
||||
unsigned argc, struct symb_s*argv);
|
||||
extern void compile_aliasw(char*label, char*array_symbol,
|
||||
unsigned long array_addr, int msb, int lsb,
|
||||
unsigned argc, struct symb_s*argv);
|
||||
|
||||
#endif
|
||||
|
||||
+72
-14
@@ -22,6 +22,7 @@
|
||||
#include "vpi_priv.h"
|
||||
#include <iostream>
|
||||
#include <cstdlib>
|
||||
#include <list>
|
||||
#include <assert.h>
|
||||
|
||||
void vvp_delay_t::calculate_min_delay_()
|
||||
@@ -349,7 +350,7 @@ void vvp_fun_delay::run_run_real_(struct vvp_fun_delay::event_*cur)
|
||||
}
|
||||
|
||||
vvp_fun_modpath::vvp_fun_modpath(vvp_net_t*net)
|
||||
: net_(net), src_list_(0)
|
||||
: net_(net), src_list_(0), ifnone_list_(0)
|
||||
{
|
||||
}
|
||||
|
||||
@@ -361,16 +362,27 @@ vvp_fun_modpath::~vvp_fun_modpath()
|
||||
src_list_ = tmp->next_;
|
||||
delete tmp;
|
||||
}
|
||||
while (ifnone_list_) {
|
||||
vvp_fun_modpath_src*tmp = ifnone_list_;
|
||||
ifnone_list_ = tmp->next_;
|
||||
delete tmp;
|
||||
}
|
||||
}
|
||||
|
||||
void vvp_fun_modpath::add_modpath_src(vvp_fun_modpath_src*that)
|
||||
void vvp_fun_modpath::add_modpath_src(vvp_fun_modpath_src*that, bool ifnone)
|
||||
{
|
||||
assert(that->next_ == 0);
|
||||
that->next_ = src_list_;
|
||||
src_list_ = that;
|
||||
if (ifnone) {
|
||||
that->next_ = ifnone_list_;
|
||||
ifnone_list_ = that;
|
||||
} else {
|
||||
that->next_ = src_list_;
|
||||
src_list_ = that;
|
||||
}
|
||||
}
|
||||
|
||||
static vvp_time64_t delay_from_edge(vvp_bit4_t a, vvp_bit4_t b, vvp_time64_t array[12])
|
||||
static vvp_time64_t delay_from_edge(vvp_bit4_t a, vvp_bit4_t b,
|
||||
vvp_time64_t array[12])
|
||||
{
|
||||
typedef delay_edge_t bit4_table4[4];
|
||||
const static bit4_table4 edge_table[4] = {
|
||||
@@ -392,17 +404,42 @@ void vvp_fun_modpath::recv_vec4(vvp_net_ptr_t port, const vvp_vector4_t&bit)
|
||||
if (cur_vec4_.eeq(bit))
|
||||
return;
|
||||
|
||||
/* Select a time delay source that applies. */
|
||||
vvp_fun_modpath_src*src = 0;
|
||||
/* Select a time delay source that applies. Notice that there
|
||||
may be multiple delay sources that apply, so collect all
|
||||
the candidates into a list first. */
|
||||
list<vvp_fun_modpath_src*>candidate_list;
|
||||
vvp_time64_t candidate_wake_time = 0;
|
||||
for (vvp_fun_modpath_src*cur = src_list_ ; cur ; cur=cur->next_) {
|
||||
/* Skip paths that are disabled by conditions. */
|
||||
if (cur->condition_flag_ == false)
|
||||
continue;
|
||||
|
||||
if (src == 0) {
|
||||
src = cur;
|
||||
} else if (cur->wake_time_ > src->wake_time_) {
|
||||
src = cur;
|
||||
if (candidate_list.empty()) {
|
||||
candidate_list.push_back(cur);
|
||||
candidate_wake_time = cur->wake_time_;
|
||||
} else if (cur->wake_time_ == candidate_wake_time) {
|
||||
candidate_list.push_back(cur);
|
||||
} else if (cur->wake_time_ > candidate_wake_time) {
|
||||
candidate_list.assign(1, cur);
|
||||
candidate_wake_time = cur->wake_time_;
|
||||
} else {
|
||||
continue; /* Skip this entry. */
|
||||
}
|
||||
}
|
||||
|
||||
/* Only add the ifnone delay if it has a later wake_time_ or
|
||||
* if there are no normal delays. */
|
||||
vvp_time64_t ifnone_wake_time = candidate_wake_time;
|
||||
for (vvp_fun_modpath_src*cur = ifnone_list_ ; cur ; cur=cur->next_) {
|
||||
if (candidate_list.empty()) {
|
||||
candidate_list.push_back(cur);
|
||||
ifnone_wake_time = cur->wake_time_;
|
||||
} else if (cur->wake_time_ == ifnone_wake_time &&
|
||||
ifnone_wake_time > candidate_wake_time) {
|
||||
candidate_list.push_back(cur);
|
||||
} else if (cur->wake_time_ > ifnone_wake_time) {
|
||||
candidate_list.assign(1, cur);
|
||||
ifnone_wake_time = cur->wake_time_;
|
||||
} else {
|
||||
continue; /* Skip this entry. */
|
||||
}
|
||||
@@ -412,16 +449,24 @@ void vvp_fun_modpath::recv_vec4(vvp_net_ptr_t port, const vvp_vector4_t&bit)
|
||||
match. This may happen, for example, if the set of
|
||||
conditional delays is incomplete, leaving some cases
|
||||
uncovered. In that case, just pass the data without delay */
|
||||
if (src == 0) {
|
||||
if (candidate_list.empty()) {
|
||||
cur_vec4_ = bit;
|
||||
schedule_generic(this, 0, false);
|
||||
return;
|
||||
}
|
||||
|
||||
assert(src);
|
||||
|
||||
/* Now given that we have a list of candidate delays, find for
|
||||
each if the 12 numbers the minimum from all the
|
||||
candidates. This minimum set becomes the chosen delay to
|
||||
use. */
|
||||
vvp_time64_t out_at[12];
|
||||
vvp_time64_t now = schedule_simtime();
|
||||
|
||||
typedef list<vvp_fun_modpath_src*>::const_iterator iter_t;
|
||||
|
||||
iter_t cur = candidate_list.begin();
|
||||
vvp_fun_modpath_src*src = *cur;
|
||||
|
||||
for (unsigned idx = 0 ; idx < 12 ; idx += 1) {
|
||||
out_at[idx] = src->wake_time_ + src->delay_[idx];
|
||||
if (out_at[idx] <= now)
|
||||
@@ -430,6 +475,19 @@ void vvp_fun_modpath::recv_vec4(vvp_net_ptr_t port, const vvp_vector4_t&bit)
|
||||
out_at[idx] -= now;
|
||||
}
|
||||
|
||||
for (cur ++ ; cur != candidate_list.end() ; cur ++) {
|
||||
src = *cur;
|
||||
for (unsigned idx = 0 ; idx < 12 ; idx += 1) {
|
||||
vvp_time64_t tmp = src->wake_time_ + src->delay_[idx];
|
||||
if (tmp <= now)
|
||||
tmp = 0;
|
||||
else
|
||||
tmp -= now;
|
||||
if (tmp < out_at[idx])
|
||||
out_at[idx] = tmp;
|
||||
}
|
||||
}
|
||||
|
||||
/* Given the scheduled output time, create an output event. */
|
||||
vvp_time64_t use_delay = delay_from_edge(cur_vec4_.value(0),
|
||||
bit.value(0),
|
||||
|
||||
+2
-1
@@ -150,7 +150,7 @@ class vvp_fun_modpath : public vvp_net_fun_t, private vvp_gen_event_s {
|
||||
vvp_fun_modpath(vvp_net_t*net);
|
||||
~vvp_fun_modpath();
|
||||
|
||||
void add_modpath_src(vvp_fun_modpath_src*that);
|
||||
void add_modpath_src(vvp_fun_modpath_src*that, bool ifnone);
|
||||
|
||||
void recv_vec4(vvp_net_ptr_t port, const vvp_vector4_t&bit);
|
||||
|
||||
@@ -163,6 +163,7 @@ class vvp_fun_modpath : public vvp_net_fun_t, private vvp_gen_event_s {
|
||||
vvp_vector4_t cur_vec4_;
|
||||
|
||||
vvp_fun_modpath_src*src_list_;
|
||||
vvp_fun_modpath_src*ifnone_list_;
|
||||
|
||||
private: // not implemented
|
||||
vvp_fun_modpath(const vvp_fun_modpath&);
|
||||
|
||||
+1
-709
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2001 Stephen Williams (steve@icarus.com)
|
||||
* Copyright (c) 2001-2008 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,639 +16,9 @@
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
|
||||
*/
|
||||
#ifdef HAVE_CVS_IDENT
|
||||
#ident "$Id: draw_tt.c,v 1.23 2006/11/28 05:57:20 steve Exp $"
|
||||
#endif
|
||||
|
||||
# include <stdio.h>
|
||||
|
||||
#if 0
|
||||
static void draw_AND(void)
|
||||
{
|
||||
unsigned i0, i1, i2, i3;
|
||||
|
||||
printf("const unsigned char ft_AND[64] = {");
|
||||
|
||||
for (i3 = 0 ; i3 < 4 ; i3 += 1)
|
||||
for (i2 = 0 ; i2 < 4 ; i2 += 1) {
|
||||
printf("\n ");
|
||||
for (i1 = 0 ; i1 < 4 ; i1 += 1) {
|
||||
unsigned idx = (i3 << 4) | (i2 << 2) | i1;
|
||||
unsigned char byte = 0;
|
||||
|
||||
for (i0 = 0 ; i0 < 4 ; i0 += 1) {
|
||||
unsigned val;
|
||||
if ((i0 == 0) || (i1 == 0) ||
|
||||
(i2 == 0) || (i3 == 0))
|
||||
val = 0;
|
||||
else if ((i0 == 1) && (i1 == 1) &&
|
||||
(i2 == 1) && (i3 == 1))
|
||||
val = 1;
|
||||
else
|
||||
val = 2;
|
||||
|
||||
byte |= val << (i0*2);
|
||||
}
|
||||
|
||||
printf("0x%02x, ", byte);
|
||||
}
|
||||
}
|
||||
|
||||
printf("};\n");
|
||||
}
|
||||
#endif
|
||||
#if 0
|
||||
static void draw_NAND(void)
|
||||
{
|
||||
unsigned i0, i1, i2, i3;
|
||||
|
||||
printf("const unsigned char ft_NAND[64] = {");
|
||||
|
||||
for (i3 = 0 ; i3 < 4 ; i3 += 1)
|
||||
for (i2 = 0 ; i2 < 4 ; i2 += 1) {
|
||||
printf("\n ");
|
||||
for (i1 = 0 ; i1 < 4 ; i1 += 1) {
|
||||
unsigned idx = (i3 << 4) | (i2 << 2) | i1;
|
||||
unsigned char byte = 0;
|
||||
|
||||
for (i0 = 0 ; i0 < 4 ; i0 += 1) {
|
||||
unsigned val;
|
||||
if ((i0 == 0) || (i1 == 0) ||
|
||||
(i2 == 0) || (i3 == 0))
|
||||
val = 1;
|
||||
else if ((i0 == 1) && (i1 == 1) &&
|
||||
(i2 == 1) && (i3 == 1))
|
||||
val = 0;
|
||||
else
|
||||
val = 2;
|
||||
|
||||
byte |= val << (i0*2);
|
||||
}
|
||||
|
||||
printf("0x%02x, ", byte);
|
||||
}
|
||||
}
|
||||
|
||||
printf("};\n");
|
||||
}
|
||||
#endif
|
||||
#if 0
|
||||
static void draw_BUF(void)
|
||||
{
|
||||
unsigned i0, i1, i2, i3;
|
||||
|
||||
printf("const unsigned char ft_BUF[64] = {");
|
||||
|
||||
for (i3 = 0 ; i3 < 4 ; i3 += 1)
|
||||
for (i2 = 0 ; i2 < 4 ; i2 += 1) {
|
||||
printf("\n ");
|
||||
for (i1 = 0 ; i1 < 4 ; i1 += 1) {
|
||||
unsigned idx = (i3 << 4) | (i2 << 2) | i1;
|
||||
unsigned char byte = 0;
|
||||
|
||||
for (i0 = 0 ; i0 < 4 ; i0 += 1) {
|
||||
unsigned val;
|
||||
if (i0 == 1)
|
||||
val = 1;
|
||||
else if (i0 == 0)
|
||||
val = 0;
|
||||
else
|
||||
val = 2;
|
||||
|
||||
byte |= val << (i0*2);
|
||||
}
|
||||
|
||||
printf("0x%02x, ", byte);
|
||||
}
|
||||
}
|
||||
|
||||
printf("};\n");
|
||||
}
|
||||
#endif
|
||||
|
||||
#if 0
|
||||
static void draw_BUFZ(void)
|
||||
{
|
||||
unsigned i0, i1, i2, i3;
|
||||
|
||||
printf("const unsigned char ft_BUFZ[64] = {");
|
||||
|
||||
for (i3 = 0 ; i3 < 4 ; i3 += 1)
|
||||
for (i2 = 0 ; i2 < 4 ; i2 += 1) {
|
||||
printf("\n ");
|
||||
for (i1 = 0 ; i1 < 4 ; i1 += 1) {
|
||||
unsigned idx = (i3 << 4) | (i2 << 2) | i1;
|
||||
unsigned char byte = 0;
|
||||
|
||||
for (i0 = 0 ; i0 < 4 ; i0 += 1) {
|
||||
unsigned val = i0;
|
||||
|
||||
byte |= val << (i0*2);
|
||||
}
|
||||
|
||||
printf("0x%02x, ", byte);
|
||||
}
|
||||
}
|
||||
|
||||
printf("};\n");
|
||||
}
|
||||
#endif
|
||||
#if 0
|
||||
static void draw_BUFIF0(void)
|
||||
{
|
||||
unsigned i0, i1, i2, i3;
|
||||
|
||||
printf("const unsigned char ft_BUFIF0[64] = {");
|
||||
|
||||
for (i3 = 0 ; i3 < 4 ; i3 += 1)
|
||||
for (i2 = 0 ; i2 < 4 ; i2 += 1) {
|
||||
printf("\n ");
|
||||
for (i1 = 0 ; i1 < 4 ; i1 += 1) {
|
||||
unsigned idx = (i3 << 4) | (i2 << 2) | i1;
|
||||
unsigned char byte = 0;
|
||||
|
||||
for (i0 = 0 ; i0 < 4 ; i0 += 1) {
|
||||
unsigned val;
|
||||
if (i2 == 0)
|
||||
val = 3;
|
||||
else if (i0 == 1)
|
||||
val = 1;
|
||||
else if (i0 == 0)
|
||||
val = 0;
|
||||
else
|
||||
val = 2;
|
||||
|
||||
byte |= val << (i0*2);
|
||||
}
|
||||
|
||||
printf("0x%02x, ", byte);
|
||||
}
|
||||
}
|
||||
|
||||
printf("};\n");
|
||||
}
|
||||
#endif
|
||||
#if 0
|
||||
static void draw_BUFIF1(void)
|
||||
{
|
||||
unsigned i0, i1, i2, i3;
|
||||
|
||||
printf("const unsigned char ft_BUFIF1[64] = {");
|
||||
|
||||
for (i3 = 0 ; i3 < 4 ; i3 += 1)
|
||||
for (i2 = 0 ; i2 < 4 ; i2 += 1) {
|
||||
printf("\n ");
|
||||
for (i1 = 0 ; i1 < 4 ; i1 += 1) {
|
||||
unsigned idx = (i3 << 4) | (i2 << 2) | i1;
|
||||
unsigned char byte = 0;
|
||||
|
||||
for (i0 = 0 ; i0 < 4 ; i0 += 1) {
|
||||
unsigned val;
|
||||
if (i2 == 1)
|
||||
val = 3;
|
||||
else if (i0 == 1)
|
||||
val = 1;
|
||||
else if (i0 == 0)
|
||||
val = 0;
|
||||
else
|
||||
val = 2;
|
||||
|
||||
byte |= val << (i0*2);
|
||||
}
|
||||
|
||||
printf("0x%02x, ", byte);
|
||||
}
|
||||
}
|
||||
|
||||
printf("};\n");
|
||||
}
|
||||
#endif
|
||||
#if 0
|
||||
static void draw_PMOS(void)
|
||||
{
|
||||
unsigned i0, i1, i2, i3;
|
||||
|
||||
printf("const unsigned char ft_PMOS[64] = {");
|
||||
|
||||
for (i3 = 0 ; i3 < 4 ; i3 += 1)
|
||||
for (i2 = 0 ; i2 < 4 ; i2 += 1) {
|
||||
printf("\n ");
|
||||
for (i1 = 0 ; i1 < 4 ; i1 += 1) {
|
||||
unsigned idx = (i3 << 4) | (i2 << 2) | i1;
|
||||
unsigned char byte = 0;
|
||||
|
||||
for (i0 = 0 ; i0 < 4 ; i0 += 1) {
|
||||
unsigned val;
|
||||
if (i2 == 0 || i0 == 3)
|
||||
val = 3;
|
||||
else if (i0 == 1)
|
||||
val = 1;
|
||||
else if (i0 == 0)
|
||||
val = 0;
|
||||
else
|
||||
val = 2;
|
||||
|
||||
byte |= val << (i0*2);
|
||||
}
|
||||
|
||||
printf("0x%02x, ", byte);
|
||||
}
|
||||
}
|
||||
|
||||
printf("};\n");
|
||||
}
|
||||
#endif
|
||||
#if 0
|
||||
static void draw_NMOS(void)
|
||||
{
|
||||
unsigned i0, i1, i2, i3;
|
||||
|
||||
printf("const unsigned char ft_NMOS[64] = {");
|
||||
|
||||
for (i3 = 0 ; i3 < 4 ; i3 += 1)
|
||||
for (i2 = 0 ; i2 < 4 ; i2 += 1) {
|
||||
printf("\n ");
|
||||
for (i1 = 0 ; i1 < 4 ; i1 += 1) {
|
||||
unsigned idx = (i3 << 4) | (i2 << 2) | i1;
|
||||
unsigned char byte = 0;
|
||||
|
||||
for (i0 = 0 ; i0 < 4 ; i0 += 1) {
|
||||
unsigned val;
|
||||
if (i2 == 1 || i0 == 3)
|
||||
val = 3;
|
||||
else if (i0 == 1)
|
||||
val = 1;
|
||||
else if (i0 == 0)
|
||||
val = 0;
|
||||
else
|
||||
val = 2;
|
||||
|
||||
byte |= val << (i0*2);
|
||||
}
|
||||
|
||||
printf("0x%02x, ", byte);
|
||||
}
|
||||
}
|
||||
|
||||
printf("};\n");
|
||||
}
|
||||
#endif
|
||||
static void draw_MUXX(void)
|
||||
{
|
||||
unsigned i0, i1, i2, i3;
|
||||
|
||||
printf("const unsigned char ft_MUXX[64] = {");
|
||||
|
||||
for (i3 = 0 ; i3 < 4 ; i3 += 1)
|
||||
for (i2 = 0 ; i2 < 4 ; i2 += 1) {
|
||||
printf("\n ");
|
||||
for (i1 = 0 ; i1 < 4 ; i1 += 1) {
|
||||
unsigned idx = (i3 << 4) | (i2 << 2) | i1;
|
||||
unsigned char byte = 0;
|
||||
|
||||
for (i0 = 0 ; i0 < 4 ; i0 += 1) {
|
||||
unsigned val;
|
||||
if (i3 == 0)
|
||||
val = 3;
|
||||
else if (i3 == 2)
|
||||
val = 2;
|
||||
else if (i3 == 3)
|
||||
val = 2;
|
||||
else if (i2 >= 2) {
|
||||
val = 2;
|
||||
} else if (i2 == 0)
|
||||
val = i0;
|
||||
else
|
||||
val = i1;
|
||||
|
||||
byte |= val << (i0*2);
|
||||
}
|
||||
|
||||
printf("0x%02x, ", byte);
|
||||
}
|
||||
}
|
||||
|
||||
printf("};\n");
|
||||
}
|
||||
|
||||
#if 0
|
||||
static void draw_MUXZ(void)
|
||||
{
|
||||
unsigned i0, i1, i2, i3;
|
||||
|
||||
printf("const unsigned char ft_MUXZ[64] = {");
|
||||
|
||||
for (i3 = 0 ; i3 < 4 ; i3 += 1)
|
||||
for (i2 = 0 ; i2 < 4 ; i2 += 1) {
|
||||
printf("\n ");
|
||||
for (i1 = 0 ; i1 < 4 ; i1 += 1) {
|
||||
unsigned idx = (i3 << 4) | (i2 << 2) | i1;
|
||||
unsigned char byte = 0;
|
||||
|
||||
for (i0 = 0 ; i0 < 4 ; i0 += 1) {
|
||||
unsigned val;
|
||||
if (i3 == 0)
|
||||
val = 3;
|
||||
else if (i3 == 2)
|
||||
val = 2;
|
||||
else if (i3 == 3)
|
||||
val = 2;
|
||||
else if (i2 >= 2) {
|
||||
if (i0 == i1)
|
||||
val = i0;
|
||||
else
|
||||
val = 2;
|
||||
} else if (i2 == 0)
|
||||
val = i0;
|
||||
else
|
||||
val = i1;
|
||||
|
||||
byte |= val << (i0*2);
|
||||
}
|
||||
|
||||
printf("0x%02x, ", byte);
|
||||
}
|
||||
}
|
||||
|
||||
printf("};\n");
|
||||
}
|
||||
#endif
|
||||
#if 0
|
||||
static void draw_EEQ(void)
|
||||
{
|
||||
unsigned i0, i1, i2, i3;
|
||||
|
||||
printf("const unsigned char ft_EEQ[64] = {");
|
||||
|
||||
for (i3 = 0 ; i3 < 4 ; i3 += 1)
|
||||
for (i2 = 0 ; i2 < 4 ; i2 += 1) {
|
||||
printf("\n ");
|
||||
for (i1 = 0 ; i1 < 4 ; i1 += 1) {
|
||||
unsigned idx = (i3 << 4) | (i2 << 2) | i1;
|
||||
unsigned char byte = 0;
|
||||
|
||||
for (i0 = 0 ; i0 < 4 ; i0 += 1) {
|
||||
unsigned val;
|
||||
if (i3 != i2)
|
||||
val = 0;
|
||||
else if (i1 != i0)
|
||||
val = 0;
|
||||
else
|
||||
val = 1;
|
||||
|
||||
byte |= val << (i0*2);
|
||||
}
|
||||
|
||||
printf("0x%02x, ", byte);
|
||||
}
|
||||
}
|
||||
|
||||
printf("};\n");
|
||||
}
|
||||
#endif
|
||||
#if 0
|
||||
static void draw_NOR(void)
|
||||
{
|
||||
unsigned i0, i1, i2, i3;
|
||||
|
||||
printf("const unsigned char ft_NOR[64] = {");
|
||||
|
||||
for (i3 = 0 ; i3 < 4 ; i3 += 1)
|
||||
for (i2 = 0 ; i2 < 4 ; i2 += 1) {
|
||||
printf("\n ");
|
||||
for (i1 = 0 ; i1 < 4 ; i1 += 1) {
|
||||
unsigned idx = (i3 << 4) | (i2 << 2) | i1;
|
||||
unsigned char byte = 0;
|
||||
|
||||
for (i0 = 0 ; i0 < 4 ; i0 += 1) {
|
||||
unsigned val;
|
||||
if ((i0 == 1) || (i1 == 1) ||
|
||||
(i2 == 1) || (i3 == 1))
|
||||
val = 0;
|
||||
else if ((i0 == 0) && (i1 == 0) &&
|
||||
(i2 == 0) && (i3 == 0))
|
||||
val = 1;
|
||||
else
|
||||
val = 2;
|
||||
|
||||
byte |= val << (i0*2);
|
||||
}
|
||||
|
||||
printf("0x%02x, ", byte);
|
||||
}
|
||||
}
|
||||
|
||||
printf("};\n");
|
||||
}
|
||||
#endif
|
||||
#if 0
|
||||
static void draw_NOT(void)
|
||||
{
|
||||
unsigned i0, i1, i2, i3;
|
||||
|
||||
printf("const unsigned char ft_NOT[64] = {");
|
||||
|
||||
for (i3 = 0 ; i3 < 4 ; i3 += 1)
|
||||
for (i2 = 0 ; i2 < 4 ; i2 += 1) {
|
||||
printf("\n ");
|
||||
for (i1 = 0 ; i1 < 4 ; i1 += 1) {
|
||||
unsigned idx = (i3 << 4) | (i2 << 2) | i1;
|
||||
unsigned char byte = 0;
|
||||
|
||||
for (i0 = 0 ; i0 < 4 ; i0 += 1) {
|
||||
unsigned val;
|
||||
if (i0 == 1)
|
||||
val = 0;
|
||||
else if (i0 == 0)
|
||||
val = 1;
|
||||
else
|
||||
val = 2;
|
||||
|
||||
byte |= val << (i0*2);
|
||||
}
|
||||
|
||||
printf("0x%02x, ", byte);
|
||||
}
|
||||
}
|
||||
|
||||
printf("};\n");
|
||||
}
|
||||
#endif
|
||||
#if 0
|
||||
static void draw_OR(void)
|
||||
{
|
||||
unsigned i0, i1, i2, i3;
|
||||
|
||||
printf("const unsigned char ft_OR[64] = {");
|
||||
|
||||
for (i3 = 0 ; i3 < 4 ; i3 += 1)
|
||||
for (i2 = 0 ; i2 < 4 ; i2 += 1) {
|
||||
printf("\n ");
|
||||
for (i1 = 0 ; i1 < 4 ; i1 += 1) {
|
||||
unsigned idx = (i3 << 4) | (i2 << 2) | i1;
|
||||
unsigned char byte = 0;
|
||||
|
||||
for (i0 = 0 ; i0 < 4 ; i0 += 1) {
|
||||
unsigned val;
|
||||
if ((i0 == 1) || (i1 == 1) ||
|
||||
(i2 == 1) || (i3 == 1))
|
||||
val = 1;
|
||||
else if ((i0 == 0) && (i1 == 0) &&
|
||||
(i2 == 0) && (i3 == 0))
|
||||
val = 0;
|
||||
else
|
||||
val = 2;
|
||||
|
||||
byte |= val << (i0*2);
|
||||
}
|
||||
|
||||
printf("0x%02x, ", byte);
|
||||
}
|
||||
}
|
||||
|
||||
printf("};\n");
|
||||
}
|
||||
#endif
|
||||
#if 0
|
||||
static void draw_XNOR(void)
|
||||
{
|
||||
unsigned i0, i1, i2, i3;
|
||||
|
||||
printf("const unsigned char ft_XNOR[64] = {");
|
||||
|
||||
for (i3 = 0 ; i3 < 4 ; i3 += 1)
|
||||
for (i2 = 0 ; i2 < 4 ; i2 += 1) {
|
||||
printf("\n ");
|
||||
for (i1 = 0 ; i1 < 4 ; i1 += 1) {
|
||||
unsigned idx = (i3 << 4) | (i2 << 2) | i1;
|
||||
unsigned char byte = 0;
|
||||
|
||||
for (i0 = 0 ; i0 < 4 ; i0 += 1) {
|
||||
unsigned val;
|
||||
|
||||
if ((i0 > 1) || (i1 > 1)
|
||||
|| (i2 > 1) || (i3 > 1))
|
||||
val = 2;
|
||||
else
|
||||
val = (i0 + i1 + i2 + i3) % 2 ^ 1;
|
||||
|
||||
byte |= val << (i0*2);
|
||||
}
|
||||
|
||||
printf("0x%02x, ", byte);
|
||||
}
|
||||
}
|
||||
|
||||
printf("};\n");
|
||||
}
|
||||
#endif
|
||||
#if 0
|
||||
static void draw_XOR(void)
|
||||
{
|
||||
unsigned i0, i1, i2, i3;
|
||||
|
||||
printf("const unsigned char ft_XOR[64] = {");
|
||||
|
||||
for (i3 = 0 ; i3 < 4 ; i3 += 1)
|
||||
for (i2 = 0 ; i2 < 4 ; i2 += 1) {
|
||||
printf("\n ");
|
||||
for (i1 = 0 ; i1 < 4 ; i1 += 1) {
|
||||
unsigned idx = (i3 << 4) | (i2 << 2) | i1;
|
||||
unsigned char byte = 0;
|
||||
|
||||
for (i0 = 0 ; i0 < 4 ; i0 += 1) {
|
||||
unsigned val;
|
||||
|
||||
if ((i0 > 1) || (i1 > 1)
|
||||
|| (i2 > 1) || (i3 > 1))
|
||||
val = 2;
|
||||
else
|
||||
val = (i0 + i1 + i2 + i3) % 2;
|
||||
|
||||
byte |= val << (i0*2);
|
||||
}
|
||||
|
||||
printf("0x%02x, ", byte);
|
||||
}
|
||||
}
|
||||
|
||||
printf("};\n");
|
||||
}
|
||||
#endif
|
||||
|
||||
static void draw_TRIAND(void)
|
||||
{
|
||||
unsigned i0, i1, i2, i3;
|
||||
|
||||
printf("const unsigned char ft_TRIAND[64] = {");
|
||||
|
||||
for (i3 = 0 ; i3 < 4 ; i3 += 1)
|
||||
for (i2 = 0 ; i2 < 4 ; i2 += 1) {
|
||||
printf("\n ");
|
||||
for (i1 = 0 ; i1 < 4 ; i1 += 1) {
|
||||
unsigned idx = (i3 << 4) | (i2 << 2) | i1;
|
||||
unsigned char byte = 0;
|
||||
|
||||
for (i0 = 0 ; i0 < 4 ; i0 += 1) {
|
||||
unsigned val;
|
||||
if ((i0 == 0) || (i1 == 0) ||
|
||||
(i2 == 0) || (i3 == 0))
|
||||
val = 0;
|
||||
else if ((i0 == 2) || (i1 == 2) ||
|
||||
(i2 == 2) || (i3 == 2))
|
||||
val = 2;
|
||||
else if ((i0 == 3) && (i1 == 3) &&
|
||||
(i2 == 3) && (i3 == 3))
|
||||
val = 3;
|
||||
else
|
||||
val = 1;
|
||||
|
||||
byte |= val << (i0*2);
|
||||
}
|
||||
|
||||
printf("0x%02x, ", byte);
|
||||
}
|
||||
}
|
||||
|
||||
printf("};\n");
|
||||
}
|
||||
|
||||
static void draw_TRIOR(void)
|
||||
{
|
||||
unsigned i0, i1, i2, i3;
|
||||
|
||||
printf("const unsigned char ft_TRIOR[64] = {");
|
||||
|
||||
for (i3 = 0 ; i3 < 4 ; i3 += 1)
|
||||
for (i2 = 0 ; i2 < 4 ; i2 += 1) {
|
||||
printf("\n ");
|
||||
for (i1 = 0 ; i1 < 4 ; i1 += 1) {
|
||||
unsigned idx = (i3 << 4) | (i2 << 2) | i1;
|
||||
unsigned char byte = 0;
|
||||
|
||||
for (i0 = 0 ; i0 < 4 ; i0 += 1) {
|
||||
unsigned val;
|
||||
if ((i0 == 1) || (i1 == 1) ||
|
||||
(i2 == 1) || (i3 == 1))
|
||||
val = 1;
|
||||
else if ((i0 == 2) || (i1 == 2) ||
|
||||
(i2 == 2) || (i3 == 2))
|
||||
val = 2;
|
||||
else if ((i0 == 3) && (i1 == 3) &&
|
||||
(i2 == 3) && (i3 == 3))
|
||||
val = 3;
|
||||
else
|
||||
val = 0;
|
||||
|
||||
byte |= val << (i0*2);
|
||||
}
|
||||
|
||||
printf("0x%02x, ", byte);
|
||||
}
|
||||
}
|
||||
|
||||
printf("};\n");
|
||||
}
|
||||
|
||||
/*
|
||||
* The hex_digits table is not a functor truth table per say, but a
|
||||
@@ -749,85 +119,7 @@ static void draw_oct_table()
|
||||
|
||||
main()
|
||||
{
|
||||
printf("# include \"logic.h\"\n");
|
||||
draw_MUXX();
|
||||
draw_TRIAND();
|
||||
draw_TRIOR();
|
||||
draw_hex_table();
|
||||
draw_oct_table();
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* $Log: draw_tt.c,v $
|
||||
* Revision 1.23 2006/11/28 05:57:20 steve
|
||||
* Use new vvp_fun_XXX in place of old functor table for NAND/NOR/XNOR/EEQ.
|
||||
*
|
||||
* Revision 1.22 2005/09/19 21:45:09 steve
|
||||
* Use lazy eval of BUF/NOT/OR/XOR gates.
|
||||
*
|
||||
* Revision 1.21 2005/06/12 21:56:16 steve
|
||||
* Remove unused ft_MOS truth tables.
|
||||
*
|
||||
* Revision 1.20 2005/02/12 23:05:25 steve
|
||||
* Cleanup unused truth tables.
|
||||
*
|
||||
* Revision 1.19 2005/02/12 22:50:52 steve
|
||||
* Implement the vvp_fun_muxz functor.
|
||||
*
|
||||
* Revision 1.18 2005/01/29 17:52:06 steve
|
||||
* move AND to buitin instead of table.
|
||||
*
|
||||
* Revision 1.17 2004/12/31 05:57:25 steve
|
||||
* No need to draw BUF or BUFZ tables.
|
||||
*
|
||||
* Revision 1.16 2004/10/04 01:10:59 steve
|
||||
* Clean up spurious trailing white space.
|
||||
*
|
||||
* Revision 1.15 2003/07/30 01:13:29 steve
|
||||
* Add support for triand and trior.
|
||||
*
|
||||
* Revision 1.14 2002/08/29 03:04:01 steve
|
||||
* Generate x out for x select on wide muxes.
|
||||
*
|
||||
* Revision 1.13 2002/08/12 01:35:08 steve
|
||||
* conditional ident string using autoconfig.
|
||||
*
|
||||
* Revision 1.12 2002/01/12 04:02:16 steve
|
||||
* Support the BUFZ logic device.
|
||||
*
|
||||
* Revision 1.11 2001/11/06 03:07:22 steve
|
||||
* Code rearrange. (Stephan Boettcher)
|
||||
*
|
||||
* Revision 1.10 2001/10/09 02:28:17 steve
|
||||
* Add the PMOS and NMOS functor types.
|
||||
*
|
||||
* Revision 1.9 2001/06/19 03:01:10 steve
|
||||
* Add structural EEQ gates (Stephan Boettcher)
|
||||
*
|
||||
* Revision 1.8 2001/04/29 23:13:34 steve
|
||||
* Add bufif0 and bufif1 functors.
|
||||
*
|
||||
* Revision 1.7 2001/04/26 05:12:02 steve
|
||||
* Implement simple MUXZ for ?: operators.
|
||||
*
|
||||
* Revision 1.6 2001/04/21 02:04:01 steve
|
||||
* Add NAND and XNOR functors.
|
||||
*
|
||||
* Revision 1.5 2001/04/15 16:37:48 steve
|
||||
* add XOR support.
|
||||
*
|
||||
* Revision 1.4 2001/04/01 21:31:46 steve
|
||||
* Add the buf functor type.
|
||||
*
|
||||
* Revision 1.3 2001/03/25 20:45:09 steve
|
||||
* Add vpiOctStrVal access to signals.
|
||||
*
|
||||
* Revision 1.2 2001/03/25 19:37:26 steve
|
||||
* Calculate NOR and NOT tables, and also the hex_digits table.
|
||||
*
|
||||
* Revision 1.1 2001/03/11 22:42:11 steve
|
||||
* Functor values and propagation.
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
+11
-10
@@ -87,6 +87,7 @@
|
||||
".alias" { return K_ALIAS; }
|
||||
".alias/real" { return K_ALIAS_R; }
|
||||
".alias/s" { return K_ALIAS_S; }
|
||||
".abs" { return K_ARITH_ABS; }
|
||||
".arith/div" { return K_ARITH_DIV; }
|
||||
".arith/div.r" { return K_ARITH_DIV_R; }
|
||||
".arith/div.s" { return K_ARITH_DIV_S; }
|
||||
@@ -133,6 +134,7 @@
|
||||
".net/s" { return K_NET_S; }
|
||||
".param/l" { return K_PARAM_L; }
|
||||
".param/str" { return K_PARAM_STR; }
|
||||
".param/real" { return K_PARAM_REAL; }
|
||||
".part" { return K_PART; }
|
||||
".part/pv" { return K_PART_PV; }
|
||||
".part/v" { return K_PART_V; }
|
||||
@@ -159,9 +161,6 @@
|
||||
".udp" { return K_UDP; }
|
||||
".udp/c"(omb)? { return K_UDP_C; }
|
||||
".udp/s"(equ)? { return K_UDP_S; }
|
||||
".mem" { return K_MEM; }
|
||||
".mem/p"(ort)? { return K_MEM_P; }
|
||||
".mem/i"(nit)? { return K_MEM_I; }
|
||||
"-debug" { return K_DEBUG; }
|
||||
|
||||
/* instructions start with a % character. The compiler decides what
|
||||
@@ -188,13 +187,7 @@
|
||||
return T_NUMBER; }
|
||||
|
||||
|
||||
|
||||
/* Symbols are pretty much what is left. They are used to refer to
|
||||
labels so the rule must match a string that a label would match. */
|
||||
[.$_a-zA-Z\\][.$_a-zA-Z\\0-9/]* {
|
||||
yylval.text = strdup(yytext);
|
||||
assert(yylval.text);
|
||||
return T_SYMBOL; }
|
||||
"&A" { return K_A; }
|
||||
|
||||
/* Handle some specialized constant/literals as symbols. */
|
||||
|
||||
@@ -223,6 +216,14 @@
|
||||
assert(yylval.text);
|
||||
return T_SYMBOL; }
|
||||
|
||||
/* Symbols are pretty much what is left. They are used to refer to
|
||||
labels so the rule must match a string that a label would match. */
|
||||
[.$_a-zA-Z\\][.$_a-zA-Z\\0-9<>/]* {
|
||||
yylval.text = strdup(yytext);
|
||||
assert(yylval.text);
|
||||
return T_SYMBOL; }
|
||||
|
||||
|
||||
/* Accept the common assembler style comments, treat them as white
|
||||
space. Of course, also skip white space. The semi-colon is
|
||||
special, though, in that it is also a statement terminator. */
|
||||
|
||||
+74
-93
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2001-2007 Stephen Williams (steve@icarus.com)
|
||||
* Copyright (c) 2001-2008 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,9 +16,6 @@
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
|
||||
*/
|
||||
#ifdef HAVE_CVS_IDENT
|
||||
#ident "$Id: logic.cc,v 1.38 2007/02/12 05:08:27 steve Exp $"
|
||||
#endif
|
||||
|
||||
# include "logic.h"
|
||||
# include "compile.h"
|
||||
@@ -34,52 +31,6 @@
|
||||
# include <malloc.h>
|
||||
#endif
|
||||
|
||||
|
||||
/*
|
||||
* Implementation of the table functor, which provides logic with up
|
||||
* to 4 inputs.
|
||||
*/
|
||||
|
||||
table_functor_s::table_functor_s(truth_t t)
|
||||
: table(t)
|
||||
{
|
||||
count_functors_logic += 1;
|
||||
}
|
||||
|
||||
table_functor_s::~table_functor_s()
|
||||
{
|
||||
}
|
||||
|
||||
/*
|
||||
* WARNING: This function assumes that the table generator encodes the
|
||||
* values 0/1/x/z the same as the vvp_bit4_t enumeration values.
|
||||
*/
|
||||
void table_functor_s::recv_vec4(vvp_net_ptr_t ptr, const vvp_vector4_t&val)
|
||||
{
|
||||
input_[ptr.port()] = val;
|
||||
|
||||
vvp_vector4_t result (val.size());
|
||||
|
||||
for (unsigned idx = 0 ; idx < val.size() ; idx += 1) {
|
||||
|
||||
unsigned lookup = 0;
|
||||
for (unsigned pdx = 4 ; pdx > 0 ; pdx -= 1) {
|
||||
lookup <<= 2;
|
||||
if (idx < input_[pdx-1].size())
|
||||
lookup |= input_[pdx-1].value(idx);
|
||||
}
|
||||
|
||||
unsigned off = lookup / 4;
|
||||
unsigned shift = lookup % 4 * 2;
|
||||
|
||||
unsigned bit_val = table[off] >> shift;
|
||||
bit_val &= 3;
|
||||
result.set_bit(idx, (vvp_bit4_t)bit_val);
|
||||
}
|
||||
|
||||
vvp_send_vec4(ptr.ptr()->out, result);
|
||||
}
|
||||
|
||||
vvp_fun_boolean_::vvp_fun_boolean_(unsigned wid)
|
||||
{
|
||||
net_ = 0;
|
||||
@@ -259,8 +210,9 @@ void vvp_fun_bufz::recv_real(vvp_net_ptr_t ptr, double bit)
|
||||
vvp_fun_muxr::vvp_fun_muxr()
|
||||
: a_(0.0), b_(0.0)
|
||||
{
|
||||
net_ = 0;
|
||||
count_functors_logic += 1;
|
||||
select_ = 2;
|
||||
select_ = SEL_BOTH;
|
||||
}
|
||||
|
||||
vvp_fun_muxr::~vvp_fun_muxr()
|
||||
@@ -270,7 +222,7 @@ vvp_fun_muxr::~vvp_fun_muxr()
|
||||
void vvp_fun_muxr::recv_vec4(vvp_net_ptr_t ptr, const vvp_vector4_t&bit)
|
||||
{
|
||||
/* The real valued mux can only take in the select as a
|
||||
vector4_t. the muxed data is rea. */
|
||||
vector4_t. The muxed data is real. */
|
||||
if (ptr.port() != 2)
|
||||
return;
|
||||
|
||||
@@ -278,30 +230,21 @@ void vvp_fun_muxr::recv_vec4(vvp_net_ptr_t ptr, const vvp_vector4_t&bit)
|
||||
|
||||
switch (bit.value(0)) {
|
||||
case BIT4_0:
|
||||
select_ = 0;
|
||||
if (select_ == SEL_PORT0) return;
|
||||
select_ = SEL_PORT0;
|
||||
break;
|
||||
case BIT4_1:
|
||||
select_ = 1;
|
||||
if (select_ == SEL_PORT1) return;
|
||||
select_ = SEL_PORT1;
|
||||
break;
|
||||
default:
|
||||
select_ = 2;
|
||||
if (select_ == SEL_BOTH) return;
|
||||
select_ = SEL_BOTH;
|
||||
}
|
||||
|
||||
switch (select_) {
|
||||
case 0:
|
||||
vvp_send_real(ptr.ptr()->out, a_);
|
||||
break;
|
||||
case 1:
|
||||
vvp_send_real(ptr.ptr()->out, b_);
|
||||
break;
|
||||
default:
|
||||
if (a_ == b_) {
|
||||
vvp_send_real(ptr.ptr()->out, a_);
|
||||
} else {
|
||||
// Should send NaN?
|
||||
vvp_send_real(ptr.ptr()->out, 0.0);
|
||||
}
|
||||
break;
|
||||
if (net_ == 0) {
|
||||
net_ = ptr.ptr();
|
||||
schedule_generic(this, 0, false);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -309,34 +252,57 @@ void vvp_fun_muxr::recv_real(vvp_net_ptr_t ptr, double bit)
|
||||
{
|
||||
switch (ptr.port()) {
|
||||
case 0:
|
||||
if (a_ == bit)
|
||||
break;
|
||||
|
||||
if (a_ == bit) return;
|
||||
a_ = bit;
|
||||
if (select_ == 0)
|
||||
vvp_send_real(ptr.ptr()->out, a_);
|
||||
if (select_ == SEL_PORT1) return; // The other port is selected.
|
||||
break;
|
||||
|
||||
case 1:
|
||||
if (b_ == bit)
|
||||
break;
|
||||
|
||||
if (b_ == bit) return;
|
||||
b_ = bit;
|
||||
if (select_ == 1)
|
||||
vvp_send_real(ptr.ptr()->out, b_);
|
||||
if (select_ == SEL_PORT0) return; // The other port is selected.
|
||||
break;
|
||||
|
||||
default:
|
||||
fprintf(stderr, "Unsupported port type %d.\n", ptr.port());
|
||||
assert(0);
|
||||
}
|
||||
|
||||
if (net_ == 0) {
|
||||
net_ = ptr.ptr();
|
||||
schedule_generic(this, 0, false);
|
||||
}
|
||||
}
|
||||
|
||||
void vvp_fun_muxr::run_run()
|
||||
{
|
||||
vvp_net_t*ptr = net_;
|
||||
net_ = 0;
|
||||
|
||||
switch (select_) {
|
||||
case SEL_PORT0:
|
||||
vvp_send_real(ptr->out, a_);
|
||||
break;
|
||||
case SEL_PORT1:
|
||||
vvp_send_real(ptr->out, b_);
|
||||
break;
|
||||
default:
|
||||
if (a_ == b_) {
|
||||
vvp_send_real(ptr->out, a_);
|
||||
} else {
|
||||
vvp_send_real(ptr->out, 0.0); // Should this be NaN?
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
vvp_fun_muxz::vvp_fun_muxz(unsigned wid)
|
||||
: a_(wid), b_(wid)
|
||||
{
|
||||
net_ = 0;
|
||||
count_functors_logic += 1;
|
||||
select_ = 2;
|
||||
select_ = SEL_BOTH;
|
||||
has_run_ = false;
|
||||
for (unsigned idx = 0 ; idx < wid ; idx += 1) {
|
||||
a_.set_bit(idx, BIT4_X);
|
||||
b_.set_bit(idx, BIT4_X);
|
||||
@@ -351,34 +317,53 @@ void vvp_fun_muxz::recv_vec4(vvp_net_ptr_t ptr, const vvp_vector4_t&bit)
|
||||
{
|
||||
switch (ptr.port()) {
|
||||
case 0:
|
||||
if (a_ .eeq(bit) && has_run_) return;
|
||||
a_ = bit;
|
||||
if (select_ == SEL_PORT1) return; // The other port is selected.
|
||||
break;
|
||||
case 1:
|
||||
if (b_ .eeq(bit) && has_run_) return;
|
||||
b_ = bit;
|
||||
if (select_ == SEL_PORT0) return; // The other port is selected.
|
||||
break;
|
||||
case 2:
|
||||
assert(bit.size() == 1);
|
||||
switch (bit.value(0)) {
|
||||
case BIT4_0:
|
||||
select_ = 0;
|
||||
if (select_ == SEL_PORT0) return;
|
||||
select_ = SEL_PORT0;
|
||||
break;
|
||||
case BIT4_1:
|
||||
select_ = 1;
|
||||
if (select_ == SEL_PORT1) return;
|
||||
select_ = SEL_PORT1;
|
||||
break;
|
||||
default:
|
||||
select_ = 2;
|
||||
if (select_ == SEL_BOTH && has_run_) return;
|
||||
select_ = SEL_BOTH;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
return;
|
||||
}
|
||||
|
||||
if (net_ == 0) {
|
||||
net_ = ptr.ptr();
|
||||
schedule_generic(this, 0, false);
|
||||
}
|
||||
}
|
||||
|
||||
void vvp_fun_muxz::run_run()
|
||||
{
|
||||
has_run_ = true;
|
||||
vvp_net_t*ptr = net_;
|
||||
net_ = 0;
|
||||
|
||||
switch (select_) {
|
||||
case 0:
|
||||
vvp_send_vec4(ptr.ptr()->out, a_);
|
||||
case SEL_PORT0:
|
||||
vvp_send_vec4(ptr->out, a_);
|
||||
break;
|
||||
case 1:
|
||||
vvp_send_vec4(ptr.ptr()->out, b_);
|
||||
case SEL_PORT1:
|
||||
vvp_send_vec4(ptr->out, b_);
|
||||
break;
|
||||
default:
|
||||
{
|
||||
@@ -401,7 +386,7 @@ void vvp_fun_muxz::recv_vec4(vvp_net_ptr_t ptr, const vvp_vector4_t&bit)
|
||||
for (unsigned idx = min_size ; idx < max_size ; idx += 1)
|
||||
res.set_bit(idx, BIT4_X);
|
||||
|
||||
vvp_send_vec4(ptr.ptr()->out, res);
|
||||
vvp_send_vec4(ptr->out, res);
|
||||
}
|
||||
break;
|
||||
}
|
||||
@@ -573,9 +558,6 @@ void compile_functor(char*label, char*type, unsigned width,
|
||||
} else if (strcmp(type, "MUXR") == 0) {
|
||||
obj = new vvp_fun_muxr;
|
||||
|
||||
} else if (strcmp(type, "MUXX") == 0) {
|
||||
obj = new table_functor_s(ft_MUXX);
|
||||
|
||||
} else if (strcmp(type, "MUXZ") == 0) {
|
||||
obj = new vvp_fun_muxz(width);
|
||||
|
||||
@@ -645,4 +627,3 @@ void compile_functor(char*label, char*type, unsigned width,
|
||||
define_functor_symbol(label, net_drv);
|
||||
free(label);
|
||||
}
|
||||
|
||||
|
||||
+16
-35
@@ -1,7 +1,7 @@
|
||||
#ifndef __logic_H
|
||||
#define __logic_H
|
||||
/*
|
||||
* Copyright (c) 2000-2007 Stephen Williams (steve@icarus.com)
|
||||
* Copyright (c) 2000-2008 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,34 +18,11 @@
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
|
||||
*/
|
||||
#ifdef HAVE_CVS_IDENT
|
||||
#ident "$Id: logic.h,v 1.25 2006/11/28 05:57:20 steve Exp $"
|
||||
#endif
|
||||
|
||||
# include "vvp_net.h"
|
||||
# include "schedule.h"
|
||||
# include <stddef.h>
|
||||
|
||||
/*
|
||||
* Table driven functor. This kind of node takes 4 inputs and
|
||||
* generates a single output. The logic is bitwise, and implemented
|
||||
* with a lookup table.
|
||||
*/
|
||||
|
||||
class table_functor_s: public vvp_net_fun_t {
|
||||
|
||||
public:
|
||||
typedef const unsigned char *truth_t;
|
||||
explicit table_functor_s(truth_t t);
|
||||
virtual ~table_functor_s();
|
||||
|
||||
void recv_vec4(vvp_net_ptr_t p, const vvp_vector4_t&bit);
|
||||
|
||||
private:
|
||||
truth_t table;
|
||||
vvp_vector4_t input_[4];
|
||||
};
|
||||
|
||||
/*
|
||||
* vvp_fun_boolean_ is just a common hook for holding operands.
|
||||
*/
|
||||
@@ -124,6 +101,8 @@ class vvp_fun_bufz: public vvp_net_fun_t {
|
||||
private:
|
||||
};
|
||||
|
||||
enum sel_type {SEL_PORT0, SEL_PORT1, SEL_BOTH};
|
||||
|
||||
/*
|
||||
* The muxz functor is an A-B mux device, with the data inputs on
|
||||
* ports 0 and 1. port 2 is the select input.
|
||||
@@ -135,7 +114,7 @@ class vvp_fun_bufz: public vvp_net_fun_t {
|
||||
* input (port-0 or port-1) to enter the device. The narrow vector is
|
||||
* padded with X values.
|
||||
*/
|
||||
class vvp_fun_muxz : public vvp_net_fun_t {
|
||||
class vvp_fun_muxz : public vvp_net_fun_t, private vvp_gen_event_s {
|
||||
|
||||
public:
|
||||
explicit vvp_fun_muxz(unsigned width);
|
||||
@@ -143,13 +122,18 @@ class vvp_fun_muxz : public vvp_net_fun_t {
|
||||
|
||||
void recv_vec4(vvp_net_ptr_t p, const vvp_vector4_t&bit);
|
||||
|
||||
private:
|
||||
void run_run();
|
||||
|
||||
private:
|
||||
vvp_vector4_t a_;
|
||||
vvp_vector4_t b_;
|
||||
int select_;
|
||||
vvp_net_t*net_;
|
||||
sel_type select_;
|
||||
bool has_run_;
|
||||
};
|
||||
|
||||
class vvp_fun_muxr : public vvp_net_fun_t {
|
||||
class vvp_fun_muxr : public vvp_net_fun_t, private vvp_gen_event_s {
|
||||
|
||||
public:
|
||||
explicit vvp_fun_muxr();
|
||||
@@ -158,10 +142,14 @@ class vvp_fun_muxr : public vvp_net_fun_t {
|
||||
void recv_vec4(vvp_net_ptr_t p, const vvp_vector4_t&bit);
|
||||
void recv_real(vvp_net_ptr_t p, double bit);
|
||||
|
||||
private:
|
||||
void run_run();
|
||||
|
||||
private:
|
||||
double a_;
|
||||
double b_;
|
||||
int select_;
|
||||
vvp_net_t*net_;
|
||||
sel_type select_;
|
||||
};
|
||||
|
||||
class vvp_fun_not: public vvp_net_fun_t, private vvp_gen_event_s {
|
||||
@@ -202,11 +190,4 @@ class vvp_fun_xor : public vvp_fun_boolean_ {
|
||||
bool invert_;
|
||||
};
|
||||
|
||||
// table functor types
|
||||
|
||||
extern const unsigned char ft_MUXX[];
|
||||
extern const unsigned char ft_EEQ[];
|
||||
extern const unsigned char ft_TRIAND[];
|
||||
extern const unsigned char ft_TRIOR[];
|
||||
|
||||
#endif // __logic_H
|
||||
|
||||
-299
@@ -1,299 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2005 Stephen Williams (steve@icarus.com)
|
||||
* Copyright (c) 2000 Stephen Williams (steve@icarus.com)
|
||||
* Copyright (c) 2001 Stephan Boettcher <stephan@nevis.columbia.edu>
|
||||
*
|
||||
* 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
|
||||
*/
|
||||
#ifdef HAVE_CVS_IDENT
|
||||
#ident "$Id: memory.cc,v 1.29 2006/03/05 05:45:58 steve Exp $"
|
||||
#endif
|
||||
|
||||
#include "memory.h"
|
||||
#include "symbols.h"
|
||||
#include "schedule.h"
|
||||
#include "vpi_priv.h"
|
||||
#include <assert.h>
|
||||
#ifdef HAVE_MALLOC_H
|
||||
#include <malloc.h>
|
||||
#endif
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
|
||||
typedef struct vvp_memory_port_s *vvp_memory_port_t;
|
||||
|
||||
struct vvp_memory_s
|
||||
{
|
||||
// Address ranges (1 or more)
|
||||
unsigned nrange;
|
||||
struct memory_address_range*ranges;
|
||||
|
||||
// Data port properties:
|
||||
unsigned width; // number of data bits
|
||||
|
||||
int msb, lsb; // Most/Least Significant data bit (VPI)
|
||||
|
||||
// Array of words.
|
||||
unsigned word_count;
|
||||
vvp_vector4_t*words;
|
||||
|
||||
// List of ports into this memory.
|
||||
class vvp_fun_memport* port_list;
|
||||
vpiHandle vpi_self;
|
||||
};
|
||||
|
||||
#define VVP_MEMORY_NO_ADDR ((int)0x80000000)
|
||||
|
||||
// Compilation
|
||||
|
||||
static symbol_table_t memory_table = 0;
|
||||
|
||||
vvp_memory_t memory_find(char *label)
|
||||
{
|
||||
if (memory_table == 0)
|
||||
return 0;
|
||||
|
||||
symbol_value_t v = sym_get_value(memory_table, label);
|
||||
return (vvp_memory_t)v.ptr;
|
||||
}
|
||||
|
||||
vvp_memory_t memory_create(char *label)
|
||||
{
|
||||
if (!memory_table)
|
||||
memory_table = new_symbol_table();
|
||||
|
||||
assert(!memory_find(label));
|
||||
|
||||
vvp_memory_t mem = new struct vvp_memory_s;
|
||||
|
||||
symbol_value_t v;
|
||||
v.ptr = mem;
|
||||
sym_set_value(memory_table, label, v);
|
||||
|
||||
return mem;
|
||||
}
|
||||
|
||||
void memory_configure(vvp_memory_t mem,
|
||||
int msb, int lsb,
|
||||
unsigned nrange,
|
||||
const struct memory_address_range*ranges)
|
||||
{
|
||||
/* Get the word width details. */
|
||||
mem->width = msb > lsb ? msb-lsb+1 : lsb-msb+1;
|
||||
mem->msb = msb;
|
||||
mem->lsb = lsb;
|
||||
|
||||
/* Make a private copy of the memory address ranges. */
|
||||
assert(nrange > 0);
|
||||
mem->nrange = nrange;
|
||||
mem->ranges = new struct memory_address_range[nrange];
|
||||
for (unsigned idx = 0 ; idx < nrange ; idx += 1)
|
||||
mem->ranges[idx] = ranges[idx];
|
||||
|
||||
/* Scan the indices (multiplying each range) to add up the
|
||||
total number of words in this memory. */
|
||||
mem->word_count = 1;
|
||||
for (unsigned idx = 0 ; idx < mem->nrange ; idx += 1) {
|
||||
struct memory_address_range*rp = mem->ranges+idx;
|
||||
|
||||
unsigned count = rp->msb > rp->lsb
|
||||
? rp->msb - rp->lsb + 1
|
||||
: rp->lsb - rp->msb + 1;
|
||||
|
||||
mem->word_count *= count;
|
||||
}
|
||||
|
||||
mem->words = new vvp_vector4_t [mem->word_count];
|
||||
assert(mem->words);
|
||||
|
||||
mem->port_list = 0;
|
||||
mem->vpi_self = 0;
|
||||
}
|
||||
|
||||
void memory_attach_self(vvp_memory_t mem, vpiHandle self)
|
||||
{
|
||||
assert(mem->vpi_self == 0);
|
||||
mem->vpi_self = self;
|
||||
}
|
||||
|
||||
unsigned memory_word_width(vvp_memory_t mem)
|
||||
{
|
||||
return mem->width;
|
||||
}
|
||||
|
||||
unsigned memory_word_count(vvp_memory_t mem)
|
||||
{
|
||||
return mem->word_count;
|
||||
}
|
||||
|
||||
long memory_word_left_range(vvp_memory_t mem)
|
||||
{
|
||||
return mem->msb;
|
||||
}
|
||||
|
||||
long memory_word_right_range(vvp_memory_t mem)
|
||||
{
|
||||
return mem->lsb;
|
||||
}
|
||||
|
||||
long memory_left_range(vvp_memory_t mem, unsigned ix)
|
||||
{
|
||||
assert(ix < mem->nrange);
|
||||
return mem->ranges[ix].msb;
|
||||
}
|
||||
|
||||
long memory_right_range(vvp_memory_t mem, unsigned ix)
|
||||
{
|
||||
assert(ix < mem->nrange);
|
||||
return mem->ranges[ix].lsb;
|
||||
}
|
||||
|
||||
vvp_vector4_t memory_get_word(vvp_memory_t mem, unsigned addr)
|
||||
{
|
||||
/* If the address is out of range, then return a vector of all
|
||||
X bits. */
|
||||
if (addr >= mem->word_count) {
|
||||
vvp_vector4_t val (mem->width);
|
||||
for (unsigned idx = 0 ; idx < mem->width ; idx += 1)
|
||||
val.set_bit(idx, BIT4_X);
|
||||
return val;
|
||||
}
|
||||
|
||||
assert(addr <= mem->word_count);
|
||||
|
||||
if (mem->words[addr].size() == 0) {
|
||||
vvp_vector4_t tmp (mem->width);
|
||||
for (unsigned idx = 0 ; idx < mem->width ; idx += 1)
|
||||
tmp.set_bit(idx, BIT4_X);
|
||||
mem->words[addr] = tmp;
|
||||
}
|
||||
|
||||
return mem->words[addr];
|
||||
}
|
||||
|
||||
void memory_init_word(vvp_memory_t mem, unsigned addr, vvp_vector4_t val)
|
||||
{
|
||||
if (addr >= mem->word_count)
|
||||
return;
|
||||
|
||||
assert(val.size() == mem->width);
|
||||
mem->words[addr] = val;
|
||||
}
|
||||
|
||||
void memory_set_word(vvp_memory_t mem, unsigned addr,
|
||||
unsigned off, vvp_vector4_t val)
|
||||
{
|
||||
if (addr >= mem->word_count)
|
||||
return;
|
||||
|
||||
if (off >= mem->width)
|
||||
return;
|
||||
|
||||
if (off == 0 && val.size() == mem->width) {
|
||||
mem->words[addr] = val;
|
||||
|
||||
} else {
|
||||
if ((off + val.size()) > mem->width)
|
||||
val = val.subvalue(0, mem->width - off);
|
||||
|
||||
mem->words[addr].set_vec(off, val);
|
||||
}
|
||||
|
||||
for (vvp_fun_memport*cur = mem->port_list
|
||||
; cur ; cur = cur->next_) {
|
||||
cur->check_word_change(addr);
|
||||
}
|
||||
|
||||
vpip_run_memory_value_change(mem->vpi_self, addr);
|
||||
}
|
||||
|
||||
void schedule_memory(vvp_memory_t mem, unsigned addr,
|
||||
vvp_vector4_t val, unsigned long delay)
|
||||
{
|
||||
fprintf(stderr, "XXXX Forgot how to schedule memory write.\n");
|
||||
}
|
||||
|
||||
vvp_fun_memport::vvp_fun_memport(vvp_memory_t mem, vvp_net_t*net)
|
||||
: mem_(mem), net_(net)
|
||||
{
|
||||
addr_ = 0;
|
||||
next_ = mem_->port_list;
|
||||
mem_->port_list = this;
|
||||
}
|
||||
|
||||
vvp_fun_memport::~vvp_fun_memport()
|
||||
{
|
||||
}
|
||||
|
||||
void vvp_fun_memport::recv_vec4(vvp_net_ptr_t port, const vvp_vector4_t&bit)
|
||||
{
|
||||
bool addr_valid_flag;
|
||||
|
||||
switch (port.port()) {
|
||||
|
||||
case 0: // Address input
|
||||
addr_valid_flag = vector4_to_value(bit, addr_);
|
||||
if (! addr_valid_flag)
|
||||
addr_ = memory_word_count(mem_);
|
||||
vvp_send_vec4(port.ptr()->out, memory_get_word(mem_,addr_));
|
||||
break;
|
||||
|
||||
default:
|
||||
fprintf(stdout, "XXXX write ports not implemented.\n");
|
||||
assert(0);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* This function is called by the memory itself to tell this port that
|
||||
* the given address had a content change. The device itself figures
|
||||
* out what to do with that information.
|
||||
*/
|
||||
void vvp_fun_memport::check_word_change(unsigned long addr)
|
||||
{
|
||||
if (addr != addr_)
|
||||
return;
|
||||
|
||||
vvp_vector4_t bit = memory_get_word(mem_, addr_);
|
||||
vvp_send_vec4(net_->out, bit);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* $Log: memory.cc,v $
|
||||
* Revision 1.29 2006/03/05 05:45:58 steve
|
||||
* Add support for memory value change callbacks.
|
||||
*
|
||||
* Revision 1.28 2006/02/02 02:44:00 steve
|
||||
* Allow part selects of memory words in l-values.
|
||||
*
|
||||
* Revision 1.27 2005/06/22 00:04:49 steve
|
||||
* Reduce vvp_vector4 copies by using const references.
|
||||
*
|
||||
* Revision 1.26 2005/03/09 04:52:40 steve
|
||||
* reimplement memory ports.
|
||||
*
|
||||
* Revision 1.25 2005/03/06 17:07:48 steve
|
||||
* Non blocking assign to memory words.
|
||||
*
|
||||
* Revision 1.24 2005/03/05 05:44:32 steve
|
||||
* Get read width of unitialized memory words right.
|
||||
*
|
||||
* Revision 1.23 2005/03/03 04:33:10 steve
|
||||
* Rearrange how memories are supported as vvp_vector4 arrays.
|
||||
*
|
||||
*/
|
||||
-180
@@ -1,180 +0,0 @@
|
||||
#ifndef __memory_H // -*- c++ -*-
|
||||
#define __memory_H
|
||||
/*
|
||||
* Copyright (c) 2001 Stephen Williams (steve@icarus.com)
|
||||
* Copyright (c) 2001 Stephan Boettcher <stephan@nevis.columbia.edu>
|
||||
*
|
||||
* 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
|
||||
*/
|
||||
#ifdef HAVE_CVS_IDENT
|
||||
#ident "$Id: memory.h,v 1.13 2007/03/22 16:08:19 steve Exp $"
|
||||
#endif
|
||||
|
||||
#include "vvp_net.h"
|
||||
#include "vpi_user.h"
|
||||
|
||||
/*
|
||||
** vvp_memory_t is a memory
|
||||
** vvp_memory_index_t is a memory index range definition
|
||||
*/
|
||||
typedef struct vvp_memory_s *vvp_memory_t;
|
||||
|
||||
struct memory_address_range {
|
||||
int msb;
|
||||
int lsb;
|
||||
};
|
||||
|
||||
/*
|
||||
* Given a memory device, the memory_configure function configures it
|
||||
* by defining the dimensions of the device. It is an error to
|
||||
* redefine the dimensions of a device already configured.
|
||||
*
|
||||
* The lsb and msb define the dimensions of a word. They are in
|
||||
* Verilog form. The actual word contents are vvp_vector4_t values.
|
||||
*
|
||||
* The idx array is an array of address ranges that describe the
|
||||
* complete multi-dimensional array. In a normal Verilog array, idxs
|
||||
* is 1, and idx is a pointer to a single memory_address_range. The
|
||||
* table does not need to be persistent.
|
||||
*/
|
||||
extern void memory_configure(vvp_memory_t mem, int msb, int lsb,
|
||||
unsigned idxs,
|
||||
const struct memory_address_range *idx);
|
||||
extern void memory_attach_self(vvp_memory_t mem, vpiHandle self);
|
||||
|
||||
/*
|
||||
* init_word and set_word functions take the memory to be manipulated
|
||||
* and write a word value at the given word address. The idx is the
|
||||
* canonical (0-based, 1-dimensional) address of the word to be
|
||||
* written. The caller needs to have converted any multi-dimensional
|
||||
* address into a canonical address first.
|
||||
*
|
||||
* The difference between init_word and set_word are that the set_word
|
||||
* function causes values to be propagated through structural ports,
|
||||
* but the init_word does not.
|
||||
*/
|
||||
extern void memory_init_word(vvp_memory_t mem,
|
||||
unsigned idx,
|
||||
vvp_vector4_t val);
|
||||
extern void memory_set_word(vvp_memory_t mem,
|
||||
unsigned idx,
|
||||
unsigned off,
|
||||
vvp_vector4_t val);
|
||||
|
||||
/*
|
||||
* This doesn't actually write the value to the memory word, but
|
||||
* schedules for the write to happen some time in the future. The delay
|
||||
* is in simulation clock units.
|
||||
*/
|
||||
void schedule_memory(vvp_memory_t mem, unsigned addr,
|
||||
vvp_vector4_t val, unsigned long delay);
|
||||
|
||||
/*
|
||||
* Get the word value at the given index into the memory.
|
||||
*/
|
||||
extern vvp_vector4_t memory_get_word(vvp_memory_t mem, unsigned idx);
|
||||
|
||||
|
||||
/* Number of words in the memory. */
|
||||
unsigned memory_word_count(vvp_memory_t mem);
|
||||
/* Width of a word */
|
||||
unsigned memory_word_width(vvp_memory_t mem);
|
||||
/* Get the user declared geometry of the memory address. This is the
|
||||
msb and lsb values for each pair in the multi-dimensional array. */
|
||||
long memory_left_range(vvp_memory_t mem, unsigned ix);
|
||||
long memory_right_range(vvp_memory_t mem, unsigned ix);
|
||||
/* Get the user defined geometry for the memory *word*. */
|
||||
long memory_word_left_range(vvp_memory_t mem);
|
||||
long memory_word_right_range(vvp_memory_t mem);
|
||||
|
||||
|
||||
/* vvp_fun_memport
|
||||
* The vvp_fum_memport is a structural port into a vvp_memory_t
|
||||
* object. The output is the word that is read from the addressed
|
||||
* memory, and the inputs are the address and optional write controls.
|
||||
*
|
||||
* 0 -- Address
|
||||
* This addresses the word in the memory. The output follows this
|
||||
* address as it changes, and also follows the value of the addressed
|
||||
* word.
|
||||
*
|
||||
* 1 -- Write event
|
||||
*
|
||||
* 2 -- Write enable
|
||||
*
|
||||
* 3 -- Write data
|
||||
*
|
||||
* NOTE: This functor is unique in that it needs to store the
|
||||
* vvp_net_t pointer associated with it. It needs this because it can
|
||||
* received input from other than its ports. Notably, the memory
|
||||
* itself reports word changes.
|
||||
*/
|
||||
class vvp_fun_memport : public vvp_net_fun_t {
|
||||
|
||||
public:
|
||||
explicit vvp_fun_memport(vvp_memory_t mem, vvp_net_t*net);
|
||||
~vvp_fun_memport();
|
||||
|
||||
void recv_vec4(vvp_net_ptr_t port, const vvp_vector4_t&bit);
|
||||
|
||||
private:
|
||||
vvp_memory_t mem_;
|
||||
|
||||
friend void memory_set_word(vvp_memory_t, unsigned,
|
||||
unsigned, vvp_vector4_t);
|
||||
void check_word_change(unsigned long address);
|
||||
class vvp_fun_memport*next_;
|
||||
|
||||
unsigned long addr_;
|
||||
|
||||
vvp_net_t*net_;
|
||||
};
|
||||
|
||||
/*
|
||||
** Access to the memory symbol table.
|
||||
**
|
||||
** The memory_find function locates the memory device by name. If the
|
||||
** device does not exist, a nil is returned.
|
||||
**
|
||||
** The memory_create function creates a new memory device with the given
|
||||
** name. It is a fatal error to try to create a device that already exists.
|
||||
*/
|
||||
vvp_memory_t memory_find(char *label);
|
||||
vvp_memory_t memory_create(char *label);
|
||||
|
||||
/*
|
||||
* $Log: memory.h,v $
|
||||
* Revision 1.13 2007/03/22 16:08:19 steve
|
||||
* Spelling fixes from Larry
|
||||
*
|
||||
* Revision 1.12 2006/03/05 05:45:58 steve
|
||||
* Add support for memory value change callbacks.
|
||||
*
|
||||
* Revision 1.11 2006/02/02 02:44:00 steve
|
||||
* Allow part selects of memory words in l-values.
|
||||
*
|
||||
* Revision 1.10 2005/06/22 00:04:49 steve
|
||||
* Reduce vvp_vector4 copies by using const references.
|
||||
*
|
||||
* Revision 1.9 2005/03/09 04:52:40 steve
|
||||
* reimplement memory ports.
|
||||
*
|
||||
* Revision 1.8 2005/03/03 04:33:10 steve
|
||||
* Rearrange how memories are supported as vvp_vector4 arrays.
|
||||
*
|
||||
*/
|
||||
|
||||
#endif
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user