diff --git a/Changes b/Changes index 29ccc0e01..e7a40b7a0 100644 --- a/Changes +++ b/Changes @@ -15,14 +15,20 @@ The contributors that suggested a given feature are shown in []. Thanks! * Verilator 3.921 devel +** Support IEEE 1800-2017 as default language. + *** Support trig functions ($sin() etc), bug1281. [Patrick Stewart] *** Support calling system functions as tasks, bug1285. [Joel Holdsworth] *** Support assert properties, bug785, bug1290. [John Coiner, et al] +*** Support $writememh. [John Coiner] + *** Add --no-debug-leak to reduce memory use under debug. [John Coiner] +**** Fix severe runtime performance bug in certain foreach loops. [John Coiner] + **** On convergence errors, show activity. [John Coiner] **** Fix GCC 8.0 issues, bug1273. diff --git a/bin/verilator b/bin/verilator index eed2f9a31..7cbe723f9 100755 --- a/bin/verilator +++ b/bin/verilator @@ -259,6 +259,7 @@ descriptions in the next sections for more information. +1800-2005ext+ Use SystemVerilog 2005 with file extension +1800-2009ext+ Use SystemVerilog 2009 with file extension +1800-2012ext+ Use SystemVerilog 2012 with file extension + +1800-2017ext+ Use SystemVerilog 2017 with file extension --assert Enable all assertions --autoflush Flush streams after all $displays --bbox-sys Blackbox unknown $system calls @@ -345,7 +346,7 @@ descriptions in the next sections for more information. --stats Create statistics file --stats-vars Provide statistics on variables -sv Enable SystemVerilog parsing - +systemverilogext+ Synonym for +1800-2012ext+ + +systemverilogext+ Synonym for +1800-2017ext+ --top-module Name of top level input module --trace Enable waveform creation --trace-depth Depth of tracing @@ -412,6 +413,8 @@ with the --exe option. =item +1800-2012ext+I +=item +1800-2017ext+I + Specifies the language standard to be used with a specific filename extension, I. @@ -661,7 +664,7 @@ produce more detailed messages. Select the language to be used by default when first processing each Verilog file. The language value must be "1364-1995", "1364-2001", -"1364-2005", "1800-2005", "1800-2009" or "1800-2012". +"1364-2005", "1800-2005", "1800-2009", "1800-2012" or "1800-2017". Any language associated with a particular file extension (see the various +Iext+ options) will be used in preference to the language specified @@ -674,7 +677,7 @@ legacy mixed language designs, the various +Iext+ options should be used. If no language is specified, either by this flag or +Iext+ options, -then the latest SystemVerilog language (IEEE 1800-2012) is used. +then the latest SystemVerilog language (IEEE 1800-2017) is used. =item +define+I=I @@ -1152,7 +1155,7 @@ compatibility with other simulators. =item +systemverilogext+I -A synonym for C<+1800-2012ext+>I. +A synonym for C<+1800-2017ext+>I. =item --top-module I @@ -2216,6 +2219,11 @@ Verilator currently has some support for SystemVerilog synthesis constructs. As SystemVerilog features enter common usage they are added; please file a bug if a feature you need is missing. +=head2 SystemVerilog 2017 (IEEE 1800-2017) Support + +Verilator supports the 2017 "for" loop constructs, and several minor +cleanups made in 1800-2017. + =head2 Verilog AMS Support Verilator implements a very small subset of Verilog AMS (Verilog Analog and diff --git a/bin/verilator_difftree b/bin/verilator_difftree index add442199..e687f6292 100755 --- a/bin/verilator_difftree +++ b/bin/verilator_difftree @@ -85,7 +85,8 @@ sub diff_dir { diff_file($a,$b); $any = 1; } - $any or warn "%Warning: No .tree files found\n"; + $any or warn ("%Warning: No .tree files found that have similar base names:\n " + .join("\n ", sort keys %files),"\n"); } sub diff_file { diff --git a/include/verilated.cpp b/include/verilated.cpp index fda1c1a3a..172197598 100644 --- a/include/verilated.cpp +++ b/include/verilated.cpp @@ -1205,10 +1205,134 @@ IData VL_SSCANF_INX(int, const std::string& ld, const char* formatp, ...) VL_MT_ return got; } +void VL_WRITEMEM_Q(bool hex, int width, int depth, int array_lsb, int, + QData ofilename, const void* memp, IData start, + IData end) VL_MT_SAFE { + WData fnw[2]; VL_SET_WQ(fnw, ofilename); + return VL_WRITEMEM_W(hex, width,depth,array_lsb,2,fnw,memp,start,end); +} + +void VL_WRITEMEM_W(bool hex, int width, int depth, int array_lsb, int fnwords, + WDataInP ofilenamep, const void* memp, IData start, + IData end) VL_MT_SAFE { + char ofilenamez[VL_TO_STRING_MAX_WORDS*VL_WORDSIZE+1]; + _VL_VINT_TO_STRING(fnwords*VL_WORDSIZE, ofilenamez, ofilenamep); + std::string ofilenames(ofilenamez); + return VL_WRITEMEM_N(hex, width,depth,array_lsb,ofilenames,memp,start,end); +} + +const char* memhFormat(int nBits) { + assert((nBits >= 1) && (nBits <= 32)); + + static char buf[32]; + switch ((nBits - 1) / 4) { + case 0: VL_SNPRINTF(buf, 32, "%%01x"); break; + case 1: VL_SNPRINTF(buf, 32, "%%02x"); break; + case 2: VL_SNPRINTF(buf, 32, "%%03x"); break; + case 3: VL_SNPRINTF(buf, 32, "%%04x"); break; + case 4: VL_SNPRINTF(buf, 32, "%%05x"); break; + case 5: VL_SNPRINTF(buf, 32, "%%06x"); break; + case 6: VL_SNPRINTF(buf, 32, "%%07x"); break; + case 7: VL_SNPRINTF(buf, 32, "%%08x"); break; + default: assert(false); break; + } + return buf; +} + +void VL_WRITEMEM_N( + bool hex, // Hex format, else binary + int width, // Width of each array row + int depth, // Number of rows + int array_lsb, // Index of first row. Valid row addresses + // // range from array_lsb up to (array_lsb + depth - 1) + const std::string& ofilenamep, // Output file name + const void* memp, // Array state + IData start, // First array row address to write + IData end // Last address to write + ) VL_MT_SAFE { + if (VL_UNLIKELY(!hex)) { + VL_FATAL_MT(ofilenamep.c_str(), 0, "", + "VL_WRITEMEM_N only supports hex format for now, sorry!"); + return; + } + FILE* fp = fopen(ofilenamep.c_str(), "w"); + if (VL_UNLIKELY(!fp)) { + VL_FATAL_MT(ofilenamep.c_str(), 0, "", "$writemem file not found"); + return; + } + + for (int row_addr = start; row_addr <= end; ++row_addr) { + if ((row_addr < array_lsb) + || (row_addr > array_lsb + depth - 1)) { + vluint32_t endmax = ~0; + if (end != endmax) { + VL_FATAL_MT(ofilenamep.c_str(), 0, "", + "$writemem specified address out-of-bounds"); + } + // else, it's not an error to overflow due to end == endmax, + // just return cleanly. + goto cleanup; + } + + // Compute the offset into the memp array. + int row_offset = row_addr - array_lsb; + + if (width <= 8) { + const CData* datap + = &(reinterpret_cast(memp))[row_offset]; + fprintf(fp, memhFormat(width), VL_MASK_I(width) & *datap); + fprintf(fp, "\n"); + } else if (width <= 16) { + const SData* datap + = &(reinterpret_cast(memp))[row_offset]; + fprintf(fp, memhFormat(width), VL_MASK_I(width) & *datap); + fprintf(fp, "\n"); + } else if (width <= 32) { + const IData* datap + = &(reinterpret_cast(memp))[row_offset]; + fprintf(fp, memhFormat(width), VL_MASK_I(width) & *datap); + fprintf(fp, "\n"); + } else if (width <= 64) { + const QData* datap + = &(reinterpret_cast(memp))[row_offset]; + vluint64_t value = VL_MASK_Q(width) & *datap; + vluint32_t lo = value & 0xffffffff; + vluint32_t hi = value >> 32; + fprintf(fp, memhFormat(width - 32), hi); + fprintf(fp, "%08x\n", lo); + } else { + WDataInP memDatap = reinterpret_cast(memp); + WDataInP datap = &memDatap[row_offset * VL_WORDS_I(width)]; + // output as a sequence of VL_WORDSIZE'd words + // from MSB to LSB. Mask off the MSB word which could + // contain junk above the top of valid data. + int word_idx = ((width - 1) / VL_WORDSIZE); + bool first = true; + while (word_idx >= 0) { + IData data = datap[word_idx]; + if (first) { + data &= VL_MASK_I(width); + int top_word_nbits = ((width - 1) & 0x1f) + 1; + fprintf(fp, memhFormat(top_word_nbits), data); + } else { + fprintf(fp, "%08x", data); + } + + word_idx--; + first = false; + } + fprintf(fp, "\n"); + } + } + + cleanup: + fclose(fp); +} + void VL_READMEM_Q(bool hex, int width, int depth, int array_lsb, int, QData ofilename, void* memp, IData start, IData end) VL_MT_SAFE { WData fnw[2]; VL_SET_WQ(fnw, ofilename); - return VL_READMEM_W(hex,width,depth,array_lsb,2, fnw,memp,start,end); + return VL_READMEM_W(hex,width,depth,array_lsb,2,fnw,memp,start,end); } void VL_READMEM_W(bool hex, int width, int depth, int array_lsb, int fnwords, @@ -1216,12 +1340,20 @@ void VL_READMEM_W(bool hex, int width, int depth, int array_lsb, int fnwords, char ofilenamez[VL_TO_STRING_MAX_WORDS*VL_WORDSIZE+1]; _VL_VINT_TO_STRING(fnwords*VL_WORDSIZE, ofilenamez, ofilenamep); std::string ofilenames(ofilenamez); - return VL_READMEM_N(hex,width,depth,array_lsb,fnwords,ofilenames,memp,start,end); + return VL_READMEM_N(hex,width,depth,array_lsb,ofilenames,memp,start,end); } -void VL_READMEM_N(bool hex, int width, int depth, int array_lsb, int fnwords, - const std::string& ofilenamep, void* memp, IData start, IData end) VL_MT_SAFE { - if (fnwords) {} +void VL_READMEM_N( + bool hex, // Hex format, else binary + int width, // Width of each array row + int depth, // Number of rows + int array_lsb, // Index of first row. Valid row addresses + // // range from array_lsb up to (array_lsb + depth - 1) + const std::string& ofilenamep, // Input file name + void* memp, // Array state + IData start, // First array row address to read + IData end // Last row address to read + ) VL_MT_SAFE { FILE* fp = fopen(ofilenamep.c_str(), "r"); if (VL_UNLIKELY(!fp)) { // We don't report the Verilog source filename as it slow to have to pass it down diff --git a/include/verilated.h b/include/verilated.h index 7fb5220b5..ef3a7fd13 100644 --- a/include/verilated.h +++ b/include/verilated.h @@ -549,6 +549,14 @@ inline void VL_READMEM_I(bool hex, int width, int depth, int array_lsb, int fnwo IData ofilename, void* memp, IData start, IData end) VL_MT_SAFE { VL_READMEM_Q(hex, width,depth,array_lsb,fnwords, ofilename,memp,start,end); } +extern void VL_WRITEMEM_W(bool hex, int width, int depth, int array_lsb, int fnwords, + WDataInP ofilename, const void* memp, IData start, IData end); +extern void VL_WRITEMEM_Q(bool hex, int width, int depth, int array_lsb, int fnwords, + QData ofilename, const void* memp, IData start, IData end); +inline void VL_WRITEMEM_I(bool hex, int width, int depth, int array_lsb, int fnwords, + IData ofilename, const void* memp, IData start, IData end) VL_MT_SAFE { + VL_WRITEMEM_Q(hex, width,depth,array_lsb,fnwords, ofilename,memp,start,end); } + extern void VL_WRITEF(const char* formatp, ...); extern void VL_FWRITEF(IData fpi, const char* formatp, ...); diff --git a/include/verilated_heavy.h b/include/verilated_heavy.h index aed7683c7..77515849f 100644 --- a/include/verilated_heavy.h +++ b/include/verilated_heavy.h @@ -64,8 +64,12 @@ inline std::string VL_REPLICATEN_NNI(int obits,int lbits,int rbits, inline IData VL_LEN_IN(const std::string& ld) { return ld.length(); } extern IData VL_FOPEN_NI(const std::string& filename, IData mode) VL_MT_SAFE; -extern void VL_READMEM_N(bool hex, int width, int depth, int array_lsb, int fnwords, - const std::string& ofilename, void* memp, IData start, IData end) VL_MT_SAFE; +extern void VL_READMEM_N(bool hex, int width, int depth, int array_lsb, + const std::string& ofilename, + void* memp, IData start, IData end) VL_MT_SAFE; +extern void VL_WRITEMEM_N(bool hex, int width, int depth, int array_lsb, + const std::string& ofilename, + const void* memp, IData start, IData end) VL_MT_SAFE; extern IData VL_SSCANF_INX(int lbits, const std::string& ld, const char* formatp, ...) VL_MT_SAFE; extern void VL_SFORMAT_X(int obits_ignored, std::string& output, const char* formatp, ...) VL_MT_SAFE; extern std::string VL_SFORMATF_NX(const char* formatp, ...) VL_MT_SAFE; diff --git a/include/vltstd/svdpi.h b/include/vltstd/svdpi.h index 69597926d..f77630af7 100644 --- a/include/vltstd/svdpi.h +++ b/include/vltstd/svdpi.h @@ -7,7 +7,7 @@ * This file contains the constant definitions, structure definitions, * and routine declarations used by SystemVerilog DPI. * - * This file is from the SystemVerilog IEEE 1800-2012 Annex I. + * This file is from the SystemVerilog IEEE 1800-2017 Annex I. */ #ifndef INCLUDED_SVDPI @@ -117,7 +117,7 @@ typedef uint32_t svBitVecVal; /* * Return implementation version information string ("1800-2005" or "SV3.1a"). */ -XXTERN const char* svDpiVersion(); +XXTERN const char* svDpiVersion( void ); /* a handle to a scope (an instance of a module or interface) */ XXTERN typedef void* svScope; @@ -241,28 +241,28 @@ XXTERN void svGetLogicArrElem2VecVal(svLogicVecVal* d, const svOpenArrayHandle s XXTERN void svGetLogicArrElem3VecVal(svLogicVecVal* d, const svOpenArrayHandle s, int indx1, int indx2, int indx3); -XXTERN svBit svGetBitArrElem(const svOpenArrayHandle s, int indx1, ...); -XXTERN svBit svGetBitArrElem1(const svOpenArrayHandle s, int indx1); -XXTERN svBit svGetBitArrElem2(const svOpenArrayHandle s, int indx1, int indx2); -XXTERN svBit svGetBitArrElem3(const svOpenArrayHandle s, int indx1, int indx2, +XXTERN svBit svGetBitArrElem(const svOpenArrayHandle s, int indx1, ...); +XXTERN svBit svGetBitArrElem1(const svOpenArrayHandle s, int indx1); +XXTERN svBit svGetBitArrElem2(const svOpenArrayHandle s, int indx1, int indx2); +XXTERN svBit svGetBitArrElem3(const svOpenArrayHandle s, int indx1, int indx2, int indx3); -XXTERN svLogic svGetLogicArrElem(const svOpenArrayHandle s, int indx1, ...); -XXTERN svLogic svGetLogicArrElem1(const svOpenArrayHandle s, int indx1); -XXTERN svLogic svGetLogicArrElem2(const svOpenArrayHandle s, int indx1, int indx2); -XXTERN svLogic svGetLogicArrElem3(const svOpenArrayHandle s, int indx1, int indx2, +XXTERN svLogic svGetLogicArrElem(const svOpenArrayHandle s, int indx1, ...); +XXTERN svLogic svGetLogicArrElem1(const svOpenArrayHandle s, int indx1); +XXTERN svLogic svGetLogicArrElem2(const svOpenArrayHandle s, int indx1, int indx2); +XXTERN svLogic svGetLogicArrElem3(const svOpenArrayHandle s, int indx1, int indx2, int indx3); -XXTERN void svPutLogicArrElem(const svOpenArrayHandle d, svLogic value, int indx1, +XXTERN void svPutLogicArrElem(const svOpenArrayHandle d, svLogic value, int indx1, ...); -XXTERN void svPutLogicArrElem1(const svOpenArrayHandle d, svLogic value, int indx1); -XXTERN void svPutLogicArrElem2(const svOpenArrayHandle d, svLogic value, int indx1, +XXTERN void svPutLogicArrElem1(const svOpenArrayHandle d, svLogic value, int indx1); +XXTERN void svPutLogicArrElem2(const svOpenArrayHandle d, svLogic value, int indx1, int indx2); -XXTERN void svPutLogicArrElem3(const svOpenArrayHandle d, svLogic value, int indx1, +XXTERN void svPutLogicArrElem3(const svOpenArrayHandle d, svLogic value, int indx1, int indx2, int indx3); -XXTERN void svPutBitArrElem(const svOpenArrayHandle d, svBit value, int indx1, ...); -XXTERN void svPutBitArrElem1(const svOpenArrayHandle d, svBit value, int indx1); -XXTERN void svPutBitArrElem2(const svOpenArrayHandle d, svBit value, int indx1, +XXTERN void svPutBitArrElem(const svOpenArrayHandle d, svBit value, int indx1, ...); +XXTERN void svPutBitArrElem1(const svOpenArrayHandle d, svBit value, int indx1); +XXTERN void svPutBitArrElem2(const svOpenArrayHandle d, svBit value, int indx1, int indx2); -XXTERN void svPutBitArrElem3(const svOpenArrayHandle d, svBit value, int indx1, +XXTERN void svPutBitArrElem3(const svOpenArrayHandle d, svBit value, int indx1, int indx2, int indx3); /* Functions for working with DPI context */ @@ -273,7 +273,7 @@ XXTERN void svPutBitArrElem3(const svOpenArrayHandle d, svBit value, int indx1 * is the scope of the function's declaration site, not call site. * Returns NULL if called from C code that is *not* an imported function. */ -XXTERN svScope svGetScope(); +XXTERN svScope svGetScope( void ); /* * Set context for subsequent export function execution. @@ -337,7 +337,7 @@ XXTERN int svGetCallerInfo(const char** fileName, int *lineNumber); * Returns 1 if the current execution thread is in the disabled state. * Disable protocol must be adhered to if in the disabled state. */ -XXTERN int svIsDisabledState(); +XXTERN int svIsDisabledState( void ); /* * Imported functions call this API function during disable processing to @@ -345,7 +345,7 @@ XXTERN int svIsDisabledState(); * This function must be called before returning from an imported function that is * in the disabled state. */ -XXTERN void svAckDisabledState(); +XXTERN void svAckDisabledState( void ); /* ********************************************************** diff --git a/include/vltstd/vpi_user.h b/include/vltstd/vpi_user.h index c7a901b30..bc830c014 100644 --- a/include/vltstd/vpi_user.h +++ b/include/vltstd/vpi_user.h @@ -1,7 +1,7 @@ /******************************************************************************* * vpi_user.h * - * IEEE Std 1800-2012 Programming Language Interface (PLI) + * IEEE Std 1800-2017 Programming Language Interface (PLI) * * This file contains the constant definitions, structure definitions, and * routine declarations used by the SystemVerilog Verification Procedural @@ -251,7 +251,7 @@ typedef PLI_UINT32 *vpiHandle; #define vpiModPathOut 96 /* output terminal of a module path */ #define vpiOperand 97 /* operand of expression */ #define vpiPortInst 98 /* connected port instance */ -#define vpiProcess 99 /* process in module */ +#define vpiProcess 99 /* process in module, program or interface */ #define vpiVariables 100 /* variables in module */ #define vpiUse 101 /* usage */ @@ -978,7 +978,7 @@ XXTERN vpiHandle vpi_handle_by_multi_index PROTO_PARAMS((vpiHandle obj, /****************************** GLOBAL VARIABLES ******************************/ -PLI_VEXTERN PLI_DLLESPEC void (*vlog_startup_routines[])(); +PLI_VEXTERN PLI_DLLESPEC void (*vlog_startup_routines[])( void ); /* array of function pointers, last pointer should be null */ diff --git a/src/V3Ast.h b/src/V3Ast.h index 669539fdd..f2557d68c 100644 --- a/src/V3Ast.h +++ b/src/V3Ast.h @@ -1980,7 +1980,7 @@ class AstNodeFTaskRef : public AstNode { private: AstNodeFTask* m_taskp; // [AfterLink] Pointer to task referenced string m_name; // Name of variable - string m_dotted; // Dotted part of scope to task or "" + string m_dotted; // Dotted part of scope the name()ed task/func is under or "" string m_inlinedDots; // Dotted hierarchy flattened out AstPackage* m_packagep; // Package hierarchy public: diff --git a/src/V3AstNodes.cpp b/src/V3AstNodes.cpp index 255c7dce8..28989858f 100644 --- a/src/V3AstNodes.cpp +++ b/src/V3AstNodes.cpp @@ -1025,7 +1025,7 @@ void AstVarXRef::dump(std::ostream& str) { if (packagep()) { str<<" pkg="<<(void*)packagep(); } if (lvalue()) str<<" [LV] => "; else str<<" [RV] <- "; - str<dump(str); } else if (varp()) { varp()->dump(str); } @@ -1096,7 +1096,7 @@ void AstNodeFTaskRef::dump(std::ostream& str) { this->AstNode::dump(str); if (packagep()) { str<<" pkg="<<(void*)packagep(); } str<<" -> "; - if (dotted()!="") { str<dump(str); } else { str<<"UNLINKED"; } } diff --git a/src/V3AstNodes.h b/src/V3AstNodes.h index 86825dfaf..00ce3faed 100644 --- a/src/V3AstNodes.h +++ b/src/V3AstNodes.h @@ -1486,7 +1486,7 @@ class AstVarXRef : public AstNodeVarRef { // A VarRef to something in another module before AstScope. // Includes pin on a cell, as part of a ASSIGN statement to connect I/Os until AstScope private: - string m_dotted; // Scope name to connected to + string m_dotted; // Dotted part of scope the name()'ed reference is under or "" string m_inlinedDots; // Dotted hierarchy flattened out public: AstVarXRef(FileLine* fl, const string& name, const string& dotted, bool lvalue) @@ -2775,17 +2775,16 @@ public: void fromp(AstNode* nodep) { setOp2p(nodep); } }; -class AstReadMem : public AstNodeStmt { +class AstNodeReadWriteMem : public AstNodeStmt { private: bool m_isHex; // readmemh, not readmemb public: - AstReadMem(FileLine* fileline, bool hex, - AstNode* filenamep, AstNode* memp, AstNode* lsbp, AstNode* msbp) + AstNodeReadWriteMem(FileLine* fileline, bool hex, + AstNode* filenamep, AstNode* memp, + AstNode* lsbp, AstNode* msbp) : AstNodeStmt (fileline), m_isHex(hex) { setOp1p(filenamep); setOp2p(memp); setNOp3p(lsbp); setNOp4p(msbp); } - ASTNODE_NODE_FUNCS(ReadMem) - virtual string verilogKwd() const { return (isHex()?"$readmemh":"$readmemb"); } virtual bool isGateOptimizable() const { return false; } virtual bool isPredictOptimizable() const { return false; } virtual bool isPure() const { return false; } @@ -2793,12 +2792,35 @@ public: virtual bool isUnlikely() const { return true; } virtual V3Hash sameHash() const { return V3Hash(); } virtual bool same(const AstNode* samep) const { - return isHex()==static_cast(samep)->isHex(); } + return isHex()==static_cast(samep)->isHex(); + } bool isHex() const { return m_isHex; } AstNode* filenamep() const { return op1p(); } AstNode* memp() const { return op2p(); } AstNode* lsbp() const { return op3p(); } AstNode* msbp() const { return op4p(); } + virtual const char* cFuncPrefixp() const = 0; +}; + +class AstReadMem : public AstNodeReadWriteMem { +public: + AstReadMem(FileLine* fileline, bool hex, + AstNode* filenamep, AstNode* memp, AstNode* lsbp, AstNode* msbp) + : AstNodeReadWriteMem(fileline, hex, filenamep, memp, lsbp, msbp) + { } + ASTNODE_NODE_FUNCS(ReadMem); + virtual string verilogKwd() const { return (isHex()?"$readmemh":"$readmemb"); } + virtual const char* cFuncPrefixp() const { return "VL_READMEM_"; } +}; + +class AstWriteMem : public AstNodeReadWriteMem { +public: + AstWriteMem(FileLine* fileline, + AstNode* filenamep, AstNode* memp, AstNode* lsbp, AstNode* msbp) + : AstNodeReadWriteMem(fileline, true, filenamep, memp, lsbp, msbp) { } + ASTNODE_NODE_FUNCS(WriteMem) + virtual string verilogKwd() const { return (isHex()?"$writememh":"$writememb"); } + virtual const char* cFuncPrefixp() const { return "VL_WRITEMEM_"; } }; class AstSystemT : public AstNodeStmt { diff --git a/src/V3EmitC.cpp b/src/V3EmitC.cpp index 23d3bf348..885b34eb8 100644 --- a/src/V3EmitC.cpp +++ b/src/V3EmitC.cpp @@ -324,8 +324,8 @@ public: nodep->modep()->iterateAndNext(*this); puts(");\n"); } - virtual void visit(AstReadMem* nodep) { - puts("VL_READMEM_"); + virtual void visit(AstNodeReadWriteMem* nodep) { + puts(nodep->cFuncPrefixp()); emitIQW(nodep->filenamep()); puts(" ("); // We take a void* rather than emitIQW(nodep->memp()); puts(nodep->isHex()?"true":"false"); @@ -335,21 +335,24 @@ public: uint32_t array_lsb = 0; { const AstVarRef* varrefp = VN_CAST(nodep->memp(), VarRef); - if (!varrefp) { nodep->v3error("Readmem loading non-variable"); } + if (!varrefp) { nodep->v3error(nodep->verilogKwd() << " loading non-variable"); } else if (const AstUnpackArrayDType* adtypep = VN_CAST(varrefp->varp()->dtypeSkipRefp(), UnpackArrayDType)) { puts(cvtToStr(varrefp->varp()->dtypep()->arrayUnpackedElements())); array_lsb = adtypep->lsb(); } else { - nodep->v3error("Readmem loading other than unpacked-array variable"); + nodep->v3error(nodep->verilogKwd() + << " loading other than unpacked-array variable"); } } putbs(", "); puts(cvtToStr(array_lsb)); putbs(","); - puts(cvtToStr(nodep->filenamep()->widthWords())); - checkMaxWords(nodep->filenamep()); - putbs(", "); + if (!nodep->filenamep()->dtypep()->isString()) { + puts(cvtToStr(nodep->filenamep()->widthWords())); + checkMaxWords(nodep->filenamep()); + putbs(", "); + } nodep->filenamep()->iterateAndNext(*this); putbs(", "); nodep->memp()->iterateAndNext(*this); diff --git a/src/V3EmitV.cpp b/src/V3EmitV.cpp index 70663dc9e..a607bf9b7 100644 --- a/src/V3EmitV.cpp +++ b/src/V3EmitV.cpp @@ -268,7 +268,7 @@ class EmitVBaseVisitor : public EmitCBaseVisitor { if (nodep->stmtsp()) nodep->stmtsp()->iterateAndNext(*this); puts("end\n"); } - virtual void visit(AstReadMem* nodep) { + virtual void visit(AstNodeReadWriteMem* nodep) { putfs(nodep,nodep->verilogKwd()); putbs(" ("); if (nodep->filenamep()) nodep->filenamep()->iterateAndNext(*this); diff --git a/src/V3Inline.cpp b/src/V3Inline.cpp index 301a26c63..e822bf078 100644 --- a/src/V3Inline.cpp +++ b/src/V3Inline.cpp @@ -42,6 +42,7 @@ #include "V3Inst.h" #include "V3Stats.h" #include "V3Ast.h" +#include "V3String.h" // CONFIG static const int INLINE_MODS_SMALLER = 100; // If a mod is < this # nodes, can always inline it @@ -270,14 +271,14 @@ public: class InlineRelinkVisitor : public AstNVisitor { private: - typedef vl_unordered_set RenamedInterfacesSet; + typedef vl_unordered_set StringSet; // NODE STATE // Input: // See InlineVisitor // STATE - RenamedInterfacesSet m_renamedInterfaces; // Name of renamed interface variables + StringSet m_renamedInterfaces; // Name of renamed interface variables AstNodeModule* m_modp; // Current module AstCell* m_cellp; // Cell being cloned @@ -410,9 +411,8 @@ private: } virtual void visit(AstVarXRef* nodep) { // Track what scope it was originally under so V3LinkDot can resolve it - string newname = m_cellp->name(); - if (nodep->inlinedDots() != "") { newname += "." + nodep->inlinedDots(); } - nodep->inlinedDots(newname); + string newdots = VString::dot(m_cellp->name(), ".", nodep->inlinedDots()); + nodep->inlinedDots(newdots); for (string tryname = nodep->dotted(); 1;) { if (m_renamedInterfaces.count(tryname)) { nodep->dotted(m_cellp->name() + "__DOT__" + nodep->dotted()); @@ -430,9 +430,8 @@ private: } virtual void visit(AstNodeFTaskRef* nodep) { // Track what scope it was originally under so V3LinkDot can resolve it - string newname = m_cellp->name(); - if (nodep->inlinedDots() != "") { newname += "." + nodep->inlinedDots(); } - nodep->inlinedDots(newname); + string newdots = VString::dot(m_cellp->name(), ".", nodep->inlinedDots()); + nodep->inlinedDots(newdots); if (m_renamedInterfaces.count(nodep->dotted())) { nodep->dotted(m_cellp->name() + "__DOT__" + nodep->dotted()); } @@ -459,9 +458,7 @@ private: } virtual void visit(AstCoverDecl* nodep) { // Fix path in coverage statements - nodep->hier(m_cellp->prettyName() - + (nodep->hier()!="" ? ".":"") - + nodep->hier()); + nodep->hier(VString::dot(m_cellp->prettyName(), ".", nodep->hier())); nodep->iterateChildren(*this); } virtual void visit(AstNode* nodep) { @@ -537,7 +534,7 @@ private: // this loop as it clone()s itself. for (AstPin* pinp = nodep->pinsp(); pinp; pinp=VN_CAST(pinp->nextp(), Pin)) { if (!pinp->exprp()) continue; - V3Inst::pinReconnectSimple(pinp, nodep, m_modp, false); + V3Inst::pinReconnectSimple(pinp, nodep, false); } // Clone original module diff --git a/src/V3Inst.cpp b/src/V3Inst.cpp index fc2a7e2b2..de6ec807f 100644 --- a/src/V3Inst.cpp +++ b/src/V3Inst.cpp @@ -86,9 +86,9 @@ private: // Use user1p on the PIN to indicate we created an assign for this pin if (!nodep->user1SetOnce()) { // Simplify it - V3Inst::pinReconnectSimple(nodep, m_cellp, m_modp, false); - // Make a ASSIGNW (expr, pin) - AstNode* exprp = nodep->exprp()->cloneTree(false); + V3Inst::pinReconnectSimple(nodep, m_cellp, false); + // Make an ASSIGNW (expr, pin) + AstNode* exprp = nodep->exprp()->cloneTree(false); if (exprp->width() != nodep->modVarp()->width()) nodep->v3fatalSrc("Width mismatch, should have been handled in pinReconnectSimple"); if (nodep->modVarp()->isInout()) { @@ -133,6 +133,7 @@ private: } // Save some time + virtual void visit(AstNodeMath*) {} virtual void visit(AstNodeAssign*) {} virtual void visit(AstAlways*) {} @@ -496,7 +497,7 @@ private: } public: - static AstAssignW* pinReconnectSimple(AstPin* pinp, AstCell* cellp, AstNodeModule*, + static AstAssignW* pinReconnectSimple(AstPin* pinp, AstCell* cellp, bool forTristate, bool alwaysCvt) { // If a pin connection is "simple" leave it as-is // Else create a intermediate wire to perform the interconnect @@ -573,9 +574,9 @@ public: //###################################################################### // Inst class functions -AstAssignW* V3Inst::pinReconnectSimple(AstPin* pinp, AstCell* cellp, AstNodeModule* modp, +AstAssignW* V3Inst::pinReconnectSimple(AstPin* pinp, AstCell* cellp, bool forTristate, bool alwaysCvt) { - return InstStatic::pinReconnectSimple(pinp, cellp, modp, forTristate, alwaysCvt); + return InstStatic::pinReconnectSimple(pinp, cellp, forTristate, alwaysCvt); } //###################################################################### diff --git a/src/V3Inst.h b/src/V3Inst.h index e0b09c716..57700f3d0 100644 --- a/src/V3Inst.h +++ b/src/V3Inst.h @@ -31,7 +31,7 @@ class V3Inst { public: static void instAll(AstNetlist* nodep); static void dearrayAll(AstNetlist* nodep); - static AstAssignW* pinReconnectSimple(AstPin* nodep, AstCell* cellp, AstNodeModule* modp, + static AstAssignW* pinReconnectSimple(AstPin* nodep, AstCell* cellp, bool forTristate, bool alwaysCvt=false); }; diff --git a/src/V3LangCode.h b/src/V3LangCode.h index 839447b25..e2cfd3ae0 100644 --- a/src/V3LangCode.h +++ b/src/V3LangCode.h @@ -42,6 +42,7 @@ public: L1800_2005, L1800_2009, L1800_2012, + L1800_2017, // ***Add new elements below also*** _ENUM_END }; @@ -54,12 +55,14 @@ public: "1364-2005", "1800-2005", "1800-2009", - "1800-2012" + "1800-2012", + "1800-2017" }; return names[m_e]; }; - static V3LangCode mostRecent() { return V3LangCode(L1800_2012); } - bool systemVerilog() const { return m_e == L1800_2005 || m_e == L1800_2009 || m_e == L1800_2012; } + static V3LangCode mostRecent() { return V3LangCode(L1800_2017); } + bool systemVerilog() const { return m_e == L1800_2005 || m_e == L1800_2009 + || m_e == L1800_2012 || m_e == L1800_2017; } bool legal() const { return m_e != L_ERROR; } // enum en m_e; diff --git a/src/V3LinkDot.cpp b/src/V3LinkDot.cpp index e7e3a5c12..14e9351a7 100644 --- a/src/V3LinkDot.cpp +++ b/src/V3LinkDot.cpp @@ -78,6 +78,7 @@ #include "V3Graph.h" #include "V3Ast.h" #include "V3ParseImp.h" +#include "V3String.h" //###################################################################### // LinkDot state, as a visitor of each AstNode @@ -1807,8 +1808,7 @@ private: || VN_IS(foundp->nodep(), Module)) { // if top if (allowScope) { ok = true; - if (m_ds.m_dotText!="") m_ds.m_dotText += "."; - m_ds.m_dotText += nodep->name(); + m_ds.m_dotText = VString::dot(m_ds.m_dotText, ".", nodep->name()); m_ds.m_dotSymp = foundp; m_ds.m_dotPos = DP_SCOPE; // Upper AstDot visitor will handle it from here @@ -1827,8 +1827,7 @@ private: if (!ifaceRefVarp) nodep->v3fatalSrc("Can't find interface var ref: "<name(); + m_ds.m_dotText = VString::dot(m_ds.m_dotText, ".", nodep->name()); m_ds.m_dotSymp = foundp; m_ds.m_dotPos = DP_SCOPE; UINFO(9," cell -> iface varref "<nodep()<ifaceViaCellp()) ifacerefp->v3fatalSrc("Unlinked interface"); // Really this is a scope reference into an interface UINFO(9,"varref-ifaceref "<name(); + m_ds.m_dotText = VString::dot(m_ds.m_dotText, ".", nodep->name()); m_ds.m_dotSymp = m_statep->getNodeSym(ifacerefp->ifaceViaCellp()); m_ds.m_dotPos = DP_SCOPE; ok = true; @@ -1897,8 +1895,7 @@ private: if (!cellp) nodep->v3fatalSrc("Modport not referenced from a cell"); AstIface* ifacep = VN_CAST(cellp->modp(), Iface); //string cellName = m_ds.m_dotText; // Use cellp->name - if (m_ds.m_dotText!="") m_ds.m_dotText += "."; - m_ds.m_dotText += nodep->name(); + m_ds.m_dotText = VString::dot(m_ds.m_dotText, ".", nodep->name()); m_ds.m_dotSymp = m_statep->getNodeSym(modportp); m_ds.m_dotPos = DP_SCOPE; ok = true; diff --git a/src/V3LinkParse.cpp b/src/V3LinkParse.cpp index b56367af0..d276a578d 100644 --- a/src/V3LinkParse.cpp +++ b/src/V3LinkParse.cpp @@ -340,6 +340,7 @@ private: FileLine* fl = varsp->fileline(); AstNode* varp = new AstVar(fl, AstVarType::BLOCKTEMP, varsp->name(), nodep->findSigned32DType()); + // These will be the left and right dimensions of the array: AstNode* leftp = new AstAttrOf(fl, AstAttrType::DIM_LEFT, new AstVarRef(fl, arrayp->name(), false), new AstConst(fl, dimension)); @@ -347,19 +348,26 @@ private: new AstVarRef(fl, arrayp->name(), false), new AstConst(fl, dimension)); AstNode* stmtsp = varp; - stmtsp->addNext(new AstAssign(fl, new AstVarRef(fl, varp->name(), true), leftp)); - AstNode* comparep = - new AstCond(fl, new AstLte(fl, leftp->cloneTree(true), rightp->cloneTree(true)), - // left increments up to right - new AstLte(fl, new AstVarRef(fl, varp->name(), false), rightp->cloneTree(true)), - // left decrements down to right - new AstGte(fl, new AstVarRef(fl, varp->name(), false), rightp)); - AstNode* incp = - new AstAssign(fl, new AstVarRef(fl, varp->name(), true), - new AstAdd(fl, new AstVarRef(fl, varp->name(), false), - new AstNegate(fl, new AstAttrOf(fl, AstAttrType::DIM_INCREMENT, - new AstVarRef(fl, arrayp->name(), false), - new AstConst(fl, dimension))))); + // Assign left-dimension into the loop var: + stmtsp->addNext(new AstAssign + (fl, new AstVarRef(fl, varp->name(), true), leftp)); + // This will turn into a bool constant, indicating whether + // we count the loop variable up or down: + AstNode* countupp = new AstLte(fl, leftp->cloneTree(true), + rightp->cloneTree(true)); + AstNode* comparep = new AstCond( + fl, countupp->cloneTree(true), + // Left increments up to right + new AstLte(fl, new AstVarRef(fl, varp->name(), false), + rightp->cloneTree(true)), + // Left decrements down to right + new AstGte(fl, new AstVarRef(fl, varp->name(), false), rightp)); + AstNode* incp = new AstAssign( + fl, new AstVarRef(fl, varp->name(), true), + new AstAdd(fl, new AstVarRef(fl, varp->name(), false), + new AstCond(fl, countupp, + new AstConst(fl, 1), + new AstConst(fl, -1)))); stmtsp->addNext(new AstWhile(fl, comparep, newp, incp)); newp = new AstBegin(nodep->fileline(),"",stmtsp); dimension--; diff --git a/src/V3Number.cpp b/src/V3Number.cpp index eb3550464..09412acaf 100644 --- a/src/V3Number.cpp +++ b/src/V3Number.cpp @@ -142,7 +142,7 @@ V3Number::V3Number (FileLine* fileline, const char* sourcep) { if (!m_sized) { static int warned = false; if (!warned++) { - m_fileline->v3error("As that number was unsized ('d...) it is limited to 32 bits (IEEE 2012 5.7.1)"); + m_fileline->v3error("As that number was unsized ('d...) it is limited to 32 bits (IEEE 2017 5.7.1)"); } } while (*(cp+1)) cp++; // Skip ahead so don't get multiple warnings diff --git a/src/V3Options.cpp b/src/V3Options.cpp index 50d46dee2..918c54a77 100644 --- a/src/V3Options.cpp +++ b/src/V3Options.cpp @@ -604,7 +604,7 @@ void V3Options::parseOptsList(FileLine* fl, const string& optdir, int argc, char else if ( !strncmp (sw, "+incdir+", 8)) { addIncDirUser (parseFileArg(optdir, string (sw+strlen("+incdir+")))); } - else if (parseLangExt(sw, "+systemverilogext+", V3LangCode::L1800_2012) + else if (parseLangExt(sw, "+systemverilogext+", V3LangCode::L1800_2017) || parseLangExt(sw, "+verilog1995ext+", V3LangCode::L1364_1995) || parseLangExt(sw, "+verilog2001ext+", V3LangCode::L1364_2001) || parseLangExt(sw, "+1364-1995ext+", V3LangCode::L1364_1995) @@ -612,7 +612,8 @@ void V3Options::parseOptsList(FileLine* fl, const string& optdir, int argc, char || parseLangExt(sw, "+1364-2005ext+", V3LangCode::L1364_2005) || parseLangExt(sw, "+1800-2005ext+", V3LangCode::L1800_2005) || parseLangExt(sw, "+1800-2009ext+", V3LangCode::L1800_2009) - || parseLangExt(sw, "+1800-2012ext+", V3LangCode::L1800_2012)) { + || parseLangExt(sw, "+1800-2012ext+", V3LangCode::L1800_2012) + || parseLangExt(sw, "+1800-2017ext+", V3LangCode::L1800_2017)) { // Nothing to do here - all done in the test } diff --git a/src/V3Scope.cpp b/src/V3Scope.cpp index 2b3b11dcd..7b9902cb0 100644 --- a/src/V3Scope.cpp +++ b/src/V3Scope.cpp @@ -33,6 +33,8 @@ #include #include #include +#include VL_INCLUDE_UNORDERED_MAP +#include VL_INCLUDE_UNORDERED_SET #include "V3Global.h" #include "V3Scope.h" @@ -50,9 +52,9 @@ private: AstUser2InUse m_inuser2; // TYPES - typedef std::map PackageScopeMap; - typedef std::map, AstVarScope*> VarScopeMap; - typedef std::set > VarRefScopeSet; + typedef vl_unordered_map PackageScopeMap; + typedef vl_unordered_map, AstVarScope*> VarScopeMap; + typedef vl_unordered_set > VarRefScopeSet; // STATE, inside processing a single module AstNodeModule* m_modp; // Current module diff --git a/src/V3String.cpp b/src/V3String.cpp index 99fe1f7f6..9862eab39 100644 --- a/src/V3String.cpp +++ b/src/V3String.cpp @@ -69,6 +69,12 @@ bool VString::wildmatch(const char* s, const char* p) { return (*s == '\0'); } +string VString::dot(const string& a, const string& dot, const string& b) { + if (b=="") return a; + if (a=="") return b; + return a+dot+b; +} + string VString::downcase(const string& str) { string out = str; for (string::iterator pos = out.begin(); pos != out.end(); ++pos) { diff --git a/src/V3String.h b/src/V3String.h index 452d45c79..a077b514f 100644 --- a/src/V3String.h +++ b/src/V3String.h @@ -33,8 +33,13 @@ class VString { static bool wildmatchi(const char* s, const char* p); public: // METHODS (generic string utilities) + // Return true if p with ? or *'s matches s static bool wildmatch(const char* s, const char* p); + // Return {a}{dot}{b}, omitting dot if a or b are empty + static string dot(const string& a, const string& dot, const string& b); + // Convert string to lowercase static string downcase(const string& str); + // Replace any %'s with %% static string quotePercent(const string& str); }; diff --git a/src/V3SymTable.h b/src/V3SymTable.h index f189bd3d7..328563523 100644 --- a/src/V3SymTable.h +++ b/src/V3SymTable.h @@ -71,6 +71,7 @@ public: os<basicp()->prettyTypeName() - <<" (IEEE 2012 35.5.5)"); + <<" (IEEE 2017 35.5.5)"); } portp->unlinkFrBack(); rtnvarp = portp; diff --git a/src/V3Tristate.cpp b/src/V3Tristate.cpp index 67e05d769..7930bbef6 100644 --- a/src/V3Tristate.cpp +++ b/src/V3Tristate.cpp @@ -1066,7 +1066,7 @@ class TristateVisitor : public TristateBaseVisitor { if (!enModVarp) { if (nodep->exprp()) { // May have an output only that later connects to a tristate, so simplify now. - V3Inst::pinReconnectSimple(nodep, m_cellp, m_modp, false); + V3Inst::pinReconnectSimple(nodep, m_cellp, false); } iteratePinGuts(nodep); return; // No __en signals on this pin @@ -1092,7 +1092,7 @@ class TristateVisitor : public TristateBaseVisitor { } else if (inDeclProcessing) { // Not an input that was a converted tristate // Input only may have driver in underneath module which would stomp // the input value. So make a temporary connection. - AstAssignW* reAssignp = V3Inst::pinReconnectSimple(nodep, m_cellp, m_modp, true, true); + AstAssignW* reAssignp = V3Inst::pinReconnectSimple(nodep, m_cellp, true, true); UINFO(5,"Input pin buffering: "<lhsp()); } @@ -1146,7 +1146,7 @@ class TristateVisitor : public TristateBaseVisitor { TristatePinVisitor visitor (outexprp, m_tgraph, true); } if (debug()>=9) outpinp->dumpTree(cout,"-pin-opr: "); - outAssignp = V3Inst::pinReconnectSimple(outpinp, m_cellp, m_modp, true); // Note may change outpinp->exprp() + outAssignp = V3Inst::pinReconnectSimple(outpinp, m_cellp, true); // Note may change outpinp->exprp() if (debug()>=9) outpinp->dumpTree(cout,"-pin-out: "); if (debug()>=9 && outAssignp) outAssignp->dumpTree(cout,"-pin-out: "); // Must still iterate the outAssignp, as need to build output equation @@ -1154,7 +1154,7 @@ class TristateVisitor : public TristateBaseVisitor { // Existing pin becomes an input, and we mark each resulting signal as tristate TristatePinVisitor visitor (nodep->exprp(), m_tgraph, false); - AstNode* inAssignp = V3Inst::pinReconnectSimple(nodep, m_cellp, m_modp, true); // Note may change nodep->exprp() + AstNode* inAssignp = V3Inst::pinReconnectSimple(nodep, m_cellp, true); // Note may change nodep->exprp() if (debug()>=9) nodep->dumpTree(cout,"-pin-in: "); if (debug()>=9 && inAssignp) inAssignp->dumpTree(cout,"-pin-as: "); diff --git a/src/V3Width.cpp b/src/V3Width.cpp index 2940f4649..9029c71d6 100644 --- a/src/V3Width.cpp +++ b/src/V3Width.cpp @@ -20,7 +20,7 @@ // V3Width's Transformations: // Top down traversal: // Determine width of sub-expressions -// width() = # bits upper expression wants, 0 for anything-goes +// width() = # bits upper expression wants, 0 for anything-goes // widthUnsized() = # bits for unsized constant, or 0 if it's sized // widthMin() = Alternative acceptable width for linting, or width() if sized // Determine this subop's width, can be either: @@ -29,7 +29,7 @@ // Pass up: // width() = # bits this expression generates // widthSized() = true if all constants sized, else false -// Compute size of this expression +// Compute size of this expression // Lint warn about mismatches // If expr size != subop fixed, bad // If expr size < subop unsized minimum, bad @@ -446,7 +446,7 @@ private: if (!constp) { nodep->v3error("Replication value isn't a constant."); return; } uint32_t times = constp->toUInt(); if (times==0 && !VN_IS(nodep->backp(), Concat)) { // Concat Visitor will clean it up. - nodep->v3error("Replication value of 0 is only legal under a concatenation (IEEE 2012 11.4.12.1)"); times=1; + nodep->v3error("Replication value of 0 is only legal under a concatenation (IEEE 2017 11.4.12.1)"); times=1; } if (nodep->lhsp()->isString()) { AstNode* newp = new AstReplicateN(nodep->fileline(),nodep->lhsp()->unlinkFrBack(), @@ -477,7 +477,7 @@ private: if (!constp) { nodep->v3error("Replication value isn't a constant."); return; } uint32_t times = constp->toUInt(); if (times==0 && !VN_IS(nodep->backp(), Concat)) { // Concat Visitor will clean it up. - nodep->v3error("Replication value of 0 is only legal under a concatenation (IEEE 2012 11.4.12.1)"); + nodep->v3error("Replication value of 0 is only legal under a concatenation (IEEE 2017 11.4.12.1)"); } nodep->dtypeSetString(); } @@ -1299,7 +1299,7 @@ private: } if (!itemp->valuep()) { if (num.isEqZero() && itemp != nodep->itemsp()) - itemp->v3error("Enum value illegally wrapped around (IEEE 2012 6.19)"); + itemp->v3error("Enum value illegally wrapped around (IEEE 2017 6.19)"); if (!nodep->dtypep()->basicp() && !nodep->dtypep()->basicp()->keyword().isIntNumeric()) { itemp->v3error("Enum names without values only allowed on numeric types"); @@ -2206,12 +2206,13 @@ private: assertAtStatement(nodep); userIterateAndNext(nodep->lhsp(), WidthVP(SELF,BOTH).p()); } - virtual void visit(AstReadMem* nodep) { + virtual void visit(AstNodeReadWriteMem* nodep) { assertAtStatement(nodep); userIterateAndNext(nodep->filenamep(), WidthVP(SELF,BOTH).p()); userIterateAndNext(nodep->memp(), WidthVP(SELF,BOTH).p()); if (!VN_IS(nodep->memp()->dtypep()->skipRefp(), UnpackArrayDType)) { - nodep->memp()->v3error("Unsupported: $readmem into other than unpacked array"); + nodep->memp()->v3error("Unsupported: " << nodep->verilogKwd() + << " into other than unpacked array"); } userIterateAndNext(nodep->lsbp(), WidthVP(SELF,BOTH).p()); userIterateAndNext(nodep->msbp(), WidthVP(SELF,BOTH).p()); diff --git a/src/verilog.l b/src/verilog.l index 680042c1b..f116279a2 100644 --- a/src/verilog.l +++ b/src/verilog.l @@ -32,7 +32,7 @@ extern void yyerror(const char*); extern void yyerrorf(const char* format, ...); -#define STATE_VERILOG_RECENT S12 // State name for most recent Verilog Version +#define STATE_VERILOG_RECENT S17 // State name for most recent Verilog Version #define PARSEP V3ParseImp::parsep() #define SYMP PARSEP->symp() @@ -126,7 +126,7 @@ void yyerror(const char* errmsg) { static int warned = false; if (!warned++) { PARSEP->fileline()->v3error("Perhaps '"+*PARSEP->prevBisonVal().strp - +"' is a package which needs to be predeclared? (IEEE 2012 26.3)"); + +"' is a package which needs to be predeclared? (IEEE 2017 26.3)"); } } } @@ -154,7 +154,7 @@ void yyerrorf(const char* format, ...) { %a 15000 %o 25000 -%s V95 V01 V05 S05 S09 S12 +%s V95 V01 V05 S05 S09 S12 S17 %s STRING ATTRMODE TABLE %s VA5 SAX VLT %s SYSCHDR SYSCINT SYSCIMP SYSCIMPH SYSCCTOR SYSCDTOR @@ -200,7 +200,7 @@ vnum {vnum1}|{vnum2}|{vnum3}|{vnum4}|{vnum5} /************************************************************************/ /* Verilog 1995 */ -{ +{ {ws} { } /* otherwise ignore white-space */ {crnl} { NEXTLINE(); } /* Count line numbers */ /* Extensions to Verilog set, some specified by PSL */ @@ -269,6 +269,7 @@ vnum {vnum1}|{vnum2}|{vnum3}|{vnum4}|{vnum5} "$value$plusargs" { FL; return yD_VALUEPLUSARGS; } "$width" { FL; return yaTIMINGSPEC; } "$write" { FL; return yD_WRITE; } + "$writememh" { FL; return yD_WRITEMEMH; } /* Keywords */ "always" { FL; return yALWAYS; } "and" { FL; return yAND; } @@ -389,7 +390,7 @@ vnum {vnum1}|{vnum2}|{vnum3}|{vnum4}|{vnum5} } /* Verilog 2001 */ -{ +{ /* System Tasks */ "$signed" { FL; return yD_SIGNED; } "$unsigned" { FL; return yD_UNSIGNED; } @@ -420,13 +421,13 @@ vnum {vnum1}|{vnum2}|{vnum3}|{vnum4}|{vnum5} } /* Verilog 2005 */ -{ +{ /* Keywords */ "uwire" { FL; return yWIRE; } } /* System Verilog 2005 */ -{ +{ /* System Tasks */ "$bits" { FL; return yD_BITS; } "$clog2" { FL; return yD_CLOG2; } @@ -551,7 +552,7 @@ vnum {vnum1}|{vnum2}|{vnum3}|{vnum4}|{vnum5} } /* SystemVerilog 2009 */ -{ +{ /* Keywords */ "global" { FL; return yGLOBAL__LEX; } "unique0" { FL; return yUNIQUE0; } @@ -580,7 +581,7 @@ vnum {vnum1}|{vnum2}|{vnum3}|{vnum4}|{vnum5} } /* System Verilog 2012 */ -{ +{ /* Keywords */ "implements" { yyerrorf("Unsupported: SystemVerilog 2012 reserved word not implemented: %s",yytext); } "interconnect" { yyerrorf("Unsupported: SystemVerilog 2012 reserved word not implemented: %s",yytext); } @@ -588,8 +589,11 @@ vnum {vnum1}|{vnum2}|{vnum3}|{vnum4}|{vnum5} "soft" { yyerrorf("Unsupported: SystemVerilog 2012 reserved word not implemented: %s",yytext); } } + /* System Verilog 2017 */ + /* No new keywords */ + /* Default PLI rule */ -{ +{ "$"[a-zA-Z_$][a-zA-Z0-9_$]* { string str (yytext,yyleng); yylval.strp = PARSEP->newString(AstNode::encodeName(str)); // Lookup unencoded name including the $, to avoid hitting normal signals @@ -696,7 +700,7 @@ vnum {vnum1}|{vnum2}|{vnum3}|{vnum4}|{vnum5} /* Meta comments */ /* Converted from //{cmt}verilator ...{cmt} by preprocessor */ -{ +{ "/*verilator"{ws}*"*/" {} /* Ignore empty comments, may be `endif // verilator */ "/*verilator clock_enable*/" { FL; return yVL_CLOCK_ENABLE; } "/*verilator coverage_block_off*/" { FL; return yVL_COVERAGE_BLOCK_OFF; } @@ -734,7 +738,7 @@ vnum {vnum1}|{vnum2}|{vnum3}|{vnum4}|{vnum5} /************************************************************************/ /* Single character operator thingies */ -{ +{ "{" { FL; return yytext[0]; } "}" { FL; return yytext[0]; } "!" { FL; return yytext[0]; } @@ -768,7 +772,7 @@ vnum {vnum1}|{vnum2}|{vnum3}|{vnum4}|{vnum5} /* Operators and multi-character symbols */ /* Verilog 1995 Operators */ -{ +{ "&&" { FL; return yP_ANDAND; } "||" { FL; return yP_OROR; } "<=" { FL; return yP_LTE; } @@ -790,7 +794,7 @@ vnum {vnum1}|{vnum2}|{vnum3}|{vnum4}|{vnum5} } /* Verilog 2001 Operators */ -{ +{ "<<<" { FL; return yP_SLEFT; } ">>>" { FL; return yP_SSRIGHT; } "**" { FL; return yP_POW; } @@ -803,7 +807,7 @@ vnum {vnum1}|{vnum2}|{vnum3}|{vnum4}|{vnum5} } /* SystemVerilog Operators */ -{ +{ "'" { FL; return yP_TICK; } "'{" { FL; return yP_TICKBRA; } "==?" { FL; return yP_WILDEQUAL; } @@ -837,7 +841,7 @@ vnum {vnum1}|{vnum2}|{vnum3}|{vnum4}|{vnum5} } /* Identifiers and numbers */ -{ +{ {escid} { FL; yylval.strp = PARSEP->newString (AstNode::encodeName(string(yytext+1))); // +1 to skip the backslash return yaID__LEX; @@ -910,7 +914,7 @@ vnum {vnum1}|{vnum2}|{vnum3}|{vnum4}|{vnum5} /************************************************************************/ /* Attributes */ /* Note simulators vary in support for "(* /_*something*_/ foo*)" where _ doesn't exist */ -{ +{ "(*"({ws}|{crnl})*({id}|{escid}) { yymore(); yy_push_state(ATTRMODE); } /* Doesn't match (*), but (* attr_spec */ } @@ -927,7 +931,7 @@ vnum {vnum1}|{vnum2}|{vnum3}|{vnum4}|{vnum5} /* Preprocessor */ /* Common for all SYSC header states */ /* OPTIMIZE: we return one per line, make it one for the entire block */ -{ +{ "`accelerate" { } // Verilog-XL compatibility "`autoexpand_vectornets" { } // Verilog-XL compatibility "`celldefine" { PARSEP->inCellDefine(true); } @@ -971,6 +975,7 @@ vnum {vnum1}|{vnum2}|{vnum3}|{vnum4}|{vnum5} "`begin_keywords"[ \t]*\"1800-2005\" { yy_push_state(S05); PARSEP->pushBeginKeywords(YY_START); } "`begin_keywords"[ \t]*\"1800-2009\" { yy_push_state(S09); PARSEP->pushBeginKeywords(YY_START); } "`begin_keywords"[ \t]*\"1800-2012\" { yy_push_state(S12); PARSEP->pushBeginKeywords(YY_START); } + "`begin_keywords"[ \t]*\"1800-2017\" { yy_push_state(S17); PARSEP->pushBeginKeywords(YY_START); } "`begin_keywords"[ \t]*\"1800[+]VAMS\" { yy_push_state(SAX); PARSEP->pushBeginKeywords(YY_START); } /*Latest SV*/ "`end_keywords" { yy_pop_state(); if (!PARSEP->popBeginKeywords()) yyerrorf("`end_keywords when not inside `begin_keywords block"); } @@ -1002,7 +1007,7 @@ vnum {vnum1}|{vnum2}|{vnum3}|{vnum4}|{vnum5} /************************************************************************/ /* Default rules - leave last */ -{ +{ "`"[a-zA-Z_0-9]+ { FL; yyerrorf("Define or directive not defined: %s",yytext); } "//"[^\n]* { } /* throw away single line comments */ . { FL; return yytext[0]; } /* return single char ops. */ diff --git a/src/verilog.y b/src/verilog.y index ff503bfed..4ac7965ac 100644 --- a/src/verilog.y +++ b/src/verilog.y @@ -515,6 +515,7 @@ class AstSenTree; %token yD_VALUEPLUSARGS "$value$plusargs" %token yD_WARNING "$warning" %token yD_WRITE "$write" +%token yD_WRITEMEMH "$writememh" %token yVL_CLOCK "/*verilator sc_clock*/" %token yVL_CLOCKER "/*verilator clocker*/" @@ -742,7 +743,6 @@ package_or_generate_item_declaration: // ==IEEE: package_or_generate_item | local_parameter_declaration ';' { $$ = $1; } | parameter_declaration ';' { $$ = $1; } //UNSUP covergroup_declaration { $$ = $1; } - //UNSUP overload_declaration { $$ = $1; } //UNSUP assertion_item_declaration { $$ = $1; } | ';' { $$ = NULL; } ; @@ -2277,7 +2277,6 @@ block_item_declaration: // ==IEEE: block_item_declaration data_declaration { $$ = $1; } | local_parameter_declaration ';' { $$ = $1; } | parameter_declaration ';' { $$ = $1; } - //UNSUP overload_declaration { $$ = $1; } //UNSUP let_declaration { $$ = $1; } ; @@ -2376,8 +2375,7 @@ statement_item: // IEEE: statement_item | yREPEAT '(' expr ')' stmtBlock { $$ = new AstRepeat($1,$3,$5);} | yWHILE '(' expr ')' stmtBlock { $$ = new AstWhile($1,$3,$5);} // // for's first ';' is in for_initalization - | yFOR '(' for_initialization expr ';' for_stepE ')' stmtBlock - { $$ = new AstBegin($1,"",$3); $3->addNext(new AstWhile($1, $4,$8,$6)); } + | statementFor { $$ = $1; } | yDO stmtBlock yWHILE '(' expr ')' ';' { if ($2) { $$ = $2->cloneTree(true); $$->addNext(new AstWhile($1,$5,$2)); @@ -2429,6 +2427,15 @@ statement_item: // IEEE: statement_item | error ';' { $$ = NULL; } ; +statementFor: // IEEE: part of statement + yFOR '(' for_initialization expr ';' for_stepE ')' stmtBlock + { $$ = new AstBegin($1,"",$3); + $$->addStmtsp(new AstWhile($1, $4,$8,$6)); } + | yFOR '(' for_initialization ';' for_stepE ')' stmtBlock + { $$ = new AstBegin($1,"",$3); + $$->addStmtsp(new AstWhile($1, new AstConst($1,AstConst::LogicTrue()),$7,$5)); } + ; + statementVerilatorPragmas: yVL_COVERAGE_BLOCK_OFF { $$ = new AstPragma($1,AstPragmaType::COVERAGE_BLOCK_OFF); } ; @@ -2603,6 +2610,7 @@ for_initialization: // ==IEEE: for_initialization + for_variable_declarat $$ = VARDONEA($2,*$2,NULL,NULL); $$->addNext(new AstAssign($3,new AstVarRef($3,*$2,true),$4));} | varRefBase '=' expr ';' { $$ = new AstAssign($2,$1,$3); } + | ';' { $$ = NULL; } //UNSUP: List of initializations ; @@ -2707,6 +2715,10 @@ system_t_call: // IEEE: system_tf_call (as task) | yD_READMEMH '(' expr ',' idClassSel ',' expr ')' { $$ = new AstReadMem($1,true, $3,$5,$7,NULL); } | yD_READMEMH '(' expr ',' idClassSel ',' expr ',' expr ')' { $$ = new AstReadMem($1,true, $3,$5,$7,$9); } // + | yD_WRITEMEMH '(' expr ',' idClassSel ')' { $$ = new AstWriteMem($1,$3,$5,NULL,NULL); } + | yD_WRITEMEMH '(' expr ',' idClassSel ',' expr ')' { $$ = new AstWriteMem($1,$3,$5,$7,NULL); } + | yD_WRITEMEMH '(' expr ',' idClassSel ',' expr ',' expr ')' { $$ = new AstWriteMem($1,$3,$5,$7,$9); } + // // Any system function as a task | system_f_call_or_t { $$ = new AstSysFuncAsTask($1, $1); } ; @@ -3122,7 +3134,7 @@ expr: // IEEE: part of expression/constant_expression/primary // // // IEEE: "... hierarchical_identifier select" see below // - // // IEEE: empty_queue + // // IEEE: empty_queue (IEEE 1800-2017 empty_unpacked_array_concatenation) //UNSUP '{' '}' // // // IEEE: concatenation/constant_concatenation diff --git a/test_regress/t/t_dpi_logic_bad.pl b/test_regress/t/t_dpi_logic_bad.pl index 29ff03c2d..69732372e 100755 --- a/test_regress/t/t_dpi_logic_bad.pl +++ b/test_regress/t/t_dpi_logic_bad.pl @@ -11,7 +11,7 @@ compile ( v_flags2 => ["--lint-only"], fails=>$Self->{v3}, expect=> -'%Error: t/t_dpi_logic_bad.v:\d+: DPI function may not return type BASICDTYPE \'logic\' \(IEEE 2012 35.5.5\) +'%Error: t/t_dpi_logic_bad.v:\d+: DPI function may not return type BASICDTYPE \'logic\' \(IEEE 2017 35.5.5\) %Error: Exiting due to .*' ); diff --git a/test_regress/t/t_for_loop.v b/test_regress/t/t_for_loop.v index dd4b4d6d8..8d8c4acc5 100644 --- a/test_regress/t/t_for_loop.v +++ b/test_regress/t/t_for_loop.v @@ -78,6 +78,22 @@ module t (/*AUTOARG*/ if (i !== -1) $stop; if (loops !== 17) $stop; // + // 1800-2017 optionals init/expr/incr + loops = 0; + i = 0; + for (; i<10; ++i) ++loops; + if (loops !== 10) $stop; + // + loops = 0; + i = 0; + for (i=0; i<10; ) begin ++loops; ++i; end + if (loops !== 10) $stop; + // + loops = 0; + i = 0; + for (; ; ++i) begin ++loops; break; end + if (loops !== 1) $stop; + // $write("*-* All Finished *-*\n"); $finish; end diff --git a/test_regress/t/t_foreach.pl b/test_regress/t/t_foreach.pl index f91289753..6b3172aee 100755 --- a/test_regress/t/t_foreach.pl +++ b/test_regress/t/t_foreach.pl @@ -8,11 +8,21 @@ if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); di # Version 2.0. compile ( + verilator_flags2 => ['--assert'] ); execute ( check_finished=>1, ); +# We expect all loops should be unrolled by verilator, +# none of the loop variables should exist in the output: +file_grep_not ("$Self->{obj_dir}/$Self->{VM_PREFIX}.cpp", qr/index_/); + +# Further, we expect that all logic within the loop should +# have been evaluated inside the compiler. So there should be +# no references to 'sum' in the .cpp. +file_grep_not ("$Self->{obj_dir}/$Self->{VM_PREFIX}.cpp", qr/sum/); + ok(1); 1; diff --git a/test_regress/t/t_foreach.v b/test_regress/t/t_foreach.v index 97fe8021e..e6dcc5cfd 100644 --- a/test_regress/t/t_foreach.v +++ b/test_regress/t/t_foreach.v @@ -13,6 +13,7 @@ module t (/*AUTOARG*/); reg [63:0] sum; reg [2:1] [4:3] array [5:6] [7:8]; reg [1:2] [3:4] larray [6:5] [8:7]; + bit [31:0] depth1_array [0:0]; function [63:0] crc (input [63:0] sum, input [31:0] a, input [31:0] b, input [31:0] c, input [31:0] d); crc = {sum[62:0],sum[63]} ^ {4'b0,a[7:0], 4'h0,b[7:0], 4'h0,c[7:0], 4'h0,d[7:0]}; @@ -20,53 +21,68 @@ module t (/*AUTOARG*/); initial begin sum = 0; - foreach (array[a]) begin - sum = crc(sum, a, 0, 0, 0); + // We use 'index_' as the prefix for all loop vars, + // this allows t_foreach.pl to confirm that all loops + // have been unrolled and flattened away and no loop vars + // remain in the generated .cpp + foreach (depth1_array[index_a]) begin + sum = crc(sum, index_a, 0, 0, 0); + + // Ensure the index never goes out of bounds. + // We used to get this wrong for an array of depth 1. + assert (index_a != -1); + assert (index_a != 1); + end + `checkh(sum, 64'h0); + + sum = 0; + foreach (array[index_a]) begin + sum = crc(sum, index_a, 0, 0, 0); end `checkh(sum, 64'h000000c000000000); sum = 0; - foreach (array[a,b]) begin - sum = crc(sum, a, b, 0, 0); + foreach (array[index_a,index_b]) begin + sum = crc(sum, index_a, index_b, 0, 0); end `checkh(sum, 64'h000003601e000000); sum = 0; - foreach (array[a,b,c]) begin - sum = crc(sum, a, b, c, 0); + foreach (array[index_a,index_b,index_c]) begin + sum = crc(sum, index_a, index_b, index_c, 0); end `checkh(sum, 64'h00003123fc101000); sum = 0; - foreach (array[a,b,c,d]) begin - sum = crc(sum, a, b, c, d); + foreach (array[index_a,index_b,index_c,index_d]) begin + sum = crc(sum, index_a, index_b, index_c, index_d); end `checkh(sum, 64'h0030128ab2a8e557); // sum = 0; - foreach (larray[a]) begin - sum = crc(sum, a, 0, 0, 0); + foreach (larray[index_a]) begin + sum = crc(sum, index_a, 0, 0, 0); end `checkh(sum, 64'h0000009000000000); sum = 0; - foreach (larray[a,b]) begin - sum = crc(sum, a, b, 0, 0); - sum = sum + {4'b0,a[7:0], 4'h0,b[7:0]}; + foreach (larray[index_a,index_b]) begin + sum = crc(sum, index_a, index_b, 0, 0); + sum = sum + {4'b0,index_a[7:0], 4'h0,index_b[7:0]}; end `checkh(sum, 64'h000002704b057073); sum = 0; - foreach (larray[a,b,c]) begin - sum = crc(sum, a, b, c, 0); + foreach (larray[index_a,index_b,index_c]) begin + sum = crc(sum, index_a, index_b, index_c, 0); end `checkh(sum, 64'h00002136f9000000); sum = 0; - foreach (larray[a,b,c,d]) begin - sum = crc(sum, a, b, c, d); + foreach (larray[index_a,index_b,index_c,index_d]) begin + sum = crc(sum, index_a, index_b, index_c, index_d); end `checkh(sum, 64'h0020179aa7aa0aaa); diff --git a/test_regress/t/t_lint_pkg_colon_bad.pl b/test_regress/t/t_lint_pkg_colon_bad.pl index decc210b4..862dec3bc 100755 --- a/test_regress/t/t_lint_pkg_colon_bad.pl +++ b/test_regress/t/t_lint_pkg_colon_bad.pl @@ -17,7 +17,7 @@ compile ( make_main => 0, expect=> quotemeta( qq{%Error: t/t_lint_pkg_colon_bad.v:6: syntax error, unexpected ::, expecting ')' or ',' -%Error: t/t_lint_pkg_colon_bad.v:6: Perhaps 'mispkg' is a package which needs to be predeclared? (IEEE 2012 26.3) +%Error: t/t_lint_pkg_colon_bad.v:6: Perhaps 'mispkg' is a package which needs to be predeclared? (IEEE 2017 26.3) %Error: t/t_lint_pkg_colon_bad.v:7: syntax error, unexpected ::, expecting ',' or ';' }).'%Error: Exiting due to.*' ); diff --git a/test_regress/t/t_lint_unsized_bad.pl b/test_regress/t/t_lint_unsized_bad.pl index cd621a77e..f9b683e90 100755 --- a/test_regress/t/t_lint_unsized_bad.pl +++ b/test_regress/t/t_lint_unsized_bad.pl @@ -17,7 +17,7 @@ compile ( make_main => 0, expect=> quotemeta( qq{%Error: t/t_lint_unsized_bad.v:7: Too many digits for 32 bit number: 'd123456789123456789123456789 -%Error: t/t_lint_unsized_bad.v:7: As that number was unsized ('d...) it is limited to 32 bits (IEEE 2012 5.7.1) +%Error: t/t_lint_unsized_bad.v:7: As that number was unsized ('d...) it is limited to 32 bits (IEEE 2017 5.7.1) }).'%Error: Exiting due to.*' ); diff --git a/test_regress/t/t_math_arith.v b/test_regress/t/t_math_arith.v index f39fa0376..b79aeea1a 100644 --- a/test_regress/t/t_math_arith.v +++ b/test_regress/t/t_math_arith.v @@ -129,7 +129,7 @@ module t (/*AUTOARG*/ if (bug764_p11 !== 4'b000x) $stop; if (~& bug764_p11 !== 1'b1) $stop; //verilator lint_on WIDTH - // However IEEE says for constants in 2012 5.7.1 that smaller-sizes do extend + // However IEEE 2017 5.7.1 says for constants that smaller-sizes do extend if (4'bx !== 4'bxxxx) $stop; if (4'bz !== 4'bzzzz) $stop; if (4'b1 !== 4'b0001) $stop; diff --git a/test_regress/t/t_optm_redor.pl b/test_regress/t/t_optm_redor.pl new file mode 100755 index 000000000..c39ed396f --- /dev/null +++ b/test_regress/t/t_optm_redor.pl @@ -0,0 +1,20 @@ +#!/usr/bin/perl +if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; } +# DESCRIPTION: Verilator: Verilog Test driver/expect definition +# +# Copyright 2003 by Wilson Snyder. This program is free software; you can +# redistribute it and/or modify it under the terms of either the GNU +# Lesser General Public License Version 3 or the Perl Artistic License +# Version 2.0. + +compile ( + ); + +execute ( + check_finished=>1, + ); + +file_grep_not ("$Self->{obj_dir}/$Self->{VM_PREFIX}.cpp", qr/rstn_r/); + +ok(1); +1; diff --git a/test_regress/t/t_optm_redor.v b/test_regress/t/t_optm_redor.v new file mode 100644 index 000000000..b82e58b13 --- /dev/null +++ b/test_regress/t/t_optm_redor.v @@ -0,0 +1,83 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed into the Public Domain, for any use, +// without warranty, 2017 by Wilson Snyder. + +module t (/*AUTOARG*/ + // Inputs + clk + ); + input clk; + + integer cyc=0; + reg [63:0] crc; + reg [63:0] sum; + + // Take CRC data and apply to testblock inputs + wire [15:0] in = crc[15:0]; + + /*AUTOWIRE*/ + // Beginning of automatic wires (for undeclared instantiated-module outputs) + wire out; // From test of Test.v + // End of automatics + + Test test (/*AUTOINST*/ + // Outputs + .out (out), + // Inputs + .in (in[15:0])); + + // Aggregate outputs into a single result vector + wire [63:0] result = {63'h0, out}; + + // Test loop + always @ (posedge clk) begin +`ifdef TEST_VERBOSE + $write("[%0t] cyc==%0d crc=%x result=%x\n",$time, cyc, crc, result); +`endif + cyc <= cyc + 1; + crc <= {crc[62:0], crc[63]^crc[2]^crc[0]}; + sum <= result ^ {sum[62:0],sum[63]^sum[2]^sum[0]}; + if (cyc==0) begin + // Setup + crc <= 64'h5aef0c8d_d70a4497; + sum <= '0; + end + else if (cyc<10) begin + sum <= '0; + end + else if (cyc<90) begin + end + else if (cyc==99) begin + $write("[%0t] cyc==%0d crc=%x sum=%x\n",$time, cyc, crc, sum); + if (crc !== 64'hc77bb9b3784ea091) $stop; + // What checksum will we end up with (above print should match) +`define EXPECTED_SUM 64'h162c58b1635b8d6e + if (sum !== `EXPECTED_SUM) $stop; + $write("*-* All Finished *-*\n"); + $finish; + end + end + +endmodule + +module Test (/*AUTOARG*/ + // Outputs + out, + // Inputs + in + ); + + input [15:0] in; + output reg out; + + // TODO this should flatten into a reduction OR + always_comb begin + out = 0; + for (int i=0; i<16; i=i+1) begin + if (in[i]) begin + out = 1; + end + end + end +endmodule diff --git a/test_regress/t/t_preproc_kwd.v b/test_regress/t/t_preproc_kwd.v index 85fb878e1..f62e5124e 100644 --- a/test_regress/t/t_preproc_kwd.v +++ b/test_regress/t/t_preproc_kwd.v @@ -14,8 +14,10 @@ module t (/*AUTOARG*/ v05 v05 (); s05 s05 (); s09 s09 (); - a23 a23 (); s12 s12 (); + s17 s17 (); + + a23 a23 (); initial begin $finish; @@ -60,6 +62,14 @@ module s12; endmodule `end_keywords +`begin_keywords "1800-2017" +module s17; + final begin + $write("*-* All Finished *-*\n"); + end +endmodule +`end_keywords + `begin_keywords "VAMS-2.3" module a23; real foo; initial foo = sqrt(2.0); diff --git a/test_regress/t/t_sys_readmem.v b/test_regress/t/t_sys_readmem.v index 1f0f58be9..66d1a7936 100644 --- a/test_regress/t/t_sys_readmem.v +++ b/test_regress/t/t_sys_readmem.v @@ -10,14 +10,59 @@ module t; reg [5:0] binary_nostart [2:15]; reg [5:0] binary_start [0:15]; reg [175:0] hex [0:15]; + reg [(32*6)-1:0] hex_align [0:15]; + string fns; + +`ifdef WRITEMEM_READ_BACK + reg [5:0] binary_string_tmp [2:15]; + reg [5:0] binary_nostart_tmp [2:15]; + reg [5:0] binary_start_tmp [0:15]; + reg [175:0] hex_tmp [0:15]; + reg [(32*6)-1:0] hex_align_tmp [0:15]; + string fns_tmp; +`endif // verilator lint_on LITENDIAN integer i; initial begin + begin + // Initialize memories to zero, + // avoid differences between 2-state and 4-state. + for (i=0; i<16; i=i+1) begin + binary_start[i] = 6'h0; + hex[i] = 176'h0; + hex_align[i] = {32*6{1'b0}}; +`ifdef WRITEMEM_READ_BACK + binary_start_tmp[i] = 6'h0; + hex_tmp[i] = 176'h0; + hex_align_tmp[i] = {32*6{1'b0}}; +`endif + end + for (i=2; i<16; i=i+1) begin + binary_string[i] = 6'h0; + binary_nostart[i] = 6'h0; +`ifdef WRITEMEM_READ_BACK + binary_string_tmp[i] = 6'h0; + binary_nostart_tmp[i] = 6'h0; +`endif + end + end begin +`ifdef WRITEMEM_READ_BACK + $readmemb("t/t_sys_readmem_b.mem", binary_nostart_tmp); + // Do a round-trip $writememh and $readmemh cycle. + // This covers $writememh and ensures we can read our + // own memh output file. + `ifdef TEST_VERBOSE + $display("-Writing %s", `OUT_TMP1); + `endif + $writememh(`OUT_TMP1, binary_nostart_tmp); + $readmemh(`OUT_TMP1, binary_nostart); +`else $readmemb("t/t_sys_readmem_b.mem", binary_nostart); +`endif `ifdef TEST_VERBOSE for (i=0; i<16; i=i+1) $write(" @%x = %x\n", i, binary_nostart[i]); `endif @@ -33,7 +78,16 @@ module t; end begin +`ifdef WRITEMEM_READ_BACK + $readmemb("t/t_sys_readmem_b_8.mem", binary_start_tmp, 4, 4+7); + `ifdef TEST_VERBOSE + $display("-Writing %s", `OUT_TMP2); + `endif + $writememh(`OUT_TMP2, binary_start_tmp, 4, 4+7); + $readmemh(`OUT_TMP2, binary_start, 4, 4+7); +`else $readmemb("t/t_sys_readmem_b_8.mem", binary_start, 4, 4+7); +`endif `ifdef TEST_VERBOSE for (i=0; i<16; i=i+1) $write(" @%x = %x\n", i, binary_start[i]); `endif @@ -48,7 +102,18 @@ module t; end begin + // The 'hex' array is a non-exact multiple of word size + // (possible corner case) +`ifdef WRITEMEM_READ_BACK + $readmemh("t/t_sys_readmem_h.mem", hex_tmp, 0); + `ifdef TEST_VERBOSE + $display("-Writing %s", `OUT_TMP3); + `endif + $writememh(`OUT_TMP3, hex_tmp, 0); + $readmemh(`OUT_TMP3, hex, 0); +`else $readmemh("t/t_sys_readmem_h.mem", hex, 0); +`endif `ifdef TEST_VERBOSE for (i=0; i<16; i=i+1) $write(" @%x = %x\n", i, hex[i]); `endif @@ -59,8 +124,40 @@ module t; end begin - string fns = "t/t_sys_readmem_b.mem"; + // The 'hex align' array is similar to 'hex', but it is an + // exact multiple of word size -- another possible corner case. +`ifdef WRITEMEM_READ_BACK + $readmemh("t/t_sys_readmem_align_h.mem", hex_align_tmp, 0); + `ifdef TEST_VERBOSE + $display("-Writing %s", `OUT_TMP4); + `endif + $writememh(`OUT_TMP4, hex_align_tmp, 0); + $readmemh(`OUT_TMP4, hex_align, 0); +`else + $readmemh("t/t_sys_readmem_align_h.mem", hex_align, 0); +`endif +`ifdef TEST_VERBOSE + for (i=0; i<16; i=i+1) $write(" @%x = %x\n", i, hex_align[i]); +`endif + if (hex_align['h04] != 192'h77554004_37654321_27654321_17654321_07654321_abcdef10) $stop; + if (hex_align['h0a] != 192'h7755400a_37654321_27654321_17654321_07654321_abcdef11) $stop; + if (hex_align['h0b] != 192'h7755400b_37654321_27654321_17654321_07654321_abcdef12) $stop; + if (hex_align['h0c] != 192'h7755400c_37654321_27654321_17654321_07654321_abcdef13) $stop; + end + + begin + fns = "t/t_sys_readmem_b.mem"; +`ifdef WRITEMEM_READ_BACK + fns_tmp = `OUT_TMP5; + $readmemb(fns, binary_string_tmp); + `ifdef TEST_VERBOSE + $display("-Writing %s", `OUT_TMP5); + `endif + $writememh(fns_tmp, binary_string_tmp); + $readmemh(fns_tmp, binary_string); +`else $readmemb(fns, binary_string); +`endif `ifdef TEST_VERBOSE for (i=0; i<16; i=i+1) $write(" @%x = %x\n", i, binary_string[i]); `endif diff --git a/test_regress/t/t_sys_readmem_align_h.mem b/test_regress/t/t_sys_readmem_align_h.mem new file mode 100644 index 000000000..b23a4b92b --- /dev/null +++ b/test_regress/t/t_sys_readmem_align_h.mem @@ -0,0 +1,13 @@ +// DESCRIPTION: Verilator: Verilog Test data file +// +// Copyright 2006 by Wilson Snyder. This program is free software; you can +// redistribute it and/or modify it under the terms of either the GNU +// Lesser General Public License Version 3 or the Perl Artistic License +// Version 2.0. + +@4 +77554004_37654321_27654321_17654321_07654321_abcdef10 +@a +7755400a_37654321_27654321_17654321_07654321_abcdef11 +7755400b_37654321_27654321_17654321_07654321_abcdef12 +7755400c_37654321_27654321_17654321_07654321_abcdef13 diff --git a/test_regress/t/t_sys_writemem.gold1.mem b/test_regress/t/t_sys_writemem.gold1.mem new file mode 100644 index 000000000..b25ae23ef --- /dev/null +++ b/test_regress/t/t_sys_writemem.gold1.mem @@ -0,0 +1,14 @@ +02 +03 +04 +05 +06 +07 +10 +00 +00 +00 +14 +15 +00 +00 diff --git a/test_regress/t/t_sys_writemem.gold2.mem b/test_regress/t/t_sys_writemem.gold2.mem new file mode 100644 index 000000000..a1d3db086 --- /dev/null +++ b/test_regress/t/t_sys_writemem.gold2.mem @@ -0,0 +1,8 @@ +10 +11 +12 +13 +14 +15 +16 +17 diff --git a/test_regress/t/t_sys_writemem.gold3.mem b/test_regress/t/t_sys_writemem.gold3.mem new file mode 100644 index 000000000..86f3c0631 --- /dev/null +++ b/test_regress/t/t_sys_writemem.gold3.mem @@ -0,0 +1,16 @@ +00000000000000000000000000000000000000000000 +00000000000000000000000000000000000000000000 +00000000000000000000000000000000000000000000 +00000000000000000000000000000000000000000000 +400437654321276543211765432107654321abcdef10 +00000000000000000000000000000000000000000000 +00000000000000000000000000000000000000000000 +00000000000000000000000000000000000000000000 +00000000000000000000000000000000000000000000 +00000000000000000000000000000000000000000000 +400a37654321276543211765432107654321abcdef11 +400b37654321276543211765432107654321abcdef12 +400c37654321276543211765432107654321abcdef13 +00000000000000000000000000000000000000000000 +00000000000000000000000000000000000000000000 +00000000000000000000000000000000000000000000 diff --git a/test_regress/t/t_sys_writemem.gold4.mem b/test_regress/t/t_sys_writemem.gold4.mem new file mode 100644 index 000000000..3e397a9d0 --- /dev/null +++ b/test_regress/t/t_sys_writemem.gold4.mem @@ -0,0 +1,16 @@ +000000000000000000000000000000000000000000000000 +000000000000000000000000000000000000000000000000 +000000000000000000000000000000000000000000000000 +000000000000000000000000000000000000000000000000 +7755400437654321276543211765432107654321abcdef10 +000000000000000000000000000000000000000000000000 +000000000000000000000000000000000000000000000000 +000000000000000000000000000000000000000000000000 +000000000000000000000000000000000000000000000000 +000000000000000000000000000000000000000000000000 +7755400a37654321276543211765432107654321abcdef11 +7755400b37654321276543211765432107654321abcdef12 +7755400c37654321276543211765432107654321abcdef13 +000000000000000000000000000000000000000000000000 +000000000000000000000000000000000000000000000000 +000000000000000000000000000000000000000000000000 diff --git a/test_regress/t/t_sys_writemem.gold5.mem b/test_regress/t/t_sys_writemem.gold5.mem new file mode 100644 index 000000000..b25ae23ef --- /dev/null +++ b/test_regress/t/t_sys_writemem.gold5.mem @@ -0,0 +1,14 @@ +02 +03 +04 +05 +06 +07 +10 +00 +00 +00 +14 +15 +00 +00 diff --git a/test_regress/t/t_sys_writemem.pl b/test_regress/t/t_sys_writemem.pl new file mode 100755 index 000000000..523a44835 --- /dev/null +++ b/test_regress/t/t_sys_writemem.pl @@ -0,0 +1,41 @@ +#!/usr/bin/perl +if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; } +# DESCRIPTION: Verilator: Verilog Test driver/expect definition +# +# Copyright 2003 by Wilson Snyder. This program is free software; you can +# redistribute it and/or modify it under the terms of either the GNU +# Lesser General Public License Version 3 or the Perl Artistic License +# Version 2.0. + +top_filename("t/t_sys_readmem.v"); + +# Use random reset to ensure we're fully initializing arrays before +# $writememh, to avoid miscompares with X's on 4-state simulators. +$Self->{verilated_randReset} = 2; # 2 == truly random + +compile(v_flags2 => [ + "+define+WRITEMEM_READ_BACK=1", + "+define+OUT_TMP1=\\\"$Self->{obj_dir}/tmp1.mem\\\"", + "+define+OUT_TMP2=\\\"$Self->{obj_dir}/tmp2.mem\\\"", + "+define+OUT_TMP3=\\\"$Self->{obj_dir}/tmp3.mem\\\"", + "+define+OUT_TMP4=\\\"$Self->{obj_dir}/tmp4.mem\\\"", + "+define+OUT_TMP5=\\\"$Self->{obj_dir}/tmp5.mem\\\"", + ]); + +execute ( + check_finished=>1, + ); + +for (my $i = 1; $i <= 5; $i++) { + my $gold = "$Self->{t_dir}/t_sys_writemem.gold${i}.mem"; + my $out = "$Self->{obj_dir}/tmp${i}.mem"; + print "> diff $gold $out\n"; + my @diffs = `diff $gold $out`; + if (0 < scalar @diffs) { + print @diffs; + $Self->error("Got unexpected diffs against gold."); + } +} + +ok(1); +1; diff --git a/test_regress/t/t_xml_first.out b/test_regress/t/t_xml_first.out index 4548b237c..a8c29db29 100644 --- a/test_regress/t/t_xml_first.out +++ b/test_regress/t/t_xml_first.out @@ -2,11 +2,11 @@ - - - - - + + + + + diff --git a/test_regress/t/t_xml_tag.out b/test_regress/t/t_xml_tag.out index 0bde73392..0edec2e4a 100644 --- a/test_regress/t/t_xml_tag.out +++ b/test_regress/t/t_xml_tag.out @@ -2,11 +2,11 @@ - - - - - + + + + +