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