Merge pull request #3310 from robinsonb5-PRs/master
[yosys.git] / passes / techmap / iopadmap.cc
1 /*
2 * yosys -- Yosys Open SYnthesis Suite
3 *
4 * Copyright (C) 2012 Claire Xenia Wolf <claire@yosyshq.com>
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
23 USING_YOSYS_NAMESPACE
24 PRIVATE_NAMESPACE_BEGIN
25
26 void split_portname_pair(std::string &port1, std::string &port2)
27 {
28 size_t pos = port1.find_first_of(':');
29 if (pos != std::string::npos) {
30 port2 = port1.substr(pos+1);
31 port1 = port1.substr(0, pos);
32 }
33 }
34
35 struct IopadmapPass : public Pass {
36 IopadmapPass() : Pass("iopadmap", "technology mapping of i/o pads (or buffers)") { }
37 void help() override
38 {
39 log("\n");
40 log(" iopadmap [options] [selection]\n");
41 log("\n");
42 log("Map module inputs/outputs to PAD cells from a library. This pass\n");
43 log("can only map to very simple PAD cells. Use 'techmap' to further map\n");
44 log("the resulting cells to more sophisticated PAD cells.\n");
45 log("\n");
46 log(" -inpad <celltype> <in_port>[:<ext_port>]\n");
47 log(" Map module input ports to the given cell type with the\n");
48 log(" given output port name. if a 2nd portname is given, the\n");
49 log(" signal is passed through the pad cell, using the 2nd\n");
50 log(" portname as the port facing the module port.\n");
51 log("\n");
52 log(" -outpad <celltype> <out_port>[:<ext_port>]\n");
53 log(" -inoutpad <celltype> <io_port>[:<ext_port>]\n");
54 log(" Similar to -inpad, but for output and inout ports.\n");
55 log("\n");
56 log(" -toutpad <celltype> <oe_port>:<out_port>[:<ext_port>]\n");
57 log(" Merges $_TBUF_ cells into the output pad cell. This takes precedence\n");
58 log(" over the other -outpad cell. The first portname is the enable input\n");
59 log(" of the tristate driver, which can be prefixed with `~` for negative\n");
60 log(" polarity enable.\n");
61 log("\n");
62 log(" -tinoutpad <celltype> <oe_port>:<in_port>:<out_port>[:<ext_port>]\n");
63 log(" Merges $_TBUF_ cells into the inout pad cell. This takes precedence\n");
64 log(" over the other -inoutpad cell. The first portname is the enable input\n");
65 log(" of the tristate driver and the 2nd portname is the internal output\n");
66 log(" buffering the external signal. Like with `-toutpad`, the enable can\n");
67 log(" be marked as negative polarity by prefixing the name with `~`.\n");
68 log("\n");
69 log(" -ignore <celltype> <portname>[:<portname>]*\n");
70 log(" Skips mapping inputs/outputs that are already connected to given\n");
71 log(" ports of the given cell. Can be used multiple times. This is in\n");
72 log(" addition to the cells specified as mapping targets.\n");
73 log("\n");
74 log(" -widthparam <param_name>\n");
75 log(" Use the specified parameter name to set the port width.\n");
76 log("\n");
77 log(" -nameparam <param_name>\n");
78 log(" Use the specified parameter to set the port name.\n");
79 log("\n");
80 log(" -bits\n");
81 log(" create individual bit-wide buffers even for ports that\n");
82 log(" are wider. (the default behavior is to create word-wide\n");
83 log(" buffers using -widthparam to set the word size on the cell.)\n");
84 log("\n");
85 log("Tristate PADS (-toutpad, -tinoutpad) always operate in -bits mode.\n");
86 log("\n");
87 }
88
89 void module_queue(Design *design, Module *module, std::vector<Module *> &modules_sorted, pool<Module *> &modules_processed) {
90 if (modules_processed.count(module))
91 return;
92 for (auto cell : module->cells()) {
93 Module *submodule = design->module(cell->type);
94 if (!submodule)
95 continue;
96 module_queue(design, submodule, modules_sorted, modules_processed);
97 }
98 modules_sorted.push_back(module);
99 modules_processed.insert(module);
100 }
101
102 void execute(std::vector<std::string> args, RTLIL::Design *design) override
103 {
104 log_header(design, "Executing IOPADMAP pass (mapping inputs/outputs to IO-PAD cells).\n");
105
106 std::string inpad_celltype, inpad_portname_o, inpad_portname_pad;
107 std::string outpad_celltype, outpad_portname_i, outpad_portname_pad;
108 std::string inoutpad_celltype, inoutpad_portname_io, inoutpad_portname_pad;
109 std::string toutpad_celltype, toutpad_portname_oe, toutpad_portname_i, toutpad_portname_pad;
110 std::string tinoutpad_celltype, tinoutpad_portname_oe, tinoutpad_portname_o, tinoutpad_portname_i, tinoutpad_portname_pad;
111 bool toutpad_neg_oe = false, tinoutpad_neg_oe = false;
112 std::string widthparam, nameparam;
113 pool<pair<IdString, IdString>> ignore;
114 bool flag_bits = false;
115
116 size_t argidx;
117 for (argidx = 1; argidx < args.size(); argidx++)
118 {
119 std::string arg = args[argidx];
120 if (arg == "-inpad" && argidx+2 < args.size()) {
121 inpad_celltype = args[++argidx];
122 inpad_portname_o = args[++argidx];
123 split_portname_pair(inpad_portname_o, inpad_portname_pad);
124 continue;
125 }
126 if (arg == "-outpad" && argidx+2 < args.size()) {
127 outpad_celltype = args[++argidx];
128 outpad_portname_i = args[++argidx];
129 split_portname_pair(outpad_portname_i, outpad_portname_pad);
130 continue;
131 }
132 if (arg == "-inoutpad" && argidx+2 < args.size()) {
133 inoutpad_celltype = args[++argidx];
134 inoutpad_portname_io = args[++argidx];
135 split_portname_pair(inoutpad_portname_io, inoutpad_portname_pad);
136 continue;
137 }
138 if (arg == "-toutpad" && argidx+2 < args.size()) {
139 toutpad_celltype = args[++argidx];
140 toutpad_portname_oe = args[++argidx];
141 split_portname_pair(toutpad_portname_oe, toutpad_portname_i);
142 split_portname_pair(toutpad_portname_i, toutpad_portname_pad);
143 if (toutpad_portname_oe[0] == '~') {
144 toutpad_neg_oe = true;
145 toutpad_portname_oe = toutpad_portname_oe.substr(1);
146 }
147 continue;
148 }
149 if (arg == "-tinoutpad" && argidx+2 < args.size()) {
150 tinoutpad_celltype = args[++argidx];
151 tinoutpad_portname_oe = args[++argidx];
152 split_portname_pair(tinoutpad_portname_oe, tinoutpad_portname_o);
153 split_portname_pair(tinoutpad_portname_o, tinoutpad_portname_i);
154 split_portname_pair(tinoutpad_portname_i, tinoutpad_portname_pad);
155 if (tinoutpad_portname_oe[0] == '~') {
156 tinoutpad_neg_oe = true;
157 tinoutpad_portname_oe = tinoutpad_portname_oe.substr(1);
158 }
159 continue;
160 }
161 if (arg == "-ignore" && argidx+2 < args.size()) {
162 std::string ignore_celltype = args[++argidx];
163 std::string ignore_portname = args[++argidx];
164 std::string ignore_portname2;
165 while (!ignore_portname.empty()) {
166 split_portname_pair(ignore_portname, ignore_portname2);
167 ignore.insert(make_pair(RTLIL::escape_id(ignore_celltype), RTLIL::escape_id(ignore_portname)));
168
169 ignore_portname = ignore_portname2;
170 }
171 continue;
172 }
173 if (arg == "-widthparam" && argidx+1 < args.size()) {
174 widthparam = args[++argidx];
175 continue;
176 }
177 if (arg == "-nameparam" && argidx+1 < args.size()) {
178 nameparam = args[++argidx];
179 continue;
180 }
181 if (arg == "-bits") {
182 flag_bits = true;
183 continue;
184 }
185 break;
186 }
187 extra_args(args, argidx, design);
188
189 if (!inpad_portname_pad.empty())
190 ignore.insert(make_pair(RTLIL::escape_id(inpad_celltype), RTLIL::escape_id(inpad_portname_pad)));
191 if (!outpad_portname_pad.empty())
192 ignore.insert(make_pair(RTLIL::escape_id(outpad_celltype), RTLIL::escape_id(outpad_portname_pad)));
193 if (!inoutpad_portname_pad.empty())
194 ignore.insert(make_pair(RTLIL::escape_id(inoutpad_celltype), RTLIL::escape_id(inoutpad_portname_pad)));
195 if (!toutpad_portname_pad.empty())
196 ignore.insert(make_pair(RTLIL::escape_id(toutpad_celltype), RTLIL::escape_id(toutpad_portname_pad)));
197 if (!tinoutpad_portname_pad.empty())
198 ignore.insert(make_pair(RTLIL::escape_id(tinoutpad_celltype), RTLIL::escape_id(tinoutpad_portname_pad)));
199
200 // Recursively collect list of (module, port, bit) triples that already have buffers.
201
202 pool<pair<IdString, pair<IdString, int>>> buf_ports;
203
204 // Process submodules before module using them.
205 std::vector<Module *> modules_sorted;
206 pool<Module *> modules_processed;
207 for (auto module : design->selected_modules())
208 module_queue(design, module, modules_sorted, modules_processed);
209
210 for (auto module : modules_sorted)
211 {
212 pool<SigBit> buf_bits;
213 SigMap sigmap(module);
214
215 // Collect explicitly-marked already-buffered SigBits.
216 for (auto wire : module->wires())
217 if (wire->get_bool_attribute(ID::iopad_external_pin) || ignore.count(make_pair(module->name, wire->name)))
218 for (int i = 0; i < GetSize(wire); i++)
219 buf_bits.insert(sigmap(SigBit(wire, i)));
220
221 // Collect SigBits connected to already-buffered ports.
222 for (auto cell : module->cells())
223 for (auto port : cell->connections())
224 for (int i = 0; i < port.second.size(); i++)
225 if (buf_ports.count(make_pair(cell->type, make_pair(port.first, i))))
226 buf_bits.insert(sigmap(port.second[i]));
227
228 // Now fill buf_ports.
229 for (auto wire : module->wires())
230 if (wire->port_input || wire->port_output)
231 for (int i = 0; i < GetSize(wire); i++)
232 if (buf_bits.count(sigmap(SigBit(wire, i)))) {
233 buf_ports.insert(make_pair(module->name, make_pair(wire->name, i)));
234 log("Marking already mapped port: %s.%s[%d].\n", log_id(module), log_id(wire), i);
235 }
236 }
237
238 // Now do the actual buffer insertion.
239
240 for (auto module : design->selected_modules())
241 {
242 dict<Wire *, dict<int, pair<Cell *, IdString>>> rewrite_bits;
243 pool<SigSig> remove_conns;
244
245 if (!toutpad_celltype.empty() || !tinoutpad_celltype.empty())
246 {
247 dict<SigBit, Cell *> tbuf_bits;
248 pool<SigBit> driven_bits;
249 dict<SigBit, SigSig> z_conns;
250
251 // Gather tristate buffers and always-on drivers.
252 for (auto cell : module->cells())
253 if (cell->type == ID($_TBUF_)) {
254 SigBit bit = cell->getPort(ID::Y).as_bit();
255 tbuf_bits[bit] = cell;
256 } else {
257 for (auto port : cell->connections())
258 if (!cell->known() || cell->output(port.first))
259 for (auto bit : port.second)
260 driven_bits.insert(bit);
261 }
262
263 // If a wire is a target of an assignment, it is driven, unless the source is 'z.
264 for (auto &conn : module->connections())
265 for (int i = 0; i < GetSize(conn.first); i++) {
266 SigBit dstbit = conn.first[i];
267 SigBit srcbit = conn.second[i];
268 if (!srcbit.wire && srcbit.data == State::Sz) {
269 z_conns[dstbit] = conn;
270 continue;
271 }
272 driven_bits.insert(dstbit);
273 }
274
275 for (auto wire : module->selected_wires())
276 {
277 if (!wire->port_output)
278 continue;
279
280 // Don't handle inout ports if we have no suitable buffer type.
281 if (wire->port_input && tinoutpad_celltype.empty())
282 continue;
283
284 // likewise for output ports.
285 if (!wire->port_input && toutpad_celltype.empty())
286 continue;
287
288 for (int i = 0; i < GetSize(wire); i++)
289 {
290 SigBit wire_bit(wire, i);
291 Cell *tbuf_cell = nullptr;
292
293 if (buf_ports.count(make_pair(module->name, make_pair(wire->name, i))))
294 continue;
295
296 if (tbuf_bits.count(wire_bit))
297 tbuf_cell = tbuf_bits.at(wire_bit);
298
299 SigBit en_sig;
300 SigBit data_sig;
301 bool is_driven = driven_bits.count(wire_bit);
302
303 if (tbuf_cell != nullptr) {
304 // Found a tristate buffer — use it.
305 en_sig = tbuf_cell->getPort(ID::E).as_bit();
306 data_sig = tbuf_cell->getPort(ID::A).as_bit();
307 } else if (is_driven) {
308 // No tristate buffer, but an always-on driver is present.
309 // If this is an inout port, we're creating a tinoutpad
310 // anyway, just with a constant 1 as enable.
311 if (!wire->port_input)
312 continue;
313 en_sig = SigBit(State::S1);
314 data_sig = wire_bit;
315 } else {
316 // No driver on a wire. Create a tristate pad with always-0
317 // enable.
318 en_sig = SigBit(State::S0);
319 data_sig = SigBit(State::Sx);
320 if (z_conns.count(wire_bit))
321 remove_conns.insert(z_conns[wire_bit]);
322 }
323
324 if (wire->port_input)
325 {
326 log("Mapping port %s.%s[%d] using %s.\n", log_id(module), log_id(wire), i, tinoutpad_celltype.c_str());
327
328 Cell *cell = module->addCell(
329 module->uniquify(stringf("$iopadmap$%s.%s[%d]", log_id(module), log_id(wire), i)),
330 RTLIL::escape_id(tinoutpad_celltype));
331
332 if (tinoutpad_neg_oe)
333 en_sig = module->NotGate(NEW_ID, en_sig);
334 cell->setPort(RTLIL::escape_id(tinoutpad_portname_oe), en_sig);
335 cell->attributes[ID::keep] = RTLIL::Const(1);
336
337 if (tbuf_cell) {
338 module->remove(tbuf_cell);
339 cell->setPort(RTLIL::escape_id(tinoutpad_portname_o), wire_bit);
340 cell->setPort(RTLIL::escape_id(tinoutpad_portname_i), data_sig);
341 } else if (is_driven) {
342 cell->setPort(RTLIL::escape_id(tinoutpad_portname_i), wire_bit);
343 } else {
344 cell->setPort(RTLIL::escape_id(tinoutpad_portname_o), wire_bit);
345 cell->setPort(RTLIL::escape_id(tinoutpad_portname_i), data_sig);
346 }
347 if (!tinoutpad_portname_pad.empty())
348 rewrite_bits[wire][i] = make_pair(cell, RTLIL::escape_id(tinoutpad_portname_pad));
349 } else {
350 log("Mapping port %s.%s[%d] using %s.\n", log_id(module), log_id(wire), i, toutpad_celltype.c_str());
351
352 Cell *cell = module->addCell(
353 module->uniquify(stringf("$iopadmap$%s.%s[%d]", log_id(module), log_id(wire), i)),
354 RTLIL::escape_id(toutpad_celltype));
355
356 if (toutpad_neg_oe)
357 en_sig = module->NotGate(NEW_ID, en_sig);
358 cell->setPort(RTLIL::escape_id(toutpad_portname_oe), en_sig);
359 cell->setPort(RTLIL::escape_id(toutpad_portname_i), data_sig);
360 cell->attributes[ID::keep] = RTLIL::Const(1);
361
362 if (tbuf_cell) {
363 module->remove(tbuf_cell);
364 module->connect(wire_bit, data_sig);
365 }
366 if (!toutpad_portname_pad.empty())
367 rewrite_bits[wire][i] = make_pair(cell, RTLIL::escape_id(toutpad_portname_pad));
368 }
369 buf_ports.insert(make_pair(module->name, make_pair(wire->name, i)));
370 }
371 }
372 }
373
374 for (auto wire : module->selected_wires())
375 {
376 if (!wire->port_id)
377 continue;
378
379 std::string celltype, portname_int, portname_pad;
380 pool<int> skip_bit_indices;
381
382 for (int i = 0; i < GetSize(wire); i++)
383 if (buf_ports.count(make_pair(module->name, make_pair(wire->name, i))))
384 skip_bit_indices.insert(i);
385
386 if (GetSize(wire) == GetSize(skip_bit_indices))
387 continue;
388
389 if (wire->port_input && !wire->port_output) {
390 if (inpad_celltype.empty()) {
391 log("Don't map input port %s.%s: Missing option -inpad.\n", RTLIL::id2cstr(module->name), RTLIL::id2cstr(wire->name));
392 continue;
393 }
394 celltype = inpad_celltype;
395 portname_int = inpad_portname_o;
396 portname_pad = inpad_portname_pad;
397 } else
398 if (!wire->port_input && wire->port_output) {
399 if (outpad_celltype.empty()) {
400 log("Don't map output port %s.%s: Missing option -outpad.\n", RTLIL::id2cstr(module->name), RTLIL::id2cstr(wire->name));
401 continue;
402 }
403 celltype = outpad_celltype;
404 portname_int = outpad_portname_i;
405 portname_pad = outpad_portname_pad;
406 } else
407 if (wire->port_input && wire->port_output) {
408 if (inoutpad_celltype.empty()) {
409 log("Don't map inout port %s.%s: Missing option -inoutpad.\n", RTLIL::id2cstr(module->name), RTLIL::id2cstr(wire->name));
410 continue;
411 }
412 celltype = inoutpad_celltype;
413 portname_int = inoutpad_portname_io;
414 portname_pad = inoutpad_portname_pad;
415 } else
416 log_abort();
417
418 if (!flag_bits && wire->width != 1 && widthparam.empty()) {
419 log("Don't map multi-bit port %s.%s: Missing option -widthparam or -bits.\n", RTLIL::id2cstr(module->name), RTLIL::id2cstr(wire->name));
420 continue;
421 }
422
423 log("Mapping port %s.%s using %s.\n", RTLIL::id2cstr(module->name), RTLIL::id2cstr(wire->name), celltype.c_str());
424
425 if (flag_bits)
426 {
427 for (int i = 0; i < wire->width; i++)
428 {
429 if (skip_bit_indices.count(i))
430 continue;
431
432 SigBit wire_bit(wire, i);
433
434 RTLIL::Cell *cell = module->addCell(
435 module->uniquify(stringf("$iopadmap$%s.%s", log_id(module->name), log_id(wire->name))),
436 RTLIL::escape_id(celltype));
437 cell->setPort(RTLIL::escape_id(portname_int), wire_bit);
438
439 if (!portname_pad.empty())
440 rewrite_bits[wire][i] = make_pair(cell, RTLIL::escape_id(portname_pad));
441 if (!widthparam.empty())
442 cell->parameters[RTLIL::escape_id(widthparam)] = RTLIL::Const(1);
443 if (!nameparam.empty())
444 cell->parameters[RTLIL::escape_id(nameparam)] = RTLIL::Const(stringf("%s[%d]", RTLIL::id2cstr(wire->name), i));
445 cell->attributes[ID::keep] = RTLIL::Const(1);
446 }
447 }
448 else
449 {
450 RTLIL::Cell *cell = module->addCell(
451 module->uniquify(stringf("$iopadmap$%s.%s", log_id(module->name), log_id(wire->name))),
452 RTLIL::escape_id(celltype));
453 cell->setPort(RTLIL::escape_id(portname_int), RTLIL::SigSpec(wire));
454
455 if (!portname_pad.empty()) {
456 RTLIL::Wire *new_wire = NULL;
457 new_wire = module->addWire(
458 module->uniquify(stringf("$iopadmap$%s", log_id(wire))),
459 wire);
460 module->swap_names(new_wire, wire);
461 wire->attributes.clear();
462 cell->setPort(RTLIL::escape_id(portname_pad), RTLIL::SigSpec(new_wire));
463 }
464 if (!widthparam.empty())
465 cell->parameters[RTLIL::escape_id(widthparam)] = RTLIL::Const(wire->width);
466 if (!nameparam.empty())
467 cell->parameters[RTLIL::escape_id(nameparam)] = RTLIL::Const(RTLIL::id2cstr(wire->name));
468 cell->attributes[ID::keep] = RTLIL::Const(1);
469 }
470
471 if (!rewrite_bits.count(wire)) {
472 wire->port_id = 0;
473 wire->port_input = false;
474 wire->port_output = false;
475 }
476 }
477
478 if (!remove_conns.empty()) {
479 std::vector<SigSig> new_conns;
480 for (auto &conn : module->connections())
481 if (!remove_conns.count(conn))
482 new_conns.push_back(conn);
483 module->new_connections(new_conns);
484 }
485
486 for (auto &it : rewrite_bits) {
487 RTLIL::Wire *wire = it.first;
488 RTLIL::Wire *new_wire = module->addWire(
489 module->uniquify(stringf("$iopadmap$%s", log_id(wire))),
490 wire);
491 module->swap_names(new_wire, wire);
492 wire->attributes.clear();
493 for (int i = 0; i < wire->width; i++)
494 {
495 SigBit wire_bit(wire, i);
496 if (!it.second.count(i)) {
497 if (wire->port_output)
498 module->connect(SigSpec(new_wire, i), SigSpec(wire, i));
499 else
500 module->connect(SigSpec(wire, i), SigSpec(new_wire, i));
501 } else {
502 auto &new_conn = it.second.at(i);
503 new_conn.first->setPort(new_conn.second, RTLIL::SigSpec(new_wire, i));
504 }
505 }
506
507 if (wire->port_output) {
508 auto jt = new_wire->attributes.find(ID::init);
509 // For output ports, move \init attributes from old wire to new wire
510 if (jt != new_wire->attributes.end()) {
511 wire->attributes[ID::init] = std::move(jt->second);
512 new_wire->attributes.erase(jt);
513 }
514 }
515
516 wire->port_id = 0;
517 wire->port_input = false;
518 wire->port_output = false;
519 }
520
521 module->fixup_ports();
522 }
523 }
524 } IopadmapPass;
525
526 PRIVATE_NAMESPACE_END