read_vcd factor Vdd out of VcdReader

Signed-off-by: James Cherry <cherry@parallaxsw.com>
This commit is contained in:
James Cherry 2022-10-26 14:27:30 -07:00
parent 8345ac05e7
commit 01d15e05b2
1 changed files with 236 additions and 119 deletions

View File

@ -47,50 +47,6 @@ typedef vector<string> VcdScope;
// Much better syntax definition // Much better syntax definition
// https://web.archive.org/web/20120323132708/http://www.beyondttl.com/vcd.php // https://web.archive.org/web/20120323132708/http://www.beyondttl.com/vcd.php
class VcdReader : public StaState
{
public:
VcdReader(StaState *sta);
void read(const char *filename);
void reportWaveforms();
private:
void parseTimescale();
void parseVar();
void parseScope();
void parseUpscope();
void parseVarValues();
void makeVarIdMap();
void appendVarValue(string id,
char value);
string getToken();
string readStmtString();
vector<string> readStmtTokens();
VcdValues &values(VcdVar &var);
gzFile stream_;
string token_;
const char *filename_;
int file_line_;
int stmt_line_;
string date_;
string comment_;
string version_;
double time_scale_;
string time_unit_;
double time_unit_scale_;
vector<VcdVar> vars_;
size_t max_var_name_length_;
int max_var_width_;
map<string, VcdValues> id_values_map_;
VarTime time_;
VarTime prev_time_;
VarTime min_delta_time_;
VarTime time_max_;
VcdScope scope_;
};
class VcdVar class VcdVar
{ {
public: public:
@ -111,6 +67,56 @@ private:
string id_; string id_;
}; };
class Vcd : public StaState
{
public:
Vcd(StaState *sta);
VcdValues &values(VcdVar &var);
void reportWaveforms();
const string &date() const { return date_; }
void setDate(const string &date);
const string &comment() const { return comment_; }
void setComment(const string &comment);
const string &version() const { return version_; }
void setVersion(const string &version);
double timeScale() const { return time_scale_; }
void setTimeScale(double time_scale);
const string &timeUnit() const { return time_unit_; }
void setTimeUnit(const string &time_unit,
double time_unit_scale);
VarTime timeMax() const { return time_max_; }
void setTimeMax(VarTime time_max);
VarTime minDeltaTime() const { return min_delta_time_; }
void setMinDeltaTime(VarTime min_delta_time);
void makeVar(string &name,
VcdVar::VarType type,
int width,
string &id);
bool varIdValid(string &id);
void varAppendValue(string &id,
VarTime time,
char value);
void varAppendBusValue(string &id,
VarTime time,
int64_t bus_value);
private:
string date_;
string comment_;
string version_;
double time_scale_;
string time_unit_;
double time_unit_scale_;
vector<VcdVar> vars_;
size_t max_var_name_length_;
int max_var_width_;
map<string, VcdValues> id_values_map_;
VarTime min_delta_time_;
VarTime time_max_;
};
class VcdValue class VcdValue
{ {
public: public:
@ -128,19 +134,52 @@ private:
uint64_t bus_value_; uint64_t bus_value_;
}; };
////////////////////////////////////////////////////////////////
class VcdReader : public StaState
{
public:
VcdReader(StaState *sta);
Vcd read(const char *filename);
private:
void parseTimescale();
void setTimeUnit(const string &time_unit);
void parseVar();
void parseScope();
void parseUpscope();
void parseVarValues();
string getToken();
string readStmtString();
vector<string> readStmtTokens();
gzFile stream_;
string token_;
const char *filename_;
int file_line_;
int stmt_line_;
Vcd *vcd_;
VarTime time_;
VarTime prev_time_;
VcdScope scope_;
};
void void
readVcdFile(const char *filename, readVcdFile(const char *filename,
StaState *sta) StaState *sta)
{ {
VcdReader reader(sta); VcdReader reader(sta);
reader.read(filename); Vcd vcd = reader.read(filename);
reader.reportWaveforms(); vcd.reportWaveforms();
} }
void Vcd
VcdReader::read(const char *filename) VcdReader::read(const char *filename)
{ {
Vcd vcd(this);
vcd_ = &vcd;
stream_ = gzopen(filename, "r"); stream_ = gzopen(filename, "r");
if (stream_) { if (stream_) {
filename_ = filename; filename_ = filename;
@ -149,11 +188,11 @@ VcdReader::read(const char *filename)
string token = getToken(); string token = getToken();
while (!token.empty()) { while (!token.empty()) {
if (token == "$date") if (token == "$date")
date_ = readStmtString(); vcd_->setDate(readStmtString());
else if (token == "$comment") else if (token == "$comment")
comment_ = readStmtString(); vcd_->setComment(readStmtString());
else if (token == "$version") else if (token == "$version")
version_ = readStmtString(); vcd_->setVersion(readStmtString());
else if (token == "$timescale") else if (token == "$timescale")
parseTimescale(); parseTimescale();
else if (token == "$var") else if (token == "$var")
@ -162,11 +201,9 @@ VcdReader::read(const char *filename)
parseScope(); parseScope();
else if (token == "$upscope") else if (token == "$upscope")
parseUpscope(); parseUpscope();
else if (token == "$enddefinitions") { else if (token == "$enddefinitions")
// empty body // empty body
readStmtString(); readStmtString();
makeVarIdMap();
}
else if (token == "$dumpall") else if (token == "$dumpall")
parseVarValues(); parseVarValues();
else if (token == "$dumpvars") else if (token == "$dumpvars")
@ -180,18 +217,15 @@ VcdReader::read(const char *filename)
} }
gzclose(stream_); gzclose(stream_);
} }
return vcd;
} }
VcdReader::VcdReader(StaState *sta) : VcdReader::VcdReader(StaState *sta) :
StaState(sta), StaState(sta),
stmt_line_(0), stmt_line_(0),
time_unit_scale_(0.0), vcd_(nullptr),
max_var_name_length_(0),
max_var_width_(0),
time_(0), time_(0),
prev_time_(0), prev_time_(0)
min_delta_time_(std::numeric_limits<VarTime>::max()),
time_max_(0)
{ {
} }
@ -201,24 +235,30 @@ VcdReader::parseTimescale()
vector<string> tokens = readStmtTokens(); vector<string> tokens = readStmtTokens();
if (tokens.size() == 1) { if (tokens.size() == 1) {
size_t last; size_t last;
time_scale_ = std::stod(tokens[0], &last); vcd_->setTimeScale(std::stod(tokens[0], &last));
time_unit_ = tokens[0].substr(last); setTimeUnit(tokens[0].substr(last));
} }
else if (tokens.size() == 2) { else if (tokens.size() == 2) {
time_scale_ = std::stod(tokens[0]); vcd_->setTimeScale(std::stod(tokens[0]));
time_unit_ = tokens[1]; setTimeUnit(tokens[1]);
} }
else else
report_->fileError(800, filename_, stmt_line_, "timescale syntax error."); report_->fileError(800, filename_, stmt_line_, "timescale syntax error.");
}
if (time_unit_ == "fs") void
time_unit_scale_ = 1e-15; VcdReader::setTimeUnit(const string &time_unit)
else if (time_unit_ == "ps") {
time_unit_scale_ = 1e-12; double time_unit_scale = 1.0;
else if (time_unit_ == "ns") if (time_unit == "fs")
time_unit_scale_ = 1e-9; time_unit_scale = 1e-15;
else if (time_unit == "ps")
time_unit_scale = 1e-12;
else if (time_unit == "ns")
time_unit_scale = 1e-9;
else else
report_->fileError(801, filename_, stmt_line_, "Unknown timescale unit."); report_->fileError(801, filename_, stmt_line_, "Unknown timescale unit.");
vcd_->setTimeUnit(time_unit, time_unit_scale);;
} }
void void
@ -260,9 +300,7 @@ VcdReader::parseVar()
if (tokens.size() == 5) if (tokens.size() == 5)
name += tokens[4]; name += tokens[4];
vars_.push_back(VcdVar(name, type, width, id)); vcd_->makeVar(name, type, width, id);
max_var_name_length_ = std::max(max_var_name_length_, name.size());
max_var_width_ = std::max(max_var_width_, width);
} }
else else
report_->fileError(802, filename_, stmt_line_, "Variable syntax error."); report_->fileError(802, filename_, stmt_line_, "Variable syntax error.");
@ -283,16 +321,6 @@ VcdReader::parseUpscope()
scope_.pop_back(); scope_.pop_back();
} }
// Make entries for each ID used by variables.
void
VcdReader::makeVarIdMap()
{
for (VcdVar &var : vars_) {
const string &id = var.id();
id_values_map_[id].clear();
}
}
void void
VcdReader::parseVarValues() VcdReader::parseVarValues()
{ {
@ -302,64 +330,45 @@ VcdReader::parseVarValues()
prev_time_ = time_; prev_time_ = time_;
time_ = stoll(token.substr(1)); time_ = stoll(token.substr(1));
if (time_ > prev_time_) if (time_ > prev_time_)
min_delta_time_ = min(time_ - prev_time_, min_delta_time_); vcd_->setMinDeltaTime(min(time_ - prev_time_, vcd_->minDeltaTime()));
} }
else if (token[0] == '0' else if (token[0] == '0'
|| token[0] == '1' || token[0] == '1'
|| token[0] == 'X' || token[0] == 'X'
|| token[0] == 'U' || token[0] == 'U'
|| token[0] == 'Z') || token[0] == 'Z') {
appendVarValue(token.substr(1), token[0]); string id = token.substr(1);
if (!vcd_->varIdValid(id))
report_->fileError(804, filename_, stmt_line_,
"unknown variable %s", id.c_str());
vcd_->varAppendValue(id, time_, token[0]);
}
else if (token[0] == 'b') { else if (token[0] == 'b') {
if (token[1] == 'X' if (token[1] == 'X'
|| token[1] == 'U' || token[1] == 'U'
|| token[1] == 'Z') { || token[1] == 'Z') {
string id = getToken(); string id = getToken();
// Mixed 0/1/X/U not supported. if (!vcd_->varIdValid(id))
appendVarValue(id, token[1]); report_->fileError(804, filename_, stmt_line_,
"unknown variable %s", id.c_str());
// Bus mixed 0/1/X/U not supported.
vcd_->varAppendValue(id, time_, token[1]);
} }
else { else {
string bin = token.substr(1); string bin = token.substr(1);
char *end; char *end;
int64_t bus_value = strtol(bin.c_str(), &end, 2); int64_t bus_value = strtol(bin.c_str(), &end, 2);
string id = getToken(); string id = getToken();
auto values_itr = id_values_map_.find(id); if (!vcd_->varIdValid(id))
if (values_itr == id_values_map_.end())
report_->fileError(804, filename_, stmt_line_, report_->fileError(804, filename_, stmt_line_,
"unknown variable %s", id.c_str()); "unknown variable %s", id.c_str());
VcdValues &values = values_itr->second; else
values.push_back(VcdValue(time_, '\0', bus_value)); vcd_->varAppendBusValue(id, time_, bus_value);
} }
} }
token = getToken(); token = getToken();
} }
time_max_ = time_; vcd_->setTimeMax(time_);
}
void
VcdReader::appendVarValue(string id,
char value)
{
auto values_itr = id_values_map_.find(id);
if (values_itr == id_values_map_.end())
report_->fileError(805, filename_, stmt_line_,
"Unknown variable %s", id.c_str());
VcdValues &values = values_itr->second;
values.push_back(VcdValue(time_, value, 0));
}
VcdValues &
VcdReader::values(VcdVar &var)
{
if (id_values_map_.find(var.id()) == id_values_map_.end()) {
report_->error(805, "Unknown variable %s ID %s",
var.name().c_str(),
var.id().c_str());
static VcdValues empty;
return empty;
}
else
return id_values_map_[var.id()];
} }
string string
@ -415,8 +424,19 @@ VcdReader::getToken()
return token; return token;
} }
////////////////////////////////////////////////////////////////
Vcd::Vcd(StaState *sta) :
StaState(sta),
time_unit_scale_(0.0),
max_var_name_length_(0),
max_var_width_(0),
time_max_(0)
{
}
void void
VcdReader::reportWaveforms() Vcd::reportWaveforms()
{ {
report_->reportLine("Date: %s", date_.c_str()); report_->reportLine("Date: %s", date_.c_str());
report_->reportLine("Timescale: %.2f%s", time_scale_, time_unit_.c_str()); report_->reportLine("Timescale: %.2f%s", time_scale_, time_unit_.c_str());
@ -486,6 +506,103 @@ VcdReader::reportWaveforms()
//////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////
void
Vcd::setTimeUnit(const string &time_unit,
double time_unit_scale)
{
time_unit_ = time_unit;
time_unit_scale_ = time_unit_scale;
}
void
Vcd::setDate(const string &date)
{
date_ = date;
}
void
Vcd::setComment(const string &comment)
{
comment_ = comment;
}
void
Vcd::setVersion(const string &version)
{
version_ = version;
}
void
Vcd::setTimeScale(double time_scale)
{
time_scale_ = time_scale;
}
void
Vcd::setMinDeltaTime(VarTime min_delta_time)
{
min_delta_time_ = min_delta_time;
}
void
Vcd::setTimeMax(VarTime time_max)
{
time_max_ = time_max;
}
void
Vcd::makeVar(string &name,
VcdVar::VarType type,
int width,
string &id)
{
vars_.push_back(VcdVar(name, type, width, id));
max_var_name_length_ = std::max(max_var_name_length_, name.size());
max_var_width_ = std::max(max_var_width_, width);
// Make entry for var ID.
id_values_map_[id].clear();
}
bool
Vcd::varIdValid(string &id)
{
return id_values_map_.find(id) != id_values_map_.end();
}
void
Vcd::varAppendValue(string &id,
VarTime time,
char value)
{
VcdValues &values = id_values_map_[id];
values.push_back(VcdValue(time, value, 0));
}
void
Vcd::varAppendBusValue(string &id,
VarTime time,
int64_t bus_value)
{
VcdValues &values = id_values_map_[id];
values.push_back(VcdValue(time, '\0', bus_value));
}
VcdValues &
Vcd::values(VcdVar &var)
{
if (id_values_map_.find(var.id()) == id_values_map_.end()) {
report_->error(805, "Unknown variable %s ID %s",
var.name().c_str(),
var.id().c_str());
static VcdValues empty;
return empty;
}
else
return id_values_map_[var.id()];
}
////////////////////////////////////////////////////////////////
VcdVar::VcdVar(string name, VcdVar::VcdVar(string name,
VarType type, VarType type,
int width, int width,