yosys-master
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros
splice.cc
Go to the documentation of this file.
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/celltypes.h"
22 #include "kernel/sigtools.h"
23 #include "kernel/rtlil.h"
24 #include "kernel/log.h"
25 #include <tuple>
26 
29 
31 {
34 
38  bool no_outputs;
39  std::set<RTLIL::IdString> ports;
40  std::set<RTLIL::IdString> no_ports;
41 
44 
45  std::vector<RTLIL::SigBit> driven_bits;
46  std::map<RTLIL::SigBit, int> driven_bits_map;
47 
48  std::set<RTLIL::SigSpec> driven_chunks;
49  std::map<RTLIL::SigSpec, RTLIL::SigSpec> spliced_signals_cache;
50  std::map<RTLIL::SigSpec, RTLIL::SigSpec> sliced_signals_cache;
51 
52  SpliceWorker(RTLIL::Design *design, RTLIL::Module *module) : design(design), module(module), ct(design), sigmap(module)
53  {
54  }
55 
57  {
58  if (sig.size() == 0 || sig.is_fully_const())
59  return sig;
60 
61  if (sliced_signals_cache.count(sig))
62  return sliced_signals_cache.at(sig);
63 
64  int offset = 0;
65  int p = driven_bits_map.at(sig.extract(0, 1).to_single_sigbit()) - 1;
66  while (driven_bits.at(p) != RTLIL::State::Sm)
67  p--, offset++;
68 
69  RTLIL::SigSpec sig_a;
70  for (p++; driven_bits.at(p) != RTLIL::State::Sm; p++)
71  sig_a.append(driven_bits.at(p));
72 
73  RTLIL::SigSpec new_sig = sig;
74 
75  if (sig_a.size() != sig.size()) {
76  RTLIL::Cell *cell = module->addCell(NEW_ID, "$slice");
77  cell->parameters["\\OFFSET"] = offset;
78  cell->parameters["\\A_WIDTH"] = sig_a.size();
79  cell->parameters["\\Y_WIDTH"] = sig.size();
80  cell->setPort("\\A", sig_a);
81  cell->setPort("\\Y", module->addWire(NEW_ID, sig.size()));
82  new_sig = cell->getPort("\\Y");
83  }
84 
85  sliced_signals_cache[sig] = new_sig;
86 
87  return new_sig;
88  }
89 
91  {
92  if (sig.size() == 0 || sig.is_fully_const())
93  return sig;
94 
95  if (spliced_signals_cache.count(sig))
96  return spliced_signals_cache.at(sig);
97 
98  int last_bit = -1;
99  std::vector<RTLIL::SigSpec> chunks;
100 
101  for (auto &bit : sig.to_sigbit_vector())
102  {
103  if (bit.wire == NULL)
104  {
105  if (last_bit == 0)
106  chunks.back().append(bit);
107  else
108  chunks.push_back(bit);
109  last_bit = 0;
110  continue;
111  }
112 
113  if (driven_bits_map.count(bit))
114  {
115  int this_bit = driven_bits_map.at(bit);
116  if (last_bit+1 == this_bit)
117  chunks.back().append(bit);
118  else
119  chunks.push_back(bit);
120  last_bit = this_bit;
121  continue;
122  }
123 
124  log(" Failed to generate spliced signal %s.\n", log_signal(sig));
125  spliced_signals_cache[sig] = sig;
126  return sig;
127  }
128 
129 
130  RTLIL::SigSpec new_sig = get_sliced_signal(chunks.front());
131  for (size_t i = 1; i < chunks.size(); i++) {
132  RTLIL::SigSpec sig2 = get_sliced_signal(chunks[i]);
133  RTLIL::Cell *cell = module->addCell(NEW_ID, "$concat");
134  cell->parameters["\\A_WIDTH"] = new_sig.size();
135  cell->parameters["\\B_WIDTH"] = sig2.size();
136  cell->setPort("\\A", new_sig);
137  cell->setPort("\\B", sig2);
138  cell->setPort("\\Y", module->addWire(NEW_ID, new_sig.size() + sig2.size()));
139  new_sig = cell->getPort("\\Y");
140  }
141 
142  spliced_signals_cache[sig] = new_sig;
143 
144  log(" Created spliced signal: %s -> %s\n", log_signal(sig), log_signal(new_sig));
145  return new_sig;
146  }
147 
148  void run()
149  {
150  log("Splicing signals in module %s:\n", RTLIL::id2cstr(module->name));
151 
152  driven_bits.push_back(RTLIL::State::Sm);
153  driven_bits.push_back(RTLIL::State::Sm);
154 
155  for (auto &it : module->wires_)
156  if (it.second->port_input) {
157  RTLIL::SigSpec sig = sigmap(it.second);
158  driven_chunks.insert(sig);
159  for (auto &bit : sig.to_sigbit_vector())
160  driven_bits.push_back(bit);
161  driven_bits.push_back(RTLIL::State::Sm);
162  }
163 
164  for (auto &it : module->cells_)
165  for (auto &conn : it.second->connections())
166  if (!ct.cell_known(it.second->type) || ct.cell_output(it.second->type, conn.first)) {
167  RTLIL::SigSpec sig = sigmap(conn.second);
168  driven_chunks.insert(sig);
169  for (auto &bit : sig.to_sigbit_vector())
170  driven_bits.push_back(bit);
171  driven_bits.push_back(RTLIL::State::Sm);
172  }
173 
174  driven_bits.push_back(RTLIL::State::Sm);
175 
176  for (size_t i = 0; i < driven_bits.size(); i++)
178 
179  SigPool selected_bits;
180  if (!sel_by_cell)
181  for (auto &it : module->wires_)
182  if (design->selected(module, it.second))
183  selected_bits.add(sigmap(it.second));
184 
185  for (auto &it : module->cells_) {
186  if (!sel_by_wire && !design->selected(module, it.second))
187  continue;
188  for (auto &conn : it.second->connections_)
189  if (ct.cell_input(it.second->type, conn.first)) {
190  if (ports.size() > 0 && !ports.count(conn.first))
191  continue;
192  if (no_ports.size() > 0 && no_ports.count(conn.first))
193  continue;
194  RTLIL::SigSpec sig = sigmap(conn.second);
195  if (!sel_by_cell) {
196  if (!sel_any_bit && !selected_bits.check_all(sig))
197  continue;
198  if (sel_any_bit && !selected_bits.check_any(sig))
199  continue;
200  }
201  if (driven_chunks.count(sig) > 0)
202  continue;
203  conn.second = get_spliced_signal(sig);
204  }
205  }
206 
207  std::vector<std::pair<RTLIL::Wire*, RTLIL::SigSpec>> rework_wires;
208 
209  for (auto &it : module->wires_)
210  if (!no_outputs && it.second->port_output) {
211  if (!design->selected(module, it.second))
212  continue;
213  RTLIL::SigSpec sig = sigmap(it.second);
214  if (driven_chunks.count(sig) > 0)
215  continue;
216  RTLIL::SigSpec new_sig = get_spliced_signal(sig);
217  if (new_sig != sig)
218  rework_wires.push_back(std::pair<RTLIL::Wire*, RTLIL::SigSpec>(it.second, new_sig));
219  } else
220  if (!it.second->port_input) {
221  RTLIL::SigSpec sig = sigmap(it.second);
222  if (spliced_signals_cache.count(sig) && spliced_signals_cache.at(sig) != sig)
223  rework_wires.push_back(std::pair<RTLIL::Wire*, RTLIL::SigSpec>(it.second, spliced_signals_cache.at(sig)));
224  else if (sliced_signals_cache.count(sig) && sliced_signals_cache.at(sig) != sig)
225  rework_wires.push_back(std::pair<RTLIL::Wire*, RTLIL::SigSpec>(it.second, sliced_signals_cache.at(sig)));
226  }
227 
228  for (auto &it : rework_wires)
229  {
230  RTLIL::IdString orig_name = it.first->name;
231  module->rename(it.first, NEW_ID);
232 
233  RTLIL::Wire *new_port = module->addWire(orig_name, it.first);
234  it.first->port_id = 0;
235  it.first->port_input = false;
236  it.first->port_output = false;
237 
238  module->connect(RTLIL::SigSig(new_port, it.second));
239  }
240  }
241 };
242 
243 struct SplicePass : public Pass {
244  SplicePass() : Pass("splice", "create explicit splicing cells") { }
245  virtual void help()
246  {
247  // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
248  log("\n");
249  log(" splice [options] [selection]\n");
250  log("\n");
251  log("This command adds $slice and $concat cells to the design to make the splicing\n");
252  log("of multi-bit signals explicit. This for example is useful for coarse grain\n");
253  log("synthesis, where dedidacted hardware is needed to splice signals.\n");
254  log("\n");
255  log(" -sel_by_cell\n");
256  log(" only select the cell ports to rewire by the cell. if the selection\n");
257  log(" contains a cell, than all cell inputs are rewired, if necessary.\n");
258  log("\n");
259  log(" -sel_by_wire\n");
260  log(" only select the cell ports to rewire by the wire. if the selection\n");
261  log(" contains a wire, than all cell ports driven by this wire are wired,\n");
262  log(" if necessary.\n");
263  log("\n");
264  log(" -sel_any_bit\n");
265  log(" it is sufficient if the driver of any bit of a cell port is selected.\n");
266  log(" by default all bits must be selected.\n");
267  log("\n");
268  log(" -no_outputs\n");
269  log(" do not rewire selected module outputs.\n");
270  log("\n");
271  log(" -port <name>\n");
272  log(" only rewire cell ports with the specified name. can be used multiple\n");
273  log(" times. implies -no_output.\n");
274  log("\n");
275  log(" -no_port <name>\n");
276  log(" do not rewire cell ports with the specified name. can be used multiple\n");
277  log(" times. can not be combined with -port <name>.\n");
278  log("\n");
279  log("By default selected output wires and all cell ports of selected cells driven\n");
280  log("by selected wires are rewired.\n");
281  log("\n");
282  }
283  virtual void execute(std::vector<std::string> args, RTLIL::Design *design)
284  {
285  bool sel_by_cell = false;
286  bool sel_by_wire = false;
287  bool sel_any_bit = false;
288  bool no_outputs = false;
289  std::set<RTLIL::IdString> ports, no_ports;
290 
291  size_t argidx;
292  for (argidx = 1; argidx < args.size(); argidx++) {
293  if (args[argidx] == "-sel_by_cell") {
294  sel_by_cell = true;
295  continue;
296  }
297  if (args[argidx] == "-sel_by_wire") {
298  sel_by_wire = true;
299  continue;
300  }
301  if (args[argidx] == "-sel_any_bit") {
302  sel_any_bit = true;
303  continue;
304  }
305  if (args[argidx] == "-no_outputs") {
306  no_outputs = true;
307  continue;
308  }
309  if (args[argidx] == "-port" && argidx+1 < args.size()) {
310  ports.insert(RTLIL::escape_id(args[++argidx]));
311  no_outputs = true;
312  continue;
313  }
314  if (args[argidx] == "-no_port" && argidx+1 < args.size()) {
315  no_ports.insert(RTLIL::escape_id(args[++argidx]));
316  continue;
317  }
318  break;
319  }
320  extra_args(args, argidx, design);
321 
322  if (sel_by_cell && sel_by_wire)
323  log_cmd_error("The options -sel_by_cell and -sel_by_wire are exclusive!\n");
324 
325  if (sel_by_cell && sel_any_bit)
326  log_cmd_error("The options -sel_by_cell and -sel_any_bit are exclusive!\n");
327 
328  if (!ports.empty() && !no_ports.empty())
329  log_cmd_error("The options -port and -no_port are exclusive!\n");
330 
331  log_header("Executing SPLICE pass (creating cells for signal splicing).\n");
332 
333  for (auto &mod_it : design->modules_)
334  {
335  if (!design->selected(mod_it.second))
336  continue;
337 
338  if (mod_it.second->processes.size()) {
339  log("Skipping module %s as it contains processes.\n", mod_it.second->name.c_str());
340  continue;
341  }
342 
343  SpliceWorker worker(design, mod_it.second);
344  worker.sel_by_cell = sel_by_cell;
345  worker.sel_by_wire = sel_by_wire;
346  worker.sel_any_bit = sel_any_bit;
347  worker.no_outputs = no_outputs;
348  worker.ports = ports;
349  worker.no_ports = no_ports;
350  worker.run();
351  }
352  }
353 } SplicePass;
354 
bool selected(T1 *module) const
Definition: rtlil.h:551
bool sel_by_cell
Definition: splice.cc:35
RTLIL::Cell * addCell(RTLIL::IdString name, RTLIL::IdString type)
Definition: rtlil.cc:1353
void log_header(const char *format,...)
Definition: log.cc:188
void run()
Definition: splice.cc:148
std::map< RTLIL::SigSpec, RTLIL::SigSpec > sliced_signals_cache
Definition: splice.cc:50
std::map< RTLIL::IdString, RTLIL::Wire * > wires_
Definition: rtlil.h:595
RTLIL::SigSpec get_spliced_signal(RTLIL::SigSpec sig)
Definition: splice.cc:90
const char * log_signal(const RTLIL::SigSpec &sig, bool autoint)
Definition: log.cc:269
void setPort(RTLIL::IdString portname, RTLIL::SigSpec signal)
Definition: rtlil.cc:1789
std::set< RTLIL::IdString > ports
Definition: splice.cc:39
int port_id
Definition: rtlil.h:826
virtual void help()
Definition: splice.cc:245
std::map< RTLIL::IdString, RTLIL::Const > parameters
Definition: rtlil.h:856
bool no_outputs
Definition: splice.cc:38
int size() const
Definition: rtlil.h:1019
RTLIL::Module * module
Definition: splice.cc:33
static std::string escape_id(std::string str)
Definition: rtlil.h:251
std::set< RTLIL::SigSpec > driven_chunks
Definition: splice.cc:48
bool cell_known(RTLIL::IdString type)
Definition: celltypes.h:188
bool check_any(RTLIL::SigSpec sig)
Definition: sigtools.h:100
void connect(const RTLIL::SigSig &conn)
Definition: rtlil.cc:1278
std::map< RTLIL::SigSpec, RTLIL::SigSpec > spliced_signals_cache
Definition: splice.cc:49
#define PRIVATE_NAMESPACE_BEGIN
Definition: yosys.h:97
bool cell_output(RTLIL::IdString type, RTLIL::IdString port)
Definition: celltypes.h:193
const RTLIL::SigSpec & getPort(RTLIL::IdString portname) const
Definition: rtlil.cc:1809
SigMap sigmap
Definition: splice.cc:43
bool is_fully_const() const
Definition: rtlil.cc:2763
RTLIL::Wire * addWire(RTLIL::IdString name, int width=1)
Definition: rtlil.cc:1331
std::vector< RTLIL::SigBit > driven_bits
Definition: splice.cc:45
RTLIL::IdString name
Definition: rtlil.h:599
#define NEW_ID
Definition: yosys.h:166
#define PRIVATE_NAMESPACE_END
Definition: yosys.h:98
RTLIL::SigBit to_single_sigbit() const
Definition: rtlil.cc:2945
Definition: register.h:27
bool check_all(RTLIL::SigSpec sig)
Definition: sigtools.h:108
static const char * id2cstr(const RTLIL::IdString &str)
Definition: rtlil.h:267
void log_cmd_error(const char *format,...)
Definition: log.cc:211
RTLIL::SigSpec get_sliced_signal(RTLIL::SigSpec sig)
Definition: splice.cc:56
void add(RTLIL::SigSpec sig)
Definition: sigtools.h:41
#define USING_YOSYS_NAMESPACE
Definition: yosys.h:102
std::map< RTLIL::IdString, RTLIL::Module * > modules_
Definition: rtlil.h:507
#define NULL
std::map< RTLIL::IdString, RTLIL::Cell * > cells_
Definition: rtlil.h:596
std::set< RTLIL::IdString > no_ports
Definition: splice.cc:40
std::map< RTLIL::SigBit, int > driven_bits_map
Definition: splice.cc:46
bool sel_by_wire
Definition: splice.cc:36
void log(const char *format,...)
Definition: log.cc:180
CellTypes ct
Definition: splice.cc:42
SplicePass()
Definition: splice.cc:244
RTLIL::SigSpec extract(const RTLIL::SigSpec &pattern, const RTLIL::SigSpec *other=NULL) const
Definition: rtlil.cc:2414
SplicePass SplicePass
void append(const RTLIL::SigSpec &signal)
Definition: rtlil.cc:2523
virtual void execute(std::vector< std::string > args, RTLIL::Design *design)
Definition: splice.cc:283
bool cell_input(RTLIL::IdString type, RTLIL::IdString port)
Definition: celltypes.h:199
bool sel_any_bit
Definition: splice.cc:37
void extra_args(std::vector< std::string > args, size_t argidx, RTLIL::Design *design, bool select=true)
Definition: register.cc:128
RTLIL::Design * design
Definition: splice.cc:32
std::pair< SigSpec, SigSpec > SigSig
Definition: rtlil.h:71
std::vector< RTLIL::SigBit > to_sigbit_vector() const
Definition: rtlil.cc:2921
void rename(RTLIL::Wire *wire, RTLIL::IdString new_name)
Definition: rtlil.cc:1185
SpliceWorker(RTLIL::Design *design, RTLIL::Module *module)
Definition: splice.cc:52