2 * yosys -- Yosys Open SYnthesis Suite
4 * Copyright (C) 2022 Miodrag Milanovic <micko@yosyshq.com>
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.
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.
20 #include "kernel/fstdata.h"
25 static std::string
file_base_name(std::string
const & path
)
27 return path
.substr(path
.find_last_of("/\\") + 1);
30 FstData::FstData(std::string filename
) : ctx(nullptr)
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");
44 const std::vector
<std::string
> g_units
= { "s", "ms", "us", "ns", "ps", "fs", "as", "zs" };
45 ctx
= (fstReaderContext
*)fstReaderOpen(filename
.c_str());
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
);
56 if ((scale
% 3) == 0) {
60 zeros
= 3 - (-scale
% 3);
61 unit
= (-scale
/ 3) + 1;
64 for (int i
=0;i
<zeros
; i
++) timescale_str
+= "0";
65 timescale_str
+= g_units
[unit
];
73 if (!tmp_file
.empty())
74 remove(tmp_file
.c_str());
77 uint64_t FstData::getStartTime() { return fstReaderGetStartTime(ctx
); }
79 uint64_t FstData::getEndTime() { return fstReaderGetEndTime(ctx
); }
81 fstHandle
FstData::getHandle(std::string name
) {
82 if (name_to_handle
.find(name
) != name_to_handle
.end())
83 return name_to_handle
[name
];
88 dict
<int,fstHandle
> FstData::getMemoryHandles(std::string name
) {
89 if (memory_to_handle
.find(name
) != memory_to_handle
.end())
90 return memory_to_handle
[name
];
92 return dict
<int,fstHandle
>();
95 static std::string
remove_spaces(std::string str
)
97 str
.erase(std::remove(str
.begin(), str
.end(), ' '), str
.end());
101 void FstData::extractVarNames()
104 std::string fst_scope_name
;
106 while ((h
= fstReaderIterateHier(ctx
))) {
109 fst_scope_name
= fstReaderPushScope(ctx
, h
->u
.scope
.name
, NULL
);
112 case FST_HT_UPSCOPE
: {
113 fst_scope_name
= fstReaderPopScope(ctx
);
118 var
.id
= h
->u
.var
.handle
;
119 var
.is_alias
= h
->u
.var
.is_alias
;
120 var
.is_reg
= (fstVarType
)h
->u
.var
.typ
== FST_VT_VCD_REG
;
121 var
.name
= remove_spaces(h
->u
.var
.name
);
122 var
.scope
= fst_scope_name
;
123 var
.width
= h
->u
.var
.length
;
126 handle_to_var
[h
->u
.var
.handle
] = var
;
127 std::string clean_name
;
128 for(size_t i
=0;i
<strlen(h
->u
.var
.name
);i
++)
130 char c
= h
->u
.var
.name
[i
];
134 if (clean_name
[0]=='\\')
135 clean_name
= clean_name
.substr(1);
136 size_t pos
= clean_name
.find_last_of("<");
137 if (pos
!= std::string::npos
) {
138 std::string mem_cell
= clean_name
.substr(0, pos
);
139 std::string addr
= clean_name
.substr(pos
+1);
140 addr
.pop_back(); // remove closing bracket
142 int mem_addr
= strtol(addr
.c_str(), &endptr
, 16);
144 log_error("Error parsing memory address in : %s\n", clean_name
.c_str());
146 memory_to_handle
[var
.scope
+"."+mem_cell
][mem_addr
] = var
.id
;
148 pos
= clean_name
.find_last_of("[");
149 if (pos
!= std::string::npos
) {
150 std::string mem_cell
= clean_name
.substr(0, pos
);
151 std::string addr
= clean_name
.substr(pos
+1);
152 addr
.pop_back(); // remove closing bracket
154 int mem_addr
= strtol(addr
.c_str(), &endptr
, 10);
156 log_error("Error parsing memory address in : %s\n", clean_name
.c_str());
158 memory_to_handle
[var
.scope
+"."+mem_cell
][mem_addr
] = var
.id
;
160 name_to_handle
[var
.scope
+"."+clean_name
] = h
->u
.var
.handle
;
168 static void reconstruct_clb_varlen_attimes(void *user_data
, uint64_t pnt_time
, fstHandle pnt_facidx
, const unsigned char *pnt_value
, uint32_t plen
)
170 FstData
*ptr
= (FstData
*)user_data
;
171 ptr
->reconstruct_callback_attimes(pnt_time
, pnt_facidx
, pnt_value
, plen
);
174 static void reconstruct_clb_attimes(void *user_data
, uint64_t pnt_time
, fstHandle pnt_facidx
, const unsigned char *pnt_value
)
176 FstData
*ptr
= (FstData
*)user_data
;
177 uint32_t plen
= (pnt_value
) ? strlen((const char *)pnt_value
) : 0;
178 ptr
->reconstruct_callback_attimes(pnt_time
, pnt_facidx
, pnt_value
, plen
);
181 void FstData::reconstruct_callback_attimes(uint64_t pnt_time
, fstHandle pnt_facidx
, const unsigned char *pnt_value
, uint32_t /* plen */)
183 if (pnt_time
> end_time
) return;
184 // if we are past the timestamp
185 bool is_clock
= false;
187 for(auto &s
: clk_signals
) {
195 if (pnt_time
> past_time
) {
196 past_data
= last_data
;
197 past_time
= pnt_time
;
200 if (pnt_time
> last_time
) {
203 last_time
= pnt_time
;
206 std::string val
= std::string((const char *)pnt_value
);
207 std::string prev
= past_data
[pnt_facidx
];
208 if ((prev
!="1" && val
=="1") || (prev
!="0" && val
=="0")) {
210 last_time
= pnt_time
;
215 // always update last_data
216 last_data
[pnt_facidx
] = std::string((const char *)pnt_value
);
219 void FstData::reconstructAllAtTimes(std::vector
<fstHandle
> &signal
, uint64_t start
, uint64_t end
, CallbackFunction cb
)
221 clk_signals
= signal
;
226 last_time
= start_time
;
228 past_time
= start_time
;
229 all_samples
= clk_signals
.empty();
231 fstReaderSetUnlimitedTimeRange(ctx
);
232 fstReaderSetFacProcessMaskAll(ctx
);
233 fstReaderIterBlocks2(ctx
, reconstruct_clb_attimes
, reconstruct_clb_varlen_attimes
, this, nullptr);
234 if (last_time
!=end_time
) {
235 past_data
= last_data
;
241 std::string
FstData::valueOf(fstHandle signal
)
243 if (past_data
.find(signal
) == past_data
.end())
244 log_error("Signal id %d not found\n", (int)signal
);
245 return past_data
[signal
];