2022-01-26 03:23:38 -06:00
|
|
|
/*
|
|
|
|
* yosys -- Yosys Open SYnthesis Suite
|
|
|
|
*
|
|
|
|
* Copyright (C) 2022 Miodrag Milanovic <micko@yosyshq.com>
|
|
|
|
*
|
|
|
|
* Permission to use, copy, modify, and/or distribute this software for any
|
|
|
|
* purpose with or without fee is hereby granted, provided that the above
|
|
|
|
* copyright notice and this permission notice appear in all copies.
|
|
|
|
*
|
|
|
|
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
|
|
|
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
|
|
|
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
|
|
|
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
|
|
|
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
|
|
|
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
|
|
|
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
|
|
|
*
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include "kernel/fstdata.h"
|
|
|
|
|
|
|
|
USING_YOSYS_NAMESPACE
|
|
|
|
|
|
|
|
FstData::FstData(std::string filename) : ctx(nullptr)
|
|
|
|
{
|
|
|
|
ctx = (fstReaderContext *)fstReaderOpen(filename.c_str());
|
2022-01-28 03:18:02 -06:00
|
|
|
timescale = pow(10.0, (int)fstReaderGetTimescale(ctx));
|
2022-01-26 03:23:38 -06:00
|
|
|
extractVarNames();
|
|
|
|
}
|
|
|
|
|
|
|
|
FstData::~FstData()
|
|
|
|
{
|
|
|
|
if (ctx)
|
|
|
|
fstReaderClose(ctx);
|
|
|
|
}
|
|
|
|
|
|
|
|
uint64_t FstData::getStartTime() { return fstReaderGetStartTime(ctx); }
|
|
|
|
|
|
|
|
uint64_t FstData::getEndTime() { return fstReaderGetEndTime(ctx); }
|
|
|
|
|
|
|
|
fstHandle FstData::getHandle(std::string name) {
|
|
|
|
if (name_to_handle.find(name) != name_to_handle.end())
|
|
|
|
return name_to_handle[name];
|
|
|
|
else
|
|
|
|
log("Not found key %s\n", name.c_str());
|
|
|
|
return 0;
|
|
|
|
};
|
|
|
|
|
|
|
|
static std::string remove_spaces(std::string str)
|
|
|
|
{
|
|
|
|
str.erase(std::remove(str.begin(), str.end(), ' '), str.end());
|
|
|
|
return str;
|
|
|
|
}
|
|
|
|
|
|
|
|
void FstData::extractVarNames()
|
|
|
|
{
|
|
|
|
struct fstHier *h;
|
|
|
|
intptr_t snum = 0;
|
|
|
|
|
|
|
|
while ((h = fstReaderIterateHier(ctx))) {
|
|
|
|
switch (h->htyp) {
|
|
|
|
case FST_HT_SCOPE: {
|
|
|
|
snum++;
|
|
|
|
std::string fst_scope_name = fstReaderPushScope(ctx, h->u.scope.name, (void *)(snum));
|
|
|
|
scopes.push_back(fst_scope_name);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case FST_HT_UPSCOPE: {
|
|
|
|
fstReaderPopScope(ctx);
|
|
|
|
snum = fstReaderGetCurrentScopeLen(ctx) ? (intptr_t)fstReaderGetCurrentScopeUserInfo(ctx) : 0;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case FST_HT_VAR: {
|
|
|
|
FstVar var;
|
|
|
|
var.id = h->u.var.handle;
|
|
|
|
var.is_alias = h->u.var.is_alias;
|
|
|
|
var.name = remove_spaces(h->u.var.name);
|
|
|
|
var.scope = scopes.back();
|
|
|
|
var.width = h->u.var.length;
|
|
|
|
vars.push_back(var);
|
|
|
|
if (!var.is_alias)
|
|
|
|
handle_to_var[h->u.var.handle] = var;
|
|
|
|
std::string clean_name;
|
|
|
|
for(size_t i=0;i<strlen(h->u.var.name);i++)
|
|
|
|
{
|
|
|
|
char c = h->u.var.name[i];
|
|
|
|
if(c==' ') break;
|
|
|
|
clean_name += c;
|
|
|
|
}
|
|
|
|
//log("adding %s.%s\n",var.scope.c_str(), clean_name.c_str());
|
|
|
|
|
|
|
|
name_to_handle[var.scope+"."+clean_name] = h->u.var.handle;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-01-28 05:50:41 -06:00
|
|
|
static void reconstruct_edges_varlen(void *user_data, uint64_t pnt_time, fstHandle pnt_facidx, const unsigned char *pnt_value, uint32_t plen)
|
2022-01-26 03:23:38 -06:00
|
|
|
{
|
|
|
|
FstData *ptr = (FstData*)user_data;
|
2022-01-28 05:50:41 -06:00
|
|
|
ptr->reconstruct_edges_callback(pnt_time, pnt_facidx, pnt_value, plen);
|
2022-01-26 03:23:38 -06:00
|
|
|
}
|
|
|
|
|
2022-01-28 05:50:41 -06:00
|
|
|
static void reconstruct_edges(void *user_data, uint64_t pnt_time, fstHandle pnt_facidx, const unsigned char *pnt_value)
|
2022-01-26 03:23:38 -06:00
|
|
|
{
|
|
|
|
FstData *ptr = (FstData*)user_data;
|
|
|
|
uint32_t plen = (pnt_value) ? strlen((const char *)pnt_value) : 0;
|
2022-01-28 05:50:41 -06:00
|
|
|
ptr->reconstruct_edges_callback(pnt_time, pnt_facidx, pnt_value, plen);
|
2022-01-26 03:23:38 -06:00
|
|
|
}
|
|
|
|
|
2022-01-28 05:50:41 -06:00
|
|
|
void FstData::reconstruct_edges_callback(uint64_t pnt_time, fstHandle pnt_facidx, const unsigned char *pnt_value, uint32_t /* plen */)
|
2022-01-26 03:23:38 -06:00
|
|
|
{
|
2022-01-28 05:50:41 -06:00
|
|
|
std::string val = std::string((const char *)pnt_value);
|
|
|
|
std::string prev = last_data[pnt_facidx];
|
|
|
|
if (pnt_time>=start_time) {
|
2022-01-28 06:53:27 -06:00
|
|
|
if (prev!="1" && val=="1")
|
2022-01-28 05:50:41 -06:00
|
|
|
edges.push_back(pnt_time);
|
2022-01-28 06:53:27 -06:00
|
|
|
if (prev!="0" && val=="0")
|
2022-01-28 05:50:41 -06:00
|
|
|
edges.push_back(pnt_time);
|
|
|
|
}
|
|
|
|
last_data[pnt_facidx] = val;
|
2022-01-26 03:23:38 -06:00
|
|
|
}
|
|
|
|
|
2022-01-28 05:50:41 -06:00
|
|
|
std::vector<uint64_t> FstData::getAllEdges(std::vector<fstHandle> &signal, uint64_t start, uint64_t end)
|
2022-01-26 03:23:38 -06:00
|
|
|
{
|
2022-01-28 05:50:41 -06:00
|
|
|
start_time = start;
|
|
|
|
end_time = end;
|
|
|
|
last_data.clear();
|
|
|
|
for(auto &s : signal) {
|
|
|
|
last_data[s] = "x";
|
|
|
|
}
|
|
|
|
edges.clear();
|
|
|
|
fstReaderSetLimitTimeRange(ctx, start_time, end_time);
|
2022-01-26 03:23:38 -06:00
|
|
|
fstReaderClrFacProcessMaskAll(ctx);
|
|
|
|
for(const auto sig : signal)
|
|
|
|
fstReaderSetFacProcessMask(ctx,sig);
|
2022-01-28 05:50:41 -06:00
|
|
|
fstReaderIterBlocks2(ctx, reconstruct_edges, reconstruct_edges_varlen, this, nullptr);
|
|
|
|
return edges;
|
2022-01-26 03:23:38 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
static void reconstruct_clb_varlen_attimes(void *user_data, uint64_t pnt_time, fstHandle pnt_facidx, const unsigned char *pnt_value, uint32_t plen)
|
|
|
|
{
|
|
|
|
FstData *ptr = (FstData*)user_data;
|
|
|
|
ptr->reconstruct_callback_attimes(pnt_time, pnt_facidx, pnt_value, plen);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void reconstruct_clb_attimes(void *user_data, uint64_t pnt_time, fstHandle pnt_facidx, const unsigned char *pnt_value)
|
|
|
|
{
|
|
|
|
FstData *ptr = (FstData*)user_data;
|
|
|
|
uint32_t plen = (pnt_value) ? strlen((const char *)pnt_value) : 0;
|
|
|
|
ptr->reconstruct_callback_attimes(pnt_time, pnt_facidx, pnt_value, plen);
|
|
|
|
}
|
|
|
|
|
|
|
|
void FstData::reconstruct_callback_attimes(uint64_t pnt_time, fstHandle pnt_facidx, const unsigned char *pnt_value, uint32_t /* plen */)
|
|
|
|
{
|
|
|
|
if (sample_times_ndx > sample_times.size()) return;
|
2022-01-28 05:50:41 -06:00
|
|
|
|
2022-01-26 03:23:38 -06:00
|
|
|
uint64_t time = sample_times[sample_times_ndx];
|
|
|
|
// if we are past the timestamp
|
|
|
|
if (pnt_time > time) {
|
2022-01-28 05:50:41 -06:00
|
|
|
for (auto const& c : last_data)
|
2022-01-26 03:23:38 -06:00
|
|
|
{
|
|
|
|
handle_to_data[c.first].push_back(std::make_pair(time,c.second));
|
|
|
|
size_t index = handle_to_data[c.first].size() - 1;
|
|
|
|
time_to_index[c.first][time] = index;
|
|
|
|
}
|
|
|
|
sample_times_ndx++;
|
|
|
|
}
|
2022-01-28 05:50:41 -06:00
|
|
|
// always update last_data
|
|
|
|
last_data[pnt_facidx] = std::string((const char *)pnt_value);
|
2022-01-26 03:23:38 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
void FstData::reconstructAtTimes(std::vector<fstHandle> &signal, std::vector<uint64_t> time)
|
|
|
|
{
|
|
|
|
handle_to_data.clear();
|
|
|
|
time_to_index.clear();
|
2022-01-28 05:50:41 -06:00
|
|
|
last_data.clear();
|
2022-01-26 03:23:38 -06:00
|
|
|
sample_times_ndx = 0;
|
|
|
|
sample_times = time;
|
2022-01-28 05:50:41 -06:00
|
|
|
fstReaderSetUnlimitedTimeRange(ctx);
|
2022-01-26 03:23:38 -06:00
|
|
|
fstReaderClrFacProcessMaskAll(ctx);
|
|
|
|
for(const auto sig : signal)
|
|
|
|
fstReaderSetFacProcessMask(ctx,sig);
|
|
|
|
fstReaderIterBlocks2(ctx, reconstruct_clb_attimes, reconstruct_clb_varlen_attimes, this, nullptr);
|
|
|
|
|
|
|
|
if (time_to_index[signal.back()].count(time.back())==0) {
|
2022-01-28 05:50:41 -06:00
|
|
|
for (auto const& c : last_data)
|
2022-01-26 03:23:38 -06:00
|
|
|
{
|
|
|
|
handle_to_data[c.first].push_back(std::make_pair(time.back(),c.second));
|
|
|
|
size_t index = handle_to_data[c.first].size() - 1;
|
|
|
|
time_to_index[c.first][time.back()] = index;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void FstData::reconstructAllAtTimes(std::vector<uint64_t> time)
|
|
|
|
{
|
|
|
|
handle_to_data.clear();
|
|
|
|
time_to_index.clear();
|
2022-01-28 05:50:41 -06:00
|
|
|
last_data.clear();
|
2022-01-26 03:23:38 -06:00
|
|
|
sample_times_ndx = 0;
|
|
|
|
sample_times = time;
|
2022-01-28 05:50:41 -06:00
|
|
|
|
|
|
|
fstReaderSetUnlimitedTimeRange(ctx);
|
2022-01-26 03:23:38 -06:00
|
|
|
fstReaderSetFacProcessMaskAll(ctx);
|
|
|
|
fstReaderIterBlocks2(ctx, reconstruct_clb_attimes, reconstruct_clb_varlen_attimes, this, nullptr);
|
2022-01-28 05:50:41 -06:00
|
|
|
|
|
|
|
if (time_to_index[1].count(time.back())==0) {
|
|
|
|
for (auto const& c : last_data)
|
2022-01-26 03:23:38 -06:00
|
|
|
{
|
|
|
|
handle_to_data[c.first].push_back(std::make_pair(time.back(),c.second));
|
|
|
|
size_t index = handle_to_data[c.first].size() - 1;
|
|
|
|
time_to_index[c.first][time.back()] = index;
|
|
|
|
}
|
2022-01-28 05:50:41 -06:00
|
|
|
}
|
2022-01-26 03:23:38 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
std::string FstData::valueAt(fstHandle signal, uint64_t time)
|
|
|
|
{
|
2022-01-28 05:50:41 -06:00
|
|
|
if (handle_to_data.find(signal) == handle_to_data.end())
|
|
|
|
log_error("Signal id %d not found\n", (int)signal);
|
2022-01-26 03:23:38 -06:00
|
|
|
auto &data = handle_to_data[signal];
|
|
|
|
if (time_to_index[signal].count(time)!=0) {
|
|
|
|
size_t index = time_to_index[signal][time];
|
|
|
|
return data.at(index).second;
|
|
|
|
} else {
|
2022-01-28 05:54:16 -06:00
|
|
|
log_error("No data for signal %d at time %d\n", (int)signal, (int)time);
|
2022-01-26 03:23:38 -06:00
|
|
|
}
|
|
|
|
}
|