mirror of
https://github.com/steveicarus/iverilog.git
synced 2026-08-24 14:56:57 +02:00
Compare commits
172
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
afa2478801 | ||
|
|
79feb44f10 | ||
|
|
c03d76a0d7 | ||
|
|
a2dc1e0a29 | ||
|
|
6a1235ac28 | ||
|
|
7aebff2a86 | ||
|
|
b31124983a | ||
|
|
f256dfe16e | ||
|
|
7c152685dc | ||
|
|
5d86dd0bbd | ||
|
|
4f97321c75 | ||
|
|
d0f303463d | ||
|
|
35fe8fae00 | ||
|
|
2e95a740da | ||
|
|
2f4e5bf5b6 | ||
|
|
7e478cdeb8 | ||
|
|
2576543bb5 | ||
|
|
e453b347f4 | ||
|
|
f132e09475 | ||
|
|
2ee976d1c0 | ||
|
|
30570adf31 | ||
|
|
1c51ac4ac0 | ||
|
|
17a1358eb6 | ||
|
|
04a7f7054a | ||
|
|
e97a1ad610 | ||
|
|
e872310e4b | ||
|
|
95850ac112 | ||
|
|
d0e154b830 | ||
|
|
4010f6e710 | ||
|
|
d74f2fe38d | ||
|
|
db642e3850 | ||
|
|
523dff7ae7 | ||
|
|
db09f2fa7e | ||
|
|
c2061e8199 | ||
|
|
ff9166d4a5 | ||
|
|
73e2b297df | ||
|
|
6e5373c87e | ||
|
|
782bfab29e | ||
|
|
df15a0368c | ||
|
|
916f300448 | ||
|
|
7898f4e402 | ||
|
|
6f8bf90dc4 | ||
|
|
052870c0e5 | ||
|
|
1be1f65f33 | ||
|
|
fd6f017435 | ||
|
|
dfa6471227 | ||
|
|
a8f492776a | ||
|
|
6f0d98cf18 | ||
|
|
6f30813102 | ||
|
|
2fab3159dd | ||
|
|
f04fb0fc45 | ||
|
|
7a1180868a | ||
|
|
b2bdce98ab | ||
|
|
653e2661b2 | ||
|
|
9aa610f489 | ||
|
|
de7fff8ac6 | ||
|
|
2179797763 | ||
|
|
b5e9e44e07 | ||
|
|
5a0fe9ff83 | ||
|
|
f6fede5aae | ||
|
|
0fa3099ded | ||
|
|
6987d16bd3 | ||
|
|
5cc376ebd4 | ||
|
|
8190307dd3 | ||
|
|
3575f68c9f | ||
|
|
c1268d04fc | ||
|
|
ca756f3ec3 | ||
|
|
9af459f95b | ||
|
|
492b240304 | ||
|
|
d2106a3d3a | ||
|
|
cf2f4dd0af | ||
|
|
608c2574bd | ||
|
|
f17db21bf0 | ||
|
|
b26bdd3c19 | ||
|
|
6a9c5d8f7e | ||
|
|
e59f28d659 | ||
|
|
07ae300e0c | ||
|
|
4c5f24c7a7 | ||
|
|
be810c5ba6 | ||
|
|
5ec3b590bf | ||
|
|
88313670c0 | ||
|
|
d1daf6733f | ||
|
|
007056d671 | ||
|
|
2dcb1514a2 | ||
|
|
d71a1cb9c1 | ||
|
|
f9f68236bc | ||
|
|
dadb3a68d3 | ||
|
|
6121c06f15 | ||
|
|
b289d740e2 | ||
|
|
ec266ff52e | ||
|
|
ec773fe8cf | ||
|
|
4c3d764a86 | ||
|
|
a412149e2c | ||
|
|
deb7b01717 | ||
|
|
3189efacbc | ||
|
|
96ec4b7eba | ||
|
|
07c8fce530 | ||
|
|
9a00829ee4 | ||
|
|
680d3c8a3e | ||
|
|
6966c26f27 | ||
|
|
a5e3d06412 | ||
|
|
eb3dcc2786 | ||
|
|
c76e88cad5 | ||
|
|
6632e4c33b | ||
|
|
42913e46b8 | ||
|
|
e2ad59466a | ||
|
|
0cd946a7af | ||
|
|
102cbb67b4 | ||
|
|
3113392594 | ||
|
|
72b4256872 | ||
|
|
ca880c73fc | ||
|
|
f588656dd5 | ||
|
|
cef0d0071b | ||
|
|
35e48fb7b7 | ||
|
|
2934ceb548 | ||
|
|
6b908aeec3 | ||
|
|
a069b6dbe1 | ||
|
|
48f934abf7 | ||
|
|
a6dd97a5a6 | ||
|
|
2b4f7f8aed | ||
|
|
add84b153c | ||
|
|
2172c8a503 | ||
|
|
cbf96d73ee | ||
|
|
3c5bf034ca | ||
|
|
7166aea1d7 | ||
|
|
93b400c4d7 | ||
|
|
a506a18970 | ||
|
|
5b273178f5 | ||
|
|
cde87ed4a3 | ||
|
|
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 |
+55
-35
@@ -16,9 +16,6 @@
|
||||
# 59 Temple Place - Suite 330
|
||||
# Boston, MA 02111-1307, USA
|
||||
#
|
||||
#ident "$Id: Makefile.in,v 1.181 2007/05/24 04:07:11 steve Exp $"
|
||||
#
|
||||
#
|
||||
SHELL = /bin/sh
|
||||
|
||||
# This version string is only used in the version message printed
|
||||
@@ -51,6 +48,9 @@ INSTALL_PROGRAM = @INSTALL_PROGRAM@
|
||||
INSTALL_DATA = @INSTALL_DATA@
|
||||
LEX = @LEX@
|
||||
YACC = @YACC@
|
||||
MAN = @MAN@
|
||||
PS2PDF = @PS2PDF@
|
||||
GIT = @GIT@
|
||||
|
||||
CPPFLAGS = @ident_support@ @DEFS@ -I. -I$(srcdir) @CPPFLAGS@
|
||||
CXXFLAGS = -Wall @CXXFLAGS@
|
||||
@@ -65,7 +65,7 @@ all: dep version.h ivl@EXEEXT@
|
||||
|
||||
# In the windows world, the installer will need a dosify program to
|
||||
# dosify text files.
|
||||
ifeq (@MING32@,yes)
|
||||
ifeq (@MINGW32@,yes)
|
||||
all: dep dosify.exe
|
||||
dosify.exe: dosify.c
|
||||
$(CC) -o dosify.exe dosify.c
|
||||
@@ -99,15 +99,15 @@ distclean: clean
|
||||
TT = t-dll.o t-dll-api.o t-dll-expr.o t-dll-proc.o
|
||||
FF = cprop.o nodangle.o synth.o synth2.o syn-rules.o
|
||||
|
||||
O = main.o async.o design_dump.o dup_expr.o elaborate.o elab_expr.o \
|
||||
O = main.o async.o design_dump.o discipline.o dup_expr.o elaborate.o elab_expr.o \
|
||||
elab_lval.o elab_net.o elab_pexpr.o elab_scope.o \
|
||||
elab_sig.o emit.o eval.o eval_attrib.o \
|
||||
eval_tree.o expr_synth.o functor.o lexor.o lexor_keyword.o link_const.o \
|
||||
load_module.o netlist.o netmisc.o net_assign.o \
|
||||
net_design.o net_event.o net_expr.o net_force.o net_func.o \
|
||||
net_link.o net_modulo.o net_nex_input.o net_nex_output.o \
|
||||
net_proc.o net_scope.o net_udp.o pad_to_width.o \
|
||||
parse.o parse_misc.o pform.o pform_dump.o pform_types.o \
|
||||
net_proc.o net_scope.o net_tran.o net_udp.o pad_to_width.o \
|
||||
parse.o parse_misc.o pform.o pform_disciplines.o pform_dump.o pform_types.o \
|
||||
set_width.o symbol_search.o sync.o sys_funcs.o \
|
||||
verinum.o verireal.o target.o targets.o \
|
||||
Attrib.o HName.o LineInfo.o Module.o PDelays.o PEvent.o \
|
||||
@@ -174,22 +174,28 @@ lexor.cc: $(srcdir)/lexor.lex
|
||||
lexor_keyword.o: lexor_keyword.cc parse.h
|
||||
|
||||
lexor_keyword.cc: lexor_keyword.gperf
|
||||
gperf -o -i 7 -C -k 1-3,$$ -L ANSI-C -H keyword_hash -N check_identifier -t $(srcdir)/lexor_keyword.gperf > lexor_keyword.cc || (rm -f lexor_keyword.cc ; false)
|
||||
gperf -o -i 7 -C -k 1-4,$$ -L ANSI-C -H keyword_hash -N check_identifier -t $(srcdir)/lexor_keyword.gperf > lexor_keyword.cc || (rm -f lexor_keyword.cc ; false)
|
||||
|
||||
iverilog-vpi.ps: $(srcdir)/iverilog-vpi.man
|
||||
man -t $(srcdir)/iverilog-vpi.man > iverilog-vpi.ps
|
||||
$(MAN) -t $(srcdir)/iverilog-vpi.man > iverilog-vpi.ps
|
||||
|
||||
iverilog-vpi.pdf: iverilog-vpi.ps
|
||||
ps2pdf iverilog-vpi.ps iverilog-vpi.pdf
|
||||
$(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
|
||||
# "true" and "false" in the next few lines are Unix shell command names
|
||||
ifeq ($(GIT),none)
|
||||
GIT_PRESENT = false
|
||||
else
|
||||
GIT_PRESENT = true
|
||||
endif
|
||||
version.h:
|
||||
@if test -d $(srcdir)/.git; then \
|
||||
@if $(GIT_PRESENT) && test -d $(srcdir)/.git; then \
|
||||
echo "Using git-describe for VERSION_TAG"; \
|
||||
tmp=`git --git-dir $(srcdir)/.git describe \
|
||||
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 \
|
||||
@@ -200,10 +206,18 @@ version.h:
|
||||
echo '#define VERSION_TAG ""' > $@; \
|
||||
fi
|
||||
|
||||
ifeq (@MING32@,yes)
|
||||
ifeq (@MINGW32@,yes)
|
||||
ifeq ($(MAN),none)
|
||||
INSTALL_DOC = $(mandir)/man1/iverilog-vpi.1
|
||||
else
|
||||
ifeq ($(PS2PDF),none)
|
||||
INSTALL_DOC = $(mandir)/man1/iverilog-vpi.1
|
||||
else
|
||||
INSTALL_DOC = $(prefix)/iverilog-vpi.pdf $(mandir)/man1/iverilog-vpi.1
|
||||
INSTALL_DOCDIR = $(mandir)/man1
|
||||
all: dep iverilog-vpi.pdf
|
||||
endif
|
||||
endif
|
||||
INSTALL_DOCDIR = $(mandir)/man1
|
||||
else
|
||||
INSTALL_DOC = $(mandir)/man1/iverilog-vpi.1
|
||||
INSTALL_DOCDIR = $(mandir)/man1
|
||||
@@ -217,43 +231,49 @@ 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 $(libdir)/ivl/include/disciplines.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/include/disciplines.vams: $(srcdir)/disciplines.vams
|
||||
$(INSTALL_DATA) $(srcdir)/disciplines.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.
|
||||
@@ -276,22 +296,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 include/disciplines.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)
|
||||
|
||||
@@ -75,14 +75,35 @@ class Module : public PScope, public LineInfo {
|
||||
|
||||
NetNet::Type default_nettype;
|
||||
|
||||
struct range_t {
|
||||
// True if this is an exclude
|
||||
bool exclude_flag;
|
||||
// lower bound
|
||||
// If low_open_flag is false and low_expr=0, then use -inf
|
||||
bool low_open_flag;
|
||||
PExpr*low_expr;
|
||||
// upper bound
|
||||
// If high_open_flag is false and high_expr=0, then use +inf
|
||||
bool high_open_flag;
|
||||
PExpr*high_expr;
|
||||
// Next range description in list
|
||||
struct range_t*next;
|
||||
};
|
||||
|
||||
/* The module has parameters that are evaluated when the
|
||||
module is elaborated. During parsing, I put the parameters
|
||||
into this map. */
|
||||
struct param_expr_t {
|
||||
PExpr*expr;
|
||||
struct param_expr_t : public LineInfo {
|
||||
param_expr_t() : type(IVL_VT_NO_TYPE), msb(0), lsb(0), signed_flag(false), expr(0), range(0) { }
|
||||
// Type information
|
||||
ivl_variable_type_t type;
|
||||
PExpr*msb;
|
||||
PExpr*lsb;
|
||||
bool signed_flag;
|
||||
// Value expression
|
||||
PExpr*expr;
|
||||
// If there are range constrants, list them here
|
||||
range_t*range;
|
||||
};
|
||||
map<perm_string,param_expr_t>parameters;
|
||||
map<perm_string,param_expr_t>localparams;
|
||||
@@ -119,7 +140,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. */
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -306,6 +306,11 @@ class PEIdent : public PExpr {
|
||||
private:
|
||||
// Common functions to calculate parts of part/bit selects.
|
||||
bool calculate_parts_(Design*, NetScope*, long&msb, long&lsb) const;
|
||||
NetExpr* calculate_up_do_base_(Design*, NetScope*) const;
|
||||
bool calculate_param_range_(Design*, NetScope*,
|
||||
const NetExpr*msb_ex, long&msb,
|
||||
const NetExpr*lsb_ex, long&lsb) const;
|
||||
|
||||
bool calculate_up_do_width_(Design*, NetScope*, unsigned long&wid) const;
|
||||
|
||||
private:
|
||||
@@ -321,6 +326,18 @@ class PEIdent : public PExpr {
|
||||
NetScope*found,
|
||||
const NetExpr*par_msb,
|
||||
const NetExpr*par_lsb) const;
|
||||
NetExpr*elaborate_expr_param_part_(Design*des,
|
||||
NetScope*scope,
|
||||
const NetExpr*par,
|
||||
NetScope*found,
|
||||
const NetExpr*par_msb,
|
||||
const NetExpr*par_lsb) const;
|
||||
NetExpr*elaborate_expr_param_idx_up_(Design*des,
|
||||
NetScope*scope,
|
||||
const NetExpr*par,
|
||||
NetScope*found,
|
||||
const NetExpr*par_msb,
|
||||
const NetExpr*par_lsb) const;
|
||||
NetExpr*elaborate_expr_net(Design*des,
|
||||
NetScope*scope,
|
||||
NetNet*net,
|
||||
@@ -387,7 +404,7 @@ class PEIdent : public PExpr {
|
||||
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;
|
||||
|
||||
};
|
||||
|
||||
@@ -30,7 +30,7 @@ PWire::PWire(perm_string n,
|
||||
signed_(false), isint_(false),
|
||||
port_msb_(0), port_lsb_(0), port_set_(false),
|
||||
net_msb_(0), net_lsb_(0), net_set_(false), error_cnt_(0),
|
||||
lidx_(0), ridx_(0)
|
||||
lidx_(0), ridx_(0), discipline_(0)
|
||||
{
|
||||
if (t == NetNet::INTEGER) {
|
||||
type_ = NetNet::REG;
|
||||
@@ -135,19 +135,6 @@ bool PWire::get_isint() const
|
||||
return isint_;
|
||||
}
|
||||
|
||||
/*
|
||||
* Since implicitly defined list of port declarations are no longer
|
||||
* considered fully defined we no longer need this routine to force
|
||||
* them to be fully defined.
|
||||
*
|
||||
void PWire::set_net_range()
|
||||
{
|
||||
net_msb_ = port_msb_;
|
||||
net_lsb_ = port_lsb_;
|
||||
net_set_ = true;
|
||||
}
|
||||
*/
|
||||
|
||||
void PWire::set_range(PExpr*m, PExpr*l, PWSRType type)
|
||||
{
|
||||
switch (type) {
|
||||
@@ -211,3 +198,13 @@ void PWire::set_memory_idx(PExpr*ldx, PExpr*rdx)
|
||||
}
|
||||
}
|
||||
|
||||
void PWire::set_discipline(discipline_t*d)
|
||||
{
|
||||
assert(discipline_ == 0);
|
||||
discipline_ = d;
|
||||
}
|
||||
|
||||
discipline_t* PWire::get_discipline(void) const
|
||||
{
|
||||
return discipline_;
|
||||
}
|
||||
|
||||
@@ -36,6 +36,7 @@ class ostream;
|
||||
|
||||
class PExpr;
|
||||
class Design;
|
||||
class discipline_t;
|
||||
|
||||
/*
|
||||
* The different type of PWire::set_range() calls.
|
||||
@@ -78,10 +79,12 @@ class PWire : public LineInfo {
|
||||
ivl_variable_type_t get_data_type() const;
|
||||
|
||||
void set_range(PExpr*msb, PExpr*lsb, PWSRType type);
|
||||
void set_net_range();
|
||||
|
||||
void set_memory_idx(PExpr*ldx, PExpr*rdx);
|
||||
|
||||
void set_discipline(discipline_t*);
|
||||
discipline_t* get_discipline(void) const;
|
||||
|
||||
map<perm_string,PExpr*> attributes;
|
||||
|
||||
// Write myself to the specified stream.
|
||||
@@ -112,6 +115,8 @@ class PWire : public LineInfo {
|
||||
PExpr*lidx_;
|
||||
PExpr*ridx_;
|
||||
|
||||
discipline_t*discipline_;
|
||||
|
||||
private: // not implemented
|
||||
PWire(const PWire&);
|
||||
PWire& operator= (const PWire&);
|
||||
|
||||
+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
|
||||
|
||||
+1
-1
@@ -16,4 +16,4 @@ do
|
||||
done
|
||||
|
||||
echo "Precompiling lexor_keyword.gperf"
|
||||
gperf -o -i 7 -C -k 1-3,\$ -L ANSI-C -H keyword_hash -N check_identifier -t ./lexor_keyword.gperf > lexor_keyword.cc
|
||||
gperf -o -i 7 -C -k 1-4,\$ -L ANSI-C -H keyword_hash -N check_identifier -t ./lexor_keyword.gperf > lexor_keyword.cc
|
||||
|
||||
+2
-5
@@ -16,12 +16,9 @@
|
||||
# 59 Temple Place - Suite 330
|
||||
# Boston, MA 02111-1307, USA
|
||||
#
|
||||
#ident "$Id: Makefile.in,v 1.13 2007/02/06 05:07:31 steve Exp $"
|
||||
#
|
||||
#
|
||||
SHELL = /bin/sh
|
||||
|
||||
VERSION = 0.0
|
||||
VERSION = 0.9.devel
|
||||
|
||||
prefix = @prefix@
|
||||
exec_prefix = @exec_prefix@
|
||||
@@ -63,7 +60,7 @@ dep:
|
||||
O = cadpli.o
|
||||
|
||||
SYSTEM_VPI_LDFLAGS = -L../vvp -lvpi
|
||||
ifeq (@MING32@,yes)
|
||||
ifeq (@MINGW32@,yes)
|
||||
SYSTEM_VPI_LDFLAGS += @EXTRALIBS@
|
||||
endif
|
||||
|
||||
|
||||
+21
-4
@@ -86,6 +86,7 @@ extern bool debug_scopes;
|
||||
extern bool debug_eval_tree;
|
||||
extern bool debug_elaborate;
|
||||
extern bool debug_synth2;
|
||||
extern bool debug_optimizer;
|
||||
|
||||
/* Path to a directory useful for finding subcomponents. */
|
||||
extern const char*basedir;
|
||||
@@ -100,26 +101,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;
|
||||
|
||||
|
||||
@@ -9,6 +9,9 @@ AC_PROG_CC
|
||||
AC_PROG_CXX
|
||||
AC_CHECK_TOOL(STRIP, strip, true)
|
||||
AC_CHECK_PROGS(XGPERF,gperf,none)
|
||||
AC_CHECK_PROGS(MAN,man,none)
|
||||
AC_CHECK_PROGS(PS2PDF,ps2pdf,none)
|
||||
AC_CHECK_PROGS(GIT,git,none)
|
||||
if test "$XGPERF" = "none"
|
||||
then
|
||||
echo ""
|
||||
|
||||
@@ -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
|
||||
@@ -23,6 +23,7 @@
|
||||
# include "netlist.h"
|
||||
# include "netmisc.h"
|
||||
# include "functor.h"
|
||||
# include "compiler.h"
|
||||
# include "ivl_assert.h"
|
||||
|
||||
|
||||
@@ -828,6 +829,32 @@ void cprop_functor::lpm_mux(Design*des, NetMux*obj)
|
||||
count += 1;
|
||||
return;
|
||||
}
|
||||
|
||||
/* If the select input is constant, then replace with a BUFZ */
|
||||
flag = obj->pin_Sel().nexus()->drivers_constant();
|
||||
verinum::V sel_val = flag? obj->pin_Sel().nexus()->driven_value() : verinum::Vx;
|
||||
if ((sel_val != verinum::Vz) && (sel_val != verinum::Vx)) {
|
||||
NetBUFZ*tmp = new NetBUFZ(obj->scope(), obj->name(), obj->width());
|
||||
tmp->set_line(*obj);
|
||||
|
||||
if (debug_optimizer)
|
||||
cerr << obj->get_fileline() << ": debug: "
|
||||
<< "Replace binary MUX with constant select=" << sel_val
|
||||
<< " with a BUFZ to the selected input." << endl;
|
||||
|
||||
tmp->rise_time(obj->rise_time());
|
||||
tmp->fall_time(obj->fall_time());
|
||||
tmp->decay_time(obj->decay_time());
|
||||
|
||||
connect(tmp->pin(0), obj->pin_Result());
|
||||
if (sel_val == verinum::V1)
|
||||
connect(tmp->pin(1), obj->pin_Data(1));
|
||||
else
|
||||
connect(tmp->pin(1), obj->pin_Data(0));
|
||||
delete obj;
|
||||
des->add_node(tmp);
|
||||
count += 1;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
+103
-10
@@ -88,6 +88,34 @@ ostream& operator << (ostream&o, ivl_variable_type_t val)
|
||||
return o;
|
||||
}
|
||||
|
||||
ostream& operator << (ostream&o, ivl_switch_type_t val)
|
||||
{
|
||||
switch (val) {
|
||||
case IVL_SW_TRAN:
|
||||
o << "tran";
|
||||
break;
|
||||
case IVL_SW_TRANIF0:
|
||||
o << "tranif0";
|
||||
break;
|
||||
case IVL_SW_TRANIF1:
|
||||
o << "tranif1";
|
||||
break;
|
||||
case IVL_SW_RTRAN:
|
||||
o << "rtran";
|
||||
break;
|
||||
case IVL_SW_RTRANIF0:
|
||||
o << "rtranif0";
|
||||
break;
|
||||
case IVL_SW_RTRANIF1:
|
||||
o << "rtranif1";
|
||||
break;
|
||||
case IVL_SW_TRAN_VP:
|
||||
o << "tran(VP)";
|
||||
break;
|
||||
}
|
||||
return o;
|
||||
}
|
||||
|
||||
static inline void dump_scope_path(ostream&o, const NetScope*scope)
|
||||
{
|
||||
if (const NetScope*parent = scope->parent()) {
|
||||
@@ -112,9 +140,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 (is_condit()) {
|
||||
if (has_condit()) o << " if";
|
||||
else o << " ifnone";
|
||||
}
|
||||
o << " src "
|
||||
<< "(" << transition_delays_[IVL_PE_01]
|
||||
<< "," << transition_delays_[IVL_PE_10]
|
||||
@@ -246,6 +275,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()
|
||||
@@ -483,9 +521,6 @@ void NetPartSelect::dump_node(ostream&o, unsigned ind) const
|
||||
case PV:
|
||||
pt = "PV";
|
||||
break;
|
||||
case BI:
|
||||
pt = "BI";
|
||||
break;
|
||||
}
|
||||
o << setw(ind) << "" << "NetPartSelect(" << pt << "): "
|
||||
<< name();
|
||||
@@ -601,6 +636,20 @@ void NetTaskDef::dump(ostream&o, unsigned ind) const
|
||||
o << setw(ind) << "" << "endtask" << endl;
|
||||
}
|
||||
|
||||
void NetTran::dump_node(ostream&o, unsigned ind) const
|
||||
{
|
||||
o << setw(ind) << "" << type_ << " " << name()
|
||||
<< " island " << island;
|
||||
if (type_ == IVL_SW_TRAN_VP) {
|
||||
o << " width=" << vector_width()
|
||||
<< " part=" << part_width()
|
||||
<< " offset=" << part_offset();
|
||||
}
|
||||
o << endl;
|
||||
dump_node_pins(o, ind+4);
|
||||
dump_obj_attr(o, ind+4);
|
||||
}
|
||||
|
||||
void NetUDP::dump_node(ostream&o, unsigned ind) const
|
||||
{
|
||||
o << setw(ind) << "" << "UDP (" << udp_name() << "): ";
|
||||
@@ -956,8 +1005,37 @@ void NetScope::dump(ostream&o) const
|
||||
o << "[" << *(*pp).second.msb
|
||||
<< ":" << *(*pp).second.lsb << "] ";
|
||||
|
||||
o << (*pp).first << " = " <<
|
||||
*(*pp).second.expr << ";" << endl;
|
||||
o << (*pp).first << " = " << *(*pp).second.expr;
|
||||
|
||||
for (range_t*ran = (*pp).second.range ; ran ; ran = ran->next) {
|
||||
if (ran->exclude_flag)
|
||||
o << " exclude ";
|
||||
else
|
||||
o << " from ";
|
||||
|
||||
if (ran->low_open_flag)
|
||||
o << "(";
|
||||
else
|
||||
o << "[";
|
||||
if (ran->low_expr)
|
||||
o << *ran->low_expr;
|
||||
else if (ran->low_open_flag==false)
|
||||
o << "-inf";
|
||||
else
|
||||
o << "<?>";
|
||||
if (ran->high_expr)
|
||||
o << ":" << *ran->high_expr;
|
||||
else if (ran->high_open_flag==false)
|
||||
o << ":inf";
|
||||
else
|
||||
o << ":<?>";
|
||||
if (ran->high_open_flag)
|
||||
o << ")";
|
||||
else
|
||||
o << "]";
|
||||
}
|
||||
|
||||
o << ";" << endl;
|
||||
}
|
||||
|
||||
for (pp = localparams.begin()
|
||||
@@ -1081,6 +1159,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,11 +1329,9 @@ void NetESignal::dump(ostream&o) const
|
||||
void NetEParam::dump(ostream&o) const
|
||||
{
|
||||
if (scope_ != 0)
|
||||
o << "<" << scope_path(scope_) << "." << name_ << ">";
|
||||
else if (name_)
|
||||
o << "<" << name_ << ">";
|
||||
o << "<" << scope_path(scope_) << "." << (*reference_).first << ">";
|
||||
else
|
||||
o << "<" "???" ">";
|
||||
o << "<" << (*reference_).first << ">";
|
||||
}
|
||||
|
||||
void NetETernary::dump(ostream&o) const
|
||||
@@ -1266,6 +1356,9 @@ void NetEUFunc::dump(ostream&o) const
|
||||
void NetEUnary::dump(ostream&o) const
|
||||
{
|
||||
switch (op_) {
|
||||
case 'm':
|
||||
o << "abs";
|
||||
break;
|
||||
case 'N':
|
||||
o << "~|";
|
||||
break;
|
||||
|
||||
@@ -0,0 +1,39 @@
|
||||
/*
|
||||
* Copyright (c) 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
|
||||
* 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
|
||||
*/
|
||||
|
||||
# include "discipline.h"
|
||||
|
||||
nature_t::nature_t(perm_string name, perm_string access)
|
||||
: name_(name), access_(access)
|
||||
{
|
||||
}
|
||||
|
||||
nature_t::~nature_t()
|
||||
{
|
||||
}
|
||||
|
||||
discipline_t::discipline_t(perm_string name, ddomain_t domain,
|
||||
nature_t*pot, nature_t*flow)
|
||||
: name_(name), domain_(domain), potential_(pot), flow_(flow)
|
||||
{
|
||||
}
|
||||
|
||||
discipline_t::~discipline_t()
|
||||
{
|
||||
}
|
||||
@@ -0,0 +1,75 @@
|
||||
#ifndef __discipline_H
|
||||
#define __discipline_H
|
||||
/*
|
||||
* Copyright (c) 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
|
||||
* 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
|
||||
*/
|
||||
|
||||
/*
|
||||
* The discipline types include the discipline, nature and other
|
||||
* related types for managing declared and used disciplines in a
|
||||
* Verilog-AMS program.
|
||||
*/
|
||||
|
||||
# include "StringHeap.h"
|
||||
# include <iostream>
|
||||
# include <map>
|
||||
# include "LineInfo.h"
|
||||
|
||||
typedef enum { DD_NONE, DD_DISCRETE, DD_CONTINUOUS } ddomain_t;
|
||||
extern std::ostream& operator << (std::ostream&, ddomain_t);
|
||||
|
||||
class nature_t : public LineInfo {
|
||||
public:
|
||||
explicit nature_t(perm_string name, perm_string access);
|
||||
~nature_t();
|
||||
|
||||
perm_string name() const { return name_; }
|
||||
// Identifier for the access function for this nature
|
||||
perm_string access() const { return access_; }
|
||||
|
||||
private:
|
||||
perm_string name_;
|
||||
perm_string access_;
|
||||
};
|
||||
|
||||
class discipline_t : public LineInfo {
|
||||
public:
|
||||
explicit discipline_t (perm_string name, ddomain_t dom,
|
||||
nature_t*pot, nature_t*flow);
|
||||
~discipline_t();
|
||||
|
||||
perm_string name() const { return name_; }
|
||||
ddomain_t domain() const { return domain_; }
|
||||
const nature_t*potential() const { return potential_; }
|
||||
const nature_t*flow() const { return flow_; }
|
||||
|
||||
private:
|
||||
perm_string name_;
|
||||
ddomain_t domain_;
|
||||
nature_t*potential_;
|
||||
nature_t*flow_;
|
||||
|
||||
private: // not implemented
|
||||
discipline_t(const discipline_t&);
|
||||
discipline_t& operator = (const discipline_t&);
|
||||
};
|
||||
|
||||
extern map<perm_string,nature_t*> natures;
|
||||
extern map<perm_string,discipline_t*> disciplines;
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,72 @@
|
||||
|
||||
// Standard definitions for Verilog-AMS
|
||||
`ifdef DISCIPLINES_VAMS
|
||||
`else
|
||||
`define DISCIPLINES_VAMS 1
|
||||
|
||||
discipline \logic ;
|
||||
domain discrete;
|
||||
enddiscipline
|
||||
|
||||
discipline ddiscrete;
|
||||
domain discrete;
|
||||
enddiscipline
|
||||
|
||||
nature Current;
|
||||
units = "A";
|
||||
access = I;
|
||||
idt_nature = Charge;
|
||||
`ifdef CURRENT_ABSTOL
|
||||
abstol = `CURRENT_ABSTOL
|
||||
`else
|
||||
abstol = 1e-12;
|
||||
`endif
|
||||
endnature
|
||||
|
||||
nature Charge;
|
||||
units = "coul";
|
||||
access = Q;
|
||||
ddt_nature = Current;
|
||||
`ifdef CHARGE_ABSTOL
|
||||
abstol = `CHARGE_ABSTOL;
|
||||
`else
|
||||
abstol = 1e-14;
|
||||
`endif
|
||||
endnature
|
||||
|
||||
nature Voltage;
|
||||
units = "V";
|
||||
access = V;
|
||||
idt_nature = Flux;
|
||||
`ifdef VOLTAGE_ABSTOL
|
||||
abstol = `VOLTAGE_ABSTOL;
|
||||
`else
|
||||
abstol = 1e-6;
|
||||
`endif
|
||||
endnature
|
||||
|
||||
nature Flux;
|
||||
units = "Wb";
|
||||
access = Phi;
|
||||
ddt_nature = Voltage;
|
||||
`ifdef FLUX_ABSTOL
|
||||
abstol = `flux_ABSTOL;
|
||||
`else
|
||||
abstol = 1e-9;
|
||||
`endif
|
||||
endnature
|
||||
|
||||
discipline electrical;
|
||||
potential Voltage;
|
||||
flow Current;
|
||||
enddiscipline
|
||||
|
||||
discipline voltage;
|
||||
potential Voltage;
|
||||
enddiscipline
|
||||
|
||||
discipline current;
|
||||
flow Current;
|
||||
enddiscipline
|
||||
|
||||
`endif // !`ifdef DISCIPLINES_VAMS
|
||||
@@ -16,12 +16,9 @@
|
||||
# 59 Temple Place - Suite 330
|
||||
# Boston, MA 02111-1307, USA
|
||||
#
|
||||
#ident "$Id: Makefile.in,v 1.7.2.1 2006/10/04 17:08:59 steve Exp $"
|
||||
#
|
||||
#
|
||||
SHELL = /bin/sh
|
||||
|
||||
VERSION = 0.8.3
|
||||
VERSION = 0.9.devel
|
||||
|
||||
prefix = @prefix@
|
||||
exec_prefix = @exec_prefix@
|
||||
@@ -48,6 +45,8 @@ LDFLAGS = @LDFLAGS@
|
||||
|
||||
all: iverilog-vpi@EXEEXT@
|
||||
|
||||
check: all
|
||||
|
||||
clean:
|
||||
rm -f *.o config.h
|
||||
rm -f iverilog-vpi@EXEEXT@
|
||||
|
||||
+8
-8
@@ -336,6 +336,14 @@ static int parse(int argc, char *argv[])
|
||||
assignn(&gstr.pOUT, argv[idx],
|
||||
strlen(argv[idx])-strlen(dot_o_ext));
|
||||
}
|
||||
/* Check for the -mingw option */
|
||||
else if (startsWith(mingw_option, argv[idx]))
|
||||
assignn(&gstr.pMINGW, argv[idx]+sizeof(mingw_option)-1,
|
||||
strlen(argv[idx])-(sizeof(mingw_option)-1));
|
||||
/* Check for the -ivl option */
|
||||
else if (startsWith(ivl_option, argv[idx]))
|
||||
assignn(&gstr.pIVL, argv[idx]+sizeof(ivl_option)-1,
|
||||
strlen(argv[idx])-(sizeof(ivl_option)-1));
|
||||
/* Check for the --name option */
|
||||
else if (startsWith(name_option, argv[idx])) {
|
||||
assignn(&gstr.pOUT, argv[idx]+sizeof(name_option)-1,
|
||||
@@ -356,14 +364,6 @@ static int parse(int argc, char *argv[])
|
||||
append(&gstr.pDEFS, " ");
|
||||
append(&gstr.pDEFS, argv[idx]);
|
||||
}
|
||||
/* Check for the -mingw option */
|
||||
else if (startsWith(mingw_option, argv[idx]))
|
||||
assignn(&gstr.pMINGW, argv[idx]+sizeof(mingw_option)-1,
|
||||
strlen(argv[idx])-(sizeof(mingw_option)-1));
|
||||
/* Check for the -ivl option */
|
||||
else if (startsWith(ivl_option, argv[idx]))
|
||||
assignn(&gstr.pIVL, argv[idx]+sizeof(ivl_option)-1,
|
||||
strlen(argv[idx])-(sizeof(ivl_option)-1));
|
||||
/* Check for the --cflags option */
|
||||
else if (stricmp("--cflags", argv[idx]) == 0) {
|
||||
setup_ivl_environment();
|
||||
|
||||
+14
-7
@@ -16,9 +16,6 @@
|
||||
# 59 Temple Place - Suite 330
|
||||
# Boston, MA 02111-1307, USA
|
||||
#
|
||||
#ident "$Id: Makefile.in,v 1.26 2007/02/06 05:07:31 steve Exp $"
|
||||
#
|
||||
#
|
||||
SHELL = /bin/sh
|
||||
|
||||
VERSION = 0.9.devel
|
||||
@@ -41,6 +38,8 @@ CC = @CC@
|
||||
INSTALL = @INSTALL@
|
||||
INSTALL_PROGRAM = @INSTALL_PROGRAM@
|
||||
INSTALL_DATA = @INSTALL_DATA@
|
||||
MAN = @MAN@
|
||||
PS2PDF = @PS2PDF@
|
||||
|
||||
CPPFLAGS = @ident_support@ -I. -I.. -I$(srcdir)/.. -I$(srcdir) -DVERSION='"$(VERSION)"' @CPPFLAGS@ @DEFS@
|
||||
CFLAGS = -Wall @CFLAGS@
|
||||
@@ -76,15 +75,23 @@ cflexor.o: cflexor.c cfparse.h cfparse_misc.h globals.h
|
||||
cfparse.o: cfparse.c globals.h cfparse_misc.h
|
||||
|
||||
iverilog.ps: $(srcdir)/iverilog.man
|
||||
man -t $(srcdir)/iverilog.man > iverilog.ps
|
||||
$(MAN) -t $(srcdir)/iverilog.man > iverilog.ps
|
||||
|
||||
iverilog.pdf: iverilog.ps
|
||||
ps2pdf iverilog.ps iverilog.pdf
|
||||
$(PS2PDF) iverilog.ps iverilog.pdf
|
||||
|
||||
ifeq (@MING32@,yes)
|
||||
ifeq (@MINGW32@,yes)
|
||||
ifeq ($(MAN),none)
|
||||
INSTALL_DOC = $(mandir)/man1/iverilog.1
|
||||
else
|
||||
ifeq ($(PS2PDF),none)
|
||||
INSTALL_DOC = $(mandir)/man1/iverilog.1
|
||||
else
|
||||
INSTALL_DOC = $(prefix)/iverilog.pdf $(mandir)/man1/iverilog.1
|
||||
INSTALL_DOCDIR = $(mandir)/man1
|
||||
all: iverilog.pdf
|
||||
endif
|
||||
endif
|
||||
INSTALL_DOCDIR = $(mandir)/man1
|
||||
else
|
||||
INSTALL_DOC = $(mandir)/man1/iverilog.1
|
||||
INSTALL_DOCDIR = $(mandir)/man1
|
||||
|
||||
+13
-5
@@ -5,7 +5,7 @@ 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
|
||||
@@ -384,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
|
||||
|
||||
+56
-10
@@ -109,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;
|
||||
@@ -325,6 +327,9 @@ static int t_default(char*cmd, unsigned ncmd)
|
||||
remove(defines_path);
|
||||
remove(compiled_defines_path);
|
||||
}
|
||||
#ifdef __MINGW32__ /* MinGW just returns the exit status, so return it! */
|
||||
return rc;
|
||||
#else
|
||||
|
||||
if (rc != 0) {
|
||||
if (rc == 127) {
|
||||
@@ -340,6 +345,7 @@ static int t_default(char*cmd, unsigned ncmd)
|
||||
}
|
||||
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
@@ -430,21 +436,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";
|
||||
|
||||
@@ -463,17 +490,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;
|
||||
}
|
||||
@@ -563,6 +598,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. */
|
||||
@@ -727,11 +764,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);
|
||||
|
||||
+296
-111
@@ -187,7 +187,7 @@ NetExpr* 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 "
|
||||
@@ -311,6 +311,12 @@ NetExpr* 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;
|
||||
@@ -680,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) {
|
||||
@@ -707,11 +716,29 @@ NetExpr* PEConcat::elaborate_expr(Design*des, NetScope*scope,
|
||||
des->errors += 1;
|
||||
}
|
||||
|
||||
if (!rep->value().is_defined()) {
|
||||
cerr << get_fileline() << ": error: Concatenation repeat "
|
||||
<< "may not be undefined (" << rep->value()
|
||||
<< ")." << endl;
|
||||
des->errors += 1;
|
||||
concat_depth -= 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
@@ -752,6 +779,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;
|
||||
}
|
||||
|
||||
@@ -846,6 +882,51 @@ bool PEIdent::calculate_up_do_width_(Design*des, NetScope*scope,
|
||||
return flag;
|
||||
}
|
||||
|
||||
/*
|
||||
* When we know that this is an indexed part select (up or down) this
|
||||
* method calculates the up/down base, as far at it can be calculated.
|
||||
*/
|
||||
NetExpr* PEIdent::calculate_up_do_base_(Design*des, NetScope*scope) const
|
||||
{
|
||||
const name_component_t&name_tail = path_.back();
|
||||
ivl_assert(*this, !name_tail.index.empty());
|
||||
|
||||
const index_component_t&index_tail = name_tail.index.back();
|
||||
ivl_assert(*this, index_tail.lsb != 0);
|
||||
ivl_assert(*this, index_tail.msb != 0);
|
||||
|
||||
NetExpr*tmp = elab_and_eval(des, scope, index_tail.msb, -1);
|
||||
return tmp;
|
||||
}
|
||||
|
||||
bool PEIdent::calculate_param_range_(Design*des, NetScope*scope,
|
||||
const NetExpr*par_msb, long&par_msv,
|
||||
const NetExpr*par_lsb, long&par_lsv) const
|
||||
{
|
||||
if (par_msb == 0) {
|
||||
// If the parameter doesn't have an explicit range, then
|
||||
// just return range values of 0:0. The par_msv==0 is
|
||||
// correct. The par_msv is not necessarily correct, but
|
||||
// clients of this function don't need a correct value.
|
||||
ivl_assert(*this, par_lsb == 0);
|
||||
par_msv = 0;
|
||||
par_lsv = 0;
|
||||
return true;
|
||||
}
|
||||
|
||||
const NetEConst*tmp = dynamic_cast<const NetEConst*> (par_msb);
|
||||
ivl_assert(*this, tmp);
|
||||
|
||||
par_msv = tmp->value().as_long();
|
||||
|
||||
tmp = dynamic_cast<const NetEConst*> (par_lsb);
|
||||
ivl_assert(*this, tmp);
|
||||
|
||||
par_lsv = tmp->value().as_long();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
unsigned PEIdent::test_width(Design*des, NetScope*scope,
|
||||
unsigned min, unsigned lval,
|
||||
bool&unsized_flag) const
|
||||
@@ -1058,6 +1139,131 @@ NetExpr* PEIdent::elaborate_expr(Design*des, NetScope*scope,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static verinum param_part_select_bits(const verinum&par_val, long wid,
|
||||
long lsv, long par_lsv)
|
||||
{
|
||||
verinum result (verinum::Vx, wid, true);
|
||||
|
||||
for (long idx = 0 ; idx < wid ; idx += 1) {
|
||||
long off = idx + lsv - par_lsv;
|
||||
if (off < 0)
|
||||
result.set(idx, verinum::Vx);
|
||||
else if (off < (long)par_val.len())
|
||||
result.set(idx, par_val.get(off));
|
||||
else if (par_val.is_string()) // Pad strings with nulls.
|
||||
result.set(idx, verinum::V0);
|
||||
else if (par_val.has_len()) // Pad sized parameters with X
|
||||
result.set(idx, verinum::Vx);
|
||||
else // Unsized parameters are "infinite" width.
|
||||
result.set(idx, sign_bit(par_val));
|
||||
}
|
||||
|
||||
// If the input is a string, and the part select is working on
|
||||
// byte boundaries, then make the result into a string.
|
||||
if (par_val.is_string() && (labs(lsv-par_lsv)%8 == 0) && (wid%8 == 0))
|
||||
return result.as_string();
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
NetExpr* PEIdent::elaborate_expr_param_part_(Design*des, NetScope*scope,
|
||||
const NetExpr*par,
|
||||
NetScope*found_in,
|
||||
const NetExpr*par_msb,
|
||||
const NetExpr*par_lsb) const
|
||||
{
|
||||
long msv, lsv;
|
||||
bool flag = calculate_parts_(des, scope, msv, lsv);
|
||||
if (!flag)
|
||||
return 0;
|
||||
|
||||
long par_msv, par_lsv;
|
||||
flag = calculate_param_range_(des, scope, par_msb, par_msv, par_lsb, par_lsv);
|
||||
if (!flag)
|
||||
return 0;
|
||||
|
||||
// Notice that the par_msv is not used is this function other
|
||||
// then for this test. It is used to tell the direction that
|
||||
// the bits are numbers, so that we can make sure the
|
||||
// direction matches the part select direction. After that,
|
||||
// we only need the par_lsv.
|
||||
if (msv>lsv && par_msv<par_lsv || msv<lsv && par_msv>=par_lsv) {
|
||||
cerr << get_fileline() << ": error: Part select "
|
||||
<< "[" << msv << ":" << lsv << "] is out of order." << endl;
|
||||
des->errors += 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
long wid = 1 + labs(msv-lsv);
|
||||
|
||||
if (debug_elaborate)
|
||||
cerr << get_fileline() << ": debug: Calculate part select "
|
||||
<< "[" << msv << ":" << lsv << "] from range "
|
||||
<< "[" << par_msv << ":" << par_lsv << "]." << endl;
|
||||
|
||||
const NetEConst*par_ex = dynamic_cast<const NetEConst*> (par);
|
||||
ivl_assert(*this, par_ex);
|
||||
|
||||
verinum result = param_part_select_bits(par_ex->value(), wid, lsv, par_lsv);
|
||||
NetEConst*result_ex = new NetEConst(result);
|
||||
result_ex->set_line(*this);
|
||||
|
||||
return result_ex;
|
||||
}
|
||||
|
||||
NetExpr* PEIdent::elaborate_expr_param_idx_up_(Design*des, NetScope*scope,
|
||||
const NetExpr*par,
|
||||
NetScope*found_in,
|
||||
const NetExpr*par_msb,
|
||||
const NetExpr*par_lsb) const
|
||||
{
|
||||
|
||||
long par_msv, par_lsv;
|
||||
bool flag = calculate_param_range_(des, scope, par_msb, par_msv, par_lsb, par_lsv);
|
||||
if (!flag)
|
||||
return 0;
|
||||
|
||||
NetExpr*base = calculate_up_do_base_(des, scope);
|
||||
if (base == 0)
|
||||
return 0;
|
||||
|
||||
unsigned long wid = 0;
|
||||
calculate_up_do_width_(des, scope, wid);
|
||||
|
||||
const NetEConst*par_ex = dynamic_cast<const NetEConst*> (par);
|
||||
ivl_assert(*this, par_ex);
|
||||
|
||||
if (debug_elaborate)
|
||||
cerr << get_fileline() << ": debug: Calculate part select "
|
||||
<< "[" << *base << "+:" << wid << "] from range "
|
||||
<< "[" << par_msv << ":" << par_lsv << "]." << endl;
|
||||
|
||||
// Handle the special case that the base is constant. In this
|
||||
// case, just precalculate the entire constant result.
|
||||
if (NetEConst*base_c = dynamic_cast<NetEConst*> (base)) {
|
||||
long lsv = base_c->value().as_long();
|
||||
|
||||
// Watch out for reversed bit numbering. We're making
|
||||
// the part select from LSB to MSB.
|
||||
if (par_msv < par_lsv)
|
||||
lsv = lsv - wid + 1;
|
||||
|
||||
verinum result = param_part_select_bits(par_ex->value(), wid,
|
||||
lsv, par_lsv);
|
||||
NetEConst*result_ex = new NetEConst(result);
|
||||
result_ex->set_line(*this);
|
||||
return result_ex;
|
||||
}
|
||||
|
||||
if ((par_msb < par_lsb) && (wid>1))
|
||||
base = make_add_expr(base, 1-(long)wid);
|
||||
|
||||
NetExpr*tmp = par->dup_expr();
|
||||
tmp = new NetESelect(tmp, base, wid);
|
||||
tmp->set_line(*this);
|
||||
return tmp;
|
||||
}
|
||||
|
||||
/*
|
||||
* Handle the case that the identifier is a parameter reference. The
|
||||
* parameter expression has already been located for us (as the par
|
||||
@@ -1070,84 +1276,29 @@ NetExpr* PEIdent::elaborate_expr_param(Design*des,
|
||||
const NetExpr*par_msb,
|
||||
const NetExpr*par_lsb) const
|
||||
{
|
||||
NetExpr*tmp = par->dup_expr();
|
||||
|
||||
const name_component_t&name_tail = path_.back();
|
||||
index_component_t::ctype_t use_sel = index_component_t::SEL_NONE;
|
||||
if (!name_tail.index.empty())
|
||||
use_sel = name_tail.index.back().sel;
|
||||
|
||||
if (use_sel == index_component_t::SEL_PART) {
|
||||
ivl_assert(*this, !name_tail.index.empty());
|
||||
const index_component_t&index_tail = name_tail.index.back();
|
||||
ivl_assert(*this, index_tail.msb);
|
||||
ivl_assert(*this, index_tail.lsb);
|
||||
// NOTE TO SELF: This is the way I want to see this code
|
||||
// structured. This closely follows the structure of the
|
||||
// elaborate_expr_net_ code, which splits all the various
|
||||
// selects to different methods.
|
||||
if (use_sel == index_component_t::SEL_PART)
|
||||
return elaborate_expr_param_part_(des, scope, par, found_in,
|
||||
par_msb, par_lsb);
|
||||
|
||||
/* If the identifier has a part select, we support
|
||||
it by pulling the right bits out and making a
|
||||
sized unsigned constant. This code assumes the
|
||||
lsb of a parameter is 0 and the msb is the
|
||||
width of the parameter. */
|
||||
if (use_sel == index_component_t::SEL_IDX_UP)
|
||||
return elaborate_expr_param_idx_up_(des, scope, par, found_in,
|
||||
par_msb, par_lsb);
|
||||
|
||||
verinum*lsn = index_tail.lsb->eval_const(des, scope);
|
||||
verinum*msn = index_tail.msb->eval_const(des, scope);
|
||||
if ((lsn == 0) || (msn == 0)) {
|
||||
cerr << get_fileline() << ": error: "
|
||||
"Part select expressions must be "
|
||||
"constant expressions." << endl;
|
||||
des->errors += 1;
|
||||
return 0;
|
||||
}
|
||||
// NOTE TO SELF (continued): The code below should be
|
||||
// rewritten in the above format, as I get to it.
|
||||
|
||||
long lsb = lsn->as_long();
|
||||
long msb = msn->as_long();
|
||||
if ((lsb < 0) || (msb < lsb)) {
|
||||
cerr << get_fileline() << ": error: invalid part "
|
||||
<< "select: " << path_
|
||||
<< "["<<msb<<":"<<lsb<<"]" << endl;
|
||||
des->errors += 1;
|
||||
return 0;
|
||||
}
|
||||
unsigned long ulsb=lsb;
|
||||
unsigned long umsb=msb;
|
||||
NetExpr*tmp = par->dup_expr();
|
||||
|
||||
NetEConst*le = dynamic_cast<NetEConst*>(tmp);
|
||||
assert(le);
|
||||
|
||||
verinum result (verinum::V0, msb-lsb+1, true);
|
||||
verinum exl = le->value();
|
||||
|
||||
/* Pull the bits from the parameter, one at a
|
||||
time. If the bit is within the range, simply
|
||||
copy it to the result. If the bit is outside
|
||||
the range, we sign extend signed unsized
|
||||
numbers, zero extend unsigned unsigned numbers,
|
||||
and X extend sized numbers. */
|
||||
for (unsigned long idx = ulsb ; idx <= umsb ; idx += 1) {
|
||||
if (idx < exl.len())
|
||||
result.set(idx-lsb, exl.get(idx));
|
||||
else if (exl.is_string())
|
||||
result.set(idx-lsb, verinum::V0);
|
||||
else if (exl.has_len())
|
||||
result.set(idx-lsb, verinum::Vx);
|
||||
else if (exl.has_sign())
|
||||
result.set(idx-lsb, exl.get(exl.len()-1));
|
||||
else
|
||||
result.set(idx-lsb, verinum::V0);
|
||||
}
|
||||
|
||||
/* If the input is a string, and the part select
|
||||
is working on byte boundaries, then the result
|
||||
can be made into a string. */
|
||||
if (exl.is_string()
|
||||
&& (lsb%8 == 0)
|
||||
&& (result.len()%8 == 0))
|
||||
result = verinum(result.as_string());
|
||||
|
||||
delete tmp;
|
||||
tmp = new NetEConst(result);
|
||||
|
||||
} else if (use_sel == index_component_t::SEL_IDX_UP || use_sel == index_component_t::SEL_IDX_DO) {
|
||||
if (use_sel == index_component_t::SEL_IDX_DO) {
|
||||
|
||||
ivl_assert(*this, !name_tail.index.empty());
|
||||
const index_component_t&index_tail = name_tail.index.back();
|
||||
@@ -1334,8 +1485,7 @@ NetExpr* PEIdent::elaborate_expr_net_word_(Design*des, NetScope*scope,
|
||||
// Special case: The index is out of range, so the value
|
||||
// of this expression is a 'bx vector the width of a word.
|
||||
if (!net->array_index_is_valid(addr)) {
|
||||
verinum xxx (verinum::Vx, net->vector_width());
|
||||
NetEConst*resx = new NetEConst(xxx);
|
||||
NetEConst*resx = make_const_x(net->vector_width());
|
||||
resx->set_line(*this);
|
||||
delete word_index;
|
||||
return resx;
|
||||
@@ -1401,16 +1551,7 @@ NetExpr* PEIdent::elaborate_expr_net_part_(Design*des, NetScope*scope,
|
||||
negative values. However, the width that they represent is
|
||||
unsigned. Remember that any order is possible,
|
||||
i.e., [1:0], [-4:6], etc. */
|
||||
unsigned long wid = 1 + ((msv>lsv)? (msv-lsv) : (lsv-msv));
|
||||
if (wid > net->vector_width()) {
|
||||
cerr << get_fileline() << ": error: part select ["
|
||||
<< msv << ":" << lsv << "] out of range." << endl;
|
||||
des->errors += 1;
|
||||
//delete lsn;
|
||||
//delete msn;
|
||||
return net;
|
||||
}
|
||||
ivl_assert(*this, wid <= net->vector_width());
|
||||
unsigned long wid = 1 + labs(msv-lsv);
|
||||
|
||||
if (net->sig()->sb_to_idx(msv) < net->sig()->sb_to_idx(lsv)) {
|
||||
cerr << get_fileline() << ": error: part select ["
|
||||
@@ -1421,27 +1562,79 @@ NetExpr* PEIdent::elaborate_expr_net_part_(Design*des, NetScope*scope,
|
||||
return net;
|
||||
}
|
||||
|
||||
|
||||
if (net->sig()->sb_to_idx(msv) >= net->vector_width()) {
|
||||
cerr << get_fileline() << ": error: part select ["
|
||||
<< msv << ":" << lsv << "] out of range." << endl;
|
||||
des->errors += 1;
|
||||
//delete lsn;
|
||||
//delete msn;
|
||||
return net;
|
||||
}
|
||||
long sb_lsb = net->sig()->sb_to_idx(lsv);
|
||||
long sb_msb = net->sig()->sb_to_idx(msv);
|
||||
|
||||
// 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) == 0 && wid == net->vector_width())
|
||||
if (sb_lsb == 0 && wid == net->vector_width())
|
||||
return net;
|
||||
|
||||
NetExpr*ex = new NetEConst(verinum(net->sig()->sb_to_idx(lsv)));
|
||||
NetESelect*ss = new NetESelect(net, ex, wid);
|
||||
ss->set_line(*this);
|
||||
// If the part select covers NONE of the vector, then return a
|
||||
// constant X.
|
||||
|
||||
return ss;
|
||||
if ((sb_lsb >= (signed) net->vector_width()) || (sb_msb < 0)) {
|
||||
NetEConst*tmp = make_const_x(wid);
|
||||
tmp->set_line(*this);
|
||||
return tmp;
|
||||
}
|
||||
|
||||
// If the part select is entirely within the vector, then make
|
||||
// a simple part select.
|
||||
if (sb_lsb >= 0 && sb_msb < (signed)net->vector_width()) {
|
||||
NetExpr*ex = new NetEConst(verinum(sb_lsb));
|
||||
NetESelect*ss = new NetESelect(net, ex, wid);
|
||||
ss->set_line(*this);
|
||||
return ss;
|
||||
}
|
||||
|
||||
// Now the hard stuff. The part select is falling off at least
|
||||
// one end. We're going to need a NetEConcat to mix the
|
||||
// selection with overrun.
|
||||
|
||||
NetEConst*bot = 0;
|
||||
if (sb_lsb < 0) {
|
||||
bot = make_const_x( 0-sb_lsb );
|
||||
bot->set_line(*this);
|
||||
sb_lsb = 0;
|
||||
}
|
||||
NetEConst*top = 0;
|
||||
if (sb_msb >= (signed)net->vector_width()) {
|
||||
top = make_const_x( 1+sb_msb-net->vector_width() );
|
||||
top->set_line(*this);
|
||||
sb_msb = net->vector_width()-1;
|
||||
}
|
||||
|
||||
unsigned concat_count = 1;
|
||||
if (bot) concat_count += 1;
|
||||
if (top) concat_count += 1;
|
||||
|
||||
NetEConcat*concat = new NetEConcat(concat_count);
|
||||
concat->set_line(*this);
|
||||
|
||||
if (bot) {
|
||||
concat_count -= 1;
|
||||
concat->set(concat_count, bot);
|
||||
}
|
||||
if (sb_lsb == 0 && sb_msb+1 == (signed)net->vector_width()) {
|
||||
concat_count -= 1;
|
||||
concat->set(concat_count, net);
|
||||
} else {
|
||||
NetExpr*ex = new NetEConst(verinum(sb_lsb));
|
||||
ex->set_line(*this);
|
||||
NetESelect*ss = new NetESelect(net, ex, 1+sb_msb-sb_lsb);
|
||||
ss->set_line(*this);
|
||||
concat_count -= 1;
|
||||
concat->set(concat_count, ss);
|
||||
}
|
||||
if (top) {
|
||||
concat_count -= 1;
|
||||
concat->set(concat_count, top);
|
||||
}
|
||||
ivl_assert(*this, concat_count==0);
|
||||
|
||||
return concat;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -1450,14 +1643,7 @@ NetExpr* PEIdent::elaborate_expr_net_part_(Design*des, NetScope*scope,
|
||||
NetExpr* PEIdent::elaborate_expr_net_idx_up_(Design*des, NetScope*scope,
|
||||
NetESignal*net, NetScope*found_in) const
|
||||
{
|
||||
const name_component_t&name_tail = path_.back();
|
||||
ivl_assert(*this, !name_tail.index.empty());
|
||||
|
||||
const index_component_t&index_tail = name_tail.index.back();
|
||||
ivl_assert(*this, index_tail.lsb != 0);
|
||||
ivl_assert(*this, index_tail.msb != 0);
|
||||
|
||||
NetExpr*base = elab_and_eval(des, scope, index_tail.msb, -1);
|
||||
NetExpr*base = calculate_up_do_base_(des, scope);
|
||||
|
||||
unsigned long wid = 0;
|
||||
calculate_up_do_width_(des, scope, wid);
|
||||
@@ -1531,7 +1717,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.
|
||||
@@ -1581,8 +1768,7 @@ NetExpr* PEIdent::elaborate_expr_net_bit_(Design*des, NetScope*scope,
|
||||
/* The bit select is out of range of the
|
||||
vector. This is legal, but returns a
|
||||
constant 1'bx value. */
|
||||
verinum x (verinum::Vx);
|
||||
NetEConst*tmp = new NetEConst(x);
|
||||
NetEConst*tmp = make_const_x(1);
|
||||
tmp->set_line(*this);
|
||||
|
||||
cerr << get_fileline() << ": warning: Bit select ["
|
||||
@@ -1839,16 +2025,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;
|
||||
|
||||
+232
-53
@@ -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,6 +1578,14 @@ NetNet* PEConcat::elaborate_net(Design*des, NetScope*scope,
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!erep->value().is_defined()) {
|
||||
cerr << get_fileline() << ": error: Concatenation repeat "
|
||||
<< "may not be undefined (" << erep->value()
|
||||
<< ")." << endl;
|
||||
des->errors += 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (erep->value().is_negative()) {
|
||||
cerr << get_fileline() << ": error: Concatenation repeat "
|
||||
<< "may not be negative (" << erep->value().as_long()
|
||||
@@ -1591,7 +1599,7 @@ NetNet* PEConcat::elaborate_net(Design*des, NetScope*scope,
|
||||
|
||||
if (repeat == 0) {
|
||||
cerr << get_fileline() << ": error: Concatenation repeat "
|
||||
"may not be 0."
|
||||
"may not be zero."
|
||||
<< endl;
|
||||
des->errors += 1;
|
||||
return 0;
|
||||
@@ -1689,7 +1697,6 @@ NetNet* PEConcat::elaborate_net(Design*des, NetScope*scope,
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
osig->local_flag(true);
|
||||
return osig;
|
||||
}
|
||||
@@ -1895,10 +1902,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
|
||||
@@ -1964,12 +1972,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 "
|
||||
@@ -1991,7 +2057,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;
|
||||
}
|
||||
@@ -2280,30 +2375,53 @@ NetNet* PEConcat::elaborate_lnet_common_(Design*des, NetScope*scope,
|
||||
osig->local_flag(true);
|
||||
osig->set_line(*this);
|
||||
|
||||
if (debug_elaborate) {
|
||||
cerr << get_fileline() << ": debug: Generating part selects "
|
||||
<< "to connect input l-value to subexpressions."
|
||||
<< endl;
|
||||
if (bidirectional_flag) {
|
||||
if (debug_elaborate) {
|
||||
cerr << get_fileline() << ": debug: Generating tran(VP) "
|
||||
<< "to connect input l-value to subexpressions."
|
||||
<< endl;
|
||||
}
|
||||
|
||||
for (unsigned idx = 0 ; idx < nets.count() ; idx += 1) {
|
||||
unsigned wid = nets[idx]->vector_width();
|
||||
unsigned off = width - wid;
|
||||
NetTran*ps = new NetTran(scope, scope->local_symbol(),
|
||||
osig->vector_width(), wid, off);
|
||||
des->add_node(ps);
|
||||
ps->set_line(*this);
|
||||
|
||||
connect(ps->pin(0), osig->pin(0));
|
||||
connect(ps->pin(1), nets[idx]->pin(0));
|
||||
|
||||
ivl_assert(*this, wid <= width);
|
||||
width -= wid;
|
||||
}
|
||||
|
||||
} else {
|
||||
if (debug_elaborate) {
|
||||
cerr << get_fileline() << ": debug: Generating part selects "
|
||||
<< "to connect input l-value to subexpressions."
|
||||
<< endl;
|
||||
}
|
||||
|
||||
NetPartSelect::dir_t part_dir = NetPartSelect::VP;
|
||||
|
||||
for (unsigned idx = 0 ; idx < nets.count() ; idx += 1) {
|
||||
unsigned wid = nets[idx]->vector_width();
|
||||
unsigned off = width - wid;
|
||||
NetPartSelect*ps = new NetPartSelect(osig, off, wid, part_dir);
|
||||
des->add_node(ps);
|
||||
ps->set_line(*this);
|
||||
|
||||
connect(ps->pin(1), osig->pin(0));
|
||||
connect(ps->pin(0), nets[idx]->pin(0));
|
||||
|
||||
assert(wid <= width);
|
||||
width -= wid;
|
||||
}
|
||||
assert(width == 0);
|
||||
}
|
||||
|
||||
NetPartSelect::dir_t part_dir = bidirectional_flag
|
||||
? NetPartSelect::BI
|
||||
: NetPartSelect::VP;
|
||||
|
||||
for (unsigned idx = 0 ; idx < nets.count() ; idx += 1) {
|
||||
unsigned wid = nets[idx]->vector_width();
|
||||
unsigned off = width - wid;
|
||||
NetPartSelect*ps = new NetPartSelect(osig, off, wid, part_dir);
|
||||
des->add_node(ps);
|
||||
|
||||
connect(ps->pin(1), osig->pin(0));
|
||||
connect(ps->pin(0), nets[idx]->pin(0));
|
||||
|
||||
assert(wid <= width);
|
||||
width -= wid;
|
||||
}
|
||||
assert(width == 0);
|
||||
|
||||
osig->data_type(nets[0]->data_type());
|
||||
osig->local_flag(true);
|
||||
return osig;
|
||||
@@ -2386,7 +2504,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
|
||||
@@ -2450,31 +2568,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;
|
||||
}
|
||||
|
||||
@@ -2495,7 +2618,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;
|
||||
@@ -2611,12 +2734,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;
|
||||
@@ -2642,11 +2774,6 @@ NetNet* PEIdent::elaborate_lnet_common_(Design*des, NetScope*scope,
|
||||
/* If we are processing a tran or inout, then the
|
||||
partselect is bi-directional. Otherwise, it is a
|
||||
Part-to-Vector select. */
|
||||
NetPartSelect::dir_t part_dir;
|
||||
if (bidirectional_flag)
|
||||
part_dir = NetPartSelect::BI;
|
||||
else
|
||||
part_dir = NetPartSelect::PV;
|
||||
|
||||
if (debug_elaborate)
|
||||
cerr << get_fileline() << ": debug: "
|
||||
@@ -2663,11 +2790,23 @@ NetNet* PEIdent::elaborate_lnet_common_(Design*des, NetScope*scope,
|
||||
subsig->local_flag(true);
|
||||
subsig->set_line(*this);
|
||||
|
||||
NetPartSelect*sub = new NetPartSelect(sig, lidx, subnet_wid,
|
||||
part_dir);
|
||||
des->add_node(sub);
|
||||
connect(sub->pin(0), subsig->pin(0));
|
||||
if (bidirectional_flag) {
|
||||
// Make a tran(VP)
|
||||
NetTran*sub = new NetTran(scope, scope->local_symbol(),
|
||||
sig->vector_width(),
|
||||
subnet_wid, lidx);
|
||||
sub->set_line(*this);
|
||||
des->add_node(sub);
|
||||
connect(sub->pin(0), sig->pin(0));
|
||||
connect(sub->pin(1), subsig->pin(0));
|
||||
|
||||
} else {
|
||||
NetPartSelect*sub = new NetPartSelect(sig, lidx, subnet_wid,
|
||||
NetPartSelect::PV);
|
||||
des->add_node(sub);
|
||||
sub->set_line(*this);
|
||||
connect(sub->pin(0), subsig->pin(0));
|
||||
}
|
||||
sig = subsig;
|
||||
}
|
||||
|
||||
@@ -2738,8 +2877,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
|
||||
@@ -3213,6 +3352,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;
|
||||
@@ -3291,7 +3457,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;
|
||||
}
|
||||
|
||||
@@ -3466,6 +3632,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"),
|
||||
|
||||
+74
-7
@@ -22,6 +22,7 @@
|
||||
# include "netmisc.h"
|
||||
# include <cstring>
|
||||
# include <iostream>
|
||||
# include <cstdlib>
|
||||
# include <stdio.h>
|
||||
|
||||
/*
|
||||
@@ -43,6 +44,7 @@
|
||||
# include "util.h"
|
||||
# include <typeinfo>
|
||||
# include <assert.h>
|
||||
# include "ivl_assert.h"
|
||||
|
||||
void Module::elaborate_parm_item_(perm_string name, const param_expr_t&cur,
|
||||
Design*des, NetScope*scope)
|
||||
@@ -62,9 +64,11 @@ void Module::elaborate_parm_item_(perm_string name, const param_expr_t&cur,
|
||||
parameter value is coerced to have the correct
|
||||
and defined width. */
|
||||
if (cur.msb) {
|
||||
assert(cur.lsb);
|
||||
msb = cur.msb ->elaborate_pexpr(des, scope);
|
||||
assert(msb);
|
||||
lsb = cur.lsb ->elaborate_pexpr(des, scope);
|
||||
assert(lsb);
|
||||
}
|
||||
|
||||
if (signed_flag) {
|
||||
@@ -80,8 +84,41 @@ void Module::elaborate_parm_item_(perm_string name, const param_expr_t&cur,
|
||||
signed_flag = val->has_sign();
|
||||
}
|
||||
|
||||
val = scope->set_parameter(name, val,
|
||||
msb, lsb, signed_flag);
|
||||
NetScope::range_t*range_list = 0;
|
||||
for (Module::range_t*range = cur.range ; range ; range = range->next) {
|
||||
NetScope::range_t*tmp = new NetScope::range_t;
|
||||
tmp->exclude_flag = range->exclude_flag;
|
||||
tmp->low_open_flag = range->low_open_flag;
|
||||
tmp->high_open_flag = range->high_open_flag;
|
||||
|
||||
if (range->low_expr) {
|
||||
tmp->low_expr = elab_and_eval(des, scope, range->low_expr, -1);
|
||||
ivl_assert(*range->low_expr, tmp->low_expr);
|
||||
} else {
|
||||
tmp->low_expr = 0;
|
||||
}
|
||||
|
||||
if (range->high_expr && range->high_expr==range->low_expr) {
|
||||
// Detect the special case of a "point"
|
||||
// range. These are called out by setting the high
|
||||
// and low expression ranges to the same
|
||||
// expression. The exclude_flags should be false
|
||||
// in this case
|
||||
ivl_assert(*range->high_expr, tmp->low_open_flag==false && tmp->high_open_flag==false);
|
||||
tmp->high_expr = tmp->low_expr;
|
||||
|
||||
} else if (range->high_expr) {
|
||||
tmp->high_expr = elab_and_eval(des, scope, range->high_expr, -1);
|
||||
ivl_assert(*range->high_expr, tmp->high_expr);
|
||||
} else {
|
||||
tmp->high_expr = 0;
|
||||
}
|
||||
|
||||
tmp->next = range_list;
|
||||
range_list = tmp;
|
||||
}
|
||||
|
||||
val = scope->set_parameter(name, val, cur.type, msb, lsb, signed_flag, range_list, cur);
|
||||
assert(val);
|
||||
delete val;
|
||||
}
|
||||
@@ -119,7 +156,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, (*cur).second.type,
|
||||
0, 0, false, 0, (*cur).second);
|
||||
}
|
||||
|
||||
for (mparm_it_t cur = localparams.begin()
|
||||
@@ -130,7 +168,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, (*cur).second.type,
|
||||
0, 0, false, 0, (*cur).second);
|
||||
}
|
||||
|
||||
|
||||
@@ -162,6 +201,8 @@ bool Module::elaborate_scope(Design*des, NetScope*scope,
|
||||
<< "Replace " << (*cur).first
|
||||
<< " with expression " << *val
|
||||
<< " from " << val->get_fileline() << "." << endl;
|
||||
cerr << get_fileline() << ": : "
|
||||
<< "Type=" << val->expr_type() << endl;
|
||||
}
|
||||
bool flag = scope->replace_parameter((*cur).first, val);
|
||||
if (! flag) {
|
||||
@@ -240,6 +281,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 +305,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 +380,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 +400,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 +443,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,8 +455,9 @@ 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, *this);
|
||||
if (debug_scopes)
|
||||
cerr << get_fileline() << ": debug: "
|
||||
<< "Create implicit localparam "
|
||||
@@ -463,6 +525,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 +592,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 +725,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 +877,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)
|
||||
|
||||
+13
-1
@@ -323,7 +323,7 @@ bool PGAssign::elaborate_sig(Design*des, NetScope*scope) const
|
||||
to implicitly declare nets. However, so many tools do allow
|
||||
it that Icarus Verilog will allow it, at least if extensions
|
||||
are enabled. */
|
||||
if (generation_flag == GN_VER2001X)
|
||||
if (gn_icarus_misc_flag)
|
||||
return pin(0)->elaborate_sig(des, scope);
|
||||
|
||||
return true;
|
||||
@@ -758,6 +758,18 @@ void PForStatement::elaborate_sig(Design*des, NetScope*scope) const
|
||||
statement_->elaborate_sig(des, scope);
|
||||
}
|
||||
|
||||
void PRepeat::elaborate_sig(Design*des, NetScope*scope) const
|
||||
{
|
||||
if (statement_)
|
||||
statement_->elaborate_sig(des, scope);
|
||||
}
|
||||
|
||||
void PWhile::elaborate_sig(Design*des, NetScope*scope) const
|
||||
{
|
||||
if (statement_)
|
||||
statement_->elaborate_sig(des, scope);
|
||||
}
|
||||
|
||||
/*
|
||||
* Elaborate a source wire. The "wire" is the declaration of wires,
|
||||
* registers, ports and memories. The parser has already merged the
|
||||
|
||||
+103
-16
@@ -419,7 +419,7 @@ void PGBuiltin::elaborate(Design*des, NetScope*scope) const
|
||||
}
|
||||
|
||||
/* Allocate all the netlist nodes for the gates. */
|
||||
NetLogic**cur = new NetLogic*[count];
|
||||
NetNode**cur = new NetNode*[count];
|
||||
assert(cur);
|
||||
|
||||
/* Calculate the gate delays from the delay expressions
|
||||
@@ -659,6 +659,67 @@ void PGBuiltin::elaborate(Design*des, NetScope*scope) const
|
||||
cur[idx] = new NetLogic(scope, inm, pin_count(),
|
||||
NetLogic::XOR, instance_width);
|
||||
break;
|
||||
case TRAN:
|
||||
if (pin_count() != 2) {
|
||||
cerr << get_fileline() << ": error: Pin count for "
|
||||
<< "tran device." << endl;
|
||||
des->errors += 1;
|
||||
return;
|
||||
} else {
|
||||
cur[idx] = new NetTran(scope, inm, IVL_SW_TRAN);
|
||||
}
|
||||
break;
|
||||
case RTRAN:
|
||||
if (pin_count() != 2) {
|
||||
cerr << get_fileline() << ": error: Pin count for "
|
||||
<< "rtran device." << endl;
|
||||
des->errors += 1;
|
||||
return;
|
||||
} else {
|
||||
cur[idx] = new NetTran(scope, inm, IVL_SW_RTRAN);
|
||||
return;
|
||||
}
|
||||
break;
|
||||
case TRANIF0:
|
||||
if (pin_count() != 3) {
|
||||
cerr << get_fileline() << ": error: Pin count for "
|
||||
<< "tranif0 device." << endl;
|
||||
des->errors += 1;
|
||||
return;
|
||||
} else {
|
||||
cur[idx] = new NetTran(scope, inm, IVL_SW_TRANIF0);
|
||||
}
|
||||
break;
|
||||
case RTRANIF0:
|
||||
if (pin_count() != 3) {
|
||||
cerr << get_fileline() << ": error: Pin count for "
|
||||
<< "rtranif0 device." << endl;
|
||||
des->errors += 1;
|
||||
return;
|
||||
} else {
|
||||
cur[idx] = new NetTran(scope, inm, IVL_SW_RTRANIF0);
|
||||
}
|
||||
break;
|
||||
case TRANIF1:
|
||||
if (pin_count() != 3) {
|
||||
cerr << get_fileline() << ": error: Pin count for "
|
||||
<< "tranif1 device." << endl;
|
||||
des->errors += 1;
|
||||
return;
|
||||
} else {
|
||||
cur[idx] = new NetTran(scope, inm, IVL_SW_TRANIF1);
|
||||
}
|
||||
break;
|
||||
case RTRANIF1:
|
||||
if (pin_count() != 3) {
|
||||
cerr << get_fileline() << ": error: Pin count for "
|
||||
<< "rtranif1 device." << endl;
|
||||
des->errors += 1;
|
||||
return;
|
||||
} else {
|
||||
cur[idx] = new NetTran(scope, inm, IVL_SW_RTRANIF1);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
cerr << get_fileline() << ": internal error: unhandled "
|
||||
"gate type." << endl;
|
||||
@@ -670,13 +731,18 @@ void PGBuiltin::elaborate(Design*des, NetScope*scope) const
|
||||
cur[idx]->attribute(attrib_list[adx].key,
|
||||
attrib_list[adx].val);
|
||||
|
||||
cur[idx]->rise_time(rise_time);
|
||||
cur[idx]->fall_time(fall_time);
|
||||
cur[idx]->decay_time(decay_time);
|
||||
/* The logic devices have some uniform processing. Then
|
||||
all may have output delays and output drive strength. */
|
||||
if (NetLogic*log = dynamic_cast<NetLogic*> (cur[idx])) {
|
||||
log->rise_time(rise_time);
|
||||
log->fall_time(fall_time);
|
||||
log->decay_time(decay_time);
|
||||
|
||||
cur[idx]->pin(0).drive0(drive_type(strength0()));
|
||||
cur[idx]->pin(0).drive1(drive_type(strength1()));
|
||||
log->pin(0).drive0(drive_type(strength0()));
|
||||
log->pin(0).drive1(drive_type(strength1()));
|
||||
}
|
||||
|
||||
cur[idx]->set_line(*this);
|
||||
des->add_node(cur[idx]);
|
||||
}
|
||||
|
||||
@@ -798,6 +864,9 @@ void PGBuiltin::elaborate(Design*des, NetScope*scope) const
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// "cur" is an array of pointers, and we don't need it any more.
|
||||
delete[]cur;
|
||||
}
|
||||
|
||||
NetNet*PGModule::resize_net_to_port_(Design*des, NetScope*scope,
|
||||
@@ -812,6 +881,31 @@ NetNet*PGModule::resize_net_to_port_(Design*des, NetScope*scope,
|
||||
tmp->local_flag(true);
|
||||
tmp->set_line(*sig);
|
||||
|
||||
// Handle the special case of a bi-directional part
|
||||
// select. Create a NetTran(VP) instead of a uni-directional
|
||||
// NetPartSelect node.
|
||||
if (dir == NetNet::PINOUT) {
|
||||
unsigned wida = sig->vector_width();
|
||||
unsigned widb = tmp->vector_width();
|
||||
bool part_b = widb < wida;
|
||||
NetTran*node = new NetTran(scope, scope->local_symbol(),
|
||||
part_b? wida : widb,
|
||||
part_b? widb : wida,
|
||||
0);
|
||||
if (part_b) {
|
||||
connect(node->pin(0), sig->pin(0));
|
||||
connect(node->pin(1), tmp->pin(0));
|
||||
} else {
|
||||
connect(node->pin(0), tmp->pin(0));
|
||||
connect(node->pin(1), sig->pin(0));
|
||||
}
|
||||
|
||||
node->set_line(*this);
|
||||
des->add_node(node);
|
||||
|
||||
return tmp;
|
||||
}
|
||||
|
||||
NetPartSelect*node = 0;
|
||||
|
||||
switch (dir) {
|
||||
@@ -840,15 +934,7 @@ NetNet*PGModule::resize_net_to_port_(Design*des, NetScope*scope,
|
||||
break;
|
||||
|
||||
case NetNet::PINOUT:
|
||||
if (sig->vector_width() > tmp->vector_width()) {
|
||||
node = new NetPartSelect(sig, 0, tmp->vector_width(),
|
||||
NetPartSelect::BI);
|
||||
connect(node->pin(0), tmp->pin(0));
|
||||
} else {
|
||||
node = new NetPartSelect(tmp, 0, sig->vector_width(),
|
||||
NetPartSelect::BI);
|
||||
connect(node->pin(0), sig->pin(0));
|
||||
}
|
||||
ivl_assert(*this, 0);
|
||||
break;
|
||||
|
||||
default:
|
||||
@@ -1711,7 +1797,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);
|
||||
@@ -3707,6 +3793,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);
|
||||
@@ -159,6 +165,11 @@ bool NetUserFunc::emit_node(struct target_t*tgt) const
|
||||
return tgt->net_function(this);
|
||||
}
|
||||
|
||||
bool NetTran::emit_node(struct target_t*tgt) const
|
||||
{
|
||||
return tgt->tran(this);
|
||||
}
|
||||
|
||||
bool NetBUFZ::emit_node(struct target_t*tgt) const
|
||||
{
|
||||
return tgt->bufz(this);
|
||||
|
||||
+16
-19
@@ -1171,17 +1171,9 @@ NetExpr* NetEParam::eval_tree(int prune_to_width)
|
||||
}
|
||||
|
||||
assert(scope_);
|
||||
const NetExpr*expr_msb;
|
||||
const NetExpr*expr_lsb;
|
||||
const NetExpr*expr = scope_->get_parameter(name_, expr_msb, expr_lsb);
|
||||
if (expr == 0) {
|
||||
cerr << get_fileline() << ": internal error: Unable to match "
|
||||
<< "parameter " << name_ << " in scope "
|
||||
<< scope_path(scope_) << endl;
|
||||
return 0;
|
||||
}
|
||||
|
||||
assert(expr);
|
||||
perm_string name = (*reference_).first;
|
||||
const NetExpr*expr = (*reference_).second.expr;
|
||||
ivl_assert(*this, expr);
|
||||
|
||||
NetExpr*nexpr = expr->dup_expr();
|
||||
assert(nexpr);
|
||||
@@ -1190,7 +1182,7 @@ NetExpr* NetEParam::eval_tree(int prune_to_width)
|
||||
// return the constant value.
|
||||
if (NetEConst*tmp = dynamic_cast<NetEConst*>(nexpr)) {
|
||||
verinum val = tmp->value();
|
||||
NetEConstParam*ptmp = new NetEConstParam(scope_, name_, val);
|
||||
NetEConstParam*ptmp = new NetEConstParam(scope_, name, val);
|
||||
ptmp->set_line(*this);
|
||||
delete nexpr;
|
||||
return ptmp;
|
||||
@@ -1198,7 +1190,7 @@ NetExpr* NetEParam::eval_tree(int prune_to_width)
|
||||
|
||||
if (NetECReal*tmp = dynamic_cast<NetECReal*>(nexpr)) {
|
||||
verireal val = tmp->value();
|
||||
NetECRealParam*ptmp = new NetECRealParam(scope_, name_, val);
|
||||
NetECRealParam*ptmp = new NetECRealParam(scope_, name, val);
|
||||
ptmp->set_line(*this);
|
||||
delete nexpr;
|
||||
return ptmp;
|
||||
@@ -1209,7 +1201,7 @@ NetExpr* NetEParam::eval_tree(int prune_to_width)
|
||||
NetExpr*res = nexpr->eval_tree();
|
||||
if (res == 0) {
|
||||
cerr << get_fileline() << ": internal error: Unable to evaluate "
|
||||
<< "parameter " << name_ << " expression: "
|
||||
<< "parameter " << name << " expression: "
|
||||
<< *nexpr << endl;
|
||||
delete nexpr;
|
||||
return 0;
|
||||
@@ -1217,7 +1209,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. */
|
||||
@@ -1229,7 +1226,7 @@ NetExpr* NetEParam::eval_tree(int prune_to_width)
|
||||
{ NetEConst*tmp = dynamic_cast<NetEConst*>(res);
|
||||
if (tmp == 0) {
|
||||
cerr << get_fileline() << ": internal error: parameter "
|
||||
<< name_ << " evaluates to incomprehensible "
|
||||
<< name << " evaluates to incomprehensible "
|
||||
<< *res << "." << endl;
|
||||
return 0;
|
||||
}
|
||||
@@ -1237,7 +1234,7 @@ NetExpr* NetEParam::eval_tree(int prune_to_width)
|
||||
assert(tmp);
|
||||
|
||||
verinum val = tmp->value();
|
||||
NetEConstParam*ptmp = new NetEConstParam(scope_, name_, val);
|
||||
NetEConstParam*ptmp = new NetEConstParam(scope_, name, val);
|
||||
|
||||
return ptmp;
|
||||
}
|
||||
@@ -1246,7 +1243,7 @@ NetExpr* NetEParam::eval_tree(int prune_to_width)
|
||||
{ NetECReal*tmp = dynamic_cast<NetECReal*>(res);
|
||||
if (tmp == 0) {
|
||||
cerr << get_fileline() << ": internal error: parameter "
|
||||
<< name_ << " evaluates to incomprehensible "
|
||||
<< name << " evaluates to incomprehensible "
|
||||
<< *res << "." << endl;
|
||||
return 0;
|
||||
}
|
||||
@@ -1254,7 +1251,7 @@ NetExpr* NetEParam::eval_tree(int prune_to_width)
|
||||
assert(tmp);
|
||||
|
||||
verireal val = tmp->value();
|
||||
NetECRealParam*ptmp = new NetECRealParam(scope_, name_, val);
|
||||
NetECRealParam*ptmp = new NetECRealParam(scope_, name, val);
|
||||
|
||||
return ptmp;
|
||||
}
|
||||
|
||||
+8
-1
@@ -235,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) {
|
||||
@@ -274,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) {
|
||||
@@ -290,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) {
|
||||
@@ -432,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;
|
||||
@@ -923,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*);
|
||||
|
||||
|
||||
@@ -53,6 +53,9 @@ ivl_file_table_index
|
||||
ivl_file_table_item
|
||||
ivl_file_table_size
|
||||
|
||||
ivl_island_flag_set
|
||||
ivl_island_flag_test
|
||||
|
||||
ivl_logic_attr
|
||||
ivl_logic_attr_cnt
|
||||
ivl_logic_attr_val
|
||||
@@ -115,9 +118,12 @@ ivl_nexus_ptr_pin
|
||||
ivl_nexus_ptr_lpm
|
||||
ivl_nexus_ptr_log
|
||||
ivl_nexus_ptr_sig
|
||||
ivl_nexus_ptr_switch
|
||||
|
||||
ivl_parameter_basename
|
||||
ivl_parameter_expr
|
||||
ivl_parameter_file
|
||||
ivl_parameter_lineno
|
||||
|
||||
ivl_path_condit
|
||||
ivl_path_delay
|
||||
@@ -132,8 +138,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
|
||||
@@ -146,6 +156,8 @@ ivl_scope_port
|
||||
ivl_scope_ports
|
||||
ivl_scope_sigs
|
||||
ivl_scope_sig
|
||||
ivl_scope_switch
|
||||
ivl_scope_switches
|
||||
ivl_scope_time_precision
|
||||
ivl_scope_time_units
|
||||
ivl_scope_type
|
||||
@@ -159,7 +171,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
|
||||
@@ -208,6 +222,19 @@ ivl_stmt_parm_count
|
||||
ivl_stmt_rval
|
||||
ivl_stmt_sub_stmt
|
||||
|
||||
ivl_switch_a
|
||||
ivl_switch_b
|
||||
ivl_switch_basename
|
||||
ivl_switch_enable
|
||||
ivl_switch_file
|
||||
ivl_switch_island
|
||||
ivl_switch_lineno
|
||||
ivl_switch_offset
|
||||
ivl_switch_part
|
||||
ivl_switch_scope
|
||||
ivl_switch_type
|
||||
ivl_switch_width
|
||||
|
||||
ivl_udp_init
|
||||
ivl_udp_name
|
||||
ivl_udp_nin
|
||||
|
||||
+111
-1
@@ -80,6 +80,13 @@ _BEGIN_DECL
|
||||
* processes. Structural expressions are instead treated as logic
|
||||
* gates.
|
||||
*
|
||||
* ivl_island_t
|
||||
* Certain types of objects may belong to islands. The island that
|
||||
* they belong to is represented by the ivl_island_t cookie. To
|
||||
* know if object belong to the same island, it is sufficient to
|
||||
* compare island cookies. If a==b, then island a is the same as
|
||||
* island b.
|
||||
*
|
||||
* ivl_lpm_t
|
||||
* This object is the base class for all the various LPM type
|
||||
* device nodes. This object carries a few base properties
|
||||
@@ -123,6 +130,9 @@ _BEGIN_DECL
|
||||
* ivl_process_t object holds one of these, but a statement may in
|
||||
* turn contain other statements.
|
||||
*
|
||||
* ivl_switch_t
|
||||
* Switches are the tran/tranif devices in the design.
|
||||
*
|
||||
* -- A Note About Bit Sets --
|
||||
* Some objects hold a value as an array of bits. In these cases there
|
||||
* is some method that retrieves the width of the value and another
|
||||
@@ -143,6 +153,7 @@ typedef struct ivl_delaypath_s*ivl_delaypath_t;
|
||||
typedef struct ivl_design_s *ivl_design_t;
|
||||
typedef struct ivl_event_s *ivl_event_t;
|
||||
typedef struct ivl_expr_s *ivl_expr_t;
|
||||
typedef struct ivl_island_s *ivl_island_t;
|
||||
typedef struct ivl_lpm_s *ivl_lpm_t;
|
||||
typedef struct ivl_lval_s *ivl_lval_t;
|
||||
typedef struct ivl_net_const_s*ivl_net_const_t;
|
||||
@@ -155,6 +166,7 @@ typedef struct ivl_parameter_s*ivl_parameter_t;
|
||||
typedef struct ivl_process_s *ivl_process_t;
|
||||
typedef struct ivl_scope_s *ivl_scope_t;
|
||||
typedef struct ivl_signal_s *ivl_signal_t;
|
||||
typedef struct ivl_switch_s *ivl_switch_t;
|
||||
typedef struct ivl_memory_s *ivl_memory_t; /* DEPRECATED */
|
||||
typedef struct ivl_statement_s*ivl_statement_t;
|
||||
|
||||
@@ -226,8 +238,20 @@ typedef enum ivl_logic_e {
|
||||
IVL_LO_UDP = 21
|
||||
} ivl_logic_t;
|
||||
|
||||
/* This is the type of a ivl_switch_t object */
|
||||
typedef enum ivl_switch_type_e {
|
||||
IVL_SW_TRAN = 0,
|
||||
IVL_SW_TRANIF0 = 1,
|
||||
IVL_SW_TRANIF1 = 2,
|
||||
IVL_SW_RTRAN = 3,
|
||||
IVL_SW_RTRANIF0 = 4,
|
||||
IVL_SW_RTRANIF1 = 5,
|
||||
IVL_SW_TRAN_VP = 6
|
||||
} ivl_switch_type_t;
|
||||
|
||||
/* 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,
|
||||
@@ -242,7 +266,7 @@ typedef enum ivl_lpm_type_e {
|
||||
IVL_LPM_MOD = 13,
|
||||
IVL_LPM_MULT = 4,
|
||||
IVL_LPM_MUX = 5,
|
||||
IVL_LPM_PART_BI= 28, /* part select: bi-directional (part on 0) */
|
||||
/* IVL_LPM_PART_BI= 28, / obsolete */
|
||||
IVL_LPM_PART_VP= 15, /* part select: vector to part */
|
||||
IVL_LPM_PART_PV= 17, /* part select: part written to vector */
|
||||
IVL_LPM_POW = 31,
|
||||
@@ -698,6 +722,16 @@ extern unsigned ivl_file_table_index(const char *);
|
||||
extern unsigned ivl_file_table_size(void);
|
||||
|
||||
|
||||
/* ISLAND
|
||||
*
|
||||
* ivl_island_flag_set
|
||||
* ivl_island_flag_test
|
||||
* Allow the user to test or set a boolean flag associated with the
|
||||
* island.
|
||||
*/
|
||||
extern int ivl_island_flag_set(ivl_island_t net, unsigned flag, int value);
|
||||
extern int ivl_island_flag_test(ivl_island_t net, unsigned flag);
|
||||
|
||||
/* LOGIC
|
||||
* These types and functions support manipulation of logic gates. The
|
||||
* ivl_logic_t enumeration identifies the various kinds of gates that
|
||||
@@ -1312,6 +1346,7 @@ extern unsigned ivl_nexus_ptr_pin(ivl_nexus_ptr_t net);
|
||||
extern ivl_net_const_t ivl_nexus_ptr_con(ivl_nexus_ptr_t net);
|
||||
extern ivl_net_logic_t ivl_nexus_ptr_log(ivl_nexus_ptr_t net);
|
||||
extern ivl_lpm_t ivl_nexus_ptr_lpm(ivl_nexus_ptr_t net);
|
||||
extern ivl_switch_t ivl_nexus_ptr_switch(ivl_nexus_ptr_t net);
|
||||
extern ivl_signal_t ivl_nexus_ptr_sig(ivl_nexus_ptr_t net);
|
||||
|
||||
/* PARAMETER
|
||||
@@ -1339,11 +1374,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
|
||||
@@ -1391,10 +1433,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
|
||||
@@ -1465,9 +1515,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);
|
||||
@@ -1481,6 +1535,8 @@ extern unsigned ivl_scope_ports(ivl_scope_t net);
|
||||
extern ivl_signal_t ivl_scope_port(ivl_scope_t net, unsigned idx);
|
||||
extern unsigned ivl_scope_sigs(ivl_scope_t net);
|
||||
extern ivl_signal_t ivl_scope_sig(ivl_scope_t net, unsigned idx);
|
||||
extern unsigned ivl_scope_switches(ivl_scope_t net);
|
||||
extern ivl_switch_t ivl_scope_switch(ivl_scope_t net, unsigned idx);
|
||||
extern ivl_scope_type_t ivl_scope_type(ivl_scope_t net);
|
||||
extern const char* ivl_scope_tname(ivl_scope_t net);
|
||||
extern int ivl_scope_time_precision(ivl_scope_t net);
|
||||
@@ -1574,6 +1630,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);
|
||||
@@ -1595,6 +1655,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);
|
||||
|
||||
@@ -1799,6 +1862,53 @@ extern ivl_expr_t ivl_stmt_rval(ivl_statement_t net);
|
||||
IVL_ST_WAIT, IVL_ST_WHILE */
|
||||
extern ivl_statement_t ivl_stmt_sub_stmt(ivl_statement_t net);
|
||||
|
||||
/* SWITCHES
|
||||
*
|
||||
* The switches represent the tran devices in the design.
|
||||
*
|
||||
* FUNCTION SUMMARY
|
||||
*
|
||||
* ivl_switch_type
|
||||
* Return the enumerated value that is the type of the switch.
|
||||
*
|
||||
* ivl_switch_basename
|
||||
* This is the name given to the device in the source code.
|
||||
*
|
||||
* ivl_switch_a
|
||||
* ivl_switch_b
|
||||
* The a and b ports are the two ports of the switch.
|
||||
*
|
||||
* ivl_switch_enable
|
||||
* If the device has an enable (tranifX) then this is the enable
|
||||
* port.
|
||||
*
|
||||
* SEMANTIC NOTES
|
||||
* The a/b ports can be any type, but the types must exactly
|
||||
* match, including vector widths. The enable must be a scalar.
|
||||
*
|
||||
* The IVL_SW_TRAN_VP is an exception to the above. In this case,
|
||||
* the B side may be a different size, and the a side will have a
|
||||
* a fixed width. The unused bits are padded to Z on the A side.
|
||||
*/
|
||||
extern ivl_switch_type_t ivl_switch_type(ivl_switch_t net);
|
||||
extern ivl_scope_t ivl_switch_scope(ivl_switch_t net);
|
||||
extern const char*ivl_switch_basename(ivl_switch_t net);
|
||||
extern ivl_nexus_t ivl_switch_a(ivl_switch_t net);
|
||||
extern ivl_nexus_t ivl_switch_b(ivl_switch_t net);
|
||||
extern ivl_nexus_t ivl_switch_enable(ivl_switch_t net);
|
||||
extern ivl_island_t ivl_switch_island(ivl_switch_t net);
|
||||
|
||||
/* These are only support for IVL_SW_TRAN_VP switches. */
|
||||
extern unsigned ivl_switch_width(ivl_switch_t net);
|
||||
extern unsigned ivl_switch_part(ivl_switch_t net);
|
||||
extern unsigned ivl_switch_offset(ivl_switch_t net);
|
||||
|
||||
/* Not implemented yet
|
||||
extern unsigned ivl_switch_attr_cnt(ivl_switch_t net);
|
||||
extern ivl_attribute_t ivl_switch_attr_val(ivl_switch_t net, unsigned idx);
|
||||
*** */
|
||||
extern const char* ivl_switch_file(ivl_switch_t net);
|
||||
extern unsigned ivl_switch_lineno(ivl_switch_t net);
|
||||
|
||||
#if defined(__MINGW32__) || defined (__CYGWIN32__)
|
||||
# define DLLEXPORT __declspec(dllexport)
|
||||
|
||||
@@ -0,0 +1,44 @@
|
||||
#ifndef __ivl_target_priv_H
|
||||
#define __ivl_target_H
|
||||
/*
|
||||
* Copyright (c) 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
|
||||
* 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
|
||||
*/
|
||||
|
||||
# include <inttypes.h>
|
||||
|
||||
/*
|
||||
* This deader has declarations related to the ivl_target.h API that
|
||||
* are not to be exported outside of the core via the ivl_target.h
|
||||
* interface.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Information about islands. Connected branches within a net are
|
||||
* collected into islands. Branches that are purely ddiscrete do not
|
||||
* have disciplines and do not belong to islands.
|
||||
*/
|
||||
|
||||
class discipline_t;
|
||||
|
||||
struct ivl_island_s {
|
||||
discipline_t*discipline;
|
||||
// user accessible flags. They are initially false, always.
|
||||
vector<bool> flags;
|
||||
};
|
||||
|
||||
#endif
|
||||
+40
-22
@@ -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} {}
|
||||
@@ -1171,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;
|
||||
}
|
||||
}
|
||||
@@ -1348,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];
|
||||
@@ -1364,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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1464,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;
|
||||
@@ -1537,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
|
||||
@@ -1604,7 +1616,11 @@ static int load_next_input()
|
||||
static void do_dump_precompiled_defines(FILE* out, struct define_t* table)
|
||||
{
|
||||
if (!table->keyword)
|
||||
#ifdef __MINGW32__ /* MinGW does not know about z. */
|
||||
fprintf(out, "%s:%d:%d:%s\n", table->name, table->argc, strlen(table->value), table->value);
|
||||
#else
|
||||
fprintf(out, "%s:%d:%zd:%s\n", table->name, table->argc, strlen(table->value), table->value);
|
||||
#endif
|
||||
|
||||
if (table->left)
|
||||
do_dump_precompiled_defines(out, table->left);
|
||||
@@ -1699,6 +1715,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)
|
||||
{
|
||||
@@ -1728,6 +1745,7 @@ void reset_lexor(FILE* out, char* paths[])
|
||||
isp->ebs = 0;
|
||||
isp->next = 0;
|
||||
isp->lineno = 0;
|
||||
isp->stringify_flag = 0;
|
||||
|
||||
if (tail)
|
||||
tail->next = isp;
|
||||
|
||||
@@ -34,7 +34,8 @@
|
||||
# include <ctype.h>
|
||||
# include <string.h>
|
||||
# include "lexor_keyword.h"
|
||||
|
||||
# include "discipline.h"
|
||||
# include <list>
|
||||
|
||||
# define YY_USER_INIT reset_lexor();
|
||||
# define yylval VLlval
|
||||
@@ -83,6 +84,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;
|
||||
%}
|
||||
|
||||
@@ -93,10 +96,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(); }
|
||||
@@ -146,6 +153,7 @@ W [ \t\b\f\r]+
|
||||
"->" { return K_TRIGGER; }
|
||||
"+:" { return K_PO_POS; }
|
||||
"-:" { return K_PO_NEG; }
|
||||
"<+" { return K_CONTRIBUTE; }
|
||||
|
||||
/* Watch out for the tricky case of (*). Cannot parse this as "(*"
|
||||
and ")", but since I know that this is really ( * ), replace it
|
||||
@@ -215,17 +223,6 @@ W [ \t\b\f\r]+
|
||||
rc = PATHPULSE_IDENTIFIER;
|
||||
break;
|
||||
|
||||
case K_bool:
|
||||
case K_logic:
|
||||
case K_wone:
|
||||
if (! gn_cadence_types_enabled()) {
|
||||
yylval.text = strdupnew(yytext);
|
||||
rc = IDENTIFIER;
|
||||
} else {
|
||||
yylval.text = 0;
|
||||
}
|
||||
break;
|
||||
|
||||
case K_edge:
|
||||
BEGIN(EDGES);
|
||||
break;
|
||||
@@ -235,6 +232,18 @@ W [ \t\b\f\r]+
|
||||
break;
|
||||
}
|
||||
|
||||
/* If this identifier names a discipline, then return this as
|
||||
a DISCIPLINE_IDENTIFIER and return the discipline as the
|
||||
value instead. */
|
||||
if (rc == IDENTIFIER && gn_verilog_ams_flag) {
|
||||
perm_string tmp = lex_strings.make(yylval.text);
|
||||
map<perm_string,discipline_t*>::iterator cur = disciplines.find(tmp);
|
||||
if (cur != disciplines.end()) {
|
||||
yylval.discipline = (*cur).second;
|
||||
rc = DISCIPLINE_IDENTIFIER;
|
||||
}
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
@@ -280,6 +289,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; }
|
||||
@@ -321,6 +370,57 @@ W [ \t\b\f\r]+
|
||||
^{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
|
||||
rule collects the rest of the line and processes it. We only need
|
||||
|
||||
+160
-111
@@ -6,127 +6,176 @@
|
||||
#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
|
||||
abstol, GN_KEYWORDS_VAMS_2_3, K_abstol
|
||||
access, GN_KEYWORDS_VAMS_2_3, K_access
|
||||
acos, GN_KEYWORDS_VAMS_2_3, K_acos
|
||||
acosh, GN_KEYWORDS_VAMS_2_3, K_acosh
|
||||
always, GN_KEYWORDS_1364_1995, K_always
|
||||
analog, GN_KEYWORDS_VAMS_2_3, K_analog
|
||||
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
|
||||
continuous, GN_KEYWORDS_VAMS_2_3, K_continuous
|
||||
cos, GN_KEYWORDS_VAMS_2_3, K_cos
|
||||
cosh, GN_KEYWORDS_VAMS_2_3, K_cosh
|
||||
ddt_nature, GN_KEYWORDS_VAMS_2_3, K_ddt_nature
|
||||
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
|
||||
discipline, GN_KEYWORDS_VAMS_2_3, K_discipline
|
||||
discrete, GN_KEYWORDS_VAMS_2_3, K_discrete
|
||||
domain, GN_KEYWORDS_VAMS_2_3, K_domain
|
||||
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
|
||||
enddiscipline, GN_KEYWORDS_VAMS_2_3, K_enddiscipline
|
||||
endfunction, GN_KEYWORDS_1364_1995, K_endfunction
|
||||
endgenerate, GN_KEYWORDS_1364_1995, K_endgenerate
|
||||
endmodule, GN_KEYWORDS_1364_1995, K_endmodule
|
||||
endnature, GN_KEYWORDS_VAMS_2_3, K_endnature
|
||||
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
|
||||
exclude, GN_KEYWORDS_VAMS_2_3, K_exclude
|
||||
exp, GN_KEYWORDS_VAMS_2_3, K_exp
|
||||
floor, GN_KEYWORDS_VAMS_2_3, K_floor
|
||||
flow, GN_KEYWORDS_VAMS_2_3, K_flow
|
||||
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
|
||||
from, GN_KEYWORDS_VAMS_2_3, K_from
|
||||
function, GN_KEYWORDS_1364_1995, K_function
|
||||
generate, GN_KEYWORDS_1364_2001, K_generate
|
||||
genvar, GN_KEYWORDS_1364_2001, K_genvar
|
||||
ground, GN_KEYWORDS_VAMS_2_3, K_ground
|
||||
highz0, GN_KEYWORDS_1364_1995, K_highz0
|
||||
highz1, GN_KEYWORDS_1364_1995, K_highz1
|
||||
hypot, GN_KEYWORDS_VAMS_2_3, K_hypot
|
||||
idt_nature, GN_KEYWORDS_VAMS_2_3, K_idt_nature
|
||||
if, GN_KEYWORDS_1364_1995, K_if
|
||||
ifnone, GN_KEYWORDS_1364_1995, K_ifnone
|
||||
inf, GN_KEYWORDS_VAMS_2_3, K_inf
|
||||
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
|
||||
nature, GN_KEYWORDS_VAMS_2_3, K_nature
|
||||
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
|
||||
potential, GN_KEYWORDS_VAMS_2_3, K_potential
|
||||
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
|
||||
string, GN_KEYWORDS_VAMS_2_3, K_string
|
||||
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
|
||||
units, GN_KEYWORDS_VAMS_2_3, K_units
|
||||
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;
|
||||
}
|
||||
|
||||
@@ -57,6 +57,7 @@ const char NOTICE[] =
|
||||
# include "netlist.h"
|
||||
# include "target.h"
|
||||
# include "compiler.h"
|
||||
# include "discipline.h"
|
||||
|
||||
#if defined(__MINGW32__) && !defined(HAVE_GETOPT_H)
|
||||
extern "C" int getopt(int argc, char*argv[], const char*fmt);
|
||||
@@ -85,9 +86,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;
|
||||
@@ -121,6 +124,8 @@ bool debug_scopes = false;
|
||||
bool debug_eval_tree = false;
|
||||
bool debug_elaborate = false;
|
||||
bool debug_synth2 = false;
|
||||
bool debug_optimizer = false;
|
||||
|
||||
/*
|
||||
* Verbose messages enabled.
|
||||
*/
|
||||
@@ -197,14 +202,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;
|
||||
@@ -218,6 +239,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;
|
||||
|
||||
@@ -366,6 +393,9 @@ static void read_iconfig_file(const char*ipath)
|
||||
} else if (strcmp(cp,"synth2") == 0) {
|
||||
debug_synth2 = true;
|
||||
cerr << "debug: Enable synth2 debug" << endl;
|
||||
} else if (strcmp(cp,"optimizer") == 0) {
|
||||
debug_optimizer = true;
|
||||
cerr << "debug: Enable optimizer debug" << endl;
|
||||
} else {
|
||||
}
|
||||
|
||||
@@ -592,6 +622,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)
|
||||
@@ -605,11 +658,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
|
||||
@@ -620,6 +676,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;
|
||||
}
|
||||
|
||||
@@ -628,6 +689,16 @@ int main(int argc, char*argv[])
|
||||
|
||||
if (pf_path) {
|
||||
ofstream out (pf_path);
|
||||
out << "PFORM DUMP NATURES:" << endl;
|
||||
for (map<perm_string,nature_t*>::iterator cur = natures.begin()
|
||||
; cur != natures.end() ; cur ++ ) {
|
||||
pform_dump(out, (*cur).second);
|
||||
}
|
||||
out << "PFORM DUMP DISCIPLINES:" << endl;
|
||||
for (map<perm_string,discipline_t*>::iterator cur = disciplines.begin()
|
||||
; cur != disciplines.end() ; cur ++ ) {
|
||||
pform_dump(out, (*cur).second);
|
||||
}
|
||||
out << "PFORM DUMP MODULES:" << endl;
|
||||
for (map<perm_string,Module*>::iterator mod = pform_modules.begin()
|
||||
; mod != pform_modules.end()
|
||||
@@ -754,6 +825,11 @@ int main(int argc, char*argv[])
|
||||
func(des);
|
||||
}
|
||||
|
||||
if (verbose_flag) {
|
||||
cout << "CALCULATING ISLANDS" << endl;
|
||||
}
|
||||
des->join_islands();
|
||||
|
||||
if (net_path) {
|
||||
if (verbose_flag)
|
||||
cerr<<" dumping netlist to " <<net_path<< "..." <<endl;
|
||||
|
||||
@@ -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>
|
||||
|
||||
+283
-148
@@ -20,6 +20,7 @@
|
||||
# include "config.h"
|
||||
|
||||
# include <iostream>
|
||||
# include <cstdlib>
|
||||
|
||||
/*
|
||||
* This source file contains all the implementations of the Design
|
||||
@@ -31,6 +32,7 @@
|
||||
# include "compiler.h"
|
||||
# include "netmisc.h"
|
||||
# include <sstream>
|
||||
# include "ivl_assert.h"
|
||||
|
||||
Design:: Design()
|
||||
: errors(0), nodes_(0), procs_(0), lcounter_(0)
|
||||
@@ -242,6 +244,260 @@ void Design::evaluate_parameters()
|
||||
(*scope)->evaluate_parameters(this);
|
||||
}
|
||||
|
||||
void NetScope::evaluate_parameter_logic_(Design*des, param_ref_t cur)
|
||||
{
|
||||
long msb = 0;
|
||||
long lsb = 0;
|
||||
bool range_flag = false;
|
||||
|
||||
/* Evaluate the msb expression, if it is present. */
|
||||
if ((*cur).second.msb) {
|
||||
eval_expr((*cur).second.msb);
|
||||
if (! eval_as_long(msb, (*cur).second.msb)) {
|
||||
cerr << (*cur).second.expr->get_fileline()
|
||||
<< ": internal error: "
|
||||
<< "unable to evaluate msb expression "
|
||||
<< "for parameter " << (*cur).first << ": "
|
||||
<< *(*cur).second.msb << endl;
|
||||
des->errors += 1;
|
||||
return;
|
||||
}
|
||||
|
||||
range_flag = true;
|
||||
}
|
||||
|
||||
/* Evaluate the lsb expression, if it is present. */
|
||||
if ((*cur).second.lsb) {
|
||||
eval_expr((*cur).second.lsb);
|
||||
if (! eval_as_long(lsb, (*cur).second.lsb)) {
|
||||
cerr << (*cur).second.expr->get_fileline()
|
||||
<< ": internal error: "
|
||||
<< "unable to evaluate lsb expression "
|
||||
<< "for parameter " << (*cur).first << ": "
|
||||
<< *(*cur).second.lsb << endl;
|
||||
des->errors += 1;
|
||||
return;
|
||||
}
|
||||
|
||||
range_flag = true;
|
||||
}
|
||||
|
||||
|
||||
/* Evaluate the parameter expression, if necessary. */
|
||||
NetExpr*expr = (*cur).second.expr;
|
||||
assert(expr);
|
||||
|
||||
eval_expr(expr);
|
||||
|
||||
/* The eval_expr may delete any replace the expr pointer, so the
|
||||
second.expr value cannot be relied on. Might as well replace
|
||||
it now with the expression that we evaluated. */
|
||||
(*cur).second.expr = expr;
|
||||
|
||||
switch (expr->expr_type()) {
|
||||
case IVL_VT_REAL:
|
||||
if (! dynamic_cast<const NetECReal*>(expr)) {
|
||||
cerr << expr->get_fileline()
|
||||
<< ": internal error: "
|
||||
<< "unable to evaluate real parameter value: "
|
||||
<< *expr << endl;
|
||||
des->errors += 1;
|
||||
return;
|
||||
}
|
||||
break;
|
||||
|
||||
case IVL_VT_LOGIC:
|
||||
case IVL_VT_BOOL:
|
||||
if (! dynamic_cast<const NetEConst*>(expr)) {
|
||||
cerr << expr->get_fileline()
|
||||
<< ": internal error: "
|
||||
<< "unable to evaluate parameter "
|
||||
<< (*cur).first
|
||||
<< " value: " << *expr << endl;
|
||||
des->errors += 1;
|
||||
return;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
cerr << expr->get_fileline()
|
||||
<< ": internal error: "
|
||||
<< "unhandled expression type?" << endl;
|
||||
des->errors += 1;
|
||||
return;
|
||||
}
|
||||
|
||||
/* If the parameter has range information, then make
|
||||
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;
|
||||
|
||||
NetEConst*val = dynamic_cast<NetEConst*>(expr);
|
||||
assert(val);
|
||||
|
||||
verinum value = val->value();
|
||||
|
||||
if (! (value.has_len()
|
||||
&& (value.len() == wid)
|
||||
&& (value.has_sign() == (*cur).second.signed_flag))) {
|
||||
|
||||
verinum tmp (value, wid);
|
||||
tmp.has_sign ( (*cur).second.signed_flag );
|
||||
delete val;
|
||||
val = new NetEConst(tmp);
|
||||
expr = val;
|
||||
}
|
||||
}
|
||||
|
||||
// If there are no value ranges to test the value against,
|
||||
// then we are done.
|
||||
if ((*cur).second.range == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
NetEConst*val = dynamic_cast<NetEConst*>((*cur).second.expr);
|
||||
ivl_assert(*(*cur).second.expr, (*cur).second.expr);
|
||||
ivl_assert(*(*cur).second.expr, val);
|
||||
|
||||
verinum value = val->value();
|
||||
|
||||
bool from_flag = (*cur).second.range == 0? true : false;
|
||||
for (range_t*value_range = (*cur).second.range
|
||||
; value_range ; value_range = value_range->next) {
|
||||
|
||||
// If we already know that the value is
|
||||
// within a "from" range, then do not test
|
||||
// any more of the from ranges.
|
||||
if (from_flag && value_range->exclude_flag==false)
|
||||
continue;
|
||||
|
||||
if (value_range->low_expr) {
|
||||
NetEConst*tmp = dynamic_cast<NetEConst*>(value_range->low_expr);
|
||||
ivl_assert(*value_range->low_expr, tmp);
|
||||
if (value_range->low_open_flag && value <= tmp->value())
|
||||
continue;
|
||||
else if (value < tmp->value())
|
||||
continue;
|
||||
}
|
||||
|
||||
if (value_range->high_expr) {
|
||||
NetEConst*tmp = dynamic_cast<NetEConst*>(value_range->high_expr);
|
||||
ivl_assert(*value_range->high_expr, tmp);
|
||||
if (value_range->high_open_flag && value >= tmp->value())
|
||||
continue;
|
||||
else if (value > tmp->value())
|
||||
continue;
|
||||
}
|
||||
|
||||
// Within the range. If this is a "from"
|
||||
// range, then set the from_flag and continue.
|
||||
if (value_range->exclude_flag == false) {
|
||||
from_flag = true;
|
||||
continue;
|
||||
}
|
||||
|
||||
// OH NO! In an excluded range. signal an error.
|
||||
from_flag = false;
|
||||
break;
|
||||
}
|
||||
|
||||
// If we found no from range that contains the
|
||||
// value, then report an error.
|
||||
if (! from_flag) {
|
||||
cerr << val->get_fileline() << ": error: "
|
||||
<< "Parameter value " << value
|
||||
<< " is out of range for parameter " << (*cur).first
|
||||
<< "." << endl;
|
||||
des->errors += 1;
|
||||
}
|
||||
}
|
||||
|
||||
void NetScope::evaluate_parameter_real_(Design*des, param_ref_t cur)
|
||||
{
|
||||
NetExpr*expr = (*cur).second.expr;
|
||||
assert(expr);
|
||||
|
||||
NetECReal*res = 0;
|
||||
eval_expr(expr);
|
||||
|
||||
switch (expr->expr_type()) {
|
||||
case IVL_VT_REAL:
|
||||
if (NetECReal*tmp = dynamic_cast<NetECReal*>(expr)) {
|
||||
res = tmp;
|
||||
} else {
|
||||
ivl_assert(*expr, 0);
|
||||
}
|
||||
break;
|
||||
|
||||
case IVL_VT_LOGIC:
|
||||
case IVL_VT_BOOL:
|
||||
if (NetEConst*tmp = dynamic_cast<NetEConst*>(expr)) {
|
||||
verireal val (tmp->value().as_long());
|
||||
res = new NetECReal(val);
|
||||
res->set_line(*tmp);
|
||||
} else {
|
||||
ivl_assert(*expr, 0);
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
ivl_assert(*expr, 0);
|
||||
break;
|
||||
}
|
||||
|
||||
(*cur).second.expr = res;
|
||||
double value = res->value().as_double();
|
||||
|
||||
bool from_flag = (*cur).second.range == 0? true : false;
|
||||
for (range_t*value_range = (*cur).second.range
|
||||
; value_range ; value_range = value_range->next) {
|
||||
|
||||
if (from_flag && value_range->exclude_flag==false)
|
||||
continue;
|
||||
|
||||
if (value_range->low_expr) {
|
||||
double tmp;
|
||||
bool flag = eval_as_double(tmp, value_range->low_expr);
|
||||
ivl_assert(*value_range->low_expr, flag);
|
||||
if (value_range->low_open_flag && value <= tmp)
|
||||
continue;
|
||||
else if (value < tmp)
|
||||
continue;
|
||||
}
|
||||
|
||||
if (value_range->high_expr) {
|
||||
double tmp;
|
||||
bool flag = eval_as_double(tmp, value_range->high_expr);
|
||||
ivl_assert(*value_range->high_expr, flag);
|
||||
if (value_range->high_open_flag && value >= tmp)
|
||||
continue;
|
||||
else if (value > tmp)
|
||||
continue;
|
||||
}
|
||||
|
||||
if (value_range->exclude_flag == false) {
|
||||
from_flag = true;
|
||||
continue;
|
||||
}
|
||||
|
||||
// All the above tests failed, so we must have tripped
|
||||
// an exclude rule.
|
||||
from_flag = false;
|
||||
break;
|
||||
}
|
||||
|
||||
if (! from_flag) {
|
||||
cerr << res->get_fileline() << ": error: "
|
||||
<< "Parameter value " << value
|
||||
<< " is out of range for parameter " << (*cur).first
|
||||
<< "." << endl;
|
||||
des->errors += 1;
|
||||
}
|
||||
}
|
||||
|
||||
void NetScope::evaluate_parameters(Design*des)
|
||||
{
|
||||
NetScope*cur = sub_;
|
||||
@@ -256,161 +512,29 @@ void NetScope::evaluate_parameters(Design*des)
|
||||
// scanning code. Now the parameter expression can be fully
|
||||
// evaluated, or it cannot be evaluated at all.
|
||||
|
||||
typedef map<perm_string,param_expr_t>::iterator mparm_it_t;
|
||||
|
||||
for (mparm_it_t cur = parameters.begin()
|
||||
for (param_ref_t cur = parameters.begin()
|
||||
; cur != parameters.end() ; cur ++) {
|
||||
|
||||
long msb = 0;
|
||||
long lsb = 0;
|
||||
bool range_flag = false;
|
||||
NetExpr*expr;
|
||||
|
||||
/* Evaluate the msb expression, if it is present. */
|
||||
expr = (*cur).second.msb;
|
||||
|
||||
if (expr) {
|
||||
|
||||
NetEConst*tmp = dynamic_cast<NetEConst*>(expr);
|
||||
|
||||
if (! tmp) {
|
||||
|
||||
NetExpr*nexpr = expr->eval_tree();
|
||||
if (nexpr == 0) {
|
||||
cerr << (*cur).second.expr->get_fileline()
|
||||
<< ": internal error: "
|
||||
<< "unable to evaluate msb expression "
|
||||
<< "for parameter " << (*cur).first << ": "
|
||||
<< *expr << endl;
|
||||
des->errors += 1;
|
||||
continue;
|
||||
}
|
||||
|
||||
assert(nexpr);
|
||||
delete expr;
|
||||
(*cur).second.msb = nexpr;
|
||||
|
||||
tmp = dynamic_cast<NetEConst*>(nexpr);
|
||||
}
|
||||
|
||||
assert(tmp);
|
||||
msb = tmp->value().as_long();
|
||||
range_flag = true;
|
||||
}
|
||||
|
||||
/* Evaluate the lsb expression, if it is present. */
|
||||
expr = (*cur).second.lsb;
|
||||
if (expr) {
|
||||
|
||||
NetEConst*tmp = dynamic_cast<NetEConst*>(expr);
|
||||
|
||||
if (! tmp) {
|
||||
|
||||
NetExpr*nexpr = expr->eval_tree();
|
||||
if (nexpr == 0) {
|
||||
cerr << (*cur).second.expr->get_fileline()
|
||||
<< ": internal error: "
|
||||
<< "unable to evaluate lsb expression "
|
||||
<< "for parameter " << (*cur).first << ": "
|
||||
<< *expr << endl;
|
||||
des->errors += 1;
|
||||
continue;
|
||||
}
|
||||
|
||||
assert(nexpr);
|
||||
delete expr;
|
||||
(*cur).second.lsb = nexpr;
|
||||
|
||||
tmp = dynamic_cast<NetEConst*>(nexpr);
|
||||
}
|
||||
|
||||
assert(tmp);
|
||||
lsb = tmp->value().as_long();
|
||||
|
||||
assert(range_flag);
|
||||
}
|
||||
|
||||
|
||||
/* Evaluate the parameter expression, if necessary. */
|
||||
expr = (*cur).second.expr;
|
||||
assert(expr);
|
||||
|
||||
switch (expr->expr_type()) {
|
||||
case IVL_VT_REAL:
|
||||
if (! dynamic_cast<const NetECReal*>(expr)) {
|
||||
|
||||
NetExpr*nexpr = expr->eval_tree();
|
||||
if (nexpr == 0) {
|
||||
cerr << (*cur).second.expr->get_fileline()
|
||||
<< ": internal error: "
|
||||
<< "unable to evaluate real parameter value: "
|
||||
<< *expr << endl;
|
||||
des->errors += 1;
|
||||
continue;
|
||||
}
|
||||
|
||||
assert(nexpr);
|
||||
delete expr;
|
||||
(*cur).second.expr = nexpr;
|
||||
}
|
||||
switch ((*cur).second.type) {
|
||||
case IVL_VT_BOOL:
|
||||
case IVL_VT_LOGIC:
|
||||
evaluate_parameter_logic_(des, cur);
|
||||
break;
|
||||
|
||||
case IVL_VT_LOGIC:
|
||||
case IVL_VT_BOOL:
|
||||
if (! dynamic_cast<const NetEConst*>(expr)) {
|
||||
|
||||
// Try to evaluate the expression.
|
||||
NetExpr*nexpr = expr->eval_tree();
|
||||
if (nexpr == 0) {
|
||||
cerr << (*cur).second.expr->get_fileline()
|
||||
<< ": internal error: "
|
||||
<< "unable to evaluate parameter "
|
||||
<< (*cur).first
|
||||
<< " value: " <<
|
||||
*expr << endl;
|
||||
des->errors += 1;
|
||||
continue;
|
||||
}
|
||||
|
||||
// The evaluate worked, replace the old
|
||||
// expression with this constant value.
|
||||
assert(nexpr);
|
||||
delete expr;
|
||||
(*cur).second.expr = nexpr;
|
||||
}
|
||||
case IVL_VT_REAL:
|
||||
evaluate_parameter_real_(des, cur);
|
||||
break;
|
||||
|
||||
default:
|
||||
cerr << (*cur).second.expr->get_fileline()
|
||||
<< ": internal error: "
|
||||
<< "unhandled expression type?" << endl;
|
||||
des->errors += 1;
|
||||
continue;
|
||||
}
|
||||
|
||||
/* If the parameter has range information, then make
|
||||
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;
|
||||
|
||||
NetEConst*val = dynamic_cast<NetEConst*>((*cur).second.expr);
|
||||
assert(val);
|
||||
|
||||
verinum value = val->value();
|
||||
|
||||
if (! (value.has_len()
|
||||
&& (value.len() == wid)
|
||||
&& (value.has_sign() == (*cur).second.signed_flag))) {
|
||||
|
||||
verinum tmp (value, wid);
|
||||
tmp.has_sign ( (*cur).second.signed_flag );
|
||||
delete val;
|
||||
val = new NetEConst(tmp);
|
||||
(*cur).second.expr = val;
|
||||
}
|
||||
cerr << (*cur).second.get_fileline() << ": internal error: "
|
||||
<< "Unexpected expression type " << (*cur).second.type
|
||||
<< "." << endl;
|
||||
cerr << (*cur).second.get_fileline() << ": : "
|
||||
<< "Parameter name: " << (*cur).first << endl;
|
||||
cerr << (*cur).second.get_fileline() << ": : "
|
||||
<< "Expression is: " << *(*cur).second.expr << endl;
|
||||
ivl_assert((*cur).second, 0);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -553,3 +677,14 @@ void Design::delete_process(NetProcTop*top)
|
||||
delete top;
|
||||
}
|
||||
|
||||
void Design::join_islands(void)
|
||||
{
|
||||
if (nodes_ == 0)
|
||||
return;
|
||||
|
||||
NetNode*cur = nodes_->node_next_;
|
||||
do {
|
||||
join_island(cur);
|
||||
cur = cur->node_next_;
|
||||
} while (cur != nodes_->node_next_);
|
||||
}
|
||||
|
||||
+34
-4
@@ -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)
|
||||
{
|
||||
@@ -456,7 +476,12 @@ NetEParam::NetEParam()
|
||||
}
|
||||
|
||||
NetEParam::NetEParam(Design*d, NetScope*s, perm_string n)
|
||||
: des_(d), scope_(s), name_(n)
|
||||
: des_(d), scope_(s), reference_(scope_->find_parameter(n))
|
||||
{
|
||||
}
|
||||
|
||||
NetEParam::NetEParam(Design*d, NetScope*s, ref_t ref)
|
||||
: des_(d), scope_(s), reference_(ref)
|
||||
{
|
||||
}
|
||||
|
||||
@@ -469,9 +494,14 @@ bool NetEParam::has_width() const
|
||||
return false;
|
||||
}
|
||||
|
||||
ivl_variable_type_t NetEParam::expr_type() const
|
||||
{
|
||||
return (*reference_).second.type;
|
||||
}
|
||||
|
||||
NetEParam* NetEParam::dup_expr() const
|
||||
{
|
||||
NetEParam*tmp = new NetEParam(des_, scope_, name_);
|
||||
NetEParam*tmp = new NetEParam(des_, scope_, reference_);
|
||||
tmp->set_line(*this);
|
||||
return tmp;
|
||||
}
|
||||
|
||||
+67
-14
@@ -22,7 +22,9 @@
|
||||
|
||||
# include "netlist.h"
|
||||
# include <cstring>
|
||||
# include <cstdlib>
|
||||
# include <sstream>
|
||||
# include "ivl_assert.h"
|
||||
|
||||
/*
|
||||
* The NetScope class keeps a scope tree organized. Each node of the
|
||||
@@ -78,15 +80,50 @@ 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)
|
||||
ivl_variable_type_t type,
|
||||
NetExpr*msb, NetExpr*lsb, bool signed_flag,
|
||||
NetScope::range_t*range_list,
|
||||
const LineInfo&file_line)
|
||||
{
|
||||
param_expr_t&ref = parameters[key];
|
||||
NetExpr* res = ref.expr;
|
||||
ref.expr = expr;
|
||||
ref.type = type;
|
||||
ref.msb = msb;
|
||||
ref.lsb = lsb;
|
||||
ref.signed_flag = signed_flag;
|
||||
ivl_assert(file_line, ref.range == 0);
|
||||
ref.range = range_list;
|
||||
ref.set_line(file_line);
|
||||
|
||||
ivl_assert(file_line, type != IVL_VT_NO_TYPE);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
@@ -109,29 +146,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,
|
||||
const LineInfo&file_line)
|
||||
{
|
||||
param_expr_t&ref = localparams[key];
|
||||
NetExpr* res = ref.expr;
|
||||
@@ -139,6 +177,7 @@ NetExpr* NetScope::set_localparam(perm_string key, NetExpr*expr)
|
||||
ref.msb = 0;
|
||||
ref.lsb = 0;
|
||||
ref.signed_flag = false;
|
||||
ref.set_line(file_line);
|
||||
return res;
|
||||
}
|
||||
|
||||
@@ -171,6 +210,20 @@ const NetExpr* NetScope::get_parameter(const char* key,
|
||||
|
||||
return 0;
|
||||
}
|
||||
map<perm_string,NetScope::param_expr_t>::iterator NetScope::find_parameter(perm_string key)
|
||||
{
|
||||
map<perm_string,param_expr_t>::iterator idx;
|
||||
|
||||
idx = parameters.find(key);
|
||||
if (idx != parameters.end())
|
||||
return idx;
|
||||
|
||||
idx = localparams.find(perm_string::literal(key));
|
||||
if (idx != localparams.end())
|
||||
return idx;
|
||||
|
||||
return (map<perm_string,param_expr_t>::iterator) 0;
|
||||
}
|
||||
|
||||
NetScope::TYPE NetScope::type() const
|
||||
{
|
||||
|
||||
+160
@@ -0,0 +1,160 @@
|
||||
/*
|
||||
* Copyright (c) 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
|
||||
* 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
|
||||
*/
|
||||
|
||||
# include "config.h"
|
||||
|
||||
# include <iostream>
|
||||
|
||||
# include <typeinfo>
|
||||
# include <cstdlib>
|
||||
# include "compiler.h"
|
||||
# include "netlist.h"
|
||||
# include "netmisc.h"
|
||||
# include "ivl_target_priv.h"
|
||||
# include "ivl_assert.h"
|
||||
|
||||
static bool has_enable(ivl_switch_type_t tt)
|
||||
{
|
||||
switch (tt) {
|
||||
case IVL_SW_TRANIF0:
|
||||
case IVL_SW_TRANIF1:
|
||||
case IVL_SW_RTRANIF0:
|
||||
case IVL_SW_RTRANIF1:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
NetTran::NetTran(NetScope*scope, perm_string n, ivl_switch_type_t tt)
|
||||
: NetNode(scope, n, has_enable(tt)? 3 : 2), type_(tt)
|
||||
{
|
||||
pin(0).set_dir(Link::PASSIVE); pin(0).set_name(perm_string::literal("A"), 0);
|
||||
pin(1).set_dir(Link::PASSIVE); pin(1).set_name(perm_string::literal("B"), 0);
|
||||
if (pin_count() == 3) {
|
||||
pin(2).set_dir(Link::INPUT);
|
||||
pin(2).set_name(perm_string::literal("E"), 0);
|
||||
}
|
||||
}
|
||||
|
||||
NetTran::NetTran(NetScope*scope, perm_string n, unsigned wid, unsigned part, unsigned off)
|
||||
: NetNode(scope, n, 2), type_(IVL_SW_TRAN_VP), wid_(wid), part_(part), off_(off)
|
||||
{
|
||||
pin(0).set_dir(Link::PASSIVE); pin(0).set_name(perm_string::literal("A"), 0);
|
||||
pin(1).set_dir(Link::PASSIVE); pin(1).set_name(perm_string::literal("B"), 0);
|
||||
}
|
||||
|
||||
NetTran::~NetTran()
|
||||
{
|
||||
}
|
||||
|
||||
unsigned NetTran::vector_width() const
|
||||
{
|
||||
return wid_;
|
||||
}
|
||||
|
||||
unsigned NetTran::part_width() const
|
||||
{
|
||||
return part_;
|
||||
}
|
||||
|
||||
unsigned NetTran::part_offset() const
|
||||
{
|
||||
return off_;
|
||||
}
|
||||
|
||||
void join_island(NetObj*obj)
|
||||
{
|
||||
IslandBranch*branch = dynamic_cast<IslandBranch*> (obj);
|
||||
|
||||
// If this is not even a branch, then stop now.
|
||||
if (branch == 0)
|
||||
return;
|
||||
|
||||
// If this is a branch, but already given to an island, then
|
||||
// stop.
|
||||
if (branch->island)
|
||||
return;
|
||||
|
||||
list<NetObj*> uncommitted_neighbors;
|
||||
|
||||
// Look for neighboring objects that might already be in
|
||||
// islands. If we find something, then join that island.
|
||||
for (unsigned idx = 0 ; idx < obj->pin_count() ; idx += 1) {
|
||||
Nexus*nex = obj->pin(idx).nexus();
|
||||
for (Link*cur = nex->first_nlink() ; cur ; cur = cur->next_nlink()) {
|
||||
unsigned pin;
|
||||
NetObj*tmp;
|
||||
cur->cur_link(tmp, pin);
|
||||
|
||||
// Skip self.
|
||||
if (tmp == obj)
|
||||
continue;
|
||||
|
||||
// If tmb is not a branch, then skip it.
|
||||
IslandBranch*tmp_branch = dynamic_cast<IslandBranch*> (tmp);
|
||||
if (tmp_branch == 0)
|
||||
continue;
|
||||
|
||||
// If that is an uncommitted branch, then save
|
||||
// it. When I finally choose an island for self,
|
||||
// these branches will be scanned so tha they join
|
||||
// this island as well.
|
||||
if (tmp_branch->island == 0) {
|
||||
uncommitted_neighbors.push_back(tmp);
|
||||
continue;
|
||||
}
|
||||
|
||||
ivl_assert(*obj, branch->island==0 || branch->island==tmp_branch->island);
|
||||
|
||||
// We found an existing island to join. Join it
|
||||
// now. Keep scanning in order to find more neighbors.
|
||||
if (branch->island == 0) {
|
||||
if (debug_elaborate)
|
||||
cerr << obj->get_fileline() << ": debug: "
|
||||
<< "Join brach to existing island." << endl;
|
||||
branch->island = tmp_branch->island;
|
||||
|
||||
} else if (branch->island != tmp_branch->island) {
|
||||
cerr << obj->get_fileline() << ": internal error: "
|
||||
<< "Oops, Found 2 neighboring islands." << endl;
|
||||
ivl_assert(*obj, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// If after all that we did not find an idland to join, then
|
||||
// start the island not and join it.
|
||||
if (branch->island == 0) {
|
||||
branch->island = new ivl_island_s;
|
||||
branch->island->discipline = 0;
|
||||
if (debug_elaborate)
|
||||
cerr << obj->get_fileline() << ": debug: "
|
||||
<< "Create new island for this branch" << endl;
|
||||
}
|
||||
|
||||
// Now scan all the uncommitted neighbors I found. Calling
|
||||
// join_island() on them will cause them to notice me in the
|
||||
// process, and thus they will join my island. This process
|
||||
// will recurse until all the connected branches join this island.
|
||||
for (list<NetObj*>::iterator cur = uncommitted_neighbors.begin()
|
||||
; cur != uncommitted_neighbors.end() ; cur ++ ) {
|
||||
join_island(*cur);
|
||||
}
|
||||
}
|
||||
+20
-9
@@ -648,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_;
|
||||
@@ -761,10 +761,6 @@ NetPartSelect::NetPartSelect(NetNet*sig, unsigned off, unsigned wid,
|
||||
pin(0).set_dir(Link::INPUT);
|
||||
pin(1).set_dir(Link::OUTPUT);
|
||||
break;
|
||||
case NetPartSelect::BI:
|
||||
pin(0).set_dir(Link::OUTPUT);
|
||||
pin(1).set_dir(Link::OUTPUT);
|
||||
break;
|
||||
}
|
||||
pin(0).set_name(perm_string::literal("Part"), 0);
|
||||
pin(1).set_name(perm_string::literal("Vect"), 0);
|
||||
@@ -787,10 +783,6 @@ NetPartSelect::NetPartSelect(NetNet*sig, NetNet*sel,
|
||||
pin(0).set_dir(Link::INPUT);
|
||||
pin(1).set_dir(Link::OUTPUT);
|
||||
break;
|
||||
case NetPartSelect::BI:
|
||||
pin(0).set_dir(Link::PASSIVE);
|
||||
pin(1).set_dir(Link::PASSIVE);
|
||||
break;
|
||||
}
|
||||
pin(2).set_dir(Link::INPUT);
|
||||
|
||||
@@ -1046,6 +1038,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:
|
||||
@@ -2294,6 +2304,7 @@ NetEUnary::NetEUnary(char op, NetExpr*ex)
|
||||
switch (op_) {
|
||||
case '-':
|
||||
case '+':
|
||||
case 'm': // abs()
|
||||
cast_signed(ex->has_sign());
|
||||
break;
|
||||
default:
|
||||
|
||||
@@ -49,8 +49,10 @@ class ostream;
|
||||
class Design;
|
||||
class Link;
|
||||
class Nexus;
|
||||
class NetEvent;
|
||||
class NetNet;
|
||||
class NetNode;
|
||||
class NetObj;
|
||||
class NetProc;
|
||||
class NetProcTop;
|
||||
class NetRelease;
|
||||
@@ -60,6 +62,7 @@ class NetExpr;
|
||||
class NetESignal;
|
||||
class NetFuncDef;
|
||||
class NetRamDq;
|
||||
class NetTaskDef;
|
||||
class NetEvTrig;
|
||||
class NetEvWait;
|
||||
|
||||
@@ -69,6 +72,8 @@ struct functor_t;
|
||||
|
||||
ostream& operator << (ostream&o, ivl_variable_type_t val);
|
||||
|
||||
extern void join_island(NetObj*obj);
|
||||
|
||||
/* =========
|
||||
* A NetObj is anything that has any kind of behavior in the
|
||||
* netlist. Nodes can be gates, registers, etc. and are linked
|
||||
@@ -129,6 +134,20 @@ class NetObj : public Attrib, public virtual LineInfo {
|
||||
const NetExpr* delay3_;
|
||||
};
|
||||
|
||||
/*
|
||||
* Objects that can be island branches are derived from this. (It is
|
||||
* possible for an object to be a NetObj and an IslandBranch.) This is
|
||||
* used to collect island information about the node.
|
||||
*/
|
||||
|
||||
class IslandBranch {
|
||||
public:
|
||||
IslandBranch() : island(0) { }
|
||||
|
||||
public:
|
||||
struct ivl_island_s* island;
|
||||
};
|
||||
|
||||
class Link {
|
||||
|
||||
friend void connect(Link&, Link&);
|
||||
@@ -510,7 +529,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
|
||||
@@ -578,6 +597,255 @@ class NetNet : public NetObj {
|
||||
vector<class NetDelaySrc*> delay_paths_;
|
||||
};
|
||||
|
||||
/*
|
||||
* This object type is used to contain a logical scope within a
|
||||
* design. The scope doesn't represent any executable hardware, but is
|
||||
* just a handle that netlist processors can use to grab at the design.
|
||||
*/
|
||||
class NetScope : public Attrib {
|
||||
|
||||
public:
|
||||
enum TYPE { MODULE, TASK, FUNC, BEGIN_END, FORK_JOIN, GENBLOCK };
|
||||
|
||||
/* Create a new scope, and attach it to the given parent. The
|
||||
name is expected to have been permallocated. */
|
||||
NetScope(NetScope*up, const hname_t&name, TYPE t);
|
||||
~NetScope();
|
||||
|
||||
/* Rename the scope using the name generated by inserting as
|
||||
many pad characters as required between prefix and suffix
|
||||
to make the name unique in the parent scope. Return false
|
||||
if a unique name couldn't be generated. */
|
||||
bool auto_name(const char* prefix, char pad, const char* suffix);
|
||||
|
||||
/* Parameters exist within a scope, and these methods allow
|
||||
one to manipulate the set. In these cases, the name is the
|
||||
*simple* name of the parameter, the hierarchy is implicit in
|
||||
the scope. The return value from set_parameter is the
|
||||
previous expression, if there was one. */
|
||||
|
||||
struct range_t;
|
||||
NetExpr* set_parameter(perm_string name, NetExpr*val,
|
||||
ivl_variable_type_t type,
|
||||
NetExpr*msb, NetExpr*lsb, bool signed_flag,
|
||||
NetScope::range_t*range_list,
|
||||
const LineInfo&file_line);
|
||||
NetExpr* set_localparam(perm_string name, NetExpr*val,
|
||||
const LineInfo&file_line);
|
||||
|
||||
const NetExpr*get_parameter(const char* name,
|
||||
const NetExpr*&msb,
|
||||
const NetExpr*&lsb) const;
|
||||
|
||||
/* These are used by defparam elaboration to replace the
|
||||
expression with a new expression, without affecting the
|
||||
range or signed_flag. Return false if the name does not
|
||||
exist. */
|
||||
bool replace_parameter(perm_string name, NetExpr*val);
|
||||
|
||||
/* These methods set or access events that live in this
|
||||
scope. */
|
||||
|
||||
void add_event(NetEvent*);
|
||||
void rem_event(NetEvent*);
|
||||
NetEvent*find_event(perm_string name);
|
||||
|
||||
|
||||
/* These methods manage signals. The add_ and rem_signal
|
||||
methods are used by the NetNet objects to make themselves
|
||||
available to the scope, and the find_signal method can be
|
||||
used to locate signals within a scope. */
|
||||
|
||||
void add_signal(NetNet*);
|
||||
void rem_signal(NetNet*);
|
||||
NetNet* find_signal(perm_string name);
|
||||
|
||||
/* The parent and child() methods allow users of NetScope
|
||||
objects to locate nearby scopes. */
|
||||
NetScope* parent();
|
||||
NetScope* child(const hname_t&name);
|
||||
const NetScope* parent() const;
|
||||
const NetScope* child(const hname_t&name) const;
|
||||
|
||||
TYPE type() const;
|
||||
|
||||
void set_task_def(NetTaskDef*);
|
||||
void set_func_def(NetFuncDef*);
|
||||
void set_module_name(perm_string);
|
||||
|
||||
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;
|
||||
const NetFuncDef* func_def() const;
|
||||
|
||||
/* If the scope represents a module instance, the module_name
|
||||
is the name of the module itself. */
|
||||
perm_string module_name() const;
|
||||
|
||||
/* Scopes have their own time units and time precision. The
|
||||
unit and precision are given as power of 10, i.e., -3 is
|
||||
units of milliseconds.
|
||||
|
||||
If a NetScope is created with a parent scope, the new scope
|
||||
will initially inherit the unit and precision of the
|
||||
parent scope. */
|
||||
|
||||
void time_unit(int);
|
||||
void time_precision(int);
|
||||
|
||||
int time_unit() const;
|
||||
int time_precision() const;
|
||||
|
||||
void default_nettype(NetNet::Type);
|
||||
NetNet::Type default_nettype() const;
|
||||
|
||||
/* The fullname of the scope is the hierarchical name
|
||||
component (which includes the name and array index) whereas
|
||||
the basename is just my name. */
|
||||
perm_string basename() const;
|
||||
const hname_t& fullname() const { return name_; }
|
||||
|
||||
void run_defparams(class Design*);
|
||||
void evaluate_parameters(class Design*);
|
||||
|
||||
/* This method generates a non-hierarchical name that is
|
||||
guaranteed to be unique within this scope. */
|
||||
perm_string local_symbol();
|
||||
|
||||
void dump(ostream&) const;
|
||||
void emit_scope(struct target_t*tgt) const;
|
||||
bool emit_defs(struct target_t*tgt) const;
|
||||
|
||||
/* This method runs the functor on me. Recurse through the
|
||||
children of this node as well. */
|
||||
void run_functor(Design*des, functor_t*fun);
|
||||
|
||||
|
||||
/* This member is used during elaboration to pass defparam
|
||||
assignments from the scope pass to the parameter evaluation
|
||||
step. After that, it is not used. */
|
||||
|
||||
map<pform_name_t,NetExpr*>defparams;
|
||||
|
||||
public:
|
||||
struct range_t {
|
||||
bool exclude_flag;
|
||||
// Lower bound
|
||||
bool low_open_flag;
|
||||
NetExpr*low_expr;
|
||||
// Upper bound
|
||||
bool high_open_flag;
|
||||
NetExpr*high_expr;
|
||||
// Link to the next range specification
|
||||
struct range_t*next;
|
||||
};
|
||||
|
||||
/* After everything is all set up, the code generators like
|
||||
access to these things to make up the parameter lists. */
|
||||
struct param_expr_t : public LineInfo {
|
||||
param_expr_t() : type(IVL_VT_NO_TYPE), range(0) { }
|
||||
// Type information
|
||||
ivl_variable_type_t type;
|
||||
bool signed_flag;
|
||||
NetExpr*msb;
|
||||
NetExpr*lsb;
|
||||
// range constraints
|
||||
struct range_t*range;
|
||||
// Expression value
|
||||
NetExpr*expr;
|
||||
};
|
||||
map<perm_string,param_expr_t>parameters;
|
||||
map<perm_string,param_expr_t>localparams;
|
||||
|
||||
typedef map<perm_string,param_expr_t>::iterator param_ref_t;
|
||||
|
||||
param_ref_t find_parameter(perm_string name);
|
||||
|
||||
|
||||
struct spec_val_t {
|
||||
ivl_variable_type_t type;
|
||||
union {
|
||||
double real_val; // type == IVL_VT_REAL
|
||||
long integer; // type == IVL_VT_BOOL
|
||||
};
|
||||
};
|
||||
map<perm_string,spec_val_t>specparams;
|
||||
|
||||
/* Module instance arrays are collected here for access during
|
||||
the multiple elaboration passes. */
|
||||
typedef svector<NetScope*> scope_vec_t;
|
||||
map<perm_string, scope_vec_t>instance_arrays;
|
||||
|
||||
/* Loop generate uses this as scratch space during
|
||||
elaboration. Expression evaluation can use this to match
|
||||
names. */
|
||||
perm_string genvar_tmp;
|
||||
long genvar_tmp_val;
|
||||
|
||||
private:
|
||||
void evaluate_parameter_logic_(Design*des, param_ref_t cur);
|
||||
void evaluate_parameter_real_(Design*des, param_ref_t cur);
|
||||
|
||||
private:
|
||||
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_;
|
||||
|
||||
NetEvent *events_;
|
||||
NetNet *signals_;
|
||||
perm_string module_name_;
|
||||
union {
|
||||
NetTaskDef*task_;
|
||||
NetFuncDef*func_;
|
||||
};
|
||||
|
||||
NetScope*up_;
|
||||
NetScope*sib_;
|
||||
NetScope*sub_;
|
||||
|
||||
unsigned lcounter_;
|
||||
};
|
||||
|
||||
/*
|
||||
* 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
|
||||
@@ -1108,6 +1376,33 @@ class NetSysFunc : public NetNode {
|
||||
const struct sfunc_return_type*def_;
|
||||
};
|
||||
|
||||
class NetTran : public NetNode, public IslandBranch {
|
||||
|
||||
public:
|
||||
// Tran devices other then TRAN_VP
|
||||
NetTran(NetScope*scope, perm_string n, ivl_switch_type_t type);
|
||||
// Create a TRAN_VP
|
||||
NetTran(NetScope*scope, perm_string n, unsigned wid,
|
||||
unsigned part, unsigned off);
|
||||
~NetTran();
|
||||
|
||||
ivl_switch_type_t type() const { return type_; }
|
||||
|
||||
// These are only used for IVL_SW_TRAN_PV
|
||||
unsigned vector_width() const;
|
||||
unsigned part_width() const;
|
||||
unsigned part_offset() const;
|
||||
|
||||
virtual void dump_node(ostream&, unsigned ind) const;
|
||||
virtual bool emit_node(struct target_t*) const;
|
||||
|
||||
private:
|
||||
ivl_switch_type_t type_;
|
||||
unsigned wid_;
|
||||
unsigned part_;
|
||||
unsigned off_;
|
||||
};
|
||||
|
||||
/* =========
|
||||
* There are cases where expressions need to be represented. The
|
||||
* NetExpr class is the root of a hierarchy that serves that purpose.
|
||||
@@ -1322,8 +1617,8 @@ class NetECRealParam : public NetECReal {
|
||||
* selector as the input.
|
||||
*
|
||||
* The NetPartSelect can be output from the signal (i.e. reading a
|
||||
* part), input into the signal, or bi-directional. The DIR method
|
||||
* gives the type of the node.
|
||||
* part) or input into the signal. The DIR method gives the type of
|
||||
* the node.
|
||||
*
|
||||
* VP (Vector-to-Part)
|
||||
* Output pin 0 is the part select, and input pin 1 is connected to
|
||||
@@ -1333,10 +1628,6 @@ class NetECRealParam : public NetECReal {
|
||||
* Output pin 1 is connected to the NetNet, and input pin 0 is the
|
||||
* part select. In this case, the node is driving the NetNet.
|
||||
*
|
||||
* BI (BI-directional)
|
||||
* Pin 0 is the part select and pin 1 is connected to the NetNet, but
|
||||
* the ports are intended to be bi-directional.
|
||||
*
|
||||
* Note that whatever the direction that data is intended to flow,
|
||||
* pin-0 is the part select and pin-1 is connected to the NetNet.
|
||||
*/
|
||||
@@ -1344,7 +1635,7 @@ class NetPartSelect : public NetNode {
|
||||
|
||||
public:
|
||||
// enum for the device direction
|
||||
enum dir_t { VP, PV, BI };
|
||||
enum dir_t { VP, PV};
|
||||
|
||||
explicit NetPartSelect(NetNet*sig,
|
||||
unsigned off, unsigned wid, dir_t dir);
|
||||
@@ -2664,6 +2955,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 {
|
||||
|
||||
@@ -2831,6 +3124,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.
|
||||
@@ -2965,6 +3276,7 @@ class NetEParam : public NetExpr {
|
||||
virtual bool set_width(unsigned w, bool last_chance);
|
||||
virtual bool has_width() const;
|
||||
virtual void expr_scan(struct expr_scan_t*) const;
|
||||
virtual ivl_variable_type_t expr_type() const;
|
||||
virtual NetExpr* eval_tree(int prune_to_width = -1);
|
||||
virtual NetEParam* dup_expr() const;
|
||||
|
||||
@@ -2973,7 +3285,10 @@ class NetEParam : public NetExpr {
|
||||
private:
|
||||
Design*des_;
|
||||
NetScope*scope_;
|
||||
perm_string name_;
|
||||
typedef map<perm_string,NetScope::param_expr_t>::iterator ref_t;
|
||||
ref_t reference_;
|
||||
|
||||
NetEParam(class Design*des, NetScope*scope, ref_t ref);
|
||||
};
|
||||
|
||||
|
||||
@@ -3143,6 +3458,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 {
|
||||
|
||||
@@ -3245,188 +3561,6 @@ class NetESignal : public NetExpr {
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
* This object type is used to contain a logical scope within a
|
||||
* design. The scope doesn't represent any executable hardware, but is
|
||||
* just a handle that netlist processors can use to grab at the design.
|
||||
*/
|
||||
class NetScope : public Attrib {
|
||||
|
||||
public:
|
||||
enum TYPE { MODULE, TASK, FUNC, BEGIN_END, FORK_JOIN, GENBLOCK };
|
||||
|
||||
/* Create a new scope, and attach it to the given parent. The
|
||||
name is expected to have been permallocated. */
|
||||
NetScope(NetScope*up, const hname_t&name, TYPE t);
|
||||
~NetScope();
|
||||
|
||||
/* Rename the scope using the name generated by inserting as
|
||||
many pad characters as required between prefix and suffix
|
||||
to make the name unique in the parent scope. Return false
|
||||
if a unique name couldn't be generated. */
|
||||
bool auto_name(const char* prefix, char pad, const char* suffix);
|
||||
|
||||
/* Parameters exist within a scope, and these methods allow
|
||||
one to manipulate the set. In these cases, the name is the
|
||||
*simple* name of the parameter, the hierarchy is implicit in
|
||||
the scope. The return value from set_parameter is the
|
||||
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);
|
||||
|
||||
const NetExpr*get_parameter(const char* name,
|
||||
const NetExpr*&msb,
|
||||
const NetExpr*&lsb) const;
|
||||
|
||||
/* These are used by defparam elaboration to replace the
|
||||
expression with a new expression, without affecting the
|
||||
range or signed_flag. Return false if the name does not
|
||||
exist. */
|
||||
bool replace_parameter(perm_string name, NetExpr*val);
|
||||
|
||||
/* These methods set or access events that live in this
|
||||
scope. */
|
||||
|
||||
void add_event(NetEvent*);
|
||||
void rem_event(NetEvent*);
|
||||
NetEvent*find_event(perm_string name);
|
||||
|
||||
|
||||
/* These methods manage signals. The add_ and rem_signal
|
||||
methods are used by the NetNet objects to make themselves
|
||||
available to the scope, and the find_signal method can be
|
||||
used to locate signals within a scope. */
|
||||
|
||||
void add_signal(NetNet*);
|
||||
void rem_signal(NetNet*);
|
||||
NetNet* find_signal(perm_string name);
|
||||
|
||||
/* The parent and child() methods allow users of NetScope
|
||||
objects to locate nearby scopes. */
|
||||
NetScope* parent();
|
||||
NetScope* child(const hname_t&name);
|
||||
const NetScope* parent() const;
|
||||
const NetScope* child(const hname_t&name) const;
|
||||
|
||||
TYPE type() const;
|
||||
|
||||
void set_task_def(NetTaskDef*);
|
||||
void set_func_def(NetFuncDef*);
|
||||
void set_module_name(perm_string);
|
||||
|
||||
NetTaskDef* task_def();
|
||||
NetFuncDef* func_def();
|
||||
|
||||
bool in_func();
|
||||
|
||||
const NetTaskDef* task_def() const;
|
||||
const NetFuncDef* func_def() const;
|
||||
|
||||
/* If the scope represents a module instance, the module_name
|
||||
is the name of the module itself. */
|
||||
perm_string module_name() const;
|
||||
|
||||
/* Scopes have their own time units and time precision. The
|
||||
unit and precision are given as power of 10, i.e., -3 is
|
||||
units of milliseconds.
|
||||
|
||||
If a NetScope is created with a parent scope, the new scope
|
||||
will initially inherit the unit and precision of the
|
||||
parent scope. */
|
||||
|
||||
void time_unit(int);
|
||||
void time_precision(int);
|
||||
|
||||
int time_unit() const;
|
||||
int time_precision() const;
|
||||
|
||||
void default_nettype(NetNet::Type);
|
||||
NetNet::Type default_nettype() const;
|
||||
|
||||
/* The fullname of the scope is the hierarchical name
|
||||
component (which includes the name and array index) whereas
|
||||
the basename is just my name. */
|
||||
perm_string basename() const;
|
||||
const hname_t& fullname() const { return name_; }
|
||||
|
||||
void run_defparams(class Design*);
|
||||
void evaluate_parameters(class Design*);
|
||||
|
||||
/* This method generates a non-hierarchical name that is
|
||||
guaranteed to be unique within this scope. */
|
||||
perm_string local_symbol();
|
||||
|
||||
void dump(ostream&) const;
|
||||
void emit_scope(struct target_t*tgt) const;
|
||||
bool emit_defs(struct target_t*tgt) const;
|
||||
|
||||
/* This method runs the functor on me. Recurse through the
|
||||
children of this node as well. */
|
||||
void run_functor(Design*des, functor_t*fun);
|
||||
|
||||
|
||||
/* This member is used during elaboration to pass defparam
|
||||
assignments from the scope pass to the parameter evaluation
|
||||
step. After that, it is not used. */
|
||||
|
||||
map<pform_name_t,NetExpr*>defparams;
|
||||
|
||||
public:
|
||||
/* After everything is all set up, the code generators like
|
||||
access to these things to make up the parameter lists. */
|
||||
struct param_expr_t {
|
||||
NetExpr*expr;
|
||||
NetExpr*msb;
|
||||
NetExpr*lsb;
|
||||
bool signed_flag;
|
||||
};
|
||||
map<perm_string,param_expr_t>parameters;
|
||||
map<perm_string,param_expr_t>localparams;
|
||||
|
||||
struct spec_val_t {
|
||||
ivl_variable_type_t type;
|
||||
union {
|
||||
double real_val; // type == IVL_VT_REAL
|
||||
long integer; // type == IVL_VT_BOOL
|
||||
};
|
||||
};
|
||||
map<perm_string,spec_val_t>specparams;
|
||||
|
||||
/* Module instance arrays are collected here for access during
|
||||
the multiple elaboration passes. */
|
||||
typedef svector<NetScope*> scope_vec_t;
|
||||
map<perm_string, scope_vec_t>instance_arrays;
|
||||
|
||||
/* Loop generate uses this as scratch space during
|
||||
elaboration. Expression evaluation can use this to match
|
||||
names. */
|
||||
perm_string genvar_tmp;
|
||||
long genvar_tmp_val;
|
||||
|
||||
private:
|
||||
TYPE type_;
|
||||
hname_t name_;
|
||||
|
||||
signed char time_unit_, time_prec_;
|
||||
NetNet::Type default_nettype_;
|
||||
|
||||
NetEvent *events_;
|
||||
NetNet *signals_;
|
||||
perm_string module_name_;
|
||||
union {
|
||||
NetTaskDef*task_;
|
||||
NetFuncDef*func_;
|
||||
};
|
||||
|
||||
NetScope*up_;
|
||||
NetScope*sib_;
|
||||
NetScope*sub_;
|
||||
|
||||
unsigned lcounter_;
|
||||
};
|
||||
|
||||
/*
|
||||
* This class contains an entire design. It includes processes and a
|
||||
* netlist, and can be passed around from function to function.
|
||||
@@ -3504,6 +3638,7 @@ class Design {
|
||||
// Iterate over the design...
|
||||
void dump(ostream&) const;
|
||||
void functor(struct functor_t*);
|
||||
void join_islands(void);
|
||||
int emit(struct target_t*) const;
|
||||
|
||||
// This is incremented by elaboration when an error is
|
||||
|
||||
+22
@@ -123,6 +123,13 @@ NetExpr* make_sub_expr(long val, NetExpr*expr)
|
||||
return res;
|
||||
}
|
||||
|
||||
NetEConst* make_const_x(unsigned long wid)
|
||||
{
|
||||
verinum xxx (verinum::Vx, wid);
|
||||
NetEConst*resx = new NetEConst(xxx);
|
||||
return resx;
|
||||
}
|
||||
|
||||
NetExpr* condition_reduce(NetExpr*expr)
|
||||
{
|
||||
if (expr->expr_width() == 1)
|
||||
@@ -182,6 +189,21 @@ bool eval_as_long(long&value, NetExpr*expr)
|
||||
return false;
|
||||
}
|
||||
|
||||
bool eval_as_double(double&value, NetExpr*expr)
|
||||
{
|
||||
if (NetEConst*tmp = dynamic_cast<NetEConst*>(expr) ) {
|
||||
value = tmp->value().as_long();
|
||||
return true;
|
||||
}
|
||||
|
||||
if (NetECReal*rtmp = dynamic_cast<NetECReal*>(expr)) {
|
||||
value = rtmp->value().as_double();
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
std::list<hname_t> eval_scope_path(Design*des, NetScope*scope,
|
||||
const pform_name_t&path)
|
||||
{
|
||||
|
||||
@@ -102,6 +102,11 @@ extern NetNet*add_to_net(Design*des, NetNet*sig, long val);
|
||||
extern NetExpr*make_add_expr(NetExpr*expr, long val);
|
||||
extern NetExpr*make_sub_expr(long val, NetExpr*expr);
|
||||
|
||||
/*
|
||||
* Make a NetEConst object that contains only X bits.
|
||||
*/
|
||||
extern NetEConst*make_const_x(unsigned long wid);
|
||||
|
||||
/*
|
||||
* In some cases the lval is accessible as a pointer to the head of
|
||||
* a list of NetAssign_ objects. This function returns the width of
|
||||
@@ -138,6 +143,7 @@ void eval_expr(NetExpr*&expr, int prune_width =-1);
|
||||
* down to a constant) then return false and leave value unchanged.
|
||||
*/
|
||||
bool eval_as_long(long&value, NetExpr*expr);
|
||||
bool eval_as_double(double&value, NetExpr*expr);
|
||||
|
||||
extern std::list<hname_t> eval_scope_path(Design*des, NetScope*scope,
|
||||
const pform_name_t&path);
|
||||
|
||||
@@ -35,8 +35,9 @@ class PSpecPath;
|
||||
extern void lex_start_table();
|
||||
extern void lex_end_table();
|
||||
|
||||
static svector<PExpr*>* active_range = 0;
|
||||
static bool active_signed = false;
|
||||
static svector<PExpr*>* param_active_range = 0;
|
||||
static bool param_active_signed = false;
|
||||
static ivl_variable_type_t param_active_type = IVL_VT_LOGIC;
|
||||
|
||||
/* Port declaration lists use this structure for context. */
|
||||
static struct {
|
||||
@@ -94,12 +95,6 @@ static list<perm_string>* list_from_identifier(list<perm_string>*tmp, char*id)
|
||||
return tmp;
|
||||
}
|
||||
|
||||
static inline void FILE_NAME(LineInfo*tmp, const struct vlltype&where)
|
||||
{
|
||||
tmp->set_lineno(where.first_line);
|
||||
tmp->set_file(filename_strings.make(where.text));
|
||||
}
|
||||
|
||||
static svector<PExpr*>* copy_range(svector<PExpr*>* orig)
|
||||
{
|
||||
svector<PExpr*>*copy = 0;
|
||||
@@ -113,6 +108,27 @@ static svector<PExpr*>* copy_range(svector<PExpr*>* orig)
|
||||
return copy;
|
||||
}
|
||||
|
||||
/*
|
||||
* This is a shorthand for making a PECallFunction that takes a single
|
||||
* arg. This is used by some of the code that detects built-ins.
|
||||
*/
|
||||
static PECallFunction*make_call_function(perm_string tn, PExpr*arg)
|
||||
{
|
||||
svector<PExpr*> parms(1);
|
||||
parms[0] = arg;
|
||||
PECallFunction*tmp = new PECallFunction(tn, parms);
|
||||
return tmp;
|
||||
}
|
||||
|
||||
static PECallFunction*make_call_function(perm_string tn, PExpr*arg1, PExpr*arg2)
|
||||
{
|
||||
svector<PExpr*> parms(2);
|
||||
parms[0] = arg1;
|
||||
parms[1] = arg2;
|
||||
PECallFunction*tmp = new PECallFunction(tn, parms);
|
||||
return tmp;
|
||||
}
|
||||
|
||||
%}
|
||||
|
||||
%union {
|
||||
@@ -126,6 +142,8 @@ static svector<PExpr*>* copy_range(svector<PExpr*>* orig)
|
||||
list<perm_string>*perm_strings;
|
||||
pform_name_t*pform_name;
|
||||
|
||||
discipline_t*discipline;
|
||||
|
||||
hname_t*hier;
|
||||
|
||||
list<string>*strings;
|
||||
@@ -139,6 +157,7 @@ static svector<PExpr*>* copy_range(svector<PExpr*>* orig)
|
||||
svector<lgate>*gates;
|
||||
|
||||
Module::port_t *mport;
|
||||
Module::range_t* value_range;
|
||||
svector<Module::port_t*>*mports;
|
||||
|
||||
named_pexpr_t*named_pexpr;
|
||||
@@ -175,37 +194,50 @@ static svector<PExpr*>* copy_range(svector<PExpr*>* orig)
|
||||
};
|
||||
|
||||
%token <text> IDENTIFIER SYSTEM_IDENTIFIER STRING
|
||||
%token <discipline> DISCIPLINE_IDENTIFIER
|
||||
%token <text> PATHPULSE_IDENTIFIER
|
||||
%token <number> BASED_NUMBER DEC_NUMBER
|
||||
%token <realtime> REALTIME
|
||||
%token K_LE K_GE K_EG K_EQ K_NE K_CEQ K_CNE K_LS K_RS K_RSS K_SG
|
||||
/* K_CONTRIBUTE is <+, the contribution assign. */
|
||||
%token K_CONTRIBUTE
|
||||
%token K_PO_POS K_PO_NEG K_POW
|
||||
%token K_PSTAR K_STARP
|
||||
%token K_LOR K_LAND K_NAND K_NOR K_NXOR K_TRIGGER
|
||||
%token K_abs K_abstol K_access K_acos K_acosh K_asin K_analog K_asinh
|
||||
%token K_atan K_atanh K_atan2
|
||||
%token K_always K_and K_assign K_begin K_bool K_buf K_bufif0 K_bufif1 K_case
|
||||
%token K_casex K_casez K_cmos K_deassign K_default K_defparam K_disable
|
||||
%token K_edge K_edge_descriptor
|
||||
%token K_else K_end K_endcase K_endfunction K_endgenerate K_endmodule
|
||||
%token K_endprimitive K_endspecify K_endtable K_endtask K_event K_for
|
||||
%token K_force K_forever K_fork K_function K_generate K_genvar
|
||||
%token K_highz0 K_highz1 K_if K_ifnone
|
||||
%token K_initial K_inout K_input K_integer K_join K_large K_localparam
|
||||
%token K_logic K_macromodule
|
||||
%token K_medium K_module K_nand K_negedge K_nmos K_nor K_not K_notif0
|
||||
%token K_notif1 K_or K_output K_parameter K_pmos K_posedge K_primitive
|
||||
%token K_casex K_casez K_ceil K_cmos K_continuous K_cos K_cosh
|
||||
%token K_ddt_nature K_deassign K_default K_defparam K_disable K_discrete
|
||||
%token K_domain K_edge K_edge_descriptor K_discipline
|
||||
%token K_else K_end K_endcase K_enddiscipline K_endfunction K_endgenerate
|
||||
%token K_endmodule K_endnature
|
||||
%token K_endprimitive K_endspecify K_endtable K_endtask K_event
|
||||
%token K_exclude K_exp K_floor K_flow K_from
|
||||
%token K_for K_force K_forever K_fork K_function K_generate K_genvar
|
||||
%token K_ground K_highz0 K_highz1 K_hypot K_idt_nature K_if K_ifnone K_inf
|
||||
%token K_initial K_inout K_input K_integer K_join K_large K_ln K_localparam
|
||||
%token K_log K_logic K_macromodule K_max
|
||||
%token K_medium K_min K_module K_nand K_nature K_negedge
|
||||
%token K_nmos K_nor K_not K_notif0
|
||||
%token K_notif1 K_or K_output K_parameter K_pmos K_posedge K_potential
|
||||
%token K_pow K_primitive
|
||||
%token K_pull0 K_pull1 K_pulldown K_pullup K_rcmos K_real K_realtime
|
||||
%token K_reg K_release K_repeat
|
||||
%token K_rnmos K_rpmos K_rtran K_rtranif0 K_rtranif1 K_scalared
|
||||
%token K_signed K_small K_specify
|
||||
%token K_specparam K_strong0 K_strong1 K_supply0 K_supply1 K_table K_task
|
||||
%token K_signed K_sin K_sinh K_small K_specify
|
||||
%token K_specparam K_sqrt K_string K_strong0 K_strong1 K_supply0 K_supply1
|
||||
%token K_table
|
||||
%token K_tan K_tanh K_task
|
||||
%token K_time K_tran K_tranif0 K_tranif1 K_tri K_tri0 K_tri1 K_triand
|
||||
%token K_trior K_trireg K_vectored K_wait K_wand K_weak0 K_weak1
|
||||
%token K_trior K_trireg K_units K_vectored K_wait K_wand K_weak0 K_weak1
|
||||
%token K_while K_wire
|
||||
%token K_wone K_wor K_xnor K_xor
|
||||
%token K_Shold K_Speriod K_Srecovery K_Srecrem K_Ssetup K_Swidth K_Ssetuphold
|
||||
|
||||
%token KK_attribute
|
||||
|
||||
%type <flag> from_exclude
|
||||
%type <number> number
|
||||
%type <flag> signed_opt udp_reg_opt edge_operator
|
||||
%type <drive> drive_strength drive_strength_opt dr_strength0 dr_strength1
|
||||
@@ -227,6 +259,9 @@ static svector<PExpr*>* copy_range(svector<PExpr*>* orig)
|
||||
%type <mport> port port_opt port_reference port_reference_list
|
||||
%type <mport> port_declaration
|
||||
%type <mports> list_of_ports module_port_list_opt list_of_port_declarations
|
||||
%type <value_range> parameter_value_range parameter_value_ranges
|
||||
%type <value_range> parameter_value_ranges_opt
|
||||
%type <expr> value_range_expression
|
||||
|
||||
%type <wires> task_item task_item_list task_item_list_opt
|
||||
%type <wires> task_port_item task_port_decl task_port_decl_list
|
||||
@@ -288,10 +323,15 @@ static svector<PExpr*>* copy_range(svector<PExpr*>* orig)
|
||||
%left K_POW
|
||||
%left UNARY_PREC
|
||||
|
||||
|
||||
/* to resolve dangling else ambiguity. */
|
||||
%nonassoc less_than_K_else
|
||||
%nonassoc K_else
|
||||
|
||||
/* to resolve exclude (... ambiguity */
|
||||
%nonassoc '('
|
||||
%nonassoc K_exclude
|
||||
|
||||
%%
|
||||
|
||||
/* A degenerate source file can be completely empty. */
|
||||
@@ -631,15 +671,71 @@ delay_value_simple
|
||||
;
|
||||
|
||||
description
|
||||
: module
|
||||
| udp_primitive
|
||||
| KK_attribute '(' IDENTIFIER ',' STRING ',' STRING ')'
|
||||
{ perm_string tmp3 = lex_strings.make($3);
|
||||
pform_set_type_attrib(tmp3, $5, $7);
|
||||
delete[]$3;
|
||||
delete $5;
|
||||
}
|
||||
;
|
||||
: module
|
||||
| udp_primitive
|
||||
| nature_declaration
|
||||
| discipline_declaration
|
||||
| KK_attribute '(' IDENTIFIER ',' STRING ',' STRING ')'
|
||||
{ perm_string tmp3 = lex_strings.make($3);
|
||||
pform_set_type_attrib(tmp3, $5, $7);
|
||||
delete[]$3;
|
||||
delete $5;
|
||||
}
|
||||
;
|
||||
|
||||
/* The discipline and nature declarations used to take no ';' after
|
||||
the identifier. The 2.3 LRM adds the ';', but since there are
|
||||
programs written to the 2.1 and 2.2 standard that don't, we
|
||||
choose to make the ';' optional in this context. */
|
||||
optional_semicolon : ';' | ;
|
||||
|
||||
discipline_declaration
|
||||
: K_discipline IDENTIFIER optional_semicolon
|
||||
{ pform_start_discipline($2); }
|
||||
discipline_items K_enddiscipline
|
||||
{ pform_end_discipline(@1); delete[] $2; }
|
||||
;
|
||||
|
||||
discipline_items
|
||||
: discipline_items discipline_item
|
||||
| discipline_item
|
||||
;
|
||||
|
||||
discipline_item
|
||||
: K_domain K_discrete ';'
|
||||
{ pform_discipline_domain(@1, DD_DISCRETE); }
|
||||
| K_domain K_continuous ';'
|
||||
{ pform_discipline_domain(@1, DD_CONTINUOUS); }
|
||||
| K_potential IDENTIFIER ';'
|
||||
{ pform_discipline_potential(@1, $2); delete[] $2; }
|
||||
| K_flow IDENTIFIER ';'
|
||||
{ pform_discipline_flow(@1, $2); delete[] $2; }
|
||||
;
|
||||
|
||||
nature_declaration
|
||||
: K_nature IDENTIFIER optional_semicolon
|
||||
{ pform_start_nature($2); }
|
||||
nature_items
|
||||
K_endnature
|
||||
{ pform_end_nature(@1); delete[] $2; }
|
||||
;
|
||||
|
||||
nature_items
|
||||
: nature_items nature_item
|
||||
| nature_item
|
||||
;
|
||||
|
||||
nature_item
|
||||
: K_units '=' STRING ';'
|
||||
{ delete[] $3; }
|
||||
| K_abstol '=' expression ';'
|
||||
| K_access '=' IDENTIFIER ';'
|
||||
{ pform_nature_access(@1, $3); delete[] $3; }
|
||||
| K_idt_nature '=' IDENTIFIER ';'
|
||||
{ delete[] $3; }
|
||||
| K_ddt_nature '=' IDENTIFIER ';'
|
||||
{ delete[] $3; }
|
||||
;
|
||||
|
||||
drive_strength
|
||||
: '(' dr_strength0 ',' dr_strength1 ')'
|
||||
@@ -749,6 +845,15 @@ event_expression
|
||||
}
|
||||
;
|
||||
|
||||
/* A branch probe expression applies a probe function (potential or
|
||||
flow) to a branch. The branch may be implicit as a pair of nets
|
||||
or explicit as a named branch. Elaboration will check that the
|
||||
function name really is a nature attribute identifier. */
|
||||
branch_probe_expression
|
||||
: IDENTIFIER '(' IDENTIFIER ',' IDENTIFIER ')'
|
||||
| IDENTIFIER '(' IDENTIFIER ')'
|
||||
;
|
||||
|
||||
expression
|
||||
: expr_primary
|
||||
{ $$ = $1; }
|
||||
@@ -1066,19 +1171,191 @@ expr_primary
|
||||
function call. If a system identifier, then a system function
|
||||
call. */
|
||||
|
||||
| hierarchy_identifier '(' expression_list_proper ')'
|
||||
{ PECallFunction*tmp = new PECallFunction(*$1, *$3);
|
||||
FILE_NAME(tmp, @1);
|
||||
delete $1;
|
||||
$$ = tmp;
|
||||
}
|
||||
| SYSTEM_IDENTIFIER '(' expression_list_proper ')'
|
||||
{ perm_string tn = lex_strings.make($1);
|
||||
PECallFunction*tmp = new PECallFunction(tn, *$3);
|
||||
FILE_NAME(tmp, @1);
|
||||
delete[]$1;
|
||||
$$ = tmp;
|
||||
}
|
||||
| hierarchy_identifier '(' expression_list_proper ')'
|
||||
{ PECallFunction*tmp = new PECallFunction(*$1, *$3);
|
||||
FILE_NAME(tmp, @1);
|
||||
delete $1;
|
||||
$$ = tmp;
|
||||
}
|
||||
| SYSTEM_IDENTIFIER '(' expression_list_proper ')'
|
||||
{ perm_string tn = lex_strings.make($1);
|
||||
PECallFunction*tmp = new PECallFunction(tn, *$3);
|
||||
FILE_NAME(tmp, @1);
|
||||
delete[]$1;
|
||||
$$ = tmp;
|
||||
}
|
||||
|
||||
/* Many of the VAMS built-in functions are available as builtin
|
||||
functions with $system_function equivilents. */
|
||||
|
||||
| K_acos '(' expression ')'
|
||||
{ perm_string tn = perm_string::literal("$acos");
|
||||
PECallFunction*tmp = make_call_function(tn, $3);
|
||||
FILE_NAME(tmp,@1);
|
||||
$$ = tmp;
|
||||
}
|
||||
|
||||
| K_acosh '(' expression ')'
|
||||
{ perm_string tn = perm_string::literal("$acosh");
|
||||
PECallFunction*tmp = make_call_function(tn, $3);
|
||||
FILE_NAME(tmp,@1);
|
||||
$$ = tmp;
|
||||
}
|
||||
|
||||
| K_asin '(' expression ')'
|
||||
{ perm_string tn = perm_string::literal("$asin");
|
||||
PECallFunction*tmp = make_call_function(tn, $3);
|
||||
FILE_NAME(tmp,@1);
|
||||
$$ = tmp;
|
||||
}
|
||||
|
||||
| K_asinh '(' expression ')'
|
||||
{ perm_string tn = perm_string::literal("$asinh");
|
||||
PECallFunction*tmp = make_call_function(tn, $3);
|
||||
FILE_NAME(tmp,@1);
|
||||
$$ = tmp;
|
||||
}
|
||||
|
||||
| K_atan '(' expression ')'
|
||||
{ perm_string tn = perm_string::literal("$atan");
|
||||
PECallFunction*tmp = make_call_function(tn, $3);
|
||||
FILE_NAME(tmp,@1);
|
||||
$$ = tmp;
|
||||
}
|
||||
|
||||
| K_atanh '(' expression ')'
|
||||
{ perm_string tn = perm_string::literal("$atanh");
|
||||
PECallFunction*tmp = make_call_function(tn, $3);
|
||||
FILE_NAME(tmp,@1);
|
||||
$$ = tmp;
|
||||
}
|
||||
|
||||
| K_atan2 '(' expression ',' expression ')'
|
||||
{ perm_string tn = perm_string::literal("$atan2");
|
||||
PECallFunction*tmp = make_call_function(tn, $3, $5);
|
||||
FILE_NAME(tmp,@1);
|
||||
$$ = tmp;
|
||||
}
|
||||
|
||||
| K_ceil '(' expression ')'
|
||||
{ perm_string tn = perm_string::literal("$ceil");
|
||||
PECallFunction*tmp = make_call_function(tn, $3);
|
||||
FILE_NAME(tmp,@1);
|
||||
$$ = tmp;
|
||||
}
|
||||
|
||||
| K_cos '(' expression ')'
|
||||
{ perm_string tn = perm_string::literal("$cos");
|
||||
PECallFunction*tmp = make_call_function(tn, $3);
|
||||
FILE_NAME(tmp,@1);
|
||||
$$ = tmp;
|
||||
}
|
||||
|
||||
| K_cosh '(' expression ')'
|
||||
{ perm_string tn = perm_string::literal("$cosh");
|
||||
PECallFunction*tmp = make_call_function(tn, $3);
|
||||
FILE_NAME(tmp,@1);
|
||||
$$ = tmp;
|
||||
}
|
||||
|
||||
| K_exp '(' expression ')'
|
||||
{ perm_string tn = perm_string::literal("$exp");
|
||||
PECallFunction*tmp = make_call_function(tn, $3);
|
||||
FILE_NAME(tmp,@1);
|
||||
$$ = tmp;
|
||||
}
|
||||
|
||||
| K_floor '(' expression ')'
|
||||
{ perm_string tn = perm_string::literal("$floor");
|
||||
PECallFunction*tmp = make_call_function(tn, $3);
|
||||
FILE_NAME(tmp,@1);
|
||||
$$ = tmp;
|
||||
}
|
||||
|
||||
| K_hypot '(' expression ',' expression ')'
|
||||
{ perm_string tn = perm_string::literal("$hypot");
|
||||
PECallFunction*tmp = make_call_function(tn, $3, $5);
|
||||
FILE_NAME(tmp,@1);
|
||||
$$ = tmp;
|
||||
}
|
||||
|
||||
| K_ln '(' expression ')'
|
||||
{ perm_string tn = perm_string::literal("$ln");
|
||||
PECallFunction*tmp = make_call_function(tn, $3);
|
||||
FILE_NAME(tmp,@1);
|
||||
$$ = tmp;
|
||||
}
|
||||
|
||||
| K_log '(' expression ')'
|
||||
{ perm_string tn = perm_string::literal("$log10");
|
||||
PECallFunction*tmp = make_call_function(tn, $3);
|
||||
FILE_NAME(tmp,@1);
|
||||
$$ = tmp;
|
||||
}
|
||||
|
||||
| K_pow '(' expression ',' expression ')'
|
||||
{ perm_string tn = perm_string::literal("$pow");
|
||||
PECallFunction*tmp = make_call_function(tn, $3, $5);
|
||||
FILE_NAME(tmp,@1);
|
||||
$$ = tmp;
|
||||
}
|
||||
|
||||
| K_sin '(' expression ')'
|
||||
{ perm_string tn = perm_string::literal("$sin");
|
||||
PECallFunction*tmp = make_call_function(tn, $3);
|
||||
FILE_NAME(tmp,@1);
|
||||
$$ = tmp;
|
||||
}
|
||||
|
||||
| K_sinh '(' expression ')'
|
||||
{ perm_string tn = perm_string::literal("$sinh");
|
||||
PECallFunction*tmp = make_call_function(tn, $3);
|
||||
FILE_NAME(tmp,@1);
|
||||
$$ = tmp;
|
||||
}
|
||||
|
||||
| K_sqrt '(' expression ')'
|
||||
{ perm_string tn = perm_string::literal("$sqrt");
|
||||
PECallFunction*tmp = make_call_function(tn, $3);
|
||||
FILE_NAME(tmp,@1);
|
||||
$$ = tmp;
|
||||
}
|
||||
|
||||
| K_tan '(' expression ')'
|
||||
{ perm_string tn = perm_string::literal("$tan");
|
||||
PECallFunction*tmp = make_call_function(tn, $3);
|
||||
FILE_NAME(tmp,@1);
|
||||
$$ = tmp;
|
||||
}
|
||||
|
||||
| K_tanh '(' expression ')'
|
||||
{ perm_string tn = perm_string::literal("$tanh");
|
||||
PECallFunction*tmp = make_call_function(tn, $3);
|
||||
FILE_NAME(tmp,@1);
|
||||
$$ = tmp;
|
||||
}
|
||||
|
||||
/* These mathematical functions are conveniently expressed as unary
|
||||
and binary expressions. They behave much like unary/binary
|
||||
operators, even though they are parsed as functions. */
|
||||
|
||||
| K_abs '(' expression ')'
|
||||
{ PEUnary*tmp = new PEUnary('m', $3);
|
||||
FILE_NAME(tmp,@1);
|
||||
$$ = tmp;
|
||||
}
|
||||
|
||||
| K_max '(' expression ',' expression ')'
|
||||
{ PEBinary*tmp = new PEBinary('M', $3, $5);
|
||||
FILE_NAME(tmp,@1);
|
||||
$$ = tmp;
|
||||
}
|
||||
|
||||
| K_min '(' expression ',' expression ')'
|
||||
{ PEBinary*tmp = new PEBinary('m', $3, $5);
|
||||
FILE_NAME(tmp,@1);
|
||||
$$ = tmp;
|
||||
}
|
||||
|
||||
/* Parenthesized expressions are primaries. */
|
||||
|
||||
@@ -1706,6 +1983,12 @@ module_item
|
||||
yyerrok;
|
||||
}
|
||||
|
||||
/* Maybe this is a discipline declaration? If so, then the lexor
|
||||
will see the discipline name as an identifier. We match it to the
|
||||
discipline or type name semantically. */
|
||||
| DISCIPLINE_IDENTIFIER list_of_identifiers ';'
|
||||
{ pform_attach_discipline(@1, $1, $2); }
|
||||
|
||||
/* block_item_decl rule is shared with task blocks and named
|
||||
begin/end. */
|
||||
|
||||
@@ -1785,16 +2068,16 @@ module_item
|
||||
|
||||
/* Always and initial items are behavioral processes. */
|
||||
|
||||
| attribute_list_opt K_always statement
|
||||
{ PProcess*tmp = pform_make_behavior(PProcess::PR_ALWAYS,
|
||||
$3, $1);
|
||||
FILE_NAME(tmp, @2);
|
||||
}
|
||||
| attribute_list_opt K_initial statement
|
||||
{ PProcess*tmp = pform_make_behavior(PProcess::PR_INITIAL,
|
||||
$3, $1);
|
||||
FILE_NAME(tmp, @2);
|
||||
}
|
||||
| attribute_list_opt K_always statement
|
||||
{ PProcess*tmp = pform_make_behavior(PProcess::PR_ALWAYS, $3, $1);
|
||||
FILE_NAME(tmp, @2);
|
||||
}
|
||||
| attribute_list_opt K_initial statement
|
||||
{ PProcess*tmp = pform_make_behavior(PProcess::PR_INITIAL, $3, $1);
|
||||
FILE_NAME(tmp, @2);
|
||||
}
|
||||
|
||||
| attribute_list_opt K_analog analog_statement
|
||||
|
||||
/* The task declaration rule matches the task declaration
|
||||
header, then pushes the function scope. This causes the
|
||||
@@ -1891,7 +2174,7 @@ module_item
|
||||
| K_generate module_item_list_opt K_endgenerate
|
||||
|
||||
| K_genvar list_of_identifiers ';'
|
||||
{ pform_genvars($2); }
|
||||
{ pform_genvars(@1, $2); }
|
||||
|
||||
| K_for '(' IDENTIFIER '=' expression ';'
|
||||
expression ';'
|
||||
@@ -2079,23 +2362,48 @@ var_type
|
||||
generates a type (optional) and a list of assignments. */
|
||||
|
||||
parameter_assign_decl
|
||||
: parameter_assign_list
|
||||
| range { active_range = $1; active_signed = false; }
|
||||
parameter_assign_list
|
||||
{ active_range = 0;
|
||||
active_signed = false;
|
||||
}
|
||||
| K_signed range { active_range = $2; active_signed = true; }
|
||||
parameter_assign_list
|
||||
{ active_range = 0;
|
||||
active_signed = false;
|
||||
}
|
||||
| K_integer { active_range = 0; active_signed = true; }
|
||||
parameter_assign_list
|
||||
{ active_range = 0;
|
||||
active_signed = false;
|
||||
}
|
||||
;
|
||||
: parameter_assign_list
|
||||
| range
|
||||
{ param_active_range = $1;
|
||||
param_active_signed = false;
|
||||
param_active_type = IVL_VT_LOGIC;
|
||||
}
|
||||
parameter_assign_list
|
||||
{ param_active_range = 0;
|
||||
param_active_signed = false;
|
||||
param_active_type = IVL_VT_LOGIC;
|
||||
}
|
||||
| K_signed range
|
||||
{ param_active_range = $2;
|
||||
param_active_signed = true;
|
||||
param_active_type = IVL_VT_LOGIC;
|
||||
}
|
||||
parameter_assign_list
|
||||
{ param_active_range = 0;
|
||||
param_active_signed = false;
|
||||
param_active_type = IVL_VT_LOGIC;
|
||||
}
|
||||
| K_integer
|
||||
{ param_active_range = 0;
|
||||
param_active_signed = true;
|
||||
param_active_type = IVL_VT_LOGIC;
|
||||
}
|
||||
parameter_assign_list
|
||||
{ param_active_range = 0;
|
||||
param_active_signed = false;
|
||||
param_active_type = IVL_VT_LOGIC;
|
||||
}
|
||||
| K_real
|
||||
{ param_active_range = 0;
|
||||
param_active_signed = true;
|
||||
param_active_type = IVL_VT_REAL;
|
||||
}
|
||||
parameter_assign_list
|
||||
{ param_active_range = 0;
|
||||
param_active_signed = false;
|
||||
param_active_type = IVL_VT_LOGIC;
|
||||
}
|
||||
;
|
||||
|
||||
parameter_assign_list
|
||||
: parameter_assign
|
||||
@@ -2103,21 +2411,44 @@ parameter_assign_list
|
||||
;
|
||||
|
||||
parameter_assign
|
||||
: IDENTIFIER '=' expression
|
||||
{ PExpr*tmp = $3;
|
||||
if (!pform_expression_is_constant(tmp)) {
|
||||
yyerror(@3, "error: parameter value "
|
||||
"must be a constant expression.");
|
||||
delete tmp;
|
||||
tmp = 0;
|
||||
} else {
|
||||
pform_set_parameter(lex_strings.make($1),
|
||||
active_signed,
|
||||
active_range, tmp);
|
||||
}
|
||||
delete[]$1;
|
||||
}
|
||||
;
|
||||
: IDENTIFIER '=' expression parameter_value_ranges_opt
|
||||
{ PExpr*tmp = $3;
|
||||
pform_set_parameter(@1, lex_strings.make($1), param_active_type,
|
||||
param_active_signed, param_active_range, tmp, $4);
|
||||
delete[]$1;
|
||||
}
|
||||
;
|
||||
|
||||
parameter_value_ranges_opt : parameter_value_ranges { $$ = $1; } | { $$ = 0; } ;
|
||||
|
||||
parameter_value_ranges
|
||||
: parameter_value_ranges parameter_value_range
|
||||
{ $$ = $2; $$->next = $1; }
|
||||
| parameter_value_range
|
||||
{ $$ = $1; $$->next = 0; }
|
||||
;
|
||||
|
||||
parameter_value_range
|
||||
: from_exclude '[' value_range_expression ':' value_range_expression ']'
|
||||
{ $$ = pform_parameter_value_range($1, false, $3, false, $5); }
|
||||
| from_exclude '[' value_range_expression ':' value_range_expression ')'
|
||||
{ $$ = pform_parameter_value_range($1, false, $3, true, $5); }
|
||||
| from_exclude '(' value_range_expression ':' value_range_expression ']'
|
||||
{ $$ = pform_parameter_value_range($1, true, $3, false, $5); }
|
||||
| from_exclude '(' value_range_expression ':' value_range_expression ')'
|
||||
{ $$ = pform_parameter_value_range($1, true, $3, true, $5); }
|
||||
| K_exclude expression
|
||||
{ $$ = pform_parameter_value_range(true, false, $2, false, $2); }
|
||||
;
|
||||
|
||||
value_range_expression
|
||||
: expression { $$ = $1; }
|
||||
| K_inf { $$ = 0; }
|
||||
| '+' K_inf { $$ = 0; }
|
||||
| '-' K_inf { $$ = 0; }
|
||||
;
|
||||
|
||||
from_exclude : K_from { $$ = false; } | K_exclude { $$ = true; } ;
|
||||
|
||||
/* Localparam assignments and assignment lists are broken into
|
||||
separate BNF so that I can call slightly different parameter
|
||||
@@ -2125,40 +2456,59 @@ parameter_assign
|
||||
behave differently when someone tries to override them. */
|
||||
|
||||
localparam_assign
|
||||
: IDENTIFIER '=' expression
|
||||
{ PExpr*tmp = $3;
|
||||
if (!pform_expression_is_constant(tmp)) {
|
||||
yyerror(@3, "error: parameter value "
|
||||
"must be constant.");
|
||||
delete tmp;
|
||||
tmp = 0;
|
||||
} else {
|
||||
pform_set_localparam(lex_strings.make($1),
|
||||
active_signed,
|
||||
active_range, tmp);
|
||||
}
|
||||
delete[]$1;
|
||||
}
|
||||
;
|
||||
: IDENTIFIER '=' expression
|
||||
{ PExpr*tmp = $3;
|
||||
pform_set_localparam(@1, lex_strings.make($1),
|
||||
param_active_type,
|
||||
param_active_signed,
|
||||
param_active_range, tmp);
|
||||
delete[]$1;
|
||||
}
|
||||
;
|
||||
|
||||
localparam_assign_decl
|
||||
: localparam_assign_list
|
||||
| range { active_range = $1; active_signed = false; }
|
||||
localparam_assign_list
|
||||
{ active_range = 0;
|
||||
active_signed = false;
|
||||
}
|
||||
| K_signed range { active_range = $2; active_signed = true; }
|
||||
localparam_assign_list
|
||||
{ active_range = 0;
|
||||
active_signed = false;
|
||||
}
|
||||
| K_integer { active_range = 0; active_signed = true; }
|
||||
localparam_assign_list
|
||||
{ active_range = 0;
|
||||
active_signed = false;
|
||||
}
|
||||
;
|
||||
: localparam_assign_list
|
||||
| range
|
||||
{ param_active_range = $1;
|
||||
param_active_signed = false;
|
||||
param_active_type = IVL_VT_LOGIC;
|
||||
}
|
||||
localparam_assign_list
|
||||
{ param_active_range = 0;
|
||||
param_active_signed = false;
|
||||
param_active_type = IVL_VT_NO_TYPE;
|
||||
}
|
||||
| K_signed range
|
||||
{ param_active_range = $2;
|
||||
param_active_signed = true;
|
||||
param_active_type = IVL_VT_LOGIC;
|
||||
}
|
||||
localparam_assign_list
|
||||
{ param_active_range = 0;
|
||||
param_active_signed = false;
|
||||
param_active_type = IVL_VT_LOGIC;
|
||||
}
|
||||
| K_integer
|
||||
{ param_active_range = 0;
|
||||
param_active_signed = true;
|
||||
param_active_type = IVL_VT_LOGIC;
|
||||
}
|
||||
localparam_assign_list
|
||||
{ param_active_range = 0;
|
||||
param_active_signed = false;
|
||||
param_active_type = IVL_VT_LOGIC;
|
||||
}
|
||||
| K_real
|
||||
{ param_active_range = 0;
|
||||
param_active_signed = true;
|
||||
param_active_type = IVL_VT_REAL;
|
||||
}
|
||||
localparam_assign_list
|
||||
{ param_active_range = 0;
|
||||
param_active_signed = false;
|
||||
param_active_type = IVL_VT_LOGIC;
|
||||
}
|
||||
;
|
||||
|
||||
localparam_assign_list
|
||||
: localparam_assign
|
||||
@@ -3294,6 +3644,12 @@ statement_or_null
|
||||
| ';' { $$ = 0; }
|
||||
;
|
||||
|
||||
|
||||
analog_statement
|
||||
: branch_probe_expression K_CONTRIBUTE expression ';'
|
||||
{ yyerror(@1, "sorry: Analog contribution statements not supported."); }
|
||||
;
|
||||
|
||||
/* Task items are, other than the statement, task port items and
|
||||
other block items. */
|
||||
task_item
|
||||
|
||||
@@ -23,6 +23,7 @@
|
||||
#endif
|
||||
|
||||
# include <list>
|
||||
# include "compiler.h"
|
||||
# include "pform.h"
|
||||
|
||||
/*
|
||||
@@ -39,6 +40,13 @@ struct vlltype {
|
||||
};
|
||||
# define YYLTYPE struct vlltype
|
||||
|
||||
class LineInfo;
|
||||
inline void FILE_NAME(LineInfo*tmp, const struct vlltype&where)
|
||||
{
|
||||
tmp->set_lineno(where.first_line);
|
||||
tmp->set_file(filename_strings.make(where.text));
|
||||
}
|
||||
|
||||
/* This for compatibility with new and older bison versions. */
|
||||
#ifndef yylloc
|
||||
# define yylloc VLlloc
|
||||
|
||||
@@ -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
|
||||
@@ -27,6 +27,7 @@
|
||||
# include "PUdp.h"
|
||||
# include "PGenerate.h"
|
||||
# include "PSpec.h"
|
||||
# include "discipline.h"
|
||||
# include <list>
|
||||
# include <map>
|
||||
# include <assert.h>
|
||||
@@ -38,7 +39,6 @@
|
||||
|
||||
# include "ivl_assert.h"
|
||||
|
||||
|
||||
map<perm_string,Module*> pform_modules;
|
||||
map<perm_string,PUdp*> pform_primitives;
|
||||
|
||||
@@ -82,12 +82,6 @@ static inline void FILE_NAME(LineInfo*obj, const char*file, unsigned lineno)
|
||||
obj->set_file(filename_strings.make(file));
|
||||
}
|
||||
|
||||
static inline void FILE_NAME(LineInfo*tmp, const struct vlltype&where)
|
||||
{
|
||||
tmp->set_lineno(where.first_line);
|
||||
tmp->set_file(filename_strings.make(where.text));
|
||||
}
|
||||
|
||||
/*
|
||||
* The lexical_scope keeps track of the current lexical scope that is
|
||||
* being parsed. The lexical scope may stack, so the current scope may
|
||||
@@ -137,7 +131,7 @@ PBlock* pform_push_block_scope(char*name, PBlock::BL_TYPE bt)
|
||||
return block;
|
||||
}
|
||||
|
||||
static PWire*get_wire_in_scope(perm_string name)
|
||||
PWire*pform_get_wire_in_scope(perm_string name)
|
||||
{
|
||||
/* Note that if we are processing a generate, then the
|
||||
scope depth will be empty because generate schemes
|
||||
@@ -363,11 +357,13 @@ void pform_endmodule(const char*name)
|
||||
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;
|
||||
@@ -923,7 +919,7 @@ static void pform_set_net_range(perm_string name,
|
||||
ivl_variable_type_t dt,
|
||||
PWSRType rt)
|
||||
{
|
||||
PWire*cur = get_wire_in_scope(name);
|
||||
PWire*cur = pform_get_wire_in_scope(name);
|
||||
if (cur == 0) {
|
||||
VLerror("error: name is not a valid net.");
|
||||
return;
|
||||
@@ -1342,7 +1338,7 @@ void pform_makewire(const vlltype&li, perm_string name,
|
||||
ivl_variable_type_t dt,
|
||||
svector<named_pexpr_t*>*attr)
|
||||
{
|
||||
PWire*cur = get_wire_in_scope(name);
|
||||
PWire*cur = pform_get_wire_in_scope(name);
|
||||
|
||||
// If this is not implicit ("implicit" meaning we don't know
|
||||
// what the type is yet) then set the type now.
|
||||
@@ -1456,7 +1452,7 @@ void pform_makewire(const vlltype&li,
|
||||
SR_NET);
|
||||
}
|
||||
|
||||
PWire*cur = get_wire_in_scope(first->name);
|
||||
PWire*cur = pform_get_wire_in_scope(first->name);
|
||||
if (cur != 0) {
|
||||
PEIdent*lval = new PEIdent(first->name);
|
||||
FILE_NAME(lval, li.text, li.first_line);
|
||||
@@ -1638,44 +1634,76 @@ void pform_set_reg_idx(perm_string name, PExpr*l, PExpr*r)
|
||||
cur->set_memory_idx(l, r);
|
||||
}
|
||||
|
||||
void pform_set_parameter(perm_string name, bool signed_flag,
|
||||
svector<PExpr*>*range, PExpr*expr)
|
||||
Module::range_t* pform_parameter_value_range(bool exclude_flag,
|
||||
bool low_open, PExpr*low_expr,
|
||||
bool hig_open, PExpr*hig_expr)
|
||||
{
|
||||
// Detect +-inf and make the the *_open flags false to force
|
||||
// the range interpretation as inf.
|
||||
if (low_expr == 0) low_open = false;
|
||||
if (hig_expr == 0) hig_open = false;
|
||||
|
||||
Module::range_t*tmp = new Module::range_t;
|
||||
tmp->exclude_flag = exclude_flag;
|
||||
tmp->low_open_flag = low_open;
|
||||
tmp->low_expr = low_expr;
|
||||
tmp->high_open_flag = hig_open;
|
||||
tmp->high_expr = hig_expr;
|
||||
tmp->next = 0;
|
||||
return tmp;
|
||||
}
|
||||
|
||||
void pform_set_parameter(const struct vlltype&loc,
|
||||
perm_string name, ivl_variable_type_t type,
|
||||
bool signed_flag, svector<PExpr*>*range, PExpr*expr,
|
||||
Module::range_t*value_range)
|
||||
{
|
||||
assert(expr);
|
||||
pform_cur_module->parameters[name].expr = expr;
|
||||
Module::param_expr_t&parm = pform_cur_module->parameters[name];
|
||||
FILE_NAME(&parm, loc);
|
||||
|
||||
parm.expr = expr;
|
||||
|
||||
parm.type = type;
|
||||
if (range) {
|
||||
assert(range->count() == 2);
|
||||
assert((*range)[0]);
|
||||
assert((*range)[1]);
|
||||
pform_cur_module->parameters[name].msb = (*range)[0];
|
||||
pform_cur_module->parameters[name].lsb = (*range)[1];
|
||||
parm.msb = (*range)[0];
|
||||
parm.lsb = (*range)[1];
|
||||
} else {
|
||||
pform_cur_module->parameters[name].msb = 0;
|
||||
pform_cur_module->parameters[name].lsb = 0;
|
||||
parm.msb = 0;
|
||||
parm.lsb = 0;
|
||||
}
|
||||
pform_cur_module->parameters[name].signed_flag = signed_flag;
|
||||
parm.signed_flag = signed_flag;
|
||||
parm.range = value_range;
|
||||
|
||||
pform_cur_module->param_names.push_back(name);
|
||||
}
|
||||
|
||||
void pform_set_localparam(perm_string name, bool signed_flag,
|
||||
svector<PExpr*>*range, PExpr*expr)
|
||||
void pform_set_localparam(const struct vlltype&loc,
|
||||
perm_string name, ivl_variable_type_t type,
|
||||
bool signed_flag, svector<PExpr*>*range, PExpr*expr)
|
||||
{
|
||||
assert(expr);
|
||||
pform_cur_module->localparams[name].expr = expr;
|
||||
Module::param_expr_t&parm = pform_cur_module->localparams[name];
|
||||
FILE_NAME(&parm, loc);
|
||||
|
||||
parm.expr = expr;
|
||||
|
||||
parm.type = type;
|
||||
if (range) {
|
||||
assert(range->count() == 2);
|
||||
assert((*range)[0]);
|
||||
assert((*range)[1]);
|
||||
pform_cur_module->localparams[name].msb = (*range)[0];
|
||||
pform_cur_module->localparams[name].lsb = (*range)[1];
|
||||
parm.msb = (*range)[0];
|
||||
parm.lsb = (*range)[1];
|
||||
} else {
|
||||
pform_cur_module->localparams[name].msb = 0;
|
||||
pform_cur_module->localparams[name].lsb = 0;
|
||||
parm.msb = 0;
|
||||
parm.lsb = 0;
|
||||
}
|
||||
pform_cur_module->localparams[name].signed_flag = signed_flag;
|
||||
parm.signed_flag = signed_flag;
|
||||
parm.range = 0;
|
||||
}
|
||||
|
||||
void pform_set_specparam(perm_string name, PExpr*expr)
|
||||
@@ -1925,4 +1953,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"
|
||||
@@ -33,6 +30,7 @@
|
||||
# include "PUdp.h"
|
||||
# include "PWire.h"
|
||||
# include "verinum.h"
|
||||
# include "discipline.h"
|
||||
# include <iostream>
|
||||
# include <string>
|
||||
# include <list>
|
||||
@@ -118,11 +116,19 @@ struct lgate {
|
||||
unsigned lineno;
|
||||
};
|
||||
|
||||
|
||||
/* The lexor calls this function to change the default nettype. */
|
||||
extern void pform_set_default_nettype(NetNet::Type net,
|
||||
const char*file,
|
||||
unsigned lineno);
|
||||
|
||||
/*
|
||||
* Look for the given wire in the current lexical scope. If the wire
|
||||
* (including variables of any type) cannot be found in the current
|
||||
* scope, then return 0.
|
||||
*/
|
||||
extern PWire* pform_get_wire_in_scope(perm_string name);
|
||||
|
||||
/*
|
||||
* The parser uses startmodule and endmodule together to build up a
|
||||
* module as it parses it. The startmodule tells the pform code that a
|
||||
@@ -175,13 +181,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,
|
||||
@@ -260,13 +266,21 @@ extern void pform_set_attrib(perm_string name, perm_string key,
|
||||
extern void pform_set_type_attrib(perm_string name, const string&key,
|
||||
char*value);
|
||||
|
||||
extern void pform_set_parameter(perm_string name,
|
||||
bool signed_flag,
|
||||
svector<PExpr*>*range,
|
||||
PExpr*expr);
|
||||
extern void pform_set_localparam(perm_string name,
|
||||
extern Module::range_t* pform_parameter_value_range(bool exclude_flag,
|
||||
bool low_open, PExpr*low_expr,
|
||||
bool hig_open, PExpr*hig_expr);
|
||||
|
||||
extern void pform_set_parameter(const struct vlltype&loc,
|
||||
perm_string name,
|
||||
ivl_variable_type_t type,
|
||||
bool signed_flag,
|
||||
svector<PExpr*>*range,
|
||||
PExpr*expr, Module::range_t*value_range);
|
||||
extern void pform_set_localparam(const struct vlltype&loc,
|
||||
perm_string name,
|
||||
ivl_variable_type_t type,
|
||||
bool signed_flag,
|
||||
svector<PExpr*>*range,
|
||||
PExpr*expr);
|
||||
extern void pform_set_defparam(const pform_name_t&name, PExpr*expr);
|
||||
|
||||
@@ -351,4 +365,28 @@ extern void pform_dump(ostream&out, Module*mod);
|
||||
*/
|
||||
extern void pform_error_nested_modules();
|
||||
|
||||
/* ** pform_discipline.cc
|
||||
* Functions for handling the parse of natures and disciplines. These
|
||||
* functions are in pform_disciplines.cc
|
||||
*/
|
||||
class discipline_t;
|
||||
|
||||
extern void pform_start_nature(const char*name);
|
||||
extern void pform_end_nature(const struct vlltype&loc);
|
||||
|
||||
extern void pform_nature_access(const struct vlltype&loc, const char*name);
|
||||
|
||||
extern void pform_start_discipline(const char*name);
|
||||
extern void pform_end_discipline(const struct vlltype&loc);
|
||||
|
||||
extern void pform_discipline_domain(const struct vlltype&loc, ddomain_t use_domain);
|
||||
extern void pform_discipline_potential(const struct vlltype&loc, const char*name);
|
||||
extern void pform_discipline_flow(const struct vlltype&loc, const char*name);
|
||||
|
||||
extern void pform_attach_discipline(const struct vlltype&loc,
|
||||
discipline_t*discipline, list<perm_string>*names);
|
||||
|
||||
extern void pform_dump(ostream&out, const nature_t*);
|
||||
extern void pform_dump(ostream&out, const discipline_t*);
|
||||
|
||||
#endif
|
||||
|
||||
@@ -0,0 +1,195 @@
|
||||
/*
|
||||
* Copyright (c) 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
|
||||
* 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
|
||||
*/
|
||||
|
||||
# include "config.h"
|
||||
# include "compiler.h"
|
||||
# include "pform.h"
|
||||
# include "parse_misc.h"
|
||||
# include "discipline.h"
|
||||
|
||||
map<perm_string,nature_t*> natures;
|
||||
map<perm_string,discipline_t*> disciplines;
|
||||
|
||||
static perm_string nature_name = perm_string::perm_string();
|
||||
static perm_string nature_access = perm_string::perm_string();
|
||||
|
||||
void pform_start_nature(const char*name)
|
||||
{
|
||||
nature_name = lex_strings.make(name);
|
||||
}
|
||||
|
||||
void pform_nature_access(const struct vlltype&loc, const char*name)
|
||||
{
|
||||
if (nature_access) {
|
||||
cerr << loc.text << ":" << loc.first_line << ": error: "
|
||||
<< "Too many access names for nature "
|
||||
<< nature_name << "." << endl;
|
||||
error_count += 1;
|
||||
return;
|
||||
}
|
||||
|
||||
nature_access = lex_strings.make(name);
|
||||
}
|
||||
|
||||
void pform_end_nature(const struct vlltype&loc)
|
||||
{
|
||||
// The nature access function is required. If it is missing,
|
||||
// then signal an error. For a temporary expedient, we can set
|
||||
// the nature name as the access function, but don't expect it
|
||||
// to work.
|
||||
if (! nature_access) {
|
||||
cerr << loc.text << ":" << loc.first_line << ": error: "
|
||||
<< "Missing access name for nature "
|
||||
<< nature_name << "." << endl;
|
||||
error_count += 1;
|
||||
nature_access = nature_name;
|
||||
}
|
||||
|
||||
nature_t*tmp = new nature_t(nature_name, nature_access);
|
||||
natures[nature_name] = tmp;
|
||||
|
||||
FILE_NAME(tmp, loc);
|
||||
|
||||
nature_name = perm_string::perm_string();
|
||||
nature_access = perm_string::perm_string();
|
||||
}
|
||||
|
||||
|
||||
static perm_string discipline_name;
|
||||
static ddomain_t discipline_domain = DD_NONE;
|
||||
static nature_t* discipline_potential = 0;
|
||||
static nature_t* discipline_flow = 0;
|
||||
|
||||
void pform_start_discipline(const char*name)
|
||||
{
|
||||
discipline_name = lex_strings.make(name);
|
||||
discipline_domain = DD_NONE;
|
||||
}
|
||||
|
||||
void pform_discipline_domain(const struct vlltype&loc, ddomain_t use_domain)
|
||||
{
|
||||
assert(use_domain != DD_NONE);
|
||||
|
||||
if (discipline_domain != DD_NONE) {
|
||||
cerr << loc.text << ":" << loc.first_line << ": error: "
|
||||
<< "Too many domain attributes for discipline "
|
||||
<< discipline_name << "." << endl;
|
||||
error_count += 1;
|
||||
return;
|
||||
}
|
||||
|
||||
discipline_domain = use_domain;
|
||||
}
|
||||
|
||||
void pform_discipline_potential(const struct vlltype&loc, const char*name)
|
||||
{
|
||||
if (discipline_potential) {
|
||||
cerr << loc.text << ":" << loc.first_line << ": error: "
|
||||
<< "Too many potential natures for discipline "
|
||||
<< discipline_name << "." << endl;
|
||||
error_count += 1;
|
||||
return;
|
||||
}
|
||||
|
||||
perm_string key = lex_strings.make(name);
|
||||
discipline_potential = natures[key];
|
||||
|
||||
if (discipline_potential == 0) {
|
||||
cerr << loc.text << ":" << loc.first_line << ": error: "
|
||||
<< "nature " << key << " is not declared." << endl;
|
||||
error_count += 1;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
void pform_discipline_flow(const struct vlltype&loc, const char*name)
|
||||
{
|
||||
if (discipline_flow) {
|
||||
cerr << loc.text << ":" << loc.first_line << ": error: "
|
||||
<< "Too many flow natures for discipline "
|
||||
<< discipline_name << "." << endl;
|
||||
error_count += 1;
|
||||
return;
|
||||
}
|
||||
|
||||
perm_string key = lex_strings.make(name);
|
||||
discipline_flow = natures[key];
|
||||
|
||||
if (discipline_flow == 0) {
|
||||
cerr << loc.text << ":" << loc.first_line << ": error: "
|
||||
<< "nature " << key << " is not declared." << endl;
|
||||
error_count += 1;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
void pform_end_discipline(const struct vlltype&loc)
|
||||
{
|
||||
// If the domain is not otherwise specified, then take it to
|
||||
// be continuous if potential or flow natures are given.
|
||||
if (discipline_domain == DD_NONE && (discipline_potential||discipline_flow))
|
||||
discipline_domain = DD_CONTINUOUS;
|
||||
|
||||
discipline_t*tmp = new discipline_t(discipline_name, discipline_domain,
|
||||
discipline_potential, discipline_flow);
|
||||
disciplines[discipline_name] = tmp;
|
||||
|
||||
FILE_NAME(tmp, loc);
|
||||
|
||||
/* Clear the static variables for the next item. */
|
||||
discipline_name = perm_string::perm_string();
|
||||
discipline_domain = DD_NONE;
|
||||
discipline_potential = 0;
|
||||
discipline_flow = 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* The parser uses this function to attach a discipline to a wire. The
|
||||
* wire may be declared by now, or will be declared further later. If
|
||||
* it is already declared, we just attach the discipline. If it is not
|
||||
* declared yet, then this is the declaration and we create the signal
|
||||
* in the current lexical scope.
|
||||
*/
|
||||
void pform_attach_discipline(const struct vlltype&loc,
|
||||
discipline_t*discipline, list<perm_string>*names)
|
||||
{
|
||||
for (list<perm_string>::iterator cur = names->begin()
|
||||
; cur != names->end() ; cur ++ ) {
|
||||
|
||||
PWire* cur_net = pform_get_wire_in_scope(*cur);
|
||||
if (cur_net == 0) {
|
||||
/* Not declared yet, declare it now. */
|
||||
pform_makewire(loc, *cur, NetNet::WIRE,
|
||||
NetNet::NOT_A_PORT, IVL_VT_REAL, 0);
|
||||
cur_net = pform_get_wire_in_scope(*cur);
|
||||
assert(cur_net);
|
||||
}
|
||||
|
||||
if (discipline_t*tmp = cur_net->get_discipline()) {
|
||||
cerr << loc.text << ":" << loc.first_line << ": error: "
|
||||
<< "discipline " << discipline->name()
|
||||
<< " cannot override existing discipline " << tmp->name()
|
||||
<< " on net " << cur_net->basename() << endl;
|
||||
error_count += 1;
|
||||
|
||||
} else {
|
||||
cur_net->set_discipline(discipline);
|
||||
}
|
||||
}
|
||||
}
|
||||
+97
-7
@@ -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
|
||||
@@ -29,6 +29,7 @@
|
||||
# include "PEvent.h"
|
||||
# include "PGenerate.h"
|
||||
# include "PSpec.h"
|
||||
# include "discipline.h"
|
||||
# include <iostream>
|
||||
# include <iomanip>
|
||||
# include <typeinfo>
|
||||
@@ -128,6 +129,26 @@ ostream& operator<< (ostream&o, const pform_name_t&that)
|
||||
return o;
|
||||
}
|
||||
|
||||
|
||||
std::ostream& operator << (std::ostream&out, ddomain_t dom)
|
||||
{
|
||||
switch (dom) {
|
||||
case DD_NONE:
|
||||
out << "no-domain";
|
||||
break;
|
||||
case DD_DISCRETE:
|
||||
out << "discrete";
|
||||
break;
|
||||
case DD_CONTINUOUS:
|
||||
out << "continuous";
|
||||
break;
|
||||
default:
|
||||
assert(0);
|
||||
break;
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
void PExpr::dump(ostream&out) const
|
||||
{
|
||||
out << typeid(*this).name();
|
||||
@@ -215,11 +236,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':
|
||||
@@ -281,6 +321,10 @@ void PWire::dump(ostream&out, unsigned ind) const
|
||||
out << " signed";
|
||||
}
|
||||
|
||||
if (discipline_) {
|
||||
out << " discipline<" << discipline_->name() << ">";
|
||||
}
|
||||
|
||||
if (port_set_) {
|
||||
if (port_msb_ == 0) {
|
||||
out << " port<scalar>";
|
||||
@@ -950,7 +994,7 @@ void Module::dump(ostream&out) const
|
||||
typedef map<pform_name_t,PExpr*>::const_iterator parm_hiter_t;
|
||||
for (parm_iter_t cur = parameters.begin()
|
||||
; cur != parameters.end() ; cur ++) {
|
||||
out << " parameter ";
|
||||
out << " parameter " << (*cur).second.type << " ";
|
||||
if ((*cur).second.signed_flag)
|
||||
out << "signed ";
|
||||
if ((*cur).second.msb)
|
||||
@@ -958,9 +1002,38 @@ void Module::dump(ostream&out) const
|
||||
<< *(*cur).second.lsb << "] ";
|
||||
out << (*cur).first << " = ";
|
||||
if ((*cur).second.expr)
|
||||
out << *(*cur).second.expr << ";" << endl;
|
||||
out << *(*cur).second.expr;
|
||||
else
|
||||
out << "/* ERROR */;" << endl;
|
||||
out << "/* ERROR */";
|
||||
for (Module::range_t*tmp = (*cur).second.range
|
||||
; tmp ; tmp = tmp->next) {
|
||||
if (tmp->exclude_flag)
|
||||
out << " exclude ";
|
||||
else
|
||||
out << " from ";
|
||||
if (tmp->low_open_flag)
|
||||
out << "(";
|
||||
else
|
||||
out << "[";
|
||||
if (tmp->low_expr)
|
||||
out << *(tmp->low_expr);
|
||||
else if (tmp->low_open_flag==false)
|
||||
out << "-inf";
|
||||
else
|
||||
out << "<nil>";
|
||||
out << ":";
|
||||
if (tmp->high_expr)
|
||||
out << *(tmp->high_expr);
|
||||
else if (tmp->high_open_flag==false)
|
||||
out << "inf";
|
||||
else
|
||||
out << "<nil>";
|
||||
if (tmp->high_open_flag)
|
||||
out << ")";
|
||||
else
|
||||
out << "]";
|
||||
}
|
||||
out << ";" << endl;
|
||||
}
|
||||
|
||||
for (parm_iter_t cur = localparams.begin()
|
||||
@@ -976,10 +1049,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;
|
||||
@@ -1105,3 +1178,20 @@ void PUdp::dump(ostream&out) const
|
||||
out << "endprimitive" << endl;
|
||||
}
|
||||
|
||||
void pform_dump(std::ostream&out, const nature_t*nat)
|
||||
{
|
||||
out << "nature " << nat->name() << endl;
|
||||
out << " access " << nat->access() << ";" << endl;
|
||||
out << "endnature" << endl;
|
||||
}
|
||||
|
||||
void pform_dump(std::ostream&out, const discipline_t*dis)
|
||||
{
|
||||
out << "discipline " << dis->name() << endl;
|
||||
out << " domain " << dis->domain() << ";" << endl;
|
||||
if (const nature_t*tmp = dis->potential())
|
||||
out << " potential " << tmp->name() << ";" << endl;
|
||||
if (const nature_t*tmp = dis->flow())
|
||||
out << " flow " << tmp->name() << ";" << endl;
|
||||
out << "enddiscipline" << endl;
|
||||
}
|
||||
|
||||
@@ -45,17 +45,17 @@ if [ -e $destdir/$prefix ]; then
|
||||
fi
|
||||
|
||||
echo "Exporting $tag to $destdir/$prefix..."
|
||||
git-archive --prefix="$prefix/" $tag | ( cd "$destdir" ; tar xf - )
|
||||
git-archive --prefix="$prefix/" $tag | ( cd "$destdir" && tar xf - )
|
||||
|
||||
versionh="$destdir/verilog-$id/version.h"
|
||||
versionh="$destdir/$prefix/version.h"
|
||||
echo "Create $versionh ..."
|
||||
echo "#define VERSION_TAG \"$tag\"" > $versionh
|
||||
|
||||
echo "Running autoconf.sh..."
|
||||
( cd $destdir/$prefix ; sh autoconf.sh )
|
||||
( cd $destdir/$prefix && sh autoconf.sh )
|
||||
|
||||
echo "Making bundle $prefix.tar.gz..."
|
||||
tar czf $prefix.tar.gz -C "$destdir" $prefix
|
||||
tar czf $prefix.tar.gz --exclude=autom4te.cache -C "$destdir" $prefix
|
||||
|
||||
echo "Removing temporary $destdir/$prefix..."
|
||||
rm -rf "$destdir/$prefix"
|
||||
|
||||
+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)
|
||||
|
||||
+158
-4
@@ -555,6 +555,28 @@ extern "C" unsigned ivl_file_table_size()
|
||||
return fn_vector.size();
|
||||
}
|
||||
|
||||
extern "C" int ivl_island_flag_set(ivl_island_t net, unsigned flag, int value)
|
||||
{
|
||||
if (flag >= net->flags.size()) {
|
||||
if (value == 0)
|
||||
return 0;
|
||||
else
|
||||
net->flags.resize(flag+1, false);
|
||||
}
|
||||
|
||||
int old_flag = net->flags[flag];
|
||||
net->flags[flag] = value != 0;
|
||||
return old_flag;
|
||||
}
|
||||
|
||||
extern "C" int ivl_island_flag_test(ivl_island_t net, unsigned flag)
|
||||
{
|
||||
if (flag >= net->flags.size())
|
||||
return 0;
|
||||
else
|
||||
return net->flags[flag];
|
||||
}
|
||||
|
||||
extern "C" const char* ivl_logic_attr(ivl_net_logic_t net, const char*key)
|
||||
{
|
||||
assert(net);
|
||||
@@ -782,7 +804,6 @@ extern "C" unsigned ivl_lpm_base(ivl_lpm_t net)
|
||||
switch (net->type) {
|
||||
case IVL_LPM_PART_VP:
|
||||
case IVL_LPM_PART_PV:
|
||||
case IVL_LPM_PART_BI:
|
||||
return net->u_.part.base;
|
||||
default:
|
||||
assert(0);
|
||||
@@ -864,6 +885,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:
|
||||
@@ -914,7 +939,6 @@ extern "C" ivl_nexus_t ivl_lpm_data(ivl_lpm_t net, unsigned idx)
|
||||
|
||||
case IVL_LPM_PART_VP:
|
||||
case IVL_LPM_PART_PV:
|
||||
case IVL_LPM_PART_BI:
|
||||
assert(idx <= 1);
|
||||
if (idx == 0)
|
||||
return net->u_.part.a;
|
||||
@@ -1002,6 +1026,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:
|
||||
@@ -1056,7 +1081,6 @@ extern "C" ivl_nexus_t ivl_lpm_q(ivl_lpm_t net, unsigned idx)
|
||||
|
||||
case IVL_LPM_PART_VP:
|
||||
case IVL_LPM_PART_PV:
|
||||
case IVL_LPM_PART_BI:
|
||||
assert(idx == 0);
|
||||
return net->u_.part.q;
|
||||
|
||||
@@ -1118,6 +1142,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:
|
||||
@@ -1151,7 +1176,6 @@ extern "C" int ivl_lpm_signed(ivl_lpm_t net)
|
||||
return 0;
|
||||
case IVL_LPM_PART_VP:
|
||||
case IVL_LPM_PART_PV:
|
||||
case IVL_LPM_PART_BI:
|
||||
return net->u_.part.signed_flag;
|
||||
case IVL_LPM_REPEAT:
|
||||
return 0;
|
||||
@@ -1332,6 +1356,15 @@ extern "C" ivl_signal_t ivl_nexus_ptr_sig(ivl_nexus_ptr_t net)
|
||||
return net->l.sig;
|
||||
}
|
||||
|
||||
extern "C" ivl_switch_t ivl_nexus_ptr_switch(ivl_nexus_ptr_t net)
|
||||
{
|
||||
if (net == 0)
|
||||
return 0;
|
||||
if (net->type_ != __NEXUS_PTR_SWI)
|
||||
return 0;
|
||||
return net->l.swi;
|
||||
}
|
||||
|
||||
extern "C" const char* ivl_parameter_basename(ivl_parameter_t net)
|
||||
{
|
||||
assert(net);
|
||||
@@ -1344,6 +1377,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);
|
||||
@@ -1456,6 +1501,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);
|
||||
@@ -1469,6 +1526,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);
|
||||
@@ -1585,6 +1654,19 @@ extern "C" ivl_signal_t ivl_scope_sig(ivl_scope_t net, unsigned idx)
|
||||
return net->sigs_[idx];
|
||||
}
|
||||
|
||||
extern "C" unsigned ivl_scope_switches(ivl_scope_t net)
|
||||
{
|
||||
assert(net);
|
||||
return net->switches.size();
|
||||
}
|
||||
|
||||
extern "C" ivl_switch_t ivl_scope_switch(ivl_scope_t net, unsigned idx)
|
||||
{
|
||||
assert(net);
|
||||
assert(idx < net->switches.size());
|
||||
return net->switches[idx];
|
||||
}
|
||||
|
||||
extern "C" int ivl_scope_time_precision(ivl_scope_t net)
|
||||
{
|
||||
assert(net);
|
||||
@@ -1715,6 +1797,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_;
|
||||
@@ -2089,3 +2183,63 @@ extern "C" ivl_statement_t ivl_stmt_sub_stmt(ivl_statement_t net)
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
extern "C" const char*ivl_switch_basename(ivl_switch_t net)
|
||||
{
|
||||
return net->name;
|
||||
}
|
||||
|
||||
extern "C" ivl_scope_t ivl_switch_scope(ivl_switch_t net)
|
||||
{
|
||||
return net->scope;
|
||||
}
|
||||
|
||||
extern "C" ivl_switch_type_t ivl_switch_type(ivl_switch_t net)
|
||||
{
|
||||
return net->type;
|
||||
}
|
||||
|
||||
extern "C" ivl_nexus_t ivl_switch_a(ivl_switch_t net)
|
||||
{
|
||||
return net->pins[0];
|
||||
}
|
||||
|
||||
extern "C" ivl_nexus_t ivl_switch_b(ivl_switch_t net)
|
||||
{
|
||||
return net->pins[1];
|
||||
}
|
||||
|
||||
extern "C" ivl_nexus_t ivl_switch_enable(ivl_switch_t net)
|
||||
{
|
||||
return net->pins[2];
|
||||
}
|
||||
|
||||
extern "C" unsigned ivl_switch_width(ivl_switch_t net)
|
||||
{
|
||||
return net->width;
|
||||
}
|
||||
|
||||
extern "C" unsigned ivl_switch_part(ivl_switch_t net)
|
||||
{
|
||||
return net->part;
|
||||
}
|
||||
|
||||
extern "C" unsigned ivl_switch_offset(ivl_switch_t net)
|
||||
{
|
||||
return net->offset;
|
||||
}
|
||||
|
||||
extern "C" const char* ivl_switch_file(ivl_switch_t net)
|
||||
{
|
||||
return net->file;
|
||||
}
|
||||
|
||||
extern "C" ivl_island_t ivl_switch_island(ivl_switch_t net)
|
||||
{
|
||||
return net->island;
|
||||
}
|
||||
|
||||
extern "C" unsigned ivl_switch_lineno(ivl_switch_t net)
|
||||
{
|
||||
return net->lineno;
|
||||
}
|
||||
|
||||
@@ -380,6 +380,19 @@ static void nexus_lpm_add(ivl_nexus_t nex, ivl_lpm_t net, unsigned pin,
|
||||
nex->ptrs_[top-1].l.lpm= net;
|
||||
}
|
||||
|
||||
static void nexus_switch_add(ivl_nexus_t nex, ivl_switch_t net, unsigned pin)
|
||||
{
|
||||
unsigned top = nex->nptr_ + 1;
|
||||
nex->ptrs_ = (struct ivl_nexus_ptr_s*)
|
||||
realloc(nex->ptrs_, top*sizeof(struct ivl_nexus_ptr_s));
|
||||
nex->nptr_ = top;
|
||||
|
||||
nex->ptrs_[top-1].type_= __NEXUS_PTR_SWI;
|
||||
nex->ptrs_[top-1].drive0 = IVL_DR_HiZ;
|
||||
nex->ptrs_[top-1].drive1 = IVL_DR_HiZ;
|
||||
nex->ptrs_[top-1].pin_ = pin;
|
||||
nex->ptrs_[top-1].l.swi= net;
|
||||
}
|
||||
|
||||
void scope_add_logic(ivl_scope_t scope, ivl_net_logic_t net)
|
||||
{
|
||||
@@ -431,6 +444,11 @@ static void scope_add_lpm(ivl_scope_t scope, ivl_lpm_t net)
|
||||
}
|
||||
}
|
||||
|
||||
static void scope_add_switch(ivl_scope_t scope, ivl_switch_t net)
|
||||
{
|
||||
scope->switches.push_back(net);
|
||||
}
|
||||
|
||||
ivl_parameter_t dll_target::scope_find_param(ivl_scope_t scope,
|
||||
const char*name)
|
||||
{
|
||||
@@ -470,6 +488,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.get_file();
|
||||
cur_par->lineno = (*cur_pit).second.get_lineno();
|
||||
|
||||
NetExpr*etmp = (*cur_pit).second.expr;
|
||||
make_scope_param_expr(cur_par, etmp);
|
||||
@@ -482,6 +502,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.get_file();
|
||||
cur_par->lineno = (*cur_pit).second.get_lineno();
|
||||
|
||||
NetExpr*etmp = (*cur_pit).second.expr;
|
||||
make_scope_param_expr(cur_par, etmp);
|
||||
@@ -525,6 +547,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;
|
||||
@@ -616,6 +639,13 @@ int dll_target::end_design(const Design*)
|
||||
return rc;
|
||||
}
|
||||
|
||||
void dll_target::switch_attributes(struct ivl_switch_s *obj,
|
||||
const NetNode*net)
|
||||
{
|
||||
obj->nattr = net->attr_cnt();
|
||||
obj->attr = fill_in_attributes(net);
|
||||
}
|
||||
|
||||
void dll_target::logic_attributes(struct ivl_net_logic_s *obj,
|
||||
const NetNode*net)
|
||||
{
|
||||
@@ -1003,6 +1033,56 @@ void dll_target::logic(const NetLogic*net)
|
||||
scope_add_logic(scope, obj);
|
||||
}
|
||||
|
||||
bool dll_target::tran(const NetTran*net)
|
||||
{
|
||||
struct ivl_switch_s*obj = new struct ivl_switch_s;
|
||||
obj->type = net->type();
|
||||
obj->width = 0;
|
||||
obj->part = 0;
|
||||
obj->offset = 0;
|
||||
obj->name = net->name();
|
||||
obj->scope = find_scope(des_, net->scope());
|
||||
obj->island = net->island;
|
||||
assert(obj->scope);
|
||||
assert(obj->island);
|
||||
|
||||
const Nexus*nex;
|
||||
|
||||
nex = net->pin(0).nexus();
|
||||
assert(nex->t_cookie());
|
||||
obj->pins[0] = nex->t_cookie();
|
||||
|
||||
nex = net->pin(1).nexus();
|
||||
assert(nex->t_cookie());
|
||||
obj->pins[1] = nex->t_cookie();
|
||||
|
||||
nexus_switch_add(obj->pins[0], obj, 0);
|
||||
nexus_switch_add(obj->pins[1], obj, 1);
|
||||
|
||||
if (net->pin_count() > 2) {
|
||||
nex = net->pin(2).nexus();
|
||||
assert(nex->t_cookie());
|
||||
obj->pins[2] = nex->t_cookie();
|
||||
nexus_switch_add(obj->pins[2], obj, 2);
|
||||
} else {
|
||||
obj->pins[2] = 0;
|
||||
}
|
||||
|
||||
if (obj->type == IVL_SW_TRAN_VP) {
|
||||
obj->width = net->vector_width();
|
||||
obj->part = net->part_width();
|
||||
obj->offset= net->part_offset();
|
||||
}
|
||||
|
||||
obj->file = net->get_file();
|
||||
obj->lineno = net->get_lineno();
|
||||
|
||||
switch_attributes(obj, net);
|
||||
scope_add_switch(obj->scope, obj);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool dll_target::sign_extend(const NetSignExtend*net)
|
||||
{
|
||||
struct ivl_lpm_s*obj = new struct ivl_lpm_s;
|
||||
@@ -1302,6 +1382,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;
|
||||
@@ -1893,9 +2005,6 @@ bool dll_target::part_select(const NetPartSelect*net)
|
||||
case NetPartSelect::PV:
|
||||
obj->type = IVL_LPM_PART_PV;
|
||||
break;
|
||||
case NetPartSelect::BI:
|
||||
obj->type = IVL_LPM_PART_BI;
|
||||
break;
|
||||
}
|
||||
obj->name = net->name(); // NetPartSelect names are permallocated.
|
||||
assert(net->scope());
|
||||
@@ -1949,35 +2058,12 @@ bool dll_target::part_select(const NetPartSelect*net)
|
||||
obj->u_.part.a = nex->t_cookie();
|
||||
break;
|
||||
|
||||
case IVL_LPM_PART_BI:
|
||||
/* For now, handle this exactly the same as a PV */
|
||||
|
||||
/* NetPartSelect:pin(0) is the output pin. */
|
||||
nex = net->pin(0).nexus();
|
||||
assert(nex->t_cookie());
|
||||
|
||||
obj->u_.part.q = nex->t_cookie();
|
||||
|
||||
/* NetPartSelect:pin(1) is the input pin. */
|
||||
nex = net->pin(1).nexus();
|
||||
assert(nex->t_cookie());
|
||||
|
||||
obj->u_.part.a = nex->t_cookie();
|
||||
break;
|
||||
|
||||
default:
|
||||
assert(0);
|
||||
}
|
||||
|
||||
nexus_lpm_add(obj->u_.part.q, obj, 0, IVL_DR_STRONG, IVL_DR_STRONG);
|
||||
|
||||
/* If the device is a PART_BI, then the "input" is also a
|
||||
strength aware output, so attach it to the nexus with
|
||||
strong driver. */
|
||||
if (obj->type == IVL_LPM_PART_BI)
|
||||
nexus_lpm_add(obj->u_.part.a, obj, 0, IVL_DR_STRONG, IVL_DR_STRONG);
|
||||
else
|
||||
nexus_lpm_add(obj->u_.part.a, obj, 0, IVL_DR_HiZ, IVL_DR_HiZ);
|
||||
nexus_lpm_add(obj->u_.part.a, obj, 0, IVL_DR_HiZ, IVL_DR_HiZ);
|
||||
|
||||
/* The select input is optional. */
|
||||
if (obj->u_.part.s)
|
||||
@@ -2142,6 +2228,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());
|
||||
@@ -2214,6 +2301,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) {
|
||||
|
||||
@@ -21,8 +21,10 @@
|
||||
|
||||
# include "target.h"
|
||||
# include "ivl_target.h"
|
||||
# include "ivl_target_priv.h"
|
||||
# include "StringHeap.h"
|
||||
# include "netlist.h"
|
||||
# include <vector>
|
||||
|
||||
#if defined(__MINGW32__)
|
||||
#include <windows.h>
|
||||
@@ -67,9 +69,11 @@ struct dll_target : public target_t, public expr_scan_t {
|
||||
bool bufz(const NetBUFZ*);
|
||||
void event(const NetEvent*);
|
||||
void logic(const NetLogic*);
|
||||
bool tran(const NetTran*);
|
||||
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*);
|
||||
@@ -145,6 +149,7 @@ struct dll_target : public target_t, public expr_scan_t {
|
||||
ivl_scope_t lookup_scope_(const NetScope*scope);
|
||||
|
||||
ivl_attribute_s* fill_in_attributes(const Attrib*net);
|
||||
void switch_attributes(struct ivl_switch_s *obj, const NetNode*net);
|
||||
void logic_attributes(struct ivl_net_logic_s *obj, const NetNode*net);
|
||||
|
||||
private:
|
||||
@@ -444,6 +449,23 @@ struct ivl_net_logic_s {
|
||||
ivl_expr_t delay[3];
|
||||
};
|
||||
|
||||
struct ivl_switch_s {
|
||||
ivl_switch_type_t type;
|
||||
unsigned width;
|
||||
unsigned part;
|
||||
unsigned offset;
|
||||
|
||||
perm_string name;
|
||||
ivl_scope_t scope;
|
||||
ivl_island_t island;
|
||||
|
||||
struct ivl_attribute_s*attr;
|
||||
unsigned nattr;
|
||||
|
||||
ivl_nexus_t pins[3];
|
||||
perm_string file;
|
||||
unsigned lineno;
|
||||
};
|
||||
|
||||
/*
|
||||
* UDP definition.
|
||||
@@ -480,12 +502,14 @@ struct ivl_nexus_ptr_s {
|
||||
ivl_net_logic_t log; /* type 1 */
|
||||
ivl_net_const_t con; /* type 2 */
|
||||
ivl_lpm_t lpm; /* type 3 */
|
||||
ivl_switch_t swi; /* type 4 */
|
||||
} l;
|
||||
};
|
||||
# define __NEXUS_PTR_SIG 0
|
||||
# define __NEXUS_PTR_LOG 1
|
||||
# define __NEXUS_PTR_CON 2
|
||||
# define __NEXUS_PTR_LPM 3
|
||||
# define __NEXUS_PTR_SWI 4
|
||||
|
||||
/*
|
||||
* NOTE: ONLY allocate ivl_nexus_s objects with the included "new" operator.
|
||||
@@ -509,6 +533,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
|
||||
@@ -537,6 +563,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_;
|
||||
@@ -560,6 +590,8 @@ struct ivl_scope_s {
|
||||
unsigned ports;
|
||||
ivl_signal_t*port;
|
||||
|
||||
std::vector<ivl_switch_t>switches;
|
||||
|
||||
signed int time_precision :8;
|
||||
signed int time_units :8;
|
||||
|
||||
@@ -577,6 +609,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;
|
||||
@@ -713,4 +747,18 @@ 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();
|
||||
}
|
||||
|
||||
static inline void FILE_NAME(ivl_switch_t net, const LineInfo*info)
|
||||
{
|
||||
net->file = info->get_file();
|
||||
net->lineno = info->get_lineno();
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
@@ -61,6 +61,13 @@ void target_t::logic(const NetLogic*)
|
||||
"Unhandled logic gate" << endl;
|
||||
}
|
||||
|
||||
bool target_t::tran(const NetTran*)
|
||||
{
|
||||
cerr << "target (" << typeid(*this).name() << "): "
|
||||
<< "TRAN devices not supported." << endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
bool target_t::bufz(const NetBUFZ*)
|
||||
{
|
||||
cerr << "target (" << typeid(*this).name() << "): "
|
||||
@@ -81,6 +88,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*);
|
||||
@@ -85,6 +86,7 @@ struct target_t {
|
||||
|
||||
/* Output a gate (called for each gate) */
|
||||
virtual void logic(const NetLogic*);
|
||||
virtual bool tran(const NetTran*);
|
||||
virtual bool ureduce(const NetUReduce*); /* unary reduction operator */
|
||||
virtual bool bufz(const NetBUFZ*);
|
||||
virtual void udp(const NetUDP*);
|
||||
|
||||
@@ -16,12 +16,9 @@
|
||||
# 59 Temple Place - Suite 330
|
||||
# Boston, MA 02111-1307, USA
|
||||
#
|
||||
#ident "$Id: Makefile.in,v 1.11 2004/02/10 19:25:01 steve Exp $"
|
||||
#
|
||||
#
|
||||
SHELL = /bin/sh
|
||||
|
||||
VERSION = 0.0
|
||||
VERSION = 0.9.devel
|
||||
|
||||
prefix = @prefix@
|
||||
exec_prefix = @exec_prefix@
|
||||
@@ -44,6 +41,8 @@ LDFLAGS = @LDFLAGS@
|
||||
|
||||
all: dep null.tgt
|
||||
|
||||
check: all
|
||||
|
||||
dep:
|
||||
mkdir dep
|
||||
|
||||
|
||||
@@ -16,12 +16,9 @@
|
||||
# 59 Temple Place - Suite 330
|
||||
# Boston, MA 02111-1307, USA
|
||||
#
|
||||
#ident "$Id: Makefile.in,v 1.20 2007/02/06 05:07:32 steve Exp $"
|
||||
#
|
||||
#
|
||||
SHELL = /bin/sh
|
||||
|
||||
VERSION = 0.0
|
||||
VERSION = 0.9.devel
|
||||
|
||||
prefix = @prefix@
|
||||
exec_prefix = @exec_prefix@
|
||||
@@ -44,6 +41,8 @@ LDFLAGS = @LDFLAGS@
|
||||
|
||||
all: dep stub.tgt
|
||||
|
||||
check: all
|
||||
|
||||
dep:
|
||||
mkdir dep
|
||||
|
||||
@@ -51,7 +50,7 @@ dep:
|
||||
$(CC) $(CPPFLAGS) $(CFLAGS) -MD -c $< -o $*.o
|
||||
mv $*.d dep
|
||||
|
||||
O = stub.o expression.o statement.o
|
||||
O = stub.o expression.o statement.o switches.o
|
||||
|
||||
ifeq (@WIN32@,yes)
|
||||
TGTLDFLAGS=-L.. -livl
|
||||
|
||||
+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:
|
||||
|
||||
@@ -35,6 +35,15 @@ extern FILE*out;
|
||||
*/
|
||||
extern int stub_errors;
|
||||
|
||||
/*
|
||||
* This function finds the vector width of a signal. It relies on the
|
||||
* assumption that all the signal inputs to the nexus have the same
|
||||
* width. The ivl_target API should assert that condition.
|
||||
*/
|
||||
extern unsigned width_of_nexus(ivl_nexus_t nex);
|
||||
|
||||
extern ivl_variable_type_t type_of_nexus(ivl_nexus_t nex);
|
||||
|
||||
/*
|
||||
* Show the details of the expression.
|
||||
*/
|
||||
@@ -45,6 +54,8 @@ extern void show_expression(ivl_expr_t net, unsigned ind);
|
||||
*/
|
||||
extern void show_statement(ivl_statement_t net, unsigned ind);
|
||||
|
||||
extern void show_switch(ivl_switch_t net);
|
||||
|
||||
/*
|
||||
*/
|
||||
extern const char*data_type_string(ivl_variable_type_t vtype);
|
||||
|
||||
@@ -288,7 +288,7 @@ void show_statement(ivl_statement_t net, unsigned ind)
|
||||
break;
|
||||
|
||||
case IVL_ST_DELAY:
|
||||
fprintf(out, "%*s#%llu\n", ind, "", ivl_stmt_delay_val(net));
|
||||
fprintf(out, "%*s#%" PRIu64 "\n", ind, "", ivl_stmt_delay_val(net));
|
||||
show_statement(ivl_stmt_sub_stmt(net), ind+2);
|
||||
break;
|
||||
|
||||
|
||||
+39
-37
@@ -175,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);
|
||||
@@ -529,38 +555,6 @@ static void show_lpm_part(ivl_lpm_t net)
|
||||
}
|
||||
}
|
||||
|
||||
static void show_lpm_part_bi(ivl_lpm_t net)
|
||||
{
|
||||
unsigned width = ivl_lpm_width(net);
|
||||
unsigned base = ivl_lpm_base(net);
|
||||
ivl_nexus_t port_p = ivl_lpm_q(net,0);
|
||||
ivl_nexus_t port_v = ivl_lpm_data(net,0);
|
||||
|
||||
fprintf(out, " LPM_PART_BI %s: <width=%u, base=%u, signed=%d>\n",
|
||||
ivl_lpm_basename(net), width, base, ivl_lpm_signed(net));
|
||||
fprintf(out, " P: %s\n", ivl_nexus_name(port_p));
|
||||
fprintf(out, " V: %s <width=%u>\n", ivl_nexus_name(port_v),
|
||||
width_of_nexus(port_v));
|
||||
|
||||
|
||||
/* The data(0) port must be large enough for the part select. */
|
||||
if (width_of_nexus(ivl_lpm_data(net,0)) < (width+base)) {
|
||||
fprintf(out, " ERROR: Part select is out of range."
|
||||
" Data nexus width=%u, width+base=%u\n",
|
||||
width_of_nexus(ivl_lpm_data(net,0)), width+base);
|
||||
stub_errors += 1;
|
||||
}
|
||||
|
||||
/* The Q vector must be exactly the width of the part select. */
|
||||
if (width_of_nexus(ivl_lpm_q(net,0)) != width) {
|
||||
fprintf(out, " ERROR: Part select input mismatch."
|
||||
" Nexus width=%u, expect width=%u\n",
|
||||
width_of_nexus(ivl_lpm_q(net,0)), width);
|
||||
stub_errors += 1;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* The reduction operators have similar characteristics and are
|
||||
* displayed here.
|
||||
@@ -796,6 +790,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;
|
||||
@@ -875,11 +873,6 @@ static void show_lpm(ivl_lpm_t net)
|
||||
show_lpm_part(net);
|
||||
break;
|
||||
|
||||
/* The BI part select is slightly special. */
|
||||
case IVL_LPM_PART_BI:
|
||||
show_lpm_part_bi(net);
|
||||
break;
|
||||
|
||||
case IVL_LPM_REPEAT:
|
||||
show_lpm_repeat(net);
|
||||
break;
|
||||
@@ -1029,6 +1022,7 @@ static void show_nexus_details(ivl_signal_t net, ivl_nexus_t nex)
|
||||
ivl_net_logic_t log;
|
||||
ivl_lpm_t lpm;
|
||||
ivl_signal_t sig;
|
||||
ivl_switch_t swt;
|
||||
ivl_nexus_ptr_t ptr = ivl_nexus_ptr(nex, idx);
|
||||
|
||||
const char*dr0 = str_tab[ivl_nexus_ptr_drive0(ptr)];
|
||||
@@ -1062,6 +1056,11 @@ static void show_nexus_details(ivl_signal_t net, ivl_nexus_t nex)
|
||||
ivl_scope_name(ivl_lpm_scope(lpm)),
|
||||
ivl_lpm_basename(lpm), dr0, dr1);
|
||||
|
||||
} else if ((swt = ivl_nexus_ptr_switch(ptr))) {
|
||||
fprintf(out, " SWITCH %s.%s\n",
|
||||
ivl_scope_name(ivl_switch_scope(swt)),
|
||||
ivl_switch_basename(swt));
|
||||
|
||||
} else if ((con = ivl_nexus_ptr_con(ptr))) {
|
||||
signal_nexus_const(net, ptr, con);
|
||||
|
||||
@@ -1448,6 +1447,9 @@ static int show_scope(ivl_scope_t net, void*x)
|
||||
for (idx = 0 ; idx < ivl_scope_lpms(net) ; idx += 1)
|
||||
show_lpm(ivl_scope_lpm(net, idx));
|
||||
|
||||
for (idx = 0 ; idx < ivl_scope_switches(net) ; idx += 1)
|
||||
show_switch(ivl_scope_switch(net, idx));
|
||||
|
||||
switch (ivl_scope_type(net)) {
|
||||
case IVL_SCT_FUNCTION:
|
||||
case IVL_SCT_TASK:
|
||||
|
||||
@@ -0,0 +1,124 @@
|
||||
/*
|
||||
* Copyright (c) 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
|
||||
* 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
|
||||
*/
|
||||
|
||||
|
||||
# include "config.h"
|
||||
# include "priv.h"
|
||||
# include <stdlib.h>
|
||||
# include <inttypes.h>
|
||||
# include <assert.h>
|
||||
|
||||
void show_switch(ivl_switch_t net)
|
||||
{
|
||||
const char*name = ivl_switch_basename(net);
|
||||
int has_enable = 0;
|
||||
|
||||
switch (ivl_switch_type(net)) {
|
||||
case IVL_SW_TRAN:
|
||||
fprintf(out, " tran %s", name);
|
||||
break;
|
||||
case IVL_SW_RTRAN:
|
||||
fprintf(out, " rtran %s", name);
|
||||
break;
|
||||
case IVL_SW_TRANIF0:
|
||||
fprintf(out, " tranif0 %s", name);
|
||||
has_enable = 1;
|
||||
break;
|
||||
case IVL_SW_RTRANIF0:
|
||||
fprintf(out, " rtranif0 %s", name);
|
||||
has_enable = 1;
|
||||
break;
|
||||
case IVL_SW_TRANIF1:
|
||||
fprintf(out, " tranif1 %s", name);
|
||||
has_enable = 1;
|
||||
break;
|
||||
case IVL_SW_RTRANIF1:
|
||||
fprintf(out, " rtranif1 %s", name);
|
||||
has_enable = 1;
|
||||
break;
|
||||
case IVL_SW_TRAN_VP:
|
||||
fprintf(out, " tran(VP wid=%u, part=%u, off=%u) %s",
|
||||
ivl_switch_width(net), ivl_switch_part(net),
|
||||
ivl_switch_offset(net), name);
|
||||
break;
|
||||
}
|
||||
|
||||
fprintf(out, " island=%p\n", ivl_switch_island(net));
|
||||
|
||||
ivl_nexus_t nexa = ivl_switch_a(net);
|
||||
const char*nex_name = nexa? ivl_nexus_name(nexa) : "";
|
||||
ivl_variable_type_t nex_type_a = nexa? type_of_nexus(nexa) : IVL_VT_NO_TYPE;
|
||||
fprintf(out, " A: %s <type=%s>\n", nex_name, data_type_string(nex_type_a));
|
||||
|
||||
ivl_nexus_t nexb = ivl_switch_b(net);
|
||||
nex_name = nexb? ivl_nexus_name(nexb) : "";
|
||||
ivl_variable_type_t nex_type_b = nexb? type_of_nexus(nexb) : IVL_VT_NO_TYPE;
|
||||
fprintf(out, " B: %s <type=%s>\n", nex_name, data_type_string(nex_type_b));
|
||||
|
||||
/* The A/B pins of the switch must be present, and must match. */
|
||||
if (nex_type_a == IVL_VT_NO_TYPE) {
|
||||
fprintf(out, " A: ERROR: Type missing for pin A\n");
|
||||
stub_errors += 1;
|
||||
}
|
||||
if (nex_type_b == IVL_VT_NO_TYPE) {
|
||||
fprintf(out, " B: ERROR: Type missing for pin B\n");
|
||||
stub_errors += 1;
|
||||
}
|
||||
if (nex_type_a != nex_type_b) {
|
||||
fprintf(out, " A/B: ERROR: Type mismatch between pins A and B\n");
|
||||
stub_errors += 1;
|
||||
}
|
||||
|
||||
if (ivl_switch_type(net) == IVL_SW_TRAN_VP) {
|
||||
/* The TRAN_VP nodes are special in that the specific
|
||||
width matters for each port and should be exactly
|
||||
right for both. */
|
||||
if (width_of_nexus(nexa) != ivl_switch_width(net)) {
|
||||
fprintf(out, " A: ERROR: part vector nexus "
|
||||
"width=%u, expecting width=%u\n",
|
||||
width_of_nexus(nexa), ivl_switch_width(net));
|
||||
stub_errors += 1;
|
||||
}
|
||||
if (width_of_nexus(nexb) != ivl_switch_part(net)) {
|
||||
fprintf(out, " B: ERROR: part select nexus "
|
||||
"width=%u, expecting width=%u\n",
|
||||
width_of_nexus(nexb), ivl_switch_part(net));
|
||||
stub_errors += 1;
|
||||
}
|
||||
} else {
|
||||
/* All other TRAN nodes will have matching vector
|
||||
widths, but the actual value doesn't matter. */
|
||||
if (width_of_nexus(nexa) != width_of_nexus(nexb)) {
|
||||
fprintf(out, " A/B: ERROR: Width of ports don't match"
|
||||
": A=%u, B=%u\n",
|
||||
width_of_nexus(nexa), width_of_nexus(nexb));
|
||||
stub_errors += 1;
|
||||
}
|
||||
}
|
||||
|
||||
if (has_enable) {
|
||||
ivl_nexus_t nexe = ivl_switch_enable(net);
|
||||
nex_name = nexe? ivl_nexus_name(nexe) : "";
|
||||
fprintf(out, " E: %s\n", nex_name);
|
||||
if (width_of_nexus(nexe) != 1) {
|
||||
fprintf(out, " E: ERROR: Nexus width is %u\n",
|
||||
width_of_nexus(nexe));
|
||||
}
|
||||
}
|
||||
}
|
||||
+2
-1
@@ -51,7 +51,8 @@ dep:
|
||||
$(CC) $(CPPFLAGS) $(CFLAGS) -MD -c $< -o $*.o
|
||||
mv $*.d dep
|
||||
|
||||
O = vvp.o draw_mux.o draw_ufunc.o draw_vpi.o eval_bool.o eval_expr.o \
|
||||
O = vvp.o draw_mux.o draw_net_input.o draw_switch.o draw_ufunc.o draw_vpi.o \
|
||||
eval_bool.o eval_expr.o \
|
||||
eval_real.o modpath.o vector.o \
|
||||
vvp_process.o vvp_scope.o
|
||||
|
||||
|
||||
+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");
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,687 @@
|
||||
/*
|
||||
* 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
|
||||
* 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
|
||||
*/
|
||||
|
||||
# include "vvp_priv.h"
|
||||
#ifdef HAVE_MALLOC_H
|
||||
# include <malloc.h>
|
||||
#endif
|
||||
# include <stdlib.h>
|
||||
# include <math.h>
|
||||
# include <string.h>
|
||||
# include <inttypes.h>
|
||||
# include <assert.h>
|
||||
|
||||
#ifdef __MINGW32__ /* MinGW has inconsistent %p output. */
|
||||
#define snprintf _snprintf
|
||||
#endif
|
||||
|
||||
static ivl_signal_type_t signal_type_of_nexus(ivl_nexus_t nex)
|
||||
{
|
||||
unsigned idx;
|
||||
ivl_signal_type_t out = IVL_SIT_TRI;
|
||||
|
||||
for (idx = 0 ; idx < ivl_nexus_ptrs(nex) ; idx += 1) {
|
||||
ivl_signal_type_t stype;
|
||||
ivl_nexus_ptr_t ptr = ivl_nexus_ptr(nex, idx);
|
||||
ivl_signal_t sig = ivl_nexus_ptr_sig(ptr);
|
||||
if (sig == 0)
|
||||
continue;
|
||||
|
||||
stype = ivl_signal_type(sig);
|
||||
if (stype == IVL_SIT_REG)
|
||||
continue;
|
||||
if (stype == IVL_SIT_TRI)
|
||||
continue;
|
||||
if (stype == IVL_SIT_NONE)
|
||||
continue;
|
||||
out = stype;
|
||||
}
|
||||
|
||||
return out;
|
||||
}
|
||||
|
||||
static void draw_C4_repeated_constant(char bit_char, unsigned width)
|
||||
{
|
||||
unsigned idx;
|
||||
|
||||
fprintf(vvp_out, "C4<");
|
||||
for (idx = 0 ; idx < width ; idx += 1)
|
||||
fprintf(vvp_out, "%c", bit_char);
|
||||
|
||||
fprintf(vvp_out, ">");
|
||||
}
|
||||
|
||||
static char* draw_C4_to_string(ivl_net_const_t cptr)
|
||||
{
|
||||
const char*bits = ivl_const_bits(cptr);
|
||||
unsigned idx;
|
||||
|
||||
size_t result_len = 5 + ivl_const_width(cptr);
|
||||
char*result = malloc(result_len);
|
||||
char*dp = result;
|
||||
strcpy(dp, "C4<");
|
||||
dp += strlen(dp);
|
||||
|
||||
for (idx = 0 ; idx < ivl_const_width(cptr) ; idx += 1) {
|
||||
char bitchar = bits[ivl_const_width(cptr)-idx-1];
|
||||
*dp++ = bitchar;
|
||||
assert((dp - result) < result_len);
|
||||
}
|
||||
|
||||
strcpy(dp, ">");
|
||||
return result;
|
||||
}
|
||||
|
||||
static char* draw_C8_to_string(ivl_net_const_t cptr,
|
||||
ivl_drive_t dr0, ivl_drive_t dr1)
|
||||
{
|
||||
size_t nresult = 5 + 3*ivl_const_width(cptr);
|
||||
char*result = malloc(nresult);
|
||||
const char*bits = ivl_const_bits(cptr);
|
||||
unsigned idx;
|
||||
|
||||
char dr0c = "01234567"[dr0];
|
||||
char dr1c = "01234567"[dr1];
|
||||
char*dp = result;
|
||||
|
||||
strcpy(dp, "C8<");
|
||||
dp += strlen(dp);
|
||||
|
||||
for (idx = 0 ; idx < ivl_const_width(cptr) ; idx += 1) {
|
||||
switch (bits[ivl_const_width(cptr)-idx-1]) {
|
||||
case '0':
|
||||
*dp++ = dr0c;
|
||||
*dp++ = dr0c;
|
||||
*dp++ = '0';
|
||||
break;
|
||||
case '1':
|
||||
*dp++ = dr1c;
|
||||
*dp++ = dr1c;
|
||||
*dp++ = '1';
|
||||
break;
|
||||
case 'x':
|
||||
case 'X':
|
||||
*dp++ = dr0c;
|
||||
*dp++ = dr1c;
|
||||
*dp++ = 'x';
|
||||
break;
|
||||
case 'z':
|
||||
case 'Z':
|
||||
*dp++ = '0';
|
||||
*dp++ = '0';
|
||||
*dp++ = 'z';
|
||||
break;
|
||||
default:
|
||||
assert(0);
|
||||
break;
|
||||
}
|
||||
assert(dp - result < nresult);
|
||||
}
|
||||
|
||||
strcpy(dp, ">");
|
||||
return result;
|
||||
}
|
||||
|
||||
static struct vvp_nexus_data*new_nexus_data()
|
||||
{
|
||||
struct vvp_nexus_data*data = calloc(1, sizeof(struct vvp_nexus_data));
|
||||
return data;
|
||||
}
|
||||
|
||||
static int nexus_drive_is_strength_aware(ivl_nexus_ptr_t nptr)
|
||||
{
|
||||
if (ivl_nexus_ptr_drive0(nptr) != IVL_DR_STRONG)
|
||||
return 1;
|
||||
if (ivl_nexus_ptr_drive1(nptr) != IVL_DR_STRONG)
|
||||
return 1;
|
||||
|
||||
ivl_net_logic_t log = ivl_nexus_ptr_log(nptr);
|
||||
if (log != 0) {
|
||||
/* These logic gates are able to generate unusual
|
||||
strength values and so their outputs are considered
|
||||
strength aware. */
|
||||
if (ivl_logic_type(log) == IVL_LO_BUFIF0)
|
||||
return 1;
|
||||
if (ivl_logic_type(log) == IVL_LO_BUFIF1)
|
||||
return 1;
|
||||
if (ivl_logic_type(log) == IVL_LO_PMOS)
|
||||
return 1;
|
||||
if (ivl_logic_type(log) == IVL_LO_NMOS)
|
||||
return 1;
|
||||
if (ivl_logic_type(log) == IVL_LO_CMOS)
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Given a nexus, look for a signal that has module delay
|
||||
* paths. Return that signal. (There should be no more than 1.) If we
|
||||
* don't find any, then return nil.
|
||||
*/
|
||||
static ivl_signal_t find_modpath(ivl_nexus_t nex)
|
||||
{
|
||||
unsigned idx;
|
||||
for (idx = 0 ; idx < ivl_nexus_ptrs(nex) ; idx += 1) {
|
||||
ivl_nexus_ptr_t ptr = ivl_nexus_ptr(nex,idx);
|
||||
ivl_signal_t sig = ivl_nexus_ptr_sig(ptr);
|
||||
if (sig == 0)
|
||||
continue;
|
||||
if (ivl_signal_npath(sig) == 0)
|
||||
continue;
|
||||
|
||||
return sig;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void str_repeat(char*buf, const char*str, unsigned rpt)
|
||||
{
|
||||
unsigned idx;
|
||||
size_t len = strlen(str);
|
||||
for (idx = 0 ; idx < rpt ; idx += 1) {
|
||||
strcpy(buf, str);
|
||||
buf += len;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* This function takes a nexus and looks for an input functor. It then
|
||||
* draws to the output a string that represents that functor. What we
|
||||
* are trying to do here is find the input to the net that is attached
|
||||
* to this nexus.
|
||||
*/
|
||||
|
||||
static char* draw_net_input_drive(ivl_nexus_t nex, ivl_nexus_ptr_t nptr)
|
||||
{
|
||||
unsigned nptr_pin = ivl_nexus_ptr_pin(nptr);
|
||||
ivl_net_const_t cptr;
|
||||
ivl_net_logic_t lptr;
|
||||
ivl_signal_t sptr;
|
||||
ivl_lpm_t lpm;
|
||||
|
||||
lptr = ivl_nexus_ptr_log(nptr);
|
||||
if (lptr && (ivl_logic_type(lptr) == IVL_LO_BUFZ) && (nptr_pin == 0))
|
||||
do {
|
||||
if (! can_elide_bufz(lptr, nptr))
|
||||
break;
|
||||
|
||||
return strdup(draw_net_input(ivl_logic_pin(lptr, 1)));
|
||||
} while(0);
|
||||
|
||||
/* If this is a pulldown device, then there is a single pin
|
||||
that drives a constant value to the entire width of the
|
||||
vector. The driver normally drives a pull0 value, so a C8<>
|
||||
constant is appropriate, but if the drive is really strong,
|
||||
then we can draw a C4<> constant instead. */
|
||||
if (lptr && (ivl_logic_type(lptr) == IVL_LO_PULLDOWN)) {
|
||||
if (ivl_nexus_ptr_drive0(nptr) == IVL_DR_STRONG) {
|
||||
size_t result_len = ivl_logic_width(lptr) + 5;
|
||||
char*result = malloc(result_len);
|
||||
char*dp = result;
|
||||
strcpy(dp, "C4<");
|
||||
dp += strlen(dp);
|
||||
str_repeat(dp, "0", ivl_logic_width(lptr));
|
||||
dp += ivl_logic_width(lptr);
|
||||
*dp++ = '>';
|
||||
*dp = 0;
|
||||
assert((dp-result) <= result_len);
|
||||
return result;
|
||||
} else {
|
||||
char val[4];
|
||||
size_t result_len = 3*ivl_logic_width(lptr) + 5;
|
||||
char*result = malloc(result_len);
|
||||
char*dp = result;
|
||||
|
||||
val[0] = "01234567"[ivl_nexus_ptr_drive0(nptr)];
|
||||
val[1] = val[0];
|
||||
val[2] = '0';
|
||||
val[3] = 0;
|
||||
|
||||
strcpy(dp, "C8<");
|
||||
dp += strlen(dp);
|
||||
str_repeat(dp, val, ivl_logic_width(lptr));
|
||||
dp += 3*ivl_logic_width(lptr);
|
||||
*dp++ = '>';
|
||||
*dp = 0;
|
||||
assert((dp-result) <= result_len);
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
if (lptr && (ivl_logic_type(lptr) == IVL_LO_PULLUP)) {
|
||||
if (ivl_nexus_ptr_drive1(nptr) == IVL_DR_STRONG) {
|
||||
size_t result_len = 5 + ivl_logic_width(lptr);
|
||||
char*result = malloc(result_len);
|
||||
char*dp = result;
|
||||
strcpy(dp, "C4<");
|
||||
dp += strlen(dp);
|
||||
str_repeat(dp, "1", ivl_logic_width(lptr));
|
||||
dp += ivl_logic_width(lptr);
|
||||
*dp++ = '>';
|
||||
*dp = 0;
|
||||
assert((dp-result) <= result_len);
|
||||
return result;
|
||||
} else {
|
||||
char val[4];
|
||||
size_t result_len = 5 + 3*ivl_logic_width(lptr);
|
||||
char*result = malloc(result_len);
|
||||
char*dp = result;
|
||||
|
||||
val[0] = "01234567"[ivl_nexus_ptr_drive0(nptr)];
|
||||
val[1] = val[0];
|
||||
val[2] = '1';
|
||||
val[3] = 0;
|
||||
|
||||
strcpy(dp, "C8<");
|
||||
dp += strlen(dp);
|
||||
str_repeat(dp, val, ivl_logic_width(lptr));
|
||||
dp += 3*ivl_logic_width(lptr);
|
||||
*dp++ = '>';
|
||||
*dp = 0;
|
||||
assert((dp-result) <= result_len);
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
if (lptr && (nptr_pin == 0)) {
|
||||
char tmp[128];
|
||||
snprintf(tmp, sizeof tmp, "L_%p", lptr);
|
||||
return strdup(tmp);
|
||||
}
|
||||
|
||||
sptr = ivl_nexus_ptr_sig(nptr);
|
||||
if (sptr && (ivl_signal_type(sptr) == IVL_SIT_REG)) {
|
||||
char tmp[128];
|
||||
/* 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);
|
||||
}
|
||||
|
||||
cptr = ivl_nexus_ptr_con(nptr);
|
||||
if (cptr) {
|
||||
/* Constants should have exactly 1 pin, with a literal value. */
|
||||
assert(nptr_pin == 0);
|
||||
char *result = 0;
|
||||
|
||||
switch (ivl_const_type(cptr)) {
|
||||
case IVL_VT_LOGIC:
|
||||
case IVL_VT_BOOL:
|
||||
if ((ivl_nexus_ptr_drive0(nptr) == IVL_DR_STRONG)
|
||||
&& (ivl_nexus_ptr_drive1(nptr) == IVL_DR_STRONG)) {
|
||||
|
||||
result = draw_C4_to_string(cptr);
|
||||
|
||||
} else {
|
||||
result = draw_C8_to_string(cptr,
|
||||
ivl_nexus_ptr_drive0(nptr),
|
||||
ivl_nexus_ptr_drive1(nptr));
|
||||
}
|
||||
break;
|
||||
|
||||
case IVL_VT_REAL:
|
||||
result = draw_Cr_to_string(ivl_const_real(cptr));
|
||||
break;
|
||||
|
||||
default:
|
||||
assert(0);
|
||||
break;
|
||||
}
|
||||
|
||||
ivl_expr_t d_rise = ivl_const_delay(cptr, 0);
|
||||
ivl_expr_t d_fall = ivl_const_delay(cptr, 1);
|
||||
ivl_expr_t d_decay = ivl_const_delay(cptr, 2);
|
||||
|
||||
/* We have a delayed constant, so we need to build some code. */
|
||||
if (d_rise != 0) {
|
||||
assert(number_is_immediate(d_rise, 64));
|
||||
assert(number_is_immediate(d_fall, 64));
|
||||
assert(number_is_immediate(d_decay, 64));
|
||||
|
||||
fprintf(vvp_out, "L_%p/d .functor BUFZ 1, %s, "
|
||||
"C4<0>, C4<0>, C4<0>;\n", cptr, result);
|
||||
|
||||
fprintf(vvp_out, "L_%p .delay (%lu,%lu,%lu) L_%p/d;\n",
|
||||
cptr, get_number_immediate(d_rise),
|
||||
get_number_immediate(d_rise),
|
||||
get_number_immediate(d_rise), cptr);
|
||||
|
||||
free(result);
|
||||
char tmp[128];
|
||||
snprintf(tmp, sizeof tmp, "L_%p", cptr);
|
||||
result = strdup(tmp);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
lpm = ivl_nexus_ptr_lpm(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:
|
||||
case IVL_LPM_CMP_EEQ:
|
||||
case IVL_LPM_CMP_EQ:
|
||||
case IVL_LPM_CMP_GE:
|
||||
case IVL_LPM_CMP_GT:
|
||||
case IVL_LPM_CMP_NE:
|
||||
case IVL_LPM_CMP_NEE:
|
||||
case IVL_LPM_RE_AND:
|
||||
case IVL_LPM_RE_OR:
|
||||
case IVL_LPM_RE_XOR:
|
||||
case IVL_LPM_RE_NAND:
|
||||
case IVL_LPM_RE_NOR:
|
||||
case IVL_LPM_RE_XNOR:
|
||||
case IVL_LPM_SFUNC:
|
||||
case IVL_LPM_SHIFTL:
|
||||
case IVL_LPM_SHIFTR:
|
||||
case IVL_LPM_SIGN_EXT:
|
||||
case IVL_LPM_SUB:
|
||||
case IVL_LPM_MULT:
|
||||
case IVL_LPM_MUX:
|
||||
case IVL_LPM_POW:
|
||||
case IVL_LPM_DIVIDE:
|
||||
case IVL_LPM_MOD:
|
||||
case IVL_LPM_UFUNC:
|
||||
case IVL_LPM_PART_VP:
|
||||
case IVL_LPM_PART_PV: /* NOTE: This is only a partial driver. */
|
||||
case IVL_LPM_REPEAT:
|
||||
if (ivl_lpm_q(lpm, 0) == nex) {
|
||||
char tmp[128];
|
||||
snprintf(tmp, sizeof tmp, "L_%p", lpm);
|
||||
return strdup(tmp);
|
||||
}
|
||||
break;
|
||||
|
||||
}
|
||||
|
||||
fprintf(stderr, "internal error: no input to nexus %s\n",
|
||||
ivl_nexus_name(nex));
|
||||
assert(0);
|
||||
return strdup("C<z>");
|
||||
}
|
||||
|
||||
static char* draw_island_port(ivl_island_t island,
|
||||
ivl_nexus_t nex, const char*src)
|
||||
{
|
||||
char result[64];
|
||||
if (ivl_island_flag_test(island,0) == 0) {
|
||||
fprintf(vvp_out, "I%p .island tran;\n", island);
|
||||
ivl_island_flag_set(island,0,1);
|
||||
}
|
||||
|
||||
fprintf(vvp_out, "p%p .port I%p, %s;\n", nex, island, src);
|
||||
snprintf(result, sizeof result, "p%p", nex);
|
||||
|
||||
return strdup(result);
|
||||
}
|
||||
|
||||
/*
|
||||
* This function draws the input to a net into a string. What that
|
||||
* means is that it returns a static string that can be used to
|
||||
* represent a resolved driver to a nexus. If there are multiple
|
||||
* drivers to the nexus, then it writes out the resolver declarations
|
||||
* needed to perform strength resolution.
|
||||
*
|
||||
* The string that this returns is malloced, and that means that the
|
||||
* caller must free the string or store it permanently. This function
|
||||
* does *not* check for a previously calculated string. Use the
|
||||
* draw_net_input for the general case.
|
||||
*/
|
||||
/* Omit LPMPART_BI device pin-data(0) drivers. */
|
||||
# define OMIT_PART_BI_DATA 0x0001
|
||||
|
||||
char* draw_net_input_x(ivl_nexus_t nex,
|
||||
ivl_nexus_ptr_t omit_ptr, int omit_flags,
|
||||
struct vvp_nexus_data*nex_data)
|
||||
{
|
||||
ivl_island_t island = 0;
|
||||
ivl_signal_type_t res;
|
||||
char result[512];
|
||||
unsigned idx;
|
||||
int level;
|
||||
unsigned ndrivers = 0;
|
||||
static ivl_nexus_ptr_t *drivers = 0x0;
|
||||
static unsigned adrivers = 0;
|
||||
|
||||
const char*resolv_type;
|
||||
|
||||
char*nex_private = 0;
|
||||
|
||||
/* Accumulate nex_data flags. */
|
||||
int nex_flags = 0;
|
||||
|
||||
res = signal_type_of_nexus(nex);
|
||||
switch (res) {
|
||||
case IVL_SIT_TRI:
|
||||
resolv_type = "tri";
|
||||
break;
|
||||
case IVL_SIT_TRI0:
|
||||
resolv_type = "tri0";
|
||||
nex_flags |= VVP_NEXUS_DATA_STR;
|
||||
break;
|
||||
case IVL_SIT_TRI1:
|
||||
resolv_type = "tri1";
|
||||
nex_flags |= VVP_NEXUS_DATA_STR;
|
||||
break;
|
||||
case IVL_SIT_TRIAND:
|
||||
resolv_type = "triand";
|
||||
break;
|
||||
case IVL_SIT_TRIOR:
|
||||
resolv_type = "trior";
|
||||
break;
|
||||
default:
|
||||
fprintf(stderr, "vvp.tgt: Unsupported signal type: %u\n", res);
|
||||
assert(0);
|
||||
resolv_type = "tri";
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
for (idx = 0 ; idx < ivl_nexus_ptrs(nex) ; idx += 1) {
|
||||
ivl_lpm_t lpm_tmp;
|
||||
ivl_switch_t sw = 0;
|
||||
ivl_nexus_ptr_t nptr = ivl_nexus_ptr(nex, idx);
|
||||
|
||||
/* If this object is part of an island, then we'll be
|
||||
making a port. Save the island cookie. */
|
||||
if ( (sw = ivl_nexus_ptr_switch(nptr)) ) {
|
||||
island = ivl_switch_island(sw);
|
||||
}
|
||||
|
||||
/* If we are supposed to skip LPM_PART_BI data pins,
|
||||
check that this driver is that. */
|
||||
if ((omit_flags&OMIT_PART_BI_DATA)
|
||||
&& (lpm_tmp = ivl_nexus_ptr_lpm(nptr))
|
||||
&& (nex == ivl_lpm_data(lpm_tmp,0)))
|
||||
continue;
|
||||
|
||||
if (nptr == omit_ptr)
|
||||
continue;
|
||||
|
||||
/* Skip input only pins. */
|
||||
if ((ivl_nexus_ptr_drive0(nptr) == IVL_DR_HiZ)
|
||||
&& (ivl_nexus_ptr_drive1(nptr) == IVL_DR_HiZ))
|
||||
continue;
|
||||
|
||||
/* Mark the strength-aware flag if the driver can
|
||||
generate values other than the standard "6"
|
||||
strength. */
|
||||
if (nexus_drive_is_strength_aware(nptr))
|
||||
nex_flags |= VVP_NEXUS_DATA_STR;
|
||||
|
||||
/* Save this driver. */
|
||||
if (ndrivers >= adrivers) {
|
||||
adrivers += 4;
|
||||
drivers = realloc(drivers, adrivers*sizeof(ivl_nexus_ptr_t));
|
||||
assert(drivers);
|
||||
}
|
||||
drivers[ndrivers] = nptr;
|
||||
ndrivers += 1;
|
||||
}
|
||||
|
||||
/* If the caller is collecting nexus information, then save
|
||||
the nexus driver count in the nex_data. */
|
||||
if (nex_data) {
|
||||
nex_data->drivers_count = ndrivers;
|
||||
nex_data->flags |= nex_flags;
|
||||
}
|
||||
|
||||
/* If the nexus has no drivers, then send a constant HiZ into
|
||||
the net. */
|
||||
if (ndrivers == 0) {
|
||||
unsigned idx, wid = width_of_nexus(nex);
|
||||
char*tmp = malloc(wid + 5);
|
||||
nex_private = tmp;
|
||||
strcpy(tmp, "C4<");
|
||||
tmp += strlen(tmp);
|
||||
switch (res) {
|
||||
case IVL_SIT_TRI:
|
||||
for (idx = 0 ; idx < wid ; idx += 1)
|
||||
*tmp++ = 'z';
|
||||
break;
|
||||
case IVL_SIT_TRI0:
|
||||
for (idx = 0 ; idx < wid ; idx += 1)
|
||||
*tmp++ = '0';
|
||||
break;
|
||||
case IVL_SIT_TRI1:
|
||||
for (idx = 0 ; idx < wid ; idx += 1)
|
||||
*tmp++ = '1';
|
||||
break;
|
||||
default:
|
||||
assert(0);
|
||||
}
|
||||
*tmp++ = '>';
|
||||
*tmp = 0;
|
||||
if (island) {
|
||||
char*tmp = draw_island_port(island, nex, nex_private);
|
||||
free(nex_private);
|
||||
nex_private = tmp;
|
||||
}
|
||||
return nex_private;
|
||||
}
|
||||
|
||||
|
||||
/* If the nexus has exactly one driver, then simply draw
|
||||
it. Note that this will *not* work if the nexus is not a
|
||||
TRI type nexus. */
|
||||
if (ndrivers == 1 && res == IVL_SIT_TRI) {
|
||||
ivl_signal_t path_sig = find_modpath(nex);
|
||||
if (path_sig) {
|
||||
char*nex_str = draw_net_input_drive(nex, drivers[0]);
|
||||
char modpath_label[64];
|
||||
snprintf(modpath_label, sizeof modpath_label,
|
||||
"V_%p/m", path_sig);
|
||||
nex_private = strdup(modpath_label);
|
||||
draw_modpath(path_sig, nex_str);
|
||||
|
||||
} else {
|
||||
nex_private = draw_net_input_drive(nex, drivers[0]);
|
||||
}
|
||||
if (island) {
|
||||
char*tmp = draw_island_port(island, nex, nex_private);
|
||||
free(nex_private);
|
||||
nex_private = tmp;
|
||||
}
|
||||
return nex_private;
|
||||
}
|
||||
|
||||
level = 0;
|
||||
while (ndrivers) {
|
||||
unsigned int inst;
|
||||
for (inst = 0; inst < ndrivers; inst += 4) {
|
||||
if (ndrivers > 4)
|
||||
fprintf(vvp_out, "RS_%p/%d/%d .resolv tri",
|
||||
nex, level, inst);
|
||||
else
|
||||
fprintf(vvp_out, "RS_%p .resolv %s",
|
||||
nex, resolv_type);
|
||||
|
||||
for (idx = inst; idx < ndrivers && idx < inst+4; idx += 1) {
|
||||
if (level) {
|
||||
fprintf(vvp_out, ", RS_%p/%d/%d",
|
||||
nex, level - 1, idx*4);
|
||||
} else {
|
||||
char*drive = draw_net_input_drive(nex, drivers[idx]);
|
||||
fprintf(vvp_out, ", %s", drive);
|
||||
free(drive);
|
||||
}
|
||||
}
|
||||
for ( ; idx < inst+4 ; idx += 1) {
|
||||
fprintf(vvp_out, ", ");
|
||||
draw_C4_repeated_constant('z',width_of_nexus(nex));
|
||||
}
|
||||
|
||||
fprintf(vvp_out, ";\n");
|
||||
}
|
||||
if (ndrivers > 4)
|
||||
ndrivers = (ndrivers+3) / 4;
|
||||
else
|
||||
ndrivers = 0;
|
||||
level += 1;
|
||||
}
|
||||
|
||||
snprintf(result, sizeof result, "RS_%p", nex);
|
||||
|
||||
if (island)
|
||||
nex_private = draw_island_port(island, nex, result);
|
||||
else
|
||||
nex_private = strdup(result);
|
||||
|
||||
return nex_private;
|
||||
}
|
||||
|
||||
/*
|
||||
* Get a cached description of the nexus input, or create one if this
|
||||
* nexus has not been cached yet. This is a wrapper for the common
|
||||
* case call to draw_net_input_x.
|
||||
*/
|
||||
const char*draw_net_input(ivl_nexus_t nex)
|
||||
{
|
||||
struct vvp_nexus_data*nex_data = (struct vvp_nexus_data*)
|
||||
ivl_nexus_get_private(nex);
|
||||
|
||||
/* If this nexus already has a label, then its input is
|
||||
already figured out. Just return the existing label. */
|
||||
if (nex_data && nex_data->net_input)
|
||||
return nex_data->net_input;
|
||||
|
||||
if (nex_data == 0) {
|
||||
nex_data = new_nexus_data();
|
||||
ivl_nexus_set_private(nex, nex_data);
|
||||
}
|
||||
|
||||
assert(nex_data->net_input == 0);
|
||||
nex_data->net_input = draw_net_input_x(nex, 0, 0, nex_data);
|
||||
|
||||
return nex_data->net_input;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,81 @@
|
||||
/*
|
||||
* Copyright (c) 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
|
||||
* 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
|
||||
*/
|
||||
|
||||
# include "vvp_priv.h"
|
||||
# include <assert.h>
|
||||
#ifdef HAVE_MALLOC_H
|
||||
# include <malloc.h>
|
||||
#endif
|
||||
# include <stdlib.h>
|
||||
# include <string.h>
|
||||
|
||||
static void draw_tran_island(ivl_island_t island)
|
||||
{
|
||||
fprintf(vvp_out, "I%p .island tran;\n", island);
|
||||
ivl_island_flag_set(island, 0, 1);
|
||||
}
|
||||
|
||||
void draw_switch_in_scope(ivl_switch_t sw)
|
||||
{
|
||||
ivl_island_t island = ivl_switch_island(sw);
|
||||
if (ivl_island_flag_test(island, 0) == 0)
|
||||
draw_tran_island(island);
|
||||
|
||||
ivl_nexus_t nex_a = ivl_switch_a(sw);
|
||||
assert(nex_a);
|
||||
const char*str_a = draw_net_input(nex_a);
|
||||
|
||||
ivl_nexus_t nex_b = ivl_switch_b(sw);
|
||||
assert(nex_b);
|
||||
const char*str_b = draw_net_input(nex_b);
|
||||
|
||||
ivl_nexus_t enable = ivl_switch_enable(sw);
|
||||
const char*str_e = 0;
|
||||
if (enable)
|
||||
str_e = draw_net_input(enable);
|
||||
|
||||
|
||||
switch (ivl_switch_type(sw)) {
|
||||
case IVL_SW_TRAN:
|
||||
fprintf(vvp_out, " .tran");
|
||||
break;
|
||||
case IVL_SW_TRANIF0:
|
||||
fprintf(vvp_out, " .tranif0");
|
||||
break;
|
||||
case IVL_SW_TRANIF1:
|
||||
fprintf(vvp_out, " .tranif1");
|
||||
break;
|
||||
case IVL_SW_TRAN_VP:
|
||||
fprintf(vvp_out, " .tranvp %u %u %u,",
|
||||
ivl_switch_width(sw), ivl_switch_part(sw), ivl_switch_offset(sw));
|
||||
break;
|
||||
|
||||
default:
|
||||
fprintf(stderr, "%s:%u: sorry: vvp target does not support switch modeling.\n",
|
||||
ivl_switch_file(sw), ivl_switch_lineno(sw));
|
||||
vvp_errors += 1;
|
||||
return;
|
||||
}
|
||||
|
||||
fprintf(vvp_out, " I%p, %s %s", island, str_a, str_b);
|
||||
if (enable)
|
||||
fprintf(vvp_out, ", %s", str_e);
|
||||
|
||||
fprintf(vvp_out, ";\n");
|
||||
}
|
||||
+230
-137
@@ -25,6 +25,86 @@
|
||||
# include <stdlib.h>
|
||||
# include <assert.h>
|
||||
|
||||
#ifdef __MINGW32__ /* MinGW has inconsistent %p output. */
|
||||
#define snprintf _snprintf
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Check to see if the expression (number) can be correctly represented
|
||||
* with a long variable.
|
||||
*/
|
||||
static int is_constant_number(ivl_expr_t ex)
|
||||
{
|
||||
/* Make sure this matches the return type of constant_number(). */
|
||||
unsigned lim_wid = 8*sizeof(long);
|
||||
const char*bits;
|
||||
char pad_bit = '0';
|
||||
unsigned idx;
|
||||
unsigned nbits = ivl_expr_width(ex);
|
||||
|
||||
if (ivl_expr_type(ex) != IVL_EX_NUMBER
|
||||
&& ivl_expr_type(ex) != IVL_EX_ULONG)
|
||||
return 0;
|
||||
|
||||
bits = ivl_expr_bits(ex);
|
||||
|
||||
/* For unsigned values the effective MSB and on must be '0'. */
|
||||
if (!ivl_expr_signed(ex)) lim_wid -= 1;
|
||||
|
||||
/* For negative values the pad bit is '1'. */
|
||||
if (ivl_expr_signed(ex) && bits[nbits-1]=='1') {
|
||||
pad_bit = '1';
|
||||
}
|
||||
|
||||
/* For the number to fit in the variable all the upper bits must
|
||||
* match the pad bits. */
|
||||
for (idx = lim_wid ; idx < nbits ; idx += 1) {
|
||||
if (bits[idx] != pad_bit) return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Convert the expression (number) to a long value.
|
||||
*/
|
||||
static long get_constant_number(ivl_expr_t ex)
|
||||
{
|
||||
long rtn = 0;
|
||||
|
||||
switch (ivl_expr_type(ex)) {
|
||||
case IVL_EX_ULONG:
|
||||
rtn = (signed)ivl_expr_value(ex);
|
||||
break;
|
||||
case IVL_EX_NUMBER: {
|
||||
unsigned idx;
|
||||
const char*bits = ivl_expr_bits(ex);
|
||||
unsigned nbits = ivl_expr_width(ex);
|
||||
char pad_bit = bits[nbits-1];
|
||||
/* Define all the bits in the long (negative numbers). */
|
||||
for (idx = 0 ; idx < 8*sizeof(long) ; idx += 1) {
|
||||
char bit;
|
||||
if (idx < nbits) bit = bits[idx];
|
||||
else bit = pad_bit;
|
||||
switch (bit) {
|
||||
case '0':
|
||||
break;
|
||||
case '1':
|
||||
rtn |= 1 << idx;
|
||||
break;
|
||||
default:
|
||||
assert(0);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
assert(0);
|
||||
}
|
||||
|
||||
return rtn;
|
||||
}
|
||||
|
||||
static const char* magic_sfuncs[] = {
|
||||
"$time",
|
||||
"$stime",
|
||||
@@ -52,9 +132,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 +152,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 +177,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,23 +249,89 @@ 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) {
|
||||
struct vector_info av;
|
||||
av = draw_eval_expr(word_ex, STUFF_OK_XZ);
|
||||
snprintf(buffer, sizeof buffer,
|
||||
"&A<v%p, T<%u,%u,u>>", sig, av.base, av.wid);
|
||||
args[idx].vec = av;
|
||||
args[idx].vec_flag = 1;
|
||||
} else {
|
||||
snprintf(buffer, sizeof buffer,
|
||||
"&A<v%p, %u>", sig, use_word);
|
||||
}
|
||||
args[idx].text = strdup(buffer);
|
||||
continue;
|
||||
}
|
||||
|
||||
case IVL_EX_SELECT: {
|
||||
ivl_expr_t vexpr = ivl_expr_oper1(expr);
|
||||
assert(vexpr);
|
||||
|
||||
case IVL_EX_MEMORY:
|
||||
if (!ivl_expr_oper1(expr)) {
|
||||
continue;
|
||||
}
|
||||
/* This code is only for signals. */
|
||||
if (ivl_expr_type(vexpr) != IVL_EX_SIGNAL) break;
|
||||
|
||||
/* The signal is part of an array. */
|
||||
/* Add &APV<> code here when it is finished. */
|
||||
if (ivl_expr_oper1(vexpr)) break;
|
||||
|
||||
ivl_expr_t bexpr = ivl_expr_oper2(expr);
|
||||
assert(bexpr);
|
||||
|
||||
/* This is a constant bit/part select. */
|
||||
if (is_constant_number(bexpr)) {
|
||||
snprintf(buffer, sizeof buffer, "&PV<v%p_0, %ld, %u>",
|
||||
ivl_expr_signal(vexpr),
|
||||
get_constant_number(bexpr),
|
||||
ivl_expr_width(expr));
|
||||
/* This is an indexed bit/part select. */
|
||||
} else {
|
||||
struct vector_info rv;
|
||||
rv = draw_eval_expr(bexpr, STUFF_OK_XZ);
|
||||
snprintf(buffer, sizeof buffer, "&PV<v%p_0, %u %u, %u>",
|
||||
ivl_expr_signal(vexpr),
|
||||
rv.base, rv.wid,
|
||||
ivl_expr_width(expr));
|
||||
}
|
||||
args[idx].text = strdup(buffer);
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Everything else will need to be evaluated and
|
||||
passed as a constant to the vpi task. */
|
||||
@@ -146,143 +339,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");
|
||||
}
|
||||
|
||||
+174
-61
@@ -92,7 +92,8 @@ unsigned long get_number_immediate(ivl_expr_t ex)
|
||||
case '0':
|
||||
break;
|
||||
case '1':
|
||||
imm |= 1 << idx;
|
||||
assert(idx < 8*sizeof(imm));
|
||||
imm |= 1UL << idx;
|
||||
break;
|
||||
default:
|
||||
assert(0);
|
||||
@@ -138,8 +139,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);
|
||||
@@ -895,12 +910,43 @@ static struct vector_info draw_binary_expr_le(ivl_expr_t exp,
|
||||
return lv;
|
||||
}
|
||||
|
||||
static struct vector_info draw_logic_immediate(ivl_expr_t exp,
|
||||
ivl_expr_t le,
|
||||
ivl_expr_t re,
|
||||
unsigned wid)
|
||||
{
|
||||
struct vector_info lv = draw_eval_expr_wid(le, wid, STUFF_OK_XZ);
|
||||
unsigned long imm = get_number_immediate(re);
|
||||
|
||||
assert(lv.base >= 4);
|
||||
|
||||
switch (ivl_expr_opcode(exp)) {
|
||||
|
||||
case '&':
|
||||
fprintf(vvp_out, " %%andi %u, %lu, %u;\n", lv.base, imm, lv.wid);
|
||||
break;
|
||||
|
||||
default:
|
||||
assert(0);
|
||||
break;
|
||||
}
|
||||
|
||||
return lv;
|
||||
}
|
||||
|
||||
static struct vector_info draw_binary_expr_logic(ivl_expr_t exp,
|
||||
unsigned wid)
|
||||
{
|
||||
ivl_expr_t le = ivl_expr_oper1(exp);
|
||||
ivl_expr_t re = ivl_expr_oper2(exp);
|
||||
|
||||
if (ivl_expr_opcode(exp) == '&') {
|
||||
if (number_is_immediate(re, IMM_WID) && !number_is_unknown(re))
|
||||
return draw_logic_immediate(exp, le, re, wid);
|
||||
if (number_is_immediate(le, IMM_WID) && !number_is_unknown(le))
|
||||
return draw_logic_immediate(exp, re, le, wid);
|
||||
}
|
||||
|
||||
struct vector_info lv;
|
||||
struct vector_info rv;
|
||||
|
||||
@@ -1152,23 +1198,50 @@ static struct vector_info draw_add_immediate(ivl_expr_t le,
|
||||
|
||||
imm = get_number_immediate(re);
|
||||
|
||||
/* Now generate enough %addi instructions to add the entire
|
||||
immediate value to the destination. The adds are done 16
|
||||
bits at a time, but 17 bits are done to push the carry into
|
||||
the higher bits if needed. */
|
||||
{ unsigned base;
|
||||
for (base = 0 ; base < lv.wid ; base += 16) {
|
||||
unsigned long tmp = imm & 0xffffUL;
|
||||
unsigned add_wid = lv.wid - base;
|
||||
/* This shouldn't generally happen, because the elaborator
|
||||
should take care of simple constant propagation like this,
|
||||
but it doesn't have to and it is easy to catch here. */
|
||||
if (imm == 0)
|
||||
return lv;
|
||||
|
||||
imm >>= 16;
|
||||
switch (lv.base) {
|
||||
case 0: /* Left expression is 0. */
|
||||
lv.base = allocate_vector(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(re), ivl_expr_lineno(re), wid);
|
||||
vvp_errors += 1;
|
||||
}
|
||||
fprintf(vvp_out, " %%movi %u, %lu %u;\n", lv.base, imm, wid);
|
||||
break;
|
||||
|
||||
fprintf(vvp_out, " %%addi %u, %lu, %u;\n",
|
||||
lv.base+base, tmp, add_wid);
|
||||
case 1: /* Left expression is 1...1 (i.e. -1) */
|
||||
imm -= 1;
|
||||
if (imm == 0) {
|
||||
lv.base = 0;
|
||||
} else {
|
||||
lv.base = allocate_vector(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(re), ivl_expr_lineno(re), wid);
|
||||
vvp_errors += 1;
|
||||
}
|
||||
fprintf(vvp_out, " %%movi %u, %lu %u;\n", lv.base, imm, wid);
|
||||
}
|
||||
break;
|
||||
|
||||
if (imm == 0)
|
||||
break;
|
||||
}
|
||||
case 2: /* Left expression is X or Z */
|
||||
case 3:
|
||||
lv.base = 2;
|
||||
break;
|
||||
|
||||
default: /* The regular case. */
|
||||
fprintf(vvp_out, " %%addi %u, %lu, %u;\n", lv.base, imm, wid);
|
||||
break;
|
||||
}
|
||||
|
||||
return lv;
|
||||
@@ -1189,7 +1262,8 @@ static struct vector_info draw_sub_immediate(ivl_expr_t le,
|
||||
assert(lv.wid == wid);
|
||||
|
||||
imm = get_number_immediate(re);
|
||||
assert( (imm & ~0xffff) == 0 );
|
||||
if (imm == 0)
|
||||
return lv;
|
||||
|
||||
switch (lv.base) {
|
||||
case 0:
|
||||
@@ -1203,21 +1277,21 @@ static struct vector_info draw_sub_immediate(ivl_expr_t le,
|
||||
vvp_errors += 1;
|
||||
}
|
||||
|
||||
fprintf(vvp_out, " %%mov %u, %u, %u;\n", tmp, lv.base, wid);
|
||||
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);
|
||||
return lv;
|
||||
fprintf(vvp_out, " %%subi %u, %lu, %u;\n", lv.base, imm, wid);
|
||||
break;
|
||||
|
||||
case 2:
|
||||
case 3:
|
||||
lv.base = 2;
|
||||
return lv;
|
||||
break;
|
||||
|
||||
default:
|
||||
fprintf(vvp_out, " %%subi %u, %lu, %u;\n", lv.base, imm, wid);
|
||||
fprintf(vvp_out, " %%subi %u, %lu, %u;\n", lv.base, imm, wid);
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
return lv;
|
||||
}
|
||||
|
||||
@@ -1232,8 +1306,10 @@ static struct vector_info draw_mul_immediate(ivl_expr_t le,
|
||||
assert(lv.wid == wid);
|
||||
|
||||
imm = get_number_immediate(re);
|
||||
if (imm == 0)
|
||||
return lv;
|
||||
|
||||
fprintf(vvp_out, " %%muli %u, %lu, %u;\n", lv.base, imm, lv.wid);
|
||||
fprintf(vvp_out, " %%muli %u, %lu, %u;\n", lv.base, imm, lv.wid);
|
||||
|
||||
return lv;
|
||||
}
|
||||
@@ -1246,7 +1322,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)
|
||||
@@ -1285,13 +1361,13 @@ static struct vector_info draw_binary_expr_arith(ivl_expr_t exp, unsigned wid)
|
||||
if ((ivl_expr_opcode(exp) == '-')
|
||||
&& (ivl_expr_type(re) == IVL_EX_NUMBER)
|
||||
&& (! number_is_unknown(re))
|
||||
&& number_is_immediate(re, 16))
|
||||
&& number_is_immediate(re, IMM_WID))
|
||||
return draw_sub_immediate(le, re, wid);
|
||||
|
||||
if ((ivl_expr_opcode(exp) == '*')
|
||||
&& (ivl_expr_type(re) == IVL_EX_NUMBER)
|
||||
&& (! number_is_unknown(re))
|
||||
&& number_is_immediate(re, 16))
|
||||
&& number_is_immediate(re, IMM_WID))
|
||||
return draw_mul_immediate(le, re, wid);
|
||||
|
||||
lv = draw_eval_expr_wid(le, wid, STUFF_OK_XZ);
|
||||
@@ -1598,9 +1674,9 @@ static struct vector_info draw_number_expr(ivl_expr_t exp, unsigned wid)
|
||||
vvp_errors += 1;
|
||||
}
|
||||
|
||||
if ((!number_is_unknown(exp)) && number_is_immediate(exp, 16)) {
|
||||
int val = get_number_immediate(exp);
|
||||
fprintf(vvp_out, " %%movi %u, %d, %u;\n", res.base, val, wid);
|
||||
if ((!number_is_unknown(exp)) && number_is_immediate(exp, IMM_WID)) {
|
||||
unsigned long val = get_number_immediate(exp);
|
||||
fprintf(vvp_out, " %%movi %u, %lu, %u;\n", res.base, val, wid);
|
||||
return res;
|
||||
}
|
||||
|
||||
@@ -1822,8 +1898,8 @@ static struct vector_info draw_string_expr(ivl_expr_t exp, unsigned wid)
|
||||
idx = 0;
|
||||
while (idx < nwid) {
|
||||
unsigned bits;
|
||||
unsigned trans = 16;
|
||||
if (nwid-idx < 16)
|
||||
unsigned trans = IMM_WID;
|
||||
if (nwid-idx < trans)
|
||||
trans = nwid-idx;
|
||||
|
||||
bits = *p;
|
||||
@@ -1831,6 +1907,14 @@ static struct vector_info draw_string_expr(ivl_expr_t exp, unsigned wid)
|
||||
if (trans > 8) {
|
||||
bits |= *p << 8;
|
||||
p -= 1;
|
||||
if (trans > 16) {
|
||||
bits |= *p << 16;
|
||||
p -= 1;
|
||||
if (trans > 24) {
|
||||
bits |= *p << 24;
|
||||
p -= 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
fprintf(vvp_out, " %%movi %u, %u, %u;\n", res.base+idx,bits,trans);
|
||||
|
||||
@@ -1867,8 +1951,14 @@ void pad_expr_in_place(ivl_expr_t exp, struct vector_info res, unsigned swid)
|
||||
res.base+idx, res.base+swid-1);
|
||||
|
||||
} else {
|
||||
fprintf(vvp_out, " %%mov %u, 0, %u;\n",
|
||||
res.base+swid, res.wid-swid);
|
||||
unsigned base = res.base+swid;
|
||||
unsigned count = res.wid-swid;
|
||||
/* The %movi is faster for larger widths, but for very
|
||||
small counts, the %mov is faster. */
|
||||
if (count > 4)
|
||||
fprintf(vvp_out, " %%movi %u, 0, %u;\n", base, count);
|
||||
else
|
||||
fprintf(vvp_out, " %%mov %u, 0, %u;\n", base, count);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1894,28 +1984,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;
|
||||
}
|
||||
|
||||
|
||||
@@ -2030,14 +2115,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
|
||||
@@ -2075,7 +2162,7 @@ static struct vector_info draw_select_signal(ivl_expr_t sube,
|
||||
|
||||
for (idx = 0 ; idx < res.wid ; idx += 1) {
|
||||
if (idx >= bit_wid) {
|
||||
fprintf(vvp_out, " %%mov %u, 0, %u; Pad from %u to %u\n",
|
||||
fprintf(vvp_out, " %%movi %u, 0, %u; Pad from %u to %u\n",
|
||||
res.base+idx, res.wid-idx,
|
||||
ivl_expr_width(sube), wid);
|
||||
break;
|
||||
@@ -2399,7 +2486,7 @@ static struct vector_info draw_unary_expr(ivl_expr_t exp, unsigned wid)
|
||||
|
||||
fprintf(vvp_out, " %%mov %u, %u, %u;\n",
|
||||
tmp.base, res.base, res.wid);
|
||||
fprintf(vvp_out, " %%mov %u, 0, %u;\n",
|
||||
fprintf(vvp_out, " %%movi %u, 0, %u;\n",
|
||||
tmp.base+res.wid, tmp.wid-res.wid);
|
||||
clr_vector(res);
|
||||
res = tmp;
|
||||
@@ -2449,13 +2536,39 @@ static struct vector_info draw_unary_expr(ivl_expr_t exp, unsigned 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",
|
||||
fprintf(vvp_out, " %%movi %u, 0, %u;\n",
|
||||
tmp.base+res.wid, tmp.wid-res.wid);
|
||||
clr_vector(res);
|
||||
res = tmp;
|
||||
}
|
||||
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));
|
||||
|
||||
@@ -112,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));
|
||||
@@ -420,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;
|
||||
|
||||
@@ -22,6 +22,10 @@
|
||||
# include <stdlib.h>
|
||||
# include <assert.h>
|
||||
|
||||
#ifdef __MINGW32__ /* MinGW has inconsistent %p output. */
|
||||
#define snprintf _snprintf
|
||||
#endif
|
||||
|
||||
static ivl_signal_t find_path_source_port(ivl_delaypath_t path)
|
||||
{
|
||||
int idx;
|
||||
|
||||
+40
-1
@@ -1,7 +1,7 @@
|
||||
#ifndef __vvp_priv_H
|
||||
#define __vvp_priv_H
|
||||
/*
|
||||
* Copyright (c) 2001-2005 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
|
||||
@@ -39,12 +39,20 @@ struct vector_info {
|
||||
unsigned wid;
|
||||
};
|
||||
|
||||
/*
|
||||
* Convenient constants...
|
||||
*/
|
||||
/* Width limit for typical immediate arguments. */
|
||||
# define IMM_WID 32
|
||||
|
||||
/*
|
||||
* Mangle all non-symbol characters in an identifier, quotes in names
|
||||
*/
|
||||
extern const char *vvp_mangle_id(const char *);
|
||||
extern const char *vvp_mangle_name(const char *);
|
||||
|
||||
extern char* draw_Cr_to_string(double value);
|
||||
|
||||
/*
|
||||
* This generates a string from a signal that uniquely identifies
|
||||
* that signal with letters that can be used in a label.
|
||||
@@ -59,6 +67,8 @@ extern const char* vvp_signal_label(ivl_signal_t sig);
|
||||
extern unsigned width_of_nexus(ivl_nexus_t nex);
|
||||
extern ivl_variable_type_t data_type_of_nexus(ivl_nexus_t nex);
|
||||
|
||||
extern int can_elide_bufz(ivl_net_logic_t net, ivl_nexus_ptr_t nptr);
|
||||
|
||||
/*
|
||||
* This function draws a process (initial or always) into the output
|
||||
* file. It normally returns 0, but returns !0 of there is some sort
|
||||
@@ -104,6 +114,24 @@ extern struct vector_info draw_vpi_func_call(ivl_expr_t exp,
|
||||
unsigned wid);
|
||||
extern int draw_vpi_rfunc_call(ivl_expr_t exp);
|
||||
|
||||
/*
|
||||
* Switches (tran)
|
||||
*/
|
||||
extern void draw_switch_in_scope(ivl_switch_t sw);
|
||||
|
||||
/* Draw_net_input and friends uses this. */
|
||||
struct vvp_nexus_data {
|
||||
/* draw_net_input uses this */
|
||||
const char*net_input;
|
||||
unsigned drivers_count;
|
||||
int flags;
|
||||
/* draw_net_in_scope uses these to identify the controlling word. */
|
||||
ivl_signal_t net;
|
||||
unsigned net_word;
|
||||
};
|
||||
#define VVP_NEXUS_DATA_STR 0x0001
|
||||
|
||||
|
||||
/*
|
||||
* Given a nexus, draw a string that represents the functor output
|
||||
* that feeds the nexus. This function can be used to get the input to
|
||||
@@ -114,6 +142,17 @@ extern int draw_vpi_rfunc_call(ivl_expr_t exp);
|
||||
*/
|
||||
extern const char* draw_net_input(ivl_nexus_t nex);
|
||||
|
||||
/*
|
||||
* See draw_net_input.c for details on draw_net_input_x. (It would be
|
||||
* nice if this can be made private.)
|
||||
*/
|
||||
/* Omit LPMPART_BI device pin-data(0) drivers. */
|
||||
# define OMIT_PART_BI_DATA 0x0001
|
||||
struct vvp_nexus_data;
|
||||
extern char* draw_net_input_x(ivl_nexus_t nex,
|
||||
ivl_nexus_ptr_t omit_ptr, int omit_flags,
|
||||
struct vvp_nexus_data*nex_data);
|
||||
|
||||
/*
|
||||
* This function is different from draw_net_input in that it will
|
||||
* return a reference to a net as its first choice. This reference
|
||||
|
||||
+89
-32
@@ -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);
|
||||
@@ -185,44 +220,70 @@ static void set_to_lvariable(ivl_lval_t lval,
|
||||
|
||||
static void assign_to_array_word(ivl_signal_t lsig, ivl_expr_t word_ix,
|
||||
unsigned bit, unsigned delay, ivl_expr_t dexp,
|
||||
unsigned width)
|
||||
ivl_expr_t part_off_ex, unsigned width)
|
||||
{
|
||||
unsigned skip_assign = transient_id++;
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
if (dexp == 0) {
|
||||
/* Constant delay... */
|
||||
/* 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);
|
||||
|
||||
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);
|
||||
/* Store constant (0) word part select into index 1 */
|
||||
fprintf(vvp_out, " %%ix/load 1, 0;\n");
|
||||
|
||||
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);
|
||||
fprintf(vvp_out, "t_%u ;\n", skip_assign);
|
||||
} else {
|
||||
/* Calculated delay... */
|
||||
int delay_index = allocate_word();
|
||||
draw_eval_expr_into_integer(dexp, delay_index);
|
||||
/* 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);
|
||||
|
||||
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);
|
||||
/* Store constant (0) word part select into index 1 */
|
||||
fprintf(vvp_out, " %%ix/load 1, 0;\n");
|
||||
|
||||
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, "t_%u ;\n", skip_assign);
|
||||
}
|
||||
|
||||
fprintf(vvp_out, "t_%u ;\n", skip_assign);
|
||||
|
||||
clear_expression_lookaside();
|
||||
}
|
||||
|
||||
@@ -235,16 +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))) {
|
||||
assign_to_array_word(sig, word_ix, bit, delay, dexp, 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) {
|
||||
|
||||
+46
-730
@@ -27,24 +27,11 @@
|
||||
# include <inttypes.h>
|
||||
# include <assert.h>
|
||||
|
||||
struct vvp_nexus_data {
|
||||
/* draw_net_input uses this */
|
||||
const char*net_input;
|
||||
unsigned drivers_count;
|
||||
int flags;
|
||||
/* draw_net_in_scope uses these to identify the controlling word. */
|
||||
ivl_signal_t net;
|
||||
unsigned net_word;
|
||||
};
|
||||
#define VVP_NEXUS_DATA_STR 0x0001
|
||||
#ifdef __MINGW32__ /* MinGW has inconsistent %p output. */
|
||||
#define snprintf _snprintf
|
||||
#endif
|
||||
|
||||
|
||||
static struct vvp_nexus_data*new_nexus_data()
|
||||
{
|
||||
struct vvp_nexus_data*data = calloc(1, sizeof(struct vvp_nexus_data));
|
||||
return data;
|
||||
}
|
||||
|
||||
/*
|
||||
* Escape non-symbol characters in ids, and quotes in strings.
|
||||
*/
|
||||
@@ -143,27 +130,6 @@ const char *vvp_mangle_name(const char *id)
|
||||
return out;
|
||||
}
|
||||
|
||||
static void draw_C4_repeated_constant(char bit_char, unsigned width)
|
||||
{
|
||||
unsigned idx;
|
||||
|
||||
fprintf(vvp_out, "C4<");
|
||||
for (idx = 0 ; idx < width ; idx += 1)
|
||||
fprintf(vvp_out, "%c", bit_char);
|
||||
|
||||
fprintf(vvp_out, ">");
|
||||
}
|
||||
|
||||
static void str_repeat(char*buf, const char*str, unsigned rpt)
|
||||
{
|
||||
unsigned idx;
|
||||
size_t len = strlen(str);
|
||||
for (idx = 0 ; idx < rpt ; idx += 1) {
|
||||
strcpy(buf, str);
|
||||
buf += len;
|
||||
}
|
||||
}
|
||||
|
||||
/* REMOVE ME: vvp_signal_label should not be used. DEAD CODE
|
||||
* Given a signal, generate a string name that is suitable for use as
|
||||
* a label. The only rule is that the same signal will always have the
|
||||
@@ -194,31 +160,6 @@ ivl_signal_t signal_of_nexus(ivl_nexus_t nex, unsigned*word)
|
||||
return 0;
|
||||
}
|
||||
|
||||
ivl_signal_type_t signal_type_of_nexus(ivl_nexus_t nex)
|
||||
{
|
||||
unsigned idx;
|
||||
ivl_signal_type_t out = IVL_SIT_TRI;
|
||||
|
||||
for (idx = 0 ; idx < ivl_nexus_ptrs(nex) ; idx += 1) {
|
||||
ivl_signal_type_t stype;
|
||||
ivl_nexus_ptr_t ptr = ivl_nexus_ptr(nex, idx);
|
||||
ivl_signal_t sig = ivl_nexus_ptr_sig(ptr);
|
||||
if (sig == 0)
|
||||
continue;
|
||||
|
||||
stype = ivl_signal_type(sig);
|
||||
if (stype == IVL_SIT_REG)
|
||||
continue;
|
||||
if (stype == IVL_SIT_TRI)
|
||||
continue;
|
||||
if (stype == IVL_SIT_NONE)
|
||||
continue;
|
||||
out = stype;
|
||||
}
|
||||
|
||||
return out;
|
||||
}
|
||||
|
||||
unsigned width_of_nexus(ivl_nexus_t nex)
|
||||
{
|
||||
unsigned idx;
|
||||
@@ -328,7 +269,7 @@ const char*drive_string(ivl_drive_t drive)
|
||||
* gate will be generated for this node. Otherwise, the code generator
|
||||
* will connect its input to its output and skip the gate.
|
||||
*/
|
||||
static int can_elide_bufz(ivl_net_logic_t net, ivl_nexus_ptr_t nptr)
|
||||
int can_elide_bufz(ivl_net_logic_t net, ivl_nexus_ptr_t nptr)
|
||||
{
|
||||
ivl_nexus_t in_n;
|
||||
unsigned idx;
|
||||
@@ -376,100 +317,7 @@ static int can_elide_bufz(ivl_net_logic_t net, ivl_nexus_ptr_t nptr)
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Given a nexus, look for a signal that has module delay
|
||||
* paths. Return that signal. (There should be no more than 1.) If we
|
||||
* don't find any, then return nil.
|
||||
*/
|
||||
static ivl_signal_t find_modpath(ivl_nexus_t nex)
|
||||
{
|
||||
unsigned idx;
|
||||
for (idx = 0 ; idx < ivl_nexus_ptrs(nex) ; idx += 1) {
|
||||
ivl_nexus_ptr_t ptr = ivl_nexus_ptr(nex,idx);
|
||||
ivl_signal_t sig = ivl_nexus_ptr_sig(ptr);
|
||||
if (sig == 0)
|
||||
continue;
|
||||
if (ivl_signal_npath(sig) == 0)
|
||||
continue;
|
||||
|
||||
return sig;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static char* draw_C4_to_string(ivl_net_const_t cptr)
|
||||
{
|
||||
const char*bits = ivl_const_bits(cptr);
|
||||
unsigned idx;
|
||||
|
||||
size_t result_len = 5 + ivl_const_width(cptr);
|
||||
char*result = malloc(result_len);
|
||||
char*dp = result;
|
||||
strcpy(dp, "C4<");
|
||||
dp += strlen(dp);
|
||||
|
||||
for (idx = 0 ; idx < ivl_const_width(cptr) ; idx += 1) {
|
||||
char bitchar = bits[ivl_const_width(cptr)-idx-1];
|
||||
*dp++ = bitchar;
|
||||
assert((dp - result) < result_len);
|
||||
}
|
||||
|
||||
strcpy(dp, ">");
|
||||
return result;
|
||||
}
|
||||
|
||||
static char* draw_C8_to_string(ivl_net_const_t cptr,
|
||||
ivl_drive_t dr0, ivl_drive_t dr1)
|
||||
{
|
||||
size_t nresult = 5 + 3*ivl_const_width(cptr);
|
||||
char*result = malloc(nresult);
|
||||
const char*bits = ivl_const_bits(cptr);
|
||||
unsigned idx;
|
||||
|
||||
char dr0c = "01234567"[dr0];
|
||||
char dr1c = "01234567"[dr1];
|
||||
char*dp = result;
|
||||
|
||||
strcpy(dp, "C8<");
|
||||
dp += strlen(dp);
|
||||
|
||||
for (idx = 0 ; idx < ivl_const_width(cptr) ; idx += 1) {
|
||||
switch (bits[ivl_const_width(cptr)-idx-1]) {
|
||||
case '0':
|
||||
*dp++ = dr0c;
|
||||
*dp++ = dr0c;
|
||||
*dp++ = '0';
|
||||
break;
|
||||
case '1':
|
||||
*dp++ = dr1c;
|
||||
*dp++ = dr1c;
|
||||
*dp++ = '1';
|
||||
break;
|
||||
case 'x':
|
||||
case 'X':
|
||||
*dp++ = dr0c;
|
||||
*dp++ = dr1c;
|
||||
*dp++ = 'x';
|
||||
break;
|
||||
case 'z':
|
||||
case 'Z':
|
||||
*dp++ = '0';
|
||||
*dp++ = '0';
|
||||
*dp++ = 'z';
|
||||
break;
|
||||
default:
|
||||
assert(0);
|
||||
break;
|
||||
}
|
||||
assert(dp - result < nresult);
|
||||
}
|
||||
|
||||
strcpy(dp, ">");
|
||||
return result;
|
||||
}
|
||||
|
||||
static char* draw_Cr_to_string(double value)
|
||||
char* draw_Cr_to_string(double value)
|
||||
{
|
||||
char tmp[256];
|
||||
|
||||
@@ -504,481 +352,6 @@ static char* draw_Cr_to_string(double value)
|
||||
return strdup(tmp);
|
||||
}
|
||||
|
||||
/*
|
||||
* This function takes a nexus and looks for an input functor. It then
|
||||
* draws to the output a string that represents that functor. What we
|
||||
* are trying to do here is find the input to the net that is attached
|
||||
* to this nexus.
|
||||
*/
|
||||
|
||||
static char* draw_net_input_drive(ivl_nexus_t nex, ivl_nexus_ptr_t nptr)
|
||||
{
|
||||
unsigned nptr_pin = ivl_nexus_ptr_pin(nptr);
|
||||
ivl_net_const_t cptr;
|
||||
ivl_net_logic_t lptr;
|
||||
ivl_signal_t sptr;
|
||||
ivl_lpm_t lpm;
|
||||
|
||||
lptr = ivl_nexus_ptr_log(nptr);
|
||||
if (lptr && (ivl_logic_type(lptr) == IVL_LO_BUFZ) && (nptr_pin == 0))
|
||||
do {
|
||||
if (! can_elide_bufz(lptr, nptr))
|
||||
break;
|
||||
|
||||
return strdup(draw_net_input(ivl_logic_pin(lptr, 1)));
|
||||
} while(0);
|
||||
|
||||
/* If this is a pulldown device, then there is a single pin
|
||||
that drives a constant value to the entire width of the
|
||||
vector. The driver normally drives a pull0 value, so a C8<>
|
||||
constant is appropriate, but if the drive is really strong,
|
||||
then we can draw a C4<> constant instead. */
|
||||
if (lptr && (ivl_logic_type(lptr) == IVL_LO_PULLDOWN)) {
|
||||
if (ivl_nexus_ptr_drive0(nptr) == IVL_DR_STRONG) {
|
||||
size_t result_len = ivl_logic_width(lptr) + 5;
|
||||
char*result = malloc(result_len);
|
||||
char*dp = result;
|
||||
strcpy(dp, "C4<");
|
||||
dp += strlen(dp);
|
||||
str_repeat(dp, "0", ivl_logic_width(lptr));
|
||||
dp += ivl_logic_width(lptr);
|
||||
*dp++ = '>';
|
||||
*dp = 0;
|
||||
assert((dp-result) <= result_len);
|
||||
return result;
|
||||
} else {
|
||||
char val[4];
|
||||
size_t result_len = 3*ivl_logic_width(lptr) + 5;
|
||||
char*result = malloc(result_len);
|
||||
char*dp = result;
|
||||
|
||||
val[0] = "01234567"[ivl_nexus_ptr_drive0(nptr)];
|
||||
val[1] = val[0];
|
||||
val[2] = '0';
|
||||
val[3] = 0;
|
||||
|
||||
strcpy(dp, "C8<");
|
||||
dp += strlen(dp);
|
||||
str_repeat(dp, val, ivl_logic_width(lptr));
|
||||
dp += 3*ivl_logic_width(lptr);
|
||||
*dp++ = '>';
|
||||
*dp = 0;
|
||||
assert((dp-result) <= result_len);
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
if (lptr && (ivl_logic_type(lptr) == IVL_LO_PULLUP)) {
|
||||
if (ivl_nexus_ptr_drive1(nptr) == IVL_DR_STRONG) {
|
||||
size_t result_len = 5 + ivl_logic_width(lptr);
|
||||
char*result = malloc(result_len);
|
||||
char*dp = result;
|
||||
strcpy(dp, "C4<");
|
||||
dp += strlen(dp);
|
||||
str_repeat(dp, "1", ivl_logic_width(lptr));
|
||||
dp += ivl_logic_width(lptr);
|
||||
*dp++ = '>';
|
||||
*dp = 0;
|
||||
assert((dp-result) <= result_len);
|
||||
return result;
|
||||
} else {
|
||||
char val[4];
|
||||
size_t result_len = 5 + 3*ivl_logic_width(lptr);
|
||||
char*result = malloc(result_len);
|
||||
char*dp = result;
|
||||
|
||||
val[0] = "01234567"[ivl_nexus_ptr_drive0(nptr)];
|
||||
val[1] = val[0];
|
||||
val[2] = '1';
|
||||
val[3] = 0;
|
||||
|
||||
strcpy(dp, "C8<");
|
||||
dp += strlen(dp);
|
||||
str_repeat(dp, val, ivl_logic_width(lptr));
|
||||
dp += 3*ivl_logic_width(lptr);
|
||||
*dp++ = '>';
|
||||
*dp = 0;
|
||||
assert((dp-result) <= result_len);
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
if (lptr && (nptr_pin == 0)) {
|
||||
char tmp[128];
|
||||
snprintf(tmp, sizeof tmp, "L_%p", lptr);
|
||||
return strdup(tmp);
|
||||
}
|
||||
|
||||
sptr = ivl_nexus_ptr_sig(nptr);
|
||||
if (sptr && (ivl_signal_type(sptr) == IVL_SIT_REG)) {
|
||||
char tmp[128];
|
||||
/* 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);
|
||||
return strdup(tmp);
|
||||
}
|
||||
|
||||
cptr = ivl_nexus_ptr_con(nptr);
|
||||
if (cptr) {
|
||||
/* Constants should have exactly 1 pin, with a literal value. */
|
||||
assert(nptr_pin == 0);
|
||||
char *result = 0;
|
||||
|
||||
switch (ivl_const_type(cptr)) {
|
||||
case IVL_VT_LOGIC:
|
||||
case IVL_VT_BOOL:
|
||||
if ((ivl_nexus_ptr_drive0(nptr) == IVL_DR_STRONG)
|
||||
&& (ivl_nexus_ptr_drive1(nptr) == IVL_DR_STRONG)) {
|
||||
|
||||
result = draw_C4_to_string(cptr);
|
||||
|
||||
} else {
|
||||
result = draw_C8_to_string(cptr,
|
||||
ivl_nexus_ptr_drive0(nptr),
|
||||
ivl_nexus_ptr_drive1(nptr));
|
||||
}
|
||||
break;
|
||||
|
||||
case IVL_VT_REAL:
|
||||
result = draw_Cr_to_string(ivl_const_real(cptr));
|
||||
break;
|
||||
|
||||
default:
|
||||
assert(0);
|
||||
break;
|
||||
}
|
||||
|
||||
ivl_expr_t d_rise = ivl_const_delay(cptr, 0);
|
||||
ivl_expr_t d_fall = ivl_const_delay(cptr, 1);
|
||||
ivl_expr_t d_decay = ivl_const_delay(cptr, 2);
|
||||
|
||||
/* We have a delayed constant, so we need to build some code. */
|
||||
if (d_rise != 0) {
|
||||
assert(number_is_immediate(d_rise, 64));
|
||||
assert(number_is_immediate(d_fall, 64));
|
||||
assert(number_is_immediate(d_decay, 64));
|
||||
|
||||
fprintf(vvp_out, "L_%p/d .functor BUFZ 1, %s, "
|
||||
"C4<0>, C4<0>, C4<0>;\n", cptr, result);
|
||||
|
||||
fprintf(vvp_out, "L_%p .delay (%lu,%lu,%lu) L_%p/d;\n",
|
||||
cptr, get_number_immediate(d_rise),
|
||||
get_number_immediate(d_rise),
|
||||
get_number_immediate(d_rise), cptr);
|
||||
|
||||
free(result);
|
||||
char tmp[128];
|
||||
snprintf(tmp, sizeof tmp, "L_%p", cptr);
|
||||
result = strdup(tmp);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
lpm = ivl_nexus_ptr_lpm(nptr);
|
||||
if (lpm) switch (ivl_lpm_type(lpm)) {
|
||||
|
||||
case IVL_LPM_FF:
|
||||
case IVL_LPM_ADD:
|
||||
case IVL_LPM_ARRAY:
|
||||
case IVL_LPM_CONCAT:
|
||||
case IVL_LPM_CMP_EEQ:
|
||||
case IVL_LPM_CMP_EQ:
|
||||
case IVL_LPM_CMP_GE:
|
||||
case IVL_LPM_CMP_GT:
|
||||
case IVL_LPM_CMP_NE:
|
||||
case IVL_LPM_CMP_NEE:
|
||||
case IVL_LPM_RE_AND:
|
||||
case IVL_LPM_RE_OR:
|
||||
case IVL_LPM_RE_XOR:
|
||||
case IVL_LPM_RE_NAND:
|
||||
case IVL_LPM_RE_NOR:
|
||||
case IVL_LPM_RE_XNOR:
|
||||
case IVL_LPM_SFUNC:
|
||||
case IVL_LPM_SHIFTL:
|
||||
case IVL_LPM_SHIFTR:
|
||||
case IVL_LPM_SIGN_EXT:
|
||||
case IVL_LPM_SUB:
|
||||
case IVL_LPM_MULT:
|
||||
case IVL_LPM_MUX:
|
||||
case IVL_LPM_POW:
|
||||
case IVL_LPM_DIVIDE:
|
||||
case IVL_LPM_MOD:
|
||||
case IVL_LPM_UFUNC:
|
||||
case IVL_LPM_PART_VP:
|
||||
case IVL_LPM_PART_PV: /* NOTE: This is only a partial driver. */
|
||||
case IVL_LPM_REPEAT:
|
||||
if (ivl_lpm_q(lpm, 0) == nex) {
|
||||
char tmp[128];
|
||||
snprintf(tmp, sizeof tmp, "L_%p", lpm);
|
||||
return strdup(tmp);
|
||||
}
|
||||
break;
|
||||
|
||||
case IVL_LPM_PART_BI:
|
||||
if (ivl_lpm_q(lpm, 0) == nex) {
|
||||
char tmp[128];
|
||||
snprintf(tmp, sizeof tmp, "L_%p/P", lpm);
|
||||
return strdup(tmp);
|
||||
} else if (ivl_lpm_data(lpm,0) == nex) {
|
||||
char tmp[128];
|
||||
snprintf(tmp, sizeof tmp, "L_%p/V", lpm);
|
||||
return strdup(tmp);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
fprintf(stderr, "internal error: no input to nexus %s\n",
|
||||
ivl_nexus_name(nex));
|
||||
assert(0);
|
||||
return strdup("C<z>");
|
||||
}
|
||||
|
||||
static int nexus_drive_is_strength_aware(ivl_nexus_ptr_t nptr)
|
||||
{
|
||||
if (ivl_nexus_ptr_drive0(nptr) != IVL_DR_STRONG)
|
||||
return 1;
|
||||
if (ivl_nexus_ptr_drive1(nptr) != IVL_DR_STRONG)
|
||||
return 1;
|
||||
|
||||
ivl_net_logic_t log = ivl_nexus_ptr_log(nptr);
|
||||
if (log != 0) {
|
||||
/* These logic gates are able to generate unusual
|
||||
strength values and so their outputs are considered
|
||||
strength aware. */
|
||||
if (ivl_logic_type(log) == IVL_LO_BUFIF0)
|
||||
return 1;
|
||||
if (ivl_logic_type(log) == IVL_LO_BUFIF1)
|
||||
return 1;
|
||||
if (ivl_logic_type(log) == IVL_LO_PMOS)
|
||||
return 1;
|
||||
if (ivl_logic_type(log) == IVL_LO_NMOS)
|
||||
return 1;
|
||||
if (ivl_logic_type(log) == IVL_LO_CMOS)
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* This function draws the input to a net into a string. What that
|
||||
* means is that it returns a static string that can be used to
|
||||
* represent a resolved driver to a nexus. If there are multiple
|
||||
* drivers to the nexus, then it writes out the resolver declarations
|
||||
* needed to perform strength resolution.
|
||||
*
|
||||
* The string that this returns is malloced, and that means that the
|
||||
* caller must free the string or store it permanently. This function
|
||||
* does *not* check for a previously calculated string. Use the
|
||||
* draw_net_input for the general case.
|
||||
*/
|
||||
/* Omit LPMPART_BI device pin-data(0) drivers. */
|
||||
# define OMIT_PART_BI_DATA 0x0001
|
||||
|
||||
static char* draw_net_input_x(ivl_nexus_t nex,
|
||||
ivl_nexus_ptr_t omit_ptr, int omit_flags,
|
||||
struct vvp_nexus_data*nex_data)
|
||||
{
|
||||
ivl_signal_type_t res;
|
||||
char result[512];
|
||||
unsigned idx;
|
||||
int level;
|
||||
unsigned ndrivers = 0;
|
||||
static ivl_nexus_ptr_t *drivers = 0x0;
|
||||
static unsigned adrivers = 0;
|
||||
|
||||
const char*resolv_type;
|
||||
|
||||
char*nex_private = 0;
|
||||
|
||||
/* Accumulate nex_data flags. */
|
||||
int nex_flags = 0;
|
||||
|
||||
res = signal_type_of_nexus(nex);
|
||||
switch (res) {
|
||||
case IVL_SIT_TRI:
|
||||
resolv_type = "tri";
|
||||
break;
|
||||
case IVL_SIT_TRI0:
|
||||
resolv_type = "tri0";
|
||||
nex_flags |= VVP_NEXUS_DATA_STR;
|
||||
break;
|
||||
case IVL_SIT_TRI1:
|
||||
resolv_type = "tri1";
|
||||
nex_flags |= VVP_NEXUS_DATA_STR;
|
||||
break;
|
||||
case IVL_SIT_TRIAND:
|
||||
resolv_type = "triand";
|
||||
break;
|
||||
case IVL_SIT_TRIOR:
|
||||
resolv_type = "trior";
|
||||
break;
|
||||
default:
|
||||
fprintf(stderr, "vvp.tgt: Unsupported signal type: %u\n", res);
|
||||
assert(0);
|
||||
resolv_type = "tri";
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
for (idx = 0 ; idx < ivl_nexus_ptrs(nex) ; idx += 1) {
|
||||
ivl_lpm_t lpm_tmp;
|
||||
ivl_nexus_ptr_t nptr = ivl_nexus_ptr(nex, idx);
|
||||
|
||||
/* If we are supposed to skip LPM_PART_BI data pins,
|
||||
check that this driver is that. */
|
||||
if ((omit_flags&OMIT_PART_BI_DATA)
|
||||
&& (lpm_tmp = ivl_nexus_ptr_lpm(nptr))
|
||||
&& (nex == ivl_lpm_data(lpm_tmp,0)))
|
||||
continue;
|
||||
|
||||
if (nptr == omit_ptr)
|
||||
continue;
|
||||
|
||||
/* Skip input only pins. */
|
||||
if ((ivl_nexus_ptr_drive0(nptr) == IVL_DR_HiZ)
|
||||
&& (ivl_nexus_ptr_drive1(nptr) == IVL_DR_HiZ))
|
||||
continue;
|
||||
|
||||
/* Mark the strength-aware flag if the driver can
|
||||
generate values other than the standard "6"
|
||||
strength. */
|
||||
if (nexus_drive_is_strength_aware(nptr))
|
||||
nex_flags |= VVP_NEXUS_DATA_STR;
|
||||
|
||||
/* Save this driver. */
|
||||
if (ndrivers >= adrivers) {
|
||||
adrivers += 4;
|
||||
drivers = realloc(drivers, adrivers*sizeof(ivl_nexus_ptr_t));
|
||||
assert(drivers);
|
||||
}
|
||||
drivers[ndrivers] = nptr;
|
||||
ndrivers += 1;
|
||||
}
|
||||
|
||||
/* If the caller is collecting nexus information, then save
|
||||
the nexus driver count in the nex_data. */
|
||||
if (nex_data) {
|
||||
nex_data->drivers_count = ndrivers;
|
||||
nex_data->flags |= nex_flags;
|
||||
}
|
||||
|
||||
/* If the nexus has no drivers, then send a constant HiZ into
|
||||
the net. */
|
||||
if (ndrivers == 0) {
|
||||
unsigned idx, wid = width_of_nexus(nex);
|
||||
char*tmp = malloc(wid + 5);
|
||||
nex_private = tmp;
|
||||
strcpy(tmp, "C4<");
|
||||
tmp += strlen(tmp);
|
||||
switch (res) {
|
||||
case IVL_SIT_TRI:
|
||||
for (idx = 0 ; idx < wid ; idx += 1)
|
||||
*tmp++ = 'z';
|
||||
break;
|
||||
case IVL_SIT_TRI0:
|
||||
for (idx = 0 ; idx < wid ; idx += 1)
|
||||
*tmp++ = '0';
|
||||
break;
|
||||
case IVL_SIT_TRI1:
|
||||
for (idx = 0 ; idx < wid ; idx += 1)
|
||||
*tmp++ = '1';
|
||||
break;
|
||||
default:
|
||||
assert(0);
|
||||
}
|
||||
*tmp++ = '>';
|
||||
*tmp = 0;
|
||||
return nex_private;
|
||||
}
|
||||
|
||||
|
||||
/* If the nexus has exactly one driver, then simply draw
|
||||
it. Note that this will *not* work if the nexus is not a
|
||||
TRI type nexus. */
|
||||
if (ndrivers == 1 && res == IVL_SIT_TRI) {
|
||||
ivl_signal_t path_sig = find_modpath(nex);
|
||||
if (path_sig) {
|
||||
char*nex_str = draw_net_input_drive(nex, drivers[0]);
|
||||
char modpath_label[64];
|
||||
snprintf(modpath_label, sizeof modpath_label,
|
||||
"V_%p/m", path_sig);
|
||||
nex_private = strdup(modpath_label);
|
||||
draw_modpath(path_sig, nex_str);
|
||||
|
||||
} else {
|
||||
nex_private = draw_net_input_drive(nex, drivers[0]);
|
||||
}
|
||||
return nex_private;
|
||||
}
|
||||
|
||||
level = 0;
|
||||
while (ndrivers) {
|
||||
unsigned int inst;
|
||||
for (inst = 0; inst < ndrivers; inst += 4) {
|
||||
if (ndrivers > 4)
|
||||
fprintf(vvp_out, "RS_%p/%d/%d .resolv tri",
|
||||
nex, level, inst);
|
||||
else
|
||||
fprintf(vvp_out, "RS_%p .resolv %s",
|
||||
nex, resolv_type);
|
||||
|
||||
for (idx = inst; idx < ndrivers && idx < inst+4; idx += 1) {
|
||||
if (level) {
|
||||
fprintf(vvp_out, ", RS_%p/%d/%d",
|
||||
nex, level - 1, idx*4);
|
||||
} else {
|
||||
char*drive = draw_net_input_drive(nex, drivers[idx]);
|
||||
fprintf(vvp_out, ", %s", drive);
|
||||
free(drive);
|
||||
}
|
||||
}
|
||||
for ( ; idx < inst+4 ; idx += 1) {
|
||||
fprintf(vvp_out, ", ");
|
||||
draw_C4_repeated_constant('z',width_of_nexus(nex));
|
||||
}
|
||||
|
||||
fprintf(vvp_out, ";\n");
|
||||
}
|
||||
if (ndrivers > 4)
|
||||
ndrivers = (ndrivers+3) / 4;
|
||||
else
|
||||
ndrivers = 0;
|
||||
level += 1;
|
||||
}
|
||||
|
||||
sprintf(result, "RS_%p", nex);
|
||||
nex_private = strdup(result);
|
||||
return nex_private;
|
||||
}
|
||||
|
||||
/*
|
||||
* Get a cached description of the nexus input, or create one if this
|
||||
* nexus has not been cached yet. This is a wrapper for the common
|
||||
* case call to draw_net_input_x.
|
||||
*/
|
||||
const char*draw_net_input(ivl_nexus_t nex)
|
||||
{
|
||||
struct vvp_nexus_data*nex_data = (struct vvp_nexus_data*)
|
||||
ivl_nexus_get_private(nex);
|
||||
|
||||
/* If this nexus already has a label, then its input is
|
||||
already figured out. Just return the existing label. */
|
||||
if (nex_data && nex_data->net_input)
|
||||
return nex_data->net_input;
|
||||
|
||||
if (nex_data == 0) {
|
||||
nex_data = new_nexus_data();
|
||||
ivl_nexus_set_private(nex, nex_data);
|
||||
}
|
||||
|
||||
assert(nex_data->net_input == 0);
|
||||
nex_data->net_input = draw_net_input_x(nex, 0, 0, nex_data);
|
||||
|
||||
return nex_data->net_input;
|
||||
}
|
||||
|
||||
const char*draw_input_from_net(ivl_nexus_t nex)
|
||||
{
|
||||
static char result[32];
|
||||
@@ -987,6 +360,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;
|
||||
@@ -1693,6 +1068,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];
|
||||
@@ -1747,7 +1133,11 @@ static void draw_lpm_add(ivl_lpm_t net)
|
||||
type = "pow.s";
|
||||
if (width > 8*sizeof(long)) {
|
||||
fprintf(stderr, "%s:%u: sorry (vvp-tgt): Signed power "
|
||||
#ifdef __MINGW32__ /* MinGW does not know about z. */
|
||||
"result must be no more than %u bits.\n",
|
||||
#else
|
||||
"result must be no more than %zu bits.\n",
|
||||
#endif
|
||||
ivl_lpm_file(net), ivl_lpm_lineno(net),
|
||||
8*sizeof(long));
|
||||
exit(1);
|
||||
@@ -2221,94 +1611,6 @@ static void draw_lpm_part_pv(ivl_lpm_t net)
|
||||
fprintf(vvp_out, ", %u, %u, %u;\n", base, width, signal_width);
|
||||
}
|
||||
|
||||
/*
|
||||
* Handle the drawing of a bi-directional part select. The two ports
|
||||
* are simultaneously input and output. A simple minded connect of the
|
||||
* input to the output causes a functor cycle which will lock into an
|
||||
* X value, so something special is needed.
|
||||
*
|
||||
* NOTE: The inputs of the tran device at this point need to be from
|
||||
* all the drivers of the nexus *except* the tran itself. This
|
||||
* function will draw three labels that can be linked:
|
||||
*
|
||||
* The ivl_lpm_q of a part(bi) may be a smaller vector then the
|
||||
* ivl_lpm_data, the tran acts like a forward part select in that
|
||||
* way.
|
||||
*
|
||||
* The device creates these nodes:
|
||||
*
|
||||
* - L_%p/i
|
||||
* This is the Q port of the tran resolved and padded to the maximum
|
||||
* width of the tran. The tran itself is not included in the
|
||||
* resolution of this port.
|
||||
*
|
||||
* - L_%p/V
|
||||
* This is the Q and D parts resolved together, still without the tran
|
||||
* driving anything.
|
||||
*
|
||||
* - L_%p/P
|
||||
* This is the /V node part-selected back to the dimensions of the Q
|
||||
* side.
|
||||
*/
|
||||
static void draw_lpm_part_bi(ivl_lpm_t net)
|
||||
{
|
||||
unsigned width = ivl_lpm_width(net);
|
||||
unsigned base = ivl_lpm_base(net);
|
||||
unsigned signal_width = width_of_nexus(ivl_lpm_data(net,0));
|
||||
|
||||
unsigned idx;
|
||||
ivl_nexus_t nex;
|
||||
ivl_nexus_ptr_t ptr = 0;
|
||||
|
||||
char*p_str;
|
||||
char*v_str;
|
||||
|
||||
/* It seems implausible that the two inputs of a tran will be
|
||||
connected together. So assert that this is so to simplify
|
||||
the code to look for the nexus_ptr_t objects. */
|
||||
assert(ivl_lpm_q(net,0) != ivl_lpm_data(net,0));
|
||||
|
||||
nex = ivl_lpm_q(net,0);
|
||||
for (idx = 0 ; idx < ivl_nexus_ptrs(nex) ; idx += 1) {
|
||||
ptr = ivl_nexus_ptr(nex, idx);
|
||||
if (ivl_nexus_ptr_lpm(ptr) == net)
|
||||
break;
|
||||
}
|
||||
assert(ptr != 0);
|
||||
p_str = draw_net_input_x(nex, ptr, 0, 0);
|
||||
|
||||
nex = ivl_lpm_data(net,0);
|
||||
for (idx = 0 ; idx < ivl_nexus_ptrs(nex) ; idx += 1) {
|
||||
ptr = ivl_nexus_ptr(nex, idx);
|
||||
if (ivl_nexus_ptr_lpm(ptr) == net)
|
||||
break;
|
||||
}
|
||||
v_str = draw_net_input_x(nex, ptr, OMIT_PART_BI_DATA, 0);
|
||||
|
||||
/* Pad the part-sized input out to a common width...
|
||||
The /i label is the Q side of the tran, resolved except for
|
||||
the tran itself and padded (with z) to the larger width. */
|
||||
fprintf(vvp_out, "L_%p/i .part/pv %s, %u, %u, %u;\n",
|
||||
net, p_str, base, width, signal_width);
|
||||
|
||||
/* Resolve together the two halves of the tran...
|
||||
The /V label is the ports of the tran (now the same width)
|
||||
resolved together. Neither input to this resolver includes
|
||||
the tran itself. */
|
||||
fprintf(vvp_out, "L_%p/V .resolv tri, L_%p/i, %s;\n",
|
||||
net, net, v_str);
|
||||
|
||||
/* The full-width side is created by the tran device, all we
|
||||
have left to to is take a part select of that for the
|
||||
smaller output, and this becomes the part select output of
|
||||
the BI device. */
|
||||
fprintf(vvp_out, "L_%p/P .part L_%p/V, %u, %u;\n", net,
|
||||
net, base, width);
|
||||
|
||||
free(p_str);
|
||||
free(v_str);
|
||||
}
|
||||
|
||||
/*
|
||||
* Draw unary reduction devices.
|
||||
*/
|
||||
@@ -2338,6 +1640,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:
|
||||
@@ -2351,10 +1657,6 @@ static void draw_lpm_in_scope(ivl_lpm_t net)
|
||||
draw_lpm_array(net);
|
||||
return;
|
||||
|
||||
case IVL_LPM_PART_BI:
|
||||
draw_lpm_part_bi(net);
|
||||
return;
|
||||
|
||||
case IVL_LPM_PART_VP:
|
||||
draw_lpm_part(net);
|
||||
return;
|
||||
@@ -2444,12 +1746,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");
|
||||
@@ -2463,13 +1768,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);
|
||||
@@ -2480,8 +1789,10 @@ 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\", %s; value=%g\n",
|
||||
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;
|
||||
@@ -2528,6 +1839,11 @@ int draw_scope(ivl_scope_t net, ivl_scope_t parent)
|
||||
draw_lpm_in_scope(lpm);
|
||||
}
|
||||
|
||||
for (idx = 0 ; idx < ivl_scope_switches(net) ; idx += 1) {
|
||||
ivl_switch_t sw = ivl_scope_switch(net, idx);
|
||||
draw_switch_in_scope(sw);
|
||||
}
|
||||
|
||||
if (ivl_scope_type(net) == IVL_SCT_TASK)
|
||||
draw_task_definition(net);
|
||||
|
||||
|
||||
+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.20080429
|
||||
Version: 0.9.0.%{rev_date}
|
||||
Release: 0
|
||||
License: GPL
|
||||
Group: Productivity/Scientific/Electronics
|
||||
Source: verilog-20080429.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-20080429
|
||||
%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.
|
||||
|
||||
+4
-18
@@ -448,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)
|
||||
@@ -564,25 +564,11 @@ ostream& operator<< (ostream&o, const verinum&v)
|
||||
output. */
|
||||
if (v.has_len()) {
|
||||
o << v.len();
|
||||
if (v.has_sign())
|
||||
o << "'sb";
|
||||
else
|
||||
o << "'b";
|
||||
|
||||
if (v.len() == 0) {
|
||||
o << "0";
|
||||
return o;
|
||||
}
|
||||
|
||||
for (unsigned idx = v.len() ; idx > 0 ; idx -= 1)
|
||||
o << v[idx-1];
|
||||
|
||||
return o;
|
||||
}
|
||||
|
||||
/* If the number is fully defined (no x or z) then print it
|
||||
out as a decimal number. */
|
||||
if (v.is_defined() && v.len() < sizeof(long)) {
|
||||
if (v.is_defined() && v.len() < 8*sizeof(long)) {
|
||||
if (v.has_sign())
|
||||
o << "'sd" << v.as_long();
|
||||
else
|
||||
@@ -1238,9 +1224,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;
|
||||
|
||||
|
||||
@@ -130,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);
|
||||
|
||||
+30
-10
@@ -16,12 +16,9 @@
|
||||
# 59 Temple Place - Suite 330
|
||||
# Boston, MA 02111-1307, USA
|
||||
#
|
||||
#ident "$Id: Makefile.in,v 1.61 2007/02/06 05:07:32 steve Exp $"
|
||||
#
|
||||
#
|
||||
SHELL = /bin/sh
|
||||
|
||||
VERSION = 0.0
|
||||
VERSION = 0.9.devel
|
||||
|
||||
prefix = @prefix@
|
||||
exec_prefix = @exec_prefix@
|
||||
@@ -46,7 +43,9 @@ 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)
|
||||
|
||||
check: all
|
||||
|
||||
dep:
|
||||
mkdir dep
|
||||
@@ -55,11 +54,13 @@ 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
|
||||
mt19937int.o sys_priv.o sdf_lexor.o sdf_parse.o stringheap.o \
|
||||
vams_simparam.o
|
||||
|
||||
ifeq (@HAVE_LIBZ@,yes)
|
||||
ifeq (@HAVE_LIBBZ2@,yes)
|
||||
@@ -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)
|
||||
ifeq (@MING32@,yes)
|
||||
VA_MATH_LDFLAGS =
|
||||
ifeq (@MINGW32@,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
|
||||
|
||||
|
||||
+10
-17
@@ -60,16 +60,6 @@ struct strobe_cb_info {
|
||||
unsigned mcd;
|
||||
};
|
||||
|
||||
int is_constant(vpiHandle obj)
|
||||
{
|
||||
if (vpi_get(vpiType, obj) == vpiConstant)
|
||||
return vpiConstant;
|
||||
if (vpi_get(vpiType, obj) == vpiParameter)
|
||||
return vpiParameter;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
// The number of decimal digits needed to represent a
|
||||
// nr_bits binary number is floor(nr_bits*log_10(2))+1,
|
||||
// where log_10(2) = 0.30102999566398.... and I approximate
|
||||
@@ -665,7 +655,7 @@ static int format_str_char(vpiHandle scope, unsigned int mcd,
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (is_constant(argv[idx])
|
||||
if (is_constant_obj(argv[idx])
|
||||
&& (vpi_get(vpiConstType, argv[idx]) == vpiRealConst)) {
|
||||
|
||||
value.format = vpiRealVal;
|
||||
@@ -827,6 +817,7 @@ static void do_display(unsigned int mcd, struct strobe_cb_info*info)
|
||||
case vpiReg:
|
||||
case vpiIntegerVar:
|
||||
case vpiMemoryWord:
|
||||
case vpiPartSelect:
|
||||
do_display_numeric(mcd, info, item);
|
||||
break;
|
||||
|
||||
@@ -1118,6 +1109,12 @@ static PLI_INT32 sys_monitor_calltf(PLI_BYTE8*name)
|
||||
for (idx = 0 ; idx < monitor_info.nitems ; idx += 1) {
|
||||
|
||||
switch (vpi_get(vpiType, monitor_info.items[idx])) {
|
||||
case vpiMemoryWord:
|
||||
/*
|
||||
* We only support constant selections. Make this
|
||||
* better when we add a real compiletf routine.
|
||||
*/
|
||||
assert(vpi_get(vpiConstantSelect, monitor_info.items[idx]));
|
||||
case vpiNet:
|
||||
case vpiReg:
|
||||
case vpiIntegerVar:
|
||||
@@ -1835,6 +1832,7 @@ static char *get_display(unsigned int *rtnsz, struct strobe_cb_info *info)
|
||||
case vpiReg:
|
||||
case vpiIntegerVar:
|
||||
case vpiMemoryWord:
|
||||
case vpiPartSelect:
|
||||
width = get_numeric(&result, info, item);
|
||||
rtn = realloc(rtn, (size+width)*sizeof(char));
|
||||
memcpy(rtn+size-1, result, width);
|
||||
@@ -2184,12 +2182,7 @@ static PLI_INT32 sys_printtimescale_calltf(PLI_BYTE8*xx)
|
||||
vpiHandle argv = vpi_iterate(vpiArgument, sys);
|
||||
vpiHandle scope;
|
||||
if (!argv) {
|
||||
vpiHandle parent = vpi_handle(vpiScope, sys);
|
||||
scope = NULL; /* fallback value if parent is NULL */
|
||||
while (parent) {
|
||||
scope = parent;
|
||||
parent = vpi_handle(vpiScope, scope);
|
||||
}
|
||||
scope = sys_func_module(sys);
|
||||
} else {
|
||||
scope = vpi_scan(argv);
|
||||
vpi_free_object(argv);
|
||||
|
||||
+33
-22
@@ -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: sys_fileio.c,v 1.10 2007/03/14 04:05:51 steve Exp $"
|
||||
#endif
|
||||
|
||||
# include "vpi_user.h"
|
||||
# include "sys_priv.h"
|
||||
@@ -60,7 +57,7 @@ static PLI_INT32 sys_fopen_compiletf(PLI_BYTE8*name)
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (! is_constant(item)) {
|
||||
if (! is_constant_obj(item)) {
|
||||
vpi_printf("ERROR: %s mode argument must be a constant\n", name);
|
||||
vpi_control(vpiFinish, 1);
|
||||
}
|
||||
@@ -480,23 +477,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 +518,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 +526,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 +542,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;
|
||||
@@ -903,4 +915,3 @@ void sys_fileio_register()
|
||||
vpi_register_systf(&tf_data);
|
||||
|
||||
}
|
||||
|
||||
|
||||
+9
-81
@@ -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,44 +16,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: sys_finish.c,v 1.11 2007/04/09 22:49:33 steve Exp $"
|
||||
#endif
|
||||
|
||||
# include "vpi_config.h"
|
||||
|
||||
# include "vpi_user.h"
|
||||
# include <string.h>
|
||||
|
||||
static PLI_INT32 sys_finish_compiletf(PLI_BYTE8 *name)
|
||||
{
|
||||
vpiHandle callh = vpi_handle(vpiSysTfCall, 0);
|
||||
vpiHandle argv = vpi_iterate(vpiArgument, callh);
|
||||
vpiHandle arg;
|
||||
|
||||
/* The argument is optional. */
|
||||
if (argv == 0) return 0;
|
||||
arg = vpi_scan(argv);
|
||||
|
||||
/* A string diagnostic message level makes no sense. */
|
||||
if (vpi_get(vpiType, arg) == vpiConstant &&
|
||||
vpi_get(vpiConstType, arg) == vpiStringConst) {
|
||||
vpi_printf("Error: %s does not take a string argument.\n", name);
|
||||
vpi_control(vpiFinish, 1);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* These functions take at most one argument (diagnostic message). */
|
||||
arg = vpi_scan(argv);
|
||||
if (arg != 0) {
|
||||
vpi_printf("Error: %s takes at most one argument.\n", name);
|
||||
vpi_control(vpiFinish, 1);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* vpi_scan returning 0 (NULL) has already freed argv. */
|
||||
return 0;
|
||||
}
|
||||
#include "vpi_config.h"
|
||||
#include "vpi_user.h"
|
||||
#include "sys_priv.h"
|
||||
#include <string.h>
|
||||
|
||||
static PLI_INT32 sys_finish_calltf(PLI_BYTE8 *name)
|
||||
{
|
||||
@@ -88,55 +55,16 @@ void sys_finish_register()
|
||||
tf_data.type = vpiSysTask;
|
||||
tf_data.tfname = "$finish";
|
||||
tf_data.calltf = sys_finish_calltf;
|
||||
tf_data.compiletf = sys_finish_compiletf;
|
||||
tf_data.compiletf = sys_one_opt_numeric_arg_compiletf;
|
||||
tf_data.sizetf = 0;
|
||||
tf_data.user_data = (PLI_BYTE8*)"$finish";
|
||||
tf_data.user_data = "$finish";
|
||||
vpi_register_systf(&tf_data);
|
||||
|
||||
tf_data.type = vpiSysTask;
|
||||
tf_data.tfname = "$stop";
|
||||
tf_data.calltf = sys_finish_calltf;
|
||||
tf_data.compiletf = sys_finish_compiletf;
|
||||
tf_data.compiletf = sys_one_opt_numeric_arg_compiletf;
|
||||
tf_data.sizetf = 0;
|
||||
tf_data.user_data = (PLI_BYTE8*)"$stop";
|
||||
tf_data.user_data = "$stop";
|
||||
vpi_register_systf(&tf_data);
|
||||
}
|
||||
|
||||
/*
|
||||
* $Log: sys_finish.c,v $
|
||||
* Revision 1.11 2007/04/09 22:49:33 steve
|
||||
* More strict use of PLI_BYTE8 type.
|
||||
*
|
||||
* Revision 1.10 2006/10/30 22:45:37 steve
|
||||
* Updates for Cygwin portability (pr1585922)
|
||||
*
|
||||
* Revision 1.9 2004/01/21 01:22:53 steve
|
||||
* Give the vip directory its own configure and vpi_config.h
|
||||
*
|
||||
* Revision 1.8 2003/02/21 03:24:03 steve
|
||||
* Make the $stop system task really vpiStop.
|
||||
*
|
||||
* Revision 1.7 2002/08/12 01:35:04 steve
|
||||
* conditional ident string using autoconfig.
|
||||
*
|
||||
* Revision 1.6 2001/07/25 03:10:50 steve
|
||||
* Create a config.h.in file to hold all the config
|
||||
* junk, and support gcc 3.0. (Stephan Boettcher)
|
||||
*
|
||||
* Revision 1.5 2001/01/01 19:33:44 steve
|
||||
* Add $stop that does a finish.
|
||||
*
|
||||
* Revision 1.4 2000/02/23 02:56:56 steve
|
||||
* Macintosh compilers do not support ident.
|
||||
*
|
||||
* Revision 1.3 1999/08/28 02:10:44 steve
|
||||
* Call the right vpiFinish code.
|
||||
*
|
||||
* Revision 1.2 1999/08/19 02:51:03 steve
|
||||
* Add vpi_sim_control
|
||||
*
|
||||
* Revision 1.1 1999/08/15 01:23:56 steve
|
||||
* Convert vvm to implement system tasks with vpi.
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
@@ -0,0 +1,59 @@
|
||||
/*
|
||||
* 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 <assert.h>
|
||||
#include <vpi_user.h>
|
||||
#include "sys_priv.h"
|
||||
|
||||
static PLI_INT32 finish_and_return_calltf(PLI_BYTE8* name)
|
||||
{
|
||||
vpiHandle callh = vpi_handle(vpiSysTfCall, 0);
|
||||
vpiHandle argv = vpi_iterate(vpiArgument, callh);
|
||||
vpiHandle arg;
|
||||
s_vpi_value val;
|
||||
(void) name; /* Not used! */
|
||||
|
||||
/* Get the return value. */
|
||||
arg = vpi_scan(argv);
|
||||
vpi_free_object(argv);
|
||||
val.format = vpiIntVal;
|
||||
vpi_get_value(arg, &val);
|
||||
|
||||
/* Set the return value. */
|
||||
vpip_set_return_value(val.value.integer);
|
||||
|
||||
/* Now finish. */
|
||||
vpi_control(vpiFinish, 1);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Register the function with Verilog.
|
||||
*/
|
||||
void sys_special_register(void)
|
||||
{
|
||||
s_vpi_systf_data tf_data;
|
||||
|
||||
tf_data.type = vpiSysTask;
|
||||
tf_data.calltf = finish_and_return_calltf;
|
||||
tf_data.compiletf = sys_one_numeric_arg_compiletf;
|
||||
tf_data.sizetf = 0;
|
||||
tf_data.tfname = "$finish_and_return";
|
||||
tf_data.user_data = "$finish_and_return";
|
||||
vpi_register_systf(&tf_data);
|
||||
}
|
||||
+28
-55
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2002 Stephen Williams (steve@icarus.com)
|
||||
* Copyright (c) 2002-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_lxt.c,v 1.28 2007/03/14 04:05:51 steve Exp $"
|
||||
#endif
|
||||
|
||||
# include "sys_priv.h"
|
||||
# include "lxt_write.h"
|
||||
@@ -324,9 +321,9 @@ inline static int install_dumpvars_callback(void)
|
||||
return 0;
|
||||
|
||||
if (dumpvars_status == 2) {
|
||||
vpi_mcd_printf(1, "LXT warning:" " $dumpvars ignored, previously"
|
||||
" called at simtime %" PLI_UINT64_FMT "\n",
|
||||
dumpvars_time);
|
||||
vpi_printf("LXT warning: $dumpvars ignored, previously"
|
||||
" called at simtime %" PLI_UINT64_FMT "\n",
|
||||
dumpvars_time);
|
||||
return 1;
|
||||
}
|
||||
|
||||
@@ -431,22 +428,23 @@ static void *close_dumpfile(void)
|
||||
return (dump_file = NULL);
|
||||
}
|
||||
|
||||
static void open_dumpfile(void)
|
||||
static void open_dumpfile(vpiHandle callh)
|
||||
{
|
||||
if (dump_path == 0) dump_path = strdup("dump.lxt");
|
||||
|
||||
dump_file = lt_init(dump_path);
|
||||
|
||||
if (dump_file == 0) {
|
||||
vpi_mcd_printf(1, "LXT Error: Unable to open %s for output.\n",
|
||||
dump_path);
|
||||
vpi_printf("LXT Error: %s line %d: ", vpi_get_str(vpiFile, callh),
|
||||
(int)vpi_get(vpiLineNo, callh));
|
||||
vpi_printf("Unable to open %s for output.\n", dump_path);
|
||||
vpi_control(vpiFinish, 1);
|
||||
return;
|
||||
} else {
|
||||
int prec = vpi_get(vpiTimePrecision, 0);
|
||||
|
||||
vpi_mcd_printf(1, "LXT info: dumpfile %s opened for output.\n",
|
||||
dump_path);
|
||||
vpi_printf("LXT info: dumpfile %s opened for output.\n",
|
||||
dump_path);
|
||||
|
||||
assert(prec >= -15);
|
||||
lt_set_timescale(dump_file, prec);
|
||||
@@ -468,9 +466,9 @@ static PLI_INT32 sys_dumpfile_calltf(PLI_BYTE8*name)
|
||||
|
||||
/* $dumpfile must be called before $dumpvars starts! */
|
||||
if (dumpvars_status != 0) {
|
||||
vpi_mcd_printf(1, "LXT warning: %s called after $dumpvars started"
|
||||
",\n using existing file (%s).\n",
|
||||
name, dump_path);
|
||||
vpi_printf("LXT warning: %s called after $dumpvars started,\n"
|
||||
" using existing file (%s).\n",
|
||||
name, dump_path);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -480,8 +478,8 @@ static PLI_INT32 sys_dumpfile_calltf(PLI_BYTE8*name)
|
||||
path = strdup(value.value.str);
|
||||
|
||||
if (dump_path) {
|
||||
vpi_mcd_printf(1, "LXT warning: Overriding dump file %s with"
|
||||
" %s\n", dump_path, path);
|
||||
vpi_printf("LXT warning: Overriding dump file %s with %s\n",
|
||||
dump_path, path);
|
||||
free(dump_path);
|
||||
}
|
||||
dump_path = path;
|
||||
@@ -542,16 +540,9 @@ static void scan_item(unsigned depth, vpiHandle item, int skip)
|
||||
|
||||
switch (vpi_get(vpiType, item)) {
|
||||
|
||||
case vpiMemory:
|
||||
/* don't know how to watch memories. */
|
||||
break;
|
||||
|
||||
case vpiNamedEvent:
|
||||
/* There is nothing in named events to dump. */
|
||||
break;
|
||||
|
||||
case vpiNet: type = "wire"; if(0){
|
||||
case vpiIntegerVar:
|
||||
case vpiMemoryWord:
|
||||
case vpiTimeVar:
|
||||
case vpiReg: type = "reg"; }
|
||||
|
||||
@@ -644,18 +635,16 @@ static void scan_item(unsigned depth, vpiHandle item, int skip)
|
||||
vpi_get_str(vpiFullName, item);
|
||||
|
||||
#if 0
|
||||
vpi_mcd_printf(1,
|
||||
"LXT info:"
|
||||
" scanning scope %s, %u levels\n",
|
||||
fullname, depth);
|
||||
vpi_printf("LXT info: scanning scope %s, %u levels\n",
|
||||
fullname, depth);
|
||||
#endif
|
||||
nskip = 0 != vcd_names_search(&lxt_tab, fullname);
|
||||
|
||||
if (!nskip)
|
||||
vcd_names_add(&lxt_tab, fullname);
|
||||
else
|
||||
vpi_mcd_printf(1, "LXT warning: ignoring signals in"
|
||||
" previously scanned scope %s\n", fullname);
|
||||
vpi_printf("LXT warning: ignoring signals in "
|
||||
"previously scanned scope %s\n", fullname);
|
||||
|
||||
name = vpi_get_str(vpiName, item);
|
||||
|
||||
@@ -674,8 +663,8 @@ static void scan_item(unsigned depth, vpiHandle item, int skip)
|
||||
break;
|
||||
|
||||
default:
|
||||
vpi_mcd_printf(1, "LXT warning: $dumpvars: Unsupported parameter"
|
||||
" type (%d)\n", vpi_get(vpiType, item));
|
||||
vpi_printf("LXT warning: $dumpvars: Unsupported parameter "
|
||||
"type (%s)\n", vpi_get_str(vpiType, item));
|
||||
}
|
||||
|
||||
}
|
||||
@@ -684,7 +673,6 @@ static int draw_scope(vpiHandle item)
|
||||
{
|
||||
int depth;
|
||||
const char *name;
|
||||
// char *type; // Not needed, see below.
|
||||
|
||||
vpiHandle scope = vpi_handle(vpiScope, item);
|
||||
if (!scope)
|
||||
@@ -693,20 +681,6 @@ static int draw_scope(vpiHandle item)
|
||||
depth = 1 + draw_scope(scope);
|
||||
name = vpi_get_str(vpiName, scope);
|
||||
|
||||
#if 0 /* The type information is not needed by the LXT dumper. */
|
||||
switch (vpi_get(vpiType, scope)) {
|
||||
case vpiNamedBegin: type = "begin"; break;
|
||||
case vpiTask: type = "task"; break;
|
||||
case vpiFunction: type = "function"; break;
|
||||
case vpiNamedFork: type = "fork"; break;
|
||||
case vpiModule: type = "module"; break;
|
||||
default:
|
||||
vpi_mcd_printf(1, "LXT Error: $dumpvars: Unsupported scope "
|
||||
"type (%d)\n", vpi_get(vpiType, item));
|
||||
assert(0);
|
||||
}
|
||||
#endif
|
||||
|
||||
push_scope(name);
|
||||
|
||||
return depth;
|
||||
@@ -721,7 +695,7 @@ static PLI_INT32 sys_dumpvars_calltf(PLI_BYTE8*name)
|
||||
unsigned depth = 0;
|
||||
|
||||
if (dump_file == 0) {
|
||||
open_dumpfile();
|
||||
open_dumpfile(callh);
|
||||
if (dump_file == 0) return 0;
|
||||
}
|
||||
|
||||
@@ -784,7 +758,7 @@ void sys_lxt_register()
|
||||
tf_data.type = vpiSysTask;
|
||||
tf_data.tfname = "$dumpall";
|
||||
tf_data.calltf = sys_dumpall_calltf;
|
||||
tf_data.compiletf = sys_dumpall_compiletf;
|
||||
tf_data.compiletf = sys_no_arg_compiletf;
|
||||
tf_data.sizetf = 0;
|
||||
tf_data.user_data = "$dumpall";
|
||||
vpi_register_systf(&tf_data);
|
||||
@@ -800,7 +774,7 @@ void sys_lxt_register()
|
||||
tf_data.type = vpiSysTask;
|
||||
tf_data.tfname = "$dumpflush";
|
||||
tf_data.calltf = sys_dumpflush_calltf;
|
||||
tf_data.compiletf = sys_dumpflush_compiletf;
|
||||
tf_data.compiletf = sys_no_arg_compiletf;
|
||||
tf_data.sizetf = 0;
|
||||
tf_data.user_data = "$dumpflush";
|
||||
vpi_register_systf(&tf_data);
|
||||
@@ -808,7 +782,7 @@ void sys_lxt_register()
|
||||
tf_data.type = vpiSysTask;
|
||||
tf_data.tfname = "$dumplimit";
|
||||
tf_data.calltf = sys_dumplimit_calltf;
|
||||
tf_data.compiletf = sys_dumplimit_compiletf;
|
||||
tf_data.compiletf = sys_one_numeric_arg_compiletf;
|
||||
tf_data.sizetf = 0;
|
||||
tf_data.user_data = "$dumplimit";
|
||||
vpi_register_systf(&tf_data);
|
||||
@@ -816,7 +790,7 @@ void sys_lxt_register()
|
||||
tf_data.type = vpiSysTask;
|
||||
tf_data.tfname = "$dumpoff";
|
||||
tf_data.calltf = sys_dumpoff_calltf;
|
||||
tf_data.compiletf = sys_dumpoff_compiletf;
|
||||
tf_data.compiletf = sys_no_arg_compiletf;
|
||||
tf_data.sizetf = 0;
|
||||
tf_data.user_data = "$dumpoff";
|
||||
vpi_register_systf(&tf_data);
|
||||
@@ -824,7 +798,7 @@ void sys_lxt_register()
|
||||
tf_data.type = vpiSysTask;
|
||||
tf_data.tfname = "$dumpon";
|
||||
tf_data.calltf = sys_dumpon_calltf;
|
||||
tf_data.compiletf = sys_dumpon_compiletf;
|
||||
tf_data.compiletf = sys_no_arg_compiletf;
|
||||
tf_data.sizetf = 0;
|
||||
tf_data.user_data = "$dumpon";
|
||||
vpi_register_systf(&tf_data);
|
||||
@@ -837,4 +811,3 @@ void sys_lxt_register()
|
||||
tf_data.user_data = "$dumpvars";
|
||||
vpi_register_systf(&tf_data);
|
||||
}
|
||||
|
||||
|
||||
+28
-55
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2003-2004 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: sys_lxt2.c,v 1.10 2007/03/14 04:05:51 steve Exp $"
|
||||
#endif
|
||||
|
||||
# include "sys_priv.h"
|
||||
# include "lxt2_write.h"
|
||||
@@ -322,9 +319,9 @@ inline static int install_dumpvars_callback(void)
|
||||
if (dumpvars_status == 1) return 0;
|
||||
|
||||
if (dumpvars_status == 2) {
|
||||
vpi_mcd_printf(1, "LXT2 warning: $dumpvars ignored, previously"
|
||||
" called at simtime %" PLI_UINT64_FMT "\n",
|
||||
dumpvars_time);
|
||||
vpi_printf("LXT2 warning: $dumpvars ignored, previously"
|
||||
" called at simtime %" PLI_UINT64_FMT "\n",
|
||||
dumpvars_time);
|
||||
return 1;
|
||||
}
|
||||
|
||||
@@ -429,22 +426,23 @@ static void *close_dumpfile(void)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void open_dumpfile(void)
|
||||
static void open_dumpfile(vpiHandle callh)
|
||||
{
|
||||
if (dump_path == 0) dump_path = strdup("dump.lx2");
|
||||
|
||||
dump_file = lxt2_wr_init(dump_path);
|
||||
|
||||
if (dump_file == 0) {
|
||||
vpi_mcd_printf(1, "LXT2 Error: Unable to open %s for output.\n",
|
||||
dump_path);
|
||||
vpi_printf("LXT2 Error: %s line %d: ", vpi_get_str(vpiFile, callh),
|
||||
(int)vpi_get(vpiLineNo, callh));
|
||||
vpi_printf("Unable to open %s for output.\n", dump_path);
|
||||
vpi_control(vpiFinish, 1);
|
||||
return;
|
||||
} else {
|
||||
int prec = vpi_get(vpiTimePrecision, 0);
|
||||
|
||||
vpi_mcd_printf(1, "LXT2 info: dumpfile %s opened for output.\n",
|
||||
dump_path);
|
||||
vpi_printf("LXT2 info: dumpfile %s opened for output.\n",
|
||||
dump_path);
|
||||
|
||||
assert(prec >= -15);
|
||||
lxt2_wr_set_timescale(dump_file, prec);
|
||||
@@ -468,9 +466,9 @@ static PLI_INT32 sys_dumpfile_calltf(PLI_BYTE8*name)
|
||||
|
||||
/* $dumpfile must be called before $dumpvars starts! */
|
||||
if (dumpvars_status != 0) {
|
||||
vpi_mcd_printf(1, "LXT2 warning: %s called after $dumpvars started"
|
||||
",\n using existing file (%s).\n",
|
||||
name, dump_path);
|
||||
vpi_printf("LXT2 warning: %s called after $dumpvars started,\n"
|
||||
" using existing file (%s).\n",
|
||||
name, dump_path);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -480,8 +478,8 @@ static PLI_INT32 sys_dumpfile_calltf(PLI_BYTE8*name)
|
||||
path = strdup(value.value.str);
|
||||
|
||||
if (dump_path) {
|
||||
vpi_mcd_printf(1, "LXT2 warning: Overriding dump file %s with"
|
||||
" %s.\n", dump_path, path);
|
||||
vpi_printf("LXT2 warning: Overriding dump file %s with %s.\n",
|
||||
dump_path, path);
|
||||
free(dump_path);
|
||||
}
|
||||
dump_path = path;
|
||||
@@ -548,16 +546,9 @@ static void scan_item(unsigned depth, vpiHandle item, int skip)
|
||||
|
||||
switch (vpi_get(vpiType, item)) {
|
||||
|
||||
case vpiMemory:
|
||||
/* don't know how to watch memories. */
|
||||
break;
|
||||
|
||||
case vpiNamedEvent:
|
||||
/* There is nothing in named events to dump. */
|
||||
break;
|
||||
|
||||
case vpiNet: type = "wire"; if(0){
|
||||
case vpiIntegerVar:
|
||||
case vpiMemoryWord:
|
||||
case vpiTimeVar:
|
||||
case vpiReg: type = "reg"; }
|
||||
|
||||
@@ -657,18 +648,16 @@ static void scan_item(unsigned depth, vpiHandle item, int skip)
|
||||
vpi_get_str(vpiFullName, item);
|
||||
|
||||
#if 0
|
||||
vpi_mcd_printf(1,
|
||||
"LXT2 info:"
|
||||
" scanning scope %s, %u levels\n",
|
||||
fullname, depth);
|
||||
vpi_printf("LXT2 info: scanning scope %s, %u levels\n",
|
||||
fullname, depth);
|
||||
#endif
|
||||
nskip = 0 != vcd_names_search(&lxt_tab, fullname);
|
||||
|
||||
if (!nskip)
|
||||
vcd_names_add(&lxt_tab, fullname);
|
||||
else
|
||||
vpi_mcd_printf(1, "LXT2 warning: ignoring signals in"
|
||||
" previously scanned scope %s\n", fullname);
|
||||
vpi_printf("LXT2 warning: ignoring signals in "
|
||||
"previously scanned scope %s\n", fullname);
|
||||
|
||||
name = vpi_get_str(vpiName, item);
|
||||
|
||||
@@ -687,8 +676,8 @@ static void scan_item(unsigned depth, vpiHandle item, int skip)
|
||||
break;
|
||||
|
||||
default:
|
||||
vpi_mcd_printf(1, "LXT2 warning: $dumpvars: Unsupported parameter"
|
||||
" type (%d)\n", vpi_get(vpiType, item));
|
||||
vpi_printf("LXT2 warning: $dumpvars: Unsupported parameter "
|
||||
"type (%s)\n", vpi_get_str(vpiType, item));
|
||||
}
|
||||
|
||||
}
|
||||
@@ -697,7 +686,6 @@ static int draw_scope(vpiHandle item)
|
||||
{
|
||||
int depth;
|
||||
const char *name;
|
||||
// char *type; // Not needed, see below.
|
||||
|
||||
vpiHandle scope = vpi_handle(vpiScope, item);
|
||||
if (!scope) return 0;
|
||||
@@ -705,20 +693,6 @@ static int draw_scope(vpiHandle item)
|
||||
depth = 1 + draw_scope(scope);
|
||||
name = vpi_get_str(vpiName, scope);
|
||||
|
||||
#if 0 /* The type information is not needed by the LXT2 dumper. */
|
||||
switch (vpi_get(vpiType, item)) {
|
||||
case vpiNamedBegin: type = "begin"; break;
|
||||
case vpiTask: type = "task"; break;
|
||||
case vpiFunction: type = "function"; break;
|
||||
case vpiNamedFork: type = "fork"; break;
|
||||
case vpiModule: type = "module"; break;
|
||||
default:
|
||||
vpi_mcd_printf(1, "LXT2 Error: $dumpvars: Unsupported scope "
|
||||
"type (%d)\n", vpi_get(vpiType, item));
|
||||
assert(0);
|
||||
}
|
||||
#endif
|
||||
|
||||
push_scope(name);
|
||||
|
||||
return depth;
|
||||
@@ -733,7 +707,7 @@ static PLI_INT32 sys_dumpvars_calltf(PLI_BYTE8*name)
|
||||
unsigned depth = 0;
|
||||
|
||||
if (dump_file == 0) {
|
||||
open_dumpfile();
|
||||
open_dumpfile(callh);
|
||||
if (dump_file == 0) return 0;
|
||||
}
|
||||
|
||||
@@ -799,7 +773,7 @@ void sys_lxt2_register()
|
||||
tf_data.type = vpiSysTask;
|
||||
tf_data.tfname = "$dumpall";
|
||||
tf_data.calltf = sys_dumpall_calltf;
|
||||
tf_data.compiletf = sys_dumpall_compiletf;
|
||||
tf_data.compiletf = sys_no_arg_compiletf;
|
||||
tf_data.sizetf = 0;
|
||||
tf_data.user_data = "$dumpall";
|
||||
vpi_register_systf(&tf_data);
|
||||
@@ -815,7 +789,7 @@ void sys_lxt2_register()
|
||||
tf_data.type = vpiSysTask;
|
||||
tf_data.tfname = "$dumpflush";
|
||||
tf_data.calltf = sys_dumpflush_calltf;
|
||||
tf_data.compiletf = sys_dumpflush_compiletf;
|
||||
tf_data.compiletf = sys_no_arg_compiletf;
|
||||
tf_data.sizetf = 0;
|
||||
tf_data.user_data = "$dumpflush";
|
||||
vpi_register_systf(&tf_data);
|
||||
@@ -823,7 +797,7 @@ void sys_lxt2_register()
|
||||
tf_data.type = vpiSysTask;
|
||||
tf_data.tfname = "$dumplimit";
|
||||
tf_data.calltf = sys_dumplimit_calltf;
|
||||
tf_data.compiletf = sys_dumplimit_compiletf;
|
||||
tf_data.compiletf = sys_one_numeric_arg_compiletf;
|
||||
tf_data.sizetf = 0;
|
||||
tf_data.user_data = "$dumplimit";
|
||||
vpi_register_systf(&tf_data);
|
||||
@@ -831,7 +805,7 @@ void sys_lxt2_register()
|
||||
tf_data.type = vpiSysTask;
|
||||
tf_data.tfname = "$dumpoff";
|
||||
tf_data.calltf = sys_dumpoff_calltf;
|
||||
tf_data.compiletf = sys_dumpoff_compiletf;
|
||||
tf_data.compiletf = sys_no_arg_compiletf;
|
||||
tf_data.sizetf = 0;
|
||||
tf_data.user_data = "$dumpoff";
|
||||
vpi_register_systf(&tf_data);
|
||||
@@ -839,7 +813,7 @@ void sys_lxt2_register()
|
||||
tf_data.type = vpiSysTask;
|
||||
tf_data.tfname = "$dumpon";
|
||||
tf_data.calltf = sys_dumpon_calltf;
|
||||
tf_data.compiletf = sys_dumpon_compiletf;
|
||||
tf_data.compiletf = sys_no_arg_compiletf;
|
||||
tf_data.sizetf = 0;
|
||||
tf_data.user_data = "$dumpon";
|
||||
vpi_register_systf(&tf_data);
|
||||
@@ -852,4 +826,3 @@ void sys_lxt2_register()
|
||||
tf_data.user_data = "$dumpvars";
|
||||
vpi_register_systf(&tf_data);
|
||||
}
|
||||
|
||||
|
||||
+237
@@ -0,0 +1,237 @@
|
||||
/*
|
||||
* 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
|
||||
* 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
|
||||
*/
|
||||
|
||||
#include <assert.h>
|
||||
#include <string.h>
|
||||
#include "sys_priv.h"
|
||||
|
||||
PLI_UINT64 timerec_to_time64(const struct t_vpi_time*time)
|
||||
{
|
||||
PLI_UINT64 tmp;
|
||||
|
||||
tmp = time->high;
|
||||
tmp <<= 32;
|
||||
tmp |= (PLI_UINT64) time->low;
|
||||
|
||||
return tmp;
|
||||
}
|
||||
|
||||
/*
|
||||
* This routine returns 1 if the argument is a constant value,
|
||||
* otherwise it returns 0.
|
||||
*/
|
||||
unsigned is_constant_obj(vpiHandle obj)
|
||||
{
|
||||
assert(obj);
|
||||
unsigned rtn = 0;
|
||||
|
||||
switch(vpi_get(vpiType, obj)) {
|
||||
case vpiConstant:
|
||||
case vpiParameter:
|
||||
rtn = 1;
|
||||
break;
|
||||
}
|
||||
|
||||
return rtn;
|
||||
}
|
||||
|
||||
/*
|
||||
* This routine returns 1 if the argument supports has a numeric value,
|
||||
* otherwise it returns 0.
|
||||
*/
|
||||
unsigned is_numeric_obj(vpiHandle obj)
|
||||
{
|
||||
assert(obj);
|
||||
unsigned rtn = 0;
|
||||
|
||||
switch(vpi_get(vpiType, obj)) {
|
||||
case vpiConstant:
|
||||
case vpiParameter:
|
||||
/* These cannot be a string constant. */
|
||||
if (vpi_get(vpiConstType, obj) != vpiStringConst) rtn = 1;
|
||||
break;
|
||||
|
||||
/* These can have a valid numeric value. */
|
||||
case vpiIntegerVar:
|
||||
case vpiMemoryWord:
|
||||
case vpiNet:
|
||||
case vpiPartSelect:
|
||||
case vpiRealVar:
|
||||
case vpiReg:
|
||||
case vpiTimeVar:
|
||||
rtn = 1;;
|
||||
break;
|
||||
}
|
||||
|
||||
return rtn;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* This routine returns 1 if the argument supports a valid string value,
|
||||
* otherwise it returns 0.
|
||||
*/
|
||||
unsigned is_string_obj(vpiHandle obj)
|
||||
{
|
||||
assert(obj);
|
||||
unsigned rtn = 0;
|
||||
|
||||
switch(vpi_get(vpiType, obj)) {
|
||||
case vpiConstant:
|
||||
case vpiParameter: {
|
||||
/* These must be a string or binary constant. */
|
||||
PLI_INT32 ctype = vpi_get(vpiConstType, obj);
|
||||
if (ctype == vpiStringConst || ctype == vpiBinaryConst) rtn = 1;
|
||||
break;
|
||||
}
|
||||
|
||||
/* These can have a valid string value. */
|
||||
case vpiIntegerVar:
|
||||
case vpiMemoryWord:
|
||||
case vpiNet:
|
||||
case vpiPartSelect:
|
||||
case vpiReg:
|
||||
case vpiTimeVar:
|
||||
rtn = 1;;
|
||||
break;
|
||||
}
|
||||
|
||||
return rtn;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Find the enclosing module.
|
||||
*/
|
||||
vpiHandle sys_func_module(vpiHandle obj)
|
||||
{
|
||||
assert(obj);
|
||||
|
||||
while (vpi_get(vpiType, obj) != vpiModule) {
|
||||
obj = vpi_handle(vpiScope, obj);
|
||||
assert(obj);
|
||||
}
|
||||
|
||||
return obj;
|
||||
}
|
||||
|
||||
/*
|
||||
* Standard compiletf routines.
|
||||
*/
|
||||
|
||||
/* For system functions that do not take an argument. */
|
||||
PLI_INT32 sys_no_arg_compiletf(PLI_BYTE8 *name)
|
||||
{
|
||||
vpiHandle callh = vpi_handle(vpiSysTfCall, 0);
|
||||
vpiHandle argv = vpi_iterate(vpiArgument, callh);
|
||||
|
||||
/* Make sure there are no arguments. */
|
||||
if (argv != 0) {
|
||||
char msg [64];
|
||||
snprintf(msg, 64, "ERROR: %s line %d:",
|
||||
vpi_get_str(vpiFile, callh),
|
||||
(int)vpi_get(vpiLineNo, callh));
|
||||
|
||||
unsigned argc = 0;
|
||||
while (vpi_scan(argv)) argc += 1;
|
||||
|
||||
vpi_printf("%s %s does not take an argument.\n", msg, name);
|
||||
vpi_printf("%*s Found %u extra argument%s.\n",
|
||||
strlen(msg), " ", argc, argc == 1 ? "" : "s");
|
||||
vpi_control(vpiFinish, 1);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* For system functions that take a single numeric argument. */
|
||||
PLI_INT32 sys_one_numeric_arg_compiletf(PLI_BYTE8 *name)
|
||||
{
|
||||
vpiHandle callh = vpi_handle(vpiSysTfCall, 0);
|
||||
vpiHandle argv = vpi_iterate(vpiArgument, callh);
|
||||
|
||||
/* Check that there is an argument and that it is numeric. */
|
||||
if (argv == 0) {
|
||||
vpi_printf("ERROR: %s line %d: ", vpi_get_str(vpiFile, callh),
|
||||
(int)vpi_get(vpiLineNo, callh));
|
||||
vpi_printf("%s requires a single numeric argument.\n", name);
|
||||
vpi_control(vpiFinish, 1);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (! is_numeric_obj(vpi_scan(argv))) {
|
||||
vpi_printf("ERROR: %s line %d: ", vpi_get_str(vpiFile, callh),
|
||||
(int)vpi_get(vpiLineNo, callh));
|
||||
vpi_printf("%s's argument must be numeric.\n", name);
|
||||
vpi_control(vpiFinish, 1);
|
||||
}
|
||||
|
||||
/* Make sure there are no extra arguments. */
|
||||
if (vpi_scan(argv) != 0) {
|
||||
char msg [64];
|
||||
snprintf(msg, 64, "ERROR: %s line %d:",
|
||||
vpi_get_str(vpiFile, callh),
|
||||
(int)vpi_get(vpiLineNo, callh));
|
||||
|
||||
unsigned argc = 1;
|
||||
while (vpi_scan(argv)) argc += 1;
|
||||
|
||||
vpi_printf("%s %s takes a single numeric argument.\n", msg, name);
|
||||
vpi_printf("%*s Found %u extra argument%s.\n",
|
||||
strlen(msg), " ", argc, argc == 1 ? "" : "s");
|
||||
vpi_control(vpiFinish, 1);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* For system functions that take a single optional numeric argument. */
|
||||
PLI_INT32 sys_one_opt_numeric_arg_compiletf(PLI_BYTE8 *name)
|
||||
{
|
||||
vpiHandle callh = vpi_handle(vpiSysTfCall, 0);
|
||||
vpiHandle argv = vpi_iterate(vpiArgument, callh);
|
||||
|
||||
/* The argument is optional so just return if none are found. */
|
||||
if (argv == 0) return 0;
|
||||
|
||||
if (! is_numeric_obj(vpi_scan(argv))) {
|
||||
vpi_printf("ERROR: %s line %d: ", vpi_get_str(vpiFile, callh),
|
||||
(int)vpi_get(vpiLineNo, callh));
|
||||
vpi_printf("%s's argument must be numeric.\n", name);
|
||||
vpi_control(vpiFinish, 1);
|
||||
}
|
||||
|
||||
/* Make sure there are no extra arguments. */
|
||||
if (vpi_scan(argv) != 0) {
|
||||
char msg [64];
|
||||
snprintf(msg, 64, "ERROR: %s line %d:",
|
||||
vpi_get_str(vpiFile, callh),
|
||||
(int)vpi_get(vpiLineNo, callh));
|
||||
|
||||
unsigned argc = 1;
|
||||
while (vpi_scan(argv)) argc += 1;
|
||||
|
||||
vpi_printf("%s %s takes a single numeric argument.\n", msg, name);
|
||||
vpi_printf("%*s Found %u extra argument%s.\n",
|
||||
strlen(msg), " ", argc, argc == 1 ? "" : "s");
|
||||
vpi_control(vpiFinish, 1);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
+16
-9
@@ -1,7 +1,7 @@
|
||||
#ifndef __vpi_sys_priv_H
|
||||
#define __vpi_sys_priv_H
|
||||
/*
|
||||
* Copyright (c) 2002 Stephen Williams (steve@icarus.com)
|
||||
* Copyright (c) 2002-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,12 +18,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: sys_priv.h,v 1.8 2007/03/14 04:05:51 steve Exp $"
|
||||
#endif
|
||||
|
||||
# include "vpi_config.h"
|
||||
# include "vpi_user.h"
|
||||
#include "vpi_config.h"
|
||||
#include "vpi_user.h"
|
||||
|
||||
/*
|
||||
* Context structure for PRNG in mt19937int.c
|
||||
@@ -36,9 +33,6 @@ struct context_s {
|
||||
extern void sgenrand(struct context_s *context, unsigned long seed);
|
||||
extern unsigned long genrand(struct context_s *context);
|
||||
|
||||
|
||||
extern int is_constant(vpiHandle obj);
|
||||
|
||||
extern PLI_UINT64 timerec_to_time64(const struct t_vpi_time*time);
|
||||
|
||||
struct timeformat_info_s {
|
||||
@@ -50,4 +44,17 @@ struct timeformat_info_s {
|
||||
|
||||
extern struct timeformat_info_s timeformat_info;
|
||||
|
||||
extern unsigned is_constant_obj(vpiHandle obj);
|
||||
extern unsigned is_numeric_obj(vpiHandle obj);
|
||||
extern unsigned is_string_obj(vpiHandle obj);
|
||||
|
||||
extern vpiHandle sys_func_module(vpiHandle obj);
|
||||
|
||||
/*
|
||||
* The standard compiletf routines.
|
||||
*/
|
||||
extern PLI_INT32 sys_no_arg_compiletf(PLI_BYTE8 *name);
|
||||
extern PLI_INT32 sys_one_numeric_arg_compiletf(PLI_BYTE8 *name);
|
||||
extern PLI_INT32 sys_one_opt_numeric_arg_compiletf(PLI_BYTE8 *name);
|
||||
|
||||
#endif
|
||||
|
||||
+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;
|
||||
|
||||
+5
-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,8 @@ 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();
|
||||
extern void vams_simparam_register();
|
||||
|
||||
#ifdef HAVE_LIBZ
|
||||
#ifdef HAVE_LIBBZ2
|
||||
@@ -181,6 +180,7 @@ void (*vlog_startup_routines[])() = {
|
||||
sys_time_register,
|
||||
sys_lxt_or_vcd_register,
|
||||
sys_sdf_register,
|
||||
sys_special_register,
|
||||
vams_simparam_register,
|
||||
0
|
||||
};
|
||||
|
||||
|
||||
+37
-102
@@ -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,36 +16,14 @@
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
|
||||
*/
|
||||
#ifdef HAVE_CVS_IDENT
|
||||
#ident "$Id: sys_time.c,v 1.12 2007/03/14 04:05:51 steve Exp $"
|
||||
#endif
|
||||
|
||||
# include "vpi_config.h"
|
||||
#include "vpi_config.h"
|
||||
|
||||
# include "vpi_user.h"
|
||||
# include <string.h>
|
||||
# include <math.h>
|
||||
# include <assert.h>
|
||||
|
||||
static vpiHandle module_of_function(vpiHandle obj)
|
||||
{
|
||||
while (vpi_get(vpiType, obj) != vpiModule) {
|
||||
obj = vpi_handle(vpiScope, obj);
|
||||
assert(obj);
|
||||
}
|
||||
|
||||
return obj;
|
||||
}
|
||||
|
||||
static PLI_INT32 sys_time_sizetf(PLI_BYTE8*x)
|
||||
{
|
||||
return 64;
|
||||
}
|
||||
|
||||
static PLI_INT32 sys_stime_sizetf(PLI_BYTE8*x)
|
||||
{
|
||||
return 32;
|
||||
}
|
||||
#include "vpi_user.h"
|
||||
#include <string.h>
|
||||
#include <math.h>
|
||||
#include <assert.h>
|
||||
#include <sys_priv.h>
|
||||
|
||||
static PLI_INT32 sys_time_calltf(PLI_BYTE8*name)
|
||||
{
|
||||
@@ -60,7 +38,7 @@ static PLI_INT32 sys_time_calltf(PLI_BYTE8*name)
|
||||
call_handle = vpi_handle(vpiSysTfCall, 0);
|
||||
assert(call_handle);
|
||||
|
||||
mod = module_of_function(call_handle);
|
||||
mod = sys_func_module(call_handle);
|
||||
|
||||
now.type = vpiSimTime;
|
||||
vpi_get_time(0, &now);
|
||||
@@ -113,7 +91,7 @@ static PLI_INT32 sys_realtime_calltf(PLI_BYTE8*name)
|
||||
call_handle = vpi_handle(vpiSysTfCall, 0);
|
||||
assert(call_handle);
|
||||
|
||||
mod = module_of_function(call_handle);
|
||||
mod = sys_func_module(call_handle);
|
||||
|
||||
now.type = vpiSimTime;
|
||||
vpi_get_time(0, &now);
|
||||
@@ -134,82 +112,39 @@ void sys_time_register()
|
||||
{
|
||||
s_vpi_systf_data tf_data;
|
||||
|
||||
tf_data.type = vpiSysFunc;
|
||||
tf_data.tfname = "$time";
|
||||
tf_data.calltf = sys_time_calltf;
|
||||
tf_data.compiletf = 0;
|
||||
tf_data.sizetf = sys_time_sizetf;
|
||||
tf_data.user_data = "$time";
|
||||
tf_data.type = vpiSysFunc;
|
||||
tf_data.tfname = "$time";
|
||||
tf_data.sysfunctype = vpiTimeFunc;
|
||||
tf_data.calltf = sys_time_calltf;
|
||||
tf_data.compiletf = sys_no_arg_compiletf;
|
||||
tf_data.sizetf = 0;
|
||||
tf_data.user_data = "$time";
|
||||
vpi_register_systf(&tf_data);
|
||||
|
||||
tf_data.type = vpiSysFunc;
|
||||
tf_data.tfname = "$realtime";
|
||||
tf_data.calltf = sys_realtime_calltf;
|
||||
tf_data.compiletf = 0;
|
||||
tf_data.sizetf = 0;
|
||||
tf_data.user_data = "$realtime";
|
||||
tf_data.type = vpiSysFunc;
|
||||
tf_data.tfname = "$realtime";
|
||||
tf_data.sysfunctype = vpiRealFunc;
|
||||
tf_data.calltf = sys_realtime_calltf;
|
||||
tf_data.compiletf = sys_no_arg_compiletf;
|
||||
tf_data.sizetf = 0;
|
||||
tf_data.user_data = "$realtime";
|
||||
vpi_register_systf(&tf_data);
|
||||
|
||||
tf_data.type = vpiSysFunc;
|
||||
tf_data.tfname = "$stime";
|
||||
tf_data.calltf = sys_time_calltf;
|
||||
tf_data.compiletf = 0;
|
||||
tf_data.sizetf = sys_stime_sizetf;
|
||||
tf_data.user_data = "$stime";
|
||||
tf_data.type = vpiSysFunc;
|
||||
tf_data.tfname = "$stime";
|
||||
tf_data.sysfunctype = vpiIntFunc;
|
||||
tf_data.calltf = sys_time_calltf;
|
||||
tf_data.compiletf = sys_no_arg_compiletf;
|
||||
tf_data.sizetf = 0;
|
||||
tf_data.user_data = "$stime";
|
||||
vpi_register_systf(&tf_data);
|
||||
|
||||
tf_data.type = vpiSysFunc;
|
||||
tf_data.tfname = "$simtime";
|
||||
tf_data.calltf = sys_time_calltf;
|
||||
tf_data.compiletf = 0;
|
||||
tf_data.sizetf = sys_time_sizetf;
|
||||
tf_data.user_data = "$simtime";
|
||||
tf_data.type = vpiSysFunc;
|
||||
tf_data.tfname = "$simtime";
|
||||
tf_data.sysfunctype = vpiTimeFunc;
|
||||
tf_data.calltf = sys_time_calltf;
|
||||
tf_data.compiletf = sys_no_arg_compiletf;
|
||||
tf_data.sizetf = 0;
|
||||
tf_data.user_data = "$simtime";
|
||||
vpi_register_systf(&tf_data);
|
||||
}
|
||||
|
||||
/*
|
||||
* $Log: sys_time.c,v $
|
||||
* Revision 1.12 2007/03/14 04:05:51 steve
|
||||
* VPI tasks take PLI_BYTE* by the standard.
|
||||
*
|
||||
* Revision 1.11 2006/10/30 22:45:37 steve
|
||||
* Updates for Cygwin portability (pr1585922)
|
||||
*
|
||||
* Revision 1.10 2004/01/21 01:22:53 steve
|
||||
* Give the vip directory its own configure and vpi_config.h
|
||||
*
|
||||
* Revision 1.9 2003/06/18 00:54:28 steve
|
||||
* Account for all 64 bits in results of $time.
|
||||
*
|
||||
* Revision 1.8 2003/02/07 02:44:25 steve
|
||||
* Properly round inter time values from $time.
|
||||
*
|
||||
* Revision 1.7 2003/01/28 04:41:55 steve
|
||||
* Use more precise pow function to scale time by units.
|
||||
*
|
||||
* Revision 1.6 2003/01/27 00:14:37 steve
|
||||
* Support in various contexts the $realtime
|
||||
* system task.
|
||||
*
|
||||
* Revision 1.5 2002/12/21 00:55:58 steve
|
||||
* The $time system task returns the integer time
|
||||
* scaled to the local units. Change the internal
|
||||
* implementation of vpiSystemTime the $time functions
|
||||
* to properly account for this. Also add $simtime
|
||||
* to get the simulation time.
|
||||
*
|
||||
* Revision 1.4 2002/08/12 01:35:05 steve
|
||||
* conditional ident string using autoconfig.
|
||||
*
|
||||
* Revision 1.3 2002/01/11 05:20:59 steve
|
||||
* Add the stime system function.
|
||||
*
|
||||
* Revision 1.2 2001/07/25 03:10:50 steve
|
||||
* Create a config.h.in file to hold all the config
|
||||
* junk, and support gcc 3.0. (Stephan Boettcher)
|
||||
*
|
||||
* Revision 1.1 2000/11/01 03:19:36 steve
|
||||
* Add the general $time system function.
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
+37
-49
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 1999-2003 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_vcd.c,v 1.58 2007/03/14 04:05:51 steve Exp $"
|
||||
#endif
|
||||
|
||||
# include "sys_priv.h"
|
||||
|
||||
@@ -269,9 +266,9 @@ inline static int install_dumpvars_callback(void)
|
||||
if (dumpvars_status == 1) return 0;
|
||||
|
||||
if (dumpvars_status == 2) {
|
||||
vpi_mcd_printf(1, "VCD warning: $dumpvars ignored, previously"
|
||||
" called at simtime %" PLI_UINT64_FMT "\n",
|
||||
dumpvars_time);
|
||||
vpi_printf("VCD warning: $dumpvars ignored, previously"
|
||||
" called at simtime %" PLI_UINT64_FMT "\n",
|
||||
dumpvars_time);
|
||||
return 1;
|
||||
}
|
||||
|
||||
@@ -374,15 +371,16 @@ static PLI_INT32 sys_dumpall_calltf(PLI_BYTE8*name)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void open_dumpfile(void)
|
||||
static void open_dumpfile(vpiHandle callh)
|
||||
{
|
||||
if (dump_path == 0) dump_path = strdup("dump.vcd");
|
||||
|
||||
dump_file = fopen(dump_path, "w");
|
||||
|
||||
if (dump_file == 0) {
|
||||
vpi_mcd_printf(1, "VCD Error: Unable to open %s for output.\n",
|
||||
dump_path);
|
||||
vpi_printf("VCD Error: %s line %d: ", vpi_get_str(vpiFile, callh),
|
||||
(int)vpi_get(vpiLineNo, callh));
|
||||
vpi_printf("Unable to open %s for output.\n", dump_path);
|
||||
vpi_control(vpiFinish, 1);
|
||||
return;
|
||||
} else {
|
||||
@@ -391,8 +389,7 @@ static void open_dumpfile(void)
|
||||
unsigned udx = 0;
|
||||
time_t walltime;
|
||||
|
||||
vpi_mcd_printf(1, "VCD info: dumpfile %s opened for output.\n",
|
||||
dump_path);
|
||||
vpi_printf("VCD info: dumpfile %s opened for output.\n", dump_path);
|
||||
|
||||
time(&walltime);
|
||||
|
||||
@@ -428,9 +425,9 @@ static PLI_INT32 sys_dumpfile_calltf(PLI_BYTE8*name)
|
||||
|
||||
/* $dumpfile must be called before $dumpvars starts! */
|
||||
if (dumpvars_status != 0) {
|
||||
vpi_mcd_printf(1, "VCD warning: %s called after $dumpvars started"
|
||||
",\n using existing file (%s).\n",
|
||||
name, dump_path);
|
||||
vpi_printf("VCD warning: %s called after $dumpvars started,\n"
|
||||
" using existing file (%s).\n",
|
||||
name, dump_path);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -440,8 +437,8 @@ static PLI_INT32 sys_dumpfile_calltf(PLI_BYTE8*name)
|
||||
path = strdup(value.value.str);
|
||||
|
||||
if (dump_path) {
|
||||
vpi_mcd_printf(1, "VCD warning: Overriding dump file %s with"
|
||||
" %s\n", dump_path, path);
|
||||
vpi_printf("VCD warning: Overriding dump file %s with %s\n",
|
||||
dump_path, path);
|
||||
free(dump_path);
|
||||
}
|
||||
dump_path = path;
|
||||
@@ -502,16 +499,9 @@ static void scan_item(unsigned depth, vpiHandle item, int skip)
|
||||
|
||||
switch (vpi_get(vpiType, item)) {
|
||||
|
||||
case vpiMemory:
|
||||
/* don't know how to watch memories. */
|
||||
break;
|
||||
|
||||
case vpiNamedEvent:
|
||||
/* There is nothing in named events to dump. */
|
||||
break;
|
||||
|
||||
case vpiNet: type = "wire"; if(0){
|
||||
case vpiIntegerVar:
|
||||
case vpiMemoryWord:
|
||||
case vpiTimeVar:
|
||||
case vpiReg: type = "reg"; }
|
||||
|
||||
@@ -635,18 +625,16 @@ static void scan_item(unsigned depth, vpiHandle item, int skip)
|
||||
vpi_get_str(vpiFullName, item);
|
||||
|
||||
#if 0
|
||||
vpi_mcd_printf(1,
|
||||
"VCD info:"
|
||||
" scanning scope %s, %u levels\n",
|
||||
fullname, depth);
|
||||
vpi_printf("VCD info: scanning scope %s, %u levels\n",
|
||||
fullname, depth);
|
||||
#endif
|
||||
nskip = 0 != vcd_names_search(&vcd_tab, fullname);
|
||||
|
||||
if (!nskip)
|
||||
vcd_names_add(&vcd_tab, fullname);
|
||||
else
|
||||
vpi_mcd_printf(1, "VCD warning: ignoring signals in"
|
||||
" previously scanned scope %s\n", fullname);
|
||||
vpi_printf("VCD warning: ignoring signals in "
|
||||
"previously scanned scope %s\n", fullname);
|
||||
|
||||
name = vpi_get_str(vpiName, item);
|
||||
|
||||
@@ -665,12 +653,12 @@ static void scan_item(unsigned depth, vpiHandle item, int skip)
|
||||
break;
|
||||
|
||||
default:
|
||||
vpi_mcd_printf(1, "VCD warning: $dumpvars: Unsupported parameter "
|
||||
"type (%d)\n", vpi_get(vpiType, item));
|
||||
vpi_printf("VCD warning: $dumpvars: Unsupported parameter "
|
||||
"type (%s)\n", vpi_get_str(vpiType, item));
|
||||
}
|
||||
}
|
||||
|
||||
static int draw_scope(vpiHandle item)
|
||||
static int draw_scope(vpiHandle item, vpiHandle callh)
|
||||
{
|
||||
int depth;
|
||||
const char *name;
|
||||
@@ -679,7 +667,7 @@ static int draw_scope(vpiHandle item)
|
||||
vpiHandle scope = vpi_handle(vpiScope, item);
|
||||
if (!scope) return 0;
|
||||
|
||||
depth = 1 + draw_scope(scope);
|
||||
depth = 1 + draw_scope(scope, callh);
|
||||
name = vpi_get_str(vpiName, scope);
|
||||
|
||||
switch (vpi_get(vpiType, scope)) {
|
||||
@@ -689,8 +677,9 @@ static int draw_scope(vpiHandle item)
|
||||
case vpiNamedFork: type = "fork"; break;
|
||||
case vpiModule: type = "module"; break;
|
||||
default:
|
||||
vpi_mcd_printf(1, "VCD Error: $dumpvars: Unsupported scope "
|
||||
"type (%d)\n", vpi_get(vpiType, item));
|
||||
vpi_printf("VCD Error: %s line %d: $dumpvars: Unsupported scope "
|
||||
"type (%d)\n", vpi_get_str(vpiFile, callh),
|
||||
(int)vpi_get(vpiLineNo, callh), vpi_get(vpiType, item));
|
||||
assert(0);
|
||||
}
|
||||
|
||||
@@ -708,7 +697,7 @@ static PLI_INT32 sys_dumpvars_calltf(PLI_BYTE8*name)
|
||||
unsigned depth = 0;
|
||||
|
||||
if (dump_file == 0) {
|
||||
open_dumpfile();
|
||||
open_dumpfile(callh);
|
||||
if (dump_file == 0) return 0;
|
||||
}
|
||||
|
||||
@@ -739,23 +728,23 @@ static PLI_INT32 sys_dumpvars_calltf(PLI_BYTE8*name)
|
||||
* been included. */
|
||||
switch (vpi_get(vpiType, item)) {
|
||||
case vpiIntegerVar:
|
||||
/* What about MemoryWord? */
|
||||
case vpiMemoryWord:
|
||||
case vpiNet:
|
||||
case vpiRealVar:
|
||||
case vpiReg:
|
||||
case vpiTimeVar:
|
||||
scname = vpi_get_str(vpiFullName, vpi_handle(vpiScope, item));
|
||||
if (vcd_names_search(&vcd_tab, scname)) {
|
||||
vpi_mcd_printf(1, "VCD warning: skipping signal %s, "
|
||||
"it was previously included.\n",
|
||||
vpi_get_str(vpiFullName, item));
|
||||
vpi_printf("VCD warning: skipping signal %s, "
|
||||
"it was previously included.\n",
|
||||
vpi_get_str(vpiFullName, item));
|
||||
continue;
|
||||
} else {
|
||||
add_var = 1;
|
||||
}
|
||||
}
|
||||
|
||||
int dep = draw_scope(item);
|
||||
int dep = draw_scope(item, callh);
|
||||
|
||||
scan_item(depth, item, 0);
|
||||
|
||||
@@ -782,7 +771,7 @@ void sys_vcd_register()
|
||||
tf_data.type = vpiSysTask;
|
||||
tf_data.tfname = "$dumpall";
|
||||
tf_data.calltf = sys_dumpall_calltf;
|
||||
tf_data.compiletf = sys_dumpall_compiletf;
|
||||
tf_data.compiletf = sys_no_arg_compiletf;
|
||||
tf_data.sizetf = 0;
|
||||
tf_data.user_data = "$dumpall";
|
||||
vpi_register_systf(&tf_data);
|
||||
@@ -798,7 +787,7 @@ void sys_vcd_register()
|
||||
tf_data.type = vpiSysTask;
|
||||
tf_data.tfname = "$dumpflush";
|
||||
tf_data.calltf = sys_dumpflush_calltf;
|
||||
tf_data.compiletf = sys_dumpflush_compiletf;
|
||||
tf_data.compiletf = sys_no_arg_compiletf;
|
||||
tf_data.sizetf = 0;
|
||||
tf_data.user_data = "$dumpflush";
|
||||
vpi_register_systf(&tf_data);
|
||||
@@ -806,7 +795,7 @@ void sys_vcd_register()
|
||||
tf_data.type = vpiSysTask;
|
||||
tf_data.tfname = "$dumplimit";
|
||||
tf_data.calltf = sys_dumplimit_calltf;
|
||||
tf_data.compiletf = sys_dumplimit_compiletf;
|
||||
tf_data.compiletf = sys_one_numeric_arg_compiletf;
|
||||
tf_data.sizetf = 0;
|
||||
tf_data.user_data = "$dumplimit";
|
||||
vpi_register_systf(&tf_data);
|
||||
@@ -814,7 +803,7 @@ void sys_vcd_register()
|
||||
tf_data.type = vpiSysTask;
|
||||
tf_data.tfname = "$dumpoff";
|
||||
tf_data.calltf = sys_dumpoff_calltf;
|
||||
tf_data.compiletf = sys_dumpoff_compiletf;
|
||||
tf_data.compiletf = sys_no_arg_compiletf;
|
||||
tf_data.sizetf = 0;
|
||||
tf_data.user_data = "$dumpoff";
|
||||
vpi_register_systf(&tf_data);
|
||||
@@ -822,7 +811,7 @@ void sys_vcd_register()
|
||||
tf_data.type = vpiSysTask;
|
||||
tf_data.tfname = "$dumpon";
|
||||
tf_data.calltf = sys_dumpon_calltf;
|
||||
tf_data.compiletf = sys_dumpon_compiletf;
|
||||
tf_data.compiletf = sys_no_arg_compiletf;
|
||||
tf_data.sizetf = 0;
|
||||
tf_data.user_data = "$dumpon";
|
||||
vpi_register_systf(&tf_data);
|
||||
@@ -835,4 +824,3 @@ void sys_vcd_register()
|
||||
tf_data.user_data = "$dumpvars";
|
||||
vpi_register_systf(&tf_data);
|
||||
}
|
||||
|
||||
|
||||
+14
-18
@@ -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: sys_vcdoff.c,v 1.5 2007/03/14 04:05:52 steve Exp $"
|
||||
#endif
|
||||
|
||||
# include "sys_priv.h"
|
||||
|
||||
@@ -40,7 +37,7 @@
|
||||
|
||||
static int dump_flag = 0;
|
||||
|
||||
static PLI_INT32 sys_dump_calltf(PLI_BYTE8*name)
|
||||
static PLI_INT32 sys_dummy_calltf(PLI_BYTE8*name)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
@@ -48,7 +45,7 @@ static PLI_INT32 sys_dump_calltf(PLI_BYTE8*name)
|
||||
static PLI_INT32 sys_dumpvars_calltf(PLI_BYTE8*name)
|
||||
{
|
||||
if (dump_flag == 0) {
|
||||
vpi_mcd_printf(1, "VCD info: dumping is suppressed.\n");
|
||||
vpi_printf("VCD info: dumping is suppressed.\n");
|
||||
dump_flag = 1;
|
||||
}
|
||||
|
||||
@@ -63,15 +60,15 @@ void sys_vcdoff_register()
|
||||
|
||||
tf_data.type = vpiSysTask;
|
||||
tf_data.tfname = "$dumpall";
|
||||
tf_data.calltf = sys_dump_calltf;
|
||||
tf_data.compiletf = sys_dumpall_compiletf;
|
||||
tf_data.calltf = sys_dummy_calltf;
|
||||
tf_data.compiletf = sys_no_arg_compiletf;
|
||||
tf_data.sizetf = 0;
|
||||
tf_data.user_data = "$dumpall";
|
||||
vpi_register_systf(&tf_data);
|
||||
|
||||
tf_data.type = vpiSysTask;
|
||||
tf_data.tfname = "$dumpfile";
|
||||
tf_data.calltf = sys_dump_calltf;
|
||||
tf_data.calltf = sys_dummy_calltf;
|
||||
tf_data.compiletf = sys_dumpfile_compiletf;
|
||||
tf_data.sizetf = 0;
|
||||
tf_data.user_data = "$dumpfile";
|
||||
@@ -79,32 +76,32 @@ void sys_vcdoff_register()
|
||||
|
||||
tf_data.type = vpiSysTask;
|
||||
tf_data.tfname = "$dumpflush";
|
||||
tf_data.calltf = sys_dump_calltf;
|
||||
tf_data.compiletf = sys_dumpflush_compiletf;
|
||||
tf_data.calltf = sys_dummy_calltf;
|
||||
tf_data.compiletf = sys_no_arg_compiletf;
|
||||
tf_data.sizetf = 0;
|
||||
tf_data.user_data = "$dumpflush";
|
||||
vpi_register_systf(&tf_data);
|
||||
|
||||
tf_data.type = vpiSysTask;
|
||||
tf_data.tfname = "$dumplimit";
|
||||
tf_data.calltf = sys_dump_calltf;
|
||||
tf_data.compiletf = sys_dumplimit_compiletf;
|
||||
tf_data.calltf = sys_dummy_calltf;
|
||||
tf_data.compiletf = sys_one_numeric_arg_compiletf;
|
||||
tf_data.sizetf = 0;
|
||||
tf_data.user_data = "$dumplimit";
|
||||
vpi_register_systf(&tf_data);
|
||||
|
||||
tf_data.type = vpiSysTask;
|
||||
tf_data.tfname = "$dumpoff";
|
||||
tf_data.calltf = sys_dump_calltf;
|
||||
tf_data.compiletf = sys_dumpoff_compiletf;
|
||||
tf_data.calltf = sys_dummy_calltf;
|
||||
tf_data.compiletf = sys_no_arg_compiletf;
|
||||
tf_data.sizetf = 0;
|
||||
tf_data.user_data = "$dumpoff";
|
||||
vpi_register_systf(&tf_data);
|
||||
|
||||
tf_data.type = vpiSysTask;
|
||||
tf_data.tfname = "$dumpon";
|
||||
tf_data.calltf = sys_dump_calltf;
|
||||
tf_data.compiletf = sys_dumpon_compiletf;
|
||||
tf_data.calltf = sys_dummy_calltf;
|
||||
tf_data.compiletf = sys_no_arg_compiletf;
|
||||
tf_data.sizetf = 0;
|
||||
tf_data.user_data = "$dumpon";
|
||||
vpi_register_systf(&tf_data);
|
||||
@@ -117,4 +114,3 @@ void sys_vcdoff_register()
|
||||
tf_data.user_data = "$dumpvars";
|
||||
vpi_register_systf(&tf_data);
|
||||
}
|
||||
|
||||
|
||||
@@ -14,3 +14,6 @@ $dist_poisson vpiSysFuncInt
|
||||
$dist_chi_square vpiSysFuncInt
|
||||
$dist_t vpiSysFuncInt
|
||||
$dist_erlang vpiSysFuncInt
|
||||
|
||||
$simparam vpiSysFuncReal
|
||||
$simparam$str vpiSysFuncSized 1024 unsigned
|
||||
|
||||
+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
|
||||
};
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user