For --trace-fst, save enum decoding information, bug1358.

This commit is contained in:
Wilson Snyder 2018-10-08 07:21:22 -04:00
parent 870918a788
commit cc45a3dd72
9 changed files with 358 additions and 30 deletions

View File

@ -5,6 +5,11 @@ The contributors that suggested a given feature are shown in []. Thanks!
* Verilator 4.005 devel
*** For --trace-fst, save enum decoding information, bug1358. [Sergi Granell]
(To visualize enumeration data you must use GTKwave 3.3.95 or newer.)
*** For --trace-fst, instead of *.fst.hier, put data into *.fst. [Tony Bybell]
* Verilator 4.004 2018-10-6

View File

@ -795,6 +795,8 @@ char *geom_handle_nam;
char *valpos_handle_nam;
char *curval_handle_nam;
char *tchn_handle_nam;
fstEnumHandle max_enumhandle;
};
@ -2305,7 +2307,7 @@ if(xc && path && path[0])
const unsigned char *path2 = (const unsigned char *)path;
PPvoid_t pv;
#else
char *path2 = alloca(slen + 1); /* judy lacks const qualifier in its JudyHSIns definition */
char *path2 = (char *)alloca(slen + 1); /* judy lacks const qualifier in its JudyHSIns definition */
PPvoid_t pv;
strcpy(path2, path);
#endif
@ -2726,6 +2728,111 @@ if(xc)
}
fstEnumHandle fstWriterCreateEnumTable(void *ctx, const char *name, uint32_t elem_count, unsigned int min_valbits, const char **literal_arr, const char **val_arr)
{
fstEnumHandle handle = 0;
unsigned int *literal_lens = NULL;
unsigned int *val_lens = NULL;
int lit_len_tot = 0;
int val_len_tot = 0;
int name_len;
char elem_count_buf[16];
int elem_count_len;
int total_len;
int pos = 0;
char *attr_str = NULL;
if(ctx && name && literal_arr && val_arr && (elem_count != 0))
{
struct fstWriterContext *xc = (struct fstWriterContext *)ctx;
uint32_t i;
name_len = strlen(name);
elem_count_len = sprintf(elem_count_buf, "%" PRIu32, elem_count);
literal_lens = (unsigned int *)calloc(elem_count, sizeof(unsigned int));
val_lens = (unsigned int *)calloc(elem_count, sizeof(unsigned int));
for(i=0;i<elem_count;i++)
{
literal_lens[i] = strlen(literal_arr[i]);
lit_len_tot += fstUtilityBinToEscConvertedLen((unsigned char*)literal_arr[i], literal_lens[i]);
val_lens[i] = strlen(val_arr[i]);
val_len_tot += fstUtilityBinToEscConvertedLen((unsigned char*)val_arr[i], val_lens[i]);
if(min_valbits > 0)
{
if(val_lens[i] < min_valbits)
{
val_len_tot += (min_valbits - val_lens[i]); /* additional converted len is same for '0' character */
}
}
}
total_len = name_len + 1 + elem_count_len + 1 + lit_len_tot + elem_count + val_len_tot + elem_count;
attr_str = (char*)malloc(total_len);
pos = 0;
memcpy(attr_str+pos, name, name_len);
pos += name_len;
attr_str[pos++] = ' ';
memcpy(attr_str+pos, elem_count_buf, elem_count_len);
pos += elem_count_len;
attr_str[pos++] = ' ';
for(i=0;i<elem_count;i++)
{
pos += fstUtilityBinToEsc((unsigned char*)attr_str+pos, (unsigned char*)literal_arr[i], literal_lens[i]);
attr_str[pos++] = ' ';
}
for(i=0;i<elem_count;i++)
{
if(min_valbits > 0)
{
if(val_lens[i] < min_valbits)
{
memset(attr_str+pos, '0', min_valbits - val_lens[i]);
pos += (min_valbits - val_lens[i]);
}
}
pos += fstUtilityBinToEsc((unsigned char*)attr_str+pos, (unsigned char*)val_arr[i], val_lens[i]);
attr_str[pos++] = ' ';
}
attr_str[pos-1] = 0;
#ifdef FST_DEBUG
fprintf(stderr, FST_APIMESS"fstWriterCreateEnumTable() total_len: %d, pos: %d\n", total_len, pos);
fprintf(stderr, FST_APIMESS"*%s*\n", attr_str);
#endif
fstWriterSetAttrBegin(xc, FST_AT_MISC, FST_MT_ENUMTABLE, attr_str, handle = ++xc->max_enumhandle);
free(attr_str);
free(val_lens);
free(literal_lens);
}
return(handle);
}
void fstWriterEmitEnumTableRef(void *ctx, fstEnumHandle handle)
{
struct fstWriterContext *xc = (struct fstWriterContext *)ctx;
if(xc && handle)
{
fstWriterSetAttrBegin(xc, FST_AT_MISC, FST_MT_ENUMTABLE, NULL, handle);
}
}
/*
* value and time change emission
*/
@ -6503,9 +6610,46 @@ if(base && *base)
/*** ***/
/************************/
int fstUtilityBinToEsc(unsigned char *d, unsigned char *s, int len)
int fstUtilityBinToEscConvertedLen(const unsigned char *s, int len)
{
unsigned char *src = s;
const unsigned char *src = s;
int dlen = 0;
int i;
for(i=0;i<len;i++)
{
switch(src[i])
{
case '\a': /* fallthrough */
case '\b': /* fallthrough */
case '\f': /* fallthrough */
case '\n': /* fallthrough */
case '\r': /* fallthrough */
case '\t': /* fallthrough */
case '\v': /* fallthrough */
case '\'': /* fallthrough */
case '\"': /* fallthrough */
case '\\': /* fallthrough */
case '\?': dlen += 2; break;
default: if((src[i] > ' ') && (src[i] <= '~')) /* no white spaces in output */
{
dlen++;
}
else
{
dlen += 4;
}
break;
}
}
return(dlen);
}
int fstUtilityBinToEsc(unsigned char *d, const unsigned char *s, int len)
{
const unsigned char *src = s;
unsigned char *dst = d;
unsigned char val;
int i;
@ -6604,3 +6748,76 @@ for(i=0;i<len;i++)
return(dst - s);
}
struct fstETab *fstUtilityExtractEnumTableFromString(const char *s)
{
struct fstETab *et = NULL;
int num_spaces = 0;
int i;
int newlen;
if(s)
{
const char *csp = strchr(s, ' ');
int cnt = atoi(csp+1);
for(;;)
{
csp = strchr(csp+1, ' ');
if(csp) { num_spaces++; } else { break; }
}
if(num_spaces == (2*cnt))
{
char *sp, *sp2;
et = (struct fstETab*)calloc(1, sizeof(struct fstETab));
et->elem_count = cnt;
et->name = strdup(s);
et->literal_arr = (char**)calloc(cnt, sizeof(char *));
et->val_arr = (char**)calloc(cnt, sizeof(char *));
sp = strchr(et->name, ' ');
*sp = 0;
sp = strchr(sp+1, ' ');
for(i=0;i<cnt;i++)
{
sp2 = strchr(sp+1, ' ');
*(char*)sp2 = 0;
et->literal_arr[i] = sp+1;
sp = sp2;
newlen = fstUtilityEscToBin(NULL, (unsigned char*)et->literal_arr[i], strlen(et->literal_arr[i]));
et->literal_arr[i][newlen] = 0;
}
for(i=0;i<cnt;i++)
{
sp2 = strchr(sp+1, ' ');
if(sp2) { *sp2 = 0; }
et->val_arr[i] = sp+1;
sp = sp2;
newlen = fstUtilityEscToBin(NULL, (unsigned char*)et->val_arr[i], strlen(et->val_arr[i]));
et->val_arr[i][newlen] = 0;
}
}
}
return(et);
}
void fstUtilityFreeEnumTable(struct fstETab *etab)
{
if(etab)
{
free(etab->literal_arr);
free(etab->val_arr);
free(etab->name);
free(etab);
}
}

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2009-2017 Tony Bybell.
* Copyright (c) 2009-2018 Tony Bybell.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
@ -39,6 +39,7 @@ extern "C" {
#define FST_RDLOAD "FSTLOAD | "
typedef uint32_t fstHandle;
typedef uint32_t fstEnumHandle;
enum fstWriterPackType {
FST_WR_PT_ZLIB = 0,
@ -196,9 +197,10 @@ enum fstMiscType {
FST_MT_SOURCESTEM = 4, /* use fstWriterSetSourceStem() to emit */
FST_MT_SOURCEISTEM = 5, /* use fstWriterSetSourceInstantiationStem() to emit */
FST_MT_VALUELIST = 6, /* use fstWriterSetValueList() to emit, followed by fstWriterCreateVar*() */
FST_MT_UNKNOWN = 7,
FST_MT_ENUMTABLE = 7, /* use fstWriterCreateEnumTable() and fstWriterEmitEnumTableRef() to emit */
FST_MT_UNKNOWN = 8,
FST_MT_MAX = 7
FST_MT_MAX = 8
};
enum fstArrayType {
@ -228,7 +230,10 @@ enum fstEnumValueType {
FST_EV_SV_UNSIGNED_LONGINT = 12,
FST_EV_SV_UNSIGNED_BYTE = 13,
FST_EV_MAX = 13
FST_EV_REG = 14,
FST_EV_TIME = 15,
FST_EV_MAX = 15
};
enum fstPackType {
@ -324,11 +329,21 @@ union {
};
struct fstETab
{
char *name;
uint32_t elem_count;
char **literal_arr;
char **val_arr;
};
/*
* writer functions
*/
void fstWriterClose(void *ctx);
void * fstWriterCreate(const char *nam, int use_compressed_hier);
fstEnumHandle fstWriterCreateEnumTable(void *ctx, const char *name, uint32_t elem_count, unsigned int min_valbits, const char **literal_arr, const char **val_arr);
/* used for Verilog/SV */
fstHandle fstWriterCreateVar(void *ctx, enum fstVarType vt, enum fstVarDir vd,
uint32_t len, const char *nam, fstHandle aliasHandle);
@ -337,9 +352,10 @@ fstHandle fstWriterCreateVar(void *ctx, enum fstVarType vt, enum fstVarDir
fstHandle fstWriterCreateVar2(void *ctx, enum fstVarType vt, enum fstVarDir vd,
uint32_t len, const char *nam, fstHandle aliasHandle,
const char *type, enum fstSupplementalVarType svt, enum fstSupplementalDataType sdt);
void fstWriterEmitDumpActive(void *ctx, int enable);
void fstWriterEmitEnumTableRef(void *ctx, fstEnumHandle handle);
void fstWriterEmitValueChange(void *ctx, fstHandle handle, const void *val);
void fstWriterEmitVariableLengthValueChange(void *ctx, fstHandle handle, const void *val, uint32_t len);
void fstWriterEmitDumpActive(void *ctx, int enable);
void fstWriterEmitTimeChange(void *ctx, uint64_t tim);
void fstWriterFlushContext(void *ctx);
int fstWriterGetDumpSizeLimitReached(void *ctx);
@ -422,8 +438,12 @@ void fstReaderSetVcdExtensions(void *ctx, int enable);
/*
* utility functions
*/
int fstUtilityBinToEsc(unsigned char *d, unsigned char *s, int len);
int fstUtilityBinToEscConvertedLen(const unsigned char *s, int len); /* used for mallocs for fstUtilityBinToEsc() */
int fstUtilityBinToEsc(unsigned char *d, const unsigned char *s, int len);
int fstUtilityEscToBin(unsigned char *d, unsigned char *s, int len);
struct fstETab *fstUtilityExtractEnumTableFromString(const char *s);
void fstUtilityFreeEnumTable(struct fstETab *etab); /* must use to free fstETab properly */
#ifdef __cplusplus
}

View File

@ -94,8 +94,16 @@ void VerilatedFst::module(const std::string& name) {
//=============================================================================
// Decl
void VerilatedFst::declSymbol(vluint32_t code, const char* name, fstVarDir vardir,
fstVarType vartype,
void VerilatedFst::declDTypeEnum(int dtypenum, const char* name, vluint32_t elements,
unsigned int minValbits,
const char** itemNamesp, const char** itemValuesp) {
fstEnumHandle enumNum = fstWriterCreateEnumTable(m_fst, name, elements,
minValbits, itemNamesp, itemValuesp);
m_local2fstdtype[dtypenum] = enumNum;
}
void VerilatedFst::declSymbol(vluint32_t code, const char* name,
int dtypenum, fstVarDir vardir, fstVarType vartype,
int arraynum, vluint32_t len) {
std::pair<Code2SymbolType::iterator, bool> p
= m_code2symbol.insert(std::make_pair(code, (fstHandle)(0)));
@ -135,6 +143,10 @@ void VerilatedFst::declSymbol(vluint32_t code, const char* name, fstVarDir vardi
name_ss << "(" << arraynum << ")";
std::string name_str = name_ss.str();
if (dtypenum > 0) {
fstEnumHandle enumNum = m_local2fstdtype[dtypenum];
fstWriterEmitEnumTableRef(m_fst, enumNum);
}
if (p.second) { // New
p.first->second = fstWriterCreateVar(m_fst, vartype, vardir, len, name_str.c_str(), 0);
assert(p.first->second);

View File

@ -43,6 +43,7 @@ typedef void (*VerilatedFstCallback_t)(VerilatedFst* vcdp, void* userthis, vluin
class VerilatedFst {
typedef std::map<vluint32_t, fstHandle> Code2SymbolType;
typedef std::map<int, fstEnumHandle> Local2FstDtype;
typedef std::vector<VerilatedFstCallInfo*> CallbackVec;
private:
void* m_fst;
@ -52,11 +53,12 @@ private:
std::string m_module;
CallbackVec m_callbacks; ///< Routines to perform dumping
Code2SymbolType m_code2symbol;
Local2FstDtype m_local2fstdtype;
std::list<std::string> m_curScope;
// CONSTRUCTORS
VL_UNCOPYABLE(VerilatedFst);
void declSymbol(vluint32_t code, const char* name,
fstVarDir vardir, fstVarType vartype,
int dtypenum, fstVarDir vardir, fstVarType vartype,
int arraynum, vluint32_t len);
// helpers
std::vector<char> m_valueStrBuffer;
@ -96,30 +98,40 @@ public:
/// Inside dumping routines, declare a module
void module(const std::string& name);
/// Inside dumping routines, declare a data type
void declDTypeEnum(int dtypenum, const char* name, vluint32_t elements,
unsigned int minValbits,
const char** itemNamesp, const char** itemValuesp);
/// Inside dumping routines, declare a signal
void declBit(vluint32_t code, const char* name, fstVarDir vardir, fstVarType vartype,
void declBit(vluint32_t code, const char* name,
int dtypenum, fstVarDir vardir, fstVarType vartype,
int arraynum) {
declSymbol(code, name, vardir, vartype, arraynum, 1);
declSymbol(code, name, dtypenum, vardir, vartype, arraynum, 1);
}
void declBus(vluint32_t code, const char* name, fstVarDir vardir, fstVarType vartype,
void declBus(vluint32_t code, const char* name,
int dtypenum, fstVarDir vardir, fstVarType vartype,
int arraynum, int msb, int lsb) {
declSymbol(code, name, vardir, vartype, arraynum, msb - lsb + 1);
declSymbol(code, name, dtypenum, vardir, vartype, arraynum, msb - lsb + 1);
}
void declDouble(vluint32_t code, const char* name, fstVarDir vardir, fstVarType vartype,
void declDouble(vluint32_t code, const char* name,
int dtypenum, fstVarDir vardir, fstVarType vartype,
int arraynum) {
declSymbol(code, name, vardir, vartype, arraynum, 2);
declSymbol(code, name, dtypenum, vardir, vartype, arraynum, 2);
}
void declFloat(vluint32_t code, const char* name, fstVarDir vardir, fstVarType vartype,
void declFloat(vluint32_t code, const char* name,
int dtypenum, fstVarDir vardir, fstVarType vartype,
int arraynum) {
declSymbol(code, name, vardir, vartype, arraynum, 1);
declSymbol(code, name, dtypenum, vardir, vartype, arraynum, 1);
}
void declQuad(vluint32_t code, const char* name, fstVarDir vardir, fstVarType vartype,
void declQuad(vluint32_t code, const char* name,
int dtypenum, fstVarDir vardir, fstVarType vartype,
int arraynum, int msb, int lsb) {
declSymbol(code, name, vardir, vartype, arraynum, msb - lsb + 1);
declSymbol(code, name, dtypenum, vardir, vartype, arraynum, msb - lsb + 1);
}
void declArray(vluint32_t code, const char* name, fstVarDir vardir, fstVarType vartype,
void declArray(vluint32_t code, const char* name,
int dtypenum, fstVarDir vardir, fstVarType vartype,
int arraynum, int msb, int lsb) {
declSymbol(code, name, vardir, vartype, arraynum, msb - lsb + 1);
declSymbol(code, name, dtypenum, vardir, vartype, arraynum, msb - lsb + 1);
}
/// Inside dumping routines, dump one signal if it has changed

View File

@ -2715,8 +2715,15 @@ void EmitCImp::main(AstNodeModule* modp, bool slow, bool fast) {
// Tracing routines
class EmitCTrace : EmitCStmts {
// NODE STATE/TYPES
// Cleared on netlist
// AstNode::user1() -> int. Enum number
AstUser1InUse m_inuser1;
// MEMBERS
AstCFunc* m_funcp; // Function we're in now
bool m_slow; // Making slow file
int m_enumNum; // Enumeration number (whole netlist)
// METHODS
void newOutCFile(int filenum) {
@ -2819,7 +2826,7 @@ class EmitCTrace : EmitCStmts {
return varp->isSc() && varp->isScUint();
}
void emitTraceInitOne(AstTraceDecl* nodep) {
void emitTraceInitOne(AstTraceDecl* nodep, int enumNum) {
if (nodep->dtypep()->basicp()->isDouble()) {
puts("vcdp->declDouble");
} else if (nodep->isWide()) {
@ -2838,6 +2845,7 @@ class EmitCTrace : EmitCStmts {
putsQuoted(nodep->showname());
// Direction
if (v3Global.opt.traceFormat() == TraceFormat::FST) {
puts(","+cvtToStr(enumNum));
// fstVarDir
if (nodep->declInout()) puts(",FST_VD_INOUT");
else if (nodep->declInput()) puts(",FST_VD_INPUT");
@ -2900,6 +2908,49 @@ class EmitCTrace : EmitCStmts {
puts(");");
}
int emitTraceDeclDType(AstNodeDType* nodep) {
// Return enum number or -1 for none
if (v3Global.opt.traceFormat() == TraceFormat::FST) {
// Skip over refs-to-refs, but stop before final ref so can get data type name
// Alternatively back in V3Width we could have push enum names from upper typedefs
if (AstEnumDType* enump = VN_CAST(nodep->skipRefToEnump(), EnumDType)) {
int enumNum = enump->user1();
if (!enumNum) {
enumNum = ++m_enumNum;
enump->user1(enumNum);
int nvals = 0;
puts("{\n");
puts("const char* __VenumItemNames[]\n");
puts("= {");
for (AstEnumItem* itemp = enump->itemsp(); itemp;
itemp=VN_CAST(itemp->nextp(), EnumItem)) {
if (++nvals > 1) puts(", ");
putbs("\""+itemp->prettyName()+"\"");
}
puts("};\n");
nvals = 0;
puts("const char* __VenumItemValues[]\n");
puts("= {");
for (AstEnumItem* itemp = enump->itemsp(); itemp;
itemp=VN_CAST(itemp->nextp(), EnumItem)) {
AstConst* constp = VN_CAST(itemp->valuep(), Const);
if (++nvals > 1) puts(", ");
putbs("\""+constp->num().displayed(nodep->fileline(), "%0b")+"\"");
}
puts("};\n");
puts("vcdp->declDTypeEnum("+cvtToStr(enumNum)
+", \""+enump->prettyName()+"\", "
+cvtToStr(nvals)
+", "+cvtToStr(enump->widthMin())
+", __VenumItemNames, __VenumItemValues);\n");
puts("}\n");
}
return enumNum;
}
}
return -1;
}
void emitTraceChangeOne(AstTraceInc* nodep, int arrayindex) {
iterateAndNextNull(nodep->precondsp());
string full = ((m_funcp->funcType() == AstCFuncType::TRACE_FULL
@ -3013,12 +3064,13 @@ class EmitCTrace : EmitCStmts {
m_funcp = NULL;
}
virtual void visit(AstTraceDecl* nodep) {
int enumNum = emitTraceDeclDType(nodep->dtypep());
if (nodep->arrayRange().ranged()) {
puts("{int i; for (i=0; i<"+cvtToStr(nodep->arrayRange().elements())+"; i++) {\n");
emitTraceInitOne(nodep);
emitTraceInitOne(nodep, enumNum);
puts("}}\n");
} else {
emitTraceInitOne(nodep);
emitTraceInitOne(nodep, enumNum);
puts("\n");
}
}
@ -3041,6 +3093,7 @@ public:
explicit EmitCTrace(bool slow) {
m_funcp = NULL;
m_slow = slow;
m_enumNum = 0;
}
virtual ~EmitCTrace() {}
void main() {

View File

@ -1,5 +1,5 @@
$date
Sun Oct 7 21:45:40 2018
Mon Oct 8 07:13:10 2018
$end
$version
@ -33,7 +33,10 @@ $var real 64 3 v_real $end
$var real 64 4 v_arr_real(0) $end
$var real 64 5 v_arr_real(1) $end
$var logic 64 6 v_str32x2 $end
$attrbegin misc 07 t.enumed_t 4 ZERO ONE TWO THREE 00000000000000000000000000000000 00000000000000000000000000000001 00000000000000000000000000000010 00000000000000000000000000000011 1 $end
$attrbegin misc 07 "" 1 $end
$var logic 32 7 v_enumed $end
$attrbegin misc 07 "" 1 $end
$var logic 32 8 v_enumed2 $end
$scope module unnamedblk1 $end
$var integer 32 9 b $end

View File

@ -1,5 +1,5 @@
$date
Sun Oct 7 21:45:42 2018
Mon Oct 8 07:13:11 2018
$end
$version
@ -33,7 +33,10 @@ $var real 64 3 v_real $end
$var real 64 4 v_arr_real(0) $end
$var real 64 5 v_arr_real(1) $end
$var logic 64 6 v_str32x2 $end
$attrbegin misc 07 t.enumed_t 4 ZERO ONE TWO THREE 00000000000000000000000000000000 00000000000000000000000000000001 00000000000000000000000000000010 00000000000000000000000000000011 1 $end
$attrbegin misc 07 "" 1 $end
$var logic 32 7 v_enumed $end
$attrbegin misc 07 "" 1 $end
$var logic 32 8 v_enumed2 $end
$scope module unnamedblk1 $end
$var integer 32 9 b $end

View File

@ -1,5 +1,5 @@
$date
Sun Oct 7 21:45:44 2018
Mon Oct 8 07:13:12 2018
$end
$version
@ -72,8 +72,11 @@ $var logic 32 A data $end
$upscope $end
$scope module v_str32x2(1) $end
$var logic 32 B data $end
$attrbegin misc 07 t.enumed_t 4 ZERO ONE TWO THREE 00000000000000000000000000000000 00000000000000000000000000000001 00000000000000000000000000000010 00000000000000000000000000000011 1 $end
$upscope $end
$attrbegin misc 07 "" 1 $end
$var logic 32 C v_enumed $end
$attrbegin misc 07 "" 1 $end
$var logic 32 D v_enumed2 $end
$scope module unnamedblk1 $end
$var integer 32 E b $end