Output checking

This commit is contained in:
Todd Strader 2020-01-22 06:39:38 -05:00
parent 4952fd5203
commit 505949ec54
7 changed files with 99 additions and 19 deletions

View File

@ -23,6 +23,7 @@
//=========================================================================
#include "verilated_replay.h"
#include <cstring>
// TODO -- collapse into constructor?
int VerilatedReplay::init() {
@ -42,18 +43,35 @@ int VerilatedReplay::init() {
for (VarMap::iterator it = m_inputs.begin(); it != m_inputs.end();
++it) {
VL_PRINTF("%s = %d\n", it->second.fullName.c_str(), it->first);
VL_PRINTF("input %s = %d\n", it->second.fullName.c_str(), it->first);
fstReaderSetFacProcessMask(m_fstp, it->first);
// TODO -- double check the size hasn't changed or just defer looking at size until here
m_inputHandles[it->first] = FstSignal(it->second.hier.u.var.length,
m_inputNames[it->second.fullName].signal);
}
for (VarMap::iterator it = m_outputs.begin(); it != m_outputs.end();
++it) {
VL_PRINTF("output %s = %d\n", it->second.fullName.c_str(), it->first);
fstReaderSetFacProcessMask(m_fstp, it->first);
size_t bits = it->second.hier.u.var.length;
size_t bytes = (bits + 7) / 8;
vluint8_t* buffer = new vluint8_t [bytes];
// TODO -- double check the size hasn't changed or just defer looking at size until here
m_outputHandles[it->first] = FstSignal(bits, m_outputNames[it->second.fullName].signal,
buffer);
}
return 0;
}
VerilatedReplay::~VerilatedReplay() {
fstReaderClose(m_fstp);
for (SignalHandleMap::iterator it = m_outputHandles.begin(); it != m_outputHandles.end(); ++it) {
delete [] it->second.expected;
}
#if VM_TRACE
if (m_tfp) m_tfp->close();
#endif
@ -100,21 +118,39 @@ void VerilatedReplay::fstCb(uint64_t time, fstHandle facidx,
// TODO -- remove
VL_PRINTF("%lu %u %s\n", time, facidx, valuep);
// TODO -- is len always right, or should we use strlen() or something?
// TODO -- handle values other than 0/1, what can show up here?
vluint8_t* signal = m_inputHandles[facidx].signal;
if (m_outputHandles.empty() || m_inputHandles.find(facidx) != m_inputHandles.end()) {
handleInput(facidx, valuep, len);
} else {
handleOutput(facidx, valuep, len);
}
}
void VerilatedReplay::copyValue(unsigned char* to, const unsigned char* valuep, uint32_t len) {
vluint8_t byte = 0;
for (size_t bit = 0; bit < len; ++bit) {
char value = valuep[len - 1 - bit];
if (value == '1') byte |= 1 << (bit % 8);
if ((bit + 1) % 8 == 0 || bit == len - 1) {
*signal = byte;
++signal;
*to = byte;
++to;
byte = 0;
}
}
}
void VerilatedReplay::handleInput(fstHandle facidx, const unsigned char* valuep, uint32_t len) {
// TODO -- is len always right, or should we use strlen() or something?
// TODO -- handle values other than 0/1, what can show up here?
vluint8_t* signal = m_inputHandles[facidx].signal;
copyValue(signal, valuep, len);
}
void VerilatedReplay::handleOutput(fstHandle facidx, const unsigned char* valuep, uint32_t len) {
FstSignal& fstSignal = m_outputHandles[facidx];
size_t bytes = (len + 7) / 8;
copyValue(fstSignal.expected, valuep, len);
}
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);
@ -134,6 +170,18 @@ void VerilatedReplay::fstCallback(void* userDatap, uint64_t time, fstHandle faci
fstCallbackVarlen(userDatap, time, facidx, valuep, len);
}
void VerilatedReplay::outputCheck() {
for (SignalHandleMap::iterator it = m_outputHandles.begin(); it != m_outputHandles.end(); ++it) {
size_t bytes = (it->second.bits + 7) / 8;
if (std::memcmp(it->second.expected, it->second.signal, bytes)) {
fstHandle facidx = it->first;
// TODO -- timescale, actually print out values with Verilator runtime, etc.
VL_PRINTF("Miscompare: %s @ %ld\n", m_outputs[facidx].fullName.c_str(),
m_time);
}
}
}
void VerilatedReplay::createMod() {
// TODO -- maybe get rid of the need for VM_PREFIX by generating these things
m_modp = new VM_PREFIX;
@ -150,6 +198,7 @@ void VerilatedReplay::createMod() {
void VerilatedReplay::eval() {
// TODO -- make eval, trace and final virtual methods of VerilatedModule?
m_modp->eval();
outputCheck();
}
void VerilatedReplay::trace() {

View File

@ -42,9 +42,12 @@ private:
struct FstSignal {
size_t bits;
vluint8_t* signal;
vluint8_t* expected;
FstSignal() {}
FstSignal(size_t _bits, vluint8_t* _signal):
bits(_bits), signal(_signal) { }
bits(_bits), signal(_signal), expected(NULL) { }
FstSignal(size_t _bits, vluint8_t* _signal, vluint8_t* _expected):
bits(_bits), signal(_signal), expected(_expected) { }
};
typedef std::map<fstHandle, FstSignal> SignalHandleMap;
typedef std::map<std::string, FstSignal> SignalNameMap;
@ -53,16 +56,21 @@ private:
void addSignals();
void addInput(const std::string& fullName, vluint8_t* signal, size_t size);
void addOutput(const std::string& fullName, vluint8_t* signal, size_t size);
void outputCheck();
void eval();
void trace();
void final();
void fstCb(uint64_t time, fstHandle facidx, const unsigned char* value,
uint32_t len);
void handleInput(fstHandle facidx, const unsigned char* valuep, uint32_t len);
void handleOutput(fstHandle facidx, const unsigned char* valuep, 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);
static void copyValue(unsigned char* to, const unsigned char* valuep, uint32_t len);
std::string m_fstName;
double& m_simTime;
VM_PREFIX* m_modp;

View File

@ -37,6 +37,7 @@ int main(int argc, char** argv) {
VL_PRINTF("FST = %s\n", fstFilename.c_str());
VerilatedReplay replay(fstFilename, simTime);
if (replay.init()) exit(-1);
if (replay.replay()) exit(-1);

View File

@ -7,14 +7,8 @@ void VlrGenerator::searchFst() {
VerilatedReplayCommon::searchFst(m_opts.scope());
}
void VlrGenerator::emitVltCode() {
// TODO -- use V3OutCFile
cout << "#include \"verilated_replay.h\"" << endl;
cout << endl;
cout << "void VerilatedReplay::addSignals() {" << endl;
for (VarMap::iterator it = m_inputs.begin(); it != m_inputs.end(); ++it) {
string sigName(it->second.fullName);
string VlrGenerator::replayName(const string& fullName) {
string sigName(fullName);
// TODO -- add a trailing dot for the user if they don't
if (m_opts.replayTop()) {
@ -28,11 +22,34 @@ void VlrGenerator::emitVltCode() {
sigName = sigName.substr(replayTop.length());
}
// TODO -- need to be able to specify a new top level
return sigName;
}
void VlrGenerator::emitVltCode() {
// TODO -- use V3OutCFile
cout << "#include \"verilated_replay.h\"" << endl;
cout << endl;
cout << "void VerilatedReplay::addSignals() {" << endl;
for (VarMap::iterator it = m_inputs.begin(); it != m_inputs.end(); ++it) {
string sigName = replayName(it->second.fullName);
cout << " addInput(\"" << it->second.fullName <<
"\", &(m_modp->" << sigName <<
"), " << it->second.hier.u.var.length << ");" << endl;
// TODO -- sizof check (FST vs VLT)
}
if (m_opts.checkOutputs()) {
for (VarMap::iterator it = m_outputs.begin(); it != m_outputs.end(); ++it) {
string sigName = replayName(it->second.fullName);
cout << " addOutput(\"" << it->second.fullName <<
"\", &(m_modp->" << sigName <<
"), " << it->second.hier.u.var.length << ");" << endl;
// TODO -- sizof check (FST vs VLT)
}
}
cout << "}" << endl;
}

View File

@ -38,6 +38,7 @@ public:
// METHODS
VlrOptions& opts() { return m_opts; }
void searchFst();
std::string replayName(const std::string& fullName);
void emitVltCode();
private:
typedef std::list<std::string> StrList;

View File

@ -39,7 +39,8 @@ void VlrOptions::parseOptsList(int argc, char** argv) {
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; }
else if (onoff (sw, "-check-outputs", flag/*ref*/) ) { m_checkOutputs = flag; }
else if (onoff (sw, "-vlt", flag/*ref*/) ) { m_vlt = flag; }
//// Parameterized switches
else if (!strcmp(sw, "-debug") ) {
V3Error::debugDefault(3);

View File

@ -28,14 +28,15 @@ class VlrOptions {
public:
// CONSTRUCTORS
VlrOptions(VerilatedReplayCommon* replayp):
m_fst(NULL), m_replayTop(NULL), m_scope(NULL), m_vlt(false),
m_replayp(replayp)
m_checkOutputs(false), m_fst(NULL), m_replayTop(NULL), m_scope(NULL),
m_vlt(false), m_replayp(replayp)
{}
~VlrOptions() {}
// METHODS
void parseOptsList(int argc, char** argv);
bool checkOutputs() { return m_checkOutputs; }
const char* fst() { return m_fst; }
const char* replayTop() { return m_replayTop; }
const char* scope() { return m_scope; }
@ -45,7 +46,9 @@ private:
std::string version();
bool onoff(const char* sw, const char* arg, bool& flag);
void readSignalList(const char* filename);
void outputCheck();
bool m_checkOutputs;
char* m_fst;
char* m_replayTop;
char* m_scope;