Added support for i/o buffers to iopadmap
[yosys.git] / passes / techmap / iopadmap.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/register.h"
21 #include "kernel/rtlil.h"
22 #include "kernel/log.h"
23
24 static void split_portname_pair(std::string &port1, std::string &port2)
25 {
26 size_t pos = port1.find_first_of(':');
27 if (pos != std::string::npos) {
28 port2 = port1.substr(pos+1);
29 port1 = port1.substr(0, pos);
30 }
31 }
32
33 struct IopadmapPass : public Pass {
34 IopadmapPass() : Pass("iopadmap", "technology mapping of i/o pads (or buffers)") { }
35 virtual void help()
36 {
37 log("\n");
38 log(" iopadmap [options] [selection]\n");
39 log("\n");
40 log("Map module inputs/outputs to PAD cells from a library. This pass\n");
41 log("can only map to very simple PAD cells. Use 'techmap' to further map\n");
42 log("the resulting cells to more sophisticated PAD cells.\n");
43 log("\n");
44 log(" -inpad <celltype> <portname>[:<portname>]\n");
45 log(" Map module input ports to the given cell type with\n");
46 log(" the given port name. if a 2nd portname is given, the\n");
47 log(" signal is passed through the pad call, using the 2nd\n");
48 log(" portname as output.\n");
49 log("\n");
50 log(" -outpad <celltype> <portname>[:<portname>]\n");
51 log(" -inoutpad <celltype> <portname>[:<portname>]\n");
52 log(" Similar to -inpad, but for output and inout ports.\n");
53 log("\n");
54 log(" -widthparam <param_name>\n");
55 log(" Use the specified parameter name to set the port width.\n");
56 log("\n");
57 log(" -nameparam <param_name>\n");
58 log(" Use the specified parameter to set the port name.\n");
59 log("\n");
60 }
61 virtual void execute(std::vector<std::string> args, RTLIL::Design *design)
62 {
63 log_header("Executing IOPADMAP pass (mapping inputs/outputs to IO-PAD cells).\n");
64
65 std::string inpad_celltype, inpad_portname, inpad_portname2;
66 std::string outpad_celltype, outpad_portname, outpad_portname2;
67 std::string inoutpad_celltype, inoutpad_portname, inoutpad_portname2;
68 std::string widthparam, nameparam;
69
70 size_t argidx;
71 for (argidx = 1; argidx < args.size(); argidx++)
72 {
73 std::string arg = args[argidx];
74 if (arg == "-inpad" && argidx+2 < args.size()) {
75 inpad_celltype = args[++argidx];
76 inpad_portname = args[++argidx];
77 split_portname_pair(inpad_portname, inpad_portname2);
78 continue;
79 }
80 if (arg == "-outpad" && argidx+2 < args.size()) {
81 outpad_celltype = args[++argidx];
82 outpad_portname = args[++argidx];
83 split_portname_pair(outpad_portname, outpad_portname2);
84 continue;
85 }
86 if (arg == "-inoutpad" && argidx+2 < args.size()) {
87 inoutpad_celltype = args[++argidx];
88 inoutpad_portname = args[++argidx];
89 split_portname_pair(inoutpad_portname, inoutpad_portname2);
90 continue;
91 }
92 if (arg == "-widthparam" && argidx+1 < args.size()) {
93 widthparam = args[++argidx];
94 continue;
95 }
96 if (arg == "-nameparam" && argidx+1 < args.size()) {
97 nameparam = args[++argidx];
98 continue;
99 }
100 break;
101 }
102 extra_args(args, argidx, design);
103
104 for (auto &it : design->modules)
105 {
106 RTLIL::Module *module = it.second;
107
108 if (!design->selected(module))
109 continue;
110
111 for (auto &it2 : module->wires)
112 {
113 RTLIL::Wire *wire = it2.second;
114
115 if (!wire->port_id || !design->selected(module, wire))
116 continue;
117
118 std::string celltype, portname, portname2;
119
120 if (wire->port_input && !wire->port_output) {
121 if (inpad_celltype.empty()) {
122 log("Don't map input port %s.%s: Missing option -inpad.\n", RTLIL::id2cstr(module->name), RTLIL::id2cstr(wire->name));
123 continue;
124 }
125 celltype = inpad_celltype;
126 portname = inpad_portname;
127 portname2 = inpad_portname2;
128 } else
129 if (!wire->port_input && wire->port_output) {
130 if (outpad_celltype.empty()) {
131 log("Don't map output port %s.%s: Missing option -outpad.\n", RTLIL::id2cstr(module->name), RTLIL::id2cstr(wire->name));
132 continue;
133 }
134 celltype = outpad_celltype;
135 portname = outpad_portname;
136 portname2 = outpad_portname2;
137 } else
138 if (wire->port_input && wire->port_output) {
139 if (inoutpad_celltype.empty()) {
140 log("Don't map inout port %s.%s: Missing option -inoutpad.\n", RTLIL::id2cstr(module->name), RTLIL::id2cstr(wire->name));
141 continue;
142 }
143 celltype = inoutpad_celltype;
144 portname = inoutpad_portname;
145 portname2 = inoutpad_portname2;
146 } else
147 log_abort();
148
149 if (wire->width != 1 && widthparam.empty()) {
150 log("Don't map multi-bit port %s.%s: Missing option -widthparam.\n", RTLIL::id2cstr(module->name), RTLIL::id2cstr(wire->name));
151 continue;
152 }
153
154 log("Mapping port %s.%s using %s.\n", RTLIL::id2cstr(module->name), RTLIL::id2cstr(wire->name), celltype.c_str());
155
156 RTLIL::Cell *cell = new RTLIL::Cell;
157 cell->name = NEW_ID;
158 cell->type = RTLIL::escape_id(celltype);
159 cell->connections[RTLIL::escape_id(portname)] = RTLIL::SigSpec(wire);
160 if (!portname2.empty()) {
161 RTLIL::Wire *new_wire = new RTLIL::Wire;
162 *new_wire = *wire;
163 wire->name = NEW_ID;
164 module->wires[wire->name] = wire;
165 module->wires[new_wire->name] = new_wire;
166 cell->connections[RTLIL::escape_id(portname2)] = RTLIL::SigSpec(new_wire);
167 }
168 if (!widthparam.empty())
169 cell->parameters[RTLIL::escape_id(widthparam)] = RTLIL::Const(wire->width);
170 if (!nameparam.empty())
171 cell->parameters[RTLIL::escape_id(nameparam)] = RTLIL::Const(RTLIL::id2cstr(wire->name));
172 cell->attributes["\\keep"] = RTLIL::Const(1);
173 module->add(cell);
174
175 wire->port_id = 0;
176 wire->port_input = false;
177 wire->port_output = false;
178 }
179
180 module->fixup_ports();
181 }
182 }
183 } IopadmapPass;
184