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