Improve simplec back-end
[yosys.git] / backends / simplec / simplec.cc
1 /*
2 * yosys -- Yosys Open SYnthesis Suite
3 *
4 * Copyright (C) 2012 Clifford Wolf <clifford@clifford.at>
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/yosys.h"
21 #include "kernel/sigtools.h"
22 #include "kernel/utils.h"
23
24 USING_YOSYS_NAMESPACE
25 PRIVATE_NAMESPACE_BEGIN
26
27 struct HierDirtyFlags;
28
29 struct HierDirtyFlags
30 {
31 int dirty;
32 Module *module;
33 IdString hiername;
34 HierDirtyFlags *parent;
35 pool<SigBit> dirty_bits;
36 pool<Cell*> dirty_cells;
37 pool<SigBit> sticky_dirty_bits;
38 dict<IdString, HierDirtyFlags*> children;
39
40 HierDirtyFlags(Module *module, IdString hiername, HierDirtyFlags *parent) : dirty(0), module(module), hiername(hiername), parent(parent)
41 {
42 for (Cell *cell : module->cells()) {
43 Module *mod = module->design->module(cell->type);
44 if (mod) children[cell->name] = new HierDirtyFlags(mod, cell->name, this);
45 }
46 }
47
48 ~HierDirtyFlags()
49 {
50 for (auto &child : children)
51 delete child.second;
52 }
53
54 void set_dirty(SigBit bit)
55 {
56 if (dirty_bits.count(bit))
57 return;
58
59 dirty_bits.insert(bit);
60 sticky_dirty_bits.insert(bit);
61
62 HierDirtyFlags *p = this;
63 while (p != nullptr) {
64 p->dirty++;
65 p = p->parent;
66 }
67 }
68
69 void unset_dirty(SigBit bit)
70 {
71 if (dirty_bits.count(bit) == 0)
72 return;
73
74 dirty_bits.erase(bit);
75
76 HierDirtyFlags *p = this;
77 while (p != nullptr) {
78 p->dirty--;
79 log_assert(p->dirty >= 0);
80 p = p->parent;
81 }
82 }
83
84 void set_dirty(Cell *cell)
85 {
86 if (dirty_cells.count(cell))
87 return;
88
89 dirty_cells.insert(cell);
90
91 HierDirtyFlags *p = this;
92 while (p != nullptr) {
93 p->dirty++;
94 p = p->parent;
95 }
96 }
97
98 void unset_dirty(Cell *cell)
99 {
100 if (dirty_cells.count(cell) == 0)
101 return;
102
103 dirty_cells.erase(cell);
104
105 HierDirtyFlags *p = this;
106 while (p != nullptr) {
107 p->dirty--;
108 log_assert(p->dirty >= 0);
109 p = p->parent;
110 }
111 }
112 };
113
114 struct SimplecWorker
115 {
116 bool verbose = false;
117 int max_uintsize = 32;
118
119 Design *design;
120 dict<Module*, SigMap> sigmaps;
121
122 vector<string> signal_declarations;
123 pool<int> generated_sigtypes;
124
125 vector<string> util_declarations;
126 pool<string> generated_utils;
127
128 vector<string> struct_declarations;
129 pool<IdString> generated_structs;
130
131 vector<string> funct_declarations;
132
133 pool<string> reserved_cids;
134 dict<IdString, string> id2cid;
135
136 dict<Module*, dict<SigBit, pool<tuple<Cell*, IdString, int>>>> bit2cell;
137 dict<Module*, dict<SigBit, pool<SigBit>>> bit2output;
138
139 dict<Cell*, int> topoidx;
140
141 pool<string> activated_cells;
142 pool<string> reactivated_cells;
143
144 SimplecWorker(Design *design) : design(design)
145 {
146 }
147
148 string sigtype(int n)
149 {
150 string struct_name = stringf("signal%d_t", n);
151
152 if (generated_sigtypes.count(n) == 0)
153 {
154 signal_declarations.push_back("");
155 signal_declarations.push_back(stringf("#ifndef YOSYS_SIMPLEC_SIGNAL%d_T", n));
156 signal_declarations.push_back(stringf("#define YOSYS_SIMPLEC_SIGNAL%d_T", n));
157 signal_declarations.push_back(stringf("typedef struct {"));
158
159 for (int k = 8; k <= max_uintsize; k = 2*k)
160 if (n <= k && k <= max_uintsize) {
161 signal_declarations.push_back(stringf(" uint%d_t value_%d_0 : %d;", k, n-1, n));
162 goto end_struct;
163 }
164
165 for (int k = 0; k < n; k += max_uintsize) {
166 int bits = std::min(max_uintsize, n-k);
167 signal_declarations.push_back(stringf(" uint%d_t value_%d_%d : %d;", max_uintsize, k+bits-1, k, bits));
168 }
169
170 end_struct:
171 signal_declarations.push_back(stringf("} signal%d_t;", n));
172 signal_declarations.push_back(stringf("#endif"));
173 generated_sigtypes.insert(n);
174 }
175
176 return struct_name;
177 }
178
179 void util_ifdef_guard(string s)
180 {
181 for (int i = 0; i < GetSize(s); i++)
182 if ('a' <= s[i] && s[i] <= 'z')
183 s[i] -= 'a' - 'A';
184
185 util_declarations.push_back("");
186 util_declarations.push_back(stringf("#ifndef %s", s.c_str()));
187 util_declarations.push_back(stringf("#define %s", s.c_str()));
188 }
189
190 string util_get_bit(const string &signame, int n, int idx)
191 {
192 if (n == 1 && idx == 0)
193 return signame + ".value_0_0";
194
195 string util_name = stringf("yosys_simplec_get_bit_%d_of_%d", idx, n);
196
197 if (generated_utils.count(util_name) == 0)
198 {
199 util_ifdef_guard(util_name);
200 util_declarations.push_back(stringf("static inline bool %s(const %s *sig)", util_name.c_str(), sigtype(n).c_str()));
201 util_declarations.push_back(stringf("{"));
202
203 int word_idx = idx / max_uintsize, word_offset = idx % max_uintsize;
204 string value_name = stringf("value_%d_%d", std::min(n-1, (word_idx+1)*max_uintsize-1), word_idx*max_uintsize);
205
206 util_declarations.push_back(stringf(" return (sig->%s >> %d) & 1;", value_name.c_str(), word_offset));
207
208 util_declarations.push_back(stringf("}"));
209 util_declarations.push_back(stringf("#endif"));
210 generated_utils.insert(util_name);
211 }
212
213 return stringf("%s(&%s)", util_name.c_str(), signame.c_str());
214 }
215
216 string util_set_bit(const string &signame, int n, int idx, const string &expr)
217 {
218 if (n == 1 && idx == 0)
219 return stringf(" %s.value_0_0 = %s;", signame.c_str(), expr.c_str());
220
221 string util_name = stringf("yosys_simplec_set_bit_%d_of_%d", idx, n);
222
223 if (generated_utils.count(util_name) == 0)
224 {
225 util_ifdef_guard(util_name);
226 util_declarations.push_back(stringf("static inline void %s(%s *sig, bool value)", util_name.c_str(), sigtype(n).c_str()));
227 util_declarations.push_back(stringf("{"));
228
229 int word_idx = idx / max_uintsize, word_offset = idx % max_uintsize;
230 string value_name = stringf("value_%d_%d", std::min(n-1, (word_idx+1)*max_uintsize-1), word_idx*max_uintsize);
231
232 #if 0
233 util_declarations.push_back(stringf(" if (value)"));
234 util_declarations.push_back(stringf(" sig->%s |= 1UL << %d;", value_name.c_str(), word_offset));
235 util_declarations.push_back(stringf(" else"));
236 util_declarations.push_back(stringf(" sig->%s &= ~(1UL << %d);", value_name.c_str(), word_offset));
237 #else
238 util_declarations.push_back(stringf(" sig->%s = (sig->%s & ~((uint%d_t)1 << %d)) | ((uint%d_t)value << %d);",
239 value_name.c_str(), value_name.c_str(), max_uintsize, word_offset, max_uintsize, word_offset));
240 #endif
241
242 util_declarations.push_back(stringf("}"));
243 util_declarations.push_back(stringf("#endif"));
244 generated_utils.insert(util_name);
245 }
246
247 return stringf(" %s(&%s, %s);", util_name.c_str(), signame.c_str(), expr.c_str());
248 }
249
250 string cid(IdString id)
251 {
252 if (id2cid.count(id) == 0)
253 {
254 string s = id.str();
255 if (GetSize(s) < 2) log_abort();
256
257 if (s[0] == '\\')
258 s = s.substr(1);
259
260 if ('0' <= s[0] && s[0] <= '9') {
261 s = "_" + s;
262 }
263
264 for (int i = 0; i < GetSize(s); i++) {
265 if ('0' <= s[i] && s[i] <= '9') continue;
266 if ('A' <= s[i] && s[i] <= 'Z') continue;
267 if ('a' <= s[i] && s[i] <= 'z') continue;
268 s[i] = '_';
269 }
270
271 while (reserved_cids.count(s))
272 s += "_";
273
274 reserved_cids.insert(s);
275 id2cid[id] = s;
276 }
277
278 return id2cid.at(id);
279 }
280
281 void create_module_struct(Module *mod)
282 {
283 if (generated_structs.count(mod->name))
284 return;
285
286 generated_structs.insert(mod->name);
287 sigmaps[mod].set(mod);
288
289 for (Wire *w : mod->wires())
290 {
291 if (w->port_output)
292 for (auto bit : SigSpec(w))
293 bit2output[mod][sigmaps.at(mod)(bit)].insert(bit);
294 }
295
296 for (Cell *c : mod->cells())
297 {
298 for (auto &conn : c->connections())
299 {
300 if (!c->input(conn.first))
301 continue;
302
303 int idx = 0;
304 for (auto bit : sigmaps.at(mod)(conn.second))
305 bit2cell[mod][bit].insert(tuple<Cell*, IdString, int>(c, conn.first, idx++));
306 }
307
308 if (design->module(c->type))
309 create_module_struct(design->module(c->type));
310 }
311
312 TopoSort<IdString> topo;
313
314 for (Cell *c : mod->cells())
315 {
316 topo.node(c->name);
317
318 for (auto &conn : c->connections())
319 {
320 if (!c->input(conn.first))
321 continue;
322
323 for (auto bit : sigmaps.at(mod)(conn.second))
324 for (auto &it : bit2cell[mod][bit])
325 topo.edge(c->name, std::get<0>(it)->name);
326 }
327 }
328
329 topo.analyze_loops = false;
330 topo.sort();
331
332 for (int i = 0; i < GetSize(topo.sorted); i++)
333 topoidx[mod->cell(topo.sorted[i])] = i;
334
335 string ifdef_name = stringf("yosys_simplec_%s_state_t", cid(mod->name).c_str());
336
337 for (int i = 0; i < GetSize(ifdef_name); i++)
338 if ('a' <= ifdef_name[i] && ifdef_name[i] <= 'z')
339 ifdef_name[i] -= 'a' - 'A';
340
341 struct_declarations.push_back("");
342 struct_declarations.push_back(stringf("#ifndef %s", ifdef_name.c_str()));
343 struct_declarations.push_back(stringf("#define %s", ifdef_name.c_str()));
344 struct_declarations.push_back(stringf("struct %s_state_t", cid(mod->name).c_str()));
345 struct_declarations.push_back("{");
346
347 struct_declarations.push_back(" // Input Ports");
348 for (Wire *w : mod->wires())
349 if (w->port_input)
350 struct_declarations.push_back(stringf(" %s %s; // %s", sigtype(w->width).c_str(), cid(w->name).c_str(), log_id(w)));
351
352 struct_declarations.push_back("");
353 struct_declarations.push_back(" // Output Ports");
354 for (Wire *w : mod->wires())
355 if (!w->port_input && w->port_output)
356 struct_declarations.push_back(stringf(" %s %s; // %s", sigtype(w->width).c_str(), cid(w->name).c_str(), log_id(w)));
357
358 struct_declarations.push_back("");
359 struct_declarations.push_back(" // Internal Wires");
360 for (Wire *w : mod->wires())
361 if (!w->port_input && !w->port_output)
362 struct_declarations.push_back(stringf(" %s %s; // %s", sigtype(w->width).c_str(), cid(w->name).c_str(), log_id(w)));
363
364 for (Cell *c : mod->cells())
365 if (design->module(c->type))
366 struct_declarations.push_back(stringf(" struct %s_state_t %s; // %s", cid(c->type).c_str(), cid(c->name).c_str(), log_id(c)));
367
368 struct_declarations.push_back(stringf("};"));
369 struct_declarations.push_back("#endif");
370 }
371
372 void eval_cell(HierDirtyFlags *work, const string &prefix, const string &/* log_prefix */, Cell *cell)
373 {
374 if (cell->type.in("$_BUF_", "$_NOT_"))
375 {
376 SigBit a = sigmaps.at(work->module)(cell->getPort("\\A"));
377 SigBit y = sigmaps.at(work->module)(cell->getPort("\\Y"));
378
379 string a_expr = a.wire ? util_get_bit(prefix + cid(a.wire->name), a.wire->width, a.offset) : a.data ? "1" : "0";
380 string expr;
381
382 if (cell->type == "$_BUF_") expr = a_expr;
383 if (cell->type == "$_NOT_") expr = "!" + a_expr;
384
385 log_assert(y.wire);
386 funct_declarations.push_back(util_set_bit(prefix + cid(y.wire->name), y.wire->width, y.offset, expr) +
387 stringf(" // %s (%s)", log_id(cell), log_id(cell->type)));
388
389 work->set_dirty(y);
390 return;
391 }
392
393 if (cell->type.in("$_AND_", "$_NAND_", "$_OR_", "$_NOR_", "$_XOR_", "$_XNOR_"))
394 {
395 SigBit a = sigmaps.at(work->module)(cell->getPort("\\A"));
396 SigBit b = sigmaps.at(work->module)(cell->getPort("\\B"));
397 SigBit y = sigmaps.at(work->module)(cell->getPort("\\Y"));
398
399 string a_expr = a.wire ? util_get_bit(prefix + cid(a.wire->name), a.wire->width, a.offset) : a.data ? "1" : "0";
400 string b_expr = b.wire ? util_get_bit(prefix + cid(b.wire->name), b.wire->width, b.offset) : b.data ? "1" : "0";
401 string expr;
402
403 if (cell->type == "$_AND_") expr = stringf("%s & %s", a_expr.c_str(), b_expr.c_str());
404 if (cell->type == "$_NAND_") expr = stringf("!(%s & %s)", a_expr.c_str(), b_expr.c_str());
405 if (cell->type == "$_OR_") expr = stringf("%s | %s", a_expr.c_str(), b_expr.c_str());
406 if (cell->type == "$_NOR_") expr = stringf("!(%s | %s)", a_expr.c_str(), b_expr.c_str());
407 if (cell->type == "$_XOR_") expr = stringf("%s ^ %s", a_expr.c_str(), b_expr.c_str());
408 if (cell->type == "$_XNOR_") expr = stringf("!(%s ^ %s)", a_expr.c_str(), b_expr.c_str());
409
410 log_assert(y.wire);
411 funct_declarations.push_back(util_set_bit(prefix + cid(y.wire->name), y.wire->width, y.offset, expr) +
412 stringf(" // %s (%s)", log_id(cell), log_id(cell->type)));
413
414 work->set_dirty(y);
415 return;
416 }
417
418 if (cell->type.in("$_AOI3_", "$_OAI3_"))
419 {
420 SigBit a = sigmaps.at(work->module)(cell->getPort("\\A"));
421 SigBit b = sigmaps.at(work->module)(cell->getPort("\\B"));
422 SigBit c = sigmaps.at(work->module)(cell->getPort("\\C"));
423 SigBit y = sigmaps.at(work->module)(cell->getPort("\\Y"));
424
425 string a_expr = a.wire ? util_get_bit(prefix + cid(a.wire->name), a.wire->width, a.offset) : a.data ? "1" : "0";
426 string b_expr = b.wire ? util_get_bit(prefix + cid(b.wire->name), b.wire->width, b.offset) : b.data ? "1" : "0";
427 string c_expr = c.wire ? util_get_bit(prefix + cid(c.wire->name), c.wire->width, c.offset) : c.data ? "1" : "0";
428 string expr;
429
430 if (cell->type == "$_AOI3_") expr = stringf("!((%s & %s) | %s)", a_expr.c_str(), b_expr.c_str(), c_expr.c_str());
431 if (cell->type == "$_OAI3_") expr = stringf("!((%s | %s) & %s)", a_expr.c_str(), b_expr.c_str(), c_expr.c_str());
432
433 log_assert(y.wire);
434 funct_declarations.push_back(util_set_bit(prefix + cid(y.wire->name), y.wire->width, y.offset, expr) +
435 stringf(" // %s (%s)", log_id(cell), log_id(cell->type)));
436
437 work->set_dirty(y);
438 return;
439 }
440
441 if (cell->type.in("$_AOI4_", "$_OAI4_"))
442 {
443 SigBit a = sigmaps.at(work->module)(cell->getPort("\\A"));
444 SigBit b = sigmaps.at(work->module)(cell->getPort("\\B"));
445 SigBit c = sigmaps.at(work->module)(cell->getPort("\\C"));
446 SigBit d = sigmaps.at(work->module)(cell->getPort("\\D"));
447 SigBit y = sigmaps.at(work->module)(cell->getPort("\\Y"));
448
449 string a_expr = a.wire ? util_get_bit(prefix + cid(a.wire->name), a.wire->width, a.offset) : a.data ? "1" : "0";
450 string b_expr = b.wire ? util_get_bit(prefix + cid(b.wire->name), b.wire->width, b.offset) : b.data ? "1" : "0";
451 string c_expr = c.wire ? util_get_bit(prefix + cid(c.wire->name), c.wire->width, c.offset) : c.data ? "1" : "0";
452 string d_expr = d.wire ? util_get_bit(prefix + cid(d.wire->name), d.wire->width, d.offset) : d.data ? "1" : "0";
453 string expr;
454
455 if (cell->type == "$_AOI4_") expr = stringf("!((%s & %s) | (%s & %s))", a_expr.c_str(), b_expr.c_str(), c_expr.c_str(), d_expr.c_str());
456 if (cell->type == "$_OAI4_") expr = stringf("!((%s | %s) & (%s | %s))", a_expr.c_str(), b_expr.c_str(), c_expr.c_str(), d_expr.c_str());
457
458 log_assert(y.wire);
459 funct_declarations.push_back(util_set_bit(prefix + cid(y.wire->name), y.wire->width, y.offset, expr) +
460 stringf(" // %s (%s)", log_id(cell), log_id(cell->type)));
461
462 work->set_dirty(y);
463 return;
464 }
465
466 if (cell->type == "$_MUX_")
467 {
468 SigBit a = sigmaps.at(work->module)(cell->getPort("\\A"));
469 SigBit b = sigmaps.at(work->module)(cell->getPort("\\B"));
470 SigBit s = sigmaps.at(work->module)(cell->getPort("\\S"));
471 SigBit y = sigmaps.at(work->module)(cell->getPort("\\Y"));
472
473 string a_expr = a.wire ? util_get_bit(prefix + cid(a.wire->name), a.wire->width, a.offset) : a.data ? "1" : "0";
474 string b_expr = b.wire ? util_get_bit(prefix + cid(b.wire->name), b.wire->width, b.offset) : b.data ? "1" : "0";
475 string s_expr = s.wire ? util_get_bit(prefix + cid(s.wire->name), s.wire->width, s.offset) : s.data ? "1" : "0";
476 string expr = stringf("%s ? %s : %s", s_expr.c_str(), b_expr.c_str(), a_expr.c_str());
477
478 log_assert(y.wire);
479 funct_declarations.push_back(util_set_bit(prefix + cid(y.wire->name), y.wire->width, y.offset, expr) +
480 stringf(" // %s (%s)", log_id(cell), log_id(cell->type)));
481
482 work->set_dirty(y);
483 return;
484 }
485
486 log_error("No C model for %s available at the moment (FIXME).\n", log_id(cell->type));
487 }
488
489 void eval_dirty(HierDirtyFlags *work, const string &prefix, const string &log_prefix, const string &parent_prefix, const string &parent_log_prefix)
490 {
491 while (work->dirty)
492 {
493 if (verbose && (!work->dirty_bits.empty() || !work->dirty_cells.empty()))
494 log(" In %s:\n", log_prefix.c_str());
495
496 while (!work->dirty_bits.empty() || !work->dirty_cells.empty())
497 {
498 if (!work->dirty_bits.empty())
499 {
500 SigSpec dirtysig(work->dirty_bits);
501 dirtysig.sort_and_unify();
502
503 for (SigChunk chunk : dirtysig.chunks()) {
504 if (verbose)
505 log(" Propagating %s.%s[%d:%d].\n", log_prefix.c_str(), log_id(chunk.wire), chunk.offset+chunk.width-1, chunk.offset);
506 funct_declarations.push_back(stringf(" // Updated signal in %s: %s", log_prefix.c_str(), log_signal(chunk)));
507 }
508
509 for (SigBit bit : dirtysig)
510 {
511 if (bit2output[work->module].count(bit) && work->parent)
512 for (auto outbit : bit2output[work->module][bit])
513 {
514 Module *parent_mod = work->parent->module;
515 Cell *parent_cell = parent_mod->cell(work->hiername);
516
517 IdString port_name = outbit.wire->name;
518 int port_offset = outbit.offset;
519 SigBit parent_bit = sigmaps.at(parent_mod)(parent_cell->getPort(port_name)[port_offset]);
520
521 log_assert(bit.wire && parent_bit.wire);
522 funct_declarations.push_back(util_set_bit(parent_prefix + cid(parent_bit.wire->name), parent_bit.wire->width, parent_bit.offset,
523 util_get_bit(prefix + cid(bit.wire->name), bit.wire->width, bit.offset)));
524 work->parent->set_dirty(parent_bit);
525
526 if (verbose)
527 log(" Propagating %s.%s[%d] -> %s.%s[%d].\n", log_prefix.c_str(), log_id(bit.wire), bit.offset,
528 parent_log_prefix.c_str(), log_id(parent_bit.wire), parent_bit.offset);
529 }
530
531 for (auto &port : bit2cell[work->module][bit])
532 {
533 if (work->children.count(std::get<0>(port)->name))
534 {
535 HierDirtyFlags *child = work->children.at(std::get<0>(port)->name);
536 SigBit child_bit = sigmaps.at(child->module)(SigBit(child->module->wire(std::get<1>(port)), std::get<2>(port)));
537 log_assert(bit.wire && child_bit.wire);
538
539 funct_declarations.push_back(util_set_bit(prefix + cid(child->hiername) + "." + cid(child_bit.wire->name),
540 child_bit.wire->width, child_bit.offset, util_get_bit(prefix + cid(bit.wire->name), bit.wire->width, bit.offset)));
541 child->set_dirty(child_bit);
542
543 if (verbose)
544 log(" Propagating %s.%s[%d] -> %s.%s.%s[%d].\n", log_prefix.c_str(), log_id(bit.wire), bit.offset,
545 log_prefix.c_str(), log_id(std::get<0>(port)), log_id(child_bit.wire), child_bit.offset);
546 } else {
547 if (verbose)
548 log(" Marking cell %s.%s (via %s.%s[%d]).\n", log_prefix.c_str(), log_id(std::get<0>(port)),
549 log_prefix.c_str(), log_id(bit.wire), bit.offset);
550 work->set_dirty(std::get<0>(port));
551 }
552 }
553 work->unset_dirty(bit);
554 }
555 }
556
557 if (!work->dirty_cells.empty())
558 {
559 Cell *cell = nullptr;
560 for (auto c : work->dirty_cells)
561 if (cell == nullptr || topoidx.at(cell) < topoidx.at(c))
562 cell = c;
563
564 string hiername = log_prefix + "." + log_id(cell);
565
566 if (verbose)
567 log(" Evaluating %s (%s, best of %d).\n", hiername.c_str(), log_id(cell->type), GetSize(work->dirty_cells));
568
569 if (activated_cells.count(hiername))
570 reactivated_cells.insert(hiername);
571 activated_cells.insert(hiername);
572
573 eval_cell(work, prefix, log_prefix, cell);
574 work->unset_dirty(cell);
575 }
576 }
577
578 for (auto &child : work->children)
579 eval_dirty(child.second, prefix + cid(child.first) + ".", log_prefix + "." + cid(child.first), prefix, log_prefix);
580 }
581 }
582
583 void eval_sticky_dirty(HierDirtyFlags *work, const string &prefix, const string &log_prefix)
584 {
585 Module *mod = work->module;
586
587 for (Wire *w : mod->wires())
588 for (SigBit bit : SigSpec(w))
589 {
590 SigBit canonical_bit = sigmaps.at(mod)(bit);
591
592 if (canonical_bit == bit)
593 continue;
594
595 if (work->sticky_dirty_bits.count(canonical_bit) == 0)
596 continue;
597
598 log_assert(bit.wire && canonical_bit.wire);
599 funct_declarations.push_back(util_set_bit(prefix + cid(bit.wire->name), bit.wire->width, bit.offset,
600 util_get_bit(prefix + cid(canonical_bit.wire->name), canonical_bit.wire->width, canonical_bit.offset).c_str()));
601
602 if (verbose)
603 log(" Propagating alias %s.%s[%d] -> %s.%s[%d].\n",
604 log_prefix.c_str(), log_id(canonical_bit.wire), canonical_bit.offset,
605 log_prefix.c_str(), log_id(bit.wire), bit.offset);
606 }
607
608 work->sticky_dirty_bits.clear();
609
610 for (auto &child : work->children)
611 eval_sticky_dirty(child.second, prefix + cid(child.first) + ".", log_prefix + "." + cid(child.first));
612 }
613
614 void make_func(HierDirtyFlags *work, const string &func_name)
615 {
616 log("Generating function %s():\n", func_name.c_str());
617
618 activated_cells.clear();
619 reactivated_cells.clear();
620
621 funct_declarations.push_back("");
622 funct_declarations.push_back(stringf("static void %s(struct %s_state_t *state)", func_name.c_str(), cid(work->module->name).c_str()));
623 funct_declarations.push_back("{");
624 eval_dirty(work, "state->", log_id(work->module->name), "", "");
625 eval_sticky_dirty(work, "state->", log_id(work->module->name));
626 funct_declarations.push_back("}");
627
628 log(" Activated %d cells (%d activated more than once).\n", GetSize(activated_cells), GetSize(reactivated_cells));
629 }
630
631 void make_init_func(HierDirtyFlags* /* work */)
632 {
633 // FIXME
634 }
635
636 void make_eval_func(HierDirtyFlags *work)
637 {
638 Module *mod = work->module;
639
640 for (Wire *w : mod->wires()) {
641 if (w->port_input)
642 for (SigBit bit : sigmaps.at(mod)(w))
643 work->set_dirty(bit);
644 }
645
646 make_func(work, cid(work->module->name) + "_eval");
647 }
648
649 void make_tick_func(HierDirtyFlags* /* work */)
650 {
651 // FIXME
652 }
653
654 void run(Module *mod)
655 {
656 create_module_struct(mod);
657
658 HierDirtyFlags work(mod, IdString(), nullptr);
659
660 make_init_func(&work);
661 make_eval_func(&work);
662 make_tick_func(&work);
663 }
664
665 void write(std::ostream &f)
666 {
667 f << "#include <stdint.h>" << std::endl;
668 f << "#include <stdbool.h>" << std::endl;
669
670 for (auto &line : signal_declarations)
671 f << line << std::endl;
672
673 for (auto &line : util_declarations)
674 f << line << std::endl;
675
676 for (auto &line : struct_declarations)
677 f << line << std::endl;
678
679 for (auto &line : funct_declarations)
680 f << line << std::endl;
681 }
682 };
683
684 struct SimplecBackend : public Backend {
685 SimplecBackend() : Backend("simplec", "convert design to simple C code") { }
686 virtual void help()
687 {
688 // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
689 log("\n");
690 log(" write_simplec [options] [filename]\n");
691 log("\n");
692 log("Write simple C code for simulating the design. The C code writen can be used to\n");
693 log("simulate the design in a C environment, but the purpose of this command is to\n");
694 log("generate code that works well with C-based formal verification.\n");
695 log("\n");
696 log(" -verbose\n");
697 log(" this will print the recursive walk used to export the modules.\n");
698 log("\n");
699 log(" -i8, -i16, -i32, -i64\n");
700 log(" set the maximum integer bit width to use in the generated code.\n");
701 log("\n");
702 log("THIS COMMAND IS UNDER CONSTRUCTION\n");
703 log("\n");
704 }
705 virtual void execute(std::ostream *&f, std::string filename, std::vector<std::string> args, RTLIL::Design *design)
706 {
707 SimplecWorker worker(design);
708
709 log_header(design, "Executing SIMPLEC backend.\n");
710
711 size_t argidx;
712 for (argidx = 1; argidx < args.size(); argidx++)
713 {
714 if (args[argidx] == "-verbose") {
715 worker.verbose = true;
716 continue;
717 }
718 if (args[argidx] == "-i8") {
719 worker.max_uintsize = 8;
720 continue;
721 }
722 if (args[argidx] == "-i16") {
723 worker.max_uintsize = 16;
724 continue;
725 }
726 if (args[argidx] == "-i32") {
727 worker.max_uintsize = 32;
728 continue;
729 }
730 if (args[argidx] == "-i64") {
731 worker.max_uintsize = 64;
732 continue;
733 }
734 break;
735 }
736 extra_args(f, filename, args, argidx);
737
738 Module *topmod = design->top_module();
739
740 if (topmod == nullptr)
741 log_error("Current design has no top module.\n");
742
743 worker.run(topmod);
744 worker.write(*f);
745 }
746 } SimplecBackend;
747
748 PRIVATE_NAMESPACE_END