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/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 add_portConnwrappersWorker39 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 add_portConnwrappersWorker54 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 workConnwrappersWorker68 void work(RTLIL::Module *module) 69 { 70 std::map<RTLIL::SigBit, std::pair<bool, RTLIL::SigSpec>> extend_map; 71 SigMap sigmap(module); 72 73 for (auto cell : module->cells()) 74 { 75 if (!decl_celltypes.count(cell->type)) 76 continue; 77 78 for (auto &conn : cell->connections()) 79 { 80 std::pair<RTLIL::IdString, RTLIL::IdString> key(cell->type, conn.first); 81 82 if (!decls.count(key)) 83 continue; 84 85 portdecl_t &decl = decls.at(key); 86 87 if (!cell->parameters.count(decl.widthparam)) 88 continue; 89 90 if (!decl.signparam.empty() && !cell->parameters.count(decl.signparam)) 91 continue; 92 93 int inner_width = cell->parameters.at(decl.widthparam).as_int(); 94 int outer_width = conn.second.size(); 95 bool is_signed = decl.signparam.empty() ? decl.is_signed : cell->parameters.at(decl.signparam).as_bool(); 96 97 if (inner_width >= outer_width) 98 continue; 99 100 RTLIL::SigSpec sig = sigmap(conn.second); 101 extend_map[sig.extract(inner_width - 1, 1)] = std::pair<bool, RTLIL::SigSpec>(is_signed, 102 sig.extract(inner_width, outer_width - inner_width)); 103 } 104 } 105 106 for (auto cell : module->selected_cells()) 107 { 108 for (auto &conn : cell->connections_) 109 { 110 std::vector<RTLIL::SigBit> sigbits = sigmap(conn.second).to_sigbit_vector(); 111 RTLIL::SigSpec old_sig; 112 113 for (size_t i = 0; i < sigbits.size(); i++) 114 { 115 if (!extend_map.count(sigbits[i])) 116 continue; 117 118 bool is_signed = extend_map.at(sigbits[i]).first; 119 RTLIL::SigSpec extend_sig = extend_map.at(sigbits[i]).second; 120 121 int extend_width = 0; 122 RTLIL::SigBit extend_bit = is_signed ? sigbits[i] : RTLIL::SigBit(RTLIL::State::S0); 123 while (extend_width < extend_sig.size() && i + extend_width + 1 < sigbits.size() && 124 sigbits[i + extend_width + 1] == extend_bit) extend_width++; 125 126 if (extend_width == 0) 127 continue; 128 129 if (old_sig.size() == 0) 130 old_sig = conn.second; 131 132 conn.second.replace(i+1, extend_sig.extract(0, extend_width)); 133 i += extend_width; 134 } 135 136 if (old_sig.size()) 137 log("Connected extended bits of %s.%s:%s: %s -> %s\n", log_id(module->name), log_id(cell->name), 138 log_id(conn.first), log_signal(old_sig), log_signal(conn.second)); 139 } 140 } 141 } 142 }; 143 144 struct ConnwrappersPass : public Pass { ConnwrappersPassConnwrappersPass145 ConnwrappersPass() : Pass("connwrappers", "match width of input-output port pairs") { } helpConnwrappersPass146 void help() override 147 { 148 // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---| 149 log("\n"); 150 log(" connwrappers [options] [selection]\n"); 151 log("\n"); 152 log("Wrappers are used in coarse-grain synthesis to wrap cells with smaller ports\n"); 153 log("in wrapper cells with a (larger) constant port size. I.e. the upper bits\n"); 154 log("of the wrapper output are signed/unsigned bit extended. This command uses this\n"); 155 log("knowledge to rewire the inputs of the driven cells to match the output of\n"); 156 log("the driving cell.\n"); 157 log("\n"); 158 log(" -signed <cell_type> <port_name> <width_param>\n"); 159 log(" -unsigned <cell_type> <port_name> <width_param>\n"); 160 log(" consider the specified signed/unsigned wrapper output\n"); 161 log("\n"); 162 log(" -port <cell_type> <port_name> <width_param> <sign_param>\n"); 163 log(" use the specified parameter to decide if signed or unsigned\n"); 164 log("\n"); 165 log("The options -signed, -unsigned, and -port can be specified multiple times.\n"); 166 log("\n"); 167 } executeConnwrappersPass168 void execute(std::vector<std::string> args, RTLIL::Design *design) override 169 { 170 ConnwrappersWorker worker; 171 172 size_t argidx; 173 for (argidx = 1; argidx < args.size(); argidx++) 174 { 175 if (args[argidx] == "-signed" && argidx+3 < args.size()) { 176 worker.add_port(args[argidx+1], args[argidx+2], args[argidx+3], true); 177 argidx += 3; 178 continue; 179 } 180 if (args[argidx] == "-unsigned" && argidx+3 < args.size()) { 181 worker.add_port(args[argidx+1], args[argidx+2], args[argidx+3], false); 182 argidx += 3; 183 continue; 184 } 185 if (args[argidx] == "-port" && argidx+4 < args.size()) { 186 worker.add_port(args[argidx+1], args[argidx+2], args[argidx+3], args[argidx+4]); 187 argidx += 4; 188 continue; 189 } 190 break; 191 } 192 extra_args(args, argidx, design); 193 194 log_header(design, "Executing CONNWRAPPERS pass (connect extended ports of wrapper cells).\n"); 195 196 for (auto module : design->selected_modules()) 197 worker.work(module); 198 } 199 } ConnwrappersPass; 200 201 PRIVATE_NAMESPACE_END 202