diff --git a/Changes b/Changes index bda43c901..36d045c6d 100644 --- a/Changes +++ b/Changes @@ -10,6 +10,8 @@ The contributors that suggested a given feature are shown in []. Thanks! *** 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] **** On convergence errors, show activity. [John Coiner] 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/src/V3AstNodes.h b/src/V3AstNodes.h index c6b19f6f7..cffc5d07b 100644 --- a/src/V3AstNodes.h +++ b/src/V3AstNodes.h @@ -2773,17 +2773,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; } @@ -2791,12 +2790,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 9ee1e6239..a048ea89e 100644 --- a/src/V3EmitC.cpp +++ b/src/V3EmitC.cpp @@ -322,8 +322,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"); @@ -333,21 +333,26 @@ public: uint32_t array_lsb = 0; { AstVarRef* varrefp = nodep->memp()->castVarRef(); - if (!varrefp) { nodep->v3error("Readmem loading non-variable"); } + if (!varrefp) { + nodep->v3error(nodep->verilogKwd() << " loading non-variable"); + } else if (AstUnpackArrayDType* adtypep = varrefp->varp()->dtypeSkipRefp()->castUnpackArrayDType()) { 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 117eac41d..4b257f1b7 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/V3Width.cpp b/src/V3Width.cpp index 522ca4b48..5a2227965 100644 --- a/src/V3Width.cpp +++ b/src/V3Width.cpp @@ -2204,12 +2204,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 (!nodep->memp()->dtypep()->skipRefp()->castUnpackArrayDType()) { - 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 67a423332..dc2ff7fca 100644 --- a/src/verilog.l +++ b/src/verilog.l @@ -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; } diff --git a/src/verilog.y b/src/verilog.y index 8bf478df9..3b76f6fdc 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*/" @@ -2700,6 +2701,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); } ; 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;