2022-08-17 07:43:42 +02:00
|
|
|
|
// OpenSTA, Static Timing Analyzer
|
|
|
|
|
|
// Copyright (c) 2022, Parallax Software, Inc.
|
|
|
|
|
|
//
|
|
|
|
|
|
// This program is free software: you can redistribute it and/or modify
|
|
|
|
|
|
// it under the terms of the GNU General Public License as published by
|
|
|
|
|
|
// the Free Software Foundation, either version 3 of the License, or
|
|
|
|
|
|
// (at your option) any later version.
|
|
|
|
|
|
//
|
|
|
|
|
|
// This program 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.
|
|
|
|
|
|
//
|
|
|
|
|
|
// You should have received a copy of the GNU General Public License
|
|
|
|
|
|
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|
|
|
|
|
|
|
|
|
|
|
#include <cctype>
|
2022-11-03 02:40:51 +01:00
|
|
|
|
#include <cinttypes>
|
2022-08-17 07:43:42 +02:00
|
|
|
|
|
2022-10-26 23:53:42 +02:00
|
|
|
|
#include "VcdReader.hh"
|
2022-08-17 07:43:42 +02:00
|
|
|
|
|
2022-10-13 01:42:12 +02:00
|
|
|
|
#include "Zlib.hh"
|
|
|
|
|
|
#include "Report.hh"
|
2022-10-29 03:10:29 +02:00
|
|
|
|
#include "Error.hh"
|
2022-10-26 21:43:10 +02:00
|
|
|
|
#include "StringUtil.hh"
|
2022-10-13 01:42:12 +02:00
|
|
|
|
|
2022-08-17 07:43:42 +02:00
|
|
|
|
namespace sta {
|
|
|
|
|
|
|
|
|
|
|
|
using std::isspace;
|
|
|
|
|
|
|
2022-10-26 02:09:34 +02:00
|
|
|
|
// Very imprecise syntax definition
|
|
|
|
|
|
// https://en.wikipedia.org/wiki/Value_change_dump#Structure.2FSyntax
|
|
|
|
|
|
// Much better syntax definition
|
|
|
|
|
|
// https://web.archive.org/web/20120323132708/http://www.beyondttl.com/vcd.php
|
|
|
|
|
|
|
2022-10-26 23:27:30 +02:00
|
|
|
|
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_;
|
2022-10-28 19:52:27 +02:00
|
|
|
|
VcdTime time_;
|
|
|
|
|
|
VcdTime prev_time_;
|
2022-10-26 23:27:30 +02:00
|
|
|
|
VcdScope scope_;
|
|
|
|
|
|
};
|
|
|
|
|
|
|
2022-10-26 23:59:51 +02:00
|
|
|
|
Vcd
|
|
|
|
|
|
readVcdFile(const char *filename,
|
|
|
|
|
|
StaState *sta)
|
2022-08-17 07:43:42 +02:00
|
|
|
|
|
|
|
|
|
|
{
|
2022-10-13 01:42:12 +02:00
|
|
|
|
VcdReader reader(sta);
|
2022-10-26 23:59:51 +02:00
|
|
|
|
return reader.read(filename);
|
2022-08-17 07:43:42 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
2022-10-26 23:27:30 +02:00
|
|
|
|
Vcd
|
2022-08-17 07:43:42 +02:00
|
|
|
|
VcdReader::read(const char *filename)
|
|
|
|
|
|
{
|
2022-10-26 23:27:30 +02:00
|
|
|
|
Vcd vcd(this);
|
|
|
|
|
|
vcd_ = &vcd;
|
2022-08-17 07:43:42 +02:00
|
|
|
|
stream_ = gzopen(filename, "r");
|
|
|
|
|
|
if (stream_) {
|
2022-10-13 01:42:12 +02:00
|
|
|
|
filename_ = filename;
|
|
|
|
|
|
file_line_ = 1;
|
|
|
|
|
|
stmt_line_ = 1;
|
2022-08-17 07:43:42 +02:00
|
|
|
|
string token = getToken();
|
|
|
|
|
|
while (!token.empty()) {
|
|
|
|
|
|
if (token == "$date")
|
2022-10-26 23:27:30 +02:00
|
|
|
|
vcd_->setDate(readStmtString());
|
2022-10-26 02:09:34 +02:00
|
|
|
|
else if (token == "$comment")
|
2022-10-26 23:27:30 +02:00
|
|
|
|
vcd_->setComment(readStmtString());
|
2022-08-17 07:43:42 +02:00
|
|
|
|
else if (token == "$version")
|
2022-10-26 23:27:30 +02:00
|
|
|
|
vcd_->setVersion(readStmtString());
|
2022-08-17 07:43:42 +02:00
|
|
|
|
else if (token == "$timescale")
|
|
|
|
|
|
parseTimescale();
|
2022-10-26 02:09:34 +02:00
|
|
|
|
else if (token == "$var")
|
2022-08-17 07:43:42 +02:00
|
|
|
|
parseVar();
|
|
|
|
|
|
else if (token == "$scope")
|
|
|
|
|
|
parseScope();
|
|
|
|
|
|
else if (token == "$upscope")
|
|
|
|
|
|
parseUpscope();
|
2022-10-26 23:27:30 +02:00
|
|
|
|
else if (token == "$enddefinitions")
|
2022-08-17 07:43:42 +02:00
|
|
|
|
// empty body
|
|
|
|
|
|
readStmtString();
|
2022-10-26 02:09:34 +02:00
|
|
|
|
else if (token == "$dumpall")
|
|
|
|
|
|
parseVarValues();
|
|
|
|
|
|
else if (token == "$dumpvars")
|
|
|
|
|
|
// Initial values.
|
|
|
|
|
|
parseVarValues();
|
|
|
|
|
|
else if (token[0] == '$')
|
|
|
|
|
|
report_->fileError(800, filename_, stmt_line_, "unhandled vcd command.");
|
|
|
|
|
|
else
|
|
|
|
|
|
parseVarValues();
|
2022-08-17 07:43:42 +02:00
|
|
|
|
token = getToken();
|
|
|
|
|
|
}
|
|
|
|
|
|
gzclose(stream_);
|
|
|
|
|
|
}
|
2022-10-29 03:10:29 +02:00
|
|
|
|
else
|
|
|
|
|
|
throw FileNotReadable(filename);
|
2022-10-26 23:27:30 +02:00
|
|
|
|
return vcd;
|
2022-08-17 07:43:42 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
2022-10-13 01:42:12 +02:00
|
|
|
|
VcdReader::VcdReader(StaState *sta) :
|
|
|
|
|
|
StaState(sta),
|
2022-11-04 17:33:03 +01:00
|
|
|
|
file_line_(0),
|
2022-10-13 01:42:12 +02:00
|
|
|
|
stmt_line_(0),
|
2022-10-26 23:27:30 +02:00
|
|
|
|
vcd_(nullptr),
|
2022-10-11 00:16:42 +02:00
|
|
|
|
time_(0),
|
2022-10-26 23:27:30 +02:00
|
|
|
|
prev_time_(0)
|
2022-08-17 07:43:42 +02:00
|
|
|
|
{
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
|
VcdReader::parseTimescale()
|
|
|
|
|
|
{
|
2022-10-26 00:00:41 +02:00
|
|
|
|
vector<string> tokens = readStmtTokens();
|
|
|
|
|
|
if (tokens.size() == 1) {
|
|
|
|
|
|
size_t last;
|
2022-10-26 23:27:30 +02:00
|
|
|
|
vcd_->setTimeScale(std::stod(tokens[0], &last));
|
|
|
|
|
|
setTimeUnit(tokens[0].substr(last));
|
2022-10-26 00:00:41 +02:00
|
|
|
|
}
|
|
|
|
|
|
else if (tokens.size() == 2) {
|
2022-10-26 23:27:30 +02:00
|
|
|
|
vcd_->setTimeScale(std::stod(tokens[0]));
|
|
|
|
|
|
setTimeUnit(tokens[1]);
|
2022-10-26 00:00:41 +02:00
|
|
|
|
}
|
|
|
|
|
|
else
|
2022-10-29 03:10:29 +02:00
|
|
|
|
report_->fileError(801, filename_, stmt_line_, "timescale syntax error.");
|
2022-10-26 23:27:30 +02:00
|
|
|
|
}
|
2022-10-26 00:00:41 +02:00
|
|
|
|
|
2022-10-26 23:27:30 +02:00
|
|
|
|
void
|
|
|
|
|
|
VcdReader::setTimeUnit(const string &time_unit)
|
|
|
|
|
|
{
|
|
|
|
|
|
double time_unit_scale = 1.0;
|
|
|
|
|
|
if (time_unit == "fs")
|
|
|
|
|
|
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;
|
2022-08-17 07:43:42 +02:00
|
|
|
|
else
|
2022-10-29 03:10:29 +02:00
|
|
|
|
report_->fileError(802, filename_, stmt_line_, "Unknown timescale unit.");
|
2022-10-26 23:27:30 +02:00
|
|
|
|
vcd_->setTimeUnit(time_unit, time_unit_scale);;
|
2022-08-17 07:43:42 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
|
VcdReader::parseVar()
|
|
|
|
|
|
{
|
|
|
|
|
|
vector<string> tokens = readStmtTokens();
|
2022-10-26 00:00:41 +02:00
|
|
|
|
if (tokens.size() == 4
|
|
|
|
|
|
|| tokens.size() == 5) {
|
2022-08-17 07:43:42 +02:00
|
|
|
|
string type_name = tokens[0];
|
2022-10-26 23:53:42 +02:00
|
|
|
|
VcdVarType type = VcdVarType::wire;
|
2022-08-17 07:43:42 +02:00
|
|
|
|
if (type_name == "wire")
|
2022-10-26 23:53:42 +02:00
|
|
|
|
type = VcdVarType::wire;
|
2022-08-17 07:43:42 +02:00
|
|
|
|
else if (type_name == "reg")
|
2022-10-26 23:53:42 +02:00
|
|
|
|
type = VcdVarType::reg;
|
2022-10-26 00:00:41 +02:00
|
|
|
|
else if (type_name == "parameter")
|
2022-10-26 23:53:42 +02:00
|
|
|
|
type = VcdVarType::parameter;
|
2022-10-28 00:12:32 +02:00
|
|
|
|
else if (type_name == "real")
|
|
|
|
|
|
type = VcdVarType::real;
|
2022-08-17 07:43:42 +02:00
|
|
|
|
else
|
2022-10-13 01:42:12 +02:00
|
|
|
|
report_->fileError(803, filename_, stmt_line_,
|
|
|
|
|
|
"Unknown variable type %s.",
|
|
|
|
|
|
type_name.c_str());
|
2022-08-17 07:43:42 +02:00
|
|
|
|
|
|
|
|
|
|
int width = stoi(tokens[1]);
|
|
|
|
|
|
string id = tokens[2];
|
2022-10-26 20:00:40 +02:00
|
|
|
|
string name;
|
|
|
|
|
|
|
|
|
|
|
|
for (string &context : scope_) {
|
2022-10-30 21:26:16 +01:00
|
|
|
|
name += context;
|
|
|
|
|
|
name += '/';
|
2022-10-26 20:00:40 +02:00
|
|
|
|
}
|
|
|
|
|
|
name += tokens[3];
|
2022-10-26 00:00:41 +02:00
|
|
|
|
// iverilog separates bus base name from bit range.
|
|
|
|
|
|
if (tokens.size() == 5)
|
|
|
|
|
|
name += tokens[4];
|
2022-10-26 02:09:34 +02:00
|
|
|
|
|
2022-10-26 23:27:30 +02:00
|
|
|
|
vcd_->makeVar(name, type, width, id);
|
2022-08-17 07:43:42 +02:00
|
|
|
|
}
|
2022-10-26 00:00:41 +02:00
|
|
|
|
else
|
2022-10-29 03:10:29 +02:00
|
|
|
|
report_->fileError(804, filename_, stmt_line_, "Variable syntax error.");
|
2022-08-17 07:43:42 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
|
VcdReader::parseScope()
|
|
|
|
|
|
{
|
2022-10-26 20:00:40 +02:00
|
|
|
|
vector<string> tokens = readStmtTokens();
|
|
|
|
|
|
string &scope = tokens[1];
|
|
|
|
|
|
scope_.push_back(scope);
|
2022-08-17 07:43:42 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
|
VcdReader::parseUpscope()
|
|
|
|
|
|
{
|
2022-10-26 02:09:34 +02:00
|
|
|
|
readStmtTokens();
|
2022-10-26 20:00:40 +02:00
|
|
|
|
scope_.pop_back();
|
2022-08-17 07:43:42 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
|
VcdReader::parseVarValues()
|
|
|
|
|
|
{
|
|
|
|
|
|
string token = getToken();
|
|
|
|
|
|
while (!token.empty()) {
|
2022-10-28 00:12:32 +02:00
|
|
|
|
char char0 = toupper(token[0]);
|
|
|
|
|
|
if (char0 == '#') {
|
2022-10-26 21:43:10 +02:00
|
|
|
|
prev_time_ = time_;
|
2022-08-17 07:43:42 +02:00
|
|
|
|
time_ = stoll(token.substr(1));
|
2022-10-26 21:43:10 +02:00
|
|
|
|
if (time_ > prev_time_)
|
2022-10-26 23:27:30 +02:00
|
|
|
|
vcd_->setMinDeltaTime(min(time_ - prev_time_, vcd_->minDeltaTime()));
|
2022-10-26 21:43:10 +02:00
|
|
|
|
}
|
2022-10-28 00:12:32 +02:00
|
|
|
|
else if (char0 == '0'
|
|
|
|
|
|
|| char0 == '1'
|
|
|
|
|
|
|| char0 == 'X'
|
|
|
|
|
|
|| char0 == 'U'
|
|
|
|
|
|
|| char0 == 'Z') {
|
2022-10-26 23:27:30 +02:00
|
|
|
|
string id = token.substr(1);
|
|
|
|
|
|
if (!vcd_->varIdValid(id))
|
2022-10-29 03:10:29 +02:00
|
|
|
|
report_->fileError(805, filename_, stmt_line_,
|
2022-10-26 23:27:30 +02:00
|
|
|
|
"unknown variable %s", id.c_str());
|
2022-10-28 00:12:32 +02:00
|
|
|
|
vcd_->varAppendValue(id, time_, char0);
|
2022-10-26 23:27:30 +02:00
|
|
|
|
}
|
2022-10-28 00:12:32 +02:00
|
|
|
|
else if (char0 == 'B') {
|
|
|
|
|
|
char char1 = toupper(token[1]);
|
|
|
|
|
|
if (char1 == 'X'
|
|
|
|
|
|
|| char1 == 'U'
|
|
|
|
|
|
|| char1 == 'Z') {
|
2022-08-17 07:43:42 +02:00
|
|
|
|
string id = getToken();
|
2022-10-26 23:27:30 +02:00
|
|
|
|
if (!vcd_->varIdValid(id))
|
2022-10-29 03:10:29 +02:00
|
|
|
|
report_->fileError(806, filename_, stmt_line_,
|
2022-10-26 23:27:30 +02:00
|
|
|
|
"unknown variable %s", id.c_str());
|
|
|
|
|
|
// Bus mixed 0/1/X/U not supported.
|
2022-10-28 00:12:32 +02:00
|
|
|
|
vcd_->varAppendValue(id, time_, char1);
|
2022-08-17 07:43:42 +02:00
|
|
|
|
}
|
|
|
|
|
|
else {
|
2022-10-11 00:16:42 +02:00
|
|
|
|
string bin = token.substr(1);
|
|
|
|
|
|
char *end;
|
|
|
|
|
|
int64_t bus_value = strtol(bin.c_str(), &end, 2);
|
2022-08-17 07:43:42 +02:00
|
|
|
|
string id = getToken();
|
2022-10-26 23:27:30 +02:00
|
|
|
|
if (!vcd_->varIdValid(id))
|
2022-10-29 03:10:29 +02:00
|
|
|
|
report_->fileError(807, filename_, stmt_line_,
|
2022-10-26 00:00:41 +02:00
|
|
|
|
"unknown variable %s", id.c_str());
|
2022-10-26 23:27:30 +02:00
|
|
|
|
else
|
|
|
|
|
|
vcd_->varAppendBusValue(id, time_, bus_value);
|
2022-08-17 07:43:42 +02:00
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
token = getToken();
|
|
|
|
|
|
}
|
2022-10-26 23:27:30 +02:00
|
|
|
|
vcd_->setTimeMax(time_);
|
2022-10-11 00:16:42 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
2022-08-17 07:43:42 +02:00
|
|
|
|
string
|
|
|
|
|
|
VcdReader::readStmtString()
|
|
|
|
|
|
{
|
2022-10-13 01:42:12 +02:00
|
|
|
|
stmt_line_ = file_line_;
|
2022-08-17 07:43:42 +02:00
|
|
|
|
string line;
|
|
|
|
|
|
string token = getToken();
|
|
|
|
|
|
while (!token.empty() && token != "$end") {
|
|
|
|
|
|
if (!line.empty())
|
|
|
|
|
|
line += " ";
|
|
|
|
|
|
line += token;
|
|
|
|
|
|
token = getToken();
|
|
|
|
|
|
}
|
|
|
|
|
|
return line;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
vector<string>
|
|
|
|
|
|
VcdReader::readStmtTokens()
|
|
|
|
|
|
{
|
2022-10-13 01:42:12 +02:00
|
|
|
|
stmt_line_ = file_line_;
|
2022-08-17 07:43:42 +02:00
|
|
|
|
vector<string> tokens;
|
|
|
|
|
|
string token = getToken();
|
|
|
|
|
|
while (!token.empty() && token != "$end") {
|
|
|
|
|
|
tokens.push_back(token);
|
|
|
|
|
|
token = getToken();
|
|
|
|
|
|
}
|
|
|
|
|
|
return tokens;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
string
|
|
|
|
|
|
VcdReader::getToken()
|
|
|
|
|
|
{
|
|
|
|
|
|
string token;
|
|
|
|
|
|
int ch = gzgetc(stream_);
|
2022-10-13 01:42:12 +02:00
|
|
|
|
if (ch == '\n')
|
|
|
|
|
|
file_line_++;
|
2022-08-17 07:43:42 +02:00
|
|
|
|
// skip whitespace
|
2022-10-13 01:42:12 +02:00
|
|
|
|
while (ch != EOF && isspace(ch)) {
|
2022-08-17 07:43:42 +02:00
|
|
|
|
ch = gzgetc(stream_);
|
2022-10-13 01:42:12 +02:00
|
|
|
|
if (ch == '\n')
|
|
|
|
|
|
file_line_++;
|
|
|
|
|
|
}
|
2022-08-17 07:43:42 +02:00
|
|
|
|
while (ch != EOF && !isspace(ch)) {
|
|
|
|
|
|
token.push_back(ch);
|
|
|
|
|
|
ch = gzgetc(stream_);
|
2022-10-13 01:42:12 +02:00
|
|
|
|
if (ch == '\n')
|
|
|
|
|
|
file_line_++;
|
2022-08-17 07:43:42 +02:00
|
|
|
|
}
|
|
|
|
|
|
if (ch == EOF)
|
|
|
|
|
|
return "";
|
|
|
|
|
|
else
|
|
|
|
|
|
return token;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2022-10-26 23:27:30 +02:00
|
|
|
|
////////////////////////////////////////////////////////////////
|
|
|
|
|
|
|
2022-10-26 23:59:51 +02:00
|
|
|
|
static void
|
|
|
|
|
|
reportWaveforms(Vcd &vcd,
|
|
|
|
|
|
Report *report);
|
|
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
|
reportVcdWaveforms(const char *filename,
|
|
|
|
|
|
StaState *sta)
|
|
|
|
|
|
|
|
|
|
|
|
{
|
2022-10-28 00:12:32 +02:00
|
|
|
|
Vcd vcd = readVcdFile(filename, sta);
|
2022-10-26 23:59:51 +02:00
|
|
|
|
reportWaveforms(vcd, sta->report());
|
|
|
|
|
|
}
|
2022-10-26 23:35:25 +02:00
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
|
reportWaveforms(Vcd &vcd,
|
|
|
|
|
|
Report *report)
|
|
|
|
|
|
{
|
|
|
|
|
|
report->reportLine("Date: %s", vcd.date().c_str());
|
|
|
|
|
|
report->reportLine("Timescale: %.2f%s", vcd.timeScale(), vcd.timeUnit().c_str());
|
|
|
|
|
|
// Characters per time sample.
|
|
|
|
|
|
int zoom = (vcd.maxVarWidth() + 7) / 4;
|
|
|
|
|
|
int time_delta = vcd.minDeltaTime();
|
|
|
|
|
|
|
|
|
|
|
|
int max_var_name_length = vcd.maxVarNameLength();
|
2022-11-02 03:08:22 +01:00
|
|
|
|
for (VcdVar *var : vcd.vars()) {
|
2022-10-26 23:35:25 +02:00
|
|
|
|
string line;
|
|
|
|
|
|
stringPrint(line, " %-*s",
|
|
|
|
|
|
static_cast<int>(max_var_name_length),
|
2022-11-02 03:08:22 +01:00
|
|
|
|
var->name().c_str());
|
2022-10-26 23:35:25 +02:00
|
|
|
|
const VcdValues &var_values = vcd.values(var);
|
|
|
|
|
|
if (!var_values.empty()) {
|
|
|
|
|
|
size_t value_index = 0;
|
|
|
|
|
|
VcdValue var_value = var_values[value_index];
|
|
|
|
|
|
VcdValue prev_var_value = var_values[value_index];
|
2022-10-28 19:52:27 +02:00
|
|
|
|
VcdTime next_value_time = var_values[value_index + 1].time();
|
2022-10-26 23:35:25 +02:00
|
|
|
|
for (double time = 0.0; time < vcd.timeMax(); time += time_delta) {
|
|
|
|
|
|
if (time >= next_value_time) {
|
|
|
|
|
|
if (value_index < var_values.size() - 1)
|
|
|
|
|
|
value_index++;
|
|
|
|
|
|
var_value = var_values[value_index];
|
|
|
|
|
|
if (value_index < var_values.size())
|
|
|
|
|
|
next_value_time = var_values[value_index + 1].time();
|
|
|
|
|
|
}
|
|
|
|
|
|
if (var_value.value()) {
|
|
|
|
|
|
// 01UZX
|
|
|
|
|
|
char value = var_value.value();
|
|
|
|
|
|
char prev_value = prev_var_value.value();
|
2022-11-02 03:08:22 +01:00
|
|
|
|
if (var->width() == 1) {
|
2022-10-26 23:35:25 +02:00
|
|
|
|
if (value == '0' || value == '1') {
|
|
|
|
|
|
for (int z = 0; z < zoom; z++) {
|
|
|
|
|
|
if (z == 0
|
|
|
|
|
|
&& value != prev_value
|
|
|
|
|
|
&& (prev_value == '0'
|
|
|
|
|
|
|| prev_value == '1'))
|
|
|
|
|
|
line += (prev_value == '1') ? "╲" : "╱";
|
|
|
|
|
|
else
|
|
|
|
|
|
line += (value == '1') ? "▔" : "▁";
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
else {
|
|
|
|
|
|
string field;
|
|
|
|
|
|
stringPrint(field, "%-*c", zoom, value);
|
|
|
|
|
|
line += field;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
else {
|
|
|
|
|
|
string field;
|
|
|
|
|
|
stringPrint(field, "%-*c", zoom, value);
|
|
|
|
|
|
line += field;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
else {
|
|
|
|
|
|
// bus
|
|
|
|
|
|
string field;
|
2022-11-03 03:30:06 +01:00
|
|
|
|
stringPrint(field, "%-*" PRIX64, zoom, var_value.busValue());
|
2022-10-26 23:35:25 +02:00
|
|
|
|
line += field;
|
|
|
|
|
|
}
|
|
|
|
|
|
prev_var_value = var_value;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
report->reportLineString(line);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2022-11-02 03:08:22 +01:00
|
|
|
|
void
|
|
|
|
|
|
reportVcdVarValues(const char *filename,
|
|
|
|
|
|
const char *var_name,
|
|
|
|
|
|
StaState *sta)
|
|
|
|
|
|
{
|
|
|
|
|
|
Vcd vcd = readVcdFile(filename, sta);
|
|
|
|
|
|
VcdVar *var = vcd.var(var_name);
|
|
|
|
|
|
if (var) {
|
|
|
|
|
|
Report *report = sta->report();
|
|
|
|
|
|
for (const VcdValue &var_value : vcd.values(var)) {
|
|
|
|
|
|
double time = var_value.time() * vcd.timeUnitScale();
|
|
|
|
|
|
char value = var_value.value();
|
|
|
|
|
|
if (value == '\0')
|
2022-11-03 02:40:51 +01:00
|
|
|
|
report->reportLine("%.2e %" PRIu64,
|
2022-11-02 03:08:22 +01:00
|
|
|
|
time, var_value.busValue());
|
|
|
|
|
|
else
|
|
|
|
|
|
report->reportLine("%.2e %c", time, value);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2022-08-17 07:43:42 +02:00
|
|
|
|
}
|