Merge branch 'master' into verilog-ams

This commit is contained in:
Stephen Williams 2008-05-23 21:23:16 -07:00
commit 3575f68c9f
56 changed files with 1659 additions and 1839 deletions

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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;

View File

@ -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 ""

View File

@ -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;
}
} }
/* /*

View File

@ -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@

View File

@ -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();

View File

@ -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

View File

@ -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
} }

View File

@ -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>
/* /*

View File

@ -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);

View File

@ -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;

View File

@ -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 {
} }

View File

@ -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

View File

@ -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

View File

@ -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,

View File

@ -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

View File

@ -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

View File

@ -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;

View File

@ -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");
} }

View File

@ -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. */
if (number_is_immediate(word_ex, 8*sizeof(unsigned))) {
use_word = get_number_immediate(word_ex);
word_ex = 0;
}
}
if (word_ex)
break; 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;
snprintf(buffer, sizeof buffer, "&A<v%p, %u>", sig, use_word);
case IVL_EX_MEMORY: args[idx].text = strdup(buffer);
if (!ivl_expr_oper1(expr)) {
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: free(args);
/* 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);
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");
} }

View File

@ -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,9 +1908,9 @@ 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); draw_eval_expr_into_integer(ix, 3);
if (add_index < 0) { if (add_index < 0) {
fprintf(vvp_out, " %%load/av %u, v%p, %u;\n", fprintf(vvp_out, " %%load/av %u, v%p, %u;\n",
@ -1913,11 +1927,6 @@ static void draw_signal_dest(ivl_expr_t exp, struct vector_info res,
return; return;
} }
/* The index is constant, so we can return to direct
readout with the specific word selected. */
word = get_number_immediate(ix);
}
if (ivl_signal_data_type(sig) == IVL_VT_REAL) { if (ivl_signal_data_type(sig) == IVL_VT_REAL) {
@ -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

View File

@ -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;

View File

@ -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... */
if (number_is_immediate(word_ix, 64)) {
fprintf(vvp_out, " %%ix/load 3, %lu; address\n",
get_number_immediate(word_ix));
} else {
/* Calculate array word index into index register 3 */ /* Calculate array word index into index register 3 */
draw_eval_expr_into_integer(word_ix, 3); draw_eval_expr_into_integer(word_ix, 3);
/* Skip assignment if word expression is not defined. */ /* Skip assignment if word expression is not defined. */
fprintf(vvp_out, " %%jmp/1 t_%u, 4;\n", skip_assign); 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);
if (number_is_immediate(word_ix, 64)) {
fprintf(vvp_out, " %%ix/load 3, %lu; address\n",
get_number_immediate(word_ix));
} else {
/* Calculate array word index into index register 3 */ /* Calculate array word index into index register 3 */
draw_eval_expr_into_integer(word_ix, 3); draw_eval_expr_into_integer(word_ix, 3);
/* Skip assignment if word expression is not defined. */ /* Skip assignment if word expression is not defined. */
fprintf(vvp_out, " %%jmp/1 t_%u, 4;\n", skip_assign); 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,18 +296,14 @@ 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) {
part_off = 0; part_off = 0;
} else if (number_is_immediate(part_off_ex, 64)) { } else if (number_is_immediate(part_off_ex, 64)) {

View File

@ -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);

View File

@ -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

View File

@ -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

View File

@ -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);
} }

View File

@ -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;

View File

@ -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

View File

@ -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

View File

@ -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);
}

View File

@ -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);

View File

@ -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;

View File

@ -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

View File

@ -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.

View File

@ -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)

View File

@ -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. */

View File

@ -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;
} }

View File

@ -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.
*
*/

View File

@ -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

View File

@ -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); }
@ -794,6 +788,8 @@ argument
{ $$ = 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); }
; ;
@ -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; }

View File

@ -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,

View File

@ -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

View File

@ -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);
} }

View File

@ -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) {

View File

@ -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) {

View File

@ -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);
}

View File

@ -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);

View File

@ -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 = {

View File

@ -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;
eeq = BIT4_0;
} else if (lv < rv) {
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; eq = BIT4_X;
} else if (lv != rv) {
break;
} }
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;
}
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; eq = BIT4_X;
} if ((lv == BIT4_0) && (rv==BIT4_1))
eq = BIT4_0;
if ((lv == BIT4_1) && (rv==BIT4_0))
eq = BIT4_0;
if (eq == BIT4_0)
break;
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; thr->words[index].w_int = array[0];
thr_put_bit(thr, 4, BIT4_0);
if (base >= 4) delete[]array;
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);
return true; return true;
} }
@ -2234,14 +2314,16 @@ 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) {
vvp_bit4_t val = word.value(idx);
thr_put_bit(thr, bit, val);
} }
/* Check the address once, before we scan the vector. */
thr_check_addr(thr, bit+wid-1);
/* 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);
vvp_bit4_t lb = thr_get_bit(thr, idx1); return true;
vvp_bit4_t rb = thr_get_bit(thr, idx2);
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);
} }
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 rb = thr_get_bit(thr, idx2);
thr_put_bit(thr, idx1, ~(lb&rb));
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);
vvp_bit4_t lb = thr_get_bit(thr, idx1); return true;
vvp_bit4_t rb = thr_get_bit(thr, idx2);
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);
} }
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 rb = thr_get_bit(thr, idx2);
thr_put_bit(thr, idx1, ~(lb|rb));
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;
} }

View File

@ -36,3 +36,4 @@ vpi_sim_vcontrol
vpi_vprintf vpi_vprintf
vpip_format_strength vpip_format_strength
vpip_set_return_value

View File

@ -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,12 +357,60 @@ vvp_vector4_t::vvp_vector4_t(const vvp_vector4_t&that,
dst += 1; dst += 1;
} }
} else if (that.size_ > BITS_PER_WORD) {
/* In this case, the subvector fits in a single word,
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 { } else {
for (unsigned idx = 0 ; idx < wid ; idx += 1) { // lmask is the low bits of the destination,
set_bit(idx, that.value(adr+idx)); // 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)

View File

@ -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();

View File

@ -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);