Add VerilatedScopeNameMap for introspection, bug966.

Signed-off-by: Wilson Snyder <wsnyder@wsnyder.org>
This commit is contained in:
Todd Strader 2015-09-24 21:08:58 -04:00 committed by Wilson Snyder
parent d0653f72e2
commit 34870e899f
8 changed files with 280 additions and 16 deletions

View File

@ -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]

View File

@ -1170,6 +1170,10 @@ int Verilated::exportFuncNum(const char* namep) {
return VerilatedImp::exportFind(namep);
}
const VerilatedScopeNameMap* Verilated::scopeNameMap() {
return VerilatedImp::scopeNameMap();
}
//===========================================================================
// VerilatedModule:: Methods

View File

@ -38,6 +38,7 @@
#include <cstring>
#include <cmath>
// <iostream> avoided to reduce compile time
// <map> avoided and instead in verilated_heavy.h to reduce compile time
// <string> 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; }

View File

@ -49,7 +49,6 @@ class VerilatedImp {
// TYPES
typedef vector<string> ArgVec;
typedef map<pair<const void*,void*>,void*> UserMap;
typedef map<const char*, const VerilatedScope*, VerilatedCStrCmp> ScopeNameMap;
typedef map<const char*, int, VerilatedCStrCmp> 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 <scope_name, scope pointer>
VerilatedScopeNameMap m_nameMap; ///< Map of <scope_name, scope pointer>
// Slow - somewhat static:
ExportNameMap m_exportMap; ///< Map of <export_func_proto, func number>
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

View File

@ -32,16 +32,6 @@
#include <map>
//======================================================================
// 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<const char*, const VerilatedScope*, VerilatedCStrCmp> {
public:
VerilatedScopeNameMap() {}
~VerilatedScopeNameMap() {}
};
class VerilatedVarNameMap : public map<const char*, VerilatedVar, VerilatedCStrCmp> {
public:
VerilatedVarNameMap() {}

View File

@ -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 <verilated.h>
#include <verilated_syms.h>
#include <verilated_vcd_c.h>
#include <map>
#include <string>
#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<vluint8_t *>(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<vluint8_t *>(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;
}

23
test_regress/t/t_scope_map.pl Executable file
View File

@ -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;

View File

@ -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