From 34870e899f46947bfc2a125ee0eb6e69329abd68 Mon Sep 17 00:00:00 2001 From: Todd Strader Date: Thu, 24 Sep 2015 21:08:58 -0400 Subject: [PATCH] Add VerilatedScopeNameMap for introspection, bug966. Signed-off-by: Wilson Snyder --- Changes | 2 + include/verilated.cpp | 4 + include/verilated.h | 3 + include/verilated_imp.h | 14 +-- include/verilated_syms.h | 24 ++--- test_regress/t/t_scope_map.cpp | 160 +++++++++++++++++++++++++++++++++ test_regress/t/t_scope_map.pl | 23 +++++ test_regress/t/t_scope_map.v | 66 ++++++++++++++ 8 files changed, 280 insertions(+), 16 deletions(-) create mode 100644 test_regress/t/t_scope_map.cpp create mode 100755 test_regress/t/t_scope_map.pl create mode 100644 test_regress/t/t_scope_map.v diff --git a/Changes b/Changes index 02aefa713..214fb5321 100644 --- a/Changes +++ b/Changes @@ -5,6 +5,8 @@ indicates the contributor was also the author of the fix; Thanks! * Verilator 3.877 devel +**** Add VerilatedScopeNameMap for introspection, bug966. [Todd Strader] + **** Fix very long module names, bug937. [Todd Strader] **** Fix internal error on dotted refs into generates, bug958. [Jie Xu] diff --git a/include/verilated.cpp b/include/verilated.cpp index 11e098c92..fb3583ce0 100644 --- a/include/verilated.cpp +++ b/include/verilated.cpp @@ -1170,6 +1170,10 @@ int Verilated::exportFuncNum(const char* namep) { return VerilatedImp::exportFind(namep); } +const VerilatedScopeNameMap* Verilated::scopeNameMap() { + return VerilatedImp::scopeNameMap(); +} + //=========================================================================== // VerilatedModule:: Methods diff --git a/include/verilated.h b/include/verilated.h index 705651dc6..52d4e0976 100644 --- a/include/verilated.h +++ b/include/verilated.h @@ -38,6 +38,7 @@ #include #include // avoided to reduce compile time +// avoided and instead in verilated_heavy.h to reduce compile time // avoided and instead in verilated_heavy.h to reduce compile time using namespace std; @@ -68,6 +69,7 @@ typedef void (*VerilatedVoidCb)(void); class SpTraceVcd; class SpTraceVcdCFile; +class VerilatedScopeNameMap; class VerilatedVar; class VerilatedVarNameMap; class VerilatedVcd; @@ -308,6 +310,7 @@ public: static const char* catName(const char* n1, const char* n2); // Returns new'ed data // Internal: Find scope static const VerilatedScope* scopeFind(const char* namep); + static const VerilatedScopeNameMap* scopeNameMap(); // Internal: Get and set DPI context static const VerilatedScope* dpiScope() { return t_dpiScopep; } static void dpiScope(const VerilatedScope* scopep) { t_dpiScopep=scopep; } diff --git a/include/verilated_imp.h b/include/verilated_imp.h index 4e2e79950..3a434766a 100644 --- a/include/verilated_imp.h +++ b/include/verilated_imp.h @@ -49,7 +49,6 @@ class VerilatedImp { // TYPES typedef vector ArgVec; typedef map,void*> UserMap; - typedef map ScopeNameMap; typedef map ExportNameMap; // MEMBERS @@ -60,7 +59,7 @@ class VerilatedImp { ArgVec m_argVec; ///< Argument list (NOT save-restored, may want different results) bool m_argVecLoaded; ///< Ever loaded argument list UserMap m_userMap; ///< Map of <(scope,userkey), userData> - ScopeNameMap m_nameMap; ///< Map of + VerilatedScopeNameMap m_nameMap; ///< Map of // Slow - somewhat static: ExportNameMap m_exportMap; ///< Map of int m_exportNext; ///< Next export funcnum @@ -154,30 +153,33 @@ public: // But only for verilated*.cpp // METHODS - scope name static void scopeInsert(const VerilatedScope* scopep) { // Slow ok - called once/scope at construction - ScopeNameMap::iterator it=s_s.m_nameMap.find(scopep->name()); + VerilatedScopeNameMap::iterator it=s_s.m_nameMap.find(scopep->name()); if (it == s_s.m_nameMap.end()) { s_s.m_nameMap.insert(it, make_pair(scopep->name(),scopep)); } } static inline const VerilatedScope* scopeFind(const char* namep) { - ScopeNameMap::iterator it=s_s.m_nameMap.find(namep); + VerilatedScopeNameMap::iterator it=s_s.m_nameMap.find(namep); if (VL_LIKELY(it != s_s.m_nameMap.end())) return it->second; else return NULL; } static void scopeErase(const VerilatedScope* scopep) { // Slow ok - called once/scope at destruction userEraseScope(scopep); - ScopeNameMap::iterator it=s_s.m_nameMap.find(scopep->name()); + VerilatedScopeNameMap::iterator it=s_s.m_nameMap.find(scopep->name()); if (it != s_s.m_nameMap.end()) s_s.m_nameMap.erase(it); } static void scopesDump() { VL_PRINTF(" scopesDump:\n"); - for (ScopeNameMap::iterator it=s_s.m_nameMap.begin(); it!=s_s.m_nameMap.end(); ++it) { + for (VerilatedScopeNameMap::iterator it=s_s.m_nameMap.begin(); it!=s_s.m_nameMap.end(); ++it) { const VerilatedScope* scopep = it->second; scopep->scopeDump(); } VL_PRINTF("\n"); } + static const VerilatedScopeNameMap* scopeNameMap() { + return &s_s.m_nameMap; + } public: // But only for verilated*.cpp // METHODS - export names diff --git a/include/verilated_syms.h b/include/verilated_syms.h index 5246cbc97..8555f194f 100644 --- a/include/verilated_syms.h +++ b/include/verilated_syms.h @@ -32,16 +32,6 @@ #include -//====================================================================== -// Types - -struct VerilatedCStrCmp { - /// Ordering maps keyed by const char*'s - bool operator() (const char *a, const char *b) const { - return std::strcmp(a, b) < 0; - } -}; - //=========================================================================== /// Verilator range @@ -93,6 +83,20 @@ public: //====================================================================== /// Types +struct VerilatedCStrCmp { + /// Ordering maps keyed by const char*'s + bool operator() (const char *a, const char *b) const { + return std::strcmp(a, b) < 0; + } +}; + +class VerilatedScopeNameMap + : public map { +public: + VerilatedScopeNameMap() {} + ~VerilatedScopeNameMap() {} +}; + class VerilatedVarNameMap : public map { public: VerilatedVarNameMap() {} diff --git a/test_regress/t/t_scope_map.cpp b/test_regress/t/t_scope_map.cpp new file mode 100644 index 000000000..ed23cfafb --- /dev/null +++ b/test_regress/t/t_scope_map.cpp @@ -0,0 +1,160 @@ +// -*- mode: C++; c-file-style: "cc-mode" -*- +// +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed into the Public Domain, for any use, +// without warranty, 2008 by Wilson Snyder. + +#include +#include +#include +#include +#include + +#include "Vt_scope_map.h" + +using namespace std; + +unsigned long long main_time = 0; +double sc_time_stamp() { + return (double)main_time; +} + +const unsigned long long dt_2 = 3; + +int main(int argc, char **argv, char **env) { + Vt_scope_map *top = new Vt_scope_map("top"); + + Verilated::debug(0); + Verilated::traceEverOn(true); + + VerilatedVcdC* tfp = new VerilatedVcdC; + top->trace(tfp,99); + tfp->open("obj_dir/t_scope_map/simx.vcd"); + + top->CLK = 0; + top->eval(); + tfp->dump((unsigned int)(main_time)); + ++main_time; + + const VerilatedScopeNameMap* scopeMapp = Verilated::scopeNameMap(); + for (VerilatedScopeNameMap::const_iterator it = scopeMapp->begin(); it != scopeMapp->end(); it++) { +#ifdef TEST_VERBOSE + VL_PRINTF("---------------------------------------------\n"); + VL_PRINTF("Scope = %s\n", it->first.c_str()); + it->second->scopeDump(); +#endif + VerilatedVarNameMap * varNameMap = it->second->varsp(); + if (varNameMap == NULL) { + VL_PRINTF("%%Error: Bad varsp()\n"); + return -1; + } + + for (VerilatedVarNameMap::iterator varIt = varNameMap->begin(); varIt != varNameMap->end(); ++varIt) { + VerilatedVar * var = &varIt->second; + int varLeft = var->range().left(); + int varRight = var->range().right(); + +#ifdef TEST_VERBOSE + VL_PRINTF("\tVar = %s\n", varIt->first); + VL_PRINTF("\t Type = %d\n", var->vltype()); + VL_PRINTF("\t EntSize = %d\n", var->entSize()); + VL_PRINTF("\t Dims = %d\n", var->dims()); + VL_PRINTF("\t Range = %d:%d\n", varLeft, varRight); + VL_PRINTF("\t Is RW = %d\n", var->isPublicRW()); +#endif + + if (varRight != 0) { + VL_PRINTF("%%Error: Was expecting right range value = 0\n"); + return -1; + } + + int varBits = varLeft + 1; + + // First expect an incrementing byte pattern + vluint8_t * varData = reinterpret_cast(var->datap()); + for (int i = 0; i < varBits / 8; i++) { +#ifdef TEST_VERBOSE + VL_PRINTF("%02x ", varData[i]); +#endif + + vluint8_t expected = i % 0xff; + if (varData[i] != expected) { + VL_PRINTF("%%Error: Data mismatch, got 0x%02x, expected 0x%02x\n", varData[i], expected); + return -1; + } + } + + // Extra bits all set high initially + if (varBits % 8 != 0) { + vluint8_t got = varData[ varBits / 8 ]; + vluint8_t expected = ~(0xff << ( varBits % 8 )); + if (got != expected) { + VL_PRINTF("%%Error: Data mismatch, got 0x%02x, expected 0x%02x\n", got, expected); + return -1; + } + } + +#ifdef TEST_VERBOSE + VL_PRINTF("\n"); +#endif + + // Clear out the data + memset(varData, 0, ( varBits + 7 ) / 8); + } + } + + top->CLK = 0; + top->eval(); + tfp->dump((unsigned int)(main_time)); + ++main_time; + + // Posedge on clock, expect all the public bits to flip + top->CLK = 1; + top->eval(); + tfp->dump((unsigned int)(main_time)); + ++main_time; + + for (VerilatedScopeNameMap::const_iterator it = scopeMapp->begin(); it != scopeMapp->end(); ++it) { + VerilatedVarNameMap * varNameMap = it->second->varsp(); + if (varNameMap == NULL) { + VL_PRINTF("%%Error: Bad varsp()\n"); + return -1; + } + + for (VerilatedVarNameMap::iterator varIt = varNameMap->begin(); varIt != varNameMap->end(); ++varIt) { + VerilatedVar * var = &varIt->second; + int varLeft = var->range().left(); + int varBits = varLeft + 1; + vluint8_t * varData = reinterpret_cast(var->datap()); + + // Check that all bits are high now + for (int i = 0; i < varBits / 8; i++) { + vluint8_t expected = 0xff; + if (varData[i] != expected) { + VL_PRINTF("%%Error: Data mismatch (%s), got 0x%02x, expected 0x%02x\n", varIt->first, varData[i], expected); + return -1; + } + } + + if (varBits % 8 != 0) { + vluint8_t got = varData[ varBits / 8 ]; + vluint8_t expected = ~(0xff << ( varBits % 8 )); + if (got != expected) { + VL_PRINTF("%%Error: Data mismatch (%s), got 0x%02x, expected 0x%02x\n", varIt->first, got, expected); + return -1; + } + } + } + } + + top->CLK = 0; + top->eval(); + tfp->dump((unsigned int)(main_time)); + ++main_time; + + tfp->close(); + top->final(); + VL_PRINTF ("*-* All Finished *-*\n"); + return 0; +} diff --git a/test_regress/t/t_scope_map.pl b/test_regress/t/t_scope_map.pl new file mode 100755 index 000000000..d3e6e19b0 --- /dev/null +++ b/test_regress/t/t_scope_map.pl @@ -0,0 +1,23 @@ +#!/usr/bin/perl +if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; } +# DESCRIPTION: Verilator: Verilog Test driver/expect definition +# +# Copyright 2015 by Todd Strader. 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. + +$Self->{vlt} or $Self->skip("Verilator only test"); + +compile ( + make_top_shell => 0, + make_main => 0, + v_flags2 => ["--trace --exe $Self->{t_dir}/$Self->{name}.cpp"], + ); + +execute ( + check_finished=>1, + ); + +ok(1); +1; diff --git a/test_regress/t/t_scope_map.v b/test_regress/t/t_scope_map.v new file mode 100644 index 000000000..a69acdb26 --- /dev/null +++ b/test_regress/t/t_scope_map.v @@ -0,0 +1,66 @@ +// DESCRIPTION: Verilator: Test symbol table scope map and general public +// signal reflection +// +// This file ONLY is placed into the Public Domain, for any use, +// without warranty, 2015 by Todd Strader. + +module t + ( + input wire CLK + ); + + foo #(.WIDTH (1)) foo1 (.*); + foo #(.WIDTH (7)) foo7 (.*); + foo #(.WIDTH (8)) foo8 (.*); + foo #(.WIDTH (32)) foo32 (.*); + foo #(.WIDTH (33)) foo33 (.*); + foo #(.WIDTH (40)) foo40 (.*); + foo #(.WIDTH (41)) foo41 (.*); + foo #(.WIDTH (64)) foo64 (.*); + foo #(.WIDTH (65)) foo65 (.*); + foo #(.WIDTH (96)) foo96 (.*); + foo #(.WIDTH (97)) foo97 (.*); + foo #(.WIDTH (128)) foo128 (.*); + foo #(.WIDTH (256)) foo256 (.*); + foo #(.WIDTH (1024)) foo1024 (.*); + bar #(.WIDTH (1024)) bar1024 (.*); + +endmodule + +module foo + #( + parameter WIDTH = 32 + ) + ( + input CLK + ); + + logic [ ( ( WIDTH + 7 ) / 8 ) * 8 - 1 : 0 ] initial_value; + logic [ WIDTH - 1 : 0 ] value_q /* verilator public */; + integer i; + + initial begin + initial_value = '1; + + for (i = 0; i < WIDTH / 8; i++) + initial_value[ i * 8 +: 8 ] = i[ 7 : 0 ]; + + value_q = initial_value[ WIDTH - 1 : 0 ]; + end + + always @(posedge CLK) + value_q <= ~value_q; + +endmodule + +module bar + #( + parameter WIDTH = 32 + ) + ( + input CLK + ); + + foo #(.WIDTH (WIDTH)) foo (.*); + +endmodule