Merge pull request #1085 from YosysHQ/eddie/shregmap_improve
[yosys.git] / passes / cmds / connwrappers.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/sigtools.h"
22 #include "kernel/rtlil.h"
23 #include "kernel/log.h"
24
25 USING_YOSYS_NAMESPACE
26 PRIVATE_NAMESPACE_BEGIN
27
28 struct ConnwrappersWorker
29 {
30 struct portdecl_t {
31 // key: celltype, portname;
32 std::string widthparam, signparam;
33 bool is_signed;
34 };
35
36 std::set<RTLIL::IdString> decl_celltypes;
37 std::map<std::pair<RTLIL::IdString, RTLIL::IdString>, portdecl_t> decls;
38
39 void add_port(std::string celltype, std::string portname, std::string widthparam, std::string signparam)
40 {
41 std::pair<std::string, std::string> key(RTLIL::escape_id(celltype), RTLIL::escape_id(portname));
42 decl_celltypes.insert(key.first);
43
44 if (decls.count(key))
45 log_cmd_error("Duplicate port decl: %s %s\n", celltype.c_str(), portname.c_str());
46
47 portdecl_t decl;
48 decl.widthparam = RTLIL::escape_id(widthparam);
49 decl.signparam = RTLIL::escape_id(signparam);
50 decl.is_signed = false;
51 decls[key] = decl;
52 }
53
54 void add_port(std::string celltype, std::string portname, std::string widthparam, bool is_signed)
55 {
56 std::pair<std::string, std::string> key(RTLIL::escape_id(celltype), RTLIL::escape_id(portname));
57 decl_celltypes.insert(key.first);
58
59 if (decls.count(key))
60 log_cmd_error("Duplicate port decl: %s %s\n", celltype.c_str(), portname.c_str());
61
62 portdecl_t decl;
63 decl.widthparam = RTLIL::escape_id(widthparam);
64 decl.is_signed = is_signed;
65 decls[key] = decl;
66 }
67
68 void work(RTLIL::Design *design, RTLIL::Module *module)
69 {
70 std::map<RTLIL::SigBit, std::pair<bool, RTLIL::SigSpec>> extend_map;
71 SigMap sigmap(module);
72
73 for (auto &it : module->cells_)
74 {
75 RTLIL::Cell *cell = it.second;
76
77 if (!decl_celltypes.count(cell->type))
78 continue;
79
80 for (auto &conn : cell->connections())
81 {
82 std::pair<RTLIL::IdString, RTLIL::IdString> key(cell->type, conn.first);
83
84 if (!decls.count(key))
85 continue;
86
87 portdecl_t &decl = decls.at(key);
88
89 if (!cell->parameters.count(decl.widthparam))
90 continue;
91
92 if (!decl.signparam.empty() && !cell->parameters.count(decl.signparam))
93 continue;
94
95 int inner_width = cell->parameters.at(decl.widthparam).as_int();
96 int outer_width = conn.second.size();
97 bool is_signed = decl.signparam.empty() ? decl.is_signed : cell->parameters.at(decl.signparam).as_bool();
98
99 if (inner_width >= outer_width)
100 continue;
101
102 RTLIL::SigSpec sig = sigmap(conn.second);
103 extend_map[sig.extract(inner_width - 1, 1)] = std::pair<bool, RTLIL::SigSpec>(is_signed,
104 sig.extract(inner_width, outer_width - inner_width));
105 }
106 }
107
108 for (auto &it : module->cells_)
109 {
110 RTLIL::Cell *cell = it.second;
111
112 if (!design->selected(module, cell))
113 continue;
114
115 for (auto &conn : cell->connections_)
116 {
117 std::vector<RTLIL::SigBit> sigbits = sigmap(conn.second).to_sigbit_vector();
118 RTLIL::SigSpec old_sig;
119
120 for (size_t i = 0; i < sigbits.size(); i++)
121 {
122 if (!extend_map.count(sigbits[i]))
123 continue;
124
125 bool is_signed = extend_map.at(sigbits[i]).first;
126 RTLIL::SigSpec extend_sig = extend_map.at(sigbits[i]).second;
127
128 int extend_width = 0;
129 RTLIL::SigBit extend_bit = is_signed ? sigbits[i] : RTLIL::SigBit(RTLIL::State::S0);
130 while (extend_width < extend_sig.size() && i + extend_width + 1 < sigbits.size() &&
131 sigbits[i + extend_width + 1] == extend_bit) extend_width++;
132
133 if (extend_width == 0)
134 continue;
135
136 if (old_sig.size() == 0)
137 old_sig = conn.second;
138
139 conn.second.replace(i+1, extend_sig.extract(0, extend_width));
140 i += extend_width;
141 }
142
143 if (old_sig.size())
144 log("Connected extended bits of %s.%s:%s: %s -> %s\n", RTLIL::id2cstr(module->name), RTLIL::id2cstr(cell->name),
145 RTLIL::id2cstr(conn.first), log_signal(old_sig), log_signal(conn.second));
146 }
147 }
148 }
149 };
150
151 struct ConnwrappersPass : public Pass {
152 ConnwrappersPass() : Pass("connwrappers", "match width of input-output port pairs") { }
153 void help() YS_OVERRIDE
154 {
155 // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
156 log("\n");
157 log(" connwrappers [options] [selection]\n");
158 log("\n");
159 log("Wrappers are used in coarse-grain synthesis to wrap cells with smaller ports\n");
160 log("in wrapper cells with a (larger) constant port size. I.e. the upper bits\n");
161 log("of the wrapper output are signed/unsigned bit extended. This command uses this\n");
162 log("knowledge to rewire the inputs of the driven cells to match the output of\n");
163 log("the driving cell.\n");
164 log("\n");
165 log(" -signed <cell_type> <port_name> <width_param>\n");
166 log(" -unsigned <cell_type> <port_name> <width_param>\n");
167 log(" consider the specified signed/unsigned wrapper output\n");
168 log("\n");
169 log(" -port <cell_type> <port_name> <width_param> <sign_param>\n");
170 log(" use the specified parameter to decide if signed or unsigned\n");
171 log("\n");
172 log("The options -signed, -unsigned, and -port can be specified multiple times.\n");
173 log("\n");
174 }
175 void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
176 {
177 ConnwrappersWorker worker;
178
179 size_t argidx;
180 for (argidx = 1; argidx < args.size(); argidx++)
181 {
182 if (args[argidx] == "-signed" && argidx+3 < args.size()) {
183 worker.add_port(args[argidx+1], args[argidx+2], args[argidx+3], true);
184 argidx += 3;
185 continue;
186 }
187 if (args[argidx] == "-unsigned" && argidx+3 < args.size()) {
188 worker.add_port(args[argidx+1], args[argidx+2], args[argidx+3], false);
189 argidx += 3;
190 continue;
191 }
192 if (args[argidx] == "-port" && argidx+4 < args.size()) {
193 worker.add_port(args[argidx+1], args[argidx+2], args[argidx+3], args[argidx+4]);
194 argidx += 4;
195 continue;
196 }
197 break;
198 }
199 extra_args(args, argidx, design);
200
201 log_header(design, "Executing CONNWRAPPERS pass (connect extended ports of wrapper cells).\n");
202
203 for (auto &mod_it : design->modules_)
204 if (design->selected(mod_it.second))
205 worker.work(design, mod_it.second);
206 }
207 } ConnwrappersPass;
208
209 PRIVATE_NAMESPACE_END