diff --git a/Makefile.in b/Makefile.in index a58de7a63..cac099f67 100644 --- a/Makefile.in +++ b/Makefile.in @@ -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" diff --git a/Statement.cc b/Statement.cc index 415dffc12..e726099bb 100644 --- a/Statement.cc +++ b/Statement.cc @@ -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) { } diff --git a/Statement.h b/Statement.h index 3f3c14010..cef5833c1 100644 --- a/Statement.h +++ b/Statement.h @@ -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_ { diff --git a/configure.in b/configure.in index 56e2fc408..28349c475 100644 --- a/configure.in +++ b/configure.in @@ -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) diff --git a/cppcheck.sup b/cppcheck.sup index 0814c13dc..31acd1554 100644 --- a/cppcheck.sup +++ b/cppcheck.sup @@ -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 diff --git a/design_dump.cc b/design_dump.cc index 471ca32f3..3ebeaae5f 100644 --- a/design_dump.cc +++ b/design_dump.cc @@ -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 << ") "; diff --git a/driver-vpi/Makefile.in b/driver-vpi/Makefile.in index 37a00b0fe..8abb6a4ce 100644 --- a/driver-vpi/Makefile.in +++ b/driver-vpi/Makefile.in @@ -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@ diff --git a/elaborate.cc b/elaborate.cc index 3fb9c60a8..ed85ab6b2 100644 --- a/elaborate.cc +++ b/elaborate.cc @@ -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); diff --git a/ivl.def b/ivl.def index ebc1844fe..4e57899c5 100644 --- a/ivl.def +++ b/ivl.def @@ -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 diff --git a/ivl_target.h b/ivl_target.h index 1c5db1177..3a1c39b70 100644 --- a/ivl_target.h +++ b/ivl_target.h @@ -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 += + * 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 */ diff --git a/lexor.lex b/lexor.lex index b392ffbed..a197990fb 100644 --- a/lexor.lex +++ b/lexor.lex @@ -516,7 +516,7 @@ TU [munpf] ^{W}?`begin_keywords{W}? { BEGIN(PPBEGIN_KEYWORDS); } -\"[a-zA-Z0-9 -]*\".* { +\"[a-zA-Z0-9 -\.]*\".* { keyword_mask_stack.push_front(lexor_keyword_mask); char*word = yytext+1; diff --git a/lexor_keyword.gperf b/lexor_keyword.gperf index 57dc4d989..208b0ae0c 100644 --- a/lexor_keyword.gperf +++ b/lexor_keyword.gperf @@ -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 diff --git a/libveriuser/Makefile.in b/libveriuser/Makefile.in index 4331ce4b5..52154fbbf 100644 --- a/libveriuser/Makefile.in +++ b/libveriuser/Makefile.in @@ -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 diff --git a/libveriuser/getsimtime.c b/libveriuser/getsimtime.c index e016af08e..716480f4d 100644 --- a/libveriuser/getsimtime.c +++ b/libveriuser/getsimtime.c @@ -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) diff --git a/libveriuser/veriusertfs.c b/libveriuser/veriusertfs.c index 740b80fd2..dc8d350df 100644 --- a/libveriuser/veriusertfs.c +++ b/libveriuser/veriusertfs.c @@ -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; diff --git a/net_assign.cc b/net_assign.cc index f12bf64b2..286f4cd30 100644 --- a/net_assign.cc +++ b/net_assign.cc @@ -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) { } diff --git a/net_design.cc b/net_design.cc index 4b4ba5692..84f4a7a34 100644 --- a/net_design.cc +++ b/net_design.cc @@ -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(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, diff --git a/netlist.h b/netlist.h index cc000ecd4..8304bb777 100644 --- a/netlist.h +++ b/netlist.h @@ -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 { diff --git a/parse.y b/parse.y index 41a14a7de..3f4c78dbf 100644 --- a/parse.y +++ b/parse.y @@ -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 diff --git a/scripts/MAKE_SNAPSHOT.sh b/scripts/MAKE_SNAPSHOT.sh index d54fdc954..6b458788f 100644 --- a/scripts/MAKE_SNAPSHOT.sh +++ b/scripts/MAKE_SNAPSHOT.sh @@ -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.) # diff --git a/t-dll-api.cc b/t-dll-api.cc index d6d1f08a0..b45da977e 100644 --- a/t-dll-api.cc +++ b/t-dll-api.cc @@ -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_) { diff --git a/t-dll-proc.cc b/t-dll-proc.cc index 783ce6618..fbc55464e 100644 --- a/t-dll-proc.cc +++ b/t-dll-proc.cc @@ -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_; diff --git a/t-dll.h b/t-dll.h index 72ba60b22..62f2df303 100644 --- a/t-dll.h +++ b/t-dll.h @@ -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. diff --git a/tgt-stub/statement.c b/tgt-stub/statement.c index 652ea6a3f..401b049e7 100644 --- a/tgt-stub/statement.c +++ b/tgt-stub/statement.c @@ -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 \n", ind, "", - ivl_stmt_lwidth(net)); + opcode = ivl_stmt_opcode(net); + if (opcode == 0) + opcode = ' '; + fprintf(out, "%*sASSIGN 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); diff --git a/tgt-vvp/Makefile.in b/tgt-vvp/Makefile.in index 69697d32f..4438c8c62 100644 --- a/tgt-vvp/Makefile.in +++ b/tgt-vvp/Makefile.in @@ -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 diff --git a/tgt-vvp/stmt_assign.c b/tgt-vvp/stmt_assign.c new file mode 100644 index 000000000..13f2e2391 --- /dev/null +++ b/tgt-vvp/stmt_assign.c @@ -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 +# include +# include + +#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); +} diff --git a/tgt-vvp/vvp_priv.h b/tgt-vvp/vvp_priv.h index b46c6492a..64fb94571 100644 --- a/tgt-vvp/vvp_priv.h +++ b/tgt-vvp/vvp_priv.h @@ -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. */ diff --git a/tgt-vvp/vvp_process.c b/tgt-vvp/vvp_process.c index a975ca729..7a0e9c1e7 100644 --- a/tgt-vvp/vvp_process.c +++ b/tgt-vvp/vvp_process.c @@ -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: diff --git a/verilog.spec b/verilog.spec index f8b1f4785..a3cb4be06 100644 --- a/verilog.spec +++ b/verilog.spec @@ -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 diff --git a/vhdlpp/Makefile.in b/vhdlpp/Makefile.in index 5150f9cf2..92b159fb6 100644 --- a/vhdlpp/Makefile.in +++ b/vhdlpp/Makefile.in @@ -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 $@ diff --git a/vhdlpp/main.cc b/vhdlpp/main.cc index 7901b699e..e7cf565ae 100644 --- a/vhdlpp/main.cc +++ b/vhdlpp/main.cc @@ -81,9 +81,12 @@ const char NOTICE[] = # include #endif # include +// 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 -# define mkdir(path, mode) _mkdir(path) +# define mkdir(path, mode) mkdir(path) #endif diff --git a/vhdlpp/parse.y b/vhdlpp/parse.y index 9fcada854..8b519537e 100644 --- a/vhdlpp/parse.y +++ b/vhdlpp/parse.y @@ -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; } ; diff --git a/vvp/Makefile.in b/vvp/Makefile.in index 7b00f9e5f..6a7d278e2 100644 --- a/vvp/Makefile.in +++ b/vvp/Makefile.in @@ -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 diff --git a/vvp/codes.h b/vvp/codes.h index 5da260791..1ca329810 100644 --- a/vvp/codes.h +++ b/vvp/codes.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_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); diff --git a/vvp/compile.cc b/vvp/compile.cc index 61d3e81fe..23d266b98 100644 --- a/vvp/compile.cc +++ b/vvp/compile.cc @@ -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} }, diff --git a/vvp/ivl_dlfcn.h b/vvp/ivl_dlfcn.h index e9c5ac2ea..72cbc0a1c 100644 --- a/vvp/ivl_dlfcn.h +++ b/vvp/ivl_dlfcn.h @@ -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), diff --git a/vvp/opcodes.txt b/vvp/opcodes.txt index c51f3092a..b8ce9332e 100644 --- a/vvp/opcodes.txt +++ b/vvp/opcodes.txt @@ -631,6 +631,7 @@ This opcode is the real-valued modulus of the two real values. * %mov , , * %mov/wr , +* %mov/wu , * %movi , , This instruction copies a vector from one place in register space to diff --git a/vvp/vpi_priv.cc b/vvp/vpi_priv.cc index 7a626f192..f1c2ab814 100644 --- a/vvp/vpi_priv.cc +++ b/vvp/vpi_priv.cc @@ -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) { diff --git a/vvp/vpi_scope.cc b/vvp/vpi_scope.cc index 5d9d95b9e..33bb34ace 100644 --- a/vvp/vpi_scope.cc +++ b/vvp/vpi_scope.cc @@ -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); } diff --git a/vvp/vpi_signal.cc b/vvp/vpi_signal.cc index 08df4e1ce..65011380b 100644 --- a/vvp/vpi_signal.cc +++ b/vvp/vpi_signal.cc @@ -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; diff --git a/vvp/vthread.cc b/vvp/vthread.cc index 78980de0e..a949d00e9 100644 --- a/vvp/vthread.cc +++ b/vvp/vthread.cc @@ -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];