587678ce33ab2fc71c6d2e7255fd12b65ee0c9bf
[yosys.git] / kernel / fstdata.cc
1 /*
2 * yosys -- Yosys Open SYnthesis Suite
3 *
4 * Copyright (C) 2022 Miodrag Milanovic <micko@yosyshq.com>
5 *
6 * Permission to use, copy, modify, and/or distribute this software for any
7 * purpose with or without fee is hereby granted, provided that the above
8 * copyright notice and this permission notice appear in all copies.
9 *
10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17 *
18 */
19
20 #include "kernel/fstdata.h"
21
22 USING_YOSYS_NAMESPACE
23
24
25 static std::string file_base_name(std::string const & path)
26 {
27 return path.substr(path.find_last_of("/\\") + 1);
28 }
29
30 FstData::FstData(std::string filename) : ctx(nullptr)
31 {
32 #if !defined(YOSYS_DISABLE_SPAWN)
33 std::string filename_trim = file_base_name(filename);
34 if (filename_trim.size() > 4 && filename_trim.compare(filename_trim.size()-4, std::string::npos, ".vcd") == 0) {
35 filename_trim.erase(filename_trim.size()-4);
36 tmp_file = stringf("/tmp/converted_%s.fst", filename_trim.c_str());
37 std::string cmd = stringf("vcd2fst %s %s", filename.c_str(), tmp_file.c_str());
38 log("Exec: %s\n", cmd.c_str());
39 if (run_command(cmd) != 0)
40 log_cmd_error("Shell command failed!\n");
41 filename = tmp_file;
42 }
43 #endif
44 const std::vector<std::string> g_units = { "s", "ms", "us", "ns", "ps", "fs", "as", "zs" };
45 ctx = (fstReaderContext *)fstReaderOpen(filename.c_str());
46 if (!ctx)
47 log_error("Error opening '%s' as FST file\n", filename.c_str());
48 int scale = (int)fstReaderGetTimescale(ctx);
49 timescale = pow(10.0, scale);
50 timescale_str = "";
51 int unit = 0;
52 int zeros = 0;
53 if (scale > 0) {
54 zeros = scale;
55 } else {
56 if ((scale % 3) == 0) {
57 zeros = (-scale % 3);
58 unit = (-scale / 3);
59 } else {
60 zeros = 3 - (-scale % 3);
61 unit = (-scale / 3) + 1;
62 }
63 }
64 for (int i=0;i<zeros; i++) timescale_str += "0";
65 timescale_str += g_units[unit];
66 extractVarNames();
67 }
68
69 FstData::~FstData()
70 {
71 if (ctx)
72 fstReaderClose(ctx);
73 if (!tmp_file.empty())
74 remove(tmp_file.c_str());
75 }
76
77 uint64_t FstData::getStartTime() { return fstReaderGetStartTime(ctx); }
78
79 uint64_t FstData::getEndTime() { return fstReaderGetEndTime(ctx); }
80
81 fstHandle FstData::getHandle(std::string name) {
82 if (name_to_handle.find(name) != name_to_handle.end())
83 return name_to_handle[name];
84 else
85 return 0;
86 };
87
88 static std::string remove_spaces(std::string str)
89 {
90 str.erase(std::remove(str.begin(), str.end(), ' '), str.end());
91 return str;
92 }
93
94 void FstData::extractVarNames()
95 {
96 struct fstHier *h;
97 intptr_t snum = 0;
98
99 while ((h = fstReaderIterateHier(ctx))) {
100 switch (h->htyp) {
101 case FST_HT_SCOPE: {
102 snum++;
103 std::string fst_scope_name = fstReaderPushScope(ctx, h->u.scope.name, (void *)(snum));
104 scopes.push_back(fst_scope_name);
105 break;
106 }
107 case FST_HT_UPSCOPE: {
108 fstReaderPopScope(ctx);
109 snum = fstReaderGetCurrentScopeLen(ctx) ? (intptr_t)fstReaderGetCurrentScopeUserInfo(ctx) : 0;
110 break;
111 }
112 case FST_HT_VAR: {
113 FstVar var;
114 var.id = h->u.var.handle;
115 var.is_alias = h->u.var.is_alias;
116 var.name = remove_spaces(h->u.var.name);
117 var.scope = scopes.back();
118 var.width = h->u.var.length;
119 vars.push_back(var);
120 if (!var.is_alias)
121 handle_to_var[h->u.var.handle] = var;
122 std::string clean_name;
123 for(size_t i=0;i<strlen(h->u.var.name);i++)
124 {
125 char c = h->u.var.name[i];
126 if(c==' ') break;
127 clean_name += c;
128 }
129 if (clean_name[0]=='\\')
130 clean_name = clean_name.substr(1);
131
132 name_to_handle[var.scope+"."+clean_name] = h->u.var.handle;
133 break;
134 }
135 }
136 }
137 }
138
139
140 static void reconstruct_clb_varlen_attimes(void *user_data, uint64_t pnt_time, fstHandle pnt_facidx, const unsigned char *pnt_value, uint32_t plen)
141 {
142 FstData *ptr = (FstData*)user_data;
143 ptr->reconstruct_callback_attimes(pnt_time, pnt_facidx, pnt_value, plen);
144 }
145
146 static void reconstruct_clb_attimes(void *user_data, uint64_t pnt_time, fstHandle pnt_facidx, const unsigned char *pnt_value)
147 {
148 FstData *ptr = (FstData*)user_data;
149 uint32_t plen = (pnt_value) ? strlen((const char *)pnt_value) : 0;
150 ptr->reconstruct_callback_attimes(pnt_time, pnt_facidx, pnt_value, plen);
151 }
152
153 void FstData::reconstruct_callback_attimes(uint64_t pnt_time, fstHandle pnt_facidx, const unsigned char *pnt_value, uint32_t /* plen */)
154 {
155 if (pnt_time > end_time) return;
156 // if we are past the timestamp
157 bool is_clock = false;
158 if (!all_samples) {
159 for(auto &s : clk_signals) {
160 if (s==pnt_facidx) {
161 is_clock=true;
162 break;
163 }
164 }
165 }
166
167 if (pnt_time > past_time) {
168 past_data = last_data;
169 past_time = pnt_time;
170 }
171
172 if (pnt_time > last_time) {
173 if (all_samples) {
174 callback(last_time);
175 last_time = pnt_time;
176 } else {
177 if (is_clock) {
178 std::string val = std::string((const char *)pnt_value);
179 std::string prev = past_data[pnt_facidx];
180 if ((prev!="1" && val=="1") || (prev!="0" && val=="0")) {
181 callback(last_time);
182 last_time = pnt_time;
183 }
184 }
185 }
186 }
187 // always update last_data
188 last_data[pnt_facidx] = std::string((const char *)pnt_value);
189 }
190
191 void FstData::reconstructAllAtTimes(std::vector<fstHandle> &signal, uint64_t start, uint64_t end, CallbackFunction cb)
192 {
193 clk_signals = signal;
194 callback = cb;
195 start_time = start;
196 end_time = end;
197 last_data.clear();
198 last_time = start_time;
199 past_data.clear();
200 past_time = start_time;
201 all_samples = clk_signals.empty();
202
203 fstReaderSetUnlimitedTimeRange(ctx);
204 fstReaderSetFacProcessMaskAll(ctx);
205 fstReaderIterBlocks2(ctx, reconstruct_clb_attimes, reconstruct_clb_varlen_attimes, this, nullptr);
206 past_data = last_data;
207 callback(last_time);
208 if (last_time!=end_time)
209 callback(end_time);
210 }
211
212 std::string FstData::valueOf(fstHandle signal)
213 {
214 if (past_data.find(signal) == past_data.end())
215 log_error("Signal id %d not found\n", (int)signal);
216 return past_data[signal];
217 }