Merge branch 'master' into verilog-ams
This commit is contained in:
commit
3575f68c9f
30
Makefile.in
30
Makefile.in
|
|
@ -16,9 +16,6 @@
|
||||||
# 59 Temple Place - Suite 330
|
# 59 Temple Place - Suite 330
|
||||||
# Boston, MA 02111-1307, USA
|
# Boston, MA 02111-1307, USA
|
||||||
#
|
#
|
||||||
#ident "$Id: Makefile.in,v 1.181 2007/05/24 04:07:11 steve Exp $"
|
|
||||||
#
|
|
||||||
#
|
|
||||||
SHELL = /bin/sh
|
SHELL = /bin/sh
|
||||||
|
|
||||||
# This version string is only used in the version message printed
|
# This version string is only used in the version message printed
|
||||||
|
|
@ -51,6 +48,9 @@ INSTALL_PROGRAM = @INSTALL_PROGRAM@
|
||||||
INSTALL_DATA = @INSTALL_DATA@
|
INSTALL_DATA = @INSTALL_DATA@
|
||||||
LEX = @LEX@
|
LEX = @LEX@
|
||||||
YACC = @YACC@
|
YACC = @YACC@
|
||||||
|
MAN = @MAN@
|
||||||
|
PS2PDF = @PS2PDF@
|
||||||
|
GIT = @GIT@
|
||||||
|
|
||||||
CPPFLAGS = @ident_support@ @DEFS@ -I. -I$(srcdir) @CPPFLAGS@
|
CPPFLAGS = @ident_support@ @DEFS@ -I. -I$(srcdir) @CPPFLAGS@
|
||||||
CXXFLAGS = -Wall @CXXFLAGS@
|
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
|
# In the windows world, the installer will need a dosify program to
|
||||||
# dosify text files.
|
# dosify text files.
|
||||||
ifeq (@MING32@,yes)
|
ifeq (@MINGW32@,yes)
|
||||||
all: dep dosify.exe
|
all: dep dosify.exe
|
||||||
dosify.exe: dosify.c
|
dosify.exe: dosify.c
|
||||||
$(CC) -o dosify.exe dosify.c
|
$(CC) -o dosify.exe dosify.c
|
||||||
|
|
@ -177,19 +177,22 @@ lexor_keyword.cc: lexor_keyword.gperf
|
||||||
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)
|
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
|
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
|
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
|
# 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
|
# version.h file in the source tree (included in snapshots and releases), and
|
||||||
# finally use nothing.
|
# finally use nothing.
|
||||||
.PHONY: version.h
|
.PHONY: version.h
|
||||||
version.h:
|
version.h:
|
||||||
|
ifeq ($(GIT),none)
|
||||||
|
@echo '#define VERSION_TAG ""' > $@;
|
||||||
|
else
|
||||||
@if test -d $(srcdir)/.git; then \
|
@if test -d $(srcdir)/.git; then \
|
||||||
echo "Using git-describe for VERSION_TAG"; \
|
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";'`; \
|
| sed -e 's;\(.*\);#define VERSION_TAG "\1";'`; \
|
||||||
echo "$$tmp" | diff - $@ > /dev/null 2>&1 || echo "$$tmp" > $@ || exit 1; \
|
echo "$$tmp" | diff - $@ > /dev/null 2>&1 || echo "$$tmp" > $@ || exit 1; \
|
||||||
elif test -r $(srcdir)/$@; then \
|
elif test -r $(srcdir)/$@; then \
|
||||||
|
|
@ -199,11 +202,20 @@ version.h:
|
||||||
echo "Using empty VERSION_TAG"; \
|
echo "Using empty VERSION_TAG"; \
|
||||||
echo '#define VERSION_TAG ""' > $@; \
|
echo '#define VERSION_TAG ""' > $@; \
|
||||||
fi
|
fi
|
||||||
|
endif
|
||||||
|
|
||||||
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_DOC = $(prefix)/iverilog-vpi.pdf $(mandir)/man1/iverilog-vpi.1
|
||||||
INSTALL_DOCDIR = $(mandir)/man1
|
|
||||||
all: dep iverilog-vpi.pdf
|
all: dep iverilog-vpi.pdf
|
||||||
|
endif
|
||||||
|
endif
|
||||||
|
INSTALL_DOCDIR = $(mandir)/man1
|
||||||
else
|
else
|
||||||
INSTALL_DOC = $(mandir)/man1/iverilog-vpi.1
|
INSTALL_DOC = $(mandir)/man1/iverilog-vpi.1
|
||||||
INSTALL_DOCDIR = $(mandir)/man1
|
INSTALL_DOCDIR = $(mandir)/man1
|
||||||
|
|
|
||||||
|
|
@ -16,4 +16,4 @@ do
|
||||||
done
|
done
|
||||||
|
|
||||||
echo "Precompiling lexor_keyword.gperf"
|
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
|
||||||
|
|
|
||||||
|
|
@ -16,12 +16,9 @@
|
||||||
# 59 Temple Place - Suite 330
|
# 59 Temple Place - Suite 330
|
||||||
# Boston, MA 02111-1307, USA
|
# Boston, MA 02111-1307, USA
|
||||||
#
|
#
|
||||||
#ident "$Id: Makefile.in,v 1.13 2007/02/06 05:07:31 steve Exp $"
|
|
||||||
#
|
|
||||||
#
|
|
||||||
SHELL = /bin/sh
|
SHELL = /bin/sh
|
||||||
|
|
||||||
VERSION = 0.0
|
VERSION = 0.9.devel
|
||||||
|
|
||||||
prefix = @prefix@
|
prefix = @prefix@
|
||||||
exec_prefix = @exec_prefix@
|
exec_prefix = @exec_prefix@
|
||||||
|
|
@ -63,7 +60,7 @@ dep:
|
||||||
O = cadpli.o
|
O = cadpli.o
|
||||||
|
|
||||||
SYSTEM_VPI_LDFLAGS = -L../vvp -lvpi
|
SYSTEM_VPI_LDFLAGS = -L../vvp -lvpi
|
||||||
ifeq (@MING32@,yes)
|
ifeq (@MINGW32@,yes)
|
||||||
SYSTEM_VPI_LDFLAGS += @EXTRALIBS@
|
SYSTEM_VPI_LDFLAGS += @EXTRALIBS@
|
||||||
endif
|
endif
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -86,6 +86,7 @@ extern bool debug_scopes;
|
||||||
extern bool debug_eval_tree;
|
extern bool debug_eval_tree;
|
||||||
extern bool debug_elaborate;
|
extern bool debug_elaborate;
|
||||||
extern bool debug_synth2;
|
extern bool debug_synth2;
|
||||||
|
extern bool debug_optimizer;
|
||||||
|
|
||||||
/* Path to a directory useful for finding subcomponents. */
|
/* Path to a directory useful for finding subcomponents. */
|
||||||
extern const char*basedir;
|
extern const char*basedir;
|
||||||
|
|
|
||||||
|
|
@ -9,6 +9,9 @@ AC_PROG_CC
|
||||||
AC_PROG_CXX
|
AC_PROG_CXX
|
||||||
AC_CHECK_TOOL(STRIP, strip, true)
|
AC_CHECK_TOOL(STRIP, strip, true)
|
||||||
AC_CHECK_PROGS(XGPERF,gperf,none)
|
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"
|
if test "$XGPERF" = "none"
|
||||||
then
|
then
|
||||||
echo ""
|
echo ""
|
||||||
|
|
|
||||||
27
cprop.cc
27
cprop.cc
|
|
@ -23,6 +23,7 @@
|
||||||
# include "netlist.h"
|
# include "netlist.h"
|
||||||
# include "netmisc.h"
|
# include "netmisc.h"
|
||||||
# include "functor.h"
|
# include "functor.h"
|
||||||
|
# include "compiler.h"
|
||||||
# include "ivl_assert.h"
|
# include "ivl_assert.h"
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -828,6 +829,32 @@ void cprop_functor::lpm_mux(Design*des, NetMux*obj)
|
||||||
count += 1;
|
count += 1;
|
||||||
return;
|
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;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
|
||||||
|
|
@ -16,12 +16,9 @@
|
||||||
# 59 Temple Place - Suite 330
|
# 59 Temple Place - Suite 330
|
||||||
# Boston, MA 02111-1307, USA
|
# 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
|
SHELL = /bin/sh
|
||||||
|
|
||||||
VERSION = 0.8.3
|
VERSION = 0.9.devel
|
||||||
|
|
||||||
prefix = @prefix@
|
prefix = @prefix@
|
||||||
exec_prefix = @exec_prefix@
|
exec_prefix = @exec_prefix@
|
||||||
|
|
@ -48,6 +45,8 @@ LDFLAGS = @LDFLAGS@
|
||||||
|
|
||||||
all: iverilog-vpi@EXEEXT@
|
all: iverilog-vpi@EXEEXT@
|
||||||
|
|
||||||
|
check: all
|
||||||
|
|
||||||
clean:
|
clean:
|
||||||
rm -f *.o config.h
|
rm -f *.o config.h
|
||||||
rm -f iverilog-vpi@EXEEXT@
|
rm -f iverilog-vpi@EXEEXT@
|
||||||
|
|
|
||||||
|
|
@ -336,6 +336,14 @@ static int parse(int argc, char *argv[])
|
||||||
assignn(&gstr.pOUT, argv[idx],
|
assignn(&gstr.pOUT, argv[idx],
|
||||||
strlen(argv[idx])-strlen(dot_o_ext));
|
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 */
|
/* Check for the --name option */
|
||||||
else if (startsWith(name_option, argv[idx])) {
|
else if (startsWith(name_option, argv[idx])) {
|
||||||
assignn(&gstr.pOUT, argv[idx]+sizeof(name_option)-1,
|
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, " ");
|
||||||
append(&gstr.pDEFS, argv[idx]);
|
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 */
|
/* Check for the --cflags option */
|
||||||
else if (stricmp("--cflags", argv[idx]) == 0) {
|
else if (stricmp("--cflags", argv[idx]) == 0) {
|
||||||
setup_ivl_environment();
|
setup_ivl_environment();
|
||||||
|
|
|
||||||
|
|
@ -16,9 +16,6 @@
|
||||||
# 59 Temple Place - Suite 330
|
# 59 Temple Place - Suite 330
|
||||||
# Boston, MA 02111-1307, USA
|
# Boston, MA 02111-1307, USA
|
||||||
#
|
#
|
||||||
#ident "$Id: Makefile.in,v 1.26 2007/02/06 05:07:31 steve Exp $"
|
|
||||||
#
|
|
||||||
#
|
|
||||||
SHELL = /bin/sh
|
SHELL = /bin/sh
|
||||||
|
|
||||||
VERSION = 0.9.devel
|
VERSION = 0.9.devel
|
||||||
|
|
@ -41,6 +38,8 @@ CC = @CC@
|
||||||
INSTALL = @INSTALL@
|
INSTALL = @INSTALL@
|
||||||
INSTALL_PROGRAM = @INSTALL_PROGRAM@
|
INSTALL_PROGRAM = @INSTALL_PROGRAM@
|
||||||
INSTALL_DATA = @INSTALL_DATA@
|
INSTALL_DATA = @INSTALL_DATA@
|
||||||
|
MAN = @MAN@
|
||||||
|
PS2PDF = @PS2PDF@
|
||||||
|
|
||||||
CPPFLAGS = @ident_support@ -I. -I.. -I$(srcdir)/.. -I$(srcdir) -DVERSION='"$(VERSION)"' @CPPFLAGS@ @DEFS@
|
CPPFLAGS = @ident_support@ -I. -I.. -I$(srcdir)/.. -I$(srcdir) -DVERSION='"$(VERSION)"' @CPPFLAGS@ @DEFS@
|
||||||
CFLAGS = -Wall @CFLAGS@
|
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
|
cfparse.o: cfparse.c globals.h cfparse_misc.h
|
||||||
|
|
||||||
iverilog.ps: $(srcdir)/iverilog.man
|
iverilog.ps: $(srcdir)/iverilog.man
|
||||||
man -t $(srcdir)/iverilog.man > iverilog.ps
|
$(MAN) -t $(srcdir)/iverilog.man > iverilog.ps
|
||||||
|
|
||||||
iverilog.pdf: 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_DOC = $(prefix)/iverilog.pdf $(mandir)/man1/iverilog.1
|
||||||
INSTALL_DOCDIR = $(mandir)/man1
|
|
||||||
all: iverilog.pdf
|
all: iverilog.pdf
|
||||||
|
endif
|
||||||
|
endif
|
||||||
|
INSTALL_DOCDIR = $(mandir)/man1
|
||||||
else
|
else
|
||||||
INSTALL_DOC = $(mandir)/man1/iverilog.1
|
INSTALL_DOC = $(mandir)/man1/iverilog.1
|
||||||
INSTALL_DOCDIR = $(mandir)/man1
|
INSTALL_DOCDIR = $(mandir)/man1
|
||||||
|
|
|
||||||
|
|
@ -327,6 +327,9 @@ static int t_default(char*cmd, unsigned ncmd)
|
||||||
remove(defines_path);
|
remove(defines_path);
|
||||||
remove(compiled_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 != 0) {
|
||||||
if (rc == 127) {
|
if (rc == 127) {
|
||||||
|
|
@ -342,6 +345,7 @@ static int t_default(char*cmd, unsigned ncmd)
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -22,6 +22,7 @@
|
||||||
# include "netmisc.h"
|
# include "netmisc.h"
|
||||||
# include <cstring>
|
# include <cstring>
|
||||||
# include <iostream>
|
# include <iostream>
|
||||||
|
# include <cstdlib>
|
||||||
# include <stdio.h>
|
# include <stdio.h>
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
|
||||||
|
|
@ -1172,8 +1172,6 @@ NetExpr* NetEParam::eval_tree(int prune_to_width)
|
||||||
|
|
||||||
assert(scope_);
|
assert(scope_);
|
||||||
perm_string name = (*reference_).first;
|
perm_string name = (*reference_).first;
|
||||||
const NetExpr*expr_msb = (*reference_).second.msb;
|
|
||||||
const NetExpr*expr_lsb = (*reference_).second.lsb;
|
|
||||||
const NetExpr*expr = (*reference_).second.expr;
|
const NetExpr*expr = (*reference_).second.expr;
|
||||||
ivl_assert(*this, expr);
|
ivl_assert(*this, expr);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1616,7 +1616,11 @@ static int load_next_input()
|
||||||
static void do_dump_precompiled_defines(FILE* out, struct define_t* table)
|
static void do_dump_precompiled_defines(FILE* out, struct define_t* table)
|
||||||
{
|
{
|
||||||
if (!table->keyword)
|
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);
|
fprintf(out, "%s:%d:%zd:%s\n", table->name, table->argc, strlen(table->value), table->value);
|
||||||
|
#endif
|
||||||
|
|
||||||
if (table->left)
|
if (table->left)
|
||||||
do_dump_precompiled_defines(out, table->left);
|
do_dump_precompiled_defines(out, table->left);
|
||||||
|
|
@ -1741,6 +1745,7 @@ void reset_lexor(FILE* out, char* paths[])
|
||||||
isp->ebs = 0;
|
isp->ebs = 0;
|
||||||
isp->next = 0;
|
isp->next = 0;
|
||||||
isp->lineno = 0;
|
isp->lineno = 0;
|
||||||
|
isp->stringify_flag = 0;
|
||||||
|
|
||||||
if (tail)
|
if (tail)
|
||||||
tail->next = isp;
|
tail->next = isp;
|
||||||
|
|
|
||||||
5
main.cc
5
main.cc
|
|
@ -124,6 +124,8 @@ bool debug_scopes = false;
|
||||||
bool debug_eval_tree = false;
|
bool debug_eval_tree = false;
|
||||||
bool debug_elaborate = false;
|
bool debug_elaborate = false;
|
||||||
bool debug_synth2 = false;
|
bool debug_synth2 = false;
|
||||||
|
bool debug_optimizer = false;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Verbose messages enabled.
|
* Verbose messages enabled.
|
||||||
*/
|
*/
|
||||||
|
|
@ -391,6 +393,9 @@ static void read_iconfig_file(const char*ipath)
|
||||||
} else if (strcmp(cp,"synth2") == 0) {
|
} else if (strcmp(cp,"synth2") == 0) {
|
||||||
debug_synth2 = true;
|
debug_synth2 = true;
|
||||||
cerr << "debug: Enable synth2 debug" << endl;
|
cerr << "debug: Enable synth2 debug" << endl;
|
||||||
|
} else if (strcmp(cp,"optimizer") == 0) {
|
||||||
|
debug_optimizer = true;
|
||||||
|
cerr << "debug: Enable optimizer debug" << endl;
|
||||||
} else {
|
} else {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -20,6 +20,7 @@
|
||||||
# include "config.h"
|
# include "config.h"
|
||||||
|
|
||||||
# include <iostream>
|
# include <iostream>
|
||||||
|
# include <cstdlib>
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* This source file contains all the implementations of the Design
|
* This source file contains all the implementations of the Design
|
||||||
|
|
|
||||||
|
|
@ -22,6 +22,7 @@
|
||||||
|
|
||||||
# include "netlist.h"
|
# include "netlist.h"
|
||||||
# include <cstring>
|
# include <cstring>
|
||||||
|
# include <cstdlib>
|
||||||
# include <sstream>
|
# include <sstream>
|
||||||
# include "ivl_assert.h"
|
# include "ivl_assert.h"
|
||||||
|
|
||||||
|
|
@ -218,7 +219,7 @@ map<perm_string,NetScope::param_expr_t>::iterator NetScope::find_parameter(perm_
|
||||||
if (idx != localparams.end())
|
if (idx != localparams.end())
|
||||||
return idx;
|
return idx;
|
||||||
|
|
||||||
return 0;
|
return (map<perm_string,param_expr_t>::iterator) 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
NetScope::TYPE NetScope::type() const
|
NetScope::TYPE NetScope::type() const
|
||||||
|
|
|
||||||
|
|
@ -143,7 +143,7 @@ void pform_end_discipline(const struct vlltype&loc)
|
||||||
{
|
{
|
||||||
// If the domain is not otherwise specified, then take it to
|
// If the domain is not otherwise specified, then take it to
|
||||||
// be continuous if potential or flow natures are given.
|
// be continuous if potential or flow natures are given.
|
||||||
if (discipline_domain == DD_NONE && discipline_potential||discipline_flow)
|
if (discipline_domain == DD_NONE && (discipline_potential||discipline_flow))
|
||||||
discipline_domain = DD_CONTINUOUS;
|
discipline_domain = DD_CONTINUOUS;
|
||||||
|
|
||||||
discipline_t*tmp = new discipline_t(discipline_name, discipline_domain,
|
discipline_t*tmp = new discipline_t(discipline_name, discipline_domain,
|
||||||
|
|
|
||||||
|
|
@ -16,12 +16,9 @@
|
||||||
# 59 Temple Place - Suite 330
|
# 59 Temple Place - Suite 330
|
||||||
# Boston, MA 02111-1307, USA
|
# Boston, MA 02111-1307, USA
|
||||||
#
|
#
|
||||||
#ident "$Id: Makefile.in,v 1.11 2004/02/10 19:25:01 steve Exp $"
|
|
||||||
#
|
|
||||||
#
|
|
||||||
SHELL = /bin/sh
|
SHELL = /bin/sh
|
||||||
|
|
||||||
VERSION = 0.0
|
VERSION = 0.9.devel
|
||||||
|
|
||||||
prefix = @prefix@
|
prefix = @prefix@
|
||||||
exec_prefix = @exec_prefix@
|
exec_prefix = @exec_prefix@
|
||||||
|
|
@ -44,6 +41,8 @@ LDFLAGS = @LDFLAGS@
|
||||||
|
|
||||||
all: dep null.tgt
|
all: dep null.tgt
|
||||||
|
|
||||||
|
check: all
|
||||||
|
|
||||||
dep:
|
dep:
|
||||||
mkdir dep
|
mkdir dep
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -16,12 +16,9 @@
|
||||||
# 59 Temple Place - Suite 330
|
# 59 Temple Place - Suite 330
|
||||||
# Boston, MA 02111-1307, USA
|
# Boston, MA 02111-1307, USA
|
||||||
#
|
#
|
||||||
#ident "$Id: Makefile.in,v 1.20 2007/02/06 05:07:32 steve Exp $"
|
|
||||||
#
|
|
||||||
#
|
|
||||||
SHELL = /bin/sh
|
SHELL = /bin/sh
|
||||||
|
|
||||||
VERSION = 0.0
|
VERSION = 0.9.devel
|
||||||
|
|
||||||
prefix = @prefix@
|
prefix = @prefix@
|
||||||
exec_prefix = @exec_prefix@
|
exec_prefix = @exec_prefix@
|
||||||
|
|
@ -44,6 +41,8 @@ LDFLAGS = @LDFLAGS@
|
||||||
|
|
||||||
all: dep stub.tgt
|
all: dep stub.tgt
|
||||||
|
|
||||||
|
check: all
|
||||||
|
|
||||||
dep:
|
dep:
|
||||||
mkdir dep
|
mkdir dep
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -288,7 +288,7 @@ void show_statement(ivl_statement_t net, unsigned ind)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case IVL_ST_DELAY:
|
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);
|
show_statement(ivl_stmt_sub_stmt(net), ind+2);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -57,10 +57,14 @@ static void draw_lpm_mux_ab(ivl_lpm_t net, const char*muxz)
|
||||||
get_number_immediate(d_rise), net);
|
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, "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", input[0]);
|
||||||
fprintf(vvp_out, ", %s", draw_input_from_net(ivl_lpm_data(net,1)));
|
fprintf(vvp_out, ", %s", input[1]);
|
||||||
fprintf(vvp_out, ", %s", draw_input_from_net(ivl_lpm_select(net)));
|
fprintf(vvp_out, ", %s", input[2]);
|
||||||
fprintf(vvp_out, ", C4<>;\n");
|
fprintf(vvp_out, ", C4<>;\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -25,6 +25,10 @@
|
||||||
# include <stdlib.h>
|
# include <stdlib.h>
|
||||||
# include <assert.h>
|
# include <assert.h>
|
||||||
|
|
||||||
|
#ifdef __MINGW32__ /* MinGW has inconsistent %p output. */
|
||||||
|
#define snprintf _snprintf
|
||||||
|
#endif
|
||||||
|
|
||||||
static const char* magic_sfuncs[] = {
|
static const char* magic_sfuncs[] = {
|
||||||
"$time",
|
"$time",
|
||||||
"$stime",
|
"$stime",
|
||||||
|
|
@ -52,9 +56,12 @@ static int is_fixed_memory_word(ivl_expr_t net)
|
||||||
|
|
||||||
sig = ivl_expr_signal(net);
|
sig = ivl_expr_signal(net);
|
||||||
|
|
||||||
if (ivl_signal_array_count(sig) == 1)
|
if (ivl_signal_dimensions(sig) == 0)
|
||||||
return 1;
|
return 1;
|
||||||
|
|
||||||
|
if (ivl_signal_type(sig) == IVL_SIT_REG)
|
||||||
|
return 0;
|
||||||
|
|
||||||
if (number_is_immediate(ivl_expr_oper1(net), 8*sizeof(unsigned)))
|
if (number_is_immediate(ivl_expr_oper1(net), 8*sizeof(unsigned)))
|
||||||
return 1;
|
return 1;
|
||||||
|
|
||||||
|
|
@ -69,9 +76,14 @@ static void draw_vpi_taskfunc_args(const char*call_string,
|
||||||
unsigned parm_count = tnet
|
unsigned parm_count = tnet
|
||||||
? ivl_stmt_parm_count(tnet)
|
? ivl_stmt_parm_count(tnet)
|
||||||
: ivl_expr_parms(fnet);
|
: ivl_expr_parms(fnet);
|
||||||
struct vector_info *vec = 0x0;
|
|
||||||
unsigned int vecs= 0;
|
struct args_info {
|
||||||
unsigned int veci= 0;
|
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;
|
ivl_parameter_t par;
|
||||||
|
|
||||||
|
|
@ -89,17 +101,56 @@ static void draw_vpi_taskfunc_args(const char*call_string,
|
||||||
with VPI handles of their own. Therefore, skip
|
with VPI handles of their own. Therefore, skip
|
||||||
them in the process of evaluating expressions. */
|
them in the process of evaluating expressions. */
|
||||||
case IVL_EX_NONE:
|
case IVL_EX_NONE:
|
||||||
|
args[idx].text = strdup("\" \"");
|
||||||
|
continue;
|
||||||
|
|
||||||
case IVL_EX_ARRAY:
|
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:
|
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:
|
case IVL_EX_EVENT:
|
||||||
|
snprintf(buffer, sizeof buffer, "E_%p", ivl_expr_event(expr));
|
||||||
|
args[idx].text = strdup(buffer);
|
||||||
|
continue;
|
||||||
case IVL_EX_SCOPE:
|
case IVL_EX_SCOPE:
|
||||||
|
snprintf(buffer, sizeof buffer, "S_%p", ivl_expr_scope(expr));
|
||||||
|
args[idx].text = strdup(buffer);
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
case IVL_EX_SFUNC:
|
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;
|
continue;
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case IVL_EX_SIGNAL:
|
case IVL_EX_SIGNAL:
|
||||||
|
|
@ -122,21 +173,47 @@ static void draw_vpi_taskfunc_args(const char*call_string,
|
||||||
} else if (ivl_expr_signed(expr) !=
|
} else if (ivl_expr_signed(expr) !=
|
||||||
ivl_signal_signed(ivl_expr_signal(expr))) {
|
ivl_signal_signed(ivl_expr_signal(expr))) {
|
||||||
break;
|
break;
|
||||||
} else if (! is_fixed_memory_word(expr)){
|
} else if (is_fixed_memory_word(expr)) {
|
||||||
break;
|
/* This is a word of a non-array, or a word
|
||||||
} else {
|
of a net array, so we can address the
|
||||||
/* Some array selects need to be evaluated. */
|
word directly. */
|
||||||
|
ivl_signal_t sig = ivl_expr_signal(expr);
|
||||||
|
unsigned use_word = 0;
|
||||||
ivl_expr_t word_ex = ivl_expr_oper1(expr);
|
ivl_expr_t word_ex = ivl_expr_oper1(expr);
|
||||||
if (word_ex && !number_is_immediate(word_ex,
|
if (word_ex) {
|
||||||
8*sizeof(unsigned))) {
|
/* Some array select have been evaluated. */
|
||||||
break;
|
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;
|
continue;
|
||||||
}
|
|
||||||
|
|
||||||
|
} else {
|
||||||
|
/* What's left, this is the work of a var
|
||||||
|
array. Create the right code to handle
|
||||||
|
it. */
|
||||||
|
ivl_signal_t sig = ivl_expr_signal(expr);
|
||||||
|
unsigned use_word = 0;
|
||||||
|
ivl_expr_t word_ex = ivl_expr_oper1(expr);
|
||||||
|
if (word_ex) {
|
||||||
|
/* Some array select have been evaluated. */
|
||||||
|
if (number_is_immediate(word_ex, 8*sizeof(unsigned))) {
|
||||||
|
use_word = get_number_immediate(word_ex);
|
||||||
|
word_ex = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (word_ex)
|
||||||
|
break;
|
||||||
|
|
||||||
case IVL_EX_MEMORY:
|
snprintf(buffer, sizeof buffer, "&A<v%p, %u>", sig, use_word);
|
||||||
if (!ivl_expr_oper1(expr)) {
|
args[idx].text = strdup(buffer);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -146,143 +223,43 @@ static void draw_vpi_taskfunc_args(const char*call_string,
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
vec = (struct vector_info *)
|
|
||||||
realloc(vec, (vecs+1)*sizeof(struct vector_info));
|
|
||||||
|
|
||||||
switch (ivl_expr_value(expr)) {
|
switch (ivl_expr_value(expr)) {
|
||||||
case IVL_VT_LOGIC:
|
case IVL_VT_LOGIC:
|
||||||
case IVL_VT_BOOL:
|
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;
|
break;
|
||||||
case IVL_VT_REAL:
|
case IVL_VT_REAL:
|
||||||
vec[vecs].base = draw_eval_real(expr);
|
args[idx].vec_flag = 1;
|
||||||
vec[vecs].wid = 0;
|
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;
|
break;
|
||||||
default:
|
default:
|
||||||
assert(0);
|
assert(0);
|
||||||
}
|
}
|
||||||
vecs++;
|
args[idx].text = strdup(buffer);
|
||||||
}
|
}
|
||||||
|
|
||||||
fprintf(vvp_out, "%s", call_string);
|
fprintf(vvp_out, "%s", call_string);
|
||||||
|
|
||||||
for (idx = 0 ; idx < parm_count ; idx += 1) {
|
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)) {
|
fprintf(vvp_out, ", %s", args[idx].text);
|
||||||
case IVL_EX_NONE:
|
free(args[idx].text);
|
||||||
fprintf(vvp_out, ", \" \"");
|
if (args[idx].vec_flag) {
|
||||||
continue;
|
if (args[idx].vec.wid > 0)
|
||||||
|
clr_vector(args[idx].vec);
|
||||||
case IVL_EX_ARRAY:
|
else
|
||||||
fprintf(vvp_out, ", v%p", ivl_expr_signal(expr));
|
clr_word(args[idx].vec.base);
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
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);
|
free(args);
|
||||||
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
|
|
||||||
fprintf(vvp_out, ";\n");
|
fprintf(vvp_out, ";\n");
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -138,8 +138,22 @@ static void eval_logic_into_integer(ivl_expr_t expr, unsigned ix)
|
||||||
|
|
||||||
case IVL_EX_SIGNAL: {
|
case IVL_EX_SIGNAL: {
|
||||||
ivl_signal_t sig = ivl_expr_signal(expr);
|
ivl_signal_t sig = ivl_expr_signal(expr);
|
||||||
|
|
||||||
unsigned word = 0;
|
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);
|
ivl_expr_t ixe = ivl_expr_oper1(expr);
|
||||||
if (number_is_immediate(ixe, 8*sizeof(unsigned long)))
|
if (number_is_immediate(ixe, 8*sizeof(unsigned long)))
|
||||||
word = get_number_immediate(ixe);
|
word = get_number_immediate(ixe);
|
||||||
|
|
@ -1894,28 +1908,23 @@ static void draw_signal_dest(ivl_expr_t exp, struct vector_info res,
|
||||||
|
|
||||||
/* If this is an access to an array, handle that by emitting a
|
/* If this is an access to an array, handle that by emitting a
|
||||||
load/av instruction. */
|
load/av instruction. */
|
||||||
if (ivl_signal_array_count(sig) > 1) {
|
if (ivl_signal_dimensions(sig) > 0) {
|
||||||
ivl_expr_t ix = ivl_expr_oper1(exp);
|
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. */
|
draw_eval_expr_into_integer(ix, 3);
|
||||||
fprintf(vvp_out, " %%ix/load 0, %lu;\n", immediate);
|
if (add_index < 0) {
|
||||||
fprintf(vvp_out, " %%load/avp0 %u, v%p, %u;\n",
|
fprintf(vvp_out, " %%load/av %u, v%p, %u;\n",
|
||||||
res.base, sig, swid);
|
res.base, sig, swid);
|
||||||
}
|
} else {
|
||||||
pad_expr_in_place(exp, res, swid);
|
assert(add_index == 0);
|
||||||
return;
|
|
||||||
|
/* 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);
|
||||||
/* The index is constant, so we can return to direct
|
return;
|
||||||
readout with the specific word selected. */
|
|
||||||
word = get_number_immediate(ix);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -2030,14 +2039,16 @@ static struct vector_info draw_select_signal(ivl_expr_t sube,
|
||||||
unsigned use_word = 0;
|
unsigned use_word = 0;
|
||||||
|
|
||||||
/* If this is an access to an array, try to get the index as a
|
/* 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
|
constant. If it is (and the array is not a reg array then
|
||||||
and we stay here. If it is not constant, then give up and
|
this reduces to a signal access and we stay here. If it is
|
||||||
do an array index in front of this part select. */
|
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);
|
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);
|
return draw_select_array(sube, bit_idx, bit_wid, wid);
|
||||||
|
|
||||||
/* The index is constant, so we can return to direct
|
/* The index is constant, so we can return to direct
|
||||||
|
|
|
||||||
|
|
@ -22,6 +22,10 @@
|
||||||
# include <stdlib.h>
|
# include <stdlib.h>
|
||||||
# include <assert.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)
|
static ivl_signal_t find_path_source_port(ivl_delaypath_t path)
|
||||||
{
|
{
|
||||||
int idx;
|
int idx;
|
||||||
|
|
|
||||||
|
|
@ -99,7 +99,7 @@ static void set_to_lvariable(ivl_lval_t lval,
|
||||||
if (ivl_lval_mux(lval))
|
if (ivl_lval_mux(lval))
|
||||||
part_off_ex = 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++;
|
unsigned skip_set = transient_id++;
|
||||||
|
|
||||||
/* There is a mux expression, so this must be a write to
|
/* 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. */
|
lookaside. */
|
||||||
save_signal_lookaside(bit, sig, use_word, 0);
|
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)) {
|
} else if (part_off>0 || ivl_lval_width(lval)!=ivl_signal_width(sig)) {
|
||||||
/* There is no mux expression, but a constant part
|
/* There is no mux expression, but a constant part
|
||||||
offset. Load that into index x0 and generate a
|
offset. Load that into index x0 and generate a
|
||||||
|
|
@ -145,14 +178,16 @@ static void set_to_lvariable(ivl_lval_t lval,
|
||||||
lookaside. */
|
lookaside. */
|
||||||
save_signal_lookaside(bit, sig, use_word, 0);
|
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
|
/* If the word index is a constant, then we can write
|
||||||
directly to the word and save the index calculation. */
|
directly to the word and save the index calculation. */
|
||||||
if (word_ix == 0) {
|
if (word_ix == 0) {
|
||||||
if (use_word < ivl_signal_array_count(sig)) {
|
if (use_word < ivl_signal_array_count(sig)) {
|
||||||
fprintf(vvp_out, " %%set/v v%p_%lu, %u, %u;\n",
|
fprintf(vvp_out, " %%ix/load 1, 0;\n");
|
||||||
sig, use_word, bit, wid);
|
fprintf(vvp_out, " %%ix/load 3, %lu;\n", use_word);
|
||||||
|
fprintf(vvp_out, " %%set/av v%p, %u, %u;\n",
|
||||||
|
sig, bit, wid);
|
||||||
} else {
|
} else {
|
||||||
fprintf(vvp_out, " ; %%set/v v%p_%lu, %u, %u "
|
fprintf(vvp_out, " ; %%set/v v%p_%lu, %u, %u "
|
||||||
"OUT OF BOUNDS\n", sig, use_word, bit, wid);
|
"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,
|
static void assign_to_array_word(ivl_signal_t lsig, ivl_expr_t word_ix,
|
||||||
unsigned bit, unsigned delay, ivl_expr_t dexp,
|
unsigned bit, unsigned delay, ivl_expr_t dexp,
|
||||||
unsigned width)
|
ivl_expr_t part_off_ex, unsigned width)
|
||||||
{
|
{
|
||||||
unsigned skip_assign = transient_id++;
|
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) {
|
if (dexp == 0) {
|
||||||
/* Constant delay... */
|
/* Constant delay... */
|
||||||
/* Calculate array word index into index register 3 */
|
if (number_is_immediate(word_ix, 64)) {
|
||||||
draw_eval_expr_into_integer(word_ix, 3);
|
fprintf(vvp_out, " %%ix/load 3, %lu; address\n",
|
||||||
/* Skip assignment if word expression is not defined. */
|
get_number_immediate(word_ix));
|
||||||
fprintf(vvp_out, " %%jmp/1 t_%u, 4;\n", skip_assign);
|
} 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 */
|
/* Store expression width into index word 0 */
|
||||||
fprintf(vvp_out, " %%ix/load 0, %u; // word width\n", width);
|
fprintf(vvp_out, " %%ix/load 0, %u; word width\n", width);
|
||||||
/* Store constant (0) word part select into index 1 */
|
if (part_off_ex) {
|
||||||
fprintf(vvp_out, " %%ix/load 1, 0;\n");
|
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,
|
fprintf(vvp_out, " %%assign/av v%p, %u, %u;\n", lsig,
|
||||||
delay, bit);
|
delay, bit);
|
||||||
fprintf(vvp_out, "t_%u ;\n", skip_assign);
|
|
||||||
} else {
|
} else {
|
||||||
/* Calculated delay... */
|
/* Calculated delay... */
|
||||||
int delay_index = allocate_word();
|
int delay_index = allocate_word();
|
||||||
draw_eval_expr_into_integer(dexp, delay_index);
|
draw_eval_expr_into_integer(dexp, delay_index);
|
||||||
/* Calculate array word index into index register 3 */
|
if (number_is_immediate(word_ix, 64)) {
|
||||||
draw_eval_expr_into_integer(word_ix, 3);
|
fprintf(vvp_out, " %%ix/load 3, %lu; address\n",
|
||||||
/* Skip assignment if word expression is not defined. */
|
get_number_immediate(word_ix));
|
||||||
fprintf(vvp_out, " %%jmp/1 t_%u, 4;\n", skip_assign);
|
} 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 */
|
/* Store expression width into index word 0 */
|
||||||
fprintf(vvp_out, " %%ix/load 0, %u; // word width\n", width);
|
fprintf(vvp_out, " %%ix/load 0, %u; word width\n", width);
|
||||||
/* Store constant (0) word part select into index 1 */
|
if (part_off_ex) {
|
||||||
fprintf(vvp_out, " %%ix/load 1, 0;\n");
|
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,
|
fprintf(vvp_out, " %%assign/av/d v%p, %d, %u;\n", lsig,
|
||||||
delay_index, bit);
|
delay_index, bit);
|
||||||
fprintf(vvp_out, "t_%u ;\n", skip_assign);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fprintf(vvp_out, "t_%u ;\n", skip_assign);
|
||||||
|
|
||||||
clear_expression_lookaside();
|
clear_expression_lookaside();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -235,16 +296,12 @@ static void assign_to_lvector(ivl_lval_t lval, unsigned bit,
|
||||||
unsigned part_off = 0;
|
unsigned part_off = 0;
|
||||||
|
|
||||||
ivl_expr_t word_ix = ivl_lval_idx(lval);
|
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) {
|
if (ivl_signal_array_count(sig) > 1) {
|
||||||
assert(word_ix);
|
assert(word_ix);
|
||||||
if (! number_is_immediate(word_ix, 8*sizeof(use_word))) {
|
assign_to_array_word(sig, word_ix, bit, delay, dexp, part_off_ex, width);
|
||||||
assign_to_array_word(sig, word_ix, bit, delay, dexp, width);
|
return;
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
use_word = get_number_immediate(word_ix);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (part_off_ex == 0) {
|
if (part_off_ex == 0) {
|
||||||
|
|
|
||||||
|
|
@ -27,6 +27,10 @@
|
||||||
# include <inttypes.h>
|
# include <inttypes.h>
|
||||||
# include <assert.h>
|
# include <assert.h>
|
||||||
|
|
||||||
|
#ifdef __MINGW32__ /* MinGW has inconsistent %p output. */
|
||||||
|
#define snprintf _snprintf
|
||||||
|
#endif
|
||||||
|
|
||||||
struct vvp_nexus_data {
|
struct vvp_nexus_data {
|
||||||
/* draw_net_input uses this */
|
/* draw_net_input uses this */
|
||||||
const char*net_input;
|
const char*net_input;
|
||||||
|
|
@ -615,6 +619,12 @@ static char* draw_net_input_drive(ivl_nexus_t nex, ivl_nexus_ptr_t nptr)
|
||||||
/* Input is a .var. This device may be a non-zero pin
|
/* Input is a .var. This device may be a non-zero pin
|
||||||
because it may be an array of reg vectors. */
|
because it may be an array of reg vectors. */
|
||||||
snprintf(tmp, sizeof tmp, "v%p_%u", sptr, nptr_pin);
|
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);
|
return strdup(tmp);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -988,6 +998,8 @@ const char*draw_input_from_net(ivl_nexus_t nex)
|
||||||
ivl_signal_t sig = signal_of_nexus(nex, &word);
|
ivl_signal_t sig = signal_of_nexus(nex, &word);
|
||||||
if (sig == 0)
|
if (sig == 0)
|
||||||
return draw_net_input(nex);
|
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);
|
snprintf(result, sizeof result, "v%p_%u", sig, word);
|
||||||
return result;
|
return result;
|
||||||
|
|
@ -1759,7 +1771,11 @@ static void draw_lpm_add(ivl_lpm_t net)
|
||||||
type = "pow.s";
|
type = "pow.s";
|
||||||
if (width > 8*sizeof(long)) {
|
if (width > 8*sizeof(long)) {
|
||||||
fprintf(stderr, "%s:%u: sorry (vvp-tgt): Signed power "
|
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",
|
"result must be no more than %zu bits.\n",
|
||||||
|
#endif
|
||||||
ivl_lpm_file(net), ivl_lpm_lineno(net),
|
ivl_lpm_file(net), ivl_lpm_lineno(net),
|
||||||
8*sizeof(long));
|
8*sizeof(long));
|
||||||
exit(1);
|
exit(1);
|
||||||
|
|
|
||||||
|
|
@ -16,12 +16,9 @@
|
||||||
# 59 Temple Place - Suite 330
|
# 59 Temple Place - Suite 330
|
||||||
# Boston, MA 02111-1307, USA
|
# Boston, MA 02111-1307, USA
|
||||||
#
|
#
|
||||||
#ident "$Id: Makefile.in,v 1.61 2007/02/06 05:07:32 steve Exp $"
|
|
||||||
#
|
|
||||||
#
|
|
||||||
SHELL = /bin/sh
|
SHELL = /bin/sh
|
||||||
|
|
||||||
VERSION = 0.0
|
VERSION = 0.9.devel
|
||||||
|
|
||||||
prefix = @prefix@
|
prefix = @prefix@
|
||||||
exec_prefix = @exec_prefix@
|
exec_prefix = @exec_prefix@
|
||||||
|
|
@ -48,6 +45,8 @@ LDFLAGS = @LDFLAGS@
|
||||||
|
|
||||||
all: dep system.vpi va_math.vpi $(ALL32)
|
all: dep system.vpi va_math.vpi $(ALL32)
|
||||||
|
|
||||||
|
check: all
|
||||||
|
|
||||||
dep:
|
dep:
|
||||||
mkdir dep
|
mkdir dep
|
||||||
|
|
||||||
|
|
@ -75,7 +74,7 @@ V = va_math.o
|
||||||
LIBS = @LIBS@
|
LIBS = @LIBS@
|
||||||
SYSTEM_VPI_LDFLAGS = $(LIBS)
|
SYSTEM_VPI_LDFLAGS = $(LIBS)
|
||||||
VA_MATH_LDFLAGS =
|
VA_MATH_LDFLAGS =
|
||||||
ifeq (@MING32@,yes)
|
ifeq (@MINGW32@,yes)
|
||||||
SYSTEM_VPI_LDFLAGS += @EXTRALIBS@
|
SYSTEM_VPI_LDFLAGS += @EXTRALIBS@
|
||||||
VA_MATH_LDFLAGS += @EXTRALIBS@
|
VA_MATH_LDFLAGS += @EXTRALIBS@
|
||||||
endif
|
endif
|
||||||
|
|
|
||||||
|
|
@ -1122,6 +1122,7 @@ static PLI_INT32 sys_monitor_calltf(PLI_BYTE8*name)
|
||||||
case vpiReg:
|
case vpiReg:
|
||||||
case vpiIntegerVar:
|
case vpiIntegerVar:
|
||||||
case vpiRealVar:
|
case vpiRealVar:
|
||||||
|
case vpiMemoryWord:
|
||||||
/* Monitoring reg and net values involves setting
|
/* Monitoring reg and net values involves setting
|
||||||
a callback for value changes. Pass the storage
|
a callback for value changes. Pass the storage
|
||||||
pointer for the callback itself as user_data so
|
pointer for the callback itself as user_data so
|
||||||
|
|
|
||||||
|
|
@ -48,6 +48,93 @@ static PLI_INT32 size_32(PLI_BYTE8* ud)
|
||||||
return 32;
|
return 32;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Routine to finish the simulation and return a value to the
|
||||||
|
* calling environment.
|
||||||
|
*/
|
||||||
|
static PLI_INT32 finish_and_return_compiletf(PLI_BYTE8* ud)
|
||||||
|
{
|
||||||
|
vpiHandle callh = vpi_handle(vpiSysTfCall, 0);
|
||||||
|
vpiHandle argv = vpi_iterate(vpiArgument, callh);
|
||||||
|
vpiHandle arg;
|
||||||
|
(void) ud; /* Not used! */
|
||||||
|
|
||||||
|
/* We must have at least one argument. */
|
||||||
|
if (argv == 0) {
|
||||||
|
vpi_printf("ERROR: %s line %d: ", vpi_get_str(vpiFile, callh),
|
||||||
|
(int)vpi_get(vpiLineNo, callh));
|
||||||
|
vpi_printf("$finish_and_return requires an argument.\n");
|
||||||
|
vpi_control(vpiFinish, 1);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* This must be a numeric argument. */
|
||||||
|
arg = vpi_scan(argv);
|
||||||
|
switch(vpi_get(vpiType, arg)) {
|
||||||
|
case vpiConstant:
|
||||||
|
case vpiParameter:
|
||||||
|
/* String constants are invalid numeric values. */
|
||||||
|
if (vpi_get(vpiConstType, arg) == vpiStringConst) {
|
||||||
|
vpi_printf("ERROR: %s line %d: ", vpi_get_str(vpiFile, callh),
|
||||||
|
(int)vpi_get(vpiLineNo, callh));
|
||||||
|
vpi_printf("The argument to $finish_and_return must be numeric.\n");
|
||||||
|
vpi_control(vpiFinish, 1);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case vpiIntegerVar:
|
||||||
|
case vpiMemoryWord:
|
||||||
|
case vpiNet:
|
||||||
|
case vpiRealVar:
|
||||||
|
case vpiReg:
|
||||||
|
case vpiTimeVar:
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
vpi_printf("ERROR: %s line %d: ", vpi_get_str(vpiFile, callh),
|
||||||
|
(int)vpi_get(vpiLineNo, callh));
|
||||||
|
vpi_printf("The argument to $finish_and_return must be numeric.\n");
|
||||||
|
vpi_control(vpiFinish, 1);
|
||||||
|
return 0;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* We can only have one argument. */
|
||||||
|
if (vpi_scan(argv) != 0) {
|
||||||
|
vpi_printf("ERROR: %s line %d: ", vpi_get_str(vpiFile, callh),
|
||||||
|
(int)vpi_get(vpiLineNo, callh));
|
||||||
|
vpi_printf("$finish_and_return takes a single argument.\n");
|
||||||
|
vpi_control(vpiFinish, 1);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static PLI_INT32 finish_and_return_calltf(PLI_BYTE8* ud)
|
||||||
|
{
|
||||||
|
vpiHandle callh = vpi_handle(vpiSysTfCall, 0);
|
||||||
|
vpiHandle argv = vpi_iterate(vpiArgument, callh);
|
||||||
|
vpiHandle arg;
|
||||||
|
s_vpi_value val;
|
||||||
|
(void) ud; /* 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.
|
* Register the function with Verilog.
|
||||||
*/
|
*/
|
||||||
|
|
@ -55,7 +142,6 @@ void sys_special_register(void)
|
||||||
{
|
{
|
||||||
s_vpi_systf_data tf_data;
|
s_vpi_systf_data tf_data;
|
||||||
|
|
||||||
/* Register the single argument functions. */
|
|
||||||
tf_data.type = vpiSysFunc;
|
tf_data.type = vpiSysFunc;
|
||||||
tf_data.sysfunctype = vpiIntFunc;
|
tf_data.sysfunctype = vpiIntFunc;
|
||||||
tf_data.calltf = vvp_cpu_wordsize_calltf;
|
tf_data.calltf = vvp_cpu_wordsize_calltf;
|
||||||
|
|
@ -64,4 +150,12 @@ void sys_special_register(void)
|
||||||
tf_data.tfname = "$vvp_cpu_wordsize";
|
tf_data.tfname = "$vvp_cpu_wordsize";
|
||||||
tf_data.user_data = 0;
|
tf_data.user_data = 0;
|
||||||
vpi_register_systf(&tf_data);
|
vpi_register_systf(&tf_data);
|
||||||
|
|
||||||
|
tf_data.type = vpiSysTask;
|
||||||
|
tf_data.calltf = finish_and_return_calltf;
|
||||||
|
tf_data.compiletf = finish_and_return_compiletf;
|
||||||
|
tf_data.sizetf = 0;
|
||||||
|
tf_data.tfname = "$finish_and_return";
|
||||||
|
tf_data.user_data = 0;
|
||||||
|
vpi_register_systf(&tf_data);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -109,7 +109,6 @@ static PLI_INT32 sys_readmem_calltf(PLI_BYTE8*name)
|
||||||
FILE*file;
|
FILE*file;
|
||||||
unsigned addr;
|
unsigned addr;
|
||||||
s_vpi_value value;
|
s_vpi_value value;
|
||||||
vpiHandle words;
|
|
||||||
vpiHandle sys = vpi_handle(vpiSysTfCall, 0);
|
vpiHandle sys = vpi_handle(vpiSysTfCall, 0);
|
||||||
vpiHandle argv = vpi_iterate(vpiArgument, sys);
|
vpiHandle argv = vpi_iterate(vpiArgument, sys);
|
||||||
vpiHandle item = vpi_scan(argv);
|
vpiHandle item = vpi_scan(argv);
|
||||||
|
|
@ -283,11 +282,7 @@ static PLI_INT32 sys_readmem_calltf(PLI_BYTE8*name)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
item = vpi_handle_by_index(mitem,min_addr);
|
||||||
words = vpi_iterate(vpiMemoryWord, mitem);
|
|
||||||
assert(words);
|
|
||||||
|
|
||||||
item = vpi_scan(words);
|
|
||||||
wwid = vpi_get(vpiSize, item);
|
wwid = vpi_get(vpiSize, item);
|
||||||
|
|
||||||
/* variable that will be uses by the lexer to pass values
|
/* 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:
|
bailout:
|
||||||
free(value.value.vector);
|
free(value.value.vector);
|
||||||
|
|
||||||
if (item)
|
|
||||||
vpi_free_object(words);
|
|
||||||
free(path);
|
free(path);
|
||||||
fclose(file);
|
fclose(file);
|
||||||
return 0;
|
return 0;
|
||||||
|
|
|
||||||
|
|
@ -563,6 +563,7 @@ extern DLLEXPORT void (*vlog_startup_routines[])();
|
||||||
/* Format a scalar a la %v. The str points to a 4byte character
|
/* Format a scalar a la %v. The str points to a 4byte character
|
||||||
buffer. The value must be a vpiStrengthVal. */
|
buffer. The value must be a vpiStrengthVal. */
|
||||||
extern void vpip_format_strength(char*str, s_vpi_value*value, unsigned bit);
|
extern void vpip_format_strength(char*str, s_vpi_value*value, unsigned bit);
|
||||||
|
extern void vpip_set_return_value(int value);
|
||||||
|
|
||||||
EXTERN_C_END
|
EXTERN_C_END
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -43,6 +43,8 @@ INSTALL_DATA = @INSTALL_DATA@
|
||||||
RANLIB = @RANLIB@
|
RANLIB = @RANLIB@
|
||||||
LEX = @LEX@
|
LEX = @LEX@
|
||||||
YACC = @YACC@
|
YACC = @YACC@
|
||||||
|
MAN = @MAN@
|
||||||
|
PS2PDF = @PS2PDF@
|
||||||
|
|
||||||
CPPFLAGS = @ident_support@ -I. -I.. -I $(srcdir) -I$(srcdir)/.. @CPPFLAGS@ @DEFS@
|
CPPFLAGS = @ident_support@ -I. -I.. -I $(srcdir) -I$(srcdir)/.. @CPPFLAGS@ @DEFS@
|
||||||
CXXFLAGS = -Wall @CXXFLAGS@
|
CXXFLAGS = -Wall @CXXFLAGS@
|
||||||
|
|
@ -70,14 +72,14 @@ check: all
|
||||||
|
|
||||||
V = vpi_modules.o vpi_callback.o vpi_const.o vpi_event.o vpi_iter.o vpi_mcd.o \
|
V = vpi_modules.o vpi_callback.o vpi_const.o vpi_event.o vpi_iter.o vpi_mcd.o \
|
||||||
vpi_priv.o vpi_scope.o vpi_real.o vpi_signal.o vpi_tasks.o vpi_time.o \
|
vpi_priv.o vpi_scope.o vpi_real.o vpi_signal.o vpi_tasks.o vpi_time.o \
|
||||||
vpi_memory.o vpi_vthr_vector.o vpip_bin.o vpip_hex.o vpip_oct.o \
|
vpi_vthr_vector.o vpip_bin.o vpip_hex.o vpip_oct.o \
|
||||||
vpip_to_dec.o vpip_format.o vvp_vpi.o
|
vpip_to_dec.o vpip_format.o vvp_vpi.o
|
||||||
|
|
||||||
O = main.o parse.o parse_misc.o lexor.o arith.o array.o bufif.o compile.o \
|
O = main.o parse.o parse_misc.o lexor.o arith.o array.o bufif.o compile.o \
|
||||||
concat.o \
|
concat.o \
|
||||||
dff.o extend.o npmos.o part.o reduce.o resolv.o sfunc.o stop.o symbols.o \
|
dff.o extend.o npmos.o part.o reduce.o resolv.o sfunc.o stop.o symbols.o \
|
||||||
ufunc.o codes.o \
|
ufunc.o codes.o \
|
||||||
vthread.o schedule.o statistics.o tables.o udp.o vvp_net.o memory.o \
|
vthread.o schedule.o statistics.o tables.o udp.o vvp_net.o \
|
||||||
event.o logic.o delay.o words.o $V
|
event.o logic.o delay.o words.o $V
|
||||||
|
|
||||||
ifeq (@WIN32@,yes)
|
ifeq (@WIN32@,yes)
|
||||||
|
|
@ -133,12 +135,20 @@ lexor.cc: $(srcdir)/lexor.lex
|
||||||
$(LEX) -s -olexor.cc $(srcdir)/lexor.lex
|
$(LEX) -s -olexor.cc $(srcdir)/lexor.lex
|
||||||
|
|
||||||
vvp.pdf: $(srcdir)/vvp.man
|
vvp.pdf: $(srcdir)/vvp.man
|
||||||
man -t $(srcdir)/vvp.man | ps2pdf - vvp.pdf
|
$(MAN) -t $(srcdir)/vvp.man | $(PS2PDF) - vvp.pdf
|
||||||
|
|
||||||
ifeq (@MING32@,yes)
|
ifeq (@MINGW32@,yes)
|
||||||
|
ifeq ($(MAN),none)
|
||||||
|
INSTALL_DOC = $(mandir)/man1/vvp.1
|
||||||
|
else
|
||||||
|
ifeq ($(PS2PDF),none)
|
||||||
|
INSTALL_DOC = $(mandir)/man1/vvp.1
|
||||||
|
else
|
||||||
INSTALL_DOC = $(prefix)/vvp.pdf $(mandir)/man1/vvp.1
|
INSTALL_DOC = $(prefix)/vvp.pdf $(mandir)/man1/vvp.1
|
||||||
INSTALL_DOCDIR = $(mandir)/man1
|
|
||||||
all: vvp.pdf
|
all: vvp.pdf
|
||||||
|
endif
|
||||||
|
endif
|
||||||
|
INSTALL_DOCDIR = $(mandir)/man1
|
||||||
else
|
else
|
||||||
INSTALL_DOC = $(mandir)/man1/vvp.1
|
INSTALL_DOC = $(mandir)/man1/vvp.1
|
||||||
INSTALL_DOCDIR = $(mandir)/man1
|
INSTALL_DOCDIR = $(mandir)/man1
|
||||||
|
|
|
||||||
476
vvp/array.cc
476
vvp/array.cc
|
|
@ -35,7 +35,7 @@ static symbol_table_t array_table =0;
|
||||||
class vvp_fun_arrayport;
|
class vvp_fun_arrayport;
|
||||||
static void array_attach_port(vvp_array_t, vvp_fun_arrayport*);
|
static void array_attach_port(vvp_array_t, vvp_fun_arrayport*);
|
||||||
|
|
||||||
vvp_array_t array_find(char*label)
|
vvp_array_t array_find(const char*label)
|
||||||
{
|
{
|
||||||
if (array_table == 0)
|
if (array_table == 0)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
@ -55,9 +55,15 @@ struct __vpiArray {
|
||||||
unsigned array_count;
|
unsigned array_count;
|
||||||
struct __vpiDecConst first_addr;
|
struct __vpiDecConst first_addr;
|
||||||
struct __vpiDecConst last_addr;
|
struct __vpiDecConst last_addr;
|
||||||
vpiHandle*words;
|
// If this is a net array, nets lists the handles.
|
||||||
|
vpiHandle*nets;
|
||||||
|
// If this is a var array, then these are used instead of nets.
|
||||||
|
vvp_vector4_t *vals;
|
||||||
|
unsigned vals_width;
|
||||||
|
struct __vpiArrayWord*vals_words;
|
||||||
|
|
||||||
class vvp_fun_arrayport*ports_;
|
class vvp_fun_arrayport*ports_;
|
||||||
|
struct __vpiCallback *vpi_callbacks;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct __vpiArrayIterator {
|
struct __vpiArrayIterator {
|
||||||
|
|
@ -72,6 +78,36 @@ struct __vpiArrayIndex {
|
||||||
unsigned done;
|
unsigned done;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct __vpiArrayVthrA {
|
||||||
|
struct __vpiHandle base;
|
||||||
|
struct __vpiArray*array;
|
||||||
|
unsigned address;
|
||||||
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The vpiArrayWord is magic. It is used as the handle to return when
|
||||||
|
* vpi code tries to index or scan an array of variable words. The
|
||||||
|
* array word handle contains no actual data. It is just a hook for
|
||||||
|
* the vpi methods and to point to the parent.
|
||||||
|
*
|
||||||
|
* How the point to the parent works is tricky. The vpiArrayWord
|
||||||
|
* objects for an array are themselves allocated as an array. All the
|
||||||
|
* ArrayWord objects in the array have a word0 that points to the base
|
||||||
|
* of the array. Thus, the position into the array (and the index into
|
||||||
|
* the memory) is calculated by subtracting word0 from the ArrayWord
|
||||||
|
* pointer.
|
||||||
|
*
|
||||||
|
* To then get to the parent, use word0[-1].parent.
|
||||||
|
*/
|
||||||
|
struct __vpiArrayWord {
|
||||||
|
struct __vpiHandle base;
|
||||||
|
union {
|
||||||
|
struct __vpiArray*parent;
|
||||||
|
struct __vpiArrayWord*word0;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
static int vpi_array_get(int code, vpiHandle ref);
|
static int vpi_array_get(int code, vpiHandle ref);
|
||||||
static char*vpi_array_get_str(int code, vpiHandle ref);
|
static char*vpi_array_get_str(int code, vpiHandle ref);
|
||||||
static vpiHandle vpi_array_get_handle(int code, vpiHandle ref);
|
static vpiHandle vpi_array_get_handle(int code, vpiHandle ref);
|
||||||
|
|
@ -84,6 +120,14 @@ static int array_iterator_free_object(vpiHandle ref);
|
||||||
static vpiHandle array_index_scan(vpiHandle ref, int);
|
static vpiHandle array_index_scan(vpiHandle ref, int);
|
||||||
static int array_index_free_object(vpiHandle ref);
|
static int array_index_free_object(vpiHandle ref);
|
||||||
|
|
||||||
|
static int vpi_array_var_word_get(int code, vpiHandle);
|
||||||
|
static void vpi_array_var_word_get_value(vpiHandle, p_vpi_value);
|
||||||
|
static vpiHandle vpi_array_var_word_put_value(vpiHandle, p_vpi_value, int);
|
||||||
|
|
||||||
|
static int vpi_array_vthr_A_get(int code, vpiHandle);
|
||||||
|
static void vpi_array_vthr_A_get_value(vpiHandle, p_vpi_value);
|
||||||
|
static vpiHandle vpi_array_vthr_A_put_value(vpiHandle, p_vpi_value, int);
|
||||||
|
|
||||||
static const struct __vpirt vpip_arraymem_rt = {
|
static const struct __vpirt vpip_arraymem_rt = {
|
||||||
vpiMemory,
|
vpiMemory,
|
||||||
vpi_array_get,
|
vpi_array_get,
|
||||||
|
|
@ -122,9 +166,78 @@ static const struct __vpirt vpip_array_index_rt = {
|
||||||
array_index_free_object
|
array_index_free_object
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static const struct __vpirt vpip_array_var_word_rt = {
|
||||||
|
vpiMemoryWord,
|
||||||
|
&vpi_array_var_word_get,
|
||||||
|
0,
|
||||||
|
&vpi_array_var_word_get_value,
|
||||||
|
&vpi_array_var_word_put_value,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
0
|
||||||
|
};
|
||||||
|
|
||||||
|
static const struct __vpirt vpip_array_vthr_A_rt = {
|
||||||
|
vpiMemoryWord,
|
||||||
|
&vpi_array_vthr_A_get,
|
||||||
|
0,
|
||||||
|
&vpi_array_vthr_A_get_value,
|
||||||
|
&vpi_array_vthr_A_put_value,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
0
|
||||||
|
};
|
||||||
|
|
||||||
# define ARRAY_HANDLE(ref) (assert(ref->vpi_type->type_code==vpiMemory), \
|
# define ARRAY_HANDLE(ref) (assert(ref->vpi_type->type_code==vpiMemory), \
|
||||||
(struct __vpiArray*)ref)
|
(struct __vpiArray*)ref)
|
||||||
|
|
||||||
|
static struct __vpiArrayWord* array_var_word_from_handle(vpiHandle ref)
|
||||||
|
{
|
||||||
|
if (ref == 0)
|
||||||
|
return 0;
|
||||||
|
if (ref->vpi_type != &vpip_array_var_word_rt)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
return (struct __vpiArrayWord*) ref;
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct __vpiArrayVthrA* array_vthr_a_from_handle(vpiHandle ref)
|
||||||
|
{
|
||||||
|
if (ref == 0)
|
||||||
|
return 0;
|
||||||
|
if (ref->vpi_type != &vpip_array_vthr_A_rt)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
return (struct __vpiArrayVthrA*) ref;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void array_make_vals_words(struct __vpiArray*parent)
|
||||||
|
{
|
||||||
|
assert(parent->vals_words == 0);
|
||||||
|
parent->vals_words = new struct __vpiArrayWord[parent->array_count + 1];
|
||||||
|
|
||||||
|
// Make word[-1] point to the parent.
|
||||||
|
parent->vals_words->parent = parent;
|
||||||
|
// Now point to word-0
|
||||||
|
parent->vals_words += 1;
|
||||||
|
|
||||||
|
struct __vpiArrayWord*words = parent->vals_words;
|
||||||
|
for (unsigned idx = 0 ; idx < parent->array_count ; idx += 1) {
|
||||||
|
words[idx].base.vpi_type = &vpip_array_var_word_rt;
|
||||||
|
words[idx].word0 = words;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static unsigned decode_array_word_pointer(struct __vpiArrayWord*word,
|
||||||
|
struct __vpiArray*&parent)
|
||||||
|
{
|
||||||
|
struct __vpiArrayWord*word0 = word->word0;
|
||||||
|
parent = (word0 - 1) -> parent;
|
||||||
|
return word - word0;
|
||||||
|
}
|
||||||
|
|
||||||
static int vpi_array_get(int code, vpiHandle ref)
|
static int vpi_array_get(int code, vpiHandle ref)
|
||||||
{
|
{
|
||||||
struct __vpiArray*obj = ARRAY_HANDLE(ref);
|
struct __vpiArray*obj = ARRAY_HANDLE(ref);
|
||||||
|
|
@ -205,7 +318,56 @@ static vpiHandle vpi_array_index(vpiHandle ref, int index)
|
||||||
if (index < 0)
|
if (index < 0)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
return obj->words[index];
|
if (obj->nets != 0) {
|
||||||
|
return obj->nets[index];
|
||||||
|
}
|
||||||
|
|
||||||
|
if (obj->vals_words == 0)
|
||||||
|
array_make_vals_words(obj);
|
||||||
|
|
||||||
|
return &(obj->vals_words[index].base);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int vpi_array_var_word_get(int code, vpiHandle ref)
|
||||||
|
{
|
||||||
|
struct __vpiArrayWord*obj = array_var_word_from_handle(ref);
|
||||||
|
struct __vpiArray*parent;
|
||||||
|
|
||||||
|
assert(obj);
|
||||||
|
decode_array_word_pointer(obj, parent);
|
||||||
|
|
||||||
|
switch (code) {
|
||||||
|
case vpiSize:
|
||||||
|
return (int) parent->vals_width;
|
||||||
|
|
||||||
|
default:
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void vpi_array_var_word_get_value(vpiHandle ref, p_vpi_value value)
|
||||||
|
{
|
||||||
|
struct __vpiArrayWord*obj = array_var_word_from_handle(ref);
|
||||||
|
struct __vpiArray*parent;
|
||||||
|
|
||||||
|
assert(obj);
|
||||||
|
unsigned index = decode_array_word_pointer(obj, parent);
|
||||||
|
|
||||||
|
vpip_vec4_get_value(parent->vals[index], parent->vals_width,
|
||||||
|
false, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
static vpiHandle vpi_array_var_word_put_value(vpiHandle ref, p_vpi_value vp, int flags)
|
||||||
|
{
|
||||||
|
struct __vpiArrayWord*obj = array_var_word_from_handle(ref);
|
||||||
|
struct __vpiArray*parent;
|
||||||
|
|
||||||
|
assert(obj);
|
||||||
|
unsigned index = decode_array_word_pointer(obj, parent);
|
||||||
|
|
||||||
|
vvp_vector4_t val = vec4_from_vpi_value(vp, parent->vals_width);
|
||||||
|
array_set_word(parent, index, 0, val);
|
||||||
|
return ref;
|
||||||
}
|
}
|
||||||
|
|
||||||
# define ARRAY_ITERATOR(ref) (assert(ref->vpi_type->type_code==vpiIterator), \
|
# define ARRAY_ITERATOR(ref) (assert(ref->vpi_type->type_code==vpiIterator), \
|
||||||
|
|
@ -220,9 +382,18 @@ static vpiHandle array_iterator_scan(vpiHandle ref, int)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
vpiHandle res = obj->array->words[obj->next];
|
unsigned use_index = obj->next;
|
||||||
obj->next += 1;
|
obj->next += 1;
|
||||||
return res;
|
|
||||||
|
if (obj->array->nets)
|
||||||
|
return obj->array->nets[obj->next];
|
||||||
|
|
||||||
|
assert(obj->array->vals);
|
||||||
|
|
||||||
|
if (obj->array->vals_words == 0)
|
||||||
|
array_make_vals_words(obj->array);
|
||||||
|
|
||||||
|
return &(obj->array->vals_words[use_index].base);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int array_iterator_free_object(vpiHandle ref)
|
static int array_iterator_free_object(vpiHandle ref)
|
||||||
|
|
@ -271,6 +442,56 @@ static int array_index_free_object(vpiHandle ref)
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int vpi_array_vthr_A_get(int code, vpiHandle ref)
|
||||||
|
{
|
||||||
|
struct __vpiArrayVthrA*obj = array_vthr_a_from_handle(ref);
|
||||||
|
assert(obj);
|
||||||
|
struct __vpiArray*parent = obj->array;
|
||||||
|
|
||||||
|
switch (code) {
|
||||||
|
case vpiLineNo:
|
||||||
|
return 0; // Not implemented for now!
|
||||||
|
|
||||||
|
case vpiSize:
|
||||||
|
assert(parent->vals);
|
||||||
|
return parent->vals_width;
|
||||||
|
|
||||||
|
default:
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
static void vpi_array_vthr_A_get_value(vpiHandle ref, p_vpi_value value)
|
||||||
|
{
|
||||||
|
struct __vpiArrayVthrA*obj = array_vthr_a_from_handle(ref);
|
||||||
|
assert(obj);
|
||||||
|
struct __vpiArray*parent = obj->array;
|
||||||
|
|
||||||
|
assert(parent);
|
||||||
|
assert(parent->vals);
|
||||||
|
assert(obj->address < parent->array_count);
|
||||||
|
|
||||||
|
vpip_vec4_get_value(parent->vals[obj->address],
|
||||||
|
parent->vals_width, false, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
static vpiHandle vpi_array_vthr_A_put_value(vpiHandle ref, p_vpi_value vp, int)
|
||||||
|
{
|
||||||
|
struct __vpiArrayVthrA*obj = array_vthr_a_from_handle(ref);
|
||||||
|
assert(obj);
|
||||||
|
struct __vpiArray*parent = obj->array;
|
||||||
|
|
||||||
|
unsigned index = obj->address;
|
||||||
|
|
||||||
|
assert(parent);
|
||||||
|
assert(obj->address < parent->array_count);
|
||||||
|
|
||||||
|
vvp_vector4_t val = vec4_from_vpi_value(vp, parent->vals_width);
|
||||||
|
array_set_word(parent, index, 0, val);
|
||||||
|
|
||||||
|
return ref;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void array_set_word(vvp_array_t arr,
|
void array_set_word(vvp_array_t arr,
|
||||||
unsigned address,
|
unsigned address,
|
||||||
unsigned part_off,
|
unsigned part_off,
|
||||||
|
|
@ -279,22 +500,61 @@ void array_set_word(vvp_array_t arr,
|
||||||
if (address >= arr->array_count)
|
if (address >= arr->array_count)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
if (arr->vals) {
|
||||||
|
assert(arr->nets == 0);
|
||||||
|
if (part_off != 0 || val.size() != arr->vals_width) {
|
||||||
|
if (arr->vals[address].size() == 0)
|
||||||
|
arr->vals[address] = vvp_vector4_t(arr->vals_width, BIT4_X);
|
||||||
|
if ((part_off + val.size()) > arr->vals[address].size()) {
|
||||||
|
cerr << "part_off=" << part_off
|
||||||
|
<< " val.size()=" << val.size()
|
||||||
|
<< " arr->vals[address].size()=" << arr->vals[address].size()
|
||||||
|
<< " arr->vals_width=" << arr->vals_width << endl;
|
||||||
|
assert(0);
|
||||||
|
}
|
||||||
|
arr->vals[address].set_vec(part_off, val);
|
||||||
|
} else {
|
||||||
|
arr->vals[address] = val;
|
||||||
|
}
|
||||||
|
array_word_change(arr, address);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
assert(arr->nets != 0);
|
||||||
|
|
||||||
// Select the word of the array that we affect.
|
// Select the word of the array that we affect.
|
||||||
vpiHandle word = arr->words[address];
|
vpiHandle word = arr->nets[address];
|
||||||
struct __vpiSignal*vsig = vpip_signal_from_handle(word);
|
struct __vpiSignal*vsig = vpip_signal_from_handle(word);
|
||||||
assert(vsig);
|
assert(vsig);
|
||||||
|
|
||||||
vvp_net_ptr_t ptr (vsig->node, 0);
|
vvp_net_ptr_t ptr (vsig->node, 0);
|
||||||
vvp_send_vec4_pv(ptr, val, part_off, val.size(), vpip_size(vsig));
|
vvp_send_vec4_pv(ptr, val, part_off, val.size(), vpip_size(vsig));
|
||||||
|
array_word_change(arr, address);
|
||||||
}
|
}
|
||||||
|
|
||||||
vvp_vector4_t array_get_word(vvp_array_t arr, unsigned address)
|
vvp_vector4_t array_get_word(vvp_array_t arr, unsigned address)
|
||||||
{
|
{
|
||||||
|
if (arr->vals) {
|
||||||
|
assert(arr->nets == 0);
|
||||||
|
|
||||||
|
vvp_vector4_t tmp;
|
||||||
|
if (address < arr->array_count)
|
||||||
|
tmp = arr->vals[address];
|
||||||
|
|
||||||
|
if (tmp.size() == 0)
|
||||||
|
tmp = vvp_vector4_t(arr->vals_width, BIT4_X);
|
||||||
|
|
||||||
|
return tmp;
|
||||||
|
}
|
||||||
|
|
||||||
|
assert(arr->vals == 0);
|
||||||
|
assert(arr->nets != 0);
|
||||||
|
|
||||||
if (address >= arr->array_count) {
|
if (address >= arr->array_count) {
|
||||||
// Reading outside the array. Return X's but get the
|
// Reading outside the array. Return X's but get the
|
||||||
// width by looking at a word that we know is present.
|
// width by looking at a word that we know is present.
|
||||||
assert(arr->array_count > 0);
|
assert(arr->array_count > 0);
|
||||||
vpiHandle word = arr->words[0];
|
vpiHandle word = arr->nets[0];
|
||||||
struct __vpiSignal*vsig = vpip_signal_from_handle(word);
|
struct __vpiSignal*vsig = vpip_signal_from_handle(word);
|
||||||
assert(vsig);
|
assert(vsig);
|
||||||
vvp_fun_signal_vec*sig = dynamic_cast<vvp_fun_signal_vec*> (vsig->node->fun);
|
vvp_fun_signal_vec*sig = dynamic_cast<vvp_fun_signal_vec*> (vsig->node->fun);
|
||||||
|
|
@ -302,7 +562,7 @@ vvp_vector4_t array_get_word(vvp_array_t arr, unsigned address)
|
||||||
return vvp_vector4_t(sig->size(), BIT4_X);
|
return vvp_vector4_t(sig->size(), BIT4_X);
|
||||||
}
|
}
|
||||||
|
|
||||||
vpiHandle word = arr->words[address];
|
vpiHandle word = arr->nets[address];
|
||||||
struct __vpiSignal*vsig = vpip_signal_from_handle(word);
|
struct __vpiSignal*vsig = vpip_signal_from_handle(word);
|
||||||
assert(vsig);
|
assert(vsig);
|
||||||
vvp_fun_signal_vec*sig = dynamic_cast<vvp_fun_signal_vec*> (vsig->node->fun);
|
vvp_fun_signal_vec*sig = dynamic_cast<vvp_fun_signal_vec*> (vsig->node->fun);
|
||||||
|
|
@ -332,10 +592,15 @@ static vpiHandle vpip_make_array(char*label, const char*name,
|
||||||
vpip_make_dec_const(&obj->first_addr, first_addr);
|
vpip_make_dec_const(&obj->first_addr, first_addr);
|
||||||
vpip_make_dec_const(&obj->last_addr, last_addr);
|
vpip_make_dec_const(&obj->last_addr, last_addr);
|
||||||
|
|
||||||
obj->words = (vpiHandle*)calloc(array_count, sizeof(vpiHandle));
|
// Start off now knowing if we are nets or variables.
|
||||||
|
obj->nets = 0;
|
||||||
|
obj->vals = 0;
|
||||||
|
obj->vals_width = 0;
|
||||||
|
obj->vals_words = 0;
|
||||||
|
|
||||||
// Initialize (clear) the read-ports list.
|
// Initialize (clear) the read-ports list.
|
||||||
obj->ports_ = 0;
|
obj->ports_ = 0;
|
||||||
|
obj->vpi_callbacks = 0;
|
||||||
|
|
||||||
/* Add this symbol to the array_symbols table for later lookup. */
|
/* Add this symbol to the array_symbols table for later lookup. */
|
||||||
if (!array_table)
|
if (!array_table)
|
||||||
|
|
@ -346,19 +611,29 @@ static vpiHandle vpip_make_array(char*label, const char*name,
|
||||||
v.ptr = obj;
|
v.ptr = obj;
|
||||||
sym_set_value(array_table, label, v);
|
sym_set_value(array_table, label, v);
|
||||||
|
|
||||||
|
/* Add this into the table of VPI objects. This is used for
|
||||||
|
contexts that try to look up VPI objects in
|
||||||
|
general. (i.e. arguments to vpi_task calls.) */
|
||||||
|
compile_vpi_symbol(label, &(obj->base));
|
||||||
|
|
||||||
|
/* Blindly attach to the scope as an object. */
|
||||||
|
vpip_attach_to_current_scope(&(obj->base));
|
||||||
|
|
||||||
return &(obj->base);
|
return &(obj->base);
|
||||||
}
|
}
|
||||||
|
|
||||||
void array_alias_word(vvp_array_t array, unsigned long addr, vpiHandle word)
|
void array_alias_word(vvp_array_t array, unsigned long addr, vpiHandle word)
|
||||||
{
|
{
|
||||||
assert(addr < array->array_count);
|
assert(addr < array->array_count);
|
||||||
array->words[addr] = word;
|
assert(array->nets);
|
||||||
|
array->nets[addr] = word;
|
||||||
}
|
}
|
||||||
|
|
||||||
void array_attach_word(vvp_array_t array, unsigned long addr, vpiHandle word)
|
void array_attach_word(vvp_array_t array, unsigned long addr, vpiHandle word)
|
||||||
{
|
{
|
||||||
assert(addr < array->array_count);
|
assert(addr < array->array_count);
|
||||||
array->words[addr] = word;
|
assert(array->nets);
|
||||||
|
array->nets[addr] = word;
|
||||||
|
|
||||||
if (struct __vpiSignal*sig = vpip_signal_from_handle(word)) {
|
if (struct __vpiSignal*sig = vpip_signal_from_handle(word)) {
|
||||||
vvp_net_t*net = sig->node;
|
vvp_net_t*net = sig->node;
|
||||||
|
|
@ -371,33 +646,16 @@ void array_attach_word(vvp_array_t array, unsigned long addr, vpiHandle word)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static vpiHandle common_array_build(char*label, char*name, int last, int first)
|
|
||||||
{
|
|
||||||
vpiHandle obj = vpip_make_array(label, name, first, last);
|
|
||||||
/* Add this into the table of VPI objects. This is used for
|
|
||||||
contexts that try to look up VPI objects in
|
|
||||||
general. (i.e. arguments to vpi_task calls.) */
|
|
||||||
compile_vpi_symbol(label, obj);
|
|
||||||
/* Blindly attach to the scope as an object. */
|
|
||||||
vpip_attach_to_current_scope(obj);
|
|
||||||
|
|
||||||
return obj;
|
|
||||||
}
|
|
||||||
|
|
||||||
void compile_var_array(char*label, char*name, int last, int first,
|
void compile_var_array(char*label, char*name, int last, int first,
|
||||||
int msb, int lsb, char signed_flag)
|
int msb, int lsb, char signed_flag)
|
||||||
{
|
{
|
||||||
vpiHandle obj = common_array_build(label, name, last, first);
|
vpiHandle obj = vpip_make_array(label, name, first, last);
|
||||||
|
|
||||||
struct __vpiArray*arr = ARRAY_HANDLE(obj);
|
struct __vpiArray*arr = ARRAY_HANDLE(obj);
|
||||||
vvp_array_t array = array_find(label);
|
|
||||||
|
|
||||||
/* Make the words. */
|
/* Make the words. */
|
||||||
for (unsigned idx = 0 ; idx < arr->array_count ; idx += 1) {
|
arr->vals = new vvp_vector4_t[arr->array_count];
|
||||||
char buf[64];
|
arr->vals_width = labs(msb-lsb) + 1;
|
||||||
snprintf(buf, sizeof buf, "%s_%u", label, idx);
|
|
||||||
compile_variablew(strdup(buf), array, idx, msb, lsb, signed_flag);
|
|
||||||
}
|
|
||||||
|
|
||||||
free(label);
|
free(label);
|
||||||
free(name);
|
free(name);
|
||||||
|
|
@ -406,7 +664,7 @@ void compile_var_array(char*label, char*name, int last, int first,
|
||||||
void compile_real_array(char*label, char*name, int last, int first,
|
void compile_real_array(char*label, char*name, int last, int first,
|
||||||
int msb, int lsb)
|
int msb, int lsb)
|
||||||
{
|
{
|
||||||
vpiHandle obj = common_array_build(label, name, last, first);
|
vpiHandle obj = vpip_make_array(label, name, first, last);
|
||||||
|
|
||||||
struct __vpiArray*arr = ARRAY_HANDLE(obj);
|
struct __vpiArray*arr = ARRAY_HANDLE(obj);
|
||||||
vvp_array_t array = array_find(label);
|
vvp_array_t array = array_find(label);
|
||||||
|
|
@ -424,7 +682,10 @@ void compile_real_array(char*label, char*name, int last, int first,
|
||||||
|
|
||||||
void compile_net_array(char*label, char*name, int last, int first)
|
void compile_net_array(char*label, char*name, int last, int first)
|
||||||
{
|
{
|
||||||
/* vpiHandle obj = */ common_array_build(label, name, last, first);
|
vpiHandle obj = vpip_make_array(label, name, first, last);
|
||||||
|
|
||||||
|
struct __vpiArray*arr = ARRAY_HANDLE(obj);
|
||||||
|
arr->nets = (vpiHandle*)calloc(arr->array_count, sizeof(vpiHandle));
|
||||||
|
|
||||||
free(label);
|
free(label);
|
||||||
free(name);
|
free(name);
|
||||||
|
|
@ -434,6 +695,7 @@ class vvp_fun_arrayport : public vvp_net_fun_t {
|
||||||
|
|
||||||
public:
|
public:
|
||||||
explicit vvp_fun_arrayport(vvp_array_t mem, vvp_net_t*net);
|
explicit vvp_fun_arrayport(vvp_array_t mem, vvp_net_t*net);
|
||||||
|
explicit vvp_fun_arrayport(vvp_array_t mem, vvp_net_t*net, long addr);
|
||||||
~vvp_fun_arrayport();
|
~vvp_fun_arrayport();
|
||||||
|
|
||||||
void check_word_change(unsigned long addr);
|
void check_word_change(unsigned long addr);
|
||||||
|
|
@ -456,6 +718,12 @@ vvp_fun_arrayport::vvp_fun_arrayport(vvp_array_t mem, vvp_net_t*net)
|
||||||
next_ = 0;
|
next_ = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
vvp_fun_arrayport::vvp_fun_arrayport(vvp_array_t mem, vvp_net_t*net, long addr)
|
||||||
|
: arr_(mem), net_(net), addr_(addr)
|
||||||
|
{
|
||||||
|
next_ = 0;
|
||||||
|
}
|
||||||
|
|
||||||
vvp_fun_arrayport::~vvp_fun_arrayport()
|
vvp_fun_arrayport::~vvp_fun_arrayport()
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
@ -499,26 +767,121 @@ void array_word_change(vvp_array_t array, unsigned long addr)
|
||||||
{
|
{
|
||||||
for (vvp_fun_arrayport*cur = array->ports_; cur; cur = cur->next_)
|
for (vvp_fun_arrayport*cur = array->ports_; cur; cur = cur->next_)
|
||||||
cur->check_word_change(addr);
|
cur->check_word_change(addr);
|
||||||
|
|
||||||
|
// Run callbacks attatched to the array itself.
|
||||||
|
struct __vpiCallback *next = array->vpi_callbacks;
|
||||||
|
struct __vpiCallback *prev = 0;
|
||||||
|
|
||||||
|
while (next) {
|
||||||
|
struct __vpiCallback*cur = next;
|
||||||
|
next = cur->next;
|
||||||
|
|
||||||
|
// Skip callbacks for callbacks not for me.
|
||||||
|
if (cur->extra_data != (long)addr) {
|
||||||
|
prev = cur;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (cur->cb_data.cb_rtn != 0) {
|
||||||
|
if (cur->cb_data.value)
|
||||||
|
vpip_vec4_get_value(array->vals[addr], array->vals_width,
|
||||||
|
false, cur->cb_data.value);
|
||||||
|
|
||||||
|
callback_execute(cur);
|
||||||
|
prev = cur;
|
||||||
|
|
||||||
|
} else if (prev == 0) {
|
||||||
|
|
||||||
|
array->vpi_callbacks = next;
|
||||||
|
cur->next = 0;
|
||||||
|
delete_vpi_callback(cur);
|
||||||
|
|
||||||
|
} else {
|
||||||
|
assert(prev->next == cur);
|
||||||
|
prev->next = next;
|
||||||
|
cur->next = 0;
|
||||||
|
delete_vpi_callback(cur);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class array_port_resolv_list_t : public resolv_list_s {
|
||||||
|
|
||||||
|
public:
|
||||||
|
explicit array_port_resolv_list_t(char*label) : resolv_list_s(label) { }
|
||||||
|
|
||||||
|
vvp_net_t*ptr;
|
||||||
|
bool use_addr;
|
||||||
|
long addr;
|
||||||
|
bool resolve(bool mes);
|
||||||
|
|
||||||
|
private:
|
||||||
|
};
|
||||||
|
|
||||||
|
bool array_port_resolv_list_t::resolve(bool mes)
|
||||||
|
{
|
||||||
|
vvp_array_t mem = array_find(label());
|
||||||
|
if (mem == 0) {
|
||||||
|
assert(mem || !mes);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
vvp_fun_arrayport*fun;
|
||||||
|
if (use_addr)
|
||||||
|
fun = new vvp_fun_arrayport(mem, ptr, addr);
|
||||||
|
else
|
||||||
|
fun = new vvp_fun_arrayport(mem, ptr);
|
||||||
|
ptr->fun = fun;
|
||||||
|
|
||||||
|
array_attach_port(mem, fun);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void vpip_array_word_change(struct __vpiCallback*cb, vpiHandle obj)
|
||||||
|
{
|
||||||
|
struct __vpiArray*parent = 0;
|
||||||
|
if (struct __vpiArrayWord*word = array_var_word_from_handle(obj)) {
|
||||||
|
unsigned addr = decode_array_word_pointer(word, parent);
|
||||||
|
cb->extra_data = addr;
|
||||||
|
|
||||||
|
} else if (struct __vpiArrayVthrA*word = array_vthr_a_from_handle(obj)) {
|
||||||
|
parent = word->array;
|
||||||
|
cb->extra_data = word->address;
|
||||||
|
}
|
||||||
|
|
||||||
|
assert(parent);
|
||||||
|
cb->next = parent->vpi_callbacks;
|
||||||
|
parent->vpi_callbacks = cb;
|
||||||
}
|
}
|
||||||
|
|
||||||
void compile_array_port(char*label, char*array, char*addr)
|
void compile_array_port(char*label, char*array, char*addr)
|
||||||
{
|
{
|
||||||
vvp_array_t mem = array_find(array);
|
array_port_resolv_list_t*resolv_mem
|
||||||
assert(mem);
|
= new array_port_resolv_list_t(array);
|
||||||
|
|
||||||
vvp_net_t*ptr = new vvp_net_t;
|
|
||||||
vvp_fun_arrayport*fun = new vvp_fun_arrayport(mem, ptr);
|
|
||||||
ptr->fun = fun;
|
|
||||||
|
|
||||||
define_functor_symbol(label, ptr);
|
|
||||||
// Connect the port-0 input as the address.
|
|
||||||
input_connect(ptr, 0, addr);
|
|
||||||
|
|
||||||
array_attach_port(mem, fun);
|
|
||||||
|
|
||||||
|
resolv_mem->ptr = new vvp_net_t;
|
||||||
|
resolv_mem->use_addr = false;
|
||||||
|
define_functor_symbol(label, resolv_mem->ptr);
|
||||||
free(label);
|
free(label);
|
||||||
free(array);
|
// Connect the port-0 input as the address.
|
||||||
// The input_connect arranges for the array string to be free'ed.
|
input_connect(resolv_mem->ptr, 0, addr);
|
||||||
|
|
||||||
|
resolv_submit(resolv_mem);
|
||||||
|
}
|
||||||
|
|
||||||
|
void compile_array_port(char*label, char*array, long addr)
|
||||||
|
{
|
||||||
|
array_port_resolv_list_t*resolv_mem
|
||||||
|
= new array_port_resolv_list_t(array);
|
||||||
|
|
||||||
|
resolv_mem->ptr = new vvp_net_t;
|
||||||
|
resolv_mem->use_addr = true;
|
||||||
|
resolv_mem->addr = addr;
|
||||||
|
define_functor_symbol(label, resolv_mem->ptr);
|
||||||
|
free(label);
|
||||||
|
|
||||||
|
resolv_submit(resolv_mem);
|
||||||
}
|
}
|
||||||
|
|
||||||
void compile_array_alias(char*label, char*name, char*src)
|
void compile_array_alias(char*label, char*name, char*src)
|
||||||
|
|
@ -539,7 +902,8 @@ void compile_array_alias(char*label, char*name, char*src)
|
||||||
vpip_make_dec_const(&obj->last_addr, mem->last_addr.value);
|
vpip_make_dec_const(&obj->last_addr, mem->last_addr.value);
|
||||||
|
|
||||||
// Share the words with the source array.
|
// Share the words with the source array.
|
||||||
obj->words = mem->words;
|
obj->nets = mem->nets;
|
||||||
|
obj->vals = mem->vals;
|
||||||
|
|
||||||
obj->ports_ = 0;
|
obj->ports_ = 0;
|
||||||
|
|
||||||
|
|
@ -556,3 +920,19 @@ void compile_array_alias(char*label, char*name, char*src)
|
||||||
free(name);
|
free(name);
|
||||||
free(src);
|
free(src);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
vpiHandle vpip_make_vthr_A(char*label, unsigned addr)
|
||||||
|
{
|
||||||
|
struct __vpiArrayVthrA*obj = (struct __vpiArrayVthrA*)
|
||||||
|
malloc(sizeof (struct __vpiArrayVthrA));
|
||||||
|
|
||||||
|
obj->base.vpi_type = &vpip_array_vthr_A_rt;
|
||||||
|
|
||||||
|
obj->array = array_find(label);
|
||||||
|
assert(obj->array);
|
||||||
|
|
||||||
|
obj->address = addr;
|
||||||
|
assert(addr < obj->array->array_count);
|
||||||
|
|
||||||
|
return &(obj->base);
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -28,7 +28,7 @@ typedef struct __vpiArray* vvp_array_t;
|
||||||
* This function tries to find the array (by label) in the global
|
* This function tries to find the array (by label) in the global
|
||||||
* table of all the arrays in the design.
|
* table of all the arrays in the design.
|
||||||
*/
|
*/
|
||||||
extern vvp_array_t array_find(char*label);
|
extern vvp_array_t array_find(const char*label);
|
||||||
extern vpiHandle array_index_iterate(int code, vpiHandle ref);
|
extern vpiHandle array_index_iterate(int code, vpiHandle ref);
|
||||||
|
|
||||||
extern void array_word_change(vvp_array_t array, unsigned long addr);
|
extern void array_word_change(vvp_array_t array, unsigned long addr);
|
||||||
|
|
@ -45,6 +45,11 @@ extern void array_set_word(vvp_array_t arr,
|
||||||
|
|
||||||
extern vvp_vector4_t array_get_word(vvp_array_t array, unsigned adddress);
|
extern vvp_vector4_t array_get_word(vvp_array_t array, unsigned adddress);
|
||||||
|
|
||||||
|
/* VPI hooks */
|
||||||
|
|
||||||
|
extern void vpip_array_word_change(struct __vpiCallback*cb, vpiHandle word);
|
||||||
|
|
||||||
|
/* Compile hooks */
|
||||||
extern void compile_variablew(char*label, vvp_array_t array,
|
extern void compile_variablew(char*label, vvp_array_t array,
|
||||||
unsigned long array_addr,
|
unsigned long array_addr,
|
||||||
int msb, int lsb, char signed_flag);
|
int msb, int lsb, char signed_flag);
|
||||||
|
|
|
||||||
|
|
@ -97,7 +97,6 @@ extern bool of_JOIN(vthread_t thr, vvp_code_t code);
|
||||||
extern bool of_LOAD_AV(vthread_t thr, vvp_code_t code);
|
extern bool of_LOAD_AV(vthread_t thr, vvp_code_t code);
|
||||||
extern bool of_LOAD_AVP0(vthread_t thr, vvp_code_t code);
|
extern bool of_LOAD_AVP0(vthread_t thr, vvp_code_t code);
|
||||||
extern bool of_LOAD_AVX_P(vthread_t thr, vvp_code_t code);
|
extern bool of_LOAD_AVX_P(vthread_t thr, vvp_code_t code);
|
||||||
extern bool of_LOAD_MV(vthread_t thr, vvp_code_t code);
|
|
||||||
extern bool of_LOAD_NX(vthread_t thr, vvp_code_t code);
|
extern bool of_LOAD_NX(vthread_t thr, vvp_code_t code);
|
||||||
extern bool of_LOAD_VEC(vthread_t thr, vvp_code_t code);
|
extern bool of_LOAD_VEC(vthread_t thr, vvp_code_t code);
|
||||||
extern bool of_LOAD_VP0(vthread_t thr, vvp_code_t code);
|
extern bool of_LOAD_VP0(vthread_t thr, vvp_code_t code);
|
||||||
|
|
@ -127,7 +126,6 @@ extern bool of_RELEASE_NET(vthread_t thr, vvp_code_t code);
|
||||||
extern bool of_RELEASE_REG(vthread_t thr, vvp_code_t code);
|
extern bool of_RELEASE_REG(vthread_t thr, vvp_code_t code);
|
||||||
extern bool of_RELEASE_WR(vthread_t thr, vvp_code_t code);
|
extern bool of_RELEASE_WR(vthread_t thr, vvp_code_t code);
|
||||||
extern bool of_SET_AV(vthread_t thr, vvp_code_t code);
|
extern bool of_SET_AV(vthread_t thr, vvp_code_t code);
|
||||||
extern bool of_SET_MV(vthread_t thr, vvp_code_t code);
|
|
||||||
extern bool of_SET_VEC(vthread_t thr, vvp_code_t code);
|
extern bool of_SET_VEC(vthread_t thr, vvp_code_t code);
|
||||||
extern bool of_SET_WORDR(vthread_t thr, vvp_code_t code);
|
extern bool of_SET_WORDR(vthread_t thr, vvp_code_t code);
|
||||||
extern bool of_SET_X0(vthread_t thr, vvp_code_t code);
|
extern bool of_SET_X0(vthread_t thr, vvp_code_t code);
|
||||||
|
|
@ -162,7 +160,6 @@ struct vvp_code_s {
|
||||||
unsigned long number;
|
unsigned long number;
|
||||||
vvp_net_t *net;
|
vvp_net_t *net;
|
||||||
vvp_code_t cptr;
|
vvp_code_t cptr;
|
||||||
vvp_memory_t mem;
|
|
||||||
vvp_array_t array;
|
vvp_array_t array;
|
||||||
struct __vpiHandle*handle;
|
struct __vpiHandle*handle;
|
||||||
struct __vpiScope*scope;
|
struct __vpiScope*scope;
|
||||||
|
|
|
||||||
227
vvp/compile.cc
227
vvp/compile.cc
|
|
@ -22,7 +22,6 @@
|
||||||
# include "logic.h"
|
# include "logic.h"
|
||||||
# include "resolv.h"
|
# include "resolv.h"
|
||||||
# include "udp.h"
|
# include "udp.h"
|
||||||
# include "memory.h"
|
|
||||||
# include "symbols.h"
|
# include "symbols.h"
|
||||||
# include "codes.h"
|
# include "codes.h"
|
||||||
# include "schedule.h"
|
# include "schedule.h"
|
||||||
|
|
@ -67,8 +66,6 @@ enum operand_e {
|
||||||
OA_FUNC_PTR,
|
OA_FUNC_PTR,
|
||||||
/* The operand is a second functor pointer */
|
/* The operand is a second functor pointer */
|
||||||
OA_FUNC_PTR2,
|
OA_FUNC_PTR2,
|
||||||
/* The operand is a pointer to a memory */
|
|
||||||
OA_MEM_PTR,
|
|
||||||
/* The operand is a VPI handle */
|
/* The operand is a VPI handle */
|
||||||
OA_VPI_PTR,
|
OA_VPI_PTR,
|
||||||
};
|
};
|
||||||
|
|
@ -90,7 +87,6 @@ const static struct opcode_table_s opcode_table[] = {
|
||||||
{ "%and/r", of_ANDR, 3, {OA_BIT1, OA_BIT2, OA_NUMBER} },
|
{ "%and/r", of_ANDR, 3, {OA_BIT1, OA_BIT2, OA_NUMBER} },
|
||||||
{ "%assign/av",of_ASSIGN_AV,3,{OA_ARR_PTR,OA_BIT1, OA_BIT2} },
|
{ "%assign/av",of_ASSIGN_AV,3,{OA_ARR_PTR,OA_BIT1, OA_BIT2} },
|
||||||
{ "%assign/av/d",of_ASSIGN_AVD,3,{OA_ARR_PTR,OA_BIT1, OA_BIT2} },
|
{ "%assign/av/d",of_ASSIGN_AVD,3,{OA_ARR_PTR,OA_BIT1, OA_BIT2} },
|
||||||
{ "%assign/mv",of_ASSIGN_MV,3,{OA_MEM_PTR,OA_BIT1, OA_BIT2} },
|
|
||||||
{ "%assign/v0",of_ASSIGN_V0,3,{OA_FUNC_PTR,OA_BIT1, OA_BIT2} },
|
{ "%assign/v0",of_ASSIGN_V0,3,{OA_FUNC_PTR,OA_BIT1, OA_BIT2} },
|
||||||
{ "%assign/v0/d",of_ASSIGN_V0D,3,{OA_FUNC_PTR,OA_BIT1, OA_BIT2} },
|
{ "%assign/v0/d",of_ASSIGN_V0D,3,{OA_FUNC_PTR,OA_BIT1, OA_BIT2} },
|
||||||
{ "%assign/v0/x1",of_ASSIGN_V0X1,3,{OA_FUNC_PTR,OA_BIT1,OA_BIT2} },
|
{ "%assign/v0/x1",of_ASSIGN_V0X1,3,{OA_FUNC_PTR,OA_BIT1,OA_BIT2} },
|
||||||
|
|
@ -144,7 +140,6 @@ const static struct opcode_table_s opcode_table[] = {
|
||||||
{ "%load/av",of_LOAD_AV,3, {OA_BIT1, OA_ARR_PTR, OA_BIT2} },
|
{ "%load/av",of_LOAD_AV,3, {OA_BIT1, OA_ARR_PTR, OA_BIT2} },
|
||||||
{ "%load/avp0",of_LOAD_AVP0,3, {OA_BIT1, OA_ARR_PTR, OA_BIT2} },
|
{ "%load/avp0",of_LOAD_AVP0,3, {OA_BIT1, OA_ARR_PTR, OA_BIT2} },
|
||||||
{ "%load/avx.p",of_LOAD_AVX_P,3,{OA_BIT1, OA_ARR_PTR, OA_BIT2} },
|
{ "%load/avx.p",of_LOAD_AVX_P,3,{OA_BIT1, OA_ARR_PTR, OA_BIT2} },
|
||||||
{ "%load/mv",of_LOAD_MV,3, {OA_BIT1, OA_MEM_PTR, OA_BIT2} },
|
|
||||||
{ "%load/nx",of_LOAD_NX,3, {OA_BIT1, OA_VPI_PTR, OA_BIT2} },
|
{ "%load/nx",of_LOAD_NX,3, {OA_BIT1, OA_VPI_PTR, OA_BIT2} },
|
||||||
{ "%load/v", of_LOAD_VEC,3, {OA_BIT1, OA_FUNC_PTR, OA_BIT2} },
|
{ "%load/v", of_LOAD_VEC,3, {OA_BIT1, OA_FUNC_PTR, OA_BIT2} },
|
||||||
{ "%load/vp0",of_LOAD_VP0,3,{OA_BIT1, OA_FUNC_PTR, OA_BIT2} },
|
{ "%load/vp0",of_LOAD_VP0,3,{OA_BIT1, OA_FUNC_PTR, OA_BIT2} },
|
||||||
|
|
@ -174,7 +169,6 @@ const static struct opcode_table_s opcode_table[] = {
|
||||||
{ "%release/reg",of_RELEASE_REG,3,{OA_FUNC_PTR,OA_BIT1,OA_BIT2} },
|
{ "%release/reg",of_RELEASE_REG,3,{OA_FUNC_PTR,OA_BIT1,OA_BIT2} },
|
||||||
{ "%release/wr",of_RELEASE_WR,2,{OA_FUNC_PTR,OA_BIT1,OA_NONE} },
|
{ "%release/wr",of_RELEASE_WR,2,{OA_FUNC_PTR,OA_BIT1,OA_NONE} },
|
||||||
{ "%set/av", of_SET_AV, 3, {OA_ARR_PTR, OA_BIT1, OA_BIT2} },
|
{ "%set/av", of_SET_AV, 3, {OA_ARR_PTR, OA_BIT1, OA_BIT2} },
|
||||||
{ "%set/mv", of_SET_MV, 3, {OA_MEM_PTR, OA_BIT1, OA_BIT2} },
|
|
||||||
{ "%set/v", of_SET_VEC,3, {OA_FUNC_PTR, OA_BIT1, OA_BIT2} },
|
{ "%set/v", of_SET_VEC,3, {OA_FUNC_PTR, OA_BIT1, OA_BIT2} },
|
||||||
{ "%set/wr", of_SET_WORDR,2,{OA_VPI_PTR, OA_BIT1, OA_NONE} },
|
{ "%set/wr", of_SET_WORDR,2,{OA_VPI_PTR, OA_BIT1, OA_NONE} },
|
||||||
{ "%set/x0", of_SET_X0, 3, {OA_FUNC_PTR, OA_BIT1, OA_BIT2} },
|
{ "%set/x0", of_SET_X0, 3, {OA_FUNC_PTR, OA_BIT1, OA_BIT2} },
|
||||||
|
|
@ -321,13 +315,12 @@ vvp_net_t* vvp_net_lookup(const char*label)
|
||||||
*/
|
*/
|
||||||
static struct resolv_list_s*resolv_list = 0;
|
static struct resolv_list_s*resolv_list = 0;
|
||||||
|
|
||||||
struct resolv_list_s {
|
resolv_list_s::~resolv_list_s()
|
||||||
virtual ~resolv_list_s() { }
|
{
|
||||||
struct resolv_list_s*next;
|
free(label_);
|
||||||
virtual bool resolve(bool mes = false) = 0;
|
}
|
||||||
};
|
|
||||||
|
|
||||||
static void resolv_submit(struct resolv_list_s*cur)
|
void resolv_submit(struct resolv_list_s*cur)
|
||||||
{
|
{
|
||||||
if (cur->resolve()) {
|
if (cur->resolve()) {
|
||||||
delete cur;
|
delete cur;
|
||||||
|
|
@ -346,8 +339,8 @@ static void resolv_submit(struct resolv_list_s*cur)
|
||||||
* put net->port[port] into the fan-out list for that node.
|
* put net->port[port] into the fan-out list for that node.
|
||||||
*/
|
*/
|
||||||
struct vvp_net_resolv_list_s: public resolv_list_s {
|
struct vvp_net_resolv_list_s: public resolv_list_s {
|
||||||
// node to locate
|
|
||||||
char*source;
|
vvp_net_resolv_list_s(char*l) : resolv_list_s(l) { }
|
||||||
// port to be driven by the located node.
|
// port to be driven by the located node.
|
||||||
vvp_net_ptr_t port;
|
vvp_net_ptr_t port;
|
||||||
virtual bool resolve(bool mes);
|
virtual bool resolve(bool mes);
|
||||||
|
|
@ -355,20 +348,18 @@ struct vvp_net_resolv_list_s: public resolv_list_s {
|
||||||
|
|
||||||
bool vvp_net_resolv_list_s::resolve(bool mes)
|
bool vvp_net_resolv_list_s::resolve(bool mes)
|
||||||
{
|
{
|
||||||
vvp_net_t*tmp = vvp_net_lookup(source);
|
vvp_net_t*tmp = vvp_net_lookup(label());
|
||||||
|
|
||||||
if (tmp) {
|
if (tmp) {
|
||||||
// Link the input port to the located output.
|
// Link the input port to the located output.
|
||||||
vvp_net_t*net = port.ptr();
|
vvp_net_t*net = port.ptr();
|
||||||
net->port[port.port()] = tmp->out;
|
net->port[port.port()] = tmp->out;
|
||||||
tmp->out = port;
|
tmp->out = port;
|
||||||
|
|
||||||
free(source);
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (mes)
|
if (mes)
|
||||||
fprintf(stderr, "unresolved vvp_net reference: %s\n", source);
|
fprintf(stderr, "unresolved vvp_net reference: %s\n", label());
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
@ -376,10 +367,8 @@ bool vvp_net_resolv_list_s::resolve(bool mes)
|
||||||
inline static
|
inline static
|
||||||
void postpone_functor_input(vvp_net_ptr_t port, char*lab)
|
void postpone_functor_input(vvp_net_ptr_t port, char*lab)
|
||||||
{
|
{
|
||||||
struct vvp_net_resolv_list_s*res = new struct vvp_net_resolv_list_s;
|
struct vvp_net_resolv_list_s*res = new struct vvp_net_resolv_list_s(lab);
|
||||||
|
|
||||||
res->port = port;
|
res->port = port;
|
||||||
res->source = lab;
|
|
||||||
|
|
||||||
resolv_submit(res);
|
resolv_submit(res);
|
||||||
}
|
}
|
||||||
|
|
@ -390,24 +379,22 @@ void postpone_functor_input(vvp_net_ptr_t port, char*lab)
|
||||||
*/
|
*/
|
||||||
|
|
||||||
struct functor_gen_resolv_list_s: public resolv_list_s {
|
struct functor_gen_resolv_list_s: public resolv_list_s {
|
||||||
char*source;
|
explicit functor_gen_resolv_list_s(char*txt) : resolv_list_s(txt) { }
|
||||||
vvp_net_t**ref;
|
vvp_net_t**ref;
|
||||||
virtual bool resolve(bool mes);
|
virtual bool resolve(bool mes);
|
||||||
};
|
};
|
||||||
|
|
||||||
bool functor_gen_resolv_list_s::resolve(bool mes)
|
bool functor_gen_resolv_list_s::resolve(bool mes)
|
||||||
{
|
{
|
||||||
vvp_net_t*tmp = vvp_net_lookup(source);
|
vvp_net_t*tmp = vvp_net_lookup(label());
|
||||||
|
|
||||||
if (tmp) {
|
if (tmp) {
|
||||||
*ref = tmp;
|
*ref = tmp;
|
||||||
|
|
||||||
free(source);
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (mes)
|
if (mes)
|
||||||
fprintf(stderr, "unresolved functor reference: %s\n", source);
|
fprintf(stderr, "unresolved functor reference: %s\n", label());
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
@ -415,10 +402,9 @@ bool functor_gen_resolv_list_s::resolve(bool mes)
|
||||||
void functor_ref_lookup(vvp_net_t**ref, char*lab)
|
void functor_ref_lookup(vvp_net_t**ref, char*lab)
|
||||||
{
|
{
|
||||||
struct functor_gen_resolv_list_s*res =
|
struct functor_gen_resolv_list_s*res =
|
||||||
new struct functor_gen_resolv_list_s;
|
new struct functor_gen_resolv_list_s(lab);
|
||||||
|
|
||||||
res->ref = ref;
|
res->ref = ref;
|
||||||
res->source = lab;
|
|
||||||
|
|
||||||
resolv_submit(res);
|
resolv_submit(res);
|
||||||
}
|
}
|
||||||
|
|
@ -428,27 +414,27 @@ void functor_ref_lookup(vvp_net_t**ref, char*lab)
|
||||||
*/
|
*/
|
||||||
|
|
||||||
struct vpi_handle_resolv_list_s: public resolv_list_s {
|
struct vpi_handle_resolv_list_s: public resolv_list_s {
|
||||||
vpiHandle *handle;
|
explicit vpi_handle_resolv_list_s(char*label) : resolv_list_s(label) { }
|
||||||
char *label;
|
|
||||||
virtual bool resolve(bool mes);
|
virtual bool resolve(bool mes);
|
||||||
|
vpiHandle *handle;
|
||||||
};
|
};
|
||||||
|
|
||||||
bool vpi_handle_resolv_list_s::resolve(bool mes)
|
bool vpi_handle_resolv_list_s::resolve(bool mes)
|
||||||
{
|
{
|
||||||
symbol_value_t val = sym_get_value(sym_vpi, label);
|
symbol_value_t val = sym_get_value(sym_vpi, label());
|
||||||
if (!val.ptr) {
|
if (!val.ptr) {
|
||||||
// check for thread vector T<base,wid>
|
// check for thread vector T<base,wid>
|
||||||
unsigned base, wid;
|
unsigned base, wid;
|
||||||
unsigned n = 0;
|
unsigned n = 0;
|
||||||
char ss[32];
|
char ss[32];
|
||||||
if (2 <= sscanf(label, "T<%u,%u>%n", &base, &wid, &n)
|
if (2 <= sscanf(label(), "T<%u,%u>%n", &base, &wid, &n)
|
||||||
&& n == strlen(label)) {
|
&& n == strlen(label())) {
|
||||||
val.ptr = vpip_make_vthr_vector(base, wid, false);
|
val.ptr = vpip_make_vthr_vector(base, wid, false);
|
||||||
sym_set_value(sym_vpi, label, val);
|
sym_set_value(sym_vpi, label(), val);
|
||||||
|
|
||||||
} else if (3 <= sscanf(label, "T<%u,%u,%[su]>%n", &base,
|
} else if (3 <= sscanf(label(), "T<%u,%u,%[su]>%n", &base,
|
||||||
&wid, ss, &n)
|
&wid, ss, &n)
|
||||||
&& n == strlen(label)) {
|
&& n == strlen(label())) {
|
||||||
|
|
||||||
bool signed_flag = false;
|
bool signed_flag = false;
|
||||||
for (char*fp = ss ; *fp ; fp += 1) switch (*fp) {
|
for (char*fp = ss ; *fp ; fp += 1) switch (*fp) {
|
||||||
|
|
@ -463,13 +449,13 @@ bool vpi_handle_resolv_list_s::resolve(bool mes)
|
||||||
}
|
}
|
||||||
|
|
||||||
val.ptr = vpip_make_vthr_vector(base, wid, signed_flag);
|
val.ptr = vpip_make_vthr_vector(base, wid, signed_flag);
|
||||||
sym_set_value(sym_vpi, label, val);
|
sym_set_value(sym_vpi, label(), val);
|
||||||
|
|
||||||
} else if (2 == sscanf(label, "W<%u,%[r]>%n", &base, ss, &n)
|
} else if (2 == sscanf(label(), "W<%u,%[r]>%n", &base, ss, &n)
|
||||||
&& n == strlen(label)) {
|
&& n == strlen(label())) {
|
||||||
|
|
||||||
val.ptr = vpip_make_vthr_word(base, ss);
|
val.ptr = vpip_make_vthr_word(base, ss);
|
||||||
sym_set_value(sym_vpi, label, val);
|
sym_set_value(sym_vpi, label(), val);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
@ -480,12 +466,11 @@ bool vpi_handle_resolv_list_s::resolve(bool mes)
|
||||||
|
|
||||||
if (val.ptr) {
|
if (val.ptr) {
|
||||||
*handle = (vpiHandle) val.ptr;
|
*handle = (vpiHandle) val.ptr;
|
||||||
free(label);
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (mes)
|
if (mes)
|
||||||
fprintf(stderr, "unresolved vpi name lookup: %s\n", label);
|
fprintf(stderr, "unresolved vpi name lookup: %s\n", label());
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
@ -517,10 +502,9 @@ void compile_vpi_lookup(vpiHandle *handle, char*label)
|
||||||
}
|
}
|
||||||
|
|
||||||
struct vpi_handle_resolv_list_s*res
|
struct vpi_handle_resolv_list_s*res
|
||||||
= new struct vpi_handle_resolv_list_s;
|
= new struct vpi_handle_resolv_list_s(label);
|
||||||
|
|
||||||
res->handle = handle;
|
res->handle = handle;
|
||||||
res->label = label;
|
|
||||||
resolv_submit(res);
|
resolv_submit(res);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -529,27 +513,24 @@ void compile_vpi_lookup(vpiHandle *handle, char*label)
|
||||||
*/
|
*/
|
||||||
|
|
||||||
struct code_label_resolv_list_s: public resolv_list_s {
|
struct code_label_resolv_list_s: public resolv_list_s {
|
||||||
|
code_label_resolv_list_s(char*label) : resolv_list_s(label) { }
|
||||||
struct vvp_code_s *code;
|
struct vvp_code_s *code;
|
||||||
char *label;
|
|
||||||
virtual bool resolve(bool mes);
|
virtual bool resolve(bool mes);
|
||||||
};
|
};
|
||||||
|
|
||||||
bool code_label_resolv_list_s::resolve(bool mes)
|
bool code_label_resolv_list_s::resolve(bool mes)
|
||||||
{
|
{
|
||||||
symbol_value_t val = sym_get_value(sym_codespace, label);
|
symbol_value_t val = sym_get_value(sym_codespace, label());
|
||||||
if (val.num) {
|
if (val.num) {
|
||||||
if (code->opcode == of_FORK)
|
if (code->opcode == of_FORK)
|
||||||
code->cptr2 = reinterpret_cast<vvp_code_t>(val.ptr);
|
code->cptr2 = reinterpret_cast<vvp_code_t>(val.ptr);
|
||||||
else
|
else
|
||||||
code->cptr = reinterpret_cast<vvp_code_t>(val.ptr);
|
code->cptr = reinterpret_cast<vvp_code_t>(val.ptr);
|
||||||
free(label);
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (mes)
|
if (mes)
|
||||||
fprintf(stderr,
|
fprintf(stderr, "unresolved code label: %s\n", label());
|
||||||
"unresolved code label: %s\n",
|
|
||||||
label);
|
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
@ -557,75 +538,38 @@ bool code_label_resolv_list_s::resolve(bool mes)
|
||||||
void code_label_lookup(struct vvp_code_s *code, char *label)
|
void code_label_lookup(struct vvp_code_s *code, char *label)
|
||||||
{
|
{
|
||||||
struct code_label_resolv_list_s *res
|
struct code_label_resolv_list_s *res
|
||||||
= new struct code_label_resolv_list_s;
|
= new struct code_label_resolv_list_s(label);
|
||||||
|
|
||||||
res->code = code;
|
res->code = code;
|
||||||
res->label = label;
|
|
||||||
|
|
||||||
resolv_submit(res);
|
resolv_submit(res);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
struct code_array_resolv_list_s: public resolv_list_s {
|
||||||
* Lookup memories.
|
code_array_resolv_list_s(char*label) : resolv_list_s(label) { }
|
||||||
*/
|
|
||||||
struct memory_resolv_list_s: public resolv_list_s {
|
|
||||||
struct vvp_code_s *code;
|
struct vvp_code_s *code;
|
||||||
char *label;
|
|
||||||
virtual bool resolve(bool mes);
|
virtual bool resolve(bool mes);
|
||||||
};
|
};
|
||||||
|
|
||||||
bool memory_resolv_list_s::resolve(bool mes)
|
bool code_array_resolv_list_s::resolve(bool mes)
|
||||||
{
|
{
|
||||||
code->mem = memory_find(label);
|
code->array = array_find(label());
|
||||||
if (code->mem != 0) {
|
|
||||||
free(label);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (mes)
|
|
||||||
fprintf(stderr, "Memory unresolved: %s\n", label);
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void compile_mem_lookup(struct vvp_code_s *code, char *label)
|
|
||||||
{
|
|
||||||
struct memory_resolv_list_s *res
|
|
||||||
= new struct memory_resolv_list_s;
|
|
||||||
|
|
||||||
res->code = code;
|
|
||||||
res->label = label;
|
|
||||||
|
|
||||||
resolv_submit(res);
|
|
||||||
}
|
|
||||||
|
|
||||||
struct array_resolv_list_s: public resolv_list_s {
|
|
||||||
struct vvp_code_s *code;
|
|
||||||
char *label;
|
|
||||||
virtual bool resolve(bool mes);
|
|
||||||
};
|
|
||||||
|
|
||||||
bool array_resolv_list_s::resolve(bool mes)
|
|
||||||
{
|
|
||||||
code->array = array_find(label);
|
|
||||||
if (code->array != 0) {
|
if (code->array != 0) {
|
||||||
free(label);
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (mes)
|
if (mes)
|
||||||
fprintf(stderr, "Array unresolved: %s\n", label);
|
fprintf(stderr, "Array unresolved: %s\n", label());
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void compile_array_lookup(struct vvp_code_s*code, char*label)
|
static void compile_array_lookup(struct vvp_code_s*code, char*label)
|
||||||
{
|
{
|
||||||
struct array_resolv_list_s *res
|
struct code_array_resolv_list_s *res
|
||||||
= new struct array_resolv_list_s;
|
= new struct code_array_resolv_list_s(label);
|
||||||
|
|
||||||
res->code = code;
|
res->code = code;
|
||||||
res->label = label;
|
|
||||||
|
|
||||||
resolv_submit(res);
|
resolv_submit(res);
|
||||||
}
|
}
|
||||||
|
|
@ -1522,90 +1466,6 @@ char **compile_udp_table(char **table, char *row)
|
||||||
return table;
|
return table;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
* Take the detailed parse items from a .mem statement and generate
|
|
||||||
* the necessary internal structures.
|
|
||||||
*
|
|
||||||
* <label> .mem <name>, <msb>, <lsb>, <idxs...> ;
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
void compile_memory(char *label, char *name, int msb, int lsb,
|
|
||||||
unsigned narg, long *args)
|
|
||||||
{
|
|
||||||
/* Create an empty memory in the symbol table. */
|
|
||||||
vvp_memory_t mem = memory_create(label);
|
|
||||||
|
|
||||||
assert( narg > 0 && narg%2 == 0 );
|
|
||||||
|
|
||||||
struct memory_address_range*ranges
|
|
||||||
= new struct memory_address_range[narg/2];
|
|
||||||
|
|
||||||
for (unsigned idx = 0 ; idx < narg ; idx += 2) {
|
|
||||||
ranges[idx/2].msb = args[idx+0];
|
|
||||||
ranges[idx/2].lsb = args[idx+1];
|
|
||||||
}
|
|
||||||
|
|
||||||
memory_configure(mem, msb, lsb, narg/2, ranges);
|
|
||||||
|
|
||||||
delete[]ranges;
|
|
||||||
|
|
||||||
vpiHandle obj = vpip_make_memory(mem, name);
|
|
||||||
compile_vpi_symbol(label, obj);
|
|
||||||
vpip_attach_to_current_scope(obj);
|
|
||||||
|
|
||||||
free(label);
|
|
||||||
free(name);
|
|
||||||
}
|
|
||||||
|
|
||||||
void compile_memory_port(char *label, char *memid,
|
|
||||||
unsigned argc, struct symb_s *argv)
|
|
||||||
{
|
|
||||||
vvp_memory_t mem = memory_find(memid);
|
|
||||||
free(memid);
|
|
||||||
assert(mem);
|
|
||||||
|
|
||||||
vvp_net_t*ptr = new vvp_net_t;
|
|
||||||
vvp_fun_memport*fun = new vvp_fun_memport(mem, ptr);
|
|
||||||
ptr->fun = fun;
|
|
||||||
|
|
||||||
define_functor_symbol(label, ptr);
|
|
||||||
free(label);
|
|
||||||
|
|
||||||
inputs_connect(ptr, argc, argv);
|
|
||||||
free(argv);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* The parser calls this multiple times to parse a .mem/init
|
|
||||||
* statement. The first call includes a memid label and is used to
|
|
||||||
* select the memory and the start address. Subsequent calls contain
|
|
||||||
* only the word value to assign.
|
|
||||||
*/
|
|
||||||
void compile_memory_init(char *memid, unsigned i, long val)
|
|
||||||
{
|
|
||||||
static vvp_memory_t current_mem = 0;
|
|
||||||
static unsigned current_word;
|
|
||||||
|
|
||||||
if (memid) {
|
|
||||||
current_mem = memory_find(memid);
|
|
||||||
free(memid);
|
|
||||||
current_word = i;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
assert(current_mem);
|
|
||||||
|
|
||||||
unsigned word_wid = memory_word_width(current_mem);
|
|
||||||
|
|
||||||
vvp_vector4_t val4 (word_wid);
|
|
||||||
for (unsigned idx = 0 ; idx < word_wid ; idx += 1) {
|
|
||||||
vvp_bit4_t bit = val & 1 ? BIT4_1 : BIT4_0;
|
|
||||||
val4.set_bit(idx, bit);
|
|
||||||
}
|
|
||||||
|
|
||||||
memory_init_word(current_mem, current_word, val4);
|
|
||||||
current_word += 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* The parser uses this function to compile and link an executable
|
* The parser uses this function to compile and link an executable
|
||||||
|
|
@ -1721,15 +1581,6 @@ void compile_code(char*label, char*mnem, comp_operands_t opa)
|
||||||
code->number = opa->argv[idx].numb;
|
code->number = opa->argv[idx].numb;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case OA_MEM_PTR:
|
|
||||||
if (opa->argv[idx].ltype != L_SYMB) {
|
|
||||||
yyerror("operand format");
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
compile_mem_lookup(code, opa->argv[idx].symb.text);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case OA_VPI_PTR:
|
case OA_VPI_PTR:
|
||||||
/* The operand is a functor. Resolve the label to
|
/* The operand is a functor. Resolve the label to
|
||||||
a functor pointer, or postpone the resolution
|
a functor pointer, or postpone the resolution
|
||||||
|
|
|
||||||
|
|
@ -243,6 +243,41 @@ extern void compile_param_logic(char*label, char*name, char*value,
|
||||||
extern void compile_param_real(char*label, char*name, char*value,
|
extern void compile_param_real(char*label, char*name, char*value,
|
||||||
long file_idx, long lineno);
|
long file_idx, long lineno);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The resolv_list_s is the base class for a symbol resolve
|
||||||
|
* action. Some function creates an instance of a resolv_list_s object
|
||||||
|
* that contains the data pertinent to that resolution request, and
|
||||||
|
* executes it with the resolv_submit function. If the operation can
|
||||||
|
* complete, then the resolv_submit deletes the object. Otherwise, it
|
||||||
|
* pushes it onto the resolv_list for later processing.
|
||||||
|
*
|
||||||
|
* Derived classes implement the resolve function to perform the
|
||||||
|
* actual binding or resolution that the instance requires. If the
|
||||||
|
* function succeeds, the resolve method returns true and the object
|
||||||
|
* can be deleted any time.
|
||||||
|
*
|
||||||
|
* The mes parameter of the resolve method tells the resolver that
|
||||||
|
* this call is its last chance. If it cannot complete the operation,
|
||||||
|
* it must print an error message and return false.
|
||||||
|
*/
|
||||||
|
class resolv_list_s {
|
||||||
|
|
||||||
|
public:
|
||||||
|
explicit resolv_list_s(char*lab) : label_(lab) { }
|
||||||
|
virtual ~resolv_list_s();
|
||||||
|
virtual bool resolve(bool mes = false) = 0;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
const char*label() const { return label_; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
friend void ::resolv_submit(struct resolv_list_s*cur);
|
||||||
|
friend void ::compile_cleanup(void);
|
||||||
|
|
||||||
|
char*label_;
|
||||||
|
struct resolv_list_s*next;
|
||||||
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* This function schedules a lookup of an indexed label. The ref
|
* This function schedules a lookup of an indexed label. The ref
|
||||||
* points to the vvp_net_t that receives the result. The result may
|
* points to the vvp_net_t that receives the result. The result may
|
||||||
|
|
@ -295,15 +330,10 @@ extern void compile_net_array(char*label, char*name,
|
||||||
int last, int first);
|
int last, int first);
|
||||||
extern void compile_array_alias(char*label, char*name, char*src);
|
extern void compile_array_alias(char*label, char*name, char*src);
|
||||||
|
|
||||||
|
/* Index is a net. */
|
||||||
extern void compile_array_port(char*label, char*name, char*addr);
|
extern void compile_array_port(char*label, char*name, char*addr);
|
||||||
|
/* Index is a constant address */
|
||||||
extern void compile_memory(char *label, char *name, int lsb, int msb,
|
extern void compile_array_port(char*label, char*name, long addr);
|
||||||
unsigned idxs, long *idx);
|
|
||||||
|
|
||||||
extern void compile_memory_port(char *label, char *memid,
|
|
||||||
unsigned argc, struct symb_s *argv);
|
|
||||||
|
|
||||||
extern void compile_memory_init(char *memid, unsigned idx, long val);
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Compile the .ufunc statement.
|
* Compile the .ufunc statement.
|
||||||
|
|
|
||||||
|
|
@ -5,6 +5,8 @@ AC_PROG_CC
|
||||||
AC_PROG_CXX
|
AC_PROG_CXX
|
||||||
AC_PROG_RANLIB
|
AC_PROG_RANLIB
|
||||||
AC_CHECK_TOOL(STRIP, strip, true)
|
AC_CHECK_TOOL(STRIP, strip, true)
|
||||||
|
AC_CHECK_PROGS(MAN,man,none)
|
||||||
|
AC_CHECK_PROGS(PS2PDF,ps2pdf,none)
|
||||||
|
|
||||||
AC_EXEEXT
|
AC_EXEEXT
|
||||||
AC_SUBST(EXEEXT)
|
AC_SUBST(EXEEXT)
|
||||||
|
|
|
||||||
|
|
@ -161,9 +161,6 @@
|
||||||
".udp" { return K_UDP; }
|
".udp" { return K_UDP; }
|
||||||
".udp/c"(omb)? { return K_UDP_C; }
|
".udp/c"(omb)? { return K_UDP_C; }
|
||||||
".udp/s"(equ)? { return K_UDP_S; }
|
".udp/s"(equ)? { return K_UDP_S; }
|
||||||
".mem" { return K_MEM; }
|
|
||||||
".mem/p"(ort)? { return K_MEM_P; }
|
|
||||||
".mem/i"(nit)? { return K_MEM_I; }
|
|
||||||
"-debug" { return K_DEBUG; }
|
"-debug" { return K_DEBUG; }
|
||||||
|
|
||||||
/* instructions start with a % character. The compiler decides what
|
/* instructions start with a % character. The compiler decides what
|
||||||
|
|
@ -190,6 +187,7 @@
|
||||||
return T_NUMBER; }
|
return T_NUMBER; }
|
||||||
|
|
||||||
|
|
||||||
|
"&A" { return K_A; }
|
||||||
|
|
||||||
/* Handle some specialized constant/literals as symbols. */
|
/* Handle some specialized constant/literals as symbols. */
|
||||||
|
|
||||||
|
|
|
||||||
11
vvp/main.cc
11
vvp/main.cc
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (c) 2001-2007 Stephen Williams (steve@icarus.com)
|
* Copyright (c) 2001-2008 Stephen Williams (steve@icarus.com)
|
||||||
*
|
*
|
||||||
* This source code is free software; you can redistribute it
|
* This source code is free software; you can redistribute it
|
||||||
* and/or modify it in source code form under the terms of the GNU
|
* and/or modify it in source code form under the terms of the GNU
|
||||||
|
|
@ -66,6 +66,12 @@ extern "C" long int lround(double x)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
bool verbose_flag = false;
|
bool verbose_flag = false;
|
||||||
|
static int vvp_return_value = 0;
|
||||||
|
|
||||||
|
void vpip_set_return_value(int value)
|
||||||
|
{
|
||||||
|
vvp_return_value = value;
|
||||||
|
}
|
||||||
|
|
||||||
static char log_buffer[4096];
|
static char log_buffer[4096];
|
||||||
|
|
||||||
|
|
@ -305,6 +311,5 @@ int main(int argc, char*argv[])
|
||||||
count_gen_events);
|
count_gen_events);
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return vvp_return_value;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
299
vvp/memory.cc
299
vvp/memory.cc
|
|
@ -1,299 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright (c) 2005 Stephen Williams (steve@icarus.com)
|
|
||||||
* Copyright (c) 2000 Stephen Williams (steve@icarus.com)
|
|
||||||
* Copyright (c) 2001 Stephan Boettcher <stephan@nevis.columbia.edu>
|
|
||||||
*
|
|
||||||
* This source code is free software; you can redistribute it
|
|
||||||
* and/or modify it in source code form under the terms of the GNU
|
|
||||||
* General Public License as published by the Free Software
|
|
||||||
* Foundation; either version 2 of the License, or (at your option)
|
|
||||||
* any later version.
|
|
||||||
*
|
|
||||||
* This program is distributed in the hope that it will be useful,
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
* GNU General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU General Public License
|
|
||||||
* along with this program; if not, write to the Free Software
|
|
||||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
|
|
||||||
*/
|
|
||||||
#ifdef HAVE_CVS_IDENT
|
|
||||||
#ident "$Id: memory.cc,v 1.29 2006/03/05 05:45:58 steve Exp $"
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#include "memory.h"
|
|
||||||
#include "symbols.h"
|
|
||||||
#include "schedule.h"
|
|
||||||
#include "vpi_priv.h"
|
|
||||||
#include <assert.h>
|
|
||||||
#ifdef HAVE_MALLOC_H
|
|
||||||
#include <malloc.h>
|
|
||||||
#endif
|
|
||||||
#include <stdlib.h>
|
|
||||||
#include <string.h>
|
|
||||||
|
|
||||||
|
|
||||||
typedef struct vvp_memory_port_s *vvp_memory_port_t;
|
|
||||||
|
|
||||||
struct vvp_memory_s
|
|
||||||
{
|
|
||||||
// Address ranges (1 or more)
|
|
||||||
unsigned nrange;
|
|
||||||
struct memory_address_range*ranges;
|
|
||||||
|
|
||||||
// Data port properties:
|
|
||||||
unsigned width; // number of data bits
|
|
||||||
|
|
||||||
int msb, lsb; // Most/Least Significant data bit (VPI)
|
|
||||||
|
|
||||||
// Array of words.
|
|
||||||
unsigned word_count;
|
|
||||||
vvp_vector4_t*words;
|
|
||||||
|
|
||||||
// List of ports into this memory.
|
|
||||||
class vvp_fun_memport* port_list;
|
|
||||||
vpiHandle vpi_self;
|
|
||||||
};
|
|
||||||
|
|
||||||
#define VVP_MEMORY_NO_ADDR ((int)0x80000000)
|
|
||||||
|
|
||||||
// Compilation
|
|
||||||
|
|
||||||
static symbol_table_t memory_table = 0;
|
|
||||||
|
|
||||||
vvp_memory_t memory_find(char *label)
|
|
||||||
{
|
|
||||||
if (memory_table == 0)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
symbol_value_t v = sym_get_value(memory_table, label);
|
|
||||||
return (vvp_memory_t)v.ptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
vvp_memory_t memory_create(char *label)
|
|
||||||
{
|
|
||||||
if (!memory_table)
|
|
||||||
memory_table = new_symbol_table();
|
|
||||||
|
|
||||||
assert(!memory_find(label));
|
|
||||||
|
|
||||||
vvp_memory_t mem = new struct vvp_memory_s;
|
|
||||||
|
|
||||||
symbol_value_t v;
|
|
||||||
v.ptr = mem;
|
|
||||||
sym_set_value(memory_table, label, v);
|
|
||||||
|
|
||||||
return mem;
|
|
||||||
}
|
|
||||||
|
|
||||||
void memory_configure(vvp_memory_t mem,
|
|
||||||
int msb, int lsb,
|
|
||||||
unsigned nrange,
|
|
||||||
const struct memory_address_range*ranges)
|
|
||||||
{
|
|
||||||
/* Get the word width details. */
|
|
||||||
mem->width = msb > lsb ? msb-lsb+1 : lsb-msb+1;
|
|
||||||
mem->msb = msb;
|
|
||||||
mem->lsb = lsb;
|
|
||||||
|
|
||||||
/* Make a private copy of the memory address ranges. */
|
|
||||||
assert(nrange > 0);
|
|
||||||
mem->nrange = nrange;
|
|
||||||
mem->ranges = new struct memory_address_range[nrange];
|
|
||||||
for (unsigned idx = 0 ; idx < nrange ; idx += 1)
|
|
||||||
mem->ranges[idx] = ranges[idx];
|
|
||||||
|
|
||||||
/* Scan the indices (multiplying each range) to add up the
|
|
||||||
total number of words in this memory. */
|
|
||||||
mem->word_count = 1;
|
|
||||||
for (unsigned idx = 0 ; idx < mem->nrange ; idx += 1) {
|
|
||||||
struct memory_address_range*rp = mem->ranges+idx;
|
|
||||||
|
|
||||||
unsigned count = rp->msb > rp->lsb
|
|
||||||
? rp->msb - rp->lsb + 1
|
|
||||||
: rp->lsb - rp->msb + 1;
|
|
||||||
|
|
||||||
mem->word_count *= count;
|
|
||||||
}
|
|
||||||
|
|
||||||
mem->words = new vvp_vector4_t [mem->word_count];
|
|
||||||
assert(mem->words);
|
|
||||||
|
|
||||||
mem->port_list = 0;
|
|
||||||
mem->vpi_self = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
void memory_attach_self(vvp_memory_t mem, vpiHandle self)
|
|
||||||
{
|
|
||||||
assert(mem->vpi_self == 0);
|
|
||||||
mem->vpi_self = self;
|
|
||||||
}
|
|
||||||
|
|
||||||
unsigned memory_word_width(vvp_memory_t mem)
|
|
||||||
{
|
|
||||||
return mem->width;
|
|
||||||
}
|
|
||||||
|
|
||||||
unsigned memory_word_count(vvp_memory_t mem)
|
|
||||||
{
|
|
||||||
return mem->word_count;
|
|
||||||
}
|
|
||||||
|
|
||||||
long memory_word_left_range(vvp_memory_t mem)
|
|
||||||
{
|
|
||||||
return mem->msb;
|
|
||||||
}
|
|
||||||
|
|
||||||
long memory_word_right_range(vvp_memory_t mem)
|
|
||||||
{
|
|
||||||
return mem->lsb;
|
|
||||||
}
|
|
||||||
|
|
||||||
long memory_left_range(vvp_memory_t mem, unsigned ix)
|
|
||||||
{
|
|
||||||
assert(ix < mem->nrange);
|
|
||||||
return mem->ranges[ix].msb;
|
|
||||||
}
|
|
||||||
|
|
||||||
long memory_right_range(vvp_memory_t mem, unsigned ix)
|
|
||||||
{
|
|
||||||
assert(ix < mem->nrange);
|
|
||||||
return mem->ranges[ix].lsb;
|
|
||||||
}
|
|
||||||
|
|
||||||
vvp_vector4_t memory_get_word(vvp_memory_t mem, unsigned addr)
|
|
||||||
{
|
|
||||||
/* If the address is out of range, then return a vector of all
|
|
||||||
X bits. */
|
|
||||||
if (addr >= mem->word_count) {
|
|
||||||
vvp_vector4_t val (mem->width);
|
|
||||||
for (unsigned idx = 0 ; idx < mem->width ; idx += 1)
|
|
||||||
val.set_bit(idx, BIT4_X);
|
|
||||||
return val;
|
|
||||||
}
|
|
||||||
|
|
||||||
assert(addr <= mem->word_count);
|
|
||||||
|
|
||||||
if (mem->words[addr].size() == 0) {
|
|
||||||
vvp_vector4_t tmp (mem->width);
|
|
||||||
for (unsigned idx = 0 ; idx < mem->width ; idx += 1)
|
|
||||||
tmp.set_bit(idx, BIT4_X);
|
|
||||||
mem->words[addr] = tmp;
|
|
||||||
}
|
|
||||||
|
|
||||||
return mem->words[addr];
|
|
||||||
}
|
|
||||||
|
|
||||||
void memory_init_word(vvp_memory_t mem, unsigned addr, vvp_vector4_t val)
|
|
||||||
{
|
|
||||||
if (addr >= mem->word_count)
|
|
||||||
return;
|
|
||||||
|
|
||||||
assert(val.size() == mem->width);
|
|
||||||
mem->words[addr] = val;
|
|
||||||
}
|
|
||||||
|
|
||||||
void memory_set_word(vvp_memory_t mem, unsigned addr,
|
|
||||||
unsigned off, vvp_vector4_t val)
|
|
||||||
{
|
|
||||||
if (addr >= mem->word_count)
|
|
||||||
return;
|
|
||||||
|
|
||||||
if (off >= mem->width)
|
|
||||||
return;
|
|
||||||
|
|
||||||
if (off == 0 && val.size() == mem->width) {
|
|
||||||
mem->words[addr] = val;
|
|
||||||
|
|
||||||
} else {
|
|
||||||
if ((off + val.size()) > mem->width)
|
|
||||||
val = val.subvalue(0, mem->width - off);
|
|
||||||
|
|
||||||
mem->words[addr].set_vec(off, val);
|
|
||||||
}
|
|
||||||
|
|
||||||
for (vvp_fun_memport*cur = mem->port_list
|
|
||||||
; cur ; cur = cur->next_) {
|
|
||||||
cur->check_word_change(addr);
|
|
||||||
}
|
|
||||||
|
|
||||||
vpip_run_memory_value_change(mem->vpi_self, addr);
|
|
||||||
}
|
|
||||||
|
|
||||||
void schedule_memory(vvp_memory_t mem, unsigned addr,
|
|
||||||
vvp_vector4_t val, unsigned long delay)
|
|
||||||
{
|
|
||||||
fprintf(stderr, "XXXX Forgot how to schedule memory write.\n");
|
|
||||||
}
|
|
||||||
|
|
||||||
vvp_fun_memport::vvp_fun_memport(vvp_memory_t mem, vvp_net_t*net)
|
|
||||||
: mem_(mem), net_(net)
|
|
||||||
{
|
|
||||||
addr_ = 0;
|
|
||||||
next_ = mem_->port_list;
|
|
||||||
mem_->port_list = this;
|
|
||||||
}
|
|
||||||
|
|
||||||
vvp_fun_memport::~vvp_fun_memport()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
void vvp_fun_memport::recv_vec4(vvp_net_ptr_t port, const vvp_vector4_t&bit)
|
|
||||||
{
|
|
||||||
bool addr_valid_flag;
|
|
||||||
|
|
||||||
switch (port.port()) {
|
|
||||||
|
|
||||||
case 0: // Address input
|
|
||||||
addr_valid_flag = vector4_to_value(bit, addr_);
|
|
||||||
if (! addr_valid_flag)
|
|
||||||
addr_ = memory_word_count(mem_);
|
|
||||||
vvp_send_vec4(port.ptr()->out, memory_get_word(mem_,addr_));
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
|
||||||
fprintf(stdout, "XXXX write ports not implemented.\n");
|
|
||||||
assert(0);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* This function is called by the memory itself to tell this port that
|
|
||||||
* the given address had a content change. The device itself figures
|
|
||||||
* out what to do with that information.
|
|
||||||
*/
|
|
||||||
void vvp_fun_memport::check_word_change(unsigned long addr)
|
|
||||||
{
|
|
||||||
if (addr != addr_)
|
|
||||||
return;
|
|
||||||
|
|
||||||
vvp_vector4_t bit = memory_get_word(mem_, addr_);
|
|
||||||
vvp_send_vec4(net_->out, bit);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
* $Log: memory.cc,v $
|
|
||||||
* Revision 1.29 2006/03/05 05:45:58 steve
|
|
||||||
* Add support for memory value change callbacks.
|
|
||||||
*
|
|
||||||
* Revision 1.28 2006/02/02 02:44:00 steve
|
|
||||||
* Allow part selects of memory words in l-values.
|
|
||||||
*
|
|
||||||
* Revision 1.27 2005/06/22 00:04:49 steve
|
|
||||||
* Reduce vvp_vector4 copies by using const references.
|
|
||||||
*
|
|
||||||
* Revision 1.26 2005/03/09 04:52:40 steve
|
|
||||||
* reimplement memory ports.
|
|
||||||
*
|
|
||||||
* Revision 1.25 2005/03/06 17:07:48 steve
|
|
||||||
* Non blocking assign to memory words.
|
|
||||||
*
|
|
||||||
* Revision 1.24 2005/03/05 05:44:32 steve
|
|
||||||
* Get read width of unitialized memory words right.
|
|
||||||
*
|
|
||||||
* Revision 1.23 2005/03/03 04:33:10 steve
|
|
||||||
* Rearrange how memories are supported as vvp_vector4 arrays.
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
180
vvp/memory.h
180
vvp/memory.h
|
|
@ -1,180 +0,0 @@
|
||||||
#ifndef __memory_H // -*- c++ -*-
|
|
||||||
#define __memory_H
|
|
||||||
/*
|
|
||||||
* Copyright (c) 2001 Stephen Williams (steve@icarus.com)
|
|
||||||
* Copyright (c) 2001 Stephan Boettcher <stephan@nevis.columbia.edu>
|
|
||||||
*
|
|
||||||
* This source code is free software; you can redistribute it
|
|
||||||
* and/or modify it in source code form under the terms of the GNU
|
|
||||||
* General Public License as published by the Free Software
|
|
||||||
* Foundation; either version 2 of the License, or (at your option)
|
|
||||||
* any later version.
|
|
||||||
*
|
|
||||||
* This program is distributed in the hope that it will be useful,
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
* GNU General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU General Public License
|
|
||||||
* along with this program; if not, write to the Free Software
|
|
||||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
|
|
||||||
*/
|
|
||||||
#ifdef HAVE_CVS_IDENT
|
|
||||||
#ident "$Id: memory.h,v 1.13 2007/03/22 16:08:19 steve Exp $"
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#include "vvp_net.h"
|
|
||||||
#include "vpi_user.h"
|
|
||||||
|
|
||||||
/*
|
|
||||||
** vvp_memory_t is a memory
|
|
||||||
** vvp_memory_index_t is a memory index range definition
|
|
||||||
*/
|
|
||||||
typedef struct vvp_memory_s *vvp_memory_t;
|
|
||||||
|
|
||||||
struct memory_address_range {
|
|
||||||
int msb;
|
|
||||||
int lsb;
|
|
||||||
};
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Given a memory device, the memory_configure function configures it
|
|
||||||
* by defining the dimensions of the device. It is an error to
|
|
||||||
* redefine the dimensions of a device already configured.
|
|
||||||
*
|
|
||||||
* The lsb and msb define the dimensions of a word. They are in
|
|
||||||
* Verilog form. The actual word contents are vvp_vector4_t values.
|
|
||||||
*
|
|
||||||
* The idx array is an array of address ranges that describe the
|
|
||||||
* complete multi-dimensional array. In a normal Verilog array, idxs
|
|
||||||
* is 1, and idx is a pointer to a single memory_address_range. The
|
|
||||||
* table does not need to be persistent.
|
|
||||||
*/
|
|
||||||
extern void memory_configure(vvp_memory_t mem, int msb, int lsb,
|
|
||||||
unsigned idxs,
|
|
||||||
const struct memory_address_range *idx);
|
|
||||||
extern void memory_attach_self(vvp_memory_t mem, vpiHandle self);
|
|
||||||
|
|
||||||
/*
|
|
||||||
* init_word and set_word functions take the memory to be manipulated
|
|
||||||
* and write a word value at the given word address. The idx is the
|
|
||||||
* canonical (0-based, 1-dimensional) address of the word to be
|
|
||||||
* written. The caller needs to have converted any multi-dimensional
|
|
||||||
* address into a canonical address first.
|
|
||||||
*
|
|
||||||
* The difference between init_word and set_word are that the set_word
|
|
||||||
* function causes values to be propagated through structural ports,
|
|
||||||
* but the init_word does not.
|
|
||||||
*/
|
|
||||||
extern void memory_init_word(vvp_memory_t mem,
|
|
||||||
unsigned idx,
|
|
||||||
vvp_vector4_t val);
|
|
||||||
extern void memory_set_word(vvp_memory_t mem,
|
|
||||||
unsigned idx,
|
|
||||||
unsigned off,
|
|
||||||
vvp_vector4_t val);
|
|
||||||
|
|
||||||
/*
|
|
||||||
* This doesn't actually write the value to the memory word, but
|
|
||||||
* schedules for the write to happen some time in the future. The delay
|
|
||||||
* is in simulation clock units.
|
|
||||||
*/
|
|
||||||
void schedule_memory(vvp_memory_t mem, unsigned addr,
|
|
||||||
vvp_vector4_t val, unsigned long delay);
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Get the word value at the given index into the memory.
|
|
||||||
*/
|
|
||||||
extern vvp_vector4_t memory_get_word(vvp_memory_t mem, unsigned idx);
|
|
||||||
|
|
||||||
|
|
||||||
/* Number of words in the memory. */
|
|
||||||
unsigned memory_word_count(vvp_memory_t mem);
|
|
||||||
/* Width of a word */
|
|
||||||
unsigned memory_word_width(vvp_memory_t mem);
|
|
||||||
/* Get the user declared geometry of the memory address. This is the
|
|
||||||
msb and lsb values for each pair in the multi-dimensional array. */
|
|
||||||
long memory_left_range(vvp_memory_t mem, unsigned ix);
|
|
||||||
long memory_right_range(vvp_memory_t mem, unsigned ix);
|
|
||||||
/* Get the user defined geometry for the memory *word*. */
|
|
||||||
long memory_word_left_range(vvp_memory_t mem);
|
|
||||||
long memory_word_right_range(vvp_memory_t mem);
|
|
||||||
|
|
||||||
|
|
||||||
/* vvp_fun_memport
|
|
||||||
* The vvp_fum_memport is a structural port into a vvp_memory_t
|
|
||||||
* object. The output is the word that is read from the addressed
|
|
||||||
* memory, and the inputs are the address and optional write controls.
|
|
||||||
*
|
|
||||||
* 0 -- Address
|
|
||||||
* This addresses the word in the memory. The output follows this
|
|
||||||
* address as it changes, and also follows the value of the addressed
|
|
||||||
* word.
|
|
||||||
*
|
|
||||||
* 1 -- Write event
|
|
||||||
*
|
|
||||||
* 2 -- Write enable
|
|
||||||
*
|
|
||||||
* 3 -- Write data
|
|
||||||
*
|
|
||||||
* NOTE: This functor is unique in that it needs to store the
|
|
||||||
* vvp_net_t pointer associated with it. It needs this because it can
|
|
||||||
* received input from other than its ports. Notably, the memory
|
|
||||||
* itself reports word changes.
|
|
||||||
*/
|
|
||||||
class vvp_fun_memport : public vvp_net_fun_t {
|
|
||||||
|
|
||||||
public:
|
|
||||||
explicit vvp_fun_memport(vvp_memory_t mem, vvp_net_t*net);
|
|
||||||
~vvp_fun_memport();
|
|
||||||
|
|
||||||
void recv_vec4(vvp_net_ptr_t port, const vvp_vector4_t&bit);
|
|
||||||
|
|
||||||
private:
|
|
||||||
vvp_memory_t mem_;
|
|
||||||
|
|
||||||
friend void memory_set_word(vvp_memory_t, unsigned,
|
|
||||||
unsigned, vvp_vector4_t);
|
|
||||||
void check_word_change(unsigned long address);
|
|
||||||
class vvp_fun_memport*next_;
|
|
||||||
|
|
||||||
unsigned long addr_;
|
|
||||||
|
|
||||||
vvp_net_t*net_;
|
|
||||||
};
|
|
||||||
|
|
||||||
/*
|
|
||||||
** Access to the memory symbol table.
|
|
||||||
**
|
|
||||||
** The memory_find function locates the memory device by name. If the
|
|
||||||
** device does not exist, a nil is returned.
|
|
||||||
**
|
|
||||||
** The memory_create function creates a new memory device with the given
|
|
||||||
** name. It is a fatal error to try to create a device that already exists.
|
|
||||||
*/
|
|
||||||
vvp_memory_t memory_find(char *label);
|
|
||||||
vvp_memory_t memory_create(char *label);
|
|
||||||
|
|
||||||
/*
|
|
||||||
* $Log: memory.h,v $
|
|
||||||
* Revision 1.13 2007/03/22 16:08:19 steve
|
|
||||||
* Spelling fixes from Larry
|
|
||||||
*
|
|
||||||
* Revision 1.12 2006/03/05 05:45:58 steve
|
|
||||||
* Add support for memory value change callbacks.
|
|
||||||
*
|
|
||||||
* Revision 1.11 2006/02/02 02:44:00 steve
|
|
||||||
* Allow part selects of memory words in l-values.
|
|
||||||
*
|
|
||||||
* Revision 1.10 2005/06/22 00:04:49 steve
|
|
||||||
* Reduce vvp_vector4 copies by using const references.
|
|
||||||
*
|
|
||||||
* Revision 1.9 2005/03/09 04:52:40 steve
|
|
||||||
* reimplement memory ports.
|
|
||||||
*
|
|
||||||
* Revision 1.8 2005/03/03 04:33:10 steve
|
|
||||||
* Rearrange how memories are supported as vvp_vector4 arrays.
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
#endif
|
|
||||||
89
vvp/parse.y
89
vvp/parse.y
|
|
@ -65,7 +65,7 @@ static struct __vpiModPath*modpath_dst = 0;
|
||||||
vvp_delay_t*cdelay;
|
vvp_delay_t*cdelay;
|
||||||
};
|
};
|
||||||
|
|
||||||
%token K_ALIAS K_ALIAS_S K_ALIAS_R
|
%token K_A K_ALIAS K_ALIAS_S K_ALIAS_R
|
||||||
%token K_ARITH_ABS K_ARITH_DIV K_ARITH_DIV_R K_ARITH_DIV_S K_ARITH_MOD
|
%token K_ARITH_ABS K_ARITH_DIV K_ARITH_DIV_R K_ARITH_DIV_S K_ARITH_MOD
|
||||||
%token K_ARITH_MOD_R
|
%token K_ARITH_MOD_R
|
||||||
%token K_ARITH_MULT K_ARITH_MULT_R K_ARITH_SUB K_ARITH_SUB_R
|
%token K_ARITH_MULT K_ARITH_MULT_R K_ARITH_SUB K_ARITH_SUB_R
|
||||||
|
|
@ -82,7 +82,6 @@ static struct __vpiModPath*modpath_dst = 0;
|
||||||
%token K_RESOLV K_SCOPE K_SFUNC K_SHIFTL K_SHIFTR K_SHIFTRS
|
%token K_RESOLV K_SCOPE K_SFUNC K_SHIFTL K_SHIFTR K_SHIFTRS
|
||||||
%token K_THREAD K_TIMESCALE K_UFUNC
|
%token K_THREAD K_TIMESCALE K_UFUNC
|
||||||
%token K_UDP K_UDP_C K_UDP_S
|
%token K_UDP K_UDP_C K_UDP_S
|
||||||
%token K_MEM K_MEM_P K_MEM_I
|
|
||||||
%token K_VAR K_VAR_S K_VAR_I K_VAR_R K_vpi_call K_vpi_func K_vpi_func_r
|
%token K_VAR K_VAR_S K_VAR_I K_VAR_R K_vpi_call K_vpi_func K_vpi_func_r
|
||||||
%token K_disable K_fork
|
%token K_disable K_fork
|
||||||
%token K_vpi_module K_vpi_time_precision K_file_names
|
%token K_vpi_module K_vpi_time_precision K_file_names
|
||||||
|
|
@ -185,14 +184,6 @@ statement
|
||||||
|
|
||||||
/* Memory. Definition, port, initialization */
|
/* Memory. Definition, port, initialization */
|
||||||
|
|
||||||
| T_LABEL K_MEM T_STRING ',' T_NUMBER ',' T_NUMBER ',' numbers ';'
|
|
||||||
{ compile_memory($1, $3, $5, $7, $9.cnt, $9.nvec); }
|
|
||||||
|
|
||||||
| T_LABEL K_MEM_P T_SYMBOL ',' symbols ';'
|
|
||||||
{ compile_memory_port($1, $3, $5.cnt, $5.vect); }
|
|
||||||
|
|
||||||
| mem_init_stmt
|
|
||||||
|
|
||||||
| T_LABEL K_ARRAY T_STRING ',' signed_t_number signed_t_number ',' signed_t_number signed_t_number ';'
|
| T_LABEL K_ARRAY T_STRING ',' signed_t_number signed_t_number ',' signed_t_number signed_t_number ';'
|
||||||
{ compile_var_array($1, $3, $5, $6, $8, $9, 0); }
|
{ compile_var_array($1, $3, $5, $6, $8, $9, 0); }
|
||||||
|
|
||||||
|
|
@ -211,6 +202,9 @@ statement
|
||||||
| T_LABEL K_ARRAY_PORT T_SYMBOL ',' T_SYMBOL ';'
|
| T_LABEL K_ARRAY_PORT T_SYMBOL ',' T_SYMBOL ';'
|
||||||
{ compile_array_port($1, $3, $5); }
|
{ compile_array_port($1, $3, $5); }
|
||||||
|
|
||||||
|
| T_LABEL K_ARRAY_PORT T_SYMBOL ',' T_NUMBER ';'
|
||||||
|
{ compile_array_port($1, $3, $5); }
|
||||||
|
|
||||||
| T_LABEL K_ARRAY T_STRING ',' T_SYMBOL ';'
|
| T_LABEL K_ARRAY T_STRING ',' T_SYMBOL ';'
|
||||||
{ compile_array_alias($1, $3, $5); }
|
{ compile_array_alias($1, $3, $5); }
|
||||||
|
|
||||||
|
|
@ -763,38 +757,40 @@ argument_opt
|
||||||
;
|
;
|
||||||
|
|
||||||
argument_list
|
argument_list
|
||||||
: argument
|
: argument
|
||||||
{ struct argv_s tmp;
|
{ struct argv_s tmp;
|
||||||
argv_init(&tmp);
|
argv_init(&tmp);
|
||||||
argv_add(&tmp, $1);
|
argv_add(&tmp, $1);
|
||||||
$$ = tmp;
|
$$ = tmp;
|
||||||
}
|
}
|
||||||
| argument_list ',' argument
|
| argument_list ',' argument
|
||||||
{ struct argv_s tmp = $1;
|
{ struct argv_s tmp = $1;
|
||||||
argv_add(&tmp, $3);
|
argv_add(&tmp, $3);
|
||||||
$$ = tmp;
|
$$ = tmp;
|
||||||
}
|
}
|
||||||
| T_SYMBOL
|
| T_SYMBOL
|
||||||
{ struct argv_s tmp;
|
{ struct argv_s tmp;
|
||||||
argv_init(&tmp);
|
argv_init(&tmp);
|
||||||
argv_sym_add(&tmp, $1);
|
argv_sym_add(&tmp, $1);
|
||||||
$$ = tmp;
|
$$ = tmp;
|
||||||
}
|
}
|
||||||
| argument_list ',' T_SYMBOL
|
| argument_list ',' T_SYMBOL
|
||||||
{ struct argv_s tmp = $1;
|
{ struct argv_s tmp = $1;
|
||||||
argv_sym_add(&tmp, $3);
|
argv_sym_add(&tmp, $3);
|
||||||
$$ = tmp;
|
$$ = tmp;
|
||||||
}
|
}
|
||||||
;
|
;
|
||||||
|
|
||||||
argument
|
argument
|
||||||
: T_STRING
|
: T_STRING
|
||||||
{ $$ = vpip_make_string_const($1); }
|
{ $$ = vpip_make_string_const($1); }
|
||||||
| T_VECTOR
|
| T_VECTOR
|
||||||
{ $$ = vpip_make_binary_const($1.idx, $1.text);
|
{ $$ = vpip_make_binary_const($1.idx, $1.text);
|
||||||
free($1.text);
|
free($1.text);
|
||||||
}
|
}
|
||||||
;
|
| K_A '<' T_SYMBOL ',' T_NUMBER '>'
|
||||||
|
{ $$ = vpip_make_vthr_A($3, $5); }
|
||||||
|
;
|
||||||
|
|
||||||
|
|
||||||
/* functor operands can only be a list of symbols. */
|
/* functor operands can only be a list of symbols. */
|
||||||
|
|
@ -899,19 +895,6 @@ udp_table
|
||||||
{ $$ = compile_udp_table($1, $3); }
|
{ $$ = compile_udp_table($1, $3); }
|
||||||
;
|
;
|
||||||
|
|
||||||
mem_init_stmt
|
|
||||||
: K_MEM_I symbol T_NUMBER ','
|
|
||||||
{ compile_memory_init($2.text, $3, 0); }
|
|
||||||
mem_init_list ';'
|
|
||||||
;
|
|
||||||
|
|
||||||
mem_init_list
|
|
||||||
: mem_init_list ',' T_NUMBER
|
|
||||||
{ compile_memory_init(0, 0, $3); }
|
|
||||||
| T_NUMBER
|
|
||||||
{ compile_memory_init(0, 0, $1); }
|
|
||||||
;
|
|
||||||
|
|
||||||
signed_t_number
|
signed_t_number
|
||||||
: T_NUMBER { $$ = $1; }
|
: T_NUMBER { $$ = $1; }
|
||||||
| '-' T_NUMBER { $$ = -$2; }
|
| '-' T_NUMBER { $$ = -$2; }
|
||||||
|
|
|
||||||
|
|
@ -18,7 +18,6 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
# include "schedule.h"
|
# include "schedule.h"
|
||||||
# include "memory.h"
|
|
||||||
# include "vthread.h"
|
# include "vthread.h"
|
||||||
#ifdef HAVE_MALLOC_H
|
#ifdef HAVE_MALLOC_H
|
||||||
# include <malloc.h>
|
# include <malloc.h>
|
||||||
|
|
@ -141,20 +140,6 @@ void assign_real_event_s::run_run(void)
|
||||||
vvp_send_real(ptr, val);
|
vvp_send_real(ptr, val);
|
||||||
}
|
}
|
||||||
|
|
||||||
struct assign_memory_word_s : public event_s {
|
|
||||||
vvp_memory_t mem;
|
|
||||||
unsigned adr;
|
|
||||||
vvp_vector4_t val;
|
|
||||||
unsigned off;
|
|
||||||
void run_run(void);
|
|
||||||
};
|
|
||||||
|
|
||||||
void assign_memory_word_s::run_run(void)
|
|
||||||
{
|
|
||||||
count_assign_events += 1;
|
|
||||||
memory_set_word(mem, adr, off, val);
|
|
||||||
}
|
|
||||||
|
|
||||||
struct assign_array_word_s : public event_s {
|
struct assign_array_word_s : public event_s {
|
||||||
vvp_array_t mem;
|
vvp_array_t mem;
|
||||||
unsigned adr;
|
unsigned adr;
|
||||||
|
|
@ -500,20 +485,6 @@ void schedule_assign_vector(vvp_net_ptr_t ptr,
|
||||||
schedule_event_(cur, delay, SEQ_NBASSIGN);
|
schedule_event_(cur, delay, SEQ_NBASSIGN);
|
||||||
}
|
}
|
||||||
|
|
||||||
void schedule_assign_memory_word(vvp_memory_t mem,
|
|
||||||
unsigned word_addr,
|
|
||||||
unsigned off,
|
|
||||||
vvp_vector4_t val,
|
|
||||||
vvp_time64_t delay)
|
|
||||||
{
|
|
||||||
struct assign_memory_word_s*cur = new struct assign_memory_word_s;
|
|
||||||
cur->mem = mem;
|
|
||||||
cur->adr = word_addr;
|
|
||||||
cur->off = off;
|
|
||||||
cur->val = val;
|
|
||||||
schedule_event_(cur, delay, SEQ_NBASSIGN);
|
|
||||||
}
|
|
||||||
|
|
||||||
void schedule_assign_array_word(vvp_array_t mem,
|
void schedule_assign_array_word(vvp_array_t mem,
|
||||||
unsigned word_addr,
|
unsigned word_addr,
|
||||||
unsigned off,
|
unsigned off,
|
||||||
|
|
|
||||||
|
|
@ -22,7 +22,6 @@
|
||||||
# include "vthread.h"
|
# include "vthread.h"
|
||||||
# include "pointers.h"
|
# include "pointers.h"
|
||||||
# include "vvp_net.h"
|
# include "vvp_net.h"
|
||||||
# include "memory.h"
|
|
||||||
# include "array.h"
|
# include "array.h"
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
@ -57,11 +56,6 @@ extern void schedule_assign_array_word(vvp_array_t mem,
|
||||||
unsigned off,
|
unsigned off,
|
||||||
vvp_vector4_t val,
|
vvp_vector4_t val,
|
||||||
vvp_time64_t delay);
|
vvp_time64_t delay);
|
||||||
extern void schedule_assign_memory_word(vvp_memory_t mem,
|
|
||||||
unsigned word_address,
|
|
||||||
unsigned off,
|
|
||||||
vvp_vector4_t val,
|
|
||||||
vvp_time64_t delay);
|
|
||||||
/*
|
/*
|
||||||
* This is very similar to schedule_assign_vector, but generates an
|
* This is very similar to schedule_assign_vector, but generates an
|
||||||
* event in the active queue. It is used at link time to assign a
|
* event in the active queue. It is used at link time to assign a
|
||||||
|
|
|
||||||
10
vvp/udp.cc
10
vvp/udp.cc
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (c) 2005-2007 Stephen Williams (steve@icarus.com)
|
* Copyright (c) 2005-2008 Stephen Williams (steve@icarus.com)
|
||||||
*
|
*
|
||||||
* (This is a rewrite of code that was ...
|
* (This is a rewrite of code that was ...
|
||||||
* Copyright (c) 2001 Stephan Boettcher <stephan@nevis.columbia.edu>)
|
* Copyright (c) 2001 Stephan Boettcher <stephan@nevis.columbia.edu>)
|
||||||
|
|
@ -19,9 +19,6 @@
|
||||||
* along with this program; if not, write to the Free Software
|
* along with this program; if not, write to the Free Software
|
||||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
|
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
|
||||||
*/
|
*/
|
||||||
#ifdef HAVE_CVS_IDENT
|
|
||||||
#ident "$Id: udp.cc,v 1.35 2007/03/04 06:26:33 steve Exp $"
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#include "udp.h"
|
#include "udp.h"
|
||||||
#include "schedule.h"
|
#include "schedule.h"
|
||||||
|
|
@ -228,7 +225,11 @@ void vvp_udp_comb_s::compile_table(char**tab)
|
||||||
cur.maskx = 0;
|
cur.maskx = 0;
|
||||||
if (port_count() > 8*sizeof(cur.mask0)) {
|
if (port_count() > 8*sizeof(cur.mask0)) {
|
||||||
fprintf(stderr, "internal error: primitive port count=%u "
|
fprintf(stderr, "internal error: primitive port count=%u "
|
||||||
|
#ifdef __MINGW32__ /* MinGW does not know about z. */
|
||||||
|
" > %u\n", port_count(), sizeof(cur.mask0));
|
||||||
|
#else
|
||||||
" > %zu\n", port_count(), sizeof(cur.mask0));
|
" > %zu\n", port_count(), sizeof(cur.mask0));
|
||||||
|
#endif
|
||||||
assert(port_count() <= 8*sizeof(cur.mask0));
|
assert(port_count() <= 8*sizeof(cur.mask0));
|
||||||
}
|
}
|
||||||
for (unsigned pp = 0 ; pp < port_count() ; pp += 1) {
|
for (unsigned pp = 0 ; pp < port_count() ; pp += 1) {
|
||||||
|
|
@ -954,4 +955,3 @@ void compile_udp_functor(char*label, char*type,
|
||||||
wide_inputs_connect(core, argc, argv);
|
wide_inputs_connect(core, argc, argv);
|
||||||
free(argv);
|
free(argv);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -103,7 +103,7 @@ struct __vpiCallback* new_vpi_callback()
|
||||||
return obj;
|
return obj;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void delete_vpi_callback(struct __vpiCallback* ref)
|
void delete_vpi_callback(struct __vpiCallback* ref)
|
||||||
{
|
{
|
||||||
assert(ref);
|
assert(ref);
|
||||||
assert(ref->base.vpi_type);
|
assert(ref->base.vpi_type);
|
||||||
|
|
@ -162,8 +162,8 @@ static struct __vpiCallback* make_value_change(p_cb_data data)
|
||||||
nev->callbacks = obj;
|
nev->callbacks = obj;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case vpiMemory:
|
case vpiMemoryWord:
|
||||||
vpip_memory_value_change(obj, data->obj);
|
vpip_array_word_change(obj, data->obj);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case vpiModule:
|
case vpiModule:
|
||||||
|
|
@ -465,14 +465,11 @@ void callback_execute(struct __vpiCallback*cur)
|
||||||
vvp_vpi_callback::vvp_vpi_callback()
|
vvp_vpi_callback::vvp_vpi_callback()
|
||||||
{
|
{
|
||||||
vpi_callbacks_ = 0;
|
vpi_callbacks_ = 0;
|
||||||
array_ = 0;
|
|
||||||
array_word_ = 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
vvp_vpi_callback::~vvp_vpi_callback()
|
vvp_vpi_callback::~vvp_vpi_callback()
|
||||||
{
|
{
|
||||||
assert(vpi_callbacks_ == 0);
|
assert(vpi_callbacks_ == 0);
|
||||||
assert(array_ == 0);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void vvp_vpi_callback::add_vpi_callback(__vpiCallback*cb)
|
void vvp_vpi_callback::add_vpi_callback(__vpiCallback*cb)
|
||||||
|
|
@ -481,13 +478,6 @@ void vvp_vpi_callback::add_vpi_callback(__vpiCallback*cb)
|
||||||
vpi_callbacks_ = cb;
|
vpi_callbacks_ = cb;
|
||||||
}
|
}
|
||||||
|
|
||||||
void vvp_vpi_callback::attach_as_word(vvp_array_t arr, unsigned long addr)
|
|
||||||
{
|
|
||||||
assert(array_ == 0);
|
|
||||||
array_ = arr;
|
|
||||||
array_word_ = addr;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* A vvp_fun_signal uses this method to run its callbacks whenever it
|
* A vvp_fun_signal uses this method to run its callbacks whenever it
|
||||||
* has a value change. If the cb_rtn is non-nil, then call the
|
* has a value change. If the cb_rtn is non-nil, then call the
|
||||||
|
|
@ -499,8 +489,6 @@ void vvp_vpi_callback::run_vpi_callbacks()
|
||||||
struct __vpiCallback *next = vpi_callbacks_;
|
struct __vpiCallback *next = vpi_callbacks_;
|
||||||
struct __vpiCallback *prev = 0;
|
struct __vpiCallback *prev = 0;
|
||||||
|
|
||||||
if (array_) array_word_change(array_, array_word_);
|
|
||||||
|
|
||||||
while (next) {
|
while (next) {
|
||||||
struct __vpiCallback*cur = next;
|
struct __vpiCallback*cur = next;
|
||||||
next = cur->next;
|
next = cur->next;
|
||||||
|
|
@ -527,6 +515,31 @@ void vvp_vpi_callback::run_vpi_callbacks()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
vvp_vpi_callback_wordable::vvp_vpi_callback_wordable()
|
||||||
|
{
|
||||||
|
array_ = 0;
|
||||||
|
array_word_ = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
vvp_vpi_callback_wordable::~vvp_vpi_callback_wordable()
|
||||||
|
{
|
||||||
|
assert(array_ == 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
void vvp_vpi_callback_wordable::run_vpi_callbacks()
|
||||||
|
{
|
||||||
|
if (array_) array_word_change(array_, array_word_);
|
||||||
|
|
||||||
|
vvp_vpi_callback::run_vpi_callbacks();
|
||||||
|
}
|
||||||
|
|
||||||
|
void vvp_vpi_callback_wordable::attach_as_word(vvp_array_t arr, unsigned long addr)
|
||||||
|
{
|
||||||
|
assert(array_ == 0);
|
||||||
|
array_ = arr;
|
||||||
|
array_word_ = addr;
|
||||||
|
}
|
||||||
|
|
||||||
void vvp_fun_signal::get_value(struct t_vpi_value*vp)
|
void vvp_fun_signal::get_value(struct t_vpi_value*vp)
|
||||||
{
|
{
|
||||||
switch (vp->format) {
|
switch (vp->format) {
|
||||||
|
|
|
||||||
|
|
@ -152,7 +152,15 @@ vpi_mcd_vprintf(PLI_UINT32 mcd, const char*fmt, va_list ap)
|
||||||
mcd, fmt);
|
mcd, fmt);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef __MINGW32__
|
||||||
|
/*
|
||||||
|
* The MinGW runtime (version 3.14) fixes some things, but breaks
|
||||||
|
* %f for us, so we have to us the underlying version.
|
||||||
|
*/
|
||||||
|
rc = _vsnprintf(buffer, sizeof buffer, fmt, ap);
|
||||||
|
#else
|
||||||
rc = vsnprintf(buffer, sizeof buffer, fmt, ap);
|
rc = vsnprintf(buffer, sizeof buffer, fmt, ap);
|
||||||
|
#endif
|
||||||
|
|
||||||
for(int i = 0; i < 31; i++) {
|
for(int i = 0; i < 31; i++) {
|
||||||
if((mcd>>i) & 1) {
|
if((mcd>>i) & 1) {
|
||||||
|
|
|
||||||
|
|
@ -1,449 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright (c) 1999-2007 Stephen Williams (steve@icarus.com>
|
|
||||||
* Copyright (c) 2001 Stephan Boettcher <stephan@nevis.columbia.edu>
|
|
||||||
*
|
|
||||||
* This source code is free software; you can redistribute it
|
|
||||||
* and/or modify it in source code form under the terms of the GNU
|
|
||||||
* General Public License as published by the Free Software
|
|
||||||
* Foundation; either version 2 of the License, or (at your option)
|
|
||||||
* any later version.
|
|
||||||
*
|
|
||||||
* This program is distributed in the hope that it will be useful,
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
* GNU General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU General Public License
|
|
||||||
* along with this program; if not, write to the Free Software
|
|
||||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
|
|
||||||
*/
|
|
||||||
|
|
||||||
# include "compile.h"
|
|
||||||
# include "vpi_priv.h"
|
|
||||||
# include "memory.h"
|
|
||||||
# include "statistics.h"
|
|
||||||
# include <iostream>
|
|
||||||
# include <stdlib.h>
|
|
||||||
# include <string.h>
|
|
||||||
# include <assert.h>
|
|
||||||
|
|
||||||
# include <stdio.h>
|
|
||||||
|
|
||||||
extern const char hex_digits[256];
|
|
||||||
|
|
||||||
static void memory_make_word_handles(struct __vpiMemory*rfp);
|
|
||||||
|
|
||||||
struct __vpiMemoryWord {
|
|
||||||
struct __vpiHandle base;
|
|
||||||
struct __vpiMemory*mem;
|
|
||||||
struct __vpiDecConst index;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct __vpiMemory {
|
|
||||||
struct __vpiHandle base;
|
|
||||||
struct __vpiScope* scope;
|
|
||||||
struct __vpiMemoryWord*words;
|
|
||||||
vvp_memory_t mem;
|
|
||||||
const char*name; /* Permanently allocated string. */
|
|
||||||
struct __vpiDecConst left_range;
|
|
||||||
struct __vpiDecConst right_range;
|
|
||||||
struct __vpiDecConst word_left_range;
|
|
||||||
struct __vpiDecConst word_right_range;
|
|
||||||
|
|
||||||
struct __vpiCallback*value_change_cb;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct __vpiMemWordIterator {
|
|
||||||
struct __vpiHandle base;
|
|
||||||
struct __vpiMemory*mem;
|
|
||||||
unsigned next;
|
|
||||||
};
|
|
||||||
|
|
||||||
static vpiHandle memory_get_handle(int code, vpiHandle obj)
|
|
||||||
{
|
|
||||||
struct __vpiMemory*rfp = (struct __vpiMemory*)obj;
|
|
||||||
|
|
||||||
assert(obj->vpi_type->type_code==vpiMemory);
|
|
||||||
|
|
||||||
switch(code){
|
|
||||||
case vpiLeftRange:
|
|
||||||
return &(rfp->left_range.base);
|
|
||||||
|
|
||||||
case vpiRightRange:
|
|
||||||
return &(rfp->right_range.base);
|
|
||||||
|
|
||||||
case vpiScope:
|
|
||||||
return &rfp->scope->base;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int vpi_memory_get(int code, vpiHandle ref)
|
|
||||||
{
|
|
||||||
struct __vpiMemory*rfp = (struct __vpiMemory*)ref;
|
|
||||||
|
|
||||||
assert(ref->vpi_type->type_code==vpiMemory);
|
|
||||||
|
|
||||||
switch (code) {
|
|
||||||
case vpiSize:
|
|
||||||
return (int)memory_word_count(rfp->mem);
|
|
||||||
|
|
||||||
default:
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static char* memory_get_str(int code, vpiHandle ref)
|
|
||||||
{
|
|
||||||
assert(ref->vpi_type->type_code==vpiMemory);
|
|
||||||
|
|
||||||
struct __vpiMemory*rfp = (struct __vpiMemory*)ref;
|
|
||||||
|
|
||||||
if (code == vpiFile) { // Not implemented for now!
|
|
||||||
return simple_set_rbuf_str(file_names[0]);
|
|
||||||
}
|
|
||||||
return generic_get_str(code, &rfp->scope->base, rfp->name, NULL);
|
|
||||||
}
|
|
||||||
|
|
||||||
static vpiHandle memory_scan(vpiHandle ref, int)
|
|
||||||
{
|
|
||||||
struct __vpiMemWordIterator*obj = (struct __vpiMemWordIterator*)ref;
|
|
||||||
assert(ref->vpi_type->type_code == vpiIterator);
|
|
||||||
|
|
||||||
if (obj->next >= memory_word_count(obj->mem->mem)) {
|
|
||||||
vpi_free_object(ref);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
return &obj->mem->words[obj->next++].base;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int mem_iter_free_object(vpiHandle ref)
|
|
||||||
{
|
|
||||||
free(ref);
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
static const struct __vpirt vpip_mem_iter_rt = {
|
|
||||||
vpiIterator,
|
|
||||||
0,
|
|
||||||
0,
|
|
||||||
0,
|
|
||||||
0,
|
|
||||||
0,
|
|
||||||
0,
|
|
||||||
memory_scan,
|
|
||||||
&mem_iter_free_object
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
static vpiHandle memory_iterate(int code, vpiHandle ref)
|
|
||||||
{
|
|
||||||
struct __vpiMemory*rfp = (struct __vpiMemory*)ref;
|
|
||||||
assert(ref->vpi_type->type_code==vpiMemory);
|
|
||||||
|
|
||||||
switch (code) {
|
|
||||||
case vpiMemoryWord: {
|
|
||||||
memory_make_word_handles(rfp);
|
|
||||||
|
|
||||||
struct __vpiMemWordIterator*res =
|
|
||||||
(struct __vpiMemWordIterator*)
|
|
||||||
calloc(1, sizeof(struct __vpiMemWordIterator));
|
|
||||||
assert(res);
|
|
||||||
res->base.vpi_type = &vpip_mem_iter_rt;
|
|
||||||
res->mem = rfp;
|
|
||||||
res->next = 0;
|
|
||||||
return &(res->base);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static vpiHandle memory_index(vpiHandle ref, int index)
|
|
||||||
{
|
|
||||||
struct __vpiMemory*rfp = (struct __vpiMemory*)ref;
|
|
||||||
assert(ref->vpi_type->type_code==vpiMemory);
|
|
||||||
|
|
||||||
if (index >= (int)memory_word_count(rfp->mem))
|
|
||||||
return 0;
|
|
||||||
if (index < 0)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
memory_make_word_handles(rfp);
|
|
||||||
return &(rfp->words[index].base);
|
|
||||||
}
|
|
||||||
|
|
||||||
//==============================
|
|
||||||
|
|
||||||
static vpiHandle memory_word_get_handle(int code, vpiHandle obj)
|
|
||||||
{
|
|
||||||
struct __vpiMemoryWord*rfp = (struct __vpiMemoryWord*)obj;
|
|
||||||
assert(obj->vpi_type->type_code==vpiMemoryWord);
|
|
||||||
|
|
||||||
switch(code){
|
|
||||||
case vpiLeftRange:
|
|
||||||
return &(rfp->mem->word_left_range.base);
|
|
||||||
|
|
||||||
case vpiRightRange:
|
|
||||||
return &(rfp->mem->word_right_range.base);
|
|
||||||
|
|
||||||
case vpiIndex:
|
|
||||||
return &(rfp->index.base);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int memory_word_get(int code, vpiHandle ref)
|
|
||||||
{
|
|
||||||
struct __vpiMemoryWord*rfp = (struct __vpiMemoryWord*)ref;
|
|
||||||
assert(ref->vpi_type->type_code==vpiMemoryWord);
|
|
||||||
|
|
||||||
switch (code) {
|
|
||||||
case vpiSize:
|
|
||||||
return memory_word_width(rfp->mem->mem);
|
|
||||||
|
|
||||||
default:
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static vpiHandle memory_word_put(vpiHandle ref, p_vpi_value val, int)
|
|
||||||
{
|
|
||||||
struct __vpiMemoryWord*rfp = (struct __vpiMemoryWord*)ref;
|
|
||||||
assert(ref->vpi_type->type_code==vpiMemoryWord);
|
|
||||||
|
|
||||||
|
|
||||||
/* Get the width of the memory, and the byte index of the
|
|
||||||
first byte of the word. */
|
|
||||||
unsigned width = memory_word_width(rfp->mem->mem);
|
|
||||||
unsigned word_addr = rfp->index.value;
|
|
||||||
|
|
||||||
/* Addresses are converted to canonical form by offsetting the
|
|
||||||
address by the lowest index. */
|
|
||||||
long addr_off = memory_left_range(rfp->mem->mem, 0);
|
|
||||||
if (memory_right_range(rfp->mem->mem, 0) < addr_off)
|
|
||||||
addr_off = memory_right_range(rfp->mem->mem, 0);
|
|
||||||
|
|
||||||
assert(addr_off >= 0 && (unsigned) addr_off <= word_addr);
|
|
||||||
word_addr -= addr_off;
|
|
||||||
|
|
||||||
/* Build up the word value from whatever format the user
|
|
||||||
supplies. */
|
|
||||||
vvp_vector4_t put_val (width);
|
|
||||||
|
|
||||||
switch (val->format) {
|
|
||||||
case vpiVectorVal:
|
|
||||||
for (unsigned idx = 0 ; idx < width ; idx += 1) {
|
|
||||||
p_vpi_vecval cur = val->value.vector + (idx/32);
|
|
||||||
int aval = (cur->aval >> (idx%32)) & 1;
|
|
||||||
int bval = (cur->bval >> (idx%32)) & 1;
|
|
||||||
|
|
||||||
/* Check this bit value conversion. This is
|
|
||||||
specifically defined by the IEEE1364 standard. */
|
|
||||||
vvp_bit4_t bit;
|
|
||||||
if (bval) {
|
|
||||||
bit = aval? BIT4_Z : BIT4_X;
|
|
||||||
} else {
|
|
||||||
bit = aval? BIT4_1 : BIT4_0;
|
|
||||||
}
|
|
||||||
put_val.set_bit(idx, bit);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
case vpiIntVal: {
|
|
||||||
int cur = val->value.integer;
|
|
||||||
for (unsigned idx = 0; idx < width; idx += 1) {
|
|
||||||
vvp_bit4_t bit = (cur&1)? BIT4_1 : BIT4_0;
|
|
||||||
put_val.set_bit(idx, bit);
|
|
||||||
cur >>= 1;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
case vpiBinStrVal: {
|
|
||||||
char*str = val->value.str;
|
|
||||||
for (unsigned idx = 0 ; idx < width ; idx += 1) {
|
|
||||||
switch (str[width-idx-1]) {
|
|
||||||
case '0':
|
|
||||||
put_val.set_bit(idx, BIT4_0);
|
|
||||||
break;
|
|
||||||
case '1':
|
|
||||||
put_val.set_bit(idx, BIT4_1);
|
|
||||||
break;
|
|
||||||
case 'x':
|
|
||||||
case 'X':
|
|
||||||
put_val.set_bit(idx, BIT4_X);
|
|
||||||
break;
|
|
||||||
case 'z':
|
|
||||||
case 'Z':
|
|
||||||
put_val.set_bit(idx, BIT4_Z);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
fprintf(stderr, "Unsupported value %c(%d).\n",
|
|
||||||
str[width-idx-1], str[width-idx-1]);
|
|
||||||
assert(0);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
case vpiOctStrVal: {
|
|
||||||
char*str = val->value.str;
|
|
||||||
vpip_oct_str_to_vec4(put_val, str);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
case vpiDecStrVal: {
|
|
||||||
char*str = val->value.str;
|
|
||||||
vpip_dec_str_to_vec4(put_val, str, false);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
case vpiHexStrVal: {
|
|
||||||
char*str = val->value.str;
|
|
||||||
vpip_hex_str_to_vec4(put_val, str);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
default:
|
|
||||||
cerr << "internal error: memory_word put_value format="
|
|
||||||
<< val->format << endl;
|
|
||||||
assert(0);
|
|
||||||
}
|
|
||||||
|
|
||||||
memory_set_word(rfp->mem->mem, word_addr, 0, put_val);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static char* memory_word_get_str(int code, vpiHandle ref)
|
|
||||||
{
|
|
||||||
assert(ref->vpi_type->type_code==vpiMemoryWord);
|
|
||||||
|
|
||||||
struct __vpiMemoryWord*rfp = (struct __vpiMemoryWord*)ref;
|
|
||||||
|
|
||||||
char number[32];
|
|
||||||
sprintf(number, "%d", rfp->index.value);
|
|
||||||
|
|
||||||
return generic_get_str(code, &rfp->mem->scope->base, rfp->mem->name, number);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void memory_word_get_value(vpiHandle ref, s_vpi_value*vp)
|
|
||||||
{
|
|
||||||
struct __vpiMemoryWord*rfp = (struct __vpiMemoryWord*)ref;
|
|
||||||
assert(rfp->base.vpi_type->type_code==vpiMemoryWord);
|
|
||||||
|
|
||||||
unsigned width = memory_word_width(rfp->mem->mem);
|
|
||||||
unsigned word_address = rfp->index.value;
|
|
||||||
|
|
||||||
vvp_vector4_t word_val = memory_get_word(rfp->mem->mem, word_address);
|
|
||||||
|
|
||||||
vpip_vec4_get_value(word_val, width, false /* never signed */, vp);
|
|
||||||
}
|
|
||||||
|
|
||||||
static const struct __vpirt vpip_memory_rt = {
|
|
||||||
vpiMemory,
|
|
||||||
vpi_memory_get,
|
|
||||||
memory_get_str,
|
|
||||||
0,
|
|
||||||
0,
|
|
||||||
memory_get_handle,
|
|
||||||
memory_iterate,
|
|
||||||
memory_index,
|
|
||||||
};
|
|
||||||
|
|
||||||
static const struct __vpirt vpip_memory_word_rt = {
|
|
||||||
vpiMemoryWord,
|
|
||||||
memory_word_get,
|
|
||||||
memory_word_get_str,
|
|
||||||
memory_word_get_value,
|
|
||||||
memory_word_put,
|
|
||||||
memory_word_get_handle,
|
|
||||||
0,
|
|
||||||
0,
|
|
||||||
};
|
|
||||||
|
|
||||||
static void memory_make_word_handles(struct __vpiMemory*rfp)
|
|
||||||
{
|
|
||||||
if (rfp->words != 0)
|
|
||||||
return;
|
|
||||||
|
|
||||||
unsigned word_count = memory_word_count(rfp->mem);
|
|
||||||
|
|
||||||
rfp->words = (struct __vpiMemoryWord*)
|
|
||||||
calloc(word_count, sizeof (struct __vpiMemoryWord));
|
|
||||||
|
|
||||||
for (unsigned idx = 0 ; idx < word_count ; idx += 1) {
|
|
||||||
struct __vpiMemoryWord*cur = rfp->words + idx;
|
|
||||||
cur->base.vpi_type = &vpip_memory_word_rt;
|
|
||||||
cur->mem = rfp;
|
|
||||||
vpip_make_dec_const(&cur->index, idx);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Run the callbacks for a memory value change. The memory.cc methods
|
|
||||||
* call this method with the canonical address of the word that
|
|
||||||
* changed, and we here run through all the callbacks for the memory,
|
|
||||||
* passing the translated index through.
|
|
||||||
*/
|
|
||||||
void vpip_run_memory_value_change(vpiHandle ref, unsigned addr)
|
|
||||||
{
|
|
||||||
struct __vpiMemory*obj = reinterpret_cast<struct __vpiMemory*>(ref);
|
|
||||||
|
|
||||||
vvp_vector4_t word_val = memory_get_word(obj->mem, addr);
|
|
||||||
unsigned width = memory_word_width(obj->mem);
|
|
||||||
|
|
||||||
for (struct __vpiCallback*cur=obj->value_change_cb;
|
|
||||||
cur != 0 ; cur = cur->next) {
|
|
||||||
|
|
||||||
if (cur->cb_data.cb_rtn == 0)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
if (cur->cb_data.value)
|
|
||||||
vpip_vec4_get_value(word_val, width, false, cur->cb_data.value);
|
|
||||||
|
|
||||||
cur->cb_data.index = addr;
|
|
||||||
vpi_mode_flag = VPI_MODE_RWSYNC;
|
|
||||||
(cur->cb_data.cb_rtn) (&cur->cb_data);
|
|
||||||
vpi_mode_flag = VPI_MODE_NONE;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Attach the callback to the memory.
|
|
||||||
*/
|
|
||||||
void vpip_memory_value_change(struct __vpiCallback*cbh, vpiHandle ref)
|
|
||||||
{
|
|
||||||
struct __vpiMemory*obj = reinterpret_cast<struct __vpiMemory*>(ref);
|
|
||||||
cbh->next = obj->value_change_cb;
|
|
||||||
obj->value_change_cb = cbh;
|
|
||||||
}
|
|
||||||
|
|
||||||
vpiHandle vpip_make_memory(vvp_memory_t mem, const char*name)
|
|
||||||
{
|
|
||||||
struct __vpiMemory*obj = (struct __vpiMemory*)
|
|
||||||
malloc(sizeof(struct __vpiMemory));
|
|
||||||
count_vpi_memories += 1;
|
|
||||||
|
|
||||||
obj->base.vpi_type = &vpip_memory_rt;
|
|
||||||
obj->scope = vpip_peek_current_scope();
|
|
||||||
obj->mem = mem;
|
|
||||||
obj->name = vpip_name_string(name);
|
|
||||||
obj->value_change_cb = 0;
|
|
||||||
|
|
||||||
memory_attach_self(mem, &(obj->base));
|
|
||||||
vpip_make_dec_const(&obj->left_range, memory_left_range(mem, 0));
|
|
||||||
vpip_make_dec_const(&obj->right_range, memory_right_range(mem, 0));
|
|
||||||
vpip_make_dec_const(&obj->word_left_range, memory_word_left_range(mem));
|
|
||||||
vpip_make_dec_const(&obj->word_right_range,memory_word_right_range(mem));
|
|
||||||
|
|
||||||
obj->words = 0;
|
|
||||||
|
|
||||||
return &(obj->base);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
@ -22,7 +22,6 @@
|
||||||
# include "vpi_user.h"
|
# include "vpi_user.h"
|
||||||
# include "pointers.h"
|
# include "pointers.h"
|
||||||
# include "vvp_net.h"
|
# include "vvp_net.h"
|
||||||
# include "memory.h"
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
@ -142,11 +141,15 @@ struct __vpiCallback {
|
||||||
// scheduled event
|
// scheduled event
|
||||||
struct sync_cb* cb_sync;
|
struct sync_cb* cb_sync;
|
||||||
|
|
||||||
|
// The calback holder may use this for various purposes.
|
||||||
|
long extra_data;
|
||||||
|
|
||||||
// Used for listing callbacks.
|
// Used for listing callbacks.
|
||||||
struct __vpiCallback*next;
|
struct __vpiCallback*next;
|
||||||
};
|
};
|
||||||
|
|
||||||
extern struct __vpiCallback* new_vpi_callback();
|
extern struct __vpiCallback* new_vpi_callback();
|
||||||
|
extern void delete_vpi_callback(struct __vpiCallback* ref);
|
||||||
extern void callback_execute(struct __vpiCallback*cur);
|
extern void callback_execute(struct __vpiCallback*cur);
|
||||||
|
|
||||||
struct __vpiSystemTime {
|
struct __vpiSystemTime {
|
||||||
|
|
@ -308,12 +311,6 @@ extern void vpip_real_value_change(struct __vpiCallback*cbh,
|
||||||
* the memory.
|
* the memory.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
extern vpiHandle vpip_make_memory(vvp_memory_t mem, const char*name);
|
|
||||||
extern void vpip_memory_value_change(struct __vpiCallback*cbh,
|
|
||||||
vpiHandle ref);
|
|
||||||
|
|
||||||
extern void vpip_run_memory_value_change(vpiHandle ref, unsigned adr);
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* These are the various variable types.
|
* These are the various variable types.
|
||||||
*/
|
*/
|
||||||
|
|
@ -433,6 +430,8 @@ vpiHandle vpip_make_vthr_vector(unsigned base, unsigned wid, bool signed_flag);
|
||||||
|
|
||||||
vpiHandle vpip_make_vthr_word(unsigned base, const char*type);
|
vpiHandle vpip_make_vthr_word(unsigned base, const char*type);
|
||||||
|
|
||||||
|
vpiHandle vpip_make_vthr_A(char*symbol, unsigned index);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* This function is called before any compilation to load VPI
|
* This function is called before any compilation to load VPI
|
||||||
* modules. This gives the modules a chance to announce their
|
* modules. This gives the modules a chance to announce their
|
||||||
|
|
@ -530,6 +529,8 @@ extern void vpip_oct_str_to_vec4(vvp_vector4_t&val, const char*str);
|
||||||
extern void vpip_dec_str_to_vec4(vvp_vector4_t&val, const char*str, bool sign);
|
extern void vpip_dec_str_to_vec4(vvp_vector4_t&val, const char*str, bool sign);
|
||||||
extern void vpip_hex_str_to_vec4(vvp_vector4_t&val, const char*str);
|
extern void vpip_hex_str_to_vec4(vvp_vector4_t&val, const char*str);
|
||||||
|
|
||||||
|
extern vvp_vector4_t vec4_from_vpi_value(s_vpi_value*vp, unsigned wid);
|
||||||
|
|
||||||
extern void vpip_vec4_get_value(const vvp_vector4_t&word_val, unsigned width,
|
extern void vpip_vec4_get_value(const vvp_vector4_t&word_val, unsigned width,
|
||||||
bool signed_flag, s_vpi_value*vp);
|
bool signed_flag, s_vpi_value*vp);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -645,6 +645,27 @@ static vpiHandle signal_put_value(vpiHandle ref, s_vpi_value*vp, int flags)
|
||||||
? (rfp->msb - rfp->lsb + 1)
|
? (rfp->msb - rfp->lsb + 1)
|
||||||
: (rfp->lsb - rfp->msb + 1);
|
: (rfp->lsb - rfp->msb + 1);
|
||||||
|
|
||||||
|
|
||||||
|
vvp_vector4_t val = vec4_from_vpi_value(vp, wid);
|
||||||
|
|
||||||
|
/* If this is a vpiForce, then instead of writing to the
|
||||||
|
signal input port, we write to the special "force" port. */
|
||||||
|
int dest_port = 0;
|
||||||
|
if (flags == vpiForceFlag)
|
||||||
|
dest_port = 2;
|
||||||
|
|
||||||
|
/* This is the destination that I'm going to poke into. Make
|
||||||
|
it from the vvp_net_t pointer, and assume a write to
|
||||||
|
port-0. This is the port where signals receive input. */
|
||||||
|
vvp_net_ptr_t destination (rfp->node, dest_port);
|
||||||
|
|
||||||
|
vvp_send_vec4(destination, val);
|
||||||
|
|
||||||
|
return ref;
|
||||||
|
}
|
||||||
|
|
||||||
|
vvp_vector4_t vec4_from_vpi_value(s_vpi_value*vp, unsigned wid)
|
||||||
|
{
|
||||||
vvp_vector4_t val (wid, BIT4_0);
|
vvp_vector4_t val (wid, BIT4_0);
|
||||||
|
|
||||||
switch (vp->format) {
|
switch (vp->format) {
|
||||||
|
|
@ -691,27 +712,13 @@ static vpiHandle signal_put_value(vpiHandle ref, s_vpi_value*vp, int flags)
|
||||||
|
|
||||||
default:
|
default:
|
||||||
fprintf(stderr, "vvp internal error: put_value: "
|
fprintf(stderr, "vvp internal error: put_value: "
|
||||||
"value type %u not implemented."
|
"value type %u not implemented here.\n",
|
||||||
" Signal is %s in scope %s\n",
|
vp->format);
|
||||||
vp->format, vpi_get_str(vpiName, ref), rfp->scope->name);
|
|
||||||
assert(0);
|
assert(0);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* If this is a vpiForce, then instead of writing to the
|
return val;
|
||||||
signal input port, we write to the special "force" port. */
|
|
||||||
int dest_port = 0;
|
|
||||||
if (flags == vpiForceFlag)
|
|
||||||
dest_port = 2;
|
|
||||||
|
|
||||||
/* This is the destination that I'm going to poke into. Make
|
|
||||||
it from the vvp_net_t pointer, and assume a write to
|
|
||||||
port-0. This is the port where signals receive input. */
|
|
||||||
vvp_net_ptr_t destination (rfp->node, dest_port);
|
|
||||||
|
|
||||||
vvp_send_vec4(destination, val);
|
|
||||||
|
|
||||||
return ref;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static const struct __vpirt vpip_reg_rt = {
|
static const struct __vpirt vpip_reg_rt = {
|
||||||
|
|
|
||||||
525
vvp/vthread.cc
525
vvp/vthread.cc
|
|
@ -183,6 +183,11 @@ static unsigned long* vector_to_array(struct vthread_s*thr,
|
||||||
unsigned long*val = new unsigned long[awid];
|
unsigned long*val = new unsigned long[awid];
|
||||||
for (unsigned idx = 0 ; idx < awid ; idx += 1)
|
for (unsigned idx = 0 ; idx < awid ; idx += 1)
|
||||||
val[idx] = -1UL;
|
val[idx] = -1UL;
|
||||||
|
|
||||||
|
wid -= (awid-1) * CPU_WORD_BITS;
|
||||||
|
if (wid < CPU_WORD_BITS)
|
||||||
|
val[awid-1] &= (-1UL) >> (CPU_WORD_BITS-wid);
|
||||||
|
|
||||||
return val;
|
return val;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -205,12 +210,7 @@ static vvp_vector4_t vthread_bits_to_vector(struct vthread_s*thr,
|
||||||
return vvp_vector4_t(thr->bits4, bit, wid);
|
return vvp_vector4_t(thr->bits4, bit, wid);
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
vvp_vector4_t value(wid);
|
return vvp_vector4_t(wid, thr_index_to_bit4[bit]);
|
||||||
vvp_bit4_t bit_val = thr_index_to_bit4[bit];
|
|
||||||
for (unsigned idx = 0; idx < wid; idx +=1) {
|
|
||||||
value.set_bit(idx, bit_val);
|
|
||||||
}
|
|
||||||
return value;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -410,20 +410,29 @@ bool of_ABS_WR(vthread_t thr, vvp_code_t cp)
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool of_AND(vthread_t thr, vvp_code_t cp)
|
static bool of_AND_wide(vthread_t thr, vvp_code_t cp)
|
||||||
{
|
{
|
||||||
assert(cp->bit_idx[0] >= 4);
|
|
||||||
|
|
||||||
unsigned idx1 = cp->bit_idx[0];
|
unsigned idx1 = cp->bit_idx[0];
|
||||||
unsigned idx2 = cp->bit_idx[1];
|
unsigned idx2 = cp->bit_idx[1];
|
||||||
|
unsigned wid = cp->number;
|
||||||
|
|
||||||
for (unsigned idx = 0 ; idx < cp->number ; idx += 1) {
|
vvp_vector4_t val = vthread_bits_to_vector(thr, idx1, wid);
|
||||||
|
val &= vthread_bits_to_vector(thr, idx2, wid);
|
||||||
|
thr->bits4.set_vec(idx1, val);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool of_AND_narrow(vthread_t thr, vvp_code_t cp)
|
||||||
|
{
|
||||||
|
unsigned idx1 = cp->bit_idx[0];
|
||||||
|
unsigned idx2 = cp->bit_idx[1];
|
||||||
|
unsigned wid = cp->number;
|
||||||
|
|
||||||
|
for (unsigned idx = 0 ; idx < wid ; idx += 1) {
|
||||||
vvp_bit4_t lb = thr_get_bit(thr, idx1);
|
vvp_bit4_t lb = thr_get_bit(thr, idx1);
|
||||||
vvp_bit4_t rb = thr_get_bit(thr, idx2);
|
vvp_bit4_t rb = thr_get_bit(thr, idx2);
|
||||||
|
thr_put_bit(thr, idx1, lb&rb);
|
||||||
thr_put_bit(thr, idx1, lb & rb);
|
|
||||||
|
|
||||||
idx1 += 1;
|
idx1 += 1;
|
||||||
if (idx2 >= 4)
|
if (idx2 >= 4)
|
||||||
idx2 += 1;
|
idx2 += 1;
|
||||||
|
|
@ -432,6 +441,18 @@ bool of_AND(vthread_t thr, vvp_code_t cp)
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool of_AND(vthread_t thr, vvp_code_t cp)
|
||||||
|
{
|
||||||
|
assert(cp->bit_idx[0] >= 4);
|
||||||
|
|
||||||
|
if (cp->number <= 4)
|
||||||
|
cp->opcode = &of_AND_narrow;
|
||||||
|
else
|
||||||
|
cp->opcode = &of_AND_wide;
|
||||||
|
|
||||||
|
return cp->opcode(thr, cp);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
bool of_ADD(vthread_t thr, vvp_code_t cp)
|
bool of_ADD(vthread_t thr, vvp_code_t cp)
|
||||||
{
|
{
|
||||||
|
|
@ -728,28 +749,6 @@ bool of_ASSIGN_X0(vthread_t thr, vvp_code_t cp)
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* %assign/mv <memory>, <delay>, <bit>
|
|
||||||
* This generates an assignment event to a memory. Index register 0
|
|
||||||
* contains the width of the vector (and the word) and index register
|
|
||||||
* 3 contains the canonical address of the word in memory.
|
|
||||||
*/
|
|
||||||
bool of_ASSIGN_MV(vthread_t thr, vvp_code_t cp)
|
|
||||||
{
|
|
||||||
unsigned wid = thr->words[0].w_int;
|
|
||||||
unsigned off = thr->words[1].w_int;
|
|
||||||
unsigned adr = thr->words[3].w_int;
|
|
||||||
|
|
||||||
assert(wid > 0);
|
|
||||||
|
|
||||||
unsigned delay = cp->bit_idx[0];
|
|
||||||
unsigned bit = cp->bit_idx[1];
|
|
||||||
|
|
||||||
vvp_vector4_t value = vthread_bits_to_vector(thr, bit, wid);
|
|
||||||
|
|
||||||
schedule_assign_memory_word(cp->mem, adr, off, value, delay);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool of_BLEND(vthread_t thr, vvp_code_t cp)
|
bool of_BLEND(vthread_t thr, vvp_code_t cp)
|
||||||
{
|
{
|
||||||
assert(cp->bit_idx[0] >= 4);
|
assert(cp->bit_idx[0] >= 4);
|
||||||
|
|
@ -1018,54 +1017,92 @@ bool of_CMPIS(vthread_t thr, vvp_code_t cp)
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool of_CMPIU(vthread_t thr, vvp_code_t cp)
|
/*
|
||||||
|
* The of_CMPIU below punts to this function if there are any xz bits
|
||||||
|
* in the vector part of the instruction. In this case we know that
|
||||||
|
* there is at least 1 xz bit in the left expression (and there are
|
||||||
|
* none in the imm value) so the eeq result must be false. Otherwise,
|
||||||
|
* the eq result may me 0 or x, and the lt bit is x.
|
||||||
|
*/
|
||||||
|
static bool of_CMPIU_the_hard_way(vthread_t thr, vvp_code_t cp)
|
||||||
{
|
{
|
||||||
vvp_bit4_t eq = BIT4_1;
|
|
||||||
vvp_bit4_t eeq = BIT4_1;
|
|
||||||
vvp_bit4_t lt = BIT4_0;
|
|
||||||
|
|
||||||
unsigned idx1 = cp->bit_idx[0];
|
unsigned idx1 = cp->bit_idx[0];
|
||||||
unsigned imm = cp->bit_idx[1];
|
unsigned imm = cp->bit_idx[1];
|
||||||
|
unsigned wid = cp->number;
|
||||||
|
if (idx1 >= 4)
|
||||||
|
thr_check_addr(thr, idx1+wid-1);
|
||||||
|
|
||||||
for (unsigned idx = 0 ; idx < cp->number ; idx += 1) {
|
vvp_bit4_t lv = thr_get_bit(thr, idx1);
|
||||||
vvp_bit4_t lv = thr_get_bit(thr, idx1);
|
if (bit4_is_xz(lv)) {
|
||||||
|
thr_put_bit(thr, 4, BIT4_X);
|
||||||
|
thr_put_bit(thr, 5, BIT4_X);
|
||||||
|
thr_put_bit(thr, 6, BIT4_0);
|
||||||
|
}
|
||||||
|
|
||||||
|
vvp_bit4_t eq = BIT4_0;
|
||||||
|
for (unsigned idx = 0 ; idx < wid ; idx += 1) {
|
||||||
vvp_bit4_t rv = (imm & 1)? BIT4_1 : BIT4_0;
|
vvp_bit4_t rv = (imm & 1)? BIT4_1 : BIT4_0;
|
||||||
imm >>= 1;
|
imm >>= 1;
|
||||||
|
|
||||||
if (lv > rv) {
|
if (bit4_is_xz(lv)) {
|
||||||
lt = BIT4_0;
|
eq = BIT4_X;
|
||||||
eeq = BIT4_0;
|
} else if (lv != rv) {
|
||||||
} else if (lv < rv) {
|
break;
|
||||||
lt = BIT4_1;
|
|
||||||
eeq = BIT4_0;
|
|
||||||
}
|
|
||||||
if (eq != BIT4_X) {
|
|
||||||
if ((lv == BIT4_0) && (rv != BIT4_0))
|
|
||||||
eq = BIT4_0;
|
|
||||||
if ((lv == BIT4_1) && (rv != BIT4_1))
|
|
||||||
eq = BIT4_0;
|
|
||||||
if (bit4_is_xz(lv) || bit4_is_xz(rv))
|
|
||||||
eq = BIT4_X;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (idx1 >= 4) idx1 += 1;
|
if (idx1 >= 4) {
|
||||||
|
idx1 += 1;
|
||||||
|
if (idx1 < wid)
|
||||||
|
lv = thr_get_bit(thr, idx1);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (eq == BIT4_X)
|
|
||||||
lt = BIT4_X;
|
|
||||||
|
|
||||||
thr_put_bit(thr, 4, eq);
|
thr_put_bit(thr, 4, eq);
|
||||||
thr_put_bit(thr, 5, lt);
|
thr_put_bit(thr, 5, BIT4_X);
|
||||||
thr_put_bit(thr, 6, eeq);
|
thr_put_bit(thr, 6, BIT4_0);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool of_CMPU(vthread_t thr, vvp_code_t cp)
|
bool of_CMPIU(vthread_t thr, vvp_code_t cp)
|
||||||
|
{
|
||||||
|
unsigned addr = cp->bit_idx[0];
|
||||||
|
unsigned long imm = cp->bit_idx[1];
|
||||||
|
unsigned wid = cp->number;
|
||||||
|
|
||||||
|
unsigned long*array = vector_to_array(thr, addr, wid);
|
||||||
|
// If there are xz bits in the right hand expression, then we
|
||||||
|
// have to do the compare the hard way. That is because even
|
||||||
|
// though we know that eeq must be false (the immediate value
|
||||||
|
// cannot have x or z bits) we don't know what the EQ or LT
|
||||||
|
// bits will be.
|
||||||
|
if (array == 0)
|
||||||
|
return of_CMPIU_the_hard_way(thr, cp);
|
||||||
|
|
||||||
|
unsigned words = (wid+CPU_WORD_BITS-1) / CPU_WORD_BITS;
|
||||||
|
vvp_bit4_t eq = BIT4_1;
|
||||||
|
vvp_bit4_t lt = BIT4_0;
|
||||||
|
for (unsigned idx = 0 ; idx < words ; idx += 1, imm = 0UL) {
|
||||||
|
if (array[idx] == imm)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
eq = BIT4_0;
|
||||||
|
lt = (array[idx] < imm) ? BIT4_1 : BIT4_0;
|
||||||
|
}
|
||||||
|
|
||||||
|
delete[]array;
|
||||||
|
|
||||||
|
thr_put_bit(thr, 4, eq);
|
||||||
|
thr_put_bit(thr, 5, lt);
|
||||||
|
thr_put_bit(thr, 6, eq);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool of_CMPU_the_hard_way(vthread_t thr, vvp_code_t cp)
|
||||||
{
|
{
|
||||||
vvp_bit4_t eq = BIT4_1;
|
vvp_bit4_t eq = BIT4_1;
|
||||||
vvp_bit4_t eeq = BIT4_1;
|
vvp_bit4_t eeq = BIT4_1;
|
||||||
vvp_bit4_t lt = BIT4_0;
|
|
||||||
|
|
||||||
unsigned idx1 = cp->bit_idx[0];
|
unsigned idx1 = cp->bit_idx[0];
|
||||||
unsigned idx2 = cp->bit_idx[1];
|
unsigned idx2 = cp->bit_idx[1];
|
||||||
|
|
@ -1074,33 +1111,68 @@ bool of_CMPU(vthread_t thr, vvp_code_t cp)
|
||||||
vvp_bit4_t lv = thr_get_bit(thr, idx1);
|
vvp_bit4_t lv = thr_get_bit(thr, idx1);
|
||||||
vvp_bit4_t rv = thr_get_bit(thr, idx2);
|
vvp_bit4_t rv = thr_get_bit(thr, idx2);
|
||||||
|
|
||||||
if (lv > rv) {
|
if (lv != rv)
|
||||||
lt = BIT4_0;
|
|
||||||
eeq = BIT4_0;
|
eeq = BIT4_0;
|
||||||
} else if (lv < rv) {
|
|
||||||
lt = BIT4_1;
|
if (eq==BIT4_1 && (bit4_is_xz(lv) || bit4_is_xz(rv)))
|
||||||
eeq = BIT4_0;
|
eq = BIT4_X;
|
||||||
}
|
if ((lv == BIT4_0) && (rv==BIT4_1))
|
||||||
if (eq != BIT4_X) {
|
eq = BIT4_0;
|
||||||
if ((lv == BIT4_0) && (rv != BIT4_0))
|
if ((lv == BIT4_1) && (rv==BIT4_0))
|
||||||
eq = BIT4_0;
|
eq = BIT4_0;
|
||||||
if ((lv == BIT4_1) && (rv != BIT4_1))
|
|
||||||
eq = BIT4_0;
|
if (eq == BIT4_0)
|
||||||
if (bit4_is_xz(lv) || bit4_is_xz(rv))
|
break;
|
||||||
eq = BIT4_X;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (idx1 >= 4) idx1 += 1;
|
if (idx1 >= 4) idx1 += 1;
|
||||||
if (idx2 >= 4) idx2 += 1;
|
if (idx2 >= 4) idx2 += 1;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (eq == BIT4_X)
|
thr_put_bit(thr, 4, eq);
|
||||||
lt = BIT4_X;
|
thr_put_bit(thr, 5, BIT4_X);
|
||||||
|
thr_put_bit(thr, 6, eeq);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool of_CMPU(vthread_t thr, vvp_code_t cp)
|
||||||
|
{
|
||||||
|
vvp_bit4_t eq = BIT4_1;
|
||||||
|
vvp_bit4_t lt = BIT4_0;
|
||||||
|
|
||||||
|
unsigned idx1 = cp->bit_idx[0];
|
||||||
|
unsigned idx2 = cp->bit_idx[1];
|
||||||
|
unsigned wid = cp->number;
|
||||||
|
|
||||||
|
unsigned long*larray = vector_to_array(thr, idx1, wid);
|
||||||
|
if (larray == 0) return of_CMPU_the_hard_way(thr, cp);
|
||||||
|
|
||||||
|
unsigned long*rarray = vector_to_array(thr, idx2, wid);
|
||||||
|
if (rarray == 0) {
|
||||||
|
delete[]larray;
|
||||||
|
return of_CMPU_the_hard_way(thr, cp);
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned words = (wid+CPU_WORD_BITS-1) / CPU_WORD_BITS;
|
||||||
|
|
||||||
|
for (unsigned wdx = 0 ; wdx < words ; wdx += 1) {
|
||||||
|
if (larray[wdx] == rarray[wdx])
|
||||||
|
continue;
|
||||||
|
|
||||||
|
eq = BIT4_0;
|
||||||
|
if (larray[wdx] < rarray[wdx])
|
||||||
|
lt = BIT4_1;
|
||||||
|
else
|
||||||
|
lt = BIT4_0;
|
||||||
|
}
|
||||||
|
|
||||||
|
delete[]larray;
|
||||||
|
delete[]rarray;
|
||||||
|
|
||||||
thr_put_bit(thr, 4, eq);
|
thr_put_bit(thr, 4, eq);
|
||||||
thr_put_bit(thr, 5, lt);
|
thr_put_bit(thr, 5, lt);
|
||||||
thr_put_bit(thr, 6, eeq);
|
thr_put_bit(thr, 6, eq);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
@ -1956,25 +2028,41 @@ bool of_FORK(vthread_t thr, vvp_code_t cp)
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static bool of_INV_wide(vthread_t thr, vvp_code_t cp)
|
||||||
|
{
|
||||||
|
unsigned idx1 = cp->bit_idx[0];
|
||||||
|
unsigned wid = cp->bit_idx[1];
|
||||||
|
|
||||||
|
vvp_vector4_t val = vthread_bits_to_vector(thr, idx1, wid);
|
||||||
|
thr->bits4.set_vec(idx1, ~val);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool of_INV_narrow(vthread_t thr, vvp_code_t cp)
|
||||||
|
{
|
||||||
|
unsigned idx1 = cp->bit_idx[0];
|
||||||
|
unsigned wid = cp->bit_idx[1];
|
||||||
|
|
||||||
|
for (unsigned idx = 0 ; idx < wid ; idx += 1) {
|
||||||
|
vvp_bit4_t lb = thr_get_bit(thr, idx1);
|
||||||
|
thr_put_bit(thr, idx1, ~lb);
|
||||||
|
idx1 += 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
bool of_INV(vthread_t thr, vvp_code_t cp)
|
bool of_INV(vthread_t thr, vvp_code_t cp)
|
||||||
{
|
{
|
||||||
assert(cp->bit_idx[0] >= 4);
|
assert(cp->bit_idx[0] >= 4);
|
||||||
for (unsigned idx = 0 ; idx < cp->bit_idx[1] ; idx += 1) {
|
|
||||||
vvp_bit4_t val = thr_get_bit(thr, cp->bit_idx[0]+idx);
|
if (cp->number <= 4)
|
||||||
switch (val) {
|
cp->opcode = &of_INV_narrow;
|
||||||
case BIT4_0:
|
else
|
||||||
val = BIT4_1;
|
cp->opcode = &of_INV_wide;
|
||||||
break;
|
|
||||||
case BIT4_1:
|
return cp->opcode(thr, cp);
|
||||||
val = BIT4_0;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
val = BIT4_X;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
thr_put_bit(thr, cp->bit_idx[0]+idx, val);
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -2025,27 +2113,19 @@ bool of_IX_GET(vthread_t thr, vvp_code_t cp)
|
||||||
unsigned base = cp->bit_idx[1];
|
unsigned base = cp->bit_idx[1];
|
||||||
unsigned width = cp->number;
|
unsigned width = cp->number;
|
||||||
|
|
||||||
unsigned long v = 0;
|
unsigned long*array = vector_to_array(thr, base, width);
|
||||||
bool unknown_flag = false;
|
if (array == 0) {
|
||||||
|
/* If there are unknowns in the vector bits, then give
|
||||||
for (unsigned i = 0 ; i<width ; i += 1) {
|
up immediately. Set the value to 0, and set thread
|
||||||
vvp_bit4_t vv = thr_get_bit(thr, base);
|
bit 4 to 1 to flag the error. */
|
||||||
if (bit4_is_xz(vv)) {
|
thr->words[index].w_int = 0;
|
||||||
v = 0UL;
|
thr_put_bit(thr, 4, BIT4_1);
|
||||||
unknown_flag = true;
|
return true;
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
v |= (unsigned long) vv << i;
|
|
||||||
|
|
||||||
if (base >= 4)
|
|
||||||
base += 1;
|
|
||||||
}
|
}
|
||||||
thr->words[index].w_int = v;
|
|
||||||
|
|
||||||
/* Set bit 4 as a flag if the input is unknown. */
|
|
||||||
thr_put_bit(thr, 4, unknown_flag? BIT4_1 : BIT4_0);
|
|
||||||
|
|
||||||
|
thr->words[index].w_int = array[0];
|
||||||
|
thr_put_bit(thr, 4, BIT4_0);
|
||||||
|
delete[]array;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -2234,13 +2314,15 @@ bool of_LOAD_AV(vthread_t thr, vvp_code_t cp)
|
||||||
if (word.size() != wid) {
|
if (word.size() != wid) {
|
||||||
fprintf(stderr, "internal error: array width=%u, word.size()=%u, wid=%u\n",
|
fprintf(stderr, "internal error: array width=%u, word.size()=%u, wid=%u\n",
|
||||||
0, word.size(), wid);
|
0, word.size(), wid);
|
||||||
|
assert(word.size() == wid);
|
||||||
}
|
}
|
||||||
assert(word.size() == wid);
|
|
||||||
|
|
||||||
for (unsigned idx = 0 ; idx < wid ; idx += 1, bit += 1) {
|
/* Check the address once, before we scan the vector. */
|
||||||
vvp_bit4_t val = word.value(idx);
|
thr_check_addr(thr, bit+wid-1);
|
||||||
thr_put_bit(thr, bit, val);
|
|
||||||
}
|
/* Copy the vector bits into the bits4 vector. Do the copy
|
||||||
|
directly to skip the excess calls to thr_check_addr. */
|
||||||
|
thr->bits4.set_vec(bit, word);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
@ -2314,38 +2396,6 @@ bool of_LOAD_AVX_P(vthread_t thr, vvp_code_t cp)
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
* %load/mv <bit>, <mem-label>, <wid> ;
|
|
||||||
*
|
|
||||||
* <bit> is the thread bit address for the result
|
|
||||||
* <mem-label> is the memory device to access, and
|
|
||||||
* <wid> is the width of the word to read.
|
|
||||||
*
|
|
||||||
* The address of the word in the memory is in index register 3.
|
|
||||||
*/
|
|
||||||
bool of_LOAD_MV(vthread_t thr, vvp_code_t cp)
|
|
||||||
{
|
|
||||||
unsigned bit = cp->bit_idx[0];
|
|
||||||
unsigned wid = cp->bit_idx[1];
|
|
||||||
unsigned adr = thr->words[3].w_int;
|
|
||||||
|
|
||||||
vvp_vector4_t word = memory_get_word(cp->mem, adr);
|
|
||||||
|
|
||||||
if (word.size() != wid) {
|
|
||||||
fprintf(stderr, "internal error: mem width=%u, word.size()=%u, wid=%u\n",
|
|
||||||
memory_word_width(cp->mem), word.size(), wid);
|
|
||||||
}
|
|
||||||
assert(word.size() == wid);
|
|
||||||
|
|
||||||
for (unsigned idx = 0 ; idx < wid ; idx += 1, bit += 1) {
|
|
||||||
vvp_bit4_t val = word.value(idx);
|
|
||||||
thr_put_bit(thr, bit, val);
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* %load/nx <bit>, <vpi-label>, <idx> ; Load net/indexed.
|
* %load/nx <bit>, <vpi-label>, <idx> ; Load net/indexed.
|
||||||
*
|
*
|
||||||
|
|
@ -3078,28 +3128,29 @@ bool of_MULI(vthread_t thr, vvp_code_t cp)
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool of_NAND(vthread_t thr, vvp_code_t cp)
|
static bool of_NAND_wide(vthread_t thr, vvp_code_t cp)
|
||||||
{
|
{
|
||||||
assert(cp->bit_idx[0] >= 4);
|
|
||||||
|
|
||||||
unsigned idx1 = cp->bit_idx[0];
|
unsigned idx1 = cp->bit_idx[0];
|
||||||
unsigned idx2 = cp->bit_idx[1];
|
unsigned idx2 = cp->bit_idx[1];
|
||||||
|
unsigned wid = cp->number;
|
||||||
|
|
||||||
for (unsigned idx = 0 ; idx < cp->number ; idx += 1) {
|
vvp_vector4_t val = vthread_bits_to_vector(thr, idx1, wid);
|
||||||
|
val &= vthread_bits_to_vector(thr, idx2, wid);
|
||||||
|
thr->bits4.set_vec(idx1, ~val);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool of_NAND_narrow(vthread_t thr, vvp_code_t cp)
|
||||||
|
{
|
||||||
|
unsigned idx1 = cp->bit_idx[0];
|
||||||
|
unsigned idx2 = cp->bit_idx[1];
|
||||||
|
unsigned wid = cp->number;
|
||||||
|
|
||||||
|
for (unsigned idx = 0 ; idx < wid ; idx += 1) {
|
||||||
vvp_bit4_t lb = thr_get_bit(thr, idx1);
|
vvp_bit4_t lb = thr_get_bit(thr, idx1);
|
||||||
vvp_bit4_t rb = thr_get_bit(thr, idx2);
|
vvp_bit4_t rb = thr_get_bit(thr, idx2);
|
||||||
|
thr_put_bit(thr, idx1, ~(lb&rb));
|
||||||
if ((lb == BIT4_0) || (rb == BIT4_0)) {
|
|
||||||
thr_put_bit(thr, idx1, BIT4_1);
|
|
||||||
|
|
||||||
} else if ((lb == BIT4_1) && (rb == BIT4_1)) {
|
|
||||||
thr_put_bit(thr, idx1, BIT4_0);
|
|
||||||
|
|
||||||
} else {
|
|
||||||
thr_put_bit(thr, idx1, BIT4_X);
|
|
||||||
}
|
|
||||||
|
|
||||||
idx1 += 1;
|
idx1 += 1;
|
||||||
if (idx2 >= 4)
|
if (idx2 >= 4)
|
||||||
idx2 += 1;
|
idx2 += 1;
|
||||||
|
|
@ -3108,6 +3159,18 @@ bool of_NAND(vthread_t thr, vvp_code_t cp)
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool of_NAND(vthread_t thr, vvp_code_t cp)
|
||||||
|
{
|
||||||
|
assert(cp->bit_idx[0] >= 4);
|
||||||
|
|
||||||
|
if (cp->number <= 4)
|
||||||
|
cp->opcode = &of_NAND_narrow;
|
||||||
|
else
|
||||||
|
cp->opcode = &of_NAND_wide;
|
||||||
|
|
||||||
|
return cp->opcode(thr, cp);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
bool of_NOOP(vthread_t thr, vvp_code_t cp)
|
bool of_NOOP(vthread_t thr, vvp_code_t cp)
|
||||||
{
|
{
|
||||||
|
|
@ -3256,28 +3319,74 @@ bool of_XNORR(vthread_t thr, vvp_code_t cp)
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static bool of_OR_wide(vthread_t thr, vvp_code_t cp)
|
||||||
|
{
|
||||||
|
unsigned idx1 = cp->bit_idx[0];
|
||||||
|
unsigned idx2 = cp->bit_idx[1];
|
||||||
|
unsigned wid = cp->number;
|
||||||
|
|
||||||
|
vvp_vector4_t val = vthread_bits_to_vector(thr, idx1, wid);
|
||||||
|
val |= vthread_bits_to_vector(thr, idx2, wid);
|
||||||
|
thr->bits4.set_vec(idx1, val);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool of_OR_narrow(vthread_t thr, vvp_code_t cp)
|
||||||
|
{
|
||||||
|
unsigned idx1 = cp->bit_idx[0];
|
||||||
|
unsigned idx2 = cp->bit_idx[1];
|
||||||
|
unsigned wid = cp->number;
|
||||||
|
|
||||||
|
for (unsigned idx = 0 ; idx < wid ; idx += 1) {
|
||||||
|
vvp_bit4_t lb = thr_get_bit(thr, idx1);
|
||||||
|
vvp_bit4_t rb = thr_get_bit(thr, idx2);
|
||||||
|
thr_put_bit(thr, idx1, lb|rb);
|
||||||
|
idx1 += 1;
|
||||||
|
if (idx2 >= 4)
|
||||||
|
idx2 += 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
bool of_OR(vthread_t thr, vvp_code_t cp)
|
bool of_OR(vthread_t thr, vvp_code_t cp)
|
||||||
{
|
{
|
||||||
assert(cp->bit_idx[0] >= 4);
|
assert(cp->bit_idx[0] >= 4);
|
||||||
|
|
||||||
|
if (cp->number <= 4)
|
||||||
|
cp->opcode = &of_OR_narrow;
|
||||||
|
else
|
||||||
|
cp->opcode = &of_OR_wide;
|
||||||
|
|
||||||
|
return cp->opcode(thr, cp);
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool of_NOR_wide(vthread_t thr, vvp_code_t cp)
|
||||||
|
{
|
||||||
|
assert(cp->bit_idx[0] >= 4);
|
||||||
|
|
||||||
unsigned idx1 = cp->bit_idx[0];
|
unsigned idx1 = cp->bit_idx[0];
|
||||||
unsigned idx2 = cp->bit_idx[1];
|
unsigned idx2 = cp->bit_idx[1];
|
||||||
|
unsigned wid = cp->number;
|
||||||
|
|
||||||
for (unsigned idx = 0 ; idx < cp->number ; idx += 1) {
|
vvp_vector4_t val = vthread_bits_to_vector(thr, idx1, wid);
|
||||||
|
val |= vthread_bits_to_vector(thr, idx2, wid);
|
||||||
|
thr->bits4.set_vec(idx1, ~val);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool of_NOR_narrow(vthread_t thr, vvp_code_t cp)
|
||||||
|
{
|
||||||
|
unsigned idx1 = cp->bit_idx[0];
|
||||||
|
unsigned idx2 = cp->bit_idx[1];
|
||||||
|
unsigned wid = cp->number;
|
||||||
|
|
||||||
|
for (unsigned idx = 0 ; idx < wid ; idx += 1) {
|
||||||
vvp_bit4_t lb = thr_get_bit(thr, idx1);
|
vvp_bit4_t lb = thr_get_bit(thr, idx1);
|
||||||
vvp_bit4_t rb = thr_get_bit(thr, idx2);
|
vvp_bit4_t rb = thr_get_bit(thr, idx2);
|
||||||
|
thr_put_bit(thr, idx1, ~(lb|rb));
|
||||||
if ((lb == BIT4_1) || (rb == BIT4_1)) {
|
|
||||||
thr_put_bit(thr, idx1, BIT4_1);
|
|
||||||
|
|
||||||
} else if ((lb == BIT4_0) && (rb == BIT4_0)) {
|
|
||||||
thr_put_bit(thr, idx1, BIT4_0);
|
|
||||||
|
|
||||||
} else {
|
|
||||||
thr_put_bit(thr, idx1, BIT4_X);
|
|
||||||
}
|
|
||||||
|
|
||||||
idx1 += 1;
|
idx1 += 1;
|
||||||
if (idx2 >= 4)
|
if (idx2 >= 4)
|
||||||
idx2 += 1;
|
idx2 += 1;
|
||||||
|
|
@ -3290,30 +3399,12 @@ bool of_NOR(vthread_t thr, vvp_code_t cp)
|
||||||
{
|
{
|
||||||
assert(cp->bit_idx[0] >= 4);
|
assert(cp->bit_idx[0] >= 4);
|
||||||
|
|
||||||
unsigned idx1 = cp->bit_idx[0];
|
if (cp->number <= 4)
|
||||||
unsigned idx2 = cp->bit_idx[1];
|
cp->opcode = &of_NOR_narrow;
|
||||||
|
else
|
||||||
|
cp->opcode = &of_NOR_wide;
|
||||||
|
|
||||||
for (unsigned idx = 0 ; idx < cp->number ; idx += 1) {
|
return cp->opcode(thr, cp);
|
||||||
|
|
||||||
vvp_bit4_t lb = thr_get_bit(thr, idx1);
|
|
||||||
vvp_bit4_t rb = thr_get_bit(thr, idx2);
|
|
||||||
|
|
||||||
if ((lb == BIT4_1) || (rb == BIT4_1)) {
|
|
||||||
thr_put_bit(thr, idx1, BIT4_0);
|
|
||||||
|
|
||||||
} else if ((lb == BIT4_0) && (rb == BIT4_0)) {
|
|
||||||
thr_put_bit(thr, idx1, BIT4_1);
|
|
||||||
|
|
||||||
} else {
|
|
||||||
thr_put_bit(thr, idx1, BIT4_X);
|
|
||||||
}
|
|
||||||
|
|
||||||
idx1 += 1;
|
|
||||||
if (idx2 >= 4)
|
|
||||||
idx2 += 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool of_POW(vthread_t thr, vvp_code_t cp)
|
bool of_POW(vthread_t thr, vvp_code_t cp)
|
||||||
|
|
@ -3489,25 +3580,6 @@ bool of_SET_AV(vthread_t thr, vvp_code_t cp)
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
* This implements the "%set/mv <label>, <bit>, <wid>" instruction. In
|
|
||||||
* this case, the <label> is a memory label, and the <bit> and <wid>
|
|
||||||
* are the thread vector of a value to be written in.
|
|
||||||
*/
|
|
||||||
bool of_SET_MV(vthread_t thr, vvp_code_t cp)
|
|
||||||
{
|
|
||||||
unsigned bit = cp->bit_idx[0];
|
|
||||||
unsigned wid = cp->bit_idx[1];
|
|
||||||
unsigned off = thr->words[1].w_int;
|
|
||||||
unsigned adr = thr->words[3].w_int;
|
|
||||||
|
|
||||||
/* Make a vector of the desired width. */
|
|
||||||
vvp_vector4_t value = vthread_bits_to_vector(thr, bit, wid);
|
|
||||||
|
|
||||||
memory_set_word(cp->mem, adr, off, value);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* This implements the "%set/v <label>, <bit>, <wid>" instruction.
|
* This implements the "%set/v <label>, <bit>, <wid>" instruction.
|
||||||
|
|
@ -3529,16 +3601,7 @@ bool of_SET_VEC(vthread_t thr, vvp_code_t cp)
|
||||||
/* set the value into port 0 of the destination. */
|
/* set the value into port 0 of the destination. */
|
||||||
vvp_net_ptr_t ptr (cp->net, 0);
|
vvp_net_ptr_t ptr (cp->net, 0);
|
||||||
|
|
||||||
if (bit >= 4) {
|
vvp_send_vec4(ptr, vthread_bits_to_vector(thr, bit, wid));
|
||||||
vvp_vector4_t value(thr->bits4,bit,wid);
|
|
||||||
vvp_send_vec4(ptr, value);
|
|
||||||
|
|
||||||
} else {
|
|
||||||
/* Make a vector of the desired width. */
|
|
||||||
vvp_bit4_t bit_val = thr_index_to_bit4[bit];
|
|
||||||
vvp_vector4_t value(wid, bit_val);
|
|
||||||
vvp_send_vec4(ptr, value);
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -36,3 +36,4 @@ vpi_sim_vcontrol
|
||||||
vpi_vprintf
|
vpi_vprintf
|
||||||
|
|
||||||
vpip_format_strength
|
vpip_format_strength
|
||||||
|
vpip_set_return_value
|
||||||
|
|
|
||||||
240
vvp/vvp_net.cc
240
vvp/vvp_net.cc
|
|
@ -202,10 +202,84 @@ void vvp_send_long_pv(vvp_net_ptr_t ptr, long val,
|
||||||
|
|
||||||
void vvp_vector4_t::copy_bits(const vvp_vector4_t&that)
|
void vvp_vector4_t::copy_bits(const vvp_vector4_t&that)
|
||||||
{
|
{
|
||||||
unsigned bits_to_copy = (that.size_ < size_) ? that.size_ : size_;
|
|
||||||
|
|
||||||
for (unsigned idx = 0; idx < bits_to_copy; idx += 1)
|
if (size_ == that.size_) {
|
||||||
set_bit(idx, that.value(idx));
|
if (size_ > BITS_PER_WORD) {
|
||||||
|
unsigned words = (size_+BITS_PER_WORD-1) / BITS_PER_WORD;
|
||||||
|
for (unsigned idx = 0 ; idx < words ; idx += 1)
|
||||||
|
abits_ptr_[idx] = that.abits_ptr_[idx];
|
||||||
|
for (unsigned idx = 0 ; idx < words ; idx += 1)
|
||||||
|
bbits_ptr_[idx] = that.bbits_ptr_[idx];
|
||||||
|
} else {
|
||||||
|
abits_val_ = that.abits_val_;
|
||||||
|
bbits_val_ = that.bbits_val_;
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Now we know that the sizes of this and that are definitely
|
||||||
|
different. We can use that in code below. In any case, we
|
||||||
|
need to copy only the smaller of the sizes. */
|
||||||
|
|
||||||
|
/* If source and destination are both short, then mask/copy
|
||||||
|
the bit values. */
|
||||||
|
if (size_ <= BITS_PER_WORD && that.size_ <= BITS_PER_WORD) {
|
||||||
|
unsigned bits_to_copy = (that.size_ < size_) ? that.size_ : size_;
|
||||||
|
unsigned long mask = (1UL << bits_to_copy) - 1UL;
|
||||||
|
abits_val_ &= ~mask;
|
||||||
|
bbits_val_ &= ~mask;
|
||||||
|
abits_val_ |= that.abits_val_&mask;
|
||||||
|
bbits_val_ |= that.bbits_val_&mask;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Now we know that either source or destination are long. If
|
||||||
|
the destination is short, then mask/copy from the low word
|
||||||
|
of the long source. */
|
||||||
|
if (size_ <= BITS_PER_WORD) {
|
||||||
|
abits_val_ = that.abits_ptr_[0];
|
||||||
|
bbits_val_ = that.bbits_ptr_[0];
|
||||||
|
if (size_ < BITS_PER_WORD) {
|
||||||
|
unsigned long mask = (1UL << size_) - 1UL;
|
||||||
|
abits_val_ &= mask;
|
||||||
|
bbits_val_ &= mask;
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Now we know that the destination must be long. If the
|
||||||
|
source is short, then mask/copy from its value. */
|
||||||
|
if (that.size_ <= BITS_PER_WORD) {
|
||||||
|
unsigned long mask;
|
||||||
|
if (that.size_ < BITS_PER_WORD) {
|
||||||
|
mask = (1UL << that.size_) - 1UL;
|
||||||
|
abits_ptr_[0] &= ~mask;
|
||||||
|
bbits_ptr_[0] &= ~mask;
|
||||||
|
} else {
|
||||||
|
mask = -1UL;
|
||||||
|
}
|
||||||
|
abits_ptr_[0] |= that.abits_val_&mask;
|
||||||
|
bbits_ptr_[0] |= that.bbits_val_&mask;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Finally, we know that source and destination are long. copy
|
||||||
|
words until we get to the last. */
|
||||||
|
unsigned bits_to_copy = (that.size_ < size_) ? that.size_ : size_;
|
||||||
|
unsigned word = 0;
|
||||||
|
while (bits_to_copy >= BITS_PER_WORD) {
|
||||||
|
abits_ptr_[word] = that.abits_ptr_[word];
|
||||||
|
bbits_ptr_[word] = that.bbits_ptr_[word];
|
||||||
|
bits_to_copy -= BITS_PER_WORD;
|
||||||
|
word += 1;
|
||||||
|
}
|
||||||
|
if (bits_to_copy > 0) {
|
||||||
|
unsigned long mask = (1UL << bits_to_copy) - 1UL;
|
||||||
|
abits_ptr_[word] &= ~mask;
|
||||||
|
bbits_ptr_[word] &= ~mask;
|
||||||
|
abits_ptr_[word] |= that.abits_ptr_[word] & mask;
|
||||||
|
bbits_ptr_[word] |= that.bbits_ptr_[word] & mask;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void vvp_vector4_t::copy_from_(const vvp_vector4_t&that)
|
void vvp_vector4_t::copy_from_(const vvp_vector4_t&that)
|
||||||
|
|
@ -283,10 +357,58 @@ vvp_vector4_t::vvp_vector4_t(const vvp_vector4_t&that,
|
||||||
dst += 1;
|
dst += 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
} else {
|
} else if (that.size_ > BITS_PER_WORD) {
|
||||||
for (unsigned idx = 0 ; idx < wid ; idx += 1) {
|
/* In this case, the subvector fits in a single word,
|
||||||
set_bit(idx, that.value(adr+idx));
|
but the source is large. */
|
||||||
|
unsigned ptr = adr / BITS_PER_WORD;
|
||||||
|
unsigned long off = adr % BITS_PER_WORD;
|
||||||
|
unsigned trans = BITS_PER_WORD - off;
|
||||||
|
if (trans > wid)
|
||||||
|
trans = wid;
|
||||||
|
|
||||||
|
if (trans == BITS_PER_WORD) {
|
||||||
|
// Very special case: Copy exactly 1 perfectly
|
||||||
|
// aligned word.
|
||||||
|
abits_val_ = that.abits_ptr_[ptr];
|
||||||
|
bbits_val_ = that.bbits_ptr_[ptr];
|
||||||
|
|
||||||
|
} else {
|
||||||
|
// lmask is the low bits of the destination,
|
||||||
|
// masked into the source.
|
||||||
|
unsigned long lmask = (1UL<<trans) - 1UL;
|
||||||
|
lmask <<= off;
|
||||||
|
|
||||||
|
// The low bits of the result.
|
||||||
|
abits_val_ = (that.abits_ptr_[ptr] & lmask) >> off;
|
||||||
|
bbits_val_ = (that.bbits_ptr_[ptr] & lmask) >> off;
|
||||||
|
|
||||||
|
if (trans < wid) {
|
||||||
|
// If there are more bits, then get them
|
||||||
|
// from the bottom of the next word of the
|
||||||
|
// source.
|
||||||
|
unsigned long hmask = (1UL << (wid-trans)) - 1UL;
|
||||||
|
|
||||||
|
// The high bits of the result.
|
||||||
|
abits_val_ |= (that.abits_ptr_[ptr+1]&hmask) << trans;
|
||||||
|
bbits_val_ |= (that.bbits_ptr_[ptr+1]&hmask) << trans;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
} else if (size_ == BITS_PER_WORD) {
|
||||||
|
/* We know that source and destination are short. If the
|
||||||
|
destination is a full word, then we know the copy is
|
||||||
|
aligned and complete. */
|
||||||
|
abits_val_ = that.abits_val_;
|
||||||
|
bbits_val_ = that.bbits_val_;
|
||||||
|
|
||||||
|
} else {
|
||||||
|
/* Finally, the source and destination vectors are both
|
||||||
|
short, so there is a single mask/shift/copy. */
|
||||||
|
unsigned long mask = (1UL << size_) - 1UL;
|
||||||
|
mask <<= adr;
|
||||||
|
|
||||||
|
abits_val_ = (that.abits_val_ & mask) >> adr;
|
||||||
|
bbits_val_ = (that.bbits_val_ & mask) >> adr;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
@ -752,6 +874,93 @@ char* vvp_vector4_t::as_string(char*buf, size_t buf_len)
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void vvp_vector4_t::invert()
|
||||||
|
{
|
||||||
|
if (size_ <= BITS_PER_WORD) {
|
||||||
|
unsigned long mask = (size_<BITS_PER_WORD)? (1UL<<size_)-1UL : -1UL;
|
||||||
|
abits_val_ = mask & ~abits_val_;
|
||||||
|
abits_val_ |= bbits_val_;
|
||||||
|
} else {
|
||||||
|
unsigned remaining = size_;
|
||||||
|
unsigned idx = 0;
|
||||||
|
while (remaining >= BITS_PER_WORD) {
|
||||||
|
abits_ptr_[idx] = ~abits_ptr_[idx];
|
||||||
|
abits_ptr_[idx] |= bbits_ptr_[idx];
|
||||||
|
idx += 1;
|
||||||
|
remaining -= BITS_PER_WORD;
|
||||||
|
}
|
||||||
|
if (remaining > 0) {
|
||||||
|
unsigned long mask = (1UL<<remaining) - 1UL;
|
||||||
|
abits_ptr_[idx] = mask & ~abits_ptr_[idx];
|
||||||
|
abits_ptr_[idx] |= bbits_ptr_[idx];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
vvp_vector4_t& vvp_vector4_t::operator &= (const vvp_vector4_t&that)
|
||||||
|
{
|
||||||
|
// Make sure that all Z bits are turned into X bits.
|
||||||
|
change_z2x();
|
||||||
|
|
||||||
|
// This is sneaky. The truth table is:
|
||||||
|
// 00 01 11
|
||||||
|
// 00 00 00 00
|
||||||
|
// 01 00 01 11
|
||||||
|
// 11 00 11 11
|
||||||
|
if (size_ <= BITS_PER_WORD) {
|
||||||
|
// Each tmp bit is true if that is 1, X or Z.
|
||||||
|
unsigned long tmp = that.abits_val_ | that.bbits_val_;
|
||||||
|
abits_val_ &= that.abits_val_;
|
||||||
|
bbits_val_ = (bbits_val_ & tmp) | (abits_val_&that.bbits_val_);
|
||||||
|
|
||||||
|
} else {
|
||||||
|
unsigned words = (size_ + BITS_PER_WORD - 1) / BITS_PER_WORD;
|
||||||
|
for (unsigned idx = 0; idx < words ; idx += 1) {
|
||||||
|
unsigned long tmp = that.abits_ptr_[idx]|that.bbits_ptr_[idx];
|
||||||
|
abits_ptr_[idx] &= that.abits_ptr_[idx];
|
||||||
|
bbits_ptr_[idx] = (bbits_ptr_[idx]&tmp) | (abits_ptr_[idx]&that.bbits_ptr_[idx]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
vvp_vector4_t& vvp_vector4_t::operator |= (const vvp_vector4_t&that)
|
||||||
|
{
|
||||||
|
// Make sure that all Z bits are turned into X bits.
|
||||||
|
change_z2x();
|
||||||
|
|
||||||
|
// This is sneaky.
|
||||||
|
// The OR is 1 if either operand is 1.
|
||||||
|
// The OR is 0 if both operants are 0.
|
||||||
|
// Otherwise, the AND is X. The truth table is:
|
||||||
|
//
|
||||||
|
// 00 01 11
|
||||||
|
// 00 00 01 11
|
||||||
|
// 01 01 01 01
|
||||||
|
// 11 11 01 11
|
||||||
|
if (size_ <= BITS_PER_WORD) {
|
||||||
|
// Each tmp bit is true if that is 1, X or Z.
|
||||||
|
unsigned long tmp1 = abits_val_ | bbits_val_;
|
||||||
|
unsigned long tmp2 = that.abits_val_ | that.bbits_val_;
|
||||||
|
bbits_val_ = (bbits_val_& ~(that.abits_val_^that.bbits_val_))
|
||||||
|
| (that.bbits_val_& ~abits_val_);
|
||||||
|
abits_val_ = tmp1 | tmp2;
|
||||||
|
|
||||||
|
} else {
|
||||||
|
unsigned words = (size_ + BITS_PER_WORD - 1) / BITS_PER_WORD;
|
||||||
|
for (unsigned idx = 0; idx < words ; idx += 1) {
|
||||||
|
unsigned long tmp1 = abits_ptr_[idx] | bbits_ptr_[idx];
|
||||||
|
unsigned long tmp2 = that.abits_ptr_[idx] | that.bbits_ptr_[idx];
|
||||||
|
bbits_ptr_[idx] = (bbits_ptr_[idx]& ~(that.abits_ptr_[idx]^that.bbits_ptr_[idx]))
|
||||||
|
| (that.bbits_ptr_[idx]& ~abits_ptr_[idx]);
|
||||||
|
abits_ptr_[idx] = tmp1 | tmp2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Add an integer to the vvp_vector4_t in place, bit by bit so that
|
* Add an integer to the vvp_vector4_t in place, bit by bit so that
|
||||||
* there is no size limitations.
|
* there is no size limitations.
|
||||||
|
|
@ -1178,11 +1387,6 @@ void vvp_vector2_t::trim()
|
||||||
while (value(wid_-1) == 0 && wid_ > 1) wid_ -= 1;
|
while (value(wid_-1) == 0 && wid_ > 1) wid_ -= 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
unsigned vvp_vector2_t::size() const
|
|
||||||
{
|
|
||||||
return wid_;
|
|
||||||
}
|
|
||||||
|
|
||||||
int vvp_vector2_t::value(unsigned idx) const
|
int vvp_vector2_t::value(unsigned idx) const
|
||||||
{
|
{
|
||||||
if (idx >= wid_)
|
if (idx >= wid_)
|
||||||
|
|
@ -2755,20 +2959,6 @@ vvp_bit4_t compare_gtge(const vvp_vector4_t&lef, const vvp_vector4_t&rig,
|
||||||
return out_if_equal;
|
return out_if_equal;
|
||||||
}
|
}
|
||||||
|
|
||||||
vvp_vector4_t operator ~ (const vvp_vector4_t&that)
|
|
||||||
{
|
|
||||||
vvp_vector4_t res = that;
|
|
||||||
if (res.size_ <= vvp_vector4_t::BITS_PER_WORD) {
|
|
||||||
res.abits_val_ = res.bbits_val_ | ~res.abits_val_;
|
|
||||||
} else {
|
|
||||||
unsigned cnt = (res.size_ + vvp_vector4_t::BITS_PER_WORD - 1) / vvp_vector4_t::BITS_PER_WORD;
|
|
||||||
for (unsigned idx = 0 ; idx < cnt ; idx += 1)
|
|
||||||
res.abits_ptr_[idx] = res.bbits_val_ | ~res.abits_val_;
|
|
||||||
}
|
|
||||||
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
|
|
||||||
vvp_bit4_t compare_gtge_signed(const vvp_vector4_t&a,
|
vvp_bit4_t compare_gtge_signed(const vvp_vector4_t&a,
|
||||||
const vvp_vector4_t&b,
|
const vvp_vector4_t&b,
|
||||||
vvp_bit4_t out_if_equal)
|
vvp_bit4_t out_if_equal)
|
||||||
|
|
|
||||||
|
|
@ -152,6 +152,9 @@ class vvp_vector4_t {
|
||||||
// Display the value into the buf as a string.
|
// Display the value into the buf as a string.
|
||||||
char*as_string(char*buf, size_t buf_len);
|
char*as_string(char*buf, size_t buf_len);
|
||||||
|
|
||||||
|
void invert();
|
||||||
|
vvp_vector4_t& operator &= (const vvp_vector4_t&that);
|
||||||
|
vvp_vector4_t& operator |= (const vvp_vector4_t&that);
|
||||||
vvp_vector4_t& operator += (int64_t);
|
vvp_vector4_t& operator += (int64_t);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
@ -329,7 +332,13 @@ inline void vvp_vector4_t::set_bit(unsigned idx, vvp_bit4_t val)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
extern vvp_vector4_t operator ~ (const vvp_vector4_t&that);
|
inline vvp_vector4_t operator ~ (const vvp_vector4_t&that)
|
||||||
|
{
|
||||||
|
vvp_vector4_t res = that;
|
||||||
|
res.invert();
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
extern ostream& operator << (ostream&, const vvp_vector4_t&);
|
extern ostream& operator << (ostream&, const vvp_vector4_t&);
|
||||||
|
|
||||||
extern vvp_bit4_t compare_gtge(const vvp_vector4_t&a,
|
extern vvp_bit4_t compare_gtge(const vvp_vector4_t&a,
|
||||||
|
|
@ -421,6 +430,12 @@ extern vvp_vector4_t c4string_to_vector4(const char*str);
|
||||||
|
|
||||||
extern ostream& operator<< (ostream&, const vvp_vector2_t&);
|
extern ostream& operator<< (ostream&, const vvp_vector2_t&);
|
||||||
|
|
||||||
|
/* Inline some of the vector2_t methods. */
|
||||||
|
inline unsigned vvp_vector2_t::size() const
|
||||||
|
{
|
||||||
|
return wid_;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* This class represents a scalar value with strength. These are
|
* This class represents a scalar value with strength. These are
|
||||||
* heavier then the simple vvp_bit4_t, but more information is
|
* heavier then the simple vvp_bit4_t, but more information is
|
||||||
|
|
@ -882,20 +897,29 @@ class vvp_vpi_callback {
|
||||||
vvp_vpi_callback();
|
vvp_vpi_callback();
|
||||||
virtual ~vvp_vpi_callback();
|
virtual ~vvp_vpi_callback();
|
||||||
|
|
||||||
void run_vpi_callbacks();
|
virtual void run_vpi_callbacks();
|
||||||
void add_vpi_callback(struct __vpiCallback*);
|
void add_vpi_callback(struct __vpiCallback*);
|
||||||
|
|
||||||
virtual void get_value(struct t_vpi_value*value) =0;
|
virtual void get_value(struct t_vpi_value*value) =0;
|
||||||
|
|
||||||
|
private:
|
||||||
|
struct __vpiCallback*vpi_callbacks_;
|
||||||
|
};
|
||||||
|
|
||||||
|
class vvp_vpi_callback_wordable : public vvp_vpi_callback {
|
||||||
|
public:
|
||||||
|
vvp_vpi_callback_wordable();
|
||||||
|
~vvp_vpi_callback_wordable();
|
||||||
|
|
||||||
|
void run_vpi_callbacks();
|
||||||
void attach_as_word(class __vpiArray* arr, unsigned long addr);
|
void attach_as_word(class __vpiArray* arr, unsigned long addr);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
struct __vpiCallback*vpi_callbacks_;
|
|
||||||
class __vpiArray* array_;
|
class __vpiArray* array_;
|
||||||
unsigned long array_word_;
|
unsigned long array_word_;
|
||||||
};
|
};
|
||||||
|
|
||||||
class vvp_fun_signal_base : public vvp_net_fun_t, public vvp_vpi_callback {
|
class vvp_fun_signal_base : public vvp_net_fun_t, public vvp_vpi_callback_wordable {
|
||||||
|
|
||||||
public:
|
public:
|
||||||
vvp_fun_signal_base();
|
vvp_fun_signal_base();
|
||||||
|
|
|
||||||
|
|
@ -84,7 +84,7 @@ static void __compile_var(char*label, char*name,
|
||||||
define_functor_symbol(label, node);
|
define_functor_symbol(label, node);
|
||||||
|
|
||||||
vpiHandle obj = 0;
|
vpiHandle obj = 0;
|
||||||
if (! local_flag) {
|
if (! local_flag && !array) {
|
||||||
/* Make the vpiHandle for the reg. */
|
/* Make the vpiHandle for the reg. */
|
||||||
obj = (signed_flag > 1) ?
|
obj = (signed_flag > 1) ?
|
||||||
vpip_make_int(name, msb, lsb, node) :
|
vpip_make_int(name, msb, lsb, node) :
|
||||||
|
|
@ -102,7 +102,7 @@ static void __compile_var(char*label, char*name,
|
||||||
// it is attached to the addressed array.
|
// it is attached to the addressed array.
|
||||||
if (array) {
|
if (array) {
|
||||||
assert(!name);
|
assert(!name);
|
||||||
array_attach_word(array, array_addr, obj);
|
if (obj) array_attach_word(array, array_addr, obj);
|
||||||
}
|
}
|
||||||
free(label);
|
free(label);
|
||||||
if (name) free(name);
|
if (name) free(name);
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue