WIP - Add verilator_replay utility

This commit is contained in:
Todd Strader 2020-01-10 18:14:32 -05:00
parent 18e837336a
commit 2c25c25379
14 changed files with 652 additions and 5 deletions

1
.gitignore vendored
View File

@ -29,6 +29,7 @@ internals.txt
verilator.txt
verilator_bin*
verilator_coverage_bin*
verilator_replay_bin*
verilator.pc
verilator-config.cmake
verilator-config-version.cmake

View File

@ -0,0 +1,22 @@
// TODO -- will be generated by verilator_replay -- DO NOT PUSH UPSTREAM
#include "Vt_case_reducer.h"
#include "verilated_replay.h"
void VerilatedReplay::createMod() {
m_modp = new Vt_case_reducer;
// TODO -- make VerilatedModule destructor virtual so we can delete from the base class?
}
void VerilatedReplay::eval() {
// TODO -- make eval, trace and final virtual methods of VerilatedModule?
reinterpret_cast<Vt_case_reducer*>(m_modp)->eval();
}
void VerilatedReplay::trace() {
// TODO -- need VerilatedFstC, etc.
//reinterpret_cast<Vt_case_reducer*>(m_modp)->trace();
}
void VerilatedReplay::final() {
reinterpret_cast<Vt_case_reducer*>(m_modp)->final();
}

View File

@ -0,0 +1,169 @@
// -*- mode: C++; c-file-style: "cc-mode" -*-
//*************************************************************************
//
// Copyright 2003-2020 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.
//
// Verilator is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
//=========================================================================
///
/// \file
/// \brief Verilator: Common functions for replay tool
///
/// See verilator_replay
///
/// Code available from: http://www.veripool.org/verilator
///
//=========================================================================
#include "verilated_replay.h"
// TODO -- can we not do this?
// Include the GTKWave implementation directly
#define FST_CONFIG_INCLUDE "fst_config.h"
#include "gtkwave/fastlz.c"
#include "gtkwave/fstapi.c"
// TODO -- use the system's LZ4 library, not this copy
#include "gtkwave/lz4.c"
// TODO -- collapse into constructor?
int VerilatedReplay::init() {
m_fstp = fstReaderOpen(m_fstName.c_str());
if (!m_fstp) {
// TODO -- Verilator runtime way of tossing a fatal error?, see elsewhere
VL_PRINTF("Could not open FST: %s\n", m_fstName.c_str());
exit(-1);
}
m_time = fstReaderGetStartTime(m_fstp);
// TODO -- use FST timescale
m_simTime = m_time;
// TODO -- this is not right, just testing
fstReaderSetFacProcessMaskAll(m_fstp);
createMod();
return 0;
}
VerilatedReplay::~VerilatedReplay() {
fstReaderClose(m_fstp);
delete(m_modp);
}
//int VerilatedReplay::addInput(const std::string& signalName, void* dutSignal, unsigned bits) {
// for (std::vector<VCDSignal*>::iterator it = m_scopep->signals.begin();
// it != m_scopep->signals.end(); ++it) {
// if (signalName == (*it)->reference) {
// VerilatedReplaySignal* signalp = new VerilatedReplaySignal;
// signalp->dutSignal = dutSignal;
// signalp->bits = bits;
// signalp->hash = (*it)->hash;
//
// if ((*it)->size != bits) {
// VL_PRINTF("Error size mismatch on %s: trace=%d design=%d\n",
// signalName.c_str(), (*it)->size, bits);
// return -1;
// }
//
// if ((*it)->type != VCD_VAR_REG && (*it)->type != VCD_VAR_WIRE) {
// VL_PRINTF("Error unsupported signal type on %s\n", signalName.c_str());
// return -1;
// }
//
// m_inputs.push_back(signalp);
// return 0;
// }
// }
// VL_PRINTF("Error finding signal (%s)\n", signalName.c_str());
// return -1;
//}
//
//void VerilatedReplay::copySignal(uint8_t* signal, VCDValue* valuep) {
// VCDValueType type = valuep->get_type();
// switch(type) {
// case VCD_SCALAR: {
// copySignalBit(signal, 0, valuep->get_value_bit());
// break;
// }
// case VCD_VECTOR: {
// VCDBitVector* bitVector = valuep->get_value_vector();
// unsigned length = bitVector->size();
// for (int i = 0; i < length; ++i) {
// copySignalBit(signal, i, bitVector->at(length - i - 1));
// }
// break;
// }
// default: {
// VL_PRINTF("Error unsupported VCD value type");
// exit(-1);
// }
// }
//}
//
//void VerilatedReplay::copySignalBit(uint8_t* signal, unsigned offset, VCDBit bit) {
// unsigned byte = offset / 8;
// unsigned byteOffset = offset % 8;
// // TODO - more efficient byte copying
// signal[byte] &= ~(0x1 << byteOffset);
// // TODO - x's and z's?
// signal[byte] |= (bit == VCD_1 ? 0x1 : 0x0) << byteOffset;
//}
int VerilatedReplay::replay() {
// TODO -- lockless ring buffer for separate reader/replay threads
// TODO -- should I be using fstReaderIterBlocks instead? (only one CB)
// It appears that 0 is the error return code
if (fstReaderIterBlocks2(m_fstp, &VerilatedReplay::fstCallback,
&VerilatedReplay::fstCallbackVarlen, this, NULL) == 0) {
VL_PRINTF("Error iterating FST\n");
exit(-1);
}
// One final eval + trace since we only eval on time changes
eval();
trace();
final();
return 0;
}
void VerilatedReplay::fstCb(uint64_t time, fstHandle facidx,
const unsigned char* valuep, uint32_t len) {
// Watch for new time steps and eval before we start working on the new time
if (m_time != time) {
eval();
trace();
m_time = time;
// TODO -- use FST timescale
m_simTime = m_time;
}
VL_PRINTF("%lu %u %s\n", time, facidx, valuep);
}
void VerilatedReplay::fstCallbackVarlen(void* userDatap, uint64_t time, fstHandle facidx,
const unsigned char* valuep, uint32_t len) {
reinterpret_cast<VerilatedReplay*>(userDatap)->fstCb(time, facidx, valuep, len);
}
void VerilatedReplay::fstCallback(void* userDatap, uint64_t time, fstHandle facidx,
const unsigned char* valuep) {
// Cribbed from fstminer.c in the gtkwave repo
uint32_t len;
if(valuep) {
len = strlen((const char *)valuep);
} else {
len = 0;
}
fstCallbackVarlen(userDatap, time, facidx, valuep, len);
}

View File

@ -0,0 +1,60 @@
// -*- mode: C++; c-file-style: "cc-mode" -*-
//*************************************************************************
//
// Copyright 2003-2020 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.
//
// Verilator is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
//=========================================================================
///
/// \file
/// \brief Verilator: Include for replay tool
///
/// See verilator_replay
///
/// Code available from: http://www.veripool.org/verilator
///
//=========================================================================
#ifndef _VERILATED_REPLAY_H_
#define _VERILATED_REPLAY_H_ 1 ///< Header Guard
#include "verilated.h"
#include "gtkwave/fstapi.h"
#include <string>
class VerilatedReplay {
private:
void createMod();
void eval();
void trace();
void final();
void fstCb(uint64_t time, fstHandle facidx, const unsigned char* value,
uint32_t len);
static void fstCallback(void* userData, uint64_t time, fstHandle facidx,
const unsigned char* value);
static void fstCallbackVarlen(void* userData, uint64_t time, fstHandle facidx,
const unsigned char* value, uint32_t len);
std::string m_fstName;
double& m_simTime;
VerilatedModule* m_modp;
void* m_fstp;
uint64_t m_time;
public:
VerilatedReplay(const std::string& fstName, double& simTime):
m_fstName(fstName), m_simTime(simTime)
{}
~VerilatedReplay();
int init();
int replay();
};
#endif // Guard

View File

@ -0,0 +1,76 @@
// -*- mode: C++; c-file-style: "cc-mode" -*-
//*************************************************************************
//
// Copyright 2003-2020 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.
//
// Verilator is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
//=========================================================================
///
/// \file
/// \brief Verilator: Main used by verilator_replay
///
/// This utility will replay trace files onto a verilated design.
/// It is inteded to be used in conjunction with verilator_replay.
///
/// Code available from: http://www.veripool.org/verilator
///
//=========================================================================
#include "verilated_replay.h"
double simTime = 0;
double sc_time_stamp() {
return simTime;
}
// TODO -- should we make eval, final and trace(?) part of VerilatedModule?
// TODO -- generate this part
//#include "Vt_case_reducer.h"
//Vt_case_reducer* dutp = NULL;
//VerilatedVcdC* tfp = NULL;
//void VerilatedReplay::eval() {
// dutp->eval();
//}
//
//void VerilatedReplay::trace() {
//#if VM_TRACE
// if (tfp) tfp->dump(simTime);
//#endif // VM_TRACE
//}
//
//void VerilatedReplay::final() {
// dutp->final();
//}
int main(int argc, char** argv) {
// TODO -- actual arg parsing
std::string fstFilename(argv[1]);
VL_PRINTF("FST = %s\n", fstFilename.c_str());
VerilatedReplay replay(fstFilename, simTime);
if (replay.init()) exit(-1);
//#if VM_TRACE
// Verilated::traceEverOn(true);
// tfp = new VerilatedFstC;
// dutp->trace(tfp, 99);
// tfp->open("replay.fst");
// if (tfp) tfp->dump(simTime);
//#endif // VM_TRACE
if (replay.replay()) exit(-1);
//#if VM_TRACE
// if (tfp) tfp->close();
//#endif // VM_TRACE
return 0;
}

View File

@ -64,7 +64,7 @@ else
$(MAKE) -C obj_opt TGT=../$@ -f ../Makefile_obj
endif
dbg: ../bin/verilator_bin_dbg ../bin/verilator_coverage_bin_dbg
dbg: ../bin/verilator_bin_dbg ../bin/verilator_coverage_bin_dbg ../bin/verilator_replay_bin_dbg
../bin/verilator_bin_dbg: obj_dbg ../bin prefiles
$(MAKE) -C obj_dbg -j 1 TGT=../$@ VL_DEBUG=1 -f ../Makefile_obj serial
$(MAKE) -C obj_dbg TGT=../$@ VL_DEBUG=1 -f ../Makefile_obj
@ -73,6 +73,9 @@ dbg: ../bin/verilator_bin_dbg ../bin/verilator_coverage_bin_dbg
$(MAKE) -C obj_dbg TGT=../$@ VL_DEBUG=1 VL_VLCOV=1 -f ../Makefile_obj serial_vlcov
$(MAKE) -C obj_dbg TGT=../$@ VL_DEBUG=1 VL_VLCOV=1 -f ../Makefile_obj
../bin/verilator_replay_bin_dbg: obj_dbg ../bin prefiles
$(MAKE) -C obj_dbg TGT=../$@ VL_DEBUG=1 VL_VLREPLAY=1 -f ../Makefile_obj
prefiles::
prefiles:: config_rev.h
ifneq ($(UNDER_GIT),) # If local git tree... Else don't burden users

View File

@ -256,14 +256,28 @@ NC_OBJS += \
VLCOV_OBJS = \
VlcMain.o \
# verilator_replay
VLREPLAY_OBJS = \
V3Error.o \
VlrOptions.o \
VlrGenerator.o \
VlrMain.o \
#### Linking
ifeq ($(VL_VLCOV),)
PREDEP_H = V3Ast__gen_classes.h
OBJS += $(RAW_OBJS) $(NC_OBJS)
else
ifneq ($(VL_VLCOV),)
PREDEP_H =
OBJS += $(VLCOV_OBJS)
else ifneq ($(VL_VLREPLAY),)
PREDEP_H =
OBJS += $(VLREPLAY_OBJS)
# TODO -- do we already search for this in configure?
LIBS += -lz
# TODO -- do this for verilator_coverage as well
CXXFLAGS += -D_V3ERROR_NO_GLOBAL_=1
else
PREDEP_H = V3Ast__gen_classes.h
OBJS += $(RAW_OBJS) $(NC_OBJS)
endif
V3__CONCAT.cpp: $(addsuffix .cpp, $(basename $(RAW_OBJS)))

47
src/VlrGenerator.cpp Normal file
View File

@ -0,0 +1,47 @@
#include "VlrGenerator.h"
#include "V3Error.h"
#include "gtkwave/fstapi.h"
// TODO -- can we not do this?
// Include the GTKWave implementation directly
#define FST_CONFIG_INCLUDE "fst_config.h"
#include "gtkwave/fastlz.c"
#include "gtkwave/fstapi.c"
// TODO -- use the system's LZ4 library, not this copy
#include "gtkwave/lz4.c"
void VlrGenerator::getFstIO() {
void* fst = fstReaderOpen(opts().fst());
const char* scope = "";
string targetScope;
if (m_opts.scope()) targetScope = string(m_opts.scope());
while (struct fstHier* hier = fstReaderIterateHier(fst)) {
if (hier->htyp == FST_HT_SCOPE) {
scope = fstReaderPushScope(fst, hier->u.scope.name, NULL);
if (targetScope.empty()) targetScope = string(scope);
UINFO(3, "SCOPE "<<scope<<endl);
} else if (hier->htyp == FST_HT_UPSCOPE) {
scope = fstReaderPopScope(fst);
UINFO(3, "UPSCOPE "<<scope<<endl);
} else if (hier->htyp == FST_HT_VAR) {
if (string(scope) == targetScope) {
string varName = string(scope) + "." + string(hier->u.var.name);
switch (hier->u.var.direction) {
case FST_VD_INPUT:
UINFO(3, "VAR input "<<hier->u.var.name<<endl);
m_inputs.push_back(varName);
break;
case FST_VD_OUTPUT:
UINFO(3, "VAR output "<<hier->u.var.name<<endl);
m_outputs.push_back(varName);
break;
default: break;
}
}
}
}
}
void VlrGenerator::emitVltCode() {
}

45
src/VlrGenerator.h Normal file
View File

@ -0,0 +1,45 @@
// -*- mode: C++; c-file-style: "cc-mode" -*-
//*************************************************************************
// DESCRIPTION: verilator_replay: Replay code generator
//
// Code available from: https://verilator.org
//
//*************************************************************************
//
// Copyright 2020 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.
//
// Verilator is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
//*************************************************************************
#ifndef _VLRGENERATOR_H_
#define _VLRGENERATOR_H_ 1
#include "VlrOptions.h"
#include <list>
class VlrGenerator {
public:
// CONSTRUCTORS
VlrGenerator() {}
~VlrGenerator() {}
// METHODS
VlrOptions& opts() { return m_opts; }
void getFstIO();
void emitVltCode();
private:
typedef std::list<std::string> StrList;
VlrOptions m_opts;
StrList m_inputs;
StrList m_outputs;
};
#endif // guard

43
src/VlrMain.cpp Normal file
View File

@ -0,0 +1,43 @@
// -*- mode: C++; c-file-style: "cc-mode" -*-
//*************************************************************************
// DESCRIPTION: verilator_replay: main()
//
// Code available from: https://verilator.org
//
//*************************************************************************
//
// Copyright 2020 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.
//
// Verilator is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
//*************************************************************************
#include "VlrGenerator.h"
#include "V3Error.h"
int main(int argc, char** argv) {
VlrGenerator gen;
// Parse command line options
gen.opts().parseOptsList(argc-1, argv+1);
// Read signals from FST or signals file
if (gen.opts().fst()) {
gen.getFstIO();
}
// TODO -- manually specified lists
// TODO -- check for none of the above
// Emit replay code
if (gen.opts().vlt()) {
gen.emitVltCode();
}
// TODO -- DPI and/or VPI wrappers
// TODO -- check no emitters
}

111
src/VlrOptions.cpp Normal file
View File

@ -0,0 +1,111 @@
// -*- mode: C++; c-file-style: "cc-mode" -*-
//*************************************************************************
// DESCRIPTION: verilator_replay: Command line options
//
// Code available from: https://verilator.org
//
//*************************************************************************
//
// Copyright 2020 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.
//
// Verilator is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
//*************************************************************************
#include "VlrOptions.h"
#include "config_build.h"
#include "config_rev.h"
#include "V3Error.h"
void VlrOptions::parseOptsList(int argc, char** argv) {
// Parse parameters
// Note argc and argv DO NOT INCLUDE the filename in [0]!!!
for (int i=0; i<argc; ) {
UINFO(9, " Option: "<<argv[i]<<endl);
if (argv[i][0]=='-') {
const char* sw = argv[i];
bool flag = true;
// Allow gnu -- switches
if (sw[0]=='-' && sw[1]=='-') ++sw;
if (0) {} // TODO -- just to avoid the asymetry of one "if"?
// Single switches
else if (onoff (sw, "-vlt", flag/*ref*/) ) { m_vlt = flag; }
//// Parameterized switches
else if (!strcmp(sw, "-debug") ) {
V3Error::debugDefault(3);
}
else if (!strcmp(sw, "-debugi") && (i+1)<argc ) {
++i;
V3Error::debugDefault(atoi(argv[i]));
}
else if (!strcmp(sw, "-fst") && (i+1)<argc ) {
++i;
m_fst = argv[i];
}
else if (!strcmp(sw, "-scope") && (i+1)<argc ) {
++i;
m_scope = argv[i];
}
else if (!strcmp(sw, "-V") ) {
showVersion(true);
exit(0);
}
else if (!strcmp(sw, "-version") ) {
showVersion(false);
exit(0);
}
else {
v3fatal("Invalid option: "<<argv[i]);
}
++i;
} // - options
//else if (1) {
// addReadFile(argv[i]);
// ++i;
//}
else {
v3fatal("Invalid argument: "<<argv[i]);
++i;
}
}
}
void VlrOptions::showVersion(bool verbose) {
cout <<version();
cout <<endl;
if (!verbose) return;
cout <<endl;
cout << "Copyright 2020 by Todd Strader. Verilator is free software; you can\n";
cout << "redistribute it and/or modify the Verilator internals under the terms of\n";
cout << "either the GNU Lesser General Public License Version 3 or the Perl Artistic\n";
cout << "License Version 2.0.\n";
cout <<endl;
cout << "See https://verilator.org for documentation\n";
}
string VlrOptions::version() {
string ver = DTVERSION;
ver += " rev "+cvtToStr(DTVERSION_rev);
return ver;
}
// TODO -- Shared with Verilator too? Refactor into some common code.
bool VlrOptions::onoff(const char* sw, const char* arg, bool& flag) {
// if sw==arg, then return true (found it), and flag=true
// if sw=="-no-arg", then return true (found it), and flag=false
// if sw=="-noarg", then return true (found it), and flag=false
// else return false
if (arg[0]!='-') v3fatalSrc("OnOff switches must have leading dash.");
if (0==strcmp(sw, arg)) { flag = true; return true; }
else if (0==strncmp(sw, "-no", 3) && (0==strcmp(sw+3, arg+1))) { flag = false; return true; }
else if (0==strncmp(sw, "-no-", 4) && (0==strcmp(sw+4, arg+1))) { flag = false; return true; }
return false;
}

50
src/VlrOptions.h Normal file
View File

@ -0,0 +1,50 @@
// -*- mode: C++; c-file-style: "cc-mode" -*-
//*************************************************************************
// DESCRIPTION: verilator_replay: Command line options
//
// Code available from: https://verilator.org
//
//*************************************************************************
//
// Copyright 2020 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.
//
// Verilator is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
//*************************************************************************
#ifndef _VLROPTIONS_H_
#define _VLROPTIONS_H_ 1
#include <string>
class VlrOptions {
public:
// CONSTRUCTORS
VlrOptions():
m_fst(NULL), m_scope(NULL), m_vlt(false)
{}
~VlrOptions() {}
// METHODS
void parseOptsList(int argc, char** argv);
const char* fst() { return m_fst; }
const char* scope() { return m_scope; }
bool vlt() { return m_vlt; }
private:
void showVersion(bool version);
std::string version();
bool onoff(const char* sw, const char* arg, bool& flag);
const char* m_fst;
const char* m_scope;
bool m_vlt;
};
#endif // guard

View File

@ -10,6 +10,7 @@ if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); di
scenarios(simulator => 1);
compile(
v_flags2 => ["--trace-fst"], # TODO -- remove and make independent test
);
execute(

View File

@ -3,6 +3,9 @@
// This file ONLY is placed into the Public Domain, for any use,
// without warranty, 2012 by Wilson Snyder.
// TODO -- don't hijack this test
`ifndef REPLAY_HACK
module t (/*AUTOARG*/
// Inputs
clk
@ -64,6 +67,8 @@ module t (/*AUTOARG*/
endmodule
`endif
module Test
(
// Inputs