2 * yosys -- Yosys Open SYnthesis Suite
4 * Copyright (C) 2020 whitequark <whitequark@whitequark.org>
6 * Permission to use, copy, modify, and/or distribute this software for any
7 * purpose with or without fee is hereby granted.
9 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
22 #include <backends/cxxrtl/cxxrtl.h>
33 std::vector
<std::string
> current_scope
;
34 std::vector
<variable
> variables
;
35 bool streaming
= false;
37 void emit_timescale(unsigned number
, const std::string
&unit
) {
39 assert(number
== 1 || number
== 10 || number
== 100);
40 assert(unit
== "s" || unit
== "ms" || unit
== "us" ||
41 unit
== "ns" || unit
== "ps" || unit
== "fs");
42 buffer
+= "$timescale " + std::to_string(number
) + " " + unit
+ " $end\n";
45 void emit_scope(const std::vector
<std::string
> &scope
) {
47 while (current_scope
.size() > scope
.size() ||
48 (current_scope
.size() > 0 &&
49 current_scope
[current_scope
.size() - 1] != scope
[current_scope
.size() - 1])) {
50 buffer
+= "$upscope $end\n";
51 current_scope
.pop_back();
53 while (current_scope
.size() < scope
.size()) {
54 buffer
+= "$scope module " + scope
[current_scope
.size()] + " $end\n";
55 current_scope
.push_back(scope
[current_scope
.size()]);
59 void emit_ident(size_t ident
) {
61 buffer
+= '!' + ident
% 94; // "base94"
66 void emit_var(const variable
&var
, const std::string
&type
, const std::string
&name
) {
68 buffer
+= "$var " + type
+ " " + std::to_string(var
.width
) + " ";
69 emit_ident(var
.ident
);
70 buffer
+= " " + name
+ " $end\n";
73 void emit_enddefinitions() {
75 buffer
+= "$enddefinitions $end\n";
79 void emit_time(uint64_t timestamp
) {
81 buffer
+= "#" + std::to_string(timestamp
) + "\n";
84 void emit_scalar(const variable
&var
) {
86 assert(var
.width
== 1);
87 buffer
+= (*var
.curr
? '1' : '0');
88 emit_ident(var
.ident
);
92 void emit_vector(const variable
&var
) {
95 for (size_t bit
= var
.width
- 1; bit
!= (size_t)-1; bit
--) {
96 bool bit_curr
= var
.curr
[bit
/ (8 * sizeof(chunk_t
))] & (1 << (bit
% (8 * sizeof(chunk_t
))));
97 buffer
+= (bit_curr
? '1' : '0');
100 emit_ident(var
.ident
);
104 static std::vector
<std::string
> split_hierarchy(const std::string
&hier_name
) {
105 std::vector
<std::string
> hierarchy
;
108 size_t curr
= hier_name
.find_first_of(' ', prev
+ 1);
109 if (curr
> hier_name
.size())
110 curr
= hier_name
.size();
112 hierarchy
.push_back(hier_name
.substr(prev
, curr
- prev
));
113 if (curr
== hier_name
.size())
123 void timescale(unsigned number
, const std::string
&unit
) {
124 emit_timescale(number
, unit
);
127 void add(const std::string
&hier_name
, const debug_item
&item
) {
128 std::vector
<std::string
> scope
= split_hierarchy(hier_name
);
129 std::string name
= scope
.back();
134 // Not the best naming but oh well...
135 case debug_item::VALUE
:
136 variables
.emplace_back(variable
{ variables
.size(), item
.width
, item
.curr
});
137 emit_var(variables
.back(), "wire", name
);
139 case debug_item::WIRE
:
140 variables
.emplace_back(variable
{ variables
.size(), item
.width
, item
.curr
});
141 emit_var(variables
.back(), "reg", name
);
143 case debug_item::MEMORY
: {
144 const size_t stride
= (item
.width
+ (sizeof(chunk_t
) * 8 - 1)) / (sizeof(chunk_t
) * 8);
145 for (size_t index
= 0; index
< item
.depth
; index
++) {
146 chunk_t
*nth_curr
= &item
.curr
[stride
* index
];
147 std::string nth_name
= name
+ '[' + std::to_string(index
) + ']';
148 variables
.emplace_back(variable
{ variables
.size(), item
.width
, nth_curr
});
149 emit_var(variables
.back(), "reg", nth_name
);
156 template<class Filter
>
157 void add(const debug_items
&items
, const Filter
&filter
) {
158 // `debug_items` is a map, so the items are already sorted in an order optimal for emitting
159 // VCD scope sections.
160 for (auto &it
: items
)
161 if (filter(it
.first
, it
.second
))
162 add(it
.first
, it
.second
);
165 void add(const debug_items
&items
) {
166 this->template add(items
, [](const std::string
&, const debug_item
&) {
171 void add_without_memories(const debug_items
&items
) {
172 this->template add(items
, [](const std::string
&, const debug_item
&item
) {
173 return item
.type
== debug_item::VALUE
|| item
.type
== debug_item::WIRE
;
177 void sample(uint64_t timestamp
) {
180 emit_enddefinitions();
182 emit_time(timestamp
);
183 for (auto var
: variables
) {