From 04c96694e6f66f9a2afa179420d6ff98d40556f7 Mon Sep 17 00:00:00 2001 From: Fan Shupei Date: Thu, 2 Jul 2020 05:32:15 +0800 Subject: [PATCH] Add $writememb support (#2450) --- docs/CONTRIBUTORS | 1 + include/verilated.cpp | 68 +++++++++++++++++------ include/verilated_heavy.h | 1 + src/V3AstNodes.h | 5 +- src/verilog.l | 1 + src/verilog.y | 10 +++- test_regress/t/t_sys_readmem.v | 32 +++++++---- test_regress/t/t_sys_writemem_b.gold1.mem | 14 +++++ test_regress/t/t_sys_writemem_b.gold2.mem | 8 +++ test_regress/t/t_sys_writemem_b.gold3.mem | 16 ++++++ test_regress/t/t_sys_writemem_b.gold4.mem | 16 ++++++ test_regress/t/t_sys_writemem_b.gold5.mem | 14 +++++ test_regress/t/t_sys_writemem_b.pl | 40 +++++++++++++ 13 files changed, 192 insertions(+), 34 deletions(-) create mode 100644 test_regress/t/t_sys_writemem_b.gold1.mem create mode 100644 test_regress/t/t_sys_writemem_b.gold2.mem create mode 100644 test_regress/t/t_sys_writemem_b.gold3.mem create mode 100644 test_regress/t/t_sys_writemem_b.gold4.mem create mode 100644 test_regress/t/t_sys_writemem_b.gold5.mem create mode 100755 test_regress/t/t_sys_writemem_b.pl diff --git a/docs/CONTRIBUTORS b/docs/CONTRIBUTORS index 397daf3b0..cc00fe3a1 100644 --- a/docs/CONTRIBUTORS +++ b/docs/CONTRIBUTORS @@ -12,6 +12,7 @@ David Horton David Stanford Driss Hafdi Eric Rippey +Fan Shupei Garrett Smith Geza Lore Gianfranco Costamagna diff --git a/include/verilated.cpp b/include/verilated.cpp index c28ac450c..72f3e97c9 100644 --- a/include/verilated.cpp +++ b/include/verilated.cpp @@ -1707,7 +1707,7 @@ const char* vl_dumpctl_filenamep(bool setit, const std::string& filename) VL_MT_ static const char* memhFormat(int nBits) { assert((nBits >= 1) && (nBits <= 32)); - static char buf[32]; + static VL_THREAD_LOCAL char buf[32]; switch ((nBits - 1) / 4) { case 0: VL_SNPRINTF(buf, 32, "%%01x"); break; case 1: VL_SNPRINTF(buf, 32, "%%02x"); break; @@ -1722,6 +1722,18 @@ static const char* memhFormat(int nBits) { return buf; } +static const char* formatBinary(int nBits, vluint32_t bits) { + assert((nBits >= 1) && (nBits <= 32)); + + static VL_THREAD_LOCAL char buf[64]; + for (int i = 0; i < nBits; i++) { + bool isOne = bits & (1 << (nBits - 1 - i)); + buf[i] = (isOne ? '1' : '0'); + } + buf[nBits] = '\0'; + return buf; +} + VlReadMem::VlReadMem(bool hex, int bits, const std::string& filename, QData start, QData end) : m_hex(hex) , m_bits(bits) @@ -1859,14 +1871,9 @@ void VlReadMem::setData(void* valuep, const std::string& rhs) { } VlWriteMem::VlWriteMem(bool hex, int bits, const std::string& filename, QData start, QData end) - : m_bits(bits) + : m_hex(hex) + , m_bits(bits) , m_addr(0) { - if (VL_UNLIKELY(!hex)) { - VL_FATAL_MT(filename.c_str(), 0, "", - "Unsupported: $writemem binary format (suggest hex format)"); - return; - } - if (VL_UNLIKELY(start > end)) { VL_FATAL_MT(filename.c_str(), 0, "", "$writemem invalid address range"); return; @@ -1893,23 +1900,40 @@ void VlWriteMem::print(QData addr, bool addrstamp, const void* valuep) { m_addr = addr + 1; if (m_bits <= 8) { const CData* datap = reinterpret_cast(valuep); - fprintf(m_fp, memhFormat(m_bits), VL_MASK_I(m_bits) & *datap); - fprintf(m_fp, "\n"); + if (m_hex) { + fprintf(m_fp, memhFormat(m_bits), VL_MASK_I(m_bits) & *datap); + fprintf(m_fp, "\n"); + } else { + fprintf(m_fp, "%s\n", formatBinary(m_bits, *datap)); + } } else if (m_bits <= 16) { const SData* datap = reinterpret_cast(valuep); - fprintf(m_fp, memhFormat(m_bits), VL_MASK_I(m_bits) & *datap); - fprintf(m_fp, "\n"); + if (m_hex) { + fprintf(m_fp, memhFormat(m_bits), VL_MASK_I(m_bits) & *datap); + fprintf(m_fp, "\n"); + } else { + fprintf(m_fp, "%s\n", formatBinary(m_bits, *datap)); + } } else if (m_bits <= 32) { const IData* datap = reinterpret_cast(valuep); - fprintf(m_fp, memhFormat(m_bits), VL_MASK_I(m_bits) & *datap); - fprintf(m_fp, "\n"); + if (m_hex) { + fprintf(m_fp, memhFormat(m_bits), VL_MASK_I(m_bits) & *datap); + fprintf(m_fp, "\n"); + } else { + fprintf(m_fp, "%s\n", formatBinary(m_bits, *datap)); + } } else if (m_bits <= 64) { const QData* datap = reinterpret_cast(valuep); vluint64_t value = VL_MASK_Q(m_bits) & *datap; vluint32_t lo = value & 0xffffffff; vluint32_t hi = value >> 32; - fprintf(m_fp, memhFormat(m_bits - 32), hi); - fprintf(m_fp, "%08x\n", lo); + if (m_hex) { + fprintf(m_fp, memhFormat(m_bits - 32), hi); + fprintf(m_fp, "%08x\n", lo); + } else { + fprintf(m_fp, "%s", formatBinary(m_bits - 32, hi)); + fprintf(m_fp, "%s\n", formatBinary(32, lo)); + } } else { WDataInP datap = reinterpret_cast(valuep); // output as a sequence of VL_EDATASIZE'd words @@ -1922,9 +1946,17 @@ void VlWriteMem::print(QData addr, bool addrstamp, const void* valuep) { if (first) { data &= VL_MASK_E(m_bits); int top_word_nbits = VL_BITBIT_E(m_bits - 1) + 1; - fprintf(m_fp, memhFormat(top_word_nbits), data); + if (m_hex) { + fprintf(m_fp, memhFormat(top_word_nbits), data); + } else { + fprintf(m_fp, "%s", formatBinary(top_word_nbits, data)); + } } else { - fprintf(m_fp, "%08x", data); + if (m_hex) { + fprintf(m_fp, "%08x", data); + } else { + fprintf(m_fp, "%s", formatBinary(32, data)); + } } word_idx--; first = false; diff --git a/include/verilated_heavy.h b/include/verilated_heavy.h index 03df61629..2241bf8d1 100644 --- a/include/verilated_heavy.h +++ b/include/verilated_heavy.h @@ -62,6 +62,7 @@ public: }; class VlWriteMem { + bool m_hex; // Hex format int m_bits; // Bit width of values FILE* m_fp; // File handle for filename QData m_addr; // Next address to write diff --git a/src/V3AstNodes.h b/src/V3AstNodes.h index bea5bd1dd..d20cd79e4 100644 --- a/src/V3AstNodes.h +++ b/src/V3AstNodes.h @@ -4153,8 +4153,9 @@ public: class AstWriteMem : public AstNodeReadWriteMem { public: - AstWriteMem(FileLine* fl, AstNode* filenamep, AstNode* memp, AstNode* lsbp, AstNode* msbp) - : ASTGEN_SUPER(fl, true, filenamep, memp, lsbp, msbp) {} + AstWriteMem(FileLine* fl, bool hex, AstNode* filenamep, AstNode* memp, AstNode* lsbp, + AstNode* msbp) + : ASTGEN_SUPER(fl, hex, filenamep, memp, lsbp, msbp) {} ASTNODE_NODE_FUNCS(WriteMem) virtual string verilogKwd() const { return (isHex() ? "$writememh" : "$writememb"); } virtual const char* cFuncPrefixp() const { return "VL_WRITEMEM_"; } diff --git a/src/verilog.l b/src/verilog.l index f69f896ff..c309be3fd 100644 --- a/src/verilog.l +++ b/src/verilog.l @@ -265,6 +265,7 @@ vnum {vnum1}|{vnum2}|{vnum3}|{vnum4}|{vnum5} "$writeb" { FL; return yD_WRITEB; } "$writeh" { FL; return yD_WRITEH; } "$writeo" { FL; return yD_WRITEO; } + "$writememb" { FL; return yD_WRITEMEMB; } "$writememh" { FL; return yD_WRITEMEMH; } /* Keywords */ "always" { FL; return yALWAYS; } diff --git a/src/verilog.y b/src/verilog.y index 750f8b17a..ceb54f11c 100644 --- a/src/verilog.y +++ b/src/verilog.y @@ -801,6 +801,7 @@ class AstSenTree; %token yD_WRITE "$write" %token yD_WRITEB "$writeb" %token yD_WRITEH "$writeh" +%token yD_WRITEMEMB "$writememb" %token yD_WRITEMEMH "$writememh" %token yD_WRITEO "$writeo" @@ -3554,9 +3555,12 @@ 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); } + | yD_WRITEMEMB '(' expr ',' idClassSel ')' { $$ = new AstWriteMem($1, false, $3, $5, NULL, NULL); } + | yD_WRITEMEMB '(' expr ',' idClassSel ',' expr ')' { $$ = new AstWriteMem($1, false, $3, $5, $7, NULL); } + | yD_WRITEMEMB '(' expr ',' idClassSel ',' expr ',' expr ')' { $$ = new AstWriteMem($1, false, $3, $5, $7, $9); } + | yD_WRITEMEMH '(' expr ',' idClassSel ')' { $$ = new AstWriteMem($1, true, $3, $5, NULL, NULL); } + | yD_WRITEMEMH '(' expr ',' idClassSel ',' expr ')' { $$ = new AstWriteMem($1, true, $3, $5, $7, NULL); } + | yD_WRITEMEMH '(' expr ',' idClassSel ',' expr ',' expr ')' { $$ = new AstWriteMem($1, true, $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 d128dfb4e..ca79d8b0c 100644 --- a/test_regress/t/t_sys_readmem.v +++ b/test_regress/t/t_sys_readmem.v @@ -4,6 +4,14 @@ // any use, without warranty, 2003 by Wilson Snyder. // SPDX-License-Identifier: CC0-1.0 +`ifdef WRITEMEM_BIN + `define READMEMX $readmemb + `define WRITEMEMX $writememb +`else + `define READMEMX $readmemh + `define WRITEMEMX $writememh +`endif + module t; // verilator lint_off LITENDIAN @@ -53,14 +61,16 @@ module t; begin `ifdef WRITEMEM_READ_BACK $readmemb("t/t_sys_readmem_b.mem", binary_nostart_tmp); - // Do a round-trip $writememh and $readmemh cycle. + // Do a round-trip $writememh(b) and $readmemh(b) cycle. // This covers $writememh and ensures we can read our // own memh output file. + // If WRITEMEM_BIN is also defined, use $writememb and + // $readmemb, otherwise use $writememh and $readmemh. `ifdef TEST_VERBOSE $display("-Writing %s", `OUT_TMP1); `endif - $writememh(`OUT_TMP1, binary_nostart_tmp); - $readmemh(`OUT_TMP1, binary_nostart); + `WRITEMEMX(`OUT_TMP1, binary_nostart_tmp); + `READMEMX(`OUT_TMP1, binary_nostart); `else $readmemb("t/t_sys_readmem_b.mem", binary_nostart); `endif @@ -86,8 +96,8 @@ module t; `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); + `WRITEMEMX(`OUT_TMP2, binary_start_tmp, 4, 4+7); + `READMEMX(`OUT_TMP2, binary_start, 4, 4+7); `else $readmemb("t/t_sys_readmem_b_8.mem", binary_start, 4, 4+7); // 4-11 `endif @@ -114,8 +124,8 @@ module t; `ifdef TEST_VERBOSE $display("-Writing %s", `OUT_TMP3); `endif - $writememh(`OUT_TMP3, hex_tmp, 0); - $readmemh(`OUT_TMP3, hex, 0); + `WRITEMEMX(`OUT_TMP3, hex_tmp, 0); + `READMEMX(`OUT_TMP3, hex, 0); `else $readmemh("t/t_sys_readmem_h.mem", hex, 0); `endif @@ -136,8 +146,8 @@ module t; `ifdef TEST_VERBOSE $display("-Writing %s", `OUT_TMP4); `endif - $writememh(`OUT_TMP4, hex_align_tmp, 0); - $readmemh(`OUT_TMP4, hex_align, 0); + `WRITEMEMX(`OUT_TMP4, hex_align_tmp, 0); + `READMEMX(`OUT_TMP4, hex_align, 0); `else $readmemh("t/t_sys_readmem_align_h.mem", hex_align, 0); `endif @@ -158,8 +168,8 @@ module t; `ifdef TEST_VERBOSE $display("-Writing %s", `OUT_TMP5); `endif - $writememh(fns_tmp, binary_string_tmp); - $readmemh(fns_tmp, binary_string); + `WRITEMEMX(fns_tmp, binary_string_tmp); + `READMEMX(fns_tmp, binary_string); `else $readmemb(fns, binary_string); `endif diff --git a/test_regress/t/t_sys_writemem_b.gold1.mem b/test_regress/t/t_sys_writemem_b.gold1.mem new file mode 100644 index 000000000..6e4fbbfe0 --- /dev/null +++ b/test_regress/t/t_sys_writemem_b.gold1.mem @@ -0,0 +1,14 @@ +000010 +000011 +000100 +000101 +000110 +000111 +010000 +000000 +000000 +000000 +010100 +010101 +000000 +000000 diff --git a/test_regress/t/t_sys_writemem_b.gold2.mem b/test_regress/t/t_sys_writemem_b.gold2.mem new file mode 100644 index 000000000..490b61837 --- /dev/null +++ b/test_regress/t/t_sys_writemem_b.gold2.mem @@ -0,0 +1,8 @@ +010000 +010001 +010010 +010011 +010100 +010101 +010110 +010111 diff --git a/test_regress/t/t_sys_writemem_b.gold3.mem b/test_regress/t/t_sys_writemem_b.gold3.mem new file mode 100644 index 000000000..d83d7279c --- /dev/null +++ b/test_regress/t/t_sys_writemem_b.gold3.mem @@ -0,0 +1,16 @@ +00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +01000000000001000011011101100101010000110010000100100111011001010100001100100001000101110110010101000011001000010000011101100101010000110010000110101011110011011110111100010000 +00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +01000000000010100011011101100101010000110010000100100111011001010100001100100001000101110110010101000011001000010000011101100101010000110010000110101011110011011110111100010001 +01000000000010110011011101100101010000110010000100100111011001010100001100100001000101110110010101000011001000010000011101100101010000110010000110101011110011011110111100010010 +01000000000011000011011101100101010000110010000100100111011001010100001100100001000101110110010101000011001000010000011101100101010000110010000110101011110011011110111100010011 +00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 diff --git a/test_regress/t/t_sys_writemem_b.gold4.mem b/test_regress/t/t_sys_writemem_b.gold4.mem new file mode 100644 index 000000000..3bc80dcf3 --- /dev/null +++ b/test_regress/t/t_sys_writemem_b.gold4.mem @@ -0,0 +1,16 @@ +000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +011101110101010101000000000001000011011101100101010000110010000100100111011001010100001100100001000101110110010101000011001000010000011101100101010000110010000110101011110011011110111100010000 +000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +011101110101010101000000000010100011011101100101010000110010000100100111011001010100001100100001000101110110010101000011001000010000011101100101010000110010000110101011110011011110111100010001 +011101110101010101000000000010110011011101100101010000110010000100100111011001010100001100100001000101110110010101000011001000010000011101100101010000110010000110101011110011011110111100010010 +011101110101010101000000000011000011011101100101010000110010000100100111011001010100001100100001000101110110010101000011001000010000011101100101010000110010000110101011110011011110111100010011 +000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 diff --git a/test_regress/t/t_sys_writemem_b.gold5.mem b/test_regress/t/t_sys_writemem_b.gold5.mem new file mode 100644 index 000000000..6e4fbbfe0 --- /dev/null +++ b/test_regress/t/t_sys_writemem_b.gold5.mem @@ -0,0 +1,14 @@ +000010 +000011 +000100 +000101 +000110 +000111 +010000 +000000 +000000 +000000 +010100 +010101 +000000 +000000 diff --git a/test_regress/t/t_sys_writemem_b.pl b/test_regress/t/t_sys_writemem_b.pl new file mode 100755 index 000000000..c5b47759f --- /dev/null +++ b/test_regress/t/t_sys_writemem_b.pl @@ -0,0 +1,40 @@ +#!/usr/bin/env 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. +# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0 + +scenarios(simulator => 1); + +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+WRITEMEM_BIN=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_b.gold${i}.mem"; + my $out = "$Self->{obj_dir}/tmp${i}.mem"; + files_identical($out, $gold); +} + +ok(1); +1;