diff options
author | Miodrag Milanović <mmicko@gmail.com> | 2022-02-07 16:36:43 +0100 |
---|---|---|
committer | GitHub <noreply@github.com> | 2022-02-07 16:36:43 +0100 |
commit | d7f7227ce8edc4e4e81f8885a26e40abf474e7a4 (patch) | |
tree | 5fbc25d817e756d3290b8a1b3078c72b8d7c768b /kernel | |
parent | 9c93668954fe2ec7aa1fb64573f6e9bf97824b60 (diff) | |
parent | c0a156bcb43bb0bb42eb3f2d94c12cda9ca5ee37 (diff) | |
download | yosys-d7f7227ce8edc4e4e81f8885a26e40abf474e7a4.tar.gz yosys-d7f7227ce8edc4e4e81f8885a26e40abf474e7a4.tar.bz2 yosys-d7f7227ce8edc4e4e81f8885a26e40abf474e7a4.zip |
Merge pull request #3185 from YosysHQ/micko/co_sim
Add co-simulation in sim pass
Diffstat (limited to 'kernel')
-rw-r--r-- | kernel/fstdata.cc | 252 | ||||
-rw-r--r-- | kernel/fstdata.h | 81 |
2 files changed, 333 insertions, 0 deletions
diff --git a/kernel/fstdata.cc b/kernel/fstdata.cc new file mode 100644 index 000000000..330c4d189 --- /dev/null +++ b/kernel/fstdata.cc @@ -0,0 +1,252 @@ +/* + * 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) +{ + const std::vector<std::string> g_units = { "s", "ms", "us", "ns", "ps", "fs", "as", "zs" }; + ctx = (fstReaderContext *)fstReaderOpen(filename.c_str()); + if (!ctx) + log_error("Error opening '%s'\n", filename.c_str()); + int scale = (int)fstReaderGetTimescale(ctx); + timescale = pow(10.0, scale); + timescale_str = ""; + int unit = 0; + int zeros = 0; + if (scale > 0) { + zeros = scale; + } else { + if ((scale % 3) == 0) { + zeros = (-scale % 3); + unit = (-scale / 3); + } else { + zeros = 3 - (-scale % 3); + unit = (-scale / 3) + 1; + } + } + for (int i=0;i<zeros; i++) timescale_str += "0"; + timescale_str += g_units[unit]; + 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 + 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; + } + if (clean_name[0]=='\\') + clean_name = clean_name.substr(1); + //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; + } + } + } +} + +static void reconstruct_edges_varlen(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_edges_callback(pnt_time, pnt_facidx, pnt_value, plen); +} + +static void reconstruct_edges(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_edges_callback(pnt_time, pnt_facidx, pnt_value, plen); +} + +void FstData::reconstruct_edges_callback(uint64_t pnt_time, fstHandle pnt_facidx, const unsigned char *pnt_value, uint32_t /* plen */) +{ + std::string val = std::string((const char *)pnt_value); + std::string prev = last_data[pnt_facidx]; + if (pnt_time>=start_time) { + if (prev!="1" && val=="1") + edges.push_back(pnt_time); + if (prev!="0" && val=="0") + edges.push_back(pnt_time); + } + last_data[pnt_facidx] = val; +} + +std::vector<uint64_t> FstData::getAllEdges(std::vector<fstHandle> &signal, uint64_t start, uint64_t end) +{ + 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); + fstReaderClrFacProcessMaskAll(ctx); + for(const auto sig : signal) + fstReaderSetFacProcessMask(ctx,sig); + fstReaderIterBlocks2(ctx, reconstruct_edges, reconstruct_edges_varlen, this, nullptr); + return edges; +} + +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; + + uint64_t time = sample_times[sample_times_ndx]; + // if we are past the timestamp + if (pnt_time > time) { + for (auto const& c : last_data) + { + 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++; + } + // always update last_data + last_data[pnt_facidx] = std::string((const char *)pnt_value); +} + +void FstData::reconstructAtTimes(std::vector<fstHandle> &signal, std::vector<uint64_t> time) +{ + handle_to_data.clear(); + time_to_index.clear(); + last_data.clear(); + sample_times_ndx = 0; + sample_times = time; + fstReaderSetUnlimitedTimeRange(ctx); + 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) { + for (auto const& c : last_data) + { + 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(); + last_data.clear(); + sample_times_ndx = 0; + sample_times = time; + + fstReaderSetUnlimitedTimeRange(ctx); + fstReaderSetFacProcessMaskAll(ctx); + fstReaderIterBlocks2(ctx, reconstruct_clb_attimes, reconstruct_clb_varlen_attimes, this, nullptr); + + if (time_to_index[1].count(time.back())==0) { + for (auto const& c : last_data) + { + 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; + } + } +} + +std::string FstData::valueAt(fstHandle signal, uint64_t time) +{ + if (handle_to_data.find(signal) == handle_to_data.end()) + log_error("Signal id %d not found\n", (int)signal); + 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 { + log_error("No data for signal %d at time %d\n", (int)signal, (int)time); + } +} diff --git a/kernel/fstdata.h b/kernel/fstdata.h new file mode 100644 index 000000000..c069ff5e5 --- /dev/null +++ b/kernel/fstdata.h @@ -0,0 +1,81 @@ +/* + * 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. + * + */ + +#ifndef FSTDATA_H +#define FSTDATA_H + +#include "kernel/yosys.h" +#include "libs/fst/fstapi.h" + +YOSYS_NAMESPACE_BEGIN + +struct FstVar +{ + fstHandle id; + std::string name; + bool is_alias; + std::string scope; + int width; +}; + +class FstData +{ + public: + FstData(std::string filename); + ~FstData(); + + uint64_t getStartTime(); + uint64_t getEndTime(); + + std::vector<FstVar>& getVars() { return vars; }; + + void reconstruct_edges_callback(uint64_t pnt_time, fstHandle pnt_facidx, const unsigned char *pnt_value, uint32_t plen); + std::vector<uint64_t> getAllEdges(std::vector<fstHandle> &signal, uint64_t start_time, uint64_t end_time); + + void reconstruct_callback_attimes(uint64_t pnt_time, fstHandle pnt_facidx, const unsigned char *pnt_value, uint32_t plen); + void reconstructAtTimes(std::vector<fstHandle> &signal,std::vector<uint64_t> time); + void reconstructAllAtTimes(std::vector<uint64_t> time); + + std::string valueAt(fstHandle signal, uint64_t time); + fstHandle getHandle(std::string name); + double getTimescale() { return timescale; } + const char *getTimescaleString() { return timescale_str.c_str(); } +private: + void extractVarNames(); + + struct fstReaderContext *ctx; + std::vector<std::string> scopes; + std::vector<FstVar> vars; + std::map<fstHandle, FstVar> handle_to_var; + std::map<std::string, fstHandle> name_to_handle; + std::map<fstHandle, std::vector<std::pair<uint64_t, std::string>>> handle_to_data; + std::map<fstHandle, std::string> last_data; + std::map<fstHandle, std::map<uint64_t, size_t>> time_to_index; + std::vector<uint64_t> sample_times; + size_t sample_times_ndx; + double timescale; + std::string timescale_str; + uint64_t start_time; + uint64_t end_time; + std::vector<uint64_t> edges; +}; + +YOSYS_NAMESPACE_END + +#endif |