Merge branch 'master' of github.com:steveicarus/iverilog
This commit is contained in:
commit
cd76a504ac
14
Makefile.in
14
Makefile.in
|
|
@ -67,9 +67,13 @@ mandir = @mandir@
|
||||||
|
|
||||||
dllib=@DLLIB@
|
dllib=@DLLIB@
|
||||||
|
|
||||||
CC = @CC@
|
# For a cross compile these defines will need to be set accordingly.
|
||||||
HOSTCC = @CC@
|
HOSTCC = @CC@
|
||||||
|
HOSTCFLAGS = @WARNING_FLAGS@ @CFLAGS@
|
||||||
|
|
||||||
|
CC = @CC@
|
||||||
CXX = @CXX@
|
CXX = @CXX@
|
||||||
|
DLLTOOL = @DLLTOOL@
|
||||||
INSTALL = @INSTALL@
|
INSTALL = @INSTALL@
|
||||||
INSTALL_SCRIPT = @INSTALL_SCRIPT@
|
INSTALL_SCRIPT = @INSTALL_SCRIPT@
|
||||||
INSTALL_PROGRAM = @INSTALL_PROGRAM@
|
INSTALL_PROGRAM = @INSTALL_PROGRAM@
|
||||||
|
|
@ -120,7 +124,7 @@ all: dep config.h _pli_types.h version_tag.h ivl@EXEEXT@ version.exe iverilog-vp
|
||||||
ifeq (@MINGW32@,yes)
|
ifeq (@MINGW32@,yes)
|
||||||
all: dosify.exe
|
all: dosify.exe
|
||||||
dosify.exe: $(srcdir)/dosify.c
|
dosify.exe: $(srcdir)/dosify.c
|
||||||
$(CC) -o dosify.exe $(srcdir)/dosify.c
|
$(HOSTCC) $(HOSTCFLAGS) -o dosify.exe $(srcdir)/dosify.c
|
||||||
endif
|
endif
|
||||||
|
|
||||||
# This rule rules the compiler in the trivial hello.vl program to make
|
# This rule rules the compiler in the trivial hello.vl program to make
|
||||||
|
|
@ -203,7 +207,7 @@ ifeq (@WIN32@,yes)
|
||||||
# that really exports the things that the import library imports.
|
# that really exports the things that the import library imports.
|
||||||
ivl@EXEEXT@: $O $(srcdir)/ivl.def
|
ivl@EXEEXT@: $O $(srcdir)/ivl.def
|
||||||
$(CXX) -o ivl@EXEEXT@ $O $(dllib) @EXTRALIBS@
|
$(CXX) -o ivl@EXEEXT@ $O $(dllib) @EXTRALIBS@
|
||||||
dlltool --dllname ivl@EXEEXT@ --def $(srcdir)/ivl.def \
|
$(DLLTOOL) --dllname ivl@EXEEXT@ --def $(srcdir)/ivl.def \
|
||||||
--output-lib libivl.a --output-exp ivl.exp
|
--output-lib libivl.a --output-exp ivl.exp
|
||||||
$(CXX) $(LDFLAGS) -o ivl@EXEEXT@ ivl.exp $O $(dllib) @EXTRALIBS@
|
$(CXX) $(LDFLAGS) -o ivl@EXEEXT@ ivl.exp $O $(dllib) @EXTRALIBS@
|
||||||
else
|
else
|
||||||
|
|
@ -227,7 +231,7 @@ iverilog-vpi: $(srcdir)/iverilog-vpi.sh Makefile
|
||||||
endif
|
endif
|
||||||
|
|
||||||
version.exe: $(srcdir)/version.c $(srcdir)/version_base.h version_tag.h
|
version.exe: $(srcdir)/version.c $(srcdir)/version_base.h version_tag.h
|
||||||
$(HOSTCC) @WARNING_FLAGS@ -o version.exe -I. -I$(srcdir) $(srcdir)/version.c
|
$(HOSTCC) $(HOSTCFLAGS) -o version.exe -I. -I$(srcdir) $(srcdir)/version.c
|
||||||
|
|
||||||
%.o: %.cc config.h
|
%.o: %.cc config.h
|
||||||
$(CXX) $(CPPFLAGS) $(CXXFLAGS) @DEPENDENCY_FLAG@ -c $< -o $*.o
|
$(CXX) $(CPPFLAGS) $(CXXFLAGS) @DEPENDENCY_FLAG@ -c $< -o $*.o
|
||||||
|
|
@ -368,7 +372,7 @@ uninstall:
|
||||||
-rmdir "$(DESTDIR)$(libdir)/ivl$(suffix)"
|
-rmdir "$(DESTDIR)$(libdir)/ivl$(suffix)"
|
||||||
for f in verilog$(suffix) iverilog-vpi$(suffix) gverilog$(suffix)@EXEEXT@; \
|
for f in verilog$(suffix) iverilog-vpi$(suffix) gverilog$(suffix)@EXEEXT@; \
|
||||||
do rm -f "$(DESTDIR)$(bindir)/$$f"; done
|
do rm -f "$(DESTDIR)$(bindir)/$$f"; done
|
||||||
for f in ivl_target.h vpi_user.h _pli_types.h acc_user.h veriuser.h; \
|
for f in ivl_target.h vpi_user.h _pli_types.h sv_vpi_user.h acc_user.h veriuser.h; \
|
||||||
do rm -f "$(DESTDIR)$(includedir)/$$f"; done
|
do rm -f "$(DESTDIR)$(includedir)/$$f"; done
|
||||||
-test X$(suffix) = X || rmdir "$(DESTDIR)/$(includedir)"
|
-test X$(suffix) = X || rmdir "$(DESTDIR)/$(includedir)"
|
||||||
rm -f "$(DESTDIR)$(mandir)/man1/iverilog-vpi$(suffix).1" "$(DESTDIR)$(prefix)/iverilog-vpi$(suffix).pdf"
|
rm -f "$(DESTDIR)$(mandir)/man1/iverilog-vpi$(suffix).1" "$(DESTDIR)$(prefix)/iverilog-vpi$(suffix).pdf"
|
||||||
|
|
|
||||||
13
Statement.cc
13
Statement.cc
|
|
@ -51,22 +51,27 @@ PAssign_::~PAssign_()
|
||||||
}
|
}
|
||||||
|
|
||||||
PAssign::PAssign(PExpr*lval__, PExpr*ex)
|
PAssign::PAssign(PExpr*lval__, PExpr*ex)
|
||||||
: PAssign_(lval__, ex, false)
|
: PAssign_(lval__, ex, false), op_(0)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
PAssign::PAssign(PExpr*lval__, char op, PExpr*ex)
|
||||||
|
: PAssign_(lval__, ex, false), op_(op)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
PAssign::PAssign(PExpr*lval__, PExpr*d, PExpr*ex)
|
PAssign::PAssign(PExpr*lval__, PExpr*d, PExpr*ex)
|
||||||
: PAssign_(lval__, d, ex)
|
: PAssign_(lval__, d, ex), op_(0)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
PAssign::PAssign(PExpr*lval__, PExpr*cnt, PEventStatement*d, PExpr*ex)
|
PAssign::PAssign(PExpr*lval__, PExpr*cnt, PEventStatement*d, PExpr*ex)
|
||||||
: PAssign_(lval__, cnt, d, ex)
|
: PAssign_(lval__, cnt, d, ex), op_(0)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
PAssign::PAssign(PExpr*lval__, PExpr*ex, bool is_constant)
|
PAssign::PAssign(PExpr*lval__, PExpr*ex, bool is_constant)
|
||||||
: PAssign_(lval__, ex, is_constant)
|
: PAssign_(lval__, ex, is_constant), op_(0)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -120,7 +120,12 @@ class PAssign_ : public Statement {
|
||||||
class PAssign : public PAssign_ {
|
class PAssign : public PAssign_ {
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
// lval - assignment l-value
|
||||||
|
// ex - assignment r-value
|
||||||
|
// op - compressed assignment operator (i.e. '+', '-', ...)
|
||||||
|
// de - delayed assignment delay expression
|
||||||
explicit PAssign(PExpr*lval, PExpr*ex);
|
explicit PAssign(PExpr*lval, PExpr*ex);
|
||||||
|
explicit PAssign(PExpr*lval, char op, PExpr*ex);
|
||||||
explicit PAssign(PExpr*lval, PExpr*de, PExpr*ex);
|
explicit PAssign(PExpr*lval, PExpr*de, PExpr*ex);
|
||||||
explicit PAssign(PExpr*lval, PExpr*cnt, PEventStatement*de, PExpr*ex);
|
explicit PAssign(PExpr*lval, PExpr*cnt, PEventStatement*de, PExpr*ex);
|
||||||
explicit PAssign(PExpr*lval, PExpr*ex, bool is_constant);
|
explicit PAssign(PExpr*lval, PExpr*ex, bool is_constant);
|
||||||
|
|
@ -130,6 +135,8 @@ class PAssign : public PAssign_ {
|
||||||
virtual NetProc* elaborate(Design*des, NetScope*scope) const;
|
virtual NetProc* elaborate(Design*des, NetScope*scope) const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
NetProc* elaborate_compressed_(Design*des, NetScope*scope) const;
|
||||||
|
char op_;
|
||||||
};
|
};
|
||||||
|
|
||||||
class PAssignNB : public PAssign_ {
|
class PAssignNB : public PAssign_ {
|
||||||
|
|
|
||||||
|
|
@ -22,7 +22,11 @@ AC_PREREQ([2.60])
|
||||||
AC_PROG_CC_C99
|
AC_PROG_CC_C99
|
||||||
AC_PROG_CXX
|
AC_PROG_CXX
|
||||||
AC_PROG_RANLIB
|
AC_PROG_RANLIB
|
||||||
|
AC_CHECK_TOOL(LD, ld, false)
|
||||||
|
AC_CHECK_TOOL(AR, ar, false)
|
||||||
|
AC_CHECK_TOOL(DLLTOOL, dlltool, false)
|
||||||
AC_CHECK_TOOL(STRIP, strip, true)
|
AC_CHECK_TOOL(STRIP, strip, true)
|
||||||
|
AC_CHECK_TOOL(WINDRES,windres,false)
|
||||||
AC_CHECK_PROGS(XGPERF,gperf,none)
|
AC_CHECK_PROGS(XGPERF,gperf,none)
|
||||||
AC_CHECK_PROGS(MAN,man,none)
|
AC_CHECK_PROGS(MAN,man,none)
|
||||||
AC_CHECK_PROGS(PS2PDF,ps2pdf,none)
|
AC_CHECK_PROGS(PS2PDF,ps2pdf,none)
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,3 @@
|
||||||
// These are correct and are used to find the base (zero) pin.
|
// These are correct and are used to find the base (zero) pin.
|
||||||
thisSubtraction:netlist.h:4164
|
thisSubtraction:netlist.h:4168
|
||||||
thisSubtraction:netlist.h:4173
|
thisSubtraction:netlist.h:4177
|
||||||
|
|
|
||||||
|
|
@ -824,7 +824,10 @@ void NetAssign::dump(ostream&o, unsigned ind) const
|
||||||
o << setw(ind) << "";
|
o << setw(ind) << "";
|
||||||
dump_lval(o);
|
dump_lval(o);
|
||||||
|
|
||||||
o << " = ";
|
if (op_)
|
||||||
|
o << " " << op_ << "= ";
|
||||||
|
else
|
||||||
|
o << " = ";
|
||||||
|
|
||||||
if (const NetExpr*de = get_delay())
|
if (const NetExpr*de = get_delay())
|
||||||
o << "#(" << *de << ") ";
|
o << "#(" << *de << ") ";
|
||||||
|
|
|
||||||
|
|
@ -37,6 +37,7 @@ mandir = @mandir@
|
||||||
dllib=@DLLIB@
|
dllib=@DLLIB@
|
||||||
|
|
||||||
CC = @CC@
|
CC = @CC@
|
||||||
|
WINDRES = @WINDRES@
|
||||||
INSTALL = @INSTALL@
|
INSTALL = @INSTALL@
|
||||||
INSTALL_PROGRAM = @INSTALL_PROGRAM@
|
INSTALL_PROGRAM = @INSTALL_PROGRAM@
|
||||||
INSTALL_DATA = @INSTALL_DATA@
|
INSTALL_DATA = @INSTALL_DATA@
|
||||||
|
|
@ -88,7 +89,7 @@ res.rc: $(srcdir)/res.rc.in ../version.exe
|
||||||
$(srcdir)/res.rc.in > $@
|
$(srcdir)/res.rc.in > $@
|
||||||
|
|
||||||
res.o: res.rc
|
res.o: res.rc
|
||||||
windres -i res.rc -o res.o
|
$(WINDRES) -i res.rc -o res.o
|
||||||
#
|
#
|
||||||
|
|
||||||
install: all installdirs $(bindir)/iverilog-vpi$(suffix)@EXEEXT@
|
install: all installdirs $(bindir)/iverilog-vpi$(suffix)@EXEEXT@
|
||||||
|
|
|
||||||
23
elaborate.cc
23
elaborate.cc
|
|
@ -2259,10 +2259,33 @@ static NetExpr*elaborate_delay_expr(PExpr*expr, Design*des, NetScope*scope)
|
||||||
return dex;
|
return dex;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
NetProc* PAssign::elaborate_compressed_(Design*des, NetScope*scope) const
|
||||||
|
{
|
||||||
|
ivl_assert(*this, ! delay_);
|
||||||
|
ivl_assert(*this, ! count_);
|
||||||
|
ivl_assert(*this, ! event_);
|
||||||
|
|
||||||
|
NetAssign_*lv = elaborate_lval(des, scope);
|
||||||
|
if (lv == 0) return 0;
|
||||||
|
|
||||||
|
NetExpr*rv = elaborate_rval_(des, scope, count_lval_width(lv), lv->expr_type());
|
||||||
|
if (rv == 0) return 0;
|
||||||
|
|
||||||
|
NetAssign*cur = new NetAssign(lv, op_, rv);
|
||||||
|
cur->set_line(*this);
|
||||||
|
|
||||||
|
return cur;
|
||||||
|
}
|
||||||
|
|
||||||
NetProc* PAssign::elaborate(Design*des, NetScope*scope) const
|
NetProc* PAssign::elaborate(Design*des, NetScope*scope) const
|
||||||
{
|
{
|
||||||
assert(scope);
|
assert(scope);
|
||||||
|
|
||||||
|
/* If this is a compressed assignment, then handle the
|
||||||
|
elaboration in a specialized function. */
|
||||||
|
if (op_ != 0)
|
||||||
|
return elaborate_compressed_(des, scope);
|
||||||
|
|
||||||
/* elaborate the lval. This detects any part selects and mux
|
/* elaborate the lval. This detects any part selects and mux
|
||||||
expressions that might exist. */
|
expressions that might exist. */
|
||||||
NetAssign_*lv = elaborate_lval(des, scope);
|
NetAssign_*lv = elaborate_lval(des, scope);
|
||||||
|
|
|
||||||
1
ivl.def
1
ivl.def
|
|
@ -272,6 +272,7 @@ ivl_stmt_lvals
|
||||||
ivl_stmt_lwidth
|
ivl_stmt_lwidth
|
||||||
ivl_stmt_name
|
ivl_stmt_name
|
||||||
ivl_stmt_nevent
|
ivl_stmt_nevent
|
||||||
|
ivl_stmt_opcode
|
||||||
ivl_stmt_parm
|
ivl_stmt_parm
|
||||||
ivl_stmt_parm_count
|
ivl_stmt_parm_count
|
||||||
ivl_stmt_rval
|
ivl_stmt_rval
|
||||||
|
|
|
||||||
|
|
@ -1995,6 +1995,13 @@ extern unsigned ivl_stmt_lineno(ivl_statement_t net);
|
||||||
* the statement.) The ivl_stmt_delay_expr function returns the
|
* the statement.) The ivl_stmt_delay_expr function returns the
|
||||||
* expression for the delay, or nil if there is no delay expression.
|
* expression for the delay, or nil if there is no delay expression.
|
||||||
*
|
*
|
||||||
|
* The blocking assignment (IVL_ST_ASSIGN) may have an associated
|
||||||
|
* opcode, that can be extracted from ivl_stmt_opcode(). This opcode
|
||||||
|
* is the compressed operator used it statements like this:
|
||||||
|
* foo += <expr>
|
||||||
|
* The ivl_stmt_opcode() returns null (0) if this is not a compressed
|
||||||
|
* assignment statment.
|
||||||
|
*
|
||||||
* - IVL_ST_CASSIGN
|
* - IVL_ST_CASSIGN
|
||||||
* This reflects a procedural continuous assignment to an l-value. The
|
* This reflects a procedural continuous assignment to an l-value. The
|
||||||
* l-value is the same as any other assignment (use ivl_stmt_lval).
|
* l-value is the same as any other assignment (use ivl_stmt_lval).
|
||||||
|
|
@ -2088,6 +2095,8 @@ extern unsigned ivl_stmt_lvals(ivl_statement_t net);
|
||||||
extern unsigned ivl_stmt_lwidth(ivl_statement_t net);
|
extern unsigned ivl_stmt_lwidth(ivl_statement_t net);
|
||||||
/* IVL_ST_STASK */
|
/* IVL_ST_STASK */
|
||||||
extern const char* ivl_stmt_name(ivl_statement_t net);
|
extern const char* ivl_stmt_name(ivl_statement_t net);
|
||||||
|
/* IVL_ST_ASSIGN */
|
||||||
|
extern char ivl_stmt_opcode(ivl_statement_t net);
|
||||||
/* IVL_ST_STASK */
|
/* IVL_ST_STASK */
|
||||||
extern ivl_expr_t ivl_stmt_parm(ivl_statement_t net, unsigned idx);
|
extern ivl_expr_t ivl_stmt_parm(ivl_statement_t net, unsigned idx);
|
||||||
/* IVL_ST_STASK */
|
/* IVL_ST_STASK */
|
||||||
|
|
|
||||||
|
|
@ -516,7 +516,7 @@ TU [munpf]
|
||||||
|
|
||||||
^{W}?`begin_keywords{W}? { BEGIN(PPBEGIN_KEYWORDS); }
|
^{W}?`begin_keywords{W}? { BEGIN(PPBEGIN_KEYWORDS); }
|
||||||
|
|
||||||
<PPBEGIN_KEYWORDS>\"[a-zA-Z0-9 -]*\".* {
|
<PPBEGIN_KEYWORDS>\"[a-zA-Z0-9 -\.]*\".* {
|
||||||
keyword_mask_stack.push_front(lexor_keyword_mask);
|
keyword_mask_stack.push_front(lexor_keyword_mask);
|
||||||
|
|
||||||
char*word = yytext+1;
|
char*word = yytext+1;
|
||||||
|
|
|
||||||
|
|
@ -344,7 +344,8 @@ within, GN_KEYWORDS_1800_2005, K_within
|
||||||
# This is the name originally proposed for uwire and is deprecated!
|
# This is the name originally proposed for uwire and is deprecated!
|
||||||
wone, GN_KEYWORDS_1364_2005, K_wone
|
wone, GN_KEYWORDS_1364_2005, K_wone
|
||||||
wor, GN_KEYWORDS_1364_1995, K_wor
|
wor, GN_KEYWORDS_1364_1995, K_wor
|
||||||
wreal, GN_KEYWORDS_VAMS_2_3, K_wreal
|
# This is defined by Verilog-AMS 2.3 and as an Icarus extension.
|
||||||
|
wreal, GN_KEYWORDS_VAMS_2_3|GN_KEYWORDS_ICARUS, K_wreal
|
||||||
xnor, GN_KEYWORDS_1364_1995, K_xnor
|
xnor, GN_KEYWORDS_1364_1995, K_xnor
|
||||||
xor, GN_KEYWORDS_1364_1995, K_xor
|
xor, GN_KEYWORDS_1364_1995, K_xor
|
||||||
zi_nd, GN_KEYWORDS_VAMS_2_3, K_zi_nd
|
zi_nd, GN_KEYWORDS_VAMS_2_3, K_zi_nd
|
||||||
|
|
|
||||||
|
|
@ -31,6 +31,9 @@ libdir = @libdir@
|
||||||
includedir = $(prefix)/include
|
includedir = $(prefix)/include
|
||||||
|
|
||||||
CC = @CC@
|
CC = @CC@
|
||||||
|
RANLIB = @RANLIB@
|
||||||
|
AR = @AR@
|
||||||
|
LD = @LD@
|
||||||
INSTALL = @INSTALL@
|
INSTALL = @INSTALL@
|
||||||
INSTALL_PROGRAM = @INSTALL_PROGRAM@
|
INSTALL_PROGRAM = @INSTALL_PROGRAM@
|
||||||
INSTALL_DATA = @INSTALL_DATA@
|
INSTALL_DATA = @INSTALL_DATA@
|
||||||
|
|
@ -44,7 +47,6 @@ endif
|
||||||
CPPFLAGS = $(INCLUDE_PATH) @CPPFLAGS@ @DEFS@ @PICFLAG@
|
CPPFLAGS = $(INCLUDE_PATH) @CPPFLAGS@ @DEFS@ @PICFLAG@
|
||||||
CFLAGS = @WARNING_FLAGS@ @CFLAGS@
|
CFLAGS = @WARNING_FLAGS@ @CFLAGS@
|
||||||
LDFLAGS = @LDFLAGS@
|
LDFLAGS = @LDFLAGS@
|
||||||
RANLIB = @RANLIB@
|
|
||||||
|
|
||||||
A = a_close.o a_compare_handles.o a_configure.o a_fetch_argc.o \
|
A = a_close.o a_compare_handles.o a_configure.o a_fetch_argc.o \
|
||||||
a_fetch_argv.o a_fetch_dir.o a_fetch_fullname.o a_fetch_location.o \
|
a_fetch_argv.o a_fetch_dir.o a_fetch_fullname.o a_fetch_location.o \
|
||||||
|
|
@ -90,7 +92,7 @@ libveriuser.o: $O
|
||||||
|
|
||||||
libveriuser.a: libveriuser.o
|
libveriuser.a: libveriuser.o
|
||||||
rm -f $@
|
rm -f $@
|
||||||
ar cvq $@ libveriuser.o
|
$(AR) cvq $@ libveriuser.o
|
||||||
$(RANLIB) $@
|
$(RANLIB) $@
|
||||||
|
|
||||||
%.o: %.c config.h
|
%.o: %.c config.h
|
||||||
|
|
|
||||||
|
|
@ -36,8 +36,8 @@ scale(int high, int low, void*obj) {
|
||||||
|
|
||||||
scaled = high;
|
scaled = high;
|
||||||
scaled = (scaled << 32) | low;
|
scaled = (scaled << 32) | low;
|
||||||
scaled *= pow(10, vpi_get(vpiTimePrecision,0) -
|
scaled /= pow(10, vpi_get(vpiTimeUnit,obj ? (vpiHandle)obj : hand) -
|
||||||
vpi_get(vpiTimeUnit,obj ? (vpiHandle)obj : hand));
|
vpi_get(vpiTimePrecision,0));
|
||||||
|
|
||||||
return scaled;
|
return scaled;
|
||||||
}
|
}
|
||||||
|
|
@ -129,8 +129,8 @@ void tf_scale_realdelay(void*obj, double real, double *areal)
|
||||||
{
|
{
|
||||||
vpiHandle hand = vpi_handle(vpiScope, vpi_handle(vpiSysTfCall,0));
|
vpiHandle hand = vpi_handle(vpiScope, vpi_handle(vpiSysTfCall,0));
|
||||||
|
|
||||||
*areal = real * pow(10, vpi_get(vpiTimePrecision, 0) -
|
*areal = real / pow(10, vpi_get(vpiTimeUnit, hand) -
|
||||||
vpi_get(vpiTimeUnit, hand));
|
vpi_get(vpiTimePrecision, 0));
|
||||||
}
|
}
|
||||||
|
|
||||||
void tf_unscale_realdelay(void*obj, double real, double *areal)
|
void tf_unscale_realdelay(void*obj, double real, double *areal)
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (c) 2002-2010 Michael Ruff (mruff at chiaro.com)
|
* Copyright (c) 2002-2011 Michael Ruff (mruff at chiaro.com)
|
||||||
* Michael Runyan (mrunyan at chiaro.com)
|
* Michael Runyan (mrunyan at chiaro.com)
|
||||||
*
|
*
|
||||||
* This source code is free software; you can redistribute it
|
* This source code is free software; you can redistribute it
|
||||||
|
|
@ -402,7 +402,7 @@ PLI_INT32 tf_isetrealdelay(double dly, void*obj)
|
||||||
|
|
||||||
/* Scale delay to SimTime */
|
/* Scale delay to SimTime */
|
||||||
ivl_u64_t delay = ((dly
|
ivl_u64_t delay = ((dly
|
||||||
* pow(10, tf_gettimeprecision() - tf_gettimeunit()))
|
/ pow(10, tf_gettimeunit() - tf_gettimeprecision()))
|
||||||
+ 0.5);
|
+ 0.5);
|
||||||
ti.high = delay >> 32 & 0xffffffff;
|
ti.high = delay >> 32 & 0xffffffff;
|
||||||
ti.low = delay & 0xffffffff;
|
ti.low = delay & 0xffffffff;
|
||||||
|
|
|
||||||
|
|
@ -233,7 +233,12 @@ const NetExpr* NetAssignBase::get_delay() const
|
||||||
}
|
}
|
||||||
|
|
||||||
NetAssign::NetAssign(NetAssign_*lv, NetExpr*rv)
|
NetAssign::NetAssign(NetAssign_*lv, NetExpr*rv)
|
||||||
: NetAssignBase(lv, rv)
|
: NetAssignBase(lv, rv), op_(0)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
NetAssign::NetAssign(NetAssign_*lv, char op, NetExpr*rv)
|
||||||
|
: NetAssignBase(lv, rv), op_(op)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -405,10 +405,10 @@ void NetScope::evaluate_parameter_logic_(Design*des, param_ref_t cur)
|
||||||
}
|
}
|
||||||
(*cur).second.val = expr;
|
(*cur).second.val = expr;
|
||||||
|
|
||||||
/* If the parameter has range information, then make
|
/* If the parameter has type or range information, then make
|
||||||
sure the type is set right. Note that if the
|
sure the type is set right. Note that if the parameter
|
||||||
parameter doesn't have an explicit range, then it
|
doesn't have an explicit type or range, then it will get
|
||||||
will get the signedness from the expression itself. */
|
the signedness from the expression itself. */
|
||||||
if (range_flag) {
|
if (range_flag) {
|
||||||
/* If we have a real value convert it to an integer. */
|
/* If we have a real value convert it to an integer. */
|
||||||
if(NetECReal*tmp = dynamic_cast<NetECReal*>(expr)) {
|
if(NetECReal*tmp = dynamic_cast<NetECReal*>(expr)) {
|
||||||
|
|
@ -419,6 +419,8 @@ void NetScope::evaluate_parameter_logic_(Design*des, param_ref_t cur)
|
||||||
}
|
}
|
||||||
|
|
||||||
(*cur).second.val->cast_signed((*cur).second.signed_flag);
|
(*cur).second.val->cast_signed((*cur).second.signed_flag);
|
||||||
|
} else if ((*cur).second.signed_flag) {
|
||||||
|
(*cur).second.val->cast_signed(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
// If there are no value ranges to test the value against,
|
// If there are no value ranges to test the value against,
|
||||||
|
|
|
||||||
|
|
@ -2406,15 +2406,19 @@ class NetAssign : public NetAssignBase {
|
||||||
|
|
||||||
public:
|
public:
|
||||||
explicit NetAssign(NetAssign_*lv, NetExpr*rv);
|
explicit NetAssign(NetAssign_*lv, NetExpr*rv);
|
||||||
|
explicit NetAssign(NetAssign_*lv, char op, NetExpr*rv);
|
||||||
~NetAssign();
|
~NetAssign();
|
||||||
|
|
||||||
bool is_asynchronous();
|
bool is_asynchronous();
|
||||||
|
|
||||||
|
inline char assign_operator(void) const { return op_; }
|
||||||
|
|
||||||
virtual bool emit_proc(struct target_t*) const;
|
virtual bool emit_proc(struct target_t*) const;
|
||||||
virtual int match_proc(struct proc_match_t*);
|
virtual int match_proc(struct proc_match_t*);
|
||||||
virtual void dump(ostream&, unsigned ind) const;
|
virtual void dump(ostream&, unsigned ind) const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
char op_;
|
||||||
};
|
};
|
||||||
|
|
||||||
class NetAssignNB : public NetAssignBase {
|
class NetAssignNB : public NetAssignBase {
|
||||||
|
|
|
||||||
176
parse.y
176
parse.y
|
|
@ -2337,17 +2337,12 @@ port_declaration
|
||||||
K_output net_type_opt primitive_type_opt unsigned_signed_opt range_opt IDENTIFIER
|
K_output net_type_opt primitive_type_opt unsigned_signed_opt range_opt IDENTIFIER
|
||||||
{ Module::port_t*ptmp;
|
{ Module::port_t*ptmp;
|
||||||
perm_string name = lex_strings.make($7);
|
perm_string name = lex_strings.make($7);
|
||||||
NetNet::Type t = $3;
|
|
||||||
|
|
||||||
if ($4 != IVL_VT_NO_TYPE && t == NetNet::IMPLICIT)
|
|
||||||
t = NetNet::IMPLICIT_REG;
|
|
||||||
|
|
||||||
ptmp = pform_module_port_reference(name, @2.text,
|
ptmp = pform_module_port_reference(name, @2.text,
|
||||||
@2.first_line);
|
@2.first_line);
|
||||||
pform_module_define_port(@2, name, NetNet::POUTPUT,
|
pform_module_define_port(@2, name, NetNet::POUTPUT,
|
||||||
t, $4, $5, $6, $1);
|
$3, $4, $5, $6, $1);
|
||||||
port_declaration_context.port_type = NetNet::POUTPUT;
|
port_declaration_context.port_type = NetNet::POUTPUT;
|
||||||
port_declaration_context.port_net_type = t;
|
port_declaration_context.port_net_type = $3;
|
||||||
port_declaration_context.var_type = $4;
|
port_declaration_context.var_type = $4;
|
||||||
port_declaration_context.sign_flag = $5;
|
port_declaration_context.sign_flag = $5;
|
||||||
delete port_declaration_context.range;
|
delete port_declaration_context.range;
|
||||||
|
|
@ -2396,10 +2391,7 @@ port_declaration
|
||||||
K_output net_type_opt primitive_type_opt unsigned_signed_opt range_opt IDENTIFIER '=' expression
|
K_output net_type_opt primitive_type_opt unsigned_signed_opt range_opt IDENTIFIER '=' expression
|
||||||
{ Module::port_t*ptmp;
|
{ Module::port_t*ptmp;
|
||||||
perm_string name = lex_strings.make($7);
|
perm_string name = lex_strings.make($7);
|
||||||
NetNet::Type t = $3;
|
NetNet::Type t = ($3 == NetNet::IMPLICIT) ? NetNet::IMPLICIT_REG : $3;
|
||||||
|
|
||||||
if ($4 != IVL_VT_NO_TYPE && t == NetNet::IMPLICIT)
|
|
||||||
t = NetNet::IMPLICIT_REG;
|
|
||||||
|
|
||||||
ptmp = pform_module_port_reference(name, @2.text,
|
ptmp = pform_module_port_reference(name, @2.text,
|
||||||
@2.first_line);
|
@2.first_line);
|
||||||
|
|
@ -3320,6 +3312,16 @@ parameter_assign_decl
|
||||||
param_active_signed = false;
|
param_active_signed = false;
|
||||||
param_active_type = IVL_VT_LOGIC;
|
param_active_type = IVL_VT_LOGIC;
|
||||||
}
|
}
|
||||||
|
| K_signed
|
||||||
|
{ param_active_range = 0;
|
||||||
|
param_active_signed = true;
|
||||||
|
param_active_type = IVL_VT_LOGIC;
|
||||||
|
}
|
||||||
|
parameter_assign_list
|
||||||
|
{ param_active_range = 0;
|
||||||
|
param_active_signed = false;
|
||||||
|
param_active_type = IVL_VT_LOGIC;
|
||||||
|
}
|
||||||
| K_signed range
|
| K_signed range
|
||||||
{ param_active_range = $2;
|
{ param_active_range = $2;
|
||||||
param_active_signed = true;
|
param_active_signed = true;
|
||||||
|
|
@ -3435,6 +3437,16 @@ localparam_assign_decl
|
||||||
param_active_signed = false;
|
param_active_signed = false;
|
||||||
param_active_type = IVL_VT_LOGIC;
|
param_active_type = IVL_VT_LOGIC;
|
||||||
}
|
}
|
||||||
|
| K_signed
|
||||||
|
{ param_active_range = 0;
|
||||||
|
param_active_signed = true;
|
||||||
|
param_active_type = IVL_VT_LOGIC;
|
||||||
|
}
|
||||||
|
localparam_assign_list
|
||||||
|
{ param_active_range = 0;
|
||||||
|
param_active_signed = false;
|
||||||
|
param_active_type = IVL_VT_LOGIC;
|
||||||
|
}
|
||||||
| K_signed range
|
| K_signed range
|
||||||
{ param_active_range = $2;
|
{ param_active_range = $2;
|
||||||
param_active_signed = true;
|
param_active_signed = true;
|
||||||
|
|
@ -4560,11 +4572,11 @@ statement
|
||||||
tmp->set_statement($6);
|
tmp->set_statement($6);
|
||||||
$$ = tmp;
|
$$ = tmp;
|
||||||
}
|
}
|
||||||
| lpvalue '=' expression ';'
|
| lpvalue '=' expression ';'
|
||||||
{ PAssign*tmp = new PAssign($1,$3);
|
{ PAssign*tmp = new PAssign($1,$3);
|
||||||
FILE_NAME(tmp, @1);
|
FILE_NAME(tmp, @1);
|
||||||
$$ = tmp;
|
$$ = tmp;
|
||||||
}
|
}
|
||||||
| error '=' expression ';'
|
| error '=' expression ';'
|
||||||
{ yyerror(@2, "Syntax in assignment statement l-value.");
|
{ yyerror(@2, "Syntax in assignment statement l-value.");
|
||||||
yyerrok;
|
yyerrok;
|
||||||
|
|
@ -4671,83 +4683,61 @@ statement
|
||||||
;
|
;
|
||||||
|
|
||||||
compressed_statement
|
compressed_statement
|
||||||
: lpvalue K_PLUS_EQ expression
|
: lpvalue K_PLUS_EQ expression
|
||||||
{
|
{ PAssign*tmp = new PAssign($1, '+', $3);
|
||||||
PEBinary *t = new PEBinary('+', $1, $3);
|
FILE_NAME(tmp, @1);
|
||||||
PAssign *tmp = new PAssign($1, t);
|
$$ = tmp;
|
||||||
FILE_NAME(tmp, @1);
|
}
|
||||||
$$ = tmp;
|
| lpvalue K_MINUS_EQ expression
|
||||||
}
|
{ PAssign*tmp = new PAssign($1, '-', $3);
|
||||||
| lpvalue K_MINUS_EQ expression
|
FILE_NAME(tmp, @1);
|
||||||
{
|
$$ = tmp;
|
||||||
PEBinary *t = new PEBinary('-', $1, $3);
|
}
|
||||||
PAssign *tmp = new PAssign($1, t);
|
| lpvalue K_MUL_EQ expression
|
||||||
FILE_NAME(tmp, @1);
|
{ PAssign*tmp = new PAssign($1, '*', $3);
|
||||||
$$ = tmp;
|
FILE_NAME(tmp, @1);
|
||||||
}
|
$$ = tmp;
|
||||||
| lpvalue K_MUL_EQ expression
|
}
|
||||||
{
|
| lpvalue K_DIV_EQ expression
|
||||||
PEBinary *t = new PEBinary('*', $1, $3);
|
{ PAssign*tmp = new PAssign($1, '/', $3);
|
||||||
PAssign *tmp = new PAssign($1, t);
|
FILE_NAME(tmp, @1);
|
||||||
FILE_NAME(tmp, @1);
|
$$ = tmp;
|
||||||
$$ = tmp;
|
}
|
||||||
}
|
| lpvalue K_MOD_EQ expression
|
||||||
| lpvalue K_DIV_EQ expression
|
{ PAssign*tmp = new PAssign($1, '%', $3);
|
||||||
{
|
FILE_NAME(tmp, @1);
|
||||||
PEBinary *t = new PEBinary('/', $1, $3);
|
$$ = tmp;
|
||||||
PAssign *tmp = new PAssign($1, t);
|
}
|
||||||
FILE_NAME(tmp, @1);
|
| lpvalue K_AND_EQ expression
|
||||||
$$ = tmp;
|
{ PAssign*tmp = new PAssign($1, '&', $3);
|
||||||
}
|
FILE_NAME(tmp, @1);
|
||||||
| lpvalue K_MOD_EQ expression
|
$$ = tmp;
|
||||||
{
|
}
|
||||||
PEBinary *t = new PEBinary('%', $1, $3);
|
| lpvalue K_OR_EQ expression
|
||||||
PAssign *tmp = new PAssign($1, t);
|
{ PAssign*tmp = new PAssign($1, '|', $3);
|
||||||
FILE_NAME(tmp, @1);
|
FILE_NAME(tmp, @1);
|
||||||
$$ = tmp;
|
$$ = tmp;
|
||||||
}
|
}
|
||||||
| lpvalue K_AND_EQ expression
|
| lpvalue K_XOR_EQ expression
|
||||||
{
|
{ PAssign*tmp = new PAssign($1, '^', $3);
|
||||||
PEBinary *t = new PEBinary('&', $1, $3);
|
FILE_NAME(tmp, @1);
|
||||||
PAssign *tmp = new PAssign($1, t);
|
$$ = tmp;
|
||||||
FILE_NAME(tmp, @1);
|
}
|
||||||
$$ = tmp;
|
| lpvalue K_LS_EQ expression
|
||||||
}
|
{ PAssign *tmp = new PAssign($1, 'l', $3);
|
||||||
| lpvalue K_OR_EQ expression
|
FILE_NAME(tmp, @1);
|
||||||
{
|
$$ = tmp;
|
||||||
PEBinary *t = new PEBinary('|', $1, $3);
|
}
|
||||||
PAssign *tmp = new PAssign($1, t);
|
| lpvalue K_RS_EQ expression
|
||||||
FILE_NAME(tmp, @1);
|
{ PAssign*tmp = new PAssign($1, 'r', $3);
|
||||||
$$ = tmp;
|
FILE_NAME(tmp, @1);
|
||||||
}
|
$$ = tmp;
|
||||||
| lpvalue K_XOR_EQ expression
|
}
|
||||||
{
|
| lpvalue K_RSS_EQ expression
|
||||||
PEBinary *t = new PEBinary('^', $1, $3);
|
{ PAssign *tmp = new PAssign($1, 'R', $3);
|
||||||
PAssign *tmp = new PAssign($1, t);
|
FILE_NAME(tmp, @1);
|
||||||
FILE_NAME(tmp, @1);
|
$$ = tmp;
|
||||||
$$ = tmp;
|
}
|
||||||
}
|
|
||||||
| lpvalue K_LS_EQ expression
|
|
||||||
{
|
|
||||||
PEBShift *t = new PEBShift('l', $1, $3);
|
|
||||||
PAssign *tmp = new PAssign($1, t);
|
|
||||||
FILE_NAME(tmp, @1);
|
|
||||||
$$ = tmp;
|
|
||||||
}
|
|
||||||
| lpvalue K_RS_EQ expression
|
|
||||||
{
|
|
||||||
PEBShift *t = new PEBShift('r', $1, $3);
|
|
||||||
PAssign *tmp = new PAssign($1, t);
|
|
||||||
FILE_NAME(tmp, @1);
|
|
||||||
$$ = tmp;
|
|
||||||
}
|
|
||||||
| lpvalue K_RSS_EQ expression
|
|
||||||
{
|
|
||||||
PEBShift *t = new PEBShift('R', $1, $3);
|
|
||||||
PAssign *tmp = new PAssign($1, t);
|
|
||||||
FILE_NAME(tmp, @1);
|
|
||||||
$$ = tmp;
|
|
||||||
}
|
|
||||||
;
|
;
|
||||||
|
|
||||||
statement_list_or_null
|
statement_list_or_null
|
||||||
|
|
|
||||||
|
|
@ -15,6 +15,8 @@
|
||||||
#
|
#
|
||||||
# The complete steps to make a snapshot YYYYMMDD generally are:
|
# The complete steps to make a snapshot YYYYMMDD generally are:
|
||||||
#
|
#
|
||||||
|
# edit the verilog.spec to set the rev_date to YYYYMMDD
|
||||||
|
#
|
||||||
# git tag -a sYYYYMMDD
|
# git tag -a sYYYYMMDD
|
||||||
# (Make the tag in the local git repository.)
|
# (Make the tag in the local git repository.)
|
||||||
#
|
#
|
||||||
|
|
|
||||||
11
t-dll-api.cc
11
t-dll-api.cc
|
|
@ -2547,6 +2547,17 @@ extern "C" const char* ivl_stmt_name(ivl_statement_t net)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
extern "C" char ivl_stmt_opcode(ivl_statement_t net)
|
||||||
|
{
|
||||||
|
switch (net->type_) {
|
||||||
|
case IVL_ST_ASSIGN:
|
||||||
|
return net->u_.assign_.oper;
|
||||||
|
default:
|
||||||
|
assert(0);
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
extern "C" ivl_expr_t ivl_stmt_parm(ivl_statement_t net, unsigned idx)
|
extern "C" ivl_expr_t ivl_stmt_parm(ivl_statement_t net, unsigned idx)
|
||||||
{
|
{
|
||||||
switch (net->type_) {
|
switch (net->type_) {
|
||||||
|
|
|
||||||
|
|
@ -210,6 +210,7 @@ bool dll_target::proc_assign(const NetAssign*net)
|
||||||
/* Make the lval fields. */
|
/* Make the lval fields. */
|
||||||
make_assign_lvals_(net);
|
make_assign_lvals_(net);
|
||||||
|
|
||||||
|
stmt_cur_->u_.assign_.oper = net->assign_operator();
|
||||||
assert(expr_ == 0);
|
assert(expr_ == 0);
|
||||||
net->rval()->expr_scan(this);
|
net->rval()->expr_scan(this);
|
||||||
stmt_cur_->u_.assign_.rval_ = expr_;
|
stmt_cur_->u_.assign_.rval_ = expr_;
|
||||||
|
|
|
||||||
1
t-dll.h
1
t-dll.h
|
|
@ -729,6 +729,7 @@ struct ivl_statement_s {
|
||||||
IVL_ST_CASSIGN, IVL_ST_DEASSIGN */
|
IVL_ST_CASSIGN, IVL_ST_DEASSIGN */
|
||||||
unsigned lvals_;
|
unsigned lvals_;
|
||||||
struct ivl_lval_s*lval_;
|
struct ivl_lval_s*lval_;
|
||||||
|
char oper; // Operator if this is a compressed assignment.
|
||||||
ivl_expr_t rval_;
|
ivl_expr_t rval_;
|
||||||
ivl_expr_t delay;
|
ivl_expr_t delay;
|
||||||
// The following are only for NB event control.
|
// The following are only for NB event control.
|
||||||
|
|
|
||||||
|
|
@ -179,6 +179,7 @@ void show_stmt_wait(ivl_statement_t net, unsigned ind)
|
||||||
void show_statement(ivl_statement_t net, unsigned ind)
|
void show_statement(ivl_statement_t net, unsigned ind)
|
||||||
{
|
{
|
||||||
unsigned idx;
|
unsigned idx;
|
||||||
|
char opcode = 0;
|
||||||
const ivl_statement_type_t code = ivl_statement_type(net);
|
const ivl_statement_type_t code = ivl_statement_type(net);
|
||||||
|
|
||||||
switch (code) {
|
switch (code) {
|
||||||
|
|
@ -188,8 +189,11 @@ void show_statement(ivl_statement_t net, unsigned ind)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case IVL_ST_ASSIGN:
|
case IVL_ST_ASSIGN:
|
||||||
fprintf(out, "%*sASSIGN <lwidth=%u>\n", ind, "",
|
opcode = ivl_stmt_opcode(net);
|
||||||
ivl_stmt_lwidth(net));
|
if (opcode == 0)
|
||||||
|
opcode = ' ';
|
||||||
|
fprintf(out, "%*sASSIGN <lwidth=%u> opcode=%c\n", ind, "",
|
||||||
|
ivl_stmt_lwidth(net), opcode);
|
||||||
|
|
||||||
for (idx = 0 ; idx < ivl_stmt_lvals(net) ; idx += 1)
|
for (idx = 0 ; idx < ivl_stmt_lvals(net) ; idx += 1)
|
||||||
show_assign_lval(ivl_stmt_lval(net, idx), ind+4);
|
show_assign_lval(ivl_stmt_lval(net, idx), ind+4);
|
||||||
|
|
|
||||||
|
|
@ -49,8 +49,8 @@ CFLAGS = @WARNING_FLAGS@ @CFLAGS@
|
||||||
LDFLAGS = @LDFLAGS@
|
LDFLAGS = @LDFLAGS@
|
||||||
|
|
||||||
O = vvp.o draw_enum.o draw_mux.o draw_net_input.o draw_switch.o draw_ufunc.o draw_vpi.o \
|
O = vvp.o draw_enum.o draw_mux.o draw_net_input.o draw_switch.o draw_ufunc.o draw_vpi.o \
|
||||||
eval_bool.o eval_expr.o eval_real.o modpath.o vector.o vvp_process.o \
|
eval_bool.o eval_expr.o eval_real.o modpath.o stmt_assign.o vector.o \
|
||||||
vvp_scope.o
|
vvp_process.o vvp_scope.o
|
||||||
|
|
||||||
all: dep vvp.tgt vvp.conf vvp-s.conf
|
all: dep vvp.tgt vvp.conf vvp-s.conf
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,750 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2011 Stephen Williams (steve@icarus.com)
|
||||||
|
*
|
||||||
|
* This source code is free software; you can redistribute it
|
||||||
|
* and/or modify it in source code form under the terms of the GNU
|
||||||
|
* General Public License as published by the Free Software
|
||||||
|
* Foundation; either version 2 of the License, or (at your option)
|
||||||
|
* any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
|
||||||
|
*/
|
||||||
|
|
||||||
|
# include "vvp_priv.h"
|
||||||
|
# include <string.h>
|
||||||
|
# include <assert.h>
|
||||||
|
# include <stdlib.h>
|
||||||
|
|
||||||
|
#ifdef __MINGW32__ /* MinGW has inconsistent %p output. */
|
||||||
|
#define snprintf _snprintf
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* These functions handle the blocking assignment. Use the %set
|
||||||
|
* instruction to perform the actual assignment, and calculate any
|
||||||
|
* lvalues and rvalues that need calculating.
|
||||||
|
*
|
||||||
|
* The set_to_lvariable function takes a particular nexus and generates
|
||||||
|
* the %set statements to assign the value.
|
||||||
|
*
|
||||||
|
* The show_stmt_assign function looks at the assign statement, scans
|
||||||
|
* the l-values, and matches bits of the r-value with the correct
|
||||||
|
* nexus.
|
||||||
|
*/
|
||||||
|
|
||||||
|
enum slice_type_e {
|
||||||
|
SLICE_NO_TYPE = 0,
|
||||||
|
SLICE_SIMPLE_VECTOR,
|
||||||
|
SLICE_PART_SELECT_STATIC,
|
||||||
|
SLICE_PART_SELECT_DYNAMIC,
|
||||||
|
SLICE_MEMORY_WORD_STATIC,
|
||||||
|
SLICE_MEMORY_WORD_DYNAMIC
|
||||||
|
};
|
||||||
|
|
||||||
|
struct vec_slice_info {
|
||||||
|
enum slice_type_e type;
|
||||||
|
|
||||||
|
union {
|
||||||
|
struct {
|
||||||
|
unsigned long use_word;
|
||||||
|
} simple_vector;
|
||||||
|
|
||||||
|
struct {
|
||||||
|
unsigned long part_off;
|
||||||
|
} part_select_static;
|
||||||
|
|
||||||
|
struct {
|
||||||
|
/* Index reg that holds the memory word index */
|
||||||
|
int word_idx_reg;
|
||||||
|
/* Stored x/non-x flag */
|
||||||
|
unsigned x_flag;
|
||||||
|
} part_select_dynamic;
|
||||||
|
|
||||||
|
struct {
|
||||||
|
unsigned long use_word;
|
||||||
|
} memory_word_static;
|
||||||
|
|
||||||
|
struct {
|
||||||
|
/* Index reg that holds the memory word index */
|
||||||
|
int word_idx_reg;
|
||||||
|
/* Stored x/non-x flag */
|
||||||
|
unsigned x_flag;
|
||||||
|
} memory_word_dynamic;
|
||||||
|
} u_;
|
||||||
|
};
|
||||||
|
|
||||||
|
static void get_vec_from_lval_slice(ivl_lval_t lval, struct vec_slice_info*slice,
|
||||||
|
unsigned bit, unsigned wid)
|
||||||
|
{
|
||||||
|
ivl_signal_t sig = ivl_lval_sig(lval);
|
||||||
|
ivl_expr_t part_off_ex = ivl_lval_part_off(lval);
|
||||||
|
unsigned long part_off = 0;
|
||||||
|
|
||||||
|
/* Although Verilog doesn't support it, we'll handle
|
||||||
|
here the case of an l-value part select of an array
|
||||||
|
word if the address is constant. */
|
||||||
|
ivl_expr_t word_ix = ivl_lval_idx(lval);
|
||||||
|
unsigned long use_word = 0;
|
||||||
|
|
||||||
|
if (part_off_ex == 0) {
|
||||||
|
part_off = 0;
|
||||||
|
} else if (number_is_immediate(part_off_ex, IMM_WID, 0) &&
|
||||||
|
!number_is_unknown(part_off_ex)) {
|
||||||
|
part_off = get_number_immediate(part_off_ex);
|
||||||
|
part_off_ex = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* If the word index is a constant expression, then evaluate
|
||||||
|
it to select the word, and pay no further heed to the
|
||||||
|
expression itself. */
|
||||||
|
if (word_ix && number_is_immediate(word_ix, IMM_WID, 0)) {
|
||||||
|
assert(! number_is_unknown(word_ix));
|
||||||
|
use_word = get_number_immediate(word_ix);
|
||||||
|
word_ix = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ivl_lval_mux(lval))
|
||||||
|
part_off_ex = ivl_lval_mux(lval);
|
||||||
|
|
||||||
|
if (ivl_signal_dimensions(sig)==0 && part_off_ex==0 && word_ix==0
|
||||||
|
&& part_off==0 && wid==ivl_signal_width(sig)) {
|
||||||
|
|
||||||
|
slice->type = SLICE_SIMPLE_VECTOR;
|
||||||
|
slice->u_.simple_vector.use_word = use_word;
|
||||||
|
fprintf(vvp_out, " %%load/v %u, v%p_%lu, %u;\n",
|
||||||
|
bit, sig, use_word, wid);
|
||||||
|
|
||||||
|
} else if (ivl_signal_dimensions(sig)==0 && part_off_ex==0 && word_ix==0) {
|
||||||
|
|
||||||
|
assert(use_word == 0);
|
||||||
|
|
||||||
|
slice->type = SLICE_PART_SELECT_STATIC;
|
||||||
|
slice->u_.part_select_static.part_off = part_off;
|
||||||
|
|
||||||
|
fprintf(vvp_out, " %%ix/load 1, %lu, 0;\n", part_off);
|
||||||
|
fprintf(vvp_out, " %%load/x1p %u, v%p_0, %u;\n", bit, sig, wid);
|
||||||
|
|
||||||
|
} else if (ivl_signal_dimensions(sig)==0 && part_off_ex!=0 && word_ix==0) {
|
||||||
|
|
||||||
|
unsigned skip_set = transient_id++;
|
||||||
|
unsigned out_set = transient_id++;
|
||||||
|
|
||||||
|
assert(use_word == 0);
|
||||||
|
assert(part_off == 0);
|
||||||
|
|
||||||
|
slice->type = SLICE_PART_SELECT_DYNAMIC;
|
||||||
|
|
||||||
|
draw_eval_expr_into_integer(part_off_ex, 1);
|
||||||
|
|
||||||
|
slice->u_.part_select_dynamic.word_idx_reg = allocate_word();
|
||||||
|
slice->u_.part_select_dynamic.x_flag = allocate_vector(1);
|
||||||
|
|
||||||
|
fprintf(vvp_out, " %%mov %u, %u, 1;\n",
|
||||||
|
slice->u_.part_select_dynamic.x_flag, 4);
|
||||||
|
fprintf(vvp_out, " %%mov/wu %d, %d;\n",
|
||||||
|
slice->u_.part_select_dynamic.word_idx_reg, 1);
|
||||||
|
|
||||||
|
fprintf(vvp_out, " %%jmp/1 t_%u, 4;\n", skip_set);
|
||||||
|
fprintf(vvp_out, " %%load/x1p %u, v%p_0, %u;\n", bit, sig, wid);
|
||||||
|
fprintf(vvp_out, " %%jmp t_%u;\n", out_set);
|
||||||
|
fprintf(vvp_out, "t_%u ;\n", skip_set);
|
||||||
|
fprintf(vvp_out, " %%mov %u, 2, %u;\n", bit, wid);
|
||||||
|
fprintf(vvp_out, "t_%u ;\n", out_set);
|
||||||
|
|
||||||
|
} else if (ivl_signal_dimensions(sig) > 0 && word_ix == 0) {
|
||||||
|
|
||||||
|
slice->type = SLICE_MEMORY_WORD_STATIC;
|
||||||
|
slice->u_.memory_word_static.use_word = use_word;
|
||||||
|
if (use_word < ivl_signal_array_count(sig)) {
|
||||||
|
fprintf(vvp_out, " %%ix/load 3, %lu, 0;\n",
|
||||||
|
use_word);
|
||||||
|
fprintf(vvp_out, " %%load/av %u, v%p, %u;\n",
|
||||||
|
bit, sig, wid);
|
||||||
|
} else {
|
||||||
|
fprintf(vvp_out, " %%mov %u, 2, %u; OUT OF BOUNDS\n",
|
||||||
|
bit, wid);
|
||||||
|
}
|
||||||
|
|
||||||
|
} else if (ivl_signal_dimensions(sig) > 0 && word_ix != 0) {
|
||||||
|
|
||||||
|
unsigned skip_set = transient_id++;
|
||||||
|
unsigned out_set = transient_id++;
|
||||||
|
slice->type = SLICE_MEMORY_WORD_DYNAMIC;
|
||||||
|
|
||||||
|
draw_eval_expr_into_integer(word_ix, 3);
|
||||||
|
slice->u_.memory_word_dynamic.word_idx_reg = allocate_word();
|
||||||
|
slice->u_.memory_word_dynamic.x_flag = allocate_vector(1);
|
||||||
|
fprintf(vvp_out, " %%mov/wu %d, 3;\n",
|
||||||
|
slice->u_.memory_word_dynamic.word_idx_reg);
|
||||||
|
fprintf(vvp_out, " %%mov %u, 4, 1;\n",
|
||||||
|
slice->u_.memory_word_dynamic.x_flag);
|
||||||
|
|
||||||
|
fprintf(vvp_out, " %%jmp/1 t_%u, 4;\n", skip_set);
|
||||||
|
fprintf(vvp_out, " %%ix/load 1, 0, 0;\n");
|
||||||
|
fprintf(vvp_out, " %%load/av %u, v%p, %u;\n",
|
||||||
|
bit, sig, wid);
|
||||||
|
fprintf(vvp_out, " %%jmp t_%u;\n", out_set);
|
||||||
|
fprintf(vvp_out, "t_%u ;\n", skip_set);
|
||||||
|
fprintf(vvp_out, " %%mov %u, 2, %u;\n", bit, wid);
|
||||||
|
fprintf(vvp_out, "t_%u ;\n", out_set);
|
||||||
|
|
||||||
|
} else {
|
||||||
|
assert(0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct vector_info get_vec_from_lval(ivl_statement_t net,
|
||||||
|
struct vec_slice_info*slices)
|
||||||
|
{
|
||||||
|
struct vector_info res;
|
||||||
|
unsigned lidx;
|
||||||
|
unsigned cur_bit;
|
||||||
|
|
||||||
|
res.wid = ivl_stmt_lwidth(net);
|
||||||
|
res.base = allocate_vector(res.wid);
|
||||||
|
|
||||||
|
cur_bit = 0;
|
||||||
|
for (lidx = 0 ; lidx < ivl_stmt_lvals(net) ; lidx += 1) {
|
||||||
|
unsigned bidx;
|
||||||
|
ivl_lval_t lval;
|
||||||
|
unsigned bit_limit = res.wid - cur_bit;
|
||||||
|
|
||||||
|
lval = ivl_stmt_lval(net, lidx);
|
||||||
|
|
||||||
|
if (bit_limit > ivl_lval_width(lval))
|
||||||
|
bit_limit = ivl_lval_width(lval);
|
||||||
|
|
||||||
|
bidx = res.base + cur_bit;
|
||||||
|
|
||||||
|
get_vec_from_lval_slice(lval, slices+lidx, bidx, bit_limit);
|
||||||
|
|
||||||
|
cur_bit += bit_limit;
|
||||||
|
}
|
||||||
|
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void put_vec_to_lval_slice(ivl_lval_t lval, struct vec_slice_info*slice,
|
||||||
|
unsigned bit, unsigned wid)
|
||||||
|
{
|
||||||
|
unsigned skip_set = transient_id++;
|
||||||
|
struct vector_info tmp;
|
||||||
|
ivl_signal_t sig = ivl_lval_sig(lval);
|
||||||
|
|
||||||
|
/* If the slice of the l-value is a BOOL variable, then cast
|
||||||
|
the data to a BOOL vector so that the stores can be valid. */
|
||||||
|
if (ivl_signal_data_type(sig) == IVL_VT_BOOL) {
|
||||||
|
fprintf(vvp_out, " %%cast2 %u, %u, %u;\n", bit, bit, wid);
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (slice->type) {
|
||||||
|
default:
|
||||||
|
assert(0);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case SLICE_SIMPLE_VECTOR:
|
||||||
|
fprintf(vvp_out, " %%set/v v%p_%lu, %u, %u;\n",
|
||||||
|
sig, slice->u_.simple_vector.use_word, bit, wid);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case SLICE_PART_SELECT_STATIC:
|
||||||
|
fprintf(vvp_out, " %%ix/load 0, %lu, 0;\n",
|
||||||
|
slice->u_.part_select_static.part_off);
|
||||||
|
fprintf(vvp_out, " %%set/x0 v%p_0, %u, %u;\n", sig, bit, wid);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case SLICE_PART_SELECT_DYNAMIC:
|
||||||
|
fprintf(vvp_out, " %%jmp/1 t_%u, %u;\n", skip_set,
|
||||||
|
slice->u_.part_select_dynamic.x_flag);
|
||||||
|
fprintf(vvp_out, " %%mov/wu 0, %d;\n",
|
||||||
|
slice->u_.part_select_dynamic.word_idx_reg);
|
||||||
|
fprintf(vvp_out, " %%set/x0 v%p_0, %u, %u;\n", sig, bit, wid);
|
||||||
|
fprintf(vvp_out, "t_%u ;\n", skip_set);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case SLICE_MEMORY_WORD_STATIC:
|
||||||
|
if (slice->u_.simple_vector.use_word >= ivl_signal_array_count(sig))
|
||||||
|
break;
|
||||||
|
fprintf(vvp_out, " %%ix/load 3, %lu, 0;\n",
|
||||||
|
slice->u_.simple_vector.use_word);
|
||||||
|
fprintf(vvp_out, " %%set/av v%p, %u, %u;\n",
|
||||||
|
sig, bit, wid);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case SLICE_MEMORY_WORD_DYNAMIC:
|
||||||
|
fprintf(vvp_out, " %%jmp/1 t_%u, %u;\n", skip_set,
|
||||||
|
slice->u_.memory_word_dynamic.x_flag);
|
||||||
|
fprintf(vvp_out, " %%mov/wu 3, %d;\n",
|
||||||
|
slice->u_.memory_word_dynamic.word_idx_reg);
|
||||||
|
fprintf(vvp_out, " %%set/av v%p, %u, %u;\n",
|
||||||
|
ivl_lval_sig(lval), bit, wid);
|
||||||
|
fprintf(vvp_out, "t_%u ;\n", skip_set);
|
||||||
|
|
||||||
|
tmp.base = slice->u_.memory_word_dynamic.x_flag;
|
||||||
|
tmp.wid = 1;
|
||||||
|
clr_vector(tmp);
|
||||||
|
clr_word(slice->u_.memory_word_dynamic.word_idx_reg);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void put_vec_to_lval(ivl_statement_t net, struct vec_slice_info*slices,
|
||||||
|
struct vector_info res)
|
||||||
|
{
|
||||||
|
unsigned lidx;
|
||||||
|
unsigned cur_bit;
|
||||||
|
|
||||||
|
cur_bit = 0;
|
||||||
|
for (lidx = 0 ; lidx < ivl_stmt_lvals(net) ; lidx += 1) {
|
||||||
|
unsigned bidx;
|
||||||
|
ivl_lval_t lval;
|
||||||
|
unsigned bit_limit = res.wid - cur_bit;
|
||||||
|
|
||||||
|
lval = ivl_stmt_lval(net, lidx);
|
||||||
|
|
||||||
|
if (bit_limit > ivl_lval_width(lval))
|
||||||
|
bit_limit = ivl_lval_width(lval);
|
||||||
|
|
||||||
|
bidx = res.base + cur_bit;
|
||||||
|
|
||||||
|
put_vec_to_lval_slice(lval, slices+lidx, bidx, bit_limit);
|
||||||
|
|
||||||
|
cur_bit += bit_limit;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void set_vec_to_lval_slice(ivl_lval_t lval, unsigned bit, unsigned wid)
|
||||||
|
{
|
||||||
|
ivl_signal_t sig = ivl_lval_sig(lval);
|
||||||
|
ivl_expr_t part_off_ex = ivl_lval_part_off(lval);
|
||||||
|
unsigned long part_off = 0;
|
||||||
|
|
||||||
|
/* Although Verilog doesn't support it, we'll handle
|
||||||
|
here the case of an l-value part select of an array
|
||||||
|
word if the address is constant. */
|
||||||
|
ivl_expr_t word_ix = ivl_lval_idx(lval);
|
||||||
|
unsigned long use_word = 0;
|
||||||
|
|
||||||
|
if (part_off_ex == 0) {
|
||||||
|
part_off = 0;
|
||||||
|
} else if (number_is_immediate(part_off_ex, IMM_WID, 0) &&
|
||||||
|
!number_is_unknown(part_off_ex)) {
|
||||||
|
part_off = get_number_immediate(part_off_ex);
|
||||||
|
part_off_ex = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* If the word index is a constant expression, then evaluate
|
||||||
|
it to select the word, and pay no further heed to the
|
||||||
|
expression itself. */
|
||||||
|
if (word_ix && number_is_immediate(word_ix, IMM_WID, 0)) {
|
||||||
|
assert(! number_is_unknown(word_ix));
|
||||||
|
use_word = get_number_immediate(word_ix);
|
||||||
|
word_ix = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ivl_lval_mux(lval))
|
||||||
|
part_off_ex = ivl_lval_mux(lval);
|
||||||
|
|
||||||
|
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
|
||||||
|
a bit-select l-val. Presumably, the x0 index register
|
||||||
|
has been loaded wit the result of the evaluated
|
||||||
|
part select base expression. */
|
||||||
|
assert(!word_ix);
|
||||||
|
|
||||||
|
draw_eval_expr_into_integer(part_off_ex, 0);
|
||||||
|
fprintf(vvp_out, " %%jmp/1 t_%u, 4;\n", skip_set);
|
||||||
|
|
||||||
|
fprintf(vvp_out, " %%set/x0 v%p_%lu, %u, %u;\n",
|
||||||
|
sig, use_word, bit, wid);
|
||||||
|
fprintf(vvp_out, "t_%u ;\n", skip_set);
|
||||||
|
/* save_signal width of 0 CLEARS the signal from the
|
||||||
|
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, 0;\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, 0;\n", use_word);
|
||||||
|
}
|
||||||
|
fprintf(vvp_out, " %%ix/load 1, %lu, 0;\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
|
||||||
|
vector set instruction. */
|
||||||
|
assert(ivl_lval_width(lval) == wid);
|
||||||
|
|
||||||
|
/* If the word index is a constant, then we can write
|
||||||
|
directly to the word and save the index calculation. */
|
||||||
|
if (word_ix == 0) {
|
||||||
|
fprintf(vvp_out, " %%ix/load 0, %lu, 0;\n", part_off);
|
||||||
|
fprintf(vvp_out, " %%set/x0 v%p_%lu, %u, %u;\n",
|
||||||
|
sig, use_word, bit, wid);
|
||||||
|
|
||||||
|
} else {
|
||||||
|
unsigned skip_set = transient_id++;
|
||||||
|
unsigned index_reg = 3;
|
||||||
|
draw_eval_expr_into_integer(word_ix, index_reg);
|
||||||
|
fprintf(vvp_out, " %%jmp/1 t_%u, 4;\n", skip_set);
|
||||||
|
fprintf(vvp_out, " %%ix/load 1, %lu, 0;\n", part_off);
|
||||||
|
fprintf(vvp_out, " %%set/av v%p, %u, %u;\n",
|
||||||
|
sig, bit, wid);
|
||||||
|
fprintf(vvp_out, "t_%u ;\n", skip_set);
|
||||||
|
}
|
||||||
|
/* save_signal width of 0 CLEARS the signal from the
|
||||||
|
lookaside. */
|
||||||
|
save_signal_lookaside(bit, sig, use_word, 0);
|
||||||
|
|
||||||
|
} 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, " %%ix/load 1, 0, 0;\n");
|
||||||
|
fprintf(vvp_out, " %%ix/load 3, %lu, 0;\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);
|
||||||
|
}
|
||||||
|
|
||||||
|
} else {
|
||||||
|
unsigned skip_set = transient_id++;
|
||||||
|
unsigned index_reg = 3;
|
||||||
|
draw_eval_expr_into_integer(word_ix, index_reg);
|
||||||
|
fprintf(vvp_out, " %%jmp/1 t_%u, 4;\n", skip_set);
|
||||||
|
fprintf(vvp_out, " %%ix/load 1, 0, 0;\n");
|
||||||
|
fprintf(vvp_out, " %%set/av v%p, %u, %u;\n",
|
||||||
|
sig, bit, wid);
|
||||||
|
fprintf(vvp_out, "t_%u ;\n", skip_set);
|
||||||
|
}
|
||||||
|
/* save_signal width of 0 CLEARS the signal from the
|
||||||
|
lookaside. */
|
||||||
|
save_signal_lookaside(bit, sig, use_word, 0);
|
||||||
|
|
||||||
|
|
||||||
|
} else {
|
||||||
|
fprintf(vvp_out, " %%set/v v%p_%lu, %u, %u;\n",
|
||||||
|
sig, use_word, bit, wid);
|
||||||
|
/* save_signal width of 0 CLEARS the signal from the
|
||||||
|
lookaside. */
|
||||||
|
save_signal_lookaside(bit, sig, use_word, 0);
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This is a private function to generate %set code for the
|
||||||
|
* statement. At this point, the r-value is evaluated and stored in
|
||||||
|
* the res vector, I just need to generate the %set statements for the
|
||||||
|
* l-values of the assignment.
|
||||||
|
*/
|
||||||
|
static void set_vec_to_lval(ivl_statement_t net, struct vector_info res)
|
||||||
|
{
|
||||||
|
ivl_lval_t lval;
|
||||||
|
|
||||||
|
unsigned wid = res.wid;
|
||||||
|
unsigned lidx;
|
||||||
|
unsigned cur_rbit = 0;
|
||||||
|
|
||||||
|
for (lidx = 0 ; lidx < ivl_stmt_lvals(net) ; lidx += 1) {
|
||||||
|
unsigned bidx;
|
||||||
|
unsigned bit_limit = wid - cur_rbit;
|
||||||
|
|
||||||
|
lval = ivl_stmt_lval(net, lidx);
|
||||||
|
|
||||||
|
/* Reduce bit_limit to the width of this l-value. */
|
||||||
|
if (bit_limit > ivl_lval_width(lval))
|
||||||
|
bit_limit = ivl_lval_width(lval);
|
||||||
|
|
||||||
|
/* This is the address within the larger r-value of the
|
||||||
|
bit that this l-value takes. */
|
||||||
|
bidx = res.base < 4? res.base : (res.base+cur_rbit);
|
||||||
|
|
||||||
|
set_vec_to_lval_slice(lval, bidx, bit_limit);
|
||||||
|
|
||||||
|
/* Now we've consumed this many r-value bits for the
|
||||||
|
current l-value. */
|
||||||
|
cur_rbit += bit_limit;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static int show_stmt_assign_vector(ivl_statement_t net)
|
||||||
|
{
|
||||||
|
ivl_expr_t rval = ivl_stmt_rval(net);
|
||||||
|
struct vector_info res;
|
||||||
|
struct vector_info lres;
|
||||||
|
struct vec_slice_info*slices = 0;
|
||||||
|
|
||||||
|
/* If this is a compressed assignment, then get the contents
|
||||||
|
of the l-value. We need these values as part of the r-value
|
||||||
|
calculation. */
|
||||||
|
if (ivl_stmt_opcode(net) != 0) {
|
||||||
|
slices = calloc(ivl_stmt_lvals(net), sizeof(struct vec_slice_info));
|
||||||
|
lres = get_vec_from_lval(net, slices);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Handle the special case that the expression is a real
|
||||||
|
value. Evaluate the real expression, then convert the
|
||||||
|
result to a vector. Then store that vector into the
|
||||||
|
l-value. */
|
||||||
|
if (ivl_expr_value(rval) == IVL_VT_REAL) {
|
||||||
|
int word = draw_eval_real(rval);
|
||||||
|
/* This is the accumulated with of the l-value of the
|
||||||
|
assignment. */
|
||||||
|
unsigned wid = ivl_stmt_lwidth(net);
|
||||||
|
|
||||||
|
res.base = allocate_vector(wid);
|
||||||
|
res.wid = wid;
|
||||||
|
|
||||||
|
if (res.base == 0) {
|
||||||
|
fprintf(stderr, "%s:%u: vvp.tgt error: "
|
||||||
|
"Unable to allocate %u thread bits for "
|
||||||
|
"r-value expression.\n", ivl_expr_file(rval),
|
||||||
|
ivl_expr_lineno(rval), wid);
|
||||||
|
vvp_errors += 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
fprintf(vvp_out, " %%cvt/vr %u, %d, %u;\n",
|
||||||
|
res.base, word, res.wid);
|
||||||
|
|
||||||
|
clr_word(word);
|
||||||
|
|
||||||
|
} else {
|
||||||
|
res = draw_eval_expr(rval, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (ivl_stmt_opcode(net)) {
|
||||||
|
case 0:
|
||||||
|
set_vec_to_lval(net, res);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case '+':
|
||||||
|
if (res.base > 3) {
|
||||||
|
fprintf(vvp_out, " %%add %u, %u, %u;\n",
|
||||||
|
res.base, lres.base, res.wid);
|
||||||
|
clr_vector(lres);
|
||||||
|
} else {
|
||||||
|
fprintf(vvp_out, " %%add %u, %u, %u;\n",
|
||||||
|
lres.base, res.base, res.wid);
|
||||||
|
res.base = lres.base;
|
||||||
|
}
|
||||||
|
put_vec_to_lval(net, slices, res);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case '-':
|
||||||
|
fprintf(vvp_out, " %%sub %u, %u, %u;\n",
|
||||||
|
lres.base, res.base, res.wid);
|
||||||
|
fprintf(vvp_out, " %%mov %u, %u, %u;\n",
|
||||||
|
res.base, lres.base, res.wid);
|
||||||
|
clr_vector(lres);
|
||||||
|
put_vec_to_lval(net, slices, res);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case '*':
|
||||||
|
if (res.base > 3) {
|
||||||
|
fprintf(vvp_out, " %%mul %u, %u, %u;\n",
|
||||||
|
res.base, lres.base, res.wid);
|
||||||
|
clr_vector(lres);
|
||||||
|
} else {
|
||||||
|
fprintf(vvp_out, " %%mul %u, %u, %u;\n",
|
||||||
|
lres.base, res.base, res.wid);
|
||||||
|
res.base = lres.base;
|
||||||
|
}
|
||||||
|
put_vec_to_lval(net, slices, res);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case '/':
|
||||||
|
fprintf(vvp_out, " %%div%s %u, %u, %u;\n",
|
||||||
|
ivl_expr_signed(rval)? "/s" : "",
|
||||||
|
lres.base, res.base, res.wid);
|
||||||
|
fprintf(vvp_out, " %%mov %u, %u, %u;\n",
|
||||||
|
res.base, lres.base, res.wid);
|
||||||
|
clr_vector(lres);
|
||||||
|
put_vec_to_lval(net, slices, res);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case '%':
|
||||||
|
fprintf(vvp_out, " %%mod%s %u, %u, %u;\n",
|
||||||
|
ivl_expr_signed(rval)? "/s" : "",
|
||||||
|
lres.base, res.base, res.wid);
|
||||||
|
fprintf(vvp_out, " %%mov %u, %u, %u;\n",
|
||||||
|
res.base, lres.base, res.wid);
|
||||||
|
clr_vector(lres);
|
||||||
|
put_vec_to_lval(net, slices, res);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case '&':
|
||||||
|
if (res.base > 3) {
|
||||||
|
fprintf(vvp_out, " %%and %u, %u, %u;\n",
|
||||||
|
res.base, lres.base, res.wid);
|
||||||
|
clr_vector(lres);
|
||||||
|
} else {
|
||||||
|
fprintf(vvp_out, " %%and %u, %u, %u;\n",
|
||||||
|
lres.base, res.base, res.wid);
|
||||||
|
res.base = lres.base;
|
||||||
|
}
|
||||||
|
put_vec_to_lval(net, slices, res);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case '|':
|
||||||
|
if (res.base > 3) {
|
||||||
|
fprintf(vvp_out, " %%or %u, %u, %u;\n",
|
||||||
|
res.base, lres.base, res.wid);
|
||||||
|
clr_vector(lres);
|
||||||
|
} else {
|
||||||
|
fprintf(vvp_out, " %%or %u, %u, %u;\n",
|
||||||
|
lres.base, res.base, res.wid);
|
||||||
|
res.base = lres.base;
|
||||||
|
}
|
||||||
|
put_vec_to_lval(net, slices, res);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case '^':
|
||||||
|
if (res.base > 3) {
|
||||||
|
fprintf(vvp_out, " %%xor %u, %u, %u;\n",
|
||||||
|
res.base, lres.base, res.wid);
|
||||||
|
clr_vector(lres);
|
||||||
|
} else {
|
||||||
|
fprintf(vvp_out, " %%xor %u, %u, %u;\n",
|
||||||
|
lres.base, res.base, res.wid);
|
||||||
|
res.base = lres.base;
|
||||||
|
}
|
||||||
|
put_vec_to_lval(net, slices, res);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'l': /* lres <<= res */
|
||||||
|
fprintf(vvp_out, " %%ix/get 0, %u, %u;\n", res.base, res.wid);
|
||||||
|
fprintf(vvp_out, " %%shiftl/i0 %u, %u;\n", lres.base, res.wid);
|
||||||
|
fprintf(vvp_out, " %%mov %u, %u, %u;\n",
|
||||||
|
res.base, lres.base, res.wid);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'r': /* lres >>= res */
|
||||||
|
fprintf(vvp_out, " %%ix/get 0, %u, %u;\n", res.base, res.wid);
|
||||||
|
fprintf(vvp_out, " %%shiftr/i0 %u, %u;\n", lres.base, res.wid);
|
||||||
|
fprintf(vvp_out, " %%mov %u, %u, %u;\n",
|
||||||
|
res.base, lres.base, res.wid);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'R': /* lres >>>= res */
|
||||||
|
fprintf(vvp_out, " %%ix/get 0, %u, %u;\n", res.base, res.wid);
|
||||||
|
fprintf(vvp_out, " %%shiftr/s/i0 %u, %u;\n", lres.base, res.wid);
|
||||||
|
fprintf(vvp_out, " %%mov %u, %u, %u;\n",
|
||||||
|
res.base, lres.base, res.wid);
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
fprintf(vvp_out, "; UNSUPPORTED ASSIGNMENT OPCODE: %c\n", ivl_stmt_opcode(net));
|
||||||
|
assert(0);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (slices)
|
||||||
|
free(slices);
|
||||||
|
if (res.base > 3)
|
||||||
|
clr_vector(res);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This function assigns a value to a real .variable. This is destined
|
||||||
|
* for /dev/null when typed ivl_signal_t takes over all the real
|
||||||
|
* variable support.
|
||||||
|
*/
|
||||||
|
static int show_stmt_assign_sig_real(ivl_statement_t net)
|
||||||
|
{
|
||||||
|
int res;
|
||||||
|
ivl_lval_t lval;
|
||||||
|
ivl_signal_t var;
|
||||||
|
|
||||||
|
assert(ivl_stmt_opcode(net) == 0);
|
||||||
|
|
||||||
|
res = draw_eval_real(ivl_stmt_rval(net));
|
||||||
|
|
||||||
|
assert(ivl_stmt_lvals(net) == 1);
|
||||||
|
lval = ivl_stmt_lval(net, 0);
|
||||||
|
var = ivl_lval_sig(lval);
|
||||||
|
assert(var != 0);
|
||||||
|
|
||||||
|
if (ivl_signal_dimensions(var) == 0) {
|
||||||
|
clr_word(res);
|
||||||
|
fprintf(vvp_out, " %%set/wr v%p_0, %d;\n", var, res);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// For now, only support 1-dimensional arrays.
|
||||||
|
assert(ivl_signal_dimensions(var) == 1);
|
||||||
|
|
||||||
|
// Calculate the word index into an index register
|
||||||
|
ivl_expr_t word_ex = ivl_lval_idx(lval);
|
||||||
|
int word_ix = allocate_word();
|
||||||
|
draw_eval_expr_into_integer(word_ex, word_ix);
|
||||||
|
// Generate an assignment to write to the array.
|
||||||
|
fprintf(vvp_out, " %%set/ar v%p, %d, %d;\n", var, word_ix, res);
|
||||||
|
|
||||||
|
clr_word(res);
|
||||||
|
clr_word(word_ix);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int show_stmt_assign(ivl_statement_t net)
|
||||||
|
{
|
||||||
|
ivl_lval_t lval;
|
||||||
|
ivl_signal_t sig;
|
||||||
|
|
||||||
|
show_stmt_file_line(net, "Blocking assignment.");
|
||||||
|
|
||||||
|
lval = ivl_stmt_lval(net, 0);
|
||||||
|
|
||||||
|
sig = ivl_lval_sig(lval);
|
||||||
|
if (sig && (ivl_signal_data_type(sig) == IVL_VT_REAL)) {
|
||||||
|
return show_stmt_assign_sig_real(net);
|
||||||
|
}
|
||||||
|
|
||||||
|
return show_stmt_assign_vector(net);
|
||||||
|
}
|
||||||
|
|
@ -39,6 +39,8 @@ extern FILE* vvp_out;
|
||||||
*/
|
*/
|
||||||
extern int vvp_errors;
|
extern int vvp_errors;
|
||||||
|
|
||||||
|
extern unsigned transient_id;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Set to non-zero when the user wants to display file and line number
|
* Set to non-zero when the user wants to display file and line number
|
||||||
* information for procedural statements.
|
* information for procedural statements.
|
||||||
|
|
@ -311,6 +313,9 @@ extern int draw_eval_real(ivl_expr_t ex);
|
||||||
*/
|
*/
|
||||||
extern int draw_eval_bool64(ivl_expr_t ex);
|
extern int draw_eval_bool64(ivl_expr_t ex);
|
||||||
|
|
||||||
|
extern int show_stmt_assign(ivl_statement_t net);
|
||||||
|
extern void show_stmt_file_line(ivl_statement_t net, const char*desc);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* These functions manage word register allocation.
|
* These functions manage word register allocation.
|
||||||
*/
|
*/
|
||||||
|
|
|
||||||
|
|
@ -31,7 +31,7 @@ static int show_statement(ivl_statement_t net, ivl_scope_t sscope);
|
||||||
unsigned local_count = 0;
|
unsigned local_count = 0;
|
||||||
unsigned thread_count = 0;
|
unsigned thread_count = 0;
|
||||||
|
|
||||||
static unsigned transient_id = 0;
|
unsigned transient_id = 0;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* This file includes the code needed to generate VVP code for
|
* This file includes the code needed to generate VVP code for
|
||||||
|
|
@ -39,173 +39,6 @@ static unsigned transient_id = 0;
|
||||||
* executable code for the processes.
|
* executable code for the processes.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
* These functions handle the blocking assignment. Use the %set
|
|
||||||
* instruction to perform the actual assignment, and calculate any
|
|
||||||
* lvalues and rvalues that need calculating.
|
|
||||||
*
|
|
||||||
* The set_to_lvariable function takes a particular nexus and generates
|
|
||||||
* the %set statements to assign the value.
|
|
||||||
*
|
|
||||||
* The show_stmt_assign function looks at the assign statement, scans
|
|
||||||
* the l-values, and matches bits of the r-value with the correct
|
|
||||||
* nexus.
|
|
||||||
*/
|
|
||||||
|
|
||||||
static void set_to_lvariable(ivl_lval_t lval,
|
|
||||||
unsigned bit, unsigned wid)
|
|
||||||
{
|
|
||||||
ivl_signal_t sig = ivl_lval_sig(lval);
|
|
||||||
ivl_expr_t part_off_ex = ivl_lval_part_off(lval);
|
|
||||||
unsigned long part_off = 0;
|
|
||||||
|
|
||||||
/* Although Verilog doesn't support it, we'll handle
|
|
||||||
here the case of an l-value part select of an array
|
|
||||||
word if the address is constant. */
|
|
||||||
ivl_expr_t word_ix = ivl_lval_idx(lval);
|
|
||||||
unsigned long use_word = 0;
|
|
||||||
|
|
||||||
if (part_off_ex == 0) {
|
|
||||||
part_off = 0;
|
|
||||||
} else if (number_is_immediate(part_off_ex, IMM_WID, 0) &&
|
|
||||||
!number_is_unknown(part_off_ex)) {
|
|
||||||
part_off = get_number_immediate(part_off_ex);
|
|
||||||
part_off_ex = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* If the word index is a constant expression, then evaluate
|
|
||||||
it to select the word, and pay no further heed to the
|
|
||||||
expression itself. */
|
|
||||||
if (word_ix && number_is_immediate(word_ix, IMM_WID, 0)) {
|
|
||||||
assert(! number_is_unknown(word_ix));
|
|
||||||
use_word = get_number_immediate(word_ix);
|
|
||||||
word_ix = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (ivl_lval_mux(lval))
|
|
||||||
part_off_ex = ivl_lval_mux(lval);
|
|
||||||
|
|
||||||
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
|
|
||||||
a bit-select l-val. Presumably, the x0 index register
|
|
||||||
has been loaded wit the result of the evaluated
|
|
||||||
part select base expression. */
|
|
||||||
assert(!word_ix);
|
|
||||||
|
|
||||||
draw_eval_expr_into_integer(part_off_ex, 0);
|
|
||||||
fprintf(vvp_out, " %%jmp/1 t_%u, 4;\n", skip_set);
|
|
||||||
|
|
||||||
fprintf(vvp_out, " %%set/x0 v%p_%lu, %u, %u;\n",
|
|
||||||
sig, use_word, bit, wid);
|
|
||||||
fprintf(vvp_out, "t_%u ;\n", skip_set);
|
|
||||||
/* save_signal width of 0 CLEARS the signal from the
|
|
||||||
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, 0;\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, 0;\n", use_word);
|
|
||||||
}
|
|
||||||
fprintf(vvp_out, " %%ix/load 1, %lu, 0;\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
|
|
||||||
vector set instruction. */
|
|
||||||
assert(ivl_lval_width(lval) == wid);
|
|
||||||
|
|
||||||
/* If the word index is a constant, then we can write
|
|
||||||
directly to the word and save the index calculation. */
|
|
||||||
if (word_ix == 0) {
|
|
||||||
fprintf(vvp_out, " %%ix/load 0, %lu, 0;\n", part_off);
|
|
||||||
fprintf(vvp_out, " %%set/x0 v%p_%lu, %u, %u;\n",
|
|
||||||
sig, use_word, bit, wid);
|
|
||||||
|
|
||||||
} else {
|
|
||||||
unsigned skip_set = transient_id++;
|
|
||||||
unsigned index_reg = 3;
|
|
||||||
draw_eval_expr_into_integer(word_ix, index_reg);
|
|
||||||
fprintf(vvp_out, " %%jmp/1 t_%u, 4;\n", skip_set);
|
|
||||||
fprintf(vvp_out, " %%ix/load 1, %lu, 0;\n", part_off);
|
|
||||||
fprintf(vvp_out, " %%set/av v%p, %u, %u;\n",
|
|
||||||
sig, bit, wid);
|
|
||||||
fprintf(vvp_out, "t_%u ;\n", skip_set);
|
|
||||||
}
|
|
||||||
/* save_signal width of 0 CLEARS the signal from the
|
|
||||||
lookaside. */
|
|
||||||
save_signal_lookaside(bit, sig, use_word, 0);
|
|
||||||
|
|
||||||
} 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, " %%ix/load 1, 0, 0;\n");
|
|
||||||
fprintf(vvp_out, " %%ix/load 3, %lu, 0;\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);
|
|
||||||
}
|
|
||||||
|
|
||||||
} else {
|
|
||||||
unsigned skip_set = transient_id++;
|
|
||||||
unsigned index_reg = 3;
|
|
||||||
draw_eval_expr_into_integer(word_ix, index_reg);
|
|
||||||
fprintf(vvp_out, " %%jmp/1 t_%u, 4;\n", skip_set);
|
|
||||||
fprintf(vvp_out, " %%ix/load 1, 0, 0;\n");
|
|
||||||
fprintf(vvp_out, " %%set/av v%p, %u, %u;\n",
|
|
||||||
sig, bit, wid);
|
|
||||||
fprintf(vvp_out, "t_%u ;\n", skip_set);
|
|
||||||
}
|
|
||||||
/* save_signal width of 0 CLEARS the signal from the
|
|
||||||
lookaside. */
|
|
||||||
save_signal_lookaside(bit, sig, use_word, 0);
|
|
||||||
|
|
||||||
|
|
||||||
} else {
|
|
||||||
fprintf(vvp_out, " %%set/v v%p_%lu, %u, %u;\n",
|
|
||||||
sig, use_word, bit, wid);
|
|
||||||
/* save_signal width of 0 CLEARS the signal from the
|
|
||||||
lookaside. */
|
|
||||||
save_signal_lookaside(bit, sig, use_word, 0);
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Support a non-blocking assignment to a real array word. */
|
/* Support a non-blocking assignment to a real array word. */
|
||||||
static void assign_to_array_r_word(ivl_signal_t lsig, ivl_expr_t word_ix,
|
static void assign_to_array_r_word(ivl_signal_t lsig, ivl_expr_t word_ix,
|
||||||
unsigned bit, uint64_t delay,
|
unsigned bit, uint64_t delay,
|
||||||
|
|
@ -499,48 +332,11 @@ static void assign_to_lvector(ivl_lval_t lval, unsigned bit,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
* This is a private function to generate %set code for the
|
|
||||||
* statement. At this point, the r-value is evaluated and stored in
|
|
||||||
* the res vector, I just need to generate the %set statements for the
|
|
||||||
* l-values of the assignment.
|
|
||||||
*/
|
|
||||||
static void set_vec_to_lval(ivl_statement_t net, struct vector_info res)
|
|
||||||
{
|
|
||||||
ivl_lval_t lval;
|
|
||||||
|
|
||||||
unsigned wid = res.wid;
|
|
||||||
unsigned lidx;
|
|
||||||
unsigned cur_rbit = 0;
|
|
||||||
|
|
||||||
for (lidx = 0 ; lidx < ivl_stmt_lvals(net) ; lidx += 1) {
|
|
||||||
unsigned bidx;
|
|
||||||
unsigned bit_limit = wid - cur_rbit;
|
|
||||||
|
|
||||||
lval = ivl_stmt_lval(net, lidx);
|
|
||||||
|
|
||||||
/* Reduce bit_limit to the width of this l-value. */
|
|
||||||
if (bit_limit > ivl_lval_width(lval))
|
|
||||||
bit_limit = ivl_lval_width(lval);
|
|
||||||
|
|
||||||
/* This is the address within the larger r-value of the
|
|
||||||
bit that this l-value takes. */
|
|
||||||
bidx = res.base < 4? res.base : (res.base+cur_rbit);
|
|
||||||
|
|
||||||
set_to_lvariable(lval, bidx, bit_limit);
|
|
||||||
|
|
||||||
/* Now we've consumed this many r-value bits for the
|
|
||||||
current l-value. */
|
|
||||||
cur_rbit += bit_limit;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Routine to insert statement tracing information into the output stream
|
* Routine to insert statement tracing information into the output stream
|
||||||
* when requested by the user (compiler).
|
* when requested by the user (compiler).
|
||||||
*/
|
*/
|
||||||
static void show_stmt_file_line(ivl_statement_t net, const char* desc)
|
void show_stmt_file_line(ivl_statement_t net, const char* desc)
|
||||||
{
|
{
|
||||||
if (show_file_line) {
|
if (show_file_line) {
|
||||||
/* If the line number is not zero then the file should also
|
/* If the line number is not zero then the file should also
|
||||||
|
|
@ -562,112 +358,6 @@ static int show_stmt_alloc(ivl_statement_t net)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int show_stmt_assign_vector(ivl_statement_t net)
|
|
||||||
{
|
|
||||||
ivl_expr_t rval = ivl_stmt_rval(net);
|
|
||||||
|
|
||||||
/* Handle the special case that the expression is a real
|
|
||||||
value. Evaluate the real expression, then convert the
|
|
||||||
result to a vector. Then store that vector into the
|
|
||||||
l-value. */
|
|
||||||
if (ivl_expr_value(rval) == IVL_VT_REAL) {
|
|
||||||
int word = draw_eval_real(rval);
|
|
||||||
/* This is the accumulated with of the l-value of the
|
|
||||||
assignment. */
|
|
||||||
unsigned wid = ivl_stmt_lwidth(net);
|
|
||||||
|
|
||||||
struct vector_info vec;
|
|
||||||
|
|
||||||
vec.base = allocate_vector(wid);
|
|
||||||
vec.wid = wid;
|
|
||||||
|
|
||||||
if (vec.base == 0) {
|
|
||||||
fprintf(stderr, "%s:%u: vvp.tgt error: "
|
|
||||||
"Unable to allocate %u thread bits for "
|
|
||||||
"r-value expression.\n", ivl_expr_file(rval),
|
|
||||||
ivl_expr_lineno(rval), wid);
|
|
||||||
vvp_errors += 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
fprintf(vvp_out, " %%cvt/vr %u, %d, %u;\n",
|
|
||||||
vec.base, word, vec.wid);
|
|
||||||
|
|
||||||
clr_word(word);
|
|
||||||
|
|
||||||
set_vec_to_lval(net, vec);
|
|
||||||
|
|
||||||
clr_vector(vec);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
{ struct vector_info res = draw_eval_expr(rval, 0);
|
|
||||||
set_vec_to_lval(net, res);
|
|
||||||
if (res.base > 3)
|
|
||||||
clr_vector(res);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* This function assigns a value to a real .variable. This is destined
|
|
||||||
* for /dev/null when typed ivl_signal_t takes over all the real
|
|
||||||
* variable support.
|
|
||||||
*/
|
|
||||||
static int show_stmt_assign_sig_real(ivl_statement_t net)
|
|
||||||
{
|
|
||||||
int res;
|
|
||||||
ivl_lval_t lval;
|
|
||||||
ivl_signal_t var;
|
|
||||||
|
|
||||||
res = draw_eval_real(ivl_stmt_rval(net));
|
|
||||||
|
|
||||||
assert(ivl_stmt_lvals(net) == 1);
|
|
||||||
lval = ivl_stmt_lval(net, 0);
|
|
||||||
var = ivl_lval_sig(lval);
|
|
||||||
assert(var != 0);
|
|
||||||
|
|
||||||
if (ivl_signal_dimensions(var) == 0) {
|
|
||||||
clr_word(res);
|
|
||||||
fprintf(vvp_out, " %%set/wr v%p_0, %d;\n", var, res);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
// For now, only support 1-dimensional arrays.
|
|
||||||
assert(ivl_signal_dimensions(var) == 1);
|
|
||||||
|
|
||||||
// Calculate the word index into an index register
|
|
||||||
ivl_expr_t word_ex = ivl_lval_idx(lval);
|
|
||||||
int word_ix = allocate_word();
|
|
||||||
draw_eval_expr_into_integer(word_ex, word_ix);
|
|
||||||
// Generate an assignment to write to the array.
|
|
||||||
fprintf(vvp_out, " %%set/ar v%p, %d, %d;\n", var, word_ix, res);
|
|
||||||
|
|
||||||
clr_word(res);
|
|
||||||
clr_word(word_ix);
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int show_stmt_assign(ivl_statement_t net)
|
|
||||||
{
|
|
||||||
ivl_lval_t lval;
|
|
||||||
ivl_signal_t sig;
|
|
||||||
|
|
||||||
show_stmt_file_line(net, "Blocking assignment.");
|
|
||||||
|
|
||||||
lval = ivl_stmt_lval(net, 0);
|
|
||||||
|
|
||||||
sig = ivl_lval_sig(lval);
|
|
||||||
if (sig && (ivl_signal_data_type(sig) == IVL_VT_REAL)) {
|
|
||||||
return show_stmt_assign_sig_real(net);
|
|
||||||
}
|
|
||||||
|
|
||||||
return show_stmt_assign_vector(net);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* This function handles the case of non-blocking assign to word
|
* This function handles the case of non-blocking assign to word
|
||||||
* variables such as real, i.e:
|
* variables such as real, i.e:
|
||||||
|
|
|
||||||
12
verilog.spec
12
verilog.spec
|
|
@ -1,6 +1,6 @@
|
||||||
#norootforbuild
|
#norootforbuild
|
||||||
#
|
#
|
||||||
%define rev_date 20090923
|
%define rev_date 20111127
|
||||||
# Normally, the suff-ix is %nil, meaning the suffix is to not be used.
|
# Normally, the suff-ix is %nil, meaning the suffix is to not be used.
|
||||||
# But if the builder wants to make a suffixed package, he may set this
|
# But if the builder wants to make a suffixed package, he may set this
|
||||||
# to a value (i.e. -test) to cause suffixes to be put in all the right
|
# to a value (i.e. -test) to cause suffixes to be put in all the right
|
||||||
|
|
@ -67,6 +67,7 @@ rm -rf $RPM_BUILD_ROOT
|
||||||
%attr(-,root,root) %{_bindir}/vvp%{suff}
|
%attr(-,root,root) %{_bindir}/vvp%{suff}
|
||||||
%attr(-,root,root) %{_libdir}/ivl%{suff}/ivl
|
%attr(-,root,root) %{_libdir}/ivl%{suff}/ivl
|
||||||
%attr(-,root,root) %{_libdir}/ivl%{suff}/ivlpp
|
%attr(-,root,root) %{_libdir}/ivl%{suff}/ivlpp
|
||||||
|
%attr(-,root,root) %{_libdir}/ivl%{suff}/vhdlpp
|
||||||
%attr(-,root,root) %{_libdir}/ivl%{suff}/null.tgt
|
%attr(-,root,root) %{_libdir}/ivl%{suff}/null.tgt
|
||||||
%attr(-,root,root) %{_libdir}/ivl%{suff}/null.conf
|
%attr(-,root,root) %{_libdir}/ivl%{suff}/null.conf
|
||||||
%attr(-,root,root) %{_libdir}/ivl%{suff}/null-s.conf
|
%attr(-,root,root) %{_libdir}/ivl%{suff}/null-s.conf
|
||||||
|
|
@ -79,12 +80,20 @@ rm -rf $RPM_BUILD_ROOT
|
||||||
%attr(-,root,root) %{_libdir}/ivl%{suff}/vhdl.tgt
|
%attr(-,root,root) %{_libdir}/ivl%{suff}/vhdl.tgt
|
||||||
%attr(-,root,root) %{_libdir}/ivl%{suff}/vhdl.conf
|
%attr(-,root,root) %{_libdir}/ivl%{suff}/vhdl.conf
|
||||||
%attr(-,root,root) %{_libdir}/ivl%{suff}/vhdl-s.conf
|
%attr(-,root,root) %{_libdir}/ivl%{suff}/vhdl-s.conf
|
||||||
|
%attr(-,root,root) %{_libdir}/ivl%{suff}/vlog95.tgt
|
||||||
|
%attr(-,root,root) %{_libdir}/ivl%{suff}/vlog95.conf
|
||||||
|
%attr(-,root,root) %{_libdir}/ivl%{suff}/vlog95-s.conf
|
||||||
%attr(-,root,root) %{_libdir}/ivl%{suff}/system.sft
|
%attr(-,root,root) %{_libdir}/ivl%{suff}/system.sft
|
||||||
%attr(-,root,root) %{_libdir}/ivl%{suff}/system.vpi
|
%attr(-,root,root) %{_libdir}/ivl%{suff}/system.vpi
|
||||||
%attr(-,root,root) %{_libdir}/ivl%{suff}/va_math.sft
|
%attr(-,root,root) %{_libdir}/ivl%{suff}/va_math.sft
|
||||||
%attr(-,root,root) %{_libdir}/ivl%{suff}/va_math.vpi
|
%attr(-,root,root) %{_libdir}/ivl%{suff}/va_math.vpi
|
||||||
%attr(-,root,root) %{_libdir}/ivl%{suff}/v2005_math.sft
|
%attr(-,root,root) %{_libdir}/ivl%{suff}/v2005_math.sft
|
||||||
%attr(-,root,root) %{_libdir}/ivl%{suff}/v2005_math.vpi
|
%attr(-,root,root) %{_libdir}/ivl%{suff}/v2005_math.vpi
|
||||||
|
%attr(-,root,root) %{_libdir}/ivl%{suff}/v2009.sft
|
||||||
|
%attr(-,root,root) %{_libdir}/ivl%{suff}/v2009.vpi
|
||||||
|
%attr(-,root,root) %{_libdir}/ivl%{suff}/vhdl_sys.sft
|
||||||
|
%attr(-,root,root) %{_libdir}/ivl%{suff}/vhdl_sys.vpi
|
||||||
|
%attr(-,root,root) %{_libdir}/ivl%{suff}/vpi_debug.vpi
|
||||||
%attr(-,root,root) %{_libdir}/ivl%{suff}/cadpli.vpl
|
%attr(-,root,root) %{_libdir}/ivl%{suff}/cadpli.vpl
|
||||||
%attr(-,root,root) %{_libdir}/libvpi%{suff}.a
|
%attr(-,root,root) %{_libdir}/libvpi%{suff}.a
|
||||||
%attr(-,root,root) %{_libdir}/libveriuser%{suff}.a
|
%attr(-,root,root) %{_libdir}/libveriuser%{suff}.a
|
||||||
|
|
@ -92,6 +101,7 @@ rm -rf $RPM_BUILD_ROOT
|
||||||
%attr(-,root,root) %{_libdir}/ivl%{suff}/include/disciplines.vams
|
%attr(-,root,root) %{_libdir}/ivl%{suff}/include/disciplines.vams
|
||||||
%attr(-,root,root) /usr/include/iverilog%{suff}/ivl_target.h
|
%attr(-,root,root) /usr/include/iverilog%{suff}/ivl_target.h
|
||||||
%attr(-,root,root) /usr/include/iverilog%{suff}/vpi_user.h
|
%attr(-,root,root) /usr/include/iverilog%{suff}/vpi_user.h
|
||||||
|
%attr(-,root,root) /usr/include/iverilog%{suff}/sv_vpi_user.h
|
||||||
%attr(-,root,root) /usr/include/iverilog%{suff}/acc_user.h
|
%attr(-,root,root) /usr/include/iverilog%{suff}/acc_user.h
|
||||||
%attr(-,root,root) /usr/include/iverilog%{suff}/veriuser.h
|
%attr(-,root,root) /usr/include/iverilog%{suff}/veriuser.h
|
||||||
%attr(-,root,root) /usr/include/iverilog%{suff}/_pli_types.h
|
%attr(-,root,root) /usr/include/iverilog%{suff}/_pli_types.h
|
||||||
|
|
|
||||||
|
|
@ -128,7 +128,7 @@ installdirs: $(srcdir)/../mkinstalldirs
|
||||||
$(srcdir)/../mkinstalldirs "$(DESTDIR)$(libdir)/ivl$(suffix)"
|
$(srcdir)/../mkinstalldirs "$(DESTDIR)$(libdir)/ivl$(suffix)"
|
||||||
|
|
||||||
uninstall:
|
uninstall:
|
||||||
rm -f "$(DESTDIR)$(libdir)/ivl$(suffix)/ivhdlpp@EXEEXT@"
|
rm -f "$(DESTDIR)$(libdir)/ivl$(suffix)/vhdlpp@EXEEXT@"
|
||||||
|
|
||||||
stamp-vhdlpp_config-h: $(srcdir)/vhdlpp_config.h.in ../config.status
|
stamp-vhdlpp_config-h: $(srcdir)/vhdlpp_config.h.in ../config.status
|
||||||
@rm -f $@
|
@rm -f $@
|
||||||
|
|
|
||||||
|
|
@ -81,9 +81,12 @@ const char NOTICE[] =
|
||||||
# include <getopt.h>
|
# include <getopt.h>
|
||||||
#endif
|
#endif
|
||||||
# include <sys/stat.h>
|
# include <sys/stat.h>
|
||||||
|
// MinGW only supports mkdir() with a path. If this stops working because
|
||||||
|
// we need to use _mkdir() for mingw-w32 and mkdir() for mingw-w64 look
|
||||||
|
// at using the autoconf AX_FUNC_MKDIR macro to figure this all out.
|
||||||
#if defined(__MINGW32__)
|
#if defined(__MINGW32__)
|
||||||
# include <io.h>
|
# include <io.h>
|
||||||
# define mkdir(path, mode) _mkdir(path)
|
# define mkdir(path, mode) mkdir(path)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -971,10 +971,10 @@ for_generate_statement
|
||||||
errormsg(@1, "for-generate name %s does not match closing name %s\n",
|
errormsg(@1, "for-generate name %s does not match closing name %s\n",
|
||||||
name.str(), $11);
|
name.str(), $11);
|
||||||
}
|
}
|
||||||
delete $1;
|
delete[]$1;
|
||||||
delete $4;
|
delete[]$4;
|
||||||
delete $8;
|
delete $8;
|
||||||
delete $11;
|
delete[]$11;
|
||||||
$$ = tmp;
|
$$ = tmp;
|
||||||
}
|
}
|
||||||
;
|
;
|
||||||
|
|
|
||||||
|
|
@ -32,14 +32,19 @@ libdir = @libdir@
|
||||||
mandir = @mandir@
|
mandir = @mandir@
|
||||||
includedir = @includedir@
|
includedir = @includedir@
|
||||||
|
|
||||||
CC = @CC@
|
# For a cross compile these defines will need to be set accordingly.
|
||||||
HOSTCC = @CC@
|
HOSTCC = @CC@
|
||||||
|
HOSTCFLAGS = @WARNING_FLAGS@ @CFLAGS@
|
||||||
|
|
||||||
|
CC = @CC@
|
||||||
CXX = @CXX@
|
CXX = @CXX@
|
||||||
|
DLLTOOL = @DLLTOOL@
|
||||||
|
AR = @AR@
|
||||||
|
RANLIB = @RANLIB@
|
||||||
INSTALL = @INSTALL@
|
INSTALL = @INSTALL@
|
||||||
INSTALL_SCRIPT = @INSTALL_SCRIPT@
|
INSTALL_SCRIPT = @INSTALL_SCRIPT@
|
||||||
INSTALL_PROGRAM = @INSTALL_PROGRAM@
|
INSTALL_PROGRAM = @INSTALL_PROGRAM@
|
||||||
INSTALL_DATA = @INSTALL_DATA@
|
INSTALL_DATA = @INSTALL_DATA@
|
||||||
RANLIB = @RANLIB@
|
|
||||||
LEX = @LEX@
|
LEX = @LEX@
|
||||||
YACC = @YACC@
|
YACC = @YACC@
|
||||||
MAN = @MAN@
|
MAN = @MAN@
|
||||||
|
|
@ -118,7 +123,7 @@ ifeq (@WIN32@,yes)
|
||||||
# executable to build the library.
|
# executable to build the library.
|
||||||
vvp@EXEEXT@ libvpi.a: $O $(srcdir)/vvp.def
|
vvp@EXEEXT@ libvpi.a: $O $(srcdir)/vvp.def
|
||||||
$(CXX) -o vvp$(suffix)@EXEEXT@ $(LDFLAGS) $O $(dllib) $(LIBS)
|
$(CXX) -o vvp$(suffix)@EXEEXT@ $(LDFLAGS) $O $(dllib) $(LIBS)
|
||||||
dlltool --dllname vvp$(suffix)@EXEEXT@ --def $(srcdir)/vvp.def \
|
$(DLLTOOL) --dllname vvp$(suffix)@EXEEXT@ --def $(srcdir)/vvp.def \
|
||||||
--output-lib libvpi.a --output-exp vvp.exp
|
--output-lib libvpi.a --output-exp vvp.exp
|
||||||
rm -f vvp$(suffix)@EXEEXT@
|
rm -f vvp$(suffix)@EXEEXT@
|
||||||
$(CXX) $(LDFLAGS) -o vvp@EXEEXT@ vvp.exp $(LDFLAGS) $O $(dllib) $(LIBS)
|
$(CXX) $(LDFLAGS) -o vvp@EXEEXT@ vvp.exp $(LDFLAGS) $O $(dllib) $(LIBS)
|
||||||
|
|
@ -126,7 +131,7 @@ else
|
||||||
libvpi.a: libvpi.c
|
libvpi.a: libvpi.c
|
||||||
$(CC) $(CFLAGS) -c $<
|
$(CC) $(CFLAGS) -c $<
|
||||||
rm -f libvpi.a
|
rm -f libvpi.a
|
||||||
ar cqv libvpi.a libvpi.o
|
$(AR) cqv libvpi.a libvpi.o
|
||||||
$(RANLIB) libvpi.a
|
$(RANLIB) libvpi.a
|
||||||
|
|
||||||
vvp@EXEEXT@: $O
|
vvp@EXEEXT@: $O
|
||||||
|
|
@ -142,9 +147,9 @@ endif
|
||||||
mv $*.d dep/$*.d
|
mv $*.d dep/$*.d
|
||||||
|
|
||||||
tables.cc: $(srcdir)/draw_tt.c
|
tables.cc: $(srcdir)/draw_tt.c
|
||||||
$(HOSTCC) @WARNING_FLAGS@ -o draw_tt $(srcdir)/draw_tt.c
|
$(HOSTCC) $(HOSTCFLAGS) -o draw_tt.exe $(srcdir)/draw_tt.c
|
||||||
./draw_tt > tables.cc
|
./draw_tt.exe > tables.cc
|
||||||
rm draw_tt@EXEEXT@
|
rm draw_tt.exe
|
||||||
|
|
||||||
lexor.o: lexor.cc parse.h
|
lexor.o: lexor.cc parse.h
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -131,6 +131,7 @@ extern bool of_MOD_S(vthread_t thr, vvp_code_t code);
|
||||||
extern bool of_MOD_WR(vthread_t thr, vvp_code_t code);
|
extern bool of_MOD_WR(vthread_t thr, vvp_code_t code);
|
||||||
extern bool of_MOV(vthread_t thr, vvp_code_t code);
|
extern bool of_MOV(vthread_t thr, vvp_code_t code);
|
||||||
extern bool of_MOV_WR(vthread_t thr, vvp_code_t code);
|
extern bool of_MOV_WR(vthread_t thr, vvp_code_t code);
|
||||||
|
extern bool of_MOV_WU(vthread_t thr, vvp_code_t code);
|
||||||
extern bool of_MOVI(vthread_t thr, vvp_code_t code);
|
extern bool of_MOVI(vthread_t thr, vvp_code_t code);
|
||||||
extern bool of_MUL(vthread_t thr, vvp_code_t code);
|
extern bool of_MUL(vthread_t thr, vvp_code_t code);
|
||||||
extern bool of_MUL_WR(vthread_t thr, vvp_code_t code);
|
extern bool of_MUL_WR(vthread_t thr, vvp_code_t code);
|
||||||
|
|
|
||||||
|
|
@ -173,6 +173,7 @@ static const struct opcode_table_s opcode_table[] = {
|
||||||
{ "%mod/wr", of_MOD_WR, 2, {OA_BIT1, OA_BIT2, OA_NONE} },
|
{ "%mod/wr", of_MOD_WR, 2, {OA_BIT1, OA_BIT2, OA_NONE} },
|
||||||
{ "%mov", of_MOV, 3, {OA_BIT1, OA_BIT2, OA_NUMBER} },
|
{ "%mov", of_MOV, 3, {OA_BIT1, OA_BIT2, OA_NUMBER} },
|
||||||
{ "%mov/wr", of_MOV_WR, 2, {OA_BIT1, OA_BIT2, OA_NONE} },
|
{ "%mov/wr", of_MOV_WR, 2, {OA_BIT1, OA_BIT2, OA_NONE} },
|
||||||
|
{ "%mov/wu", of_MOV_WU, 2, {OA_BIT1, OA_BIT2, OA_NONE} },
|
||||||
{ "%movi", of_MOVI, 3, {OA_BIT1, OA_BIT2, OA_NUMBER} },
|
{ "%movi", of_MOVI, 3, {OA_BIT1, OA_BIT2, OA_NUMBER} },
|
||||||
{ "%mul", of_MUL, 3, {OA_BIT1, OA_BIT2, OA_NUMBER} },
|
{ "%mul", of_MUL, 3, {OA_BIT1, OA_BIT2, OA_NUMBER} },
|
||||||
{ "%mul/wr", of_MUL_WR, 2, {OA_BIT1, OA_BIT2, OA_NONE} },
|
{ "%mul/wr", of_MUL_WR, 2, {OA_BIT1, OA_BIT2, OA_NONE} },
|
||||||
|
|
|
||||||
|
|
@ -32,7 +32,7 @@ typedef shl_t ivl_dll_t;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if defined(__MINGW32__)
|
#if defined(__MINGW32__)
|
||||||
inline ivl_dll_t ivl_dlopen(const char *name, bool global_flag)
|
inline ivl_dll_t ivl_dlopen(const char *name, bool)
|
||||||
{
|
{
|
||||||
static char full_name[4096];
|
static char full_name[4096];
|
||||||
unsigned long length = GetFullPathName(name, sizeof(full_name),
|
unsigned long length = GetFullPathName(name, sizeof(full_name),
|
||||||
|
|
|
||||||
|
|
@ -631,6 +631,7 @@ This opcode is the real-valued modulus of the two real values.
|
||||||
|
|
||||||
* %mov <dst>, <src>, <wid>
|
* %mov <dst>, <src>, <wid>
|
||||||
* %mov/wr <dst>, <src>
|
* %mov/wr <dst>, <src>
|
||||||
|
* %mov/wu <dst>, <src>
|
||||||
* %movi <dst>, <value>, <wid>
|
* %movi <dst>, <value>, <wid>
|
||||||
|
|
||||||
This instruction copies a vector from one place in register space to
|
This instruction copies a vector from one place in register space to
|
||||||
|
|
|
||||||
|
|
@ -1016,7 +1016,11 @@ vpiHandle vpi_put_value(vpiHandle obj, s_vpi_value*vp,
|
||||||
vpiHandle vpi_handle(PLI_INT32 type, vpiHandle ref)
|
vpiHandle vpi_handle(PLI_INT32 type, vpiHandle ref)
|
||||||
{
|
{
|
||||||
if (type == vpiSysTfCall) {
|
if (type == vpiSysTfCall) {
|
||||||
assert(ref == 0);
|
if (ref != 0) {
|
||||||
|
fprintf(stderr, "VPI error: vpi_handle(vpiSysTfCall, "
|
||||||
|
"ref!=0).\n");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
if (vpi_trace) {
|
if (vpi_trace) {
|
||||||
fprintf(vpi_trace, "vpi_handle(vpiSysTfCall, 0) "
|
fprintf(vpi_trace, "vpi_handle(vpiSysTfCall, 0) "
|
||||||
|
|
@ -1028,10 +1032,10 @@ vpiHandle vpi_handle(PLI_INT32 type, vpiHandle ref)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ref == 0) {
|
if (ref == 0) {
|
||||||
fprintf(stderr, "internal error: vpi_handle(type=%d, ref=0)\n",
|
fprintf(stderr, "VPI error: vpi_handle(type=%d, ref=0).\n",
|
||||||
(int)type);
|
(int)type);
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
assert(ref);
|
|
||||||
|
|
||||||
if (ref->vpi_type->handle_ == 0) {
|
if (ref->vpi_type->handle_ == 0) {
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -155,7 +155,7 @@ static int scope_get(int code, vpiHandle obj)
|
||||||
return (int) ref->is_automatic;
|
return (int) ref->is_automatic;
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return vpiUndefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void construct_scope_fullname(struct __vpiScope*ref, char*buf)
|
static void construct_scope_fullname(struct __vpiScope*ref, char*buf)
|
||||||
|
|
@ -182,8 +182,8 @@ static const char* scope_get_type(int code)
|
||||||
case vpiNamedFork:
|
case vpiNamedFork:
|
||||||
return "vpiNamedFork";
|
return "vpiNamedFork";
|
||||||
default:
|
default:
|
||||||
fprintf(stderr, "ERROR: invalid code %d.", code);
|
fprintf(stderr, "VPI error: invalid scope type code %d.\n", code);
|
||||||
assert(0);
|
return NULL;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -223,9 +223,8 @@ static char* scope_get_str(int code, vpiHandle obj)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
fprintf(stderr, "ERROR: invalid code %d.", code);
|
fprintf(stderr, "VPI error: invalid scope string code %d.\n", code);
|
||||||
assert(0);
|
return NULL;
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
return simple_set_rbuf_str(p);
|
return simple_set_rbuf_str(p);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -549,7 +549,7 @@ static int signal_get(int code, vpiHandle ref)
|
||||||
vpi_get_value(rfp->id.index, &vp);
|
vpi_get_value(rfp->id.index, &vp);
|
||||||
return vp.value.integer;
|
return vp.value.integer;
|
||||||
} else {
|
} else {
|
||||||
return 0;
|
return vpiUndefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
case vpiSize:
|
case vpiSize:
|
||||||
|
|
@ -562,7 +562,7 @@ static int signal_get(int code, vpiHandle ref)
|
||||||
if (ref->vpi_type->type_code==vpiNet)
|
if (ref->vpi_type->type_code==vpiNet)
|
||||||
return vpiWire;
|
return vpiWire;
|
||||||
else
|
else
|
||||||
return 0;
|
return vpiUndefined;
|
||||||
|
|
||||||
case vpiLeftRange:
|
case vpiLeftRange:
|
||||||
return rfp->msb;
|
return rfp->msb;
|
||||||
|
|
@ -573,6 +573,7 @@ static int signal_get(int code, vpiHandle ref)
|
||||||
case vpiAutomatic:
|
case vpiAutomatic:
|
||||||
return (int) vpip_scope(rfp)->is_automatic;
|
return (int) vpip_scope(rfp)->is_automatic;
|
||||||
|
|
||||||
|
// This private property must return zero when undefined.
|
||||||
case _vpiNexusId:
|
case _vpiNexusId:
|
||||||
if (rfp->msb == rfp->lsb)
|
if (rfp->msb == rfp->lsb)
|
||||||
return (int) (unsigned long) rfp->node;
|
return (int) (unsigned long) rfp->node;
|
||||||
|
|
@ -580,8 +581,9 @@ static int signal_get(int code, vpiHandle ref)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
fprintf(stderr, "signal_get: property %d is unknown\n", code);
|
fprintf(stderr, "VPI error: unknown signal_get property %d.\n",
|
||||||
return 0;
|
code);
|
||||||
|
return vpiUndefined;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -594,18 +596,21 @@ static char* signal_get_str(int code, vpiHandle ref)
|
||||||
return simple_set_rbuf_str(file_names[0]);
|
return simple_set_rbuf_str(file_names[0]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ((code != vpiName) && (code != vpiFullName)) return NULL;
|
||||||
|
|
||||||
char *nm, *ixs;
|
char *nm, *ixs;
|
||||||
if (rfp->is_netarray) {
|
if (rfp->is_netarray) {
|
||||||
nm = strdup(vpi_get_str(vpiName, rfp->within.parent));
|
nm = strdup(vpi_get_str(vpiName, rfp->within.parent));
|
||||||
s_vpi_value vp;
|
s_vpi_value vp;
|
||||||
vp.format = vpiDecStrVal;
|
vp.format = vpiDecStrVal;
|
||||||
vpi_get_value(rfp->id.index, &vp);
|
vpi_get_value(rfp->id.index, &vp);
|
||||||
ixs = vp.value.str; /* do I need to strdup() this? */
|
ixs = vp.value.str; /* do I need to strdup() this? */
|
||||||
} else {
|
} else {
|
||||||
nm = strdup(rfp->id.name);
|
nm = strdup(rfp->id.name);
|
||||||
ixs = NULL;
|
ixs = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* The scope information is added here for vpiFullName. */
|
||||||
char *rbuf = generic_get_str(code, &(vpip_scope(rfp)->base), nm, ixs);
|
char *rbuf = generic_get_str(code, &(vpip_scope(rfp)->base), nm, ixs);
|
||||||
free(nm);
|
free(nm);
|
||||||
return rbuf;
|
return rbuf;
|
||||||
|
|
|
||||||
|
|
@ -3590,6 +3590,15 @@ bool of_MOV_WR(vthread_t thr, vvp_code_t cp)
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool of_MOV_WU(vthread_t thr, vvp_code_t cp)
|
||||||
|
{
|
||||||
|
unsigned dst = cp->bit_idx[0];
|
||||||
|
unsigned src = cp->bit_idx[1];
|
||||||
|
|
||||||
|
thr->words[dst].w_uint = thr->words[src].w_uint;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
bool of_MOVI(vthread_t thr, vvp_code_t cp)
|
bool of_MOVI(vthread_t thr, vvp_code_t cp)
|
||||||
{
|
{
|
||||||
unsigned dst = cp->bit_idx[0];
|
unsigned dst = cp->bit_idx[0];
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue