read_vcd factor Vdd out of VcdReader
Signed-off-by: James Cherry <cherry@parallaxsw.com>
This commit is contained in:
parent
8345ac05e7
commit
01d15e05b2
|
|
@ -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,
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue