mirror of
https://github.com/verilator/verilator.git
synced 2025-01-01 04:07:34 +00:00
Add VerilatedScopeNameMap for introspection, bug966.
Signed-off-by: Wilson Snyder <wsnyder@wsnyder.org>
This commit is contained in:
parent
d0653f72e2
commit
34870e899f
2
Changes
2
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]
|
||||
|
@ -1170,6 +1170,10 @@ int Verilated::exportFuncNum(const char* namep) {
|
||||
return VerilatedImp::exportFind(namep);
|
||||
}
|
||||
|
||||
const VerilatedScopeNameMap* Verilated::scopeNameMap() {
|
||||
return VerilatedImp::scopeNameMap();
|
||||
}
|
||||
|
||||
//===========================================================================
|
||||
// VerilatedModule:: Methods
|
||||
|
||||
|
@ -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; }
|
||||
|
@ -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
|
||||
|
@ -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() {}
|
||||
|
160
test_regress/t/t_scope_map.cpp
Normal file
160
test_regress/t/t_scope_map.cpp
Normal 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
23
test_regress/t/t_scope_map.pl
Executable 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;
|
66
test_regress/t/t_scope_map.v
Normal file
66
test_regress/t/t_scope_map.v
Normal 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
|
Loading…
Reference in New Issue
Block a user