Merge branch 'master' of github.com:steveicarus/iverilog

This commit is contained in:
Stephen Williams 2011-12-24 10:31:49 -05:00
commit cd76a504ac
41 changed files with 1028 additions and 465 deletions

View File

@ -67,9 +67,13 @@ mandir = @mandir@
dllib=@DLLIB@
CC = @CC@
# For a cross compile these defines will need to be set accordingly.
HOSTCC = @CC@
HOSTCFLAGS = @WARNING_FLAGS@ @CFLAGS@
CC = @CC@
CXX = @CXX@
DLLTOOL = @DLLTOOL@
INSTALL = @INSTALL@
INSTALL_SCRIPT = @INSTALL_SCRIPT@
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)
all: dosify.exe
dosify.exe: $(srcdir)/dosify.c
$(CC) -o dosify.exe $(srcdir)/dosify.c
$(HOSTCC) $(HOSTCFLAGS) -o dosify.exe $(srcdir)/dosify.c
endif
# 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.
ivl@EXEEXT@: $O $(srcdir)/ivl.def
$(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
$(CXX) $(LDFLAGS) -o ivl@EXEEXT@ ivl.exp $O $(dllib) @EXTRALIBS@
else
@ -227,7 +231,7 @@ iverilog-vpi: $(srcdir)/iverilog-vpi.sh Makefile
endif
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
$(CXX) $(CPPFLAGS) $(CXXFLAGS) @DEPENDENCY_FLAG@ -c $< -o $*.o
@ -368,7 +372,7 @@ uninstall:
-rmdir "$(DESTDIR)$(libdir)/ivl$(suffix)"
for f in verilog$(suffix) iverilog-vpi$(suffix) gverilog$(suffix)@EXEEXT@; \
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
-test X$(suffix) = X || rmdir "$(DESTDIR)/$(includedir)"
rm -f "$(DESTDIR)$(mandir)/man1/iverilog-vpi$(suffix).1" "$(DESTDIR)$(prefix)/iverilog-vpi$(suffix).pdf"

View File

@ -51,22 +51,27 @@ PAssign_::~PAssign_()
}
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_(lval__, d, ex)
: PAssign_(lval__, d, ex), op_(0)
{
}
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_(lval__, ex, is_constant)
: PAssign_(lval__, ex, is_constant), op_(0)
{
}

View File

@ -120,7 +120,12 @@ class PAssign_ : public Statement {
class PAssign : public PAssign_ {
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, char op, 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*ex, bool is_constant);
@ -130,6 +135,8 @@ class PAssign : public PAssign_ {
virtual NetProc* elaborate(Design*des, NetScope*scope) const;
private:
NetProc* elaborate_compressed_(Design*des, NetScope*scope) const;
char op_;
};
class PAssignNB : public PAssign_ {

View File

@ -22,7 +22,11 @@ AC_PREREQ([2.60])
AC_PROG_CC_C99
AC_PROG_CXX
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(WINDRES,windres,false)
AC_CHECK_PROGS(XGPERF,gperf,none)
AC_CHECK_PROGS(MAN,man,none)
AC_CHECK_PROGS(PS2PDF,ps2pdf,none)

View File

@ -1,3 +1,3 @@
// These are correct and are used to find the base (zero) pin.
thisSubtraction:netlist.h:4164
thisSubtraction:netlist.h:4173
thisSubtraction:netlist.h:4168
thisSubtraction:netlist.h:4177

View File

@ -824,7 +824,10 @@ void NetAssign::dump(ostream&o, unsigned ind) const
o << setw(ind) << "";
dump_lval(o);
o << " = ";
if (op_)
o << " " << op_ << "= ";
else
o << " = ";
if (const NetExpr*de = get_delay())
o << "#(" << *de << ") ";

View File

@ -37,6 +37,7 @@ mandir = @mandir@
dllib=@DLLIB@
CC = @CC@
WINDRES = @WINDRES@
INSTALL = @INSTALL@
INSTALL_PROGRAM = @INSTALL_PROGRAM@
INSTALL_DATA = @INSTALL_DATA@
@ -88,7 +89,7 @@ res.rc: $(srcdir)/res.rc.in ../version.exe
$(srcdir)/res.rc.in > $@
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@

View File

@ -2259,10 +2259,33 @@ static NetExpr*elaborate_delay_expr(PExpr*expr, Design*des, NetScope*scope)
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
{
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
expressions that might exist. */
NetAssign_*lv = elaborate_lval(des, scope);

View File

@ -272,6 +272,7 @@ ivl_stmt_lvals
ivl_stmt_lwidth
ivl_stmt_name
ivl_stmt_nevent
ivl_stmt_opcode
ivl_stmt_parm
ivl_stmt_parm_count
ivl_stmt_rval

View File

@ -1995,6 +1995,13 @@ extern unsigned ivl_stmt_lineno(ivl_statement_t net);
* the statement.) The ivl_stmt_delay_expr function returns the
* 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
* This reflects a procedural continuous assignment to an l-value. The
* 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);
/* IVL_ST_STASK */
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 */
extern ivl_expr_t ivl_stmt_parm(ivl_statement_t net, unsigned idx);
/* IVL_ST_STASK */

View File

@ -516,7 +516,7 @@ TU [munpf]
^{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);
char*word = yytext+1;

View File

@ -344,7 +344,8 @@ within, GN_KEYWORDS_1800_2005, K_within
# This is the name originally proposed for uwire and is deprecated!
wone, GN_KEYWORDS_1364_2005, K_wone
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
xor, GN_KEYWORDS_1364_1995, K_xor
zi_nd, GN_KEYWORDS_VAMS_2_3, K_zi_nd

View File

@ -31,6 +31,9 @@ libdir = @libdir@
includedir = $(prefix)/include
CC = @CC@
RANLIB = @RANLIB@
AR = @AR@
LD = @LD@
INSTALL = @INSTALL@
INSTALL_PROGRAM = @INSTALL_PROGRAM@
INSTALL_DATA = @INSTALL_DATA@
@ -44,7 +47,6 @@ endif
CPPFLAGS = $(INCLUDE_PATH) @CPPFLAGS@ @DEFS@ @PICFLAG@
CFLAGS = @WARNING_FLAGS@ @CFLAGS@
LDFLAGS = @LDFLAGS@
RANLIB = @RANLIB@
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 \
@ -90,7 +92,7 @@ libveriuser.o: $O
libveriuser.a: libveriuser.o
rm -f $@
ar cvq $@ libveriuser.o
$(AR) cvq $@ libveriuser.o
$(RANLIB) $@
%.o: %.c config.h

View File

@ -36,8 +36,8 @@ scale(int high, int low, void*obj) {
scaled = high;
scaled = (scaled << 32) | low;
scaled *= pow(10, vpi_get(vpiTimePrecision,0) -
vpi_get(vpiTimeUnit,obj ? (vpiHandle)obj : hand));
scaled /= pow(10, vpi_get(vpiTimeUnit,obj ? (vpiHandle)obj : hand) -
vpi_get(vpiTimePrecision,0));
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));
*areal = real * pow(10, vpi_get(vpiTimePrecision, 0) -
vpi_get(vpiTimeUnit, hand));
*areal = real / pow(10, vpi_get(vpiTimeUnit, hand) -
vpi_get(vpiTimePrecision, 0));
}
void tf_unscale_realdelay(void*obj, double real, double *areal)

View File

@ -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)
*
* 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 */
ivl_u64_t delay = ((dly
* pow(10, tf_gettimeprecision() - tf_gettimeunit()))
/ pow(10, tf_gettimeunit() - tf_gettimeprecision()))
+ 0.5);
ti.high = delay >> 32 & 0xffffffff;
ti.low = delay & 0xffffffff;

View File

@ -233,7 +233,12 @@ const NetExpr* NetAssignBase::get_delay() const
}
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)
{
}

View File

@ -405,10 +405,10 @@ void NetScope::evaluate_parameter_logic_(Design*des, param_ref_t cur)
}
(*cur).second.val = expr;
/* If the parameter has range information, then make
sure the type is set right. Note that if the
parameter doesn't have an explicit range, then it
will get the signedness from the expression itself. */
/* If the parameter has type or range information, then make
sure the type is set right. Note that if the parameter
doesn't have an explicit type or range, then it will get
the signedness from the expression itself. */
if (range_flag) {
/* If we have a real value convert it to an integer. */
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);
} else if ((*cur).second.signed_flag) {
(*cur).second.val->cast_signed(true);
}
// If there are no value ranges to test the value against,

View File

@ -2406,15 +2406,19 @@ class NetAssign : public NetAssignBase {
public:
explicit NetAssign(NetAssign_*lv, NetExpr*rv);
explicit NetAssign(NetAssign_*lv, char op, NetExpr*rv);
~NetAssign();
bool is_asynchronous();
inline char assign_operator(void) const { return op_; }
virtual bool emit_proc(struct target_t*) const;
virtual int match_proc(struct proc_match_t*);
virtual void dump(ostream&, unsigned ind) const;
private:
char op_;
};
class NetAssignNB : public NetAssignBase {

176
parse.y
View File

@ -2337,17 +2337,12 @@ port_declaration
K_output net_type_opt primitive_type_opt unsigned_signed_opt range_opt IDENTIFIER
{ Module::port_t*ptmp;
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,
@2.first_line);
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_net_type = t;
port_declaration_context.port_net_type = $3;
port_declaration_context.var_type = $4;
port_declaration_context.sign_flag = $5;
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
{ Module::port_t*ptmp;
perm_string name = lex_strings.make($7);
NetNet::Type t = $3;
if ($4 != IVL_VT_NO_TYPE && t == NetNet::IMPLICIT)
t = NetNet::IMPLICIT_REG;
NetNet::Type t = ($3 == NetNet::IMPLICIT) ? NetNet::IMPLICIT_REG : $3;
ptmp = pform_module_port_reference(name, @2.text,
@2.first_line);
@ -3320,6 +3312,16 @@ parameter_assign_decl
param_active_signed = false;
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
{ param_active_range = $2;
param_active_signed = true;
@ -3435,6 +3437,16 @@ localparam_assign_decl
param_active_signed = false;
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
{ param_active_range = $2;
param_active_signed = true;
@ -4560,11 +4572,11 @@ statement
tmp->set_statement($6);
$$ = tmp;
}
| lpvalue '=' expression ';'
{ PAssign*tmp = new PAssign($1,$3);
FILE_NAME(tmp, @1);
$$ = tmp;
}
| lpvalue '=' expression ';'
{ PAssign*tmp = new PAssign($1,$3);
FILE_NAME(tmp, @1);
$$ = tmp;
}
| error '=' expression ';'
{ yyerror(@2, "Syntax in assignment statement l-value.");
yyerrok;
@ -4671,83 +4683,61 @@ statement
;
compressed_statement
: lpvalue K_PLUS_EQ expression
{
PEBinary *t = new PEBinary('+', $1, $3);
PAssign *tmp = new PAssign($1, t);
FILE_NAME(tmp, @1);
$$ = tmp;
}
| lpvalue K_MINUS_EQ expression
{
PEBinary *t = new PEBinary('-', $1, $3);
PAssign *tmp = new PAssign($1, t);
FILE_NAME(tmp, @1);
$$ = tmp;
}
| lpvalue K_MUL_EQ expression
{
PEBinary *t = new PEBinary('*', $1, $3);
PAssign *tmp = new PAssign($1, t);
FILE_NAME(tmp, @1);
$$ = tmp;
}
| lpvalue K_DIV_EQ expression
{
PEBinary *t = new PEBinary('/', $1, $3);
PAssign *tmp = new PAssign($1, t);
FILE_NAME(tmp, @1);
$$ = tmp;
}
| lpvalue K_MOD_EQ expression
{
PEBinary *t = new PEBinary('%', $1, $3);
PAssign *tmp = new PAssign($1, t);
FILE_NAME(tmp, @1);
$$ = tmp;
}
| lpvalue K_AND_EQ expression
{
PEBinary *t = new PEBinary('&', $1, $3);
PAssign *tmp = new PAssign($1, t);
FILE_NAME(tmp, @1);
$$ = tmp;
}
| lpvalue K_OR_EQ expression
{
PEBinary *t = new PEBinary('|', $1, $3);
PAssign *tmp = new PAssign($1, t);
FILE_NAME(tmp, @1);
$$ = tmp;
}
| lpvalue K_XOR_EQ expression
{
PEBinary *t = new PEBinary('^', $1, $3);
PAssign *tmp = new PAssign($1, t);
FILE_NAME(tmp, @1);
$$ = 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;
}
: lpvalue K_PLUS_EQ expression
{ PAssign*tmp = new PAssign($1, '+', $3);
FILE_NAME(tmp, @1);
$$ = tmp;
}
| lpvalue K_MINUS_EQ expression
{ PAssign*tmp = new PAssign($1, '-', $3);
FILE_NAME(tmp, @1);
$$ = tmp;
}
| lpvalue K_MUL_EQ expression
{ PAssign*tmp = new PAssign($1, '*', $3);
FILE_NAME(tmp, @1);
$$ = tmp;
}
| lpvalue K_DIV_EQ expression
{ PAssign*tmp = new PAssign($1, '/', $3);
FILE_NAME(tmp, @1);
$$ = tmp;
}
| lpvalue K_MOD_EQ expression
{ PAssign*tmp = new PAssign($1, '%', $3);
FILE_NAME(tmp, @1);
$$ = tmp;
}
| lpvalue K_AND_EQ expression
{ PAssign*tmp = new PAssign($1, '&', $3);
FILE_NAME(tmp, @1);
$$ = tmp;
}
| lpvalue K_OR_EQ expression
{ PAssign*tmp = new PAssign($1, '|', $3);
FILE_NAME(tmp, @1);
$$ = tmp;
}
| lpvalue K_XOR_EQ expression
{ PAssign*tmp = new PAssign($1, '^', $3);
FILE_NAME(tmp, @1);
$$ = tmp;
}
| lpvalue K_LS_EQ expression
{ PAssign *tmp = new PAssign($1, 'l', $3);
FILE_NAME(tmp, @1);
$$ = tmp;
}
| lpvalue K_RS_EQ expression
{ PAssign*tmp = new PAssign($1, 'r', $3);
FILE_NAME(tmp, @1);
$$ = tmp;
}
| lpvalue K_RSS_EQ expression
{ PAssign *tmp = new PAssign($1, 'R', $3);
FILE_NAME(tmp, @1);
$$ = tmp;
}
;
statement_list_or_null

View File

@ -15,6 +15,8 @@
#
# 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
# (Make the tag in the local git repository.)
#

View File

@ -2547,6 +2547,17 @@ extern "C" const char* ivl_stmt_name(ivl_statement_t net)
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)
{
switch (net->type_) {

View File

@ -210,6 +210,7 @@ bool dll_target::proc_assign(const NetAssign*net)
/* Make the lval fields. */
make_assign_lvals_(net);
stmt_cur_->u_.assign_.oper = net->assign_operator();
assert(expr_ == 0);
net->rval()->expr_scan(this);
stmt_cur_->u_.assign_.rval_ = expr_;

View File

@ -729,6 +729,7 @@ struct ivl_statement_s {
IVL_ST_CASSIGN, IVL_ST_DEASSIGN */
unsigned lvals_;
struct ivl_lval_s*lval_;
char oper; // Operator if this is a compressed assignment.
ivl_expr_t rval_;
ivl_expr_t delay;
// The following are only for NB event control.

View File

@ -179,6 +179,7 @@ void show_stmt_wait(ivl_statement_t net, unsigned ind)
void show_statement(ivl_statement_t net, unsigned ind)
{
unsigned idx;
char opcode = 0;
const ivl_statement_type_t code = ivl_statement_type(net);
switch (code) {
@ -188,8 +189,11 @@ void show_statement(ivl_statement_t net, unsigned ind)
break;
case IVL_ST_ASSIGN:
fprintf(out, "%*sASSIGN <lwidth=%u>\n", ind, "",
ivl_stmt_lwidth(net));
opcode = ivl_stmt_opcode(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)
show_assign_lval(ivl_stmt_lval(net, idx), ind+4);

View File

@ -49,8 +49,8 @@ CFLAGS = @WARNING_FLAGS@ @CFLAGS@
LDFLAGS = @LDFLAGS@
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 \
vvp_scope.o
eval_bool.o eval_expr.o eval_real.o modpath.o stmt_assign.o vector.o \
vvp_process.o vvp_scope.o
all: dep vvp.tgt vvp.conf vvp-s.conf

750
tgt-vvp/stmt_assign.c Normal file
View File

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

View File

@ -39,6 +39,8 @@ extern FILE* vvp_out;
*/
extern int vvp_errors;
extern unsigned transient_id;
/*
* Set to non-zero when the user wants to display file and line number
* 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 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.
*/

View File

@ -31,7 +31,7 @@ static int show_statement(ivl_statement_t net, ivl_scope_t sscope);
unsigned local_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
@ -39,173 +39,6 @@ static unsigned transient_id = 0;
* 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. */
static void assign_to_array_r_word(ivl_signal_t lsig, ivl_expr_t word_ix,
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
* 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 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;
}
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
* variables such as real, i.e:

View File

@ -1,6 +1,6 @@
#norootforbuild
#
%define rev_date 20090923
%define rev_date 20111127
# 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
# 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) %{_libdir}/ivl%{suff}/ivl
%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.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.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.vpi
%attr(-,root,root) %{_libdir}/ivl%{suff}/va_math.sft
%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.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}/libvpi%{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) /usr/include/iverilog%{suff}/ivl_target.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}/veriuser.h
%attr(-,root,root) /usr/include/iverilog%{suff}/_pli_types.h

View File

@ -128,7 +128,7 @@ installdirs: $(srcdir)/../mkinstalldirs
$(srcdir)/../mkinstalldirs "$(DESTDIR)$(libdir)/ivl$(suffix)"
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
@rm -f $@

View File

@ -81,9 +81,12 @@ const char NOTICE[] =
# include <getopt.h>
#endif
# 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__)
# include <io.h>
# define mkdir(path, mode) _mkdir(path)
# define mkdir(path, mode) mkdir(path)
#endif

View File

@ -971,10 +971,10 @@ for_generate_statement
errormsg(@1, "for-generate name %s does not match closing name %s\n",
name.str(), $11);
}
delete $1;
delete $4;
delete[]$1;
delete[]$4;
delete $8;
delete $11;
delete[]$11;
$$ = tmp;
}
;

View File

@ -32,14 +32,19 @@ libdir = @libdir@
mandir = @mandir@
includedir = @includedir@
CC = @CC@
# For a cross compile these defines will need to be set accordingly.
HOSTCC = @CC@
HOSTCFLAGS = @WARNING_FLAGS@ @CFLAGS@
CC = @CC@
CXX = @CXX@
DLLTOOL = @DLLTOOL@
AR = @AR@
RANLIB = @RANLIB@
INSTALL = @INSTALL@
INSTALL_SCRIPT = @INSTALL_SCRIPT@
INSTALL_PROGRAM = @INSTALL_PROGRAM@
INSTALL_DATA = @INSTALL_DATA@
RANLIB = @RANLIB@
LEX = @LEX@
YACC = @YACC@
MAN = @MAN@
@ -118,7 +123,7 @@ ifeq (@WIN32@,yes)
# executable to build the library.
vvp@EXEEXT@ libvpi.a: $O $(srcdir)/vvp.def
$(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
rm -f vvp$(suffix)@EXEEXT@
$(CXX) $(LDFLAGS) -o vvp@EXEEXT@ vvp.exp $(LDFLAGS) $O $(dllib) $(LIBS)
@ -126,7 +131,7 @@ else
libvpi.a: libvpi.c
$(CC) $(CFLAGS) -c $<
rm -f libvpi.a
ar cqv libvpi.a libvpi.o
$(AR) cqv libvpi.a libvpi.o
$(RANLIB) libvpi.a
vvp@EXEEXT@: $O
@ -142,9 +147,9 @@ endif
mv $*.d dep/$*.d
tables.cc: $(srcdir)/draw_tt.c
$(HOSTCC) @WARNING_FLAGS@ -o draw_tt $(srcdir)/draw_tt.c
./draw_tt > tables.cc
rm draw_tt@EXEEXT@
$(HOSTCC) $(HOSTCFLAGS) -o draw_tt.exe $(srcdir)/draw_tt.c
./draw_tt.exe > tables.cc
rm draw_tt.exe
lexor.o: lexor.cc parse.h

View File

@ -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_MOV(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_MUL(vthread_t thr, vvp_code_t code);
extern bool of_MUL_WR(vthread_t thr, vvp_code_t code);

View File

@ -173,6 +173,7 @@ static const struct opcode_table_s opcode_table[] = {
{ "%mod/wr", of_MOD_WR, 2, {OA_BIT1, OA_BIT2, OA_NONE} },
{ "%mov", of_MOV, 3, {OA_BIT1, OA_BIT2, OA_NUMBER} },
{ "%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} },
{ "%mul", of_MUL, 3, {OA_BIT1, OA_BIT2, OA_NUMBER} },
{ "%mul/wr", of_MUL_WR, 2, {OA_BIT1, OA_BIT2, OA_NONE} },

View File

@ -32,7 +32,7 @@ typedef shl_t ivl_dll_t;
#endif
#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];
unsigned long length = GetFullPathName(name, sizeof(full_name),

View File

@ -631,6 +631,7 @@ This opcode is the real-valued modulus of the two real values.
* %mov <dst>, <src>, <wid>
* %mov/wr <dst>, <src>
* %mov/wu <dst>, <src>
* %movi <dst>, <value>, <wid>
This instruction copies a vector from one place in register space to

View File

@ -1016,7 +1016,11 @@ vpiHandle vpi_put_value(vpiHandle obj, s_vpi_value*vp,
vpiHandle vpi_handle(PLI_INT32 type, vpiHandle ref)
{
if (type == vpiSysTfCall) {
assert(ref == 0);
if (ref != 0) {
fprintf(stderr, "VPI error: vpi_handle(vpiSysTfCall, "
"ref!=0).\n");
return 0;
}
if (vpi_trace) {
fprintf(vpi_trace, "vpi_handle(vpiSysTfCall, 0) "
@ -1028,10 +1032,10 @@ vpiHandle vpi_handle(PLI_INT32 type, vpiHandle ref)
}
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);
return 0;
}
assert(ref);
if (ref->vpi_type->handle_ == 0) {

View File

@ -155,7 +155,7 @@ static int scope_get(int code, vpiHandle obj)
return (int) ref->is_automatic;
}
return 0;
return vpiUndefined;
}
static void construct_scope_fullname(struct __vpiScope*ref, char*buf)
@ -182,8 +182,8 @@ static const char* scope_get_type(int code)
case vpiNamedFork:
return "vpiNamedFork";
default:
fprintf(stderr, "ERROR: invalid code %d.", code);
assert(0);
fprintf(stderr, "VPI error: invalid scope type code %d.\n", code);
return NULL;
}
}
@ -223,9 +223,8 @@ static char* scope_get_str(int code, vpiHandle obj)
break;
default:
fprintf(stderr, "ERROR: invalid code %d.", code);
assert(0);
return 0;
fprintf(stderr, "VPI error: invalid scope string code %d.\n", code);
return NULL;
}
return simple_set_rbuf_str(p);
}

View File

@ -549,7 +549,7 @@ static int signal_get(int code, vpiHandle ref)
vpi_get_value(rfp->id.index, &vp);
return vp.value.integer;
} else {
return 0;
return vpiUndefined;
}
case vpiSize:
@ -562,7 +562,7 @@ static int signal_get(int code, vpiHandle ref)
if (ref->vpi_type->type_code==vpiNet)
return vpiWire;
else
return 0;
return vpiUndefined;
case vpiLeftRange:
return rfp->msb;
@ -573,6 +573,7 @@ static int signal_get(int code, vpiHandle ref)
case vpiAutomatic:
return (int) vpip_scope(rfp)->is_automatic;
// This private property must return zero when undefined.
case _vpiNexusId:
if (rfp->msb == rfp->lsb)
return (int) (unsigned long) rfp->node;
@ -580,8 +581,9 @@ static int signal_get(int code, vpiHandle ref)
return 0;
default:
fprintf(stderr, "signal_get: property %d is unknown\n", code);
return 0;
fprintf(stderr, "VPI error: unknown signal_get property %d.\n",
code);
return vpiUndefined;
}
}
@ -594,18 +596,21 @@ static char* signal_get_str(int code, vpiHandle ref)
return simple_set_rbuf_str(file_names[0]);
}
if ((code != vpiName) && (code != vpiFullName)) return NULL;
char *nm, *ixs;
if (rfp->is_netarray) {
nm = strdup(vpi_get_str(vpiName, rfp->within.parent));
s_vpi_value vp;
vp.format = vpiDecStrVal;
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 {
nm = strdup(rfp->id.name);
ixs = NULL;
}
/* The scope information is added here for vpiFullName. */
char *rbuf = generic_get_str(code, &(vpip_scope(rfp)->base), nm, ixs);
free(nm);
return rbuf;

View File

@ -3590,6 +3590,15 @@ bool of_MOV_WR(vthread_t thr, vvp_code_t cp)
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)
{
unsigned dst = cp->bit_idx[0];