Added "techmap -assert"
[yosys.git] / passes / techmap / techmap.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/toposort.h"
22 #include "kernel/sigtools.h"
23 #include "libs/sha1/sha1.h"
24
25 #include <stdlib.h>
26 #include <stdio.h>
27 #include <string.h>
28
29 #include "passes/techmap/stdcells.inc"
30
31 // see simplemap.cc
32 extern void simplemap_get_mappers(std::map<std::string, void(*)(RTLIL::Module*, RTLIL::Cell*)> &mappers);
33
34 static void apply_prefix(std::string prefix, std::string &id)
35 {
36 if (id[0] == '\\')
37 id = prefix + "." + id.substr(1);
38 else
39 id = "$techmap" + prefix + "." + id;
40 }
41
42 static void apply_prefix(std::string prefix, RTLIL::SigSpec &sig, RTLIL::Module *module)
43 {
44 std::vector<RTLIL::SigChunk> chunks = sig;
45 for (auto &chunk : chunks)
46 if (chunk.wire != NULL) {
47 std::string wire_name = chunk.wire->name;
48 apply_prefix(prefix, wire_name);
49 log_assert(module->wires_.count(wire_name) > 0);
50 chunk.wire = module->wires_[wire_name];
51 }
52 sig = chunks;
53 }
54
55 struct TechmapWorker
56 {
57 std::map<std::string, void(*)(RTLIL::Module*, RTLIL::Cell*)> simplemap_mappers;
58 std::map<std::pair<RTLIL::IdString, std::map<RTLIL::IdString, RTLIL::Const>>, RTLIL::Module*> techmap_cache;
59 std::map<RTLIL::Module*, bool> techmap_do_cache;
60 std::set<RTLIL::Module*> module_queue;
61
62 struct TechmapWireData {
63 RTLIL::Wire *wire;
64 RTLIL::SigSpec value;
65 };
66
67 typedef std::map<std::string, std::vector<TechmapWireData>> TechmapWires;
68
69 bool extern_mode;
70 bool assert_mode;
71 bool flatten_mode;
72
73 TechmapWorker()
74 {
75 extern_mode = false;
76 assert_mode = false;
77 flatten_mode = false;
78 }
79
80 std::string constmap_tpl_name(SigMap &sigmap, RTLIL::Module *tpl, RTLIL::Cell *cell, bool verbose)
81 {
82 std::string constmap_info;
83 std::map<RTLIL::SigBit, std::pair<std::string, int>> connbits_map;
84
85 for (auto conn : cell->connections())
86 for (int i = 0; i < SIZE(conn.second); i++) {
87 RTLIL::SigBit bit = sigmap(conn.second[i]);
88 if (bit.wire == nullptr) {
89 if (verbose)
90 log(" Constant input on bit %d of port %s: %s\n", i, log_id(conn.first), log_signal(bit));
91 constmap_info += stringf("|%s %d %d", log_id(conn.first), i, bit.data);
92 } else if (connbits_map.count(bit)) {
93 if (verbose)
94 log(" Bit %d of port %s and bit %d of port %s are connected.\n", i, log_id(conn.first),
95 connbits_map.at(bit).second, log_id(connbits_map.at(bit).first));
96 constmap_info += stringf("|%s %d %s %d", log_id(conn.first), i,
97 log_id(connbits_map.at(bit).first), connbits_map.at(bit).second);
98 } else
99 connbits_map[bit] = std::pair<std::string, int>(conn.first, i);stringf("%s %d", log_id(conn.first), i, bit.data);
100 }
101
102 unsigned char hash[20];
103 char hash_hex_string[41];
104 sha1::calc(constmap_info.c_str(), constmap_info.size(), hash);
105 sha1::toHexString(hash, hash_hex_string);
106
107 return stringf("$paramod$constmap$%s%s", hash_hex_string, tpl->name.c_str());
108 }
109
110 TechmapWires techmap_find_special_wires(RTLIL::Module *module)
111 {
112 TechmapWires result;
113
114 if (module == NULL)
115 return result;
116
117 for (auto &it : module->wires_) {
118 const char *p = it.first.c_str();
119 if (*p == '$')
120 continue;
121
122 const char *q = strrchr(p+1, '.');
123 p = q ? q : p+1;
124
125 if (!strncmp(p, "_TECHMAP_", 9)) {
126 TechmapWireData record;
127 record.wire = it.second;
128 record.value = it.second;
129 result[p].push_back(record);
130 it.second->attributes["\\keep"] = RTLIL::Const(1);
131 it.second->attributes["\\_techmap_special_"] = RTLIL::Const(1);
132 }
133 }
134
135 if (!result.empty()) {
136 SigMap sigmap(module);
137 for (auto &it1 : result)
138 for (auto &it2 : it1.second)
139 sigmap.apply(it2.value);
140 }
141
142 return result;
143 }
144
145 void techmap_module_worker(RTLIL::Design *design, RTLIL::Module *module, RTLIL::Cell *cell, RTLIL::Module *tpl)
146 {
147 log("Mapping `%s.%s' using `%s'.\n", RTLIL::id2cstr(module->name), RTLIL::id2cstr(cell->name), RTLIL::id2cstr(tpl->name));
148
149 if (tpl->memories.size() != 0)
150 log_error("Technology map yielded memories -> this is not supported.\n");
151
152 if (tpl->processes.size() != 0) {
153 log("Technology map yielded processes:\n");
154 for (auto &it : tpl->processes)
155 log(" %s",RTLIL::id2cstr(it.first));
156 log_error("Technology map yielded processes -> this is not supported.\n");
157 }
158
159 std::string orig_cell_name;
160 if (!flatten_mode)
161 for (auto &it : tpl->cells_)
162 if (it.first == "\\_TECHMAP_REPLACE_") {
163 orig_cell_name = cell->name;
164 module->rename(cell, stringf("$techmap%d", RTLIL::autoidx++) + cell->name);
165 break;
166 }
167
168 std::map<RTLIL::IdString, RTLIL::IdString> positional_ports;
169
170 for (auto &it : tpl->wires_) {
171 if (it.second->port_id > 0)
172 positional_ports[stringf("$%d", it.second->port_id)] = it.first;
173 std::string w_name = it.second->name;
174 apply_prefix(cell->name, w_name);
175 RTLIL::Wire *w = module->addWire(w_name, it.second);
176 w->port_input = false;
177 w->port_output = false;
178 w->port_id = 0;
179 if (it.second->get_bool_attribute("\\_techmap_special_"))
180 w->attributes.clear();
181 design->select(module, w);
182 }
183
184 SigMap port_signal_map;
185
186 for (auto &it : cell->connections()) {
187 RTLIL::IdString portname = it.first;
188 if (positional_ports.count(portname) > 0)
189 portname = positional_ports.at(portname);
190 if (tpl->wires_.count(portname) == 0 || tpl->wires_.at(portname)->port_id == 0) {
191 if (portname.substr(0, 1) == "$")
192 log_error("Can't map port `%s' of cell `%s' to template `%s'!\n", portname.c_str(), cell->name.c_str(), tpl->name.c_str());
193 continue;
194 }
195 RTLIL::Wire *w = tpl->wires_.at(portname);
196 RTLIL::SigSig c;
197 if (w->port_output) {
198 c.first = it.second;
199 c.second = RTLIL::SigSpec(w);
200 apply_prefix(cell->name, c.second, module);
201 } else {
202 c.first = RTLIL::SigSpec(w);
203 c.second = it.second;
204 apply_prefix(cell->name, c.first, module);
205 }
206 if (c.second.size() > c.first.size())
207 c.second.remove(c.first.size(), c.second.size() - c.first.size());
208 if (c.second.size() < c.first.size())
209 c.second.append(RTLIL::SigSpec(RTLIL::State::S0, c.first.size() - c.second.size()));
210 log_assert(c.first.size() == c.second.size());
211 if (flatten_mode) {
212 // more conservative approach:
213 // connect internal and external wires
214 module->connect(c);
215 } else {
216 // approach that yields nicer outputs:
217 // replace internal wires that are connected to external wires
218 if (w->port_output)
219 port_signal_map.add(c.second, c.first);
220 else
221 port_signal_map.add(c.first, c.second);
222 }
223 }
224
225 for (auto &it : tpl->cells_)
226 {
227 RTLIL::IdString c_name = it.second->name;
228
229 if (!flatten_mode && c_name == "\\_TECHMAP_REPLACE_")
230 c_name = orig_cell_name;
231 else
232 apply_prefix(cell->name, c_name);
233
234 RTLIL::Cell *c = module->addCell(c_name, it.second);
235 design->select(module, c);
236
237 if (!flatten_mode && c->type.substr(0, 2) == "\\$")
238 c->type = c->type.substr(1);
239
240 for (auto &it2 : c->connections_) {
241 apply_prefix(cell->name, it2.second, module);
242 port_signal_map.apply(it2.second);
243 }
244 }
245
246 for (auto &it : tpl->connections()) {
247 RTLIL::SigSig c = it;
248 apply_prefix(cell->name, c.first, module);
249 apply_prefix(cell->name, c.second, module);
250 port_signal_map.apply(c.first);
251 port_signal_map.apply(c.second);
252 module->connect(c);
253 }
254
255 module->remove(cell);
256 }
257
258 bool techmap_module(RTLIL::Design *design, RTLIL::Module *module, RTLIL::Design *map, std::set<RTLIL::Cell*> &handled_cells,
259 const std::map<RTLIL::IdString, std::set<RTLIL::IdString>> &celltypeMap)
260 {
261 if (!design->selected(module))
262 return false;
263
264 bool log_continue = false;
265 bool did_something = false;
266
267 SigMap sigmap(module);
268
269 TopoSort<RTLIL::Cell*> cells;
270 std::map<RTLIL::Cell*, std::set<RTLIL::SigBit>> cell_to_inbit;
271 std::map<RTLIL::SigBit, std::set<RTLIL::Cell*>> outbit_to_cell;
272
273 for (auto cell : module->cells())
274 {
275 if (!design->selected(module, cell) || handled_cells.count(cell) > 0)
276 continue;
277
278 if (celltypeMap.count(cell->type) == 0) {
279 if (assert_mode && cell->type.back() != '_')
280 log_error("(ASSERT MODE) No matching template cell for type %s found.\n", log_id(cell->type));
281 continue;
282 }
283
284 for (auto &conn : cell->connections())
285 {
286 RTLIL::SigSpec sig = sigmap(conn.second);
287 sig.remove_const();
288
289 if (SIZE(sig) == 0)
290 continue;
291
292 for (auto &tpl_name : celltypeMap.at(cell->type)) {
293 RTLIL::Module *tpl = map->modules_[tpl_name];
294 RTLIL::Wire *port = tpl->wire(conn.first);
295 if (port && port->port_input)
296 cell_to_inbit[cell].insert(sig.begin(), sig.end());
297 if (port && port->port_output)
298 for (auto &bit : sig)
299 outbit_to_cell[bit].insert(cell);
300 }
301 }
302
303 cells.node(cell);
304 }
305
306 for (auto &it_right : cell_to_inbit)
307 for (auto &it_sigbit : it_right.second)
308 for (auto &it_left : outbit_to_cell[it_sigbit])
309 cells.edge(it_left, it_right.first);
310
311 cells.sort();
312
313 for (auto cell : cells.sorted)
314 {
315 log_assert(handled_cells.count(cell) == 0);
316 log_assert(cell == module->cell(cell->name));
317 bool mapped_cell = false;
318
319 for (auto &tpl_name : celltypeMap.at(cell->type))
320 {
321 std::string derived_name = tpl_name;
322 RTLIL::Module *tpl = map->modules_[tpl_name];
323 std::map<RTLIL::IdString, RTLIL::Const> parameters = cell->parameters;
324
325 if (tpl->get_bool_attribute("\\blackbox"))
326 continue;
327
328 if (!flatten_mode)
329 {
330 if (tpl->get_bool_attribute("\\techmap_simplemap"))
331 {
332 if (extern_mode)
333 {
334 log("WARNING: Mapping simplemap cell %s.%s (%s) in -extern mode is not supported yet.\n", log_id(module), log_id(cell), log_id(cell->type));
335 break;
336 }
337 else
338 {
339 log("Mapping %s.%s (%s) with simplemap.\n", RTLIL::id2cstr(module->name), RTLIL::id2cstr(cell->name), RTLIL::id2cstr(cell->type));
340 if (simplemap_mappers.count(cell->type) == 0)
341 log_error("No simplemap mapper for cell type %s found!\n", RTLIL::id2cstr(cell->type));
342 simplemap_mappers.at(cell->type)(module, cell);
343 module->remove(cell);
344 cell = NULL;
345 did_something = true;
346 mapped_cell = true;
347 break;
348 }
349 }
350
351 for (auto conn : cell->connections()) {
352 if (conn.first.substr(0, 1) == "$")
353 continue;
354 if (tpl->wires_.count(conn.first) > 0 && tpl->wires_.at(conn.first)->port_id > 0)
355 continue;
356 if (!conn.second.is_fully_const() || parameters.count(conn.first) > 0 || tpl->avail_parameters.count(conn.first) == 0)
357 goto next_tpl;
358 parameters[conn.first] = conn.second.as_const();
359 }
360
361 if (0) {
362 next_tpl:
363 continue;
364 }
365
366 if (tpl->avail_parameters.count("\\_TECHMAP_CELLTYPE_") != 0)
367 parameters["\\_TECHMAP_CELLTYPE_"] = RTLIL::unescape_id(cell->type);
368
369 for (auto conn : cell->connections()) {
370 if (tpl->avail_parameters.count(stringf("\\_TECHMAP_CONSTMSK_%s_", RTLIL::id2cstr(conn.first))) != 0) {
371 std::vector<RTLIL::SigBit> v = sigmap(conn.second).to_sigbit_vector();
372 for (auto &bit : v)
373 bit = RTLIL::SigBit(bit.wire == NULL ? RTLIL::State::S1 : RTLIL::State::S0);
374 parameters[stringf("\\_TECHMAP_CONSTMSK_%s_", RTLIL::id2cstr(conn.first))] = RTLIL::SigSpec(v).as_const();
375 }
376 if (tpl->avail_parameters.count(stringf("\\_TECHMAP_CONSTVAL_%s_", RTLIL::id2cstr(conn.first))) != 0) {
377 std::vector<RTLIL::SigBit> v = sigmap(conn.second).to_sigbit_vector();
378 for (auto &bit : v)
379 if (bit.wire != NULL)
380 bit = RTLIL::SigBit(RTLIL::State::Sx);
381 parameters[stringf("\\_TECHMAP_CONSTVAL_%s_", RTLIL::id2cstr(conn.first))] = RTLIL::SigSpec(v).as_const();
382 }
383 }
384
385 int unique_bit_id_counter = 0;
386 std::map<RTLIL::SigBit, int> unique_bit_id;
387 unique_bit_id[RTLIL::State::S0] = unique_bit_id_counter++;
388 unique_bit_id[RTLIL::State::S1] = unique_bit_id_counter++;
389 unique_bit_id[RTLIL::State::Sx] = unique_bit_id_counter++;
390 unique_bit_id[RTLIL::State::Sz] = unique_bit_id_counter++;
391
392 for (auto conn : cell->connections())
393 if (tpl->avail_parameters.count(stringf("\\_TECHMAP_CONNMAP_%s_", RTLIL::id2cstr(conn.first))) != 0) {
394 for (auto &bit : sigmap(conn.second).to_sigbit_vector())
395 if (unique_bit_id.count(bit) == 0)
396 unique_bit_id[bit] = unique_bit_id_counter++;
397 }
398
399 int bits = 0;
400 for (int i = 0; i < 32; i++)
401 if (((unique_bit_id_counter-1) & (1 << i)) != 0)
402 bits = i;
403 if (tpl->avail_parameters.count("\\_TECHMAP_BITS_CONNMAP_"))
404 parameters["\\_TECHMAP_BITS_CONNMAP_"] = bits;
405
406 for (auto conn : cell->connections())
407 if (tpl->avail_parameters.count(stringf("\\_TECHMAP_CONNMAP_%s_", RTLIL::id2cstr(conn.first))) != 0) {
408 RTLIL::Const value;
409 for (auto &bit : sigmap(conn.second).to_sigbit_vector()) {
410 RTLIL::Const chunk(unique_bit_id.at(bit), bits);
411 value.bits.insert(value.bits.end(), chunk.bits.begin(), chunk.bits.end());
412 }
413 parameters[stringf("\\_TECHMAP_CONNMAP_%s_", RTLIL::id2cstr(conn.first))] = value;
414 }
415 }
416
417 std::pair<RTLIL::IdString, std::map<RTLIL::IdString, RTLIL::Const>> key(tpl_name, parameters);
418 if (techmap_cache.count(key) > 0) {
419 tpl = techmap_cache[key];
420 } else {
421 if (cell->parameters.size() != 0) {
422 derived_name = tpl->derive(map, parameters);
423 tpl = map->module(derived_name);
424 log_continue = true;
425 }
426 techmap_cache[key] = tpl;
427 }
428
429 if (flatten_mode) {
430 techmap_do_cache[tpl] = true;
431 } else {
432 RTLIL::Module *constmapped_tpl = map->module(constmap_tpl_name(sigmap, tpl, cell, false));
433 if (constmapped_tpl != nullptr)
434 tpl = constmapped_tpl;
435 }
436
437 if (techmap_do_cache.count(tpl) == 0)
438 {
439 bool keep_running = true;
440 techmap_do_cache[tpl] = true;
441
442 std::set<std::string> techmap_wire_names;
443
444 while (keep_running)
445 {
446 TechmapWires twd = techmap_find_special_wires(tpl);
447 keep_running = false;
448
449 for (auto &it : twd)
450 techmap_wire_names.insert(it.first);
451
452 for (auto &it : twd["_TECHMAP_FAIL_"]) {
453 RTLIL::SigSpec value = it.value;
454 if (value.is_fully_const() && value.as_bool()) {
455 log("Not using module `%s' from techmap as it contains a %s marker wire with non-zero value %s.\n",
456 derived_name.c_str(), RTLIL::id2cstr(it.wire->name), log_signal(value));
457 techmap_do_cache[tpl] = false;
458 }
459 }
460
461 if (!techmap_do_cache[tpl])
462 break;
463
464 for (auto &it : twd)
465 {
466 if (it.first.substr(0, 12) != "_TECHMAP_DO_" || it.second.empty())
467 continue;
468
469 auto &data = it.second.front();
470
471 if (!data.value.is_fully_const())
472 log_error("Techmap yielded config wire %s with non-const value %s.\n", RTLIL::id2cstr(data.wire->name), log_signal(data.value));
473
474 techmap_wire_names.erase(it.first);
475
476 const char *p = data.wire->name.c_str();
477 const char *q = strrchr(p+1, '.');
478 q = q ? q : p+1;
479
480 std::string cmd_string = data.value.as_const().decode_string();
481
482 if (cmd_string.rfind("CONSTMAP; ", 0) == 0)
483 {
484 cmd_string = cmd_string.substr(strlen("CONSTMAP; "));
485
486 log("Analyzing pattern of constant bits for this cell:\n");
487 std::string new_tpl_name = constmap_tpl_name(sigmap, tpl, cell, true);
488 log("Creating constmapped module `%s'.\n", log_id(new_tpl_name));
489 log_assert(map->module(new_tpl_name) == nullptr);
490
491 RTLIL::Module *new_tpl = map->addModule(new_tpl_name);
492 tpl->cloneInto(new_tpl);
493
494 techmap_do_cache.erase(tpl);
495 techmap_do_cache[new_tpl] = true;
496 tpl = new_tpl;
497
498 std::map<RTLIL::SigBit, RTLIL::SigBit> port_new2old_map;
499 std::map<RTLIL::SigBit, RTLIL::SigBit> port_connmap;
500 std::map<RTLIL::SigBit, RTLIL::SigBit> cellbits_to_tplbits;
501
502 for (auto wire : tpl->wires().to_vector())
503 {
504 if (!wire->port_input || wire->port_output)
505 continue;
506
507 std::string port_name = wire->name;
508 tpl->rename(wire, NEW_ID);
509
510 RTLIL::Wire *new_wire = tpl->addWire(port_name, wire);
511 wire->port_input = false;
512
513 for (int i = 0; i < wire->width; i++) {
514 port_new2old_map[RTLIL::SigBit(new_wire, i)] = RTLIL::SigBit(wire, i);
515 port_connmap[RTLIL::SigBit(wire, i)] = RTLIL::SigBit(new_wire, i);
516 }
517 }
518
519 for (auto conn : cell->connections())
520 for (int i = 0; i < SIZE(conn.second); i++)
521 {
522 RTLIL::SigBit bit = sigmap(conn.second[i]);
523 RTLIL::SigBit tplbit(tpl->wire(conn.first), i);
524
525 if (bit.wire == nullptr)
526 {
527 RTLIL::SigBit oldbit = port_new2old_map.at(tplbit);
528 port_connmap.at(oldbit) = bit;
529 }
530 else if (cellbits_to_tplbits.count(bit))
531 {
532 RTLIL::SigBit oldbit = port_new2old_map.at(tplbit);
533 port_connmap.at(oldbit) = cellbits_to_tplbits[bit];
534 }
535 else
536 cellbits_to_tplbits[bit] = tplbit;
537 }
538
539 RTLIL::SigSig port_conn;
540 for (auto &it : port_connmap) {
541 port_conn.first.append_bit(it.first);
542 port_conn.second.append_bit(it.second);
543 }
544 tpl->connect(port_conn);
545 }
546
547 Pass::call_on_module(map, tpl, cmd_string);
548
549 log_assert(!strncmp(q, "_TECHMAP_DO_", 12));
550 std::string new_name = data.wire->name.substr(0, q-p) + "_TECHMAP_DONE_" + data.wire->name.substr(q-p+12);
551 while (tpl->wires_.count(new_name))
552 new_name += "_";
553 tpl->rename(data.wire->name, new_name);
554
555 keep_running = true;
556 break;
557 }
558 }
559
560 TechmapWires twd = techmap_find_special_wires(tpl);
561 for (auto &it : twd) {
562 if (it.first != "_TECHMAP_FAIL_" && it.first.substr(0, 12) != "_TECHMAP_DO_" && it.first.substr(0, 14) != "_TECHMAP_DONE_")
563 log_error("Techmap yielded unknown config wire %s.\n", it.first.c_str());
564 if (techmap_do_cache[tpl])
565 for (auto &it2 : it.second)
566 if (!it2.value.is_fully_const())
567 log_error("Techmap yielded config wire %s with non-const value %s.\n", RTLIL::id2cstr(it2.wire->name), log_signal(it2.value));
568 techmap_wire_names.erase(it.first);
569 }
570
571 for (auto &it : techmap_wire_names)
572 log_error("Techmap special wire %s disappeared. This is considered a fatal error.\n", RTLIL::id2cstr(it));
573 }
574
575 if (techmap_do_cache.at(tpl) == false)
576 continue;
577
578 if (log_continue) {
579 log_header("Continuing TECHMAP pass.\n");
580 log_continue = false;
581 }
582
583 if (extern_mode)
584 {
585 std::string m_name = stringf("$extern:%s", log_id(tpl));
586
587 if (!design->module(m_name))
588 {
589 RTLIL::Module *m = design->addModule(m_name);
590 tpl->cloneInto(m);
591
592 for (auto cell : m->cells()) {
593 if (cell->type.substr(0, 2) == "\\$")
594 cell->type = cell->type.substr(1);
595 }
596
597 module_queue.insert(m);
598 }
599
600 log("Mapping %s.%s to imported %s.\n", log_id(module), log_id(cell), log_id(m_name));
601 cell->type = m_name;
602 cell->parameters.clear();
603 }
604 else
605 {
606 techmap_module_worker(design, module, cell, tpl);
607 cell = NULL;
608 }
609 did_something = true;
610 mapped_cell = true;
611 break;
612 }
613
614 if (assert_mode && !mapped_cell)
615 log_error("(ASSERT MODE) Failed to map cell %s.%s (%s).\n", log_id(module), log_id(cell), log_id(cell->type));
616
617 handled_cells.insert(cell);
618 }
619
620 if (log_continue) {
621 log_header("Continuing TECHMAP pass.\n");
622 log_continue = false;
623 }
624
625 return did_something;
626 }
627 };
628
629 struct TechmapPass : public Pass {
630 TechmapPass() : Pass("techmap", "generic technology mapper") { }
631 virtual void help()
632 {
633 // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
634 log("\n");
635 log(" techmap [-map filename] [selection]\n");
636 log("\n");
637 log("This pass implements a very simple technology mapper that replaces cells in\n");
638 log("the design with implementations given in form of a verilog or ilang source\n");
639 log("file.\n");
640 log("\n");
641 log(" -map filename\n");
642 log(" the library of cell implementations to be used.\n");
643 log(" without this parameter a builtin library is used that\n");
644 log(" transforms the internal RTL cells to the internal gate\n");
645 log(" library.\n");
646 log("\n");
647 log(" -share_map filename\n");
648 log(" like -map, but look for the file in the share directory (where the\n");
649 log(" yosys data files are). this is mainly used internally when techmap\n");
650 log(" is called from other commands.\n");
651 log("\n");
652 log(" -extern\n");
653 log(" load the cell implementations as separate modules into the design\n");
654 log(" instead of inlining them.\n");
655 log("\n");
656 log(" -max_iter <number>\n");
657 log(" only run the specified number of iterations.\n");
658 log("\n");
659 log(" -assert\n");
660 log(" this option will cause techmap to exit with an error if it can't map\n");
661 log(" a selected cell. only cell types that end on an underscore are accepted\n");
662 log(" as final cell types by this mode.\n");
663 log("\n");
664 log(" -D <define>, -I <incdir>\n");
665 log(" this options are passed as-is to the verilog frontend for loading the\n");
666 log(" map file. Note that the verilog frontend is also called with the\n");
667 log(" '-ignore_redef' option set.\n");
668 log("\n");
669 log("When a module in the map file has the 'techmap_celltype' attribute set, it will\n");
670 log("match cells with a type that match the text value of this attribute. Otherwise\n");
671 log("the module name will be used to match the cell.\n");
672 log("\n");
673 log("When a module in the map file has the 'techmap_simplemap' attribute set, techmap\n");
674 log("will use 'simplemap' (see 'help simplemap') to map cells matching the module.\n");
675 log("\n");
676 log("All wires in the modules from the map file matching the pattern _TECHMAP_*\n");
677 log("or *._TECHMAP_* are special wires that are used to pass instructions from\n");
678 log("the mapping module to the techmap command. At the moment the following special\n");
679 log("wires are supported:\n");
680 log("\n");
681 log(" _TECHMAP_FAIL_\n");
682 log(" When this wire is set to a non-zero constant value, techmap will not\n");
683 log(" use this module and instead try the next module with a matching\n");
684 log(" 'techmap_celltype' attribute.\n");
685 log("\n");
686 log(" When such a wire exists but does not have a constant value after all\n");
687 log(" _TECHMAP_DO_* commands have been executed, an error is generated.\n");
688 log("\n");
689 log(" _TECHMAP_DO_*\n");
690 log(" This wires are evaluated in alphabetical order. The constant text value\n");
691 log(" of this wire is a yosys command (or sequence of commands) that is run\n");
692 log(" by techmap on the module. A common use case is to run 'proc' on modules\n");
693 log(" that are written using always-statements.\n");
694 log("\n");
695 log(" When such a wire has a non-constant value at the time it is to be\n");
696 log(" evaluated, an error is produced. That means it is possible for such a\n");
697 log(" wire to start out as non-constant and evaluate to a constant value\n");
698 log(" during processing of other _TECHMAP_DO_* commands.\n");
699 log("\n");
700 log(" A _TECHMAP_DO_* command may start with the special token 'CONSTMAP; '.\n");
701 log(" in this case techmap will create a copy for each distinct configuration\n");
702 log(" of constant inputs and shorted inputs at this point and import the\n");
703 log(" constant and connected bits into the map module. All further commands\n");
704 log(" are executed in this copy. This is a very convenient way of creating\n");
705 log(" optimizied specializations of techmap modules without using the special\n");
706 log(" parameters described below.\n");
707 log("\n");
708 log("In addition to this special wires, techmap also supports special parameters in\n");
709 log("modules in the map file:\n");
710 log("\n");
711 log(" _TECHMAP_CELLTYPE_\n");
712 log(" When a parameter with this name exists, it will be set to the type name\n");
713 log(" of the cell that matches the module.\n");
714 log("\n");
715 log(" _TECHMAP_CONSTMSK_<port-name>_\n");
716 log(" _TECHMAP_CONSTVAL_<port-name>_\n");
717 log(" When this pair of parameters is available in a module for a port, then\n");
718 log(" former has a 1-bit for each constant input bit and the latter has the\n");
719 log(" value for this bit. The unused bits of the latter are set to undef (x).\n");
720 log("\n");
721 log(" _TECHMAP_BITS_CONNMAP_\n");
722 log(" _TECHMAP_CONNMAP_<port-name>_\n");
723 log(" For an N-bit port, the _TECHMAP_CONNMAP_<port-name>_ parameter, if it\n");
724 log(" exists, will be set to an N*_TECHMAP_BITS_CONNMAP_ bit vector containing\n");
725 log(" N words (of _TECHMAP_BITS_CONNMAP_ bits each) that assign each single\n");
726 log(" bit driver a unique id. The values 0-3 are reserved for 0, 1, x, and z.\n");
727 log(" This can be used to detect shorted inputs.\n");
728 log("\n");
729 log("When a module in the map file has a parameter where the according cell in the\n");
730 log("design has a port, the module from the map file is only used if the port in\n");
731 log("the design is connected to a constant value. The parameter is then set to the\n");
732 log("constant value.\n");
733 log("\n");
734 log("A cell with the name _TECHMAP_REPLACE_ in the map file will inherit the name\n");
735 log("of the cell that is beeing replaced.\n");
736 log("\n");
737 log("See 'help extract' for a pass that does the opposite thing.\n");
738 log("\n");
739 log("See 'help flatten' for a pass that does flatten the design (which is\n");
740 log("esentially techmap but using the design itself as map library).\n");
741 log("\n");
742 }
743 virtual void execute(std::vector<std::string> args, RTLIL::Design *design)
744 {
745 log_header("Executing TECHMAP pass (map to technology primitives).\n");
746 log_push();
747
748 TechmapWorker worker;
749 simplemap_get_mappers(worker.simplemap_mappers);
750
751 std::vector<std::string> map_files;
752 std::string verilog_frontend = "verilog -ignore_redef";
753 int max_iter = -1;
754
755 size_t argidx;
756 std::string proc_share_path = proc_share_dirname();
757 for (argidx = 1; argidx < args.size(); argidx++) {
758 if (args[argidx] == "-map" && argidx+1 < args.size()) {
759 map_files.push_back(args[++argidx]);
760 continue;
761 }
762 if (args[argidx] == "-share_map" && argidx+1 < args.size()) {
763 map_files.push_back(proc_share_path + args[++argidx]);
764 continue;
765 }
766 if (args[argidx] == "-max_iter" && argidx+1 < args.size()) {
767 max_iter = atoi(args[++argidx].c_str());
768 continue;
769 }
770 if (args[argidx] == "-D" && argidx+1 < args.size()) {
771 verilog_frontend += " -D " + args[++argidx];
772 continue;
773 }
774 if (args[argidx] == "-I" && argidx+1 < args.size()) {
775 verilog_frontend += " -I " + args[++argidx];
776 continue;
777 }
778 if (args[argidx] == "-assert") {
779 worker.assert_mode = true;
780 continue;
781 }
782 if (args[argidx] == "-extern") {
783 worker.extern_mode = true;
784 continue;
785 }
786 break;
787 }
788 extra_args(args, argidx, design);
789
790 RTLIL::Design *map = new RTLIL::Design;
791 if (map_files.empty()) {
792 FILE *f = fmemopen(stdcells_code, strlen(stdcells_code), "rt");
793 Frontend::frontend_call(map, f, "<stdcells.v>", verilog_frontend);
794 fclose(f);
795 } else
796 for (auto &fn : map_files)
797 if (fn.substr(0, 1) == "%") {
798 if (!saved_designs.count(fn.substr(1))) {
799 delete map;
800 log_cmd_error("Can't saved design `%s'.\n", fn.c_str()+1);
801 }
802 for (auto mod : saved_designs.at(fn.substr(1))->modules())
803 if (!map->has(mod->name))
804 map->add(mod->clone());
805 } else {
806 FILE *f = fopen(fn.c_str(), "rt");
807 if (f == NULL)
808 log_cmd_error("Can't open map file `%s'\n", fn.c_str());
809 Frontend::frontend_call(map, f, fn, (fn.size() > 3 && fn.substr(fn.size()-3) == ".il") ? "ilang" : verilog_frontend);
810 fclose(f);
811 }
812
813 std::map<RTLIL::IdString, RTLIL::Module*> modules_new;
814 for (auto &it : map->modules_) {
815 if (it.first.substr(0, 2) == "\\$")
816 it.second->name = it.first.substr(1);
817 modules_new[it.second->name] = it.second;
818 }
819 map->modules_.swap(modules_new);
820
821 std::map<RTLIL::IdString, std::set<RTLIL::IdString>> celltypeMap;
822 for (auto &it : map->modules_) {
823 if (it.second->attributes.count("\\techmap_celltype") && !it.second->attributes.at("\\techmap_celltype").bits.empty()) {
824 char *p = strdup(it.second->attributes.at("\\techmap_celltype").decode_string().c_str());
825 for (char *q = strtok(p, " \t\r\n"); q; q = strtok(NULL, " \t\r\n"))
826 celltypeMap[RTLIL::escape_id(q)].insert(it.first);
827 free(p);
828 } else
829 celltypeMap[it.first].insert(it.first);
830 }
831
832 worker.module_queue = design->modules();
833 while (!worker.module_queue.empty())
834 {
835 RTLIL::Module *module = *worker.module_queue.begin();
836 worker.module_queue.erase(module);
837
838 bool did_something = true;
839 std::set<RTLIL::Cell*> handled_cells;
840 while (did_something) {
841 did_something = false;
842 if (worker.techmap_module(design, module, map, handled_cells, celltypeMap))
843 did_something = true;
844 if (did_something)
845 module->check();
846 if (max_iter > 0 && --max_iter == 0)
847 break;
848 }
849 }
850
851 log("No more expansions possible.\n");
852 delete map;
853
854 log_pop();
855 }
856 } TechmapPass;
857
858 struct FlattenPass : public Pass {
859 FlattenPass() : Pass("flatten", "flatten design") { }
860 virtual void help()
861 {
862 // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
863 log("\n");
864 log(" flatten [selection]\n");
865 log("\n");
866 log("This pass flattens the design by replacing cells by their implementation. This\n");
867 log("pass is very simmilar to the 'techmap' pass. The only difference is that this\n");
868 log("pass is using the current design as mapping library.\n");
869 log("\n");
870 }
871 virtual void execute(std::vector<std::string> args, RTLIL::Design *design)
872 {
873 log_header("Executing FLATTEN pass (flatten design).\n");
874 log_push();
875
876 extra_args(args, 1, design);
877
878 TechmapWorker worker;
879 worker.flatten_mode = true;
880
881 std::map<RTLIL::IdString, std::set<RTLIL::IdString>> celltypeMap;
882 for (auto &it : design->modules_)
883 celltypeMap[it.first].insert(it.first);
884
885 RTLIL::Module *top_mod = NULL;
886 if (design->full_selection())
887 for (auto mod : design->modules())
888 if (mod->get_bool_attribute("\\top"))
889 top_mod = mod;
890
891 bool did_something = true;
892 std::set<RTLIL::Cell*> handled_cells;
893 while (did_something) {
894 did_something = false;
895 if (top_mod != NULL) {
896 if (worker.techmap_module(design, top_mod, design, handled_cells, celltypeMap))
897 did_something = true;
898 } else {
899 for (auto mod : design->modules())
900 if (worker.techmap_module(design, mod, design, handled_cells, celltypeMap))
901 did_something = true;
902 }
903 }
904
905 log("No more expansions possible.\n");
906
907 if (top_mod != NULL) {
908 std::map<RTLIL::IdString, RTLIL::Module*> new_modules;
909 for (auto mod : design->modules())
910 if (mod == top_mod || mod->get_bool_attribute("\\blackbox")) {
911 new_modules[mod->name] = mod;
912 } else {
913 log("Deleting now unused module %s.\n", log_id(mod));
914 delete mod;
915 }
916 design->modules_.swap(new_modules);
917 }
918
919 log_pop();
920 }
921 } FlattenPass;
922