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