yosys-master
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros
proc_mux.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/bitpattern.h"
22 #include "kernel/log.h"
23 #include <sstream>
24 #include <stdlib.h>
25 #include <stdio.h>
26 
29 
31 {
32  for (auto &action : cs->actions) {
33  if (action.first.size())
34  return action.first;
35  }
36 
37  for (auto sw : cs->switches)
38  for (auto cs2 : sw->cases) {
40  if (sig.size())
41  return sig;
42  }
43 
44  return RTLIL::SigSpec();
45 }
46 
48 {
49  for (auto &action : cs->actions) {
50  RTLIL::SigSpec lvalue = action.first.extract(sig);
51  if (lvalue.size())
52  sig = lvalue;
53  }
54 
55  for (auto sw : cs->switches)
56  for (auto cs2 : sw->cases)
57  extract_core_signal(cs2, sig);
58 }
59 
60 RTLIL::SigSpec gen_cmp(RTLIL::Module *mod, const RTLIL::SigSpec &signal, const std::vector<RTLIL::SigSpec> &compare, RTLIL::SwitchRule *sw)
61 {
62  std::stringstream sstr;
63  sstr << "$procmux$" << (autoidx++);
64 
65  RTLIL::Wire *cmp_wire = mod->addWire(sstr.str() + "_CMP", 0);
66 
67  for (auto comp : compare)
68  {
69  RTLIL::SigSpec sig = signal;
70 
71  // get rid of don't-care bits
72  log_assert(sig.size() == comp.size());
73  for (int i = 0; i < comp.size(); i++)
74  if (comp[i] == RTLIL::State::Sa) {
75  sig.remove(i);
76  comp.remove(i--);
77  }
78  if (comp.size() == 0)
79  return RTLIL::SigSpec();
80 
81  if (sig.size() == 1 && comp == RTLIL::SigSpec(1,1))
82  {
83  mod->connect(RTLIL::SigSig(RTLIL::SigSpec(cmp_wire, cmp_wire->width++), sig));
84  }
85  else
86  {
87  // create compare cell
88  RTLIL::Cell *eq_cell = mod->addCell(stringf("%s_CMP%d", sstr.str().c_str(), cmp_wire->width), "$eq");
89  eq_cell->attributes = sw->attributes;
90 
91  eq_cell->parameters["\\A_SIGNED"] = RTLIL::Const(0);
92  eq_cell->parameters["\\B_SIGNED"] = RTLIL::Const(0);
93 
94  eq_cell->parameters["\\A_WIDTH"] = RTLIL::Const(sig.size());
95  eq_cell->parameters["\\B_WIDTH"] = RTLIL::Const(comp.size());
96  eq_cell->parameters["\\Y_WIDTH"] = RTLIL::Const(1);
97 
98  eq_cell->setPort("\\A", sig);
99  eq_cell->setPort("\\B", comp);
100  eq_cell->setPort("\\Y", RTLIL::SigSpec(cmp_wire, cmp_wire->width++));
101  }
102  }
103 
104  RTLIL::Wire *ctrl_wire;
105  if (cmp_wire->width == 1)
106  {
107  ctrl_wire = cmp_wire;
108  }
109  else
110  {
111  ctrl_wire = mod->addWire(sstr.str() + "_CTRL");
112 
113  // reduce cmp vector to one logic signal
114  RTLIL::Cell *any_cell = mod->addCell(sstr.str() + "_ANY", "$reduce_or");
115  any_cell->attributes = sw->attributes;
116 
117  any_cell->parameters["\\A_SIGNED"] = RTLIL::Const(0);
118  any_cell->parameters["\\A_WIDTH"] = RTLIL::Const(cmp_wire->width);
119  any_cell->parameters["\\Y_WIDTH"] = RTLIL::Const(1);
120 
121  any_cell->setPort("\\A", cmp_wire);
122  any_cell->setPort("\\Y", RTLIL::SigSpec(ctrl_wire));
123  }
124 
125  return RTLIL::SigSpec(ctrl_wire);
126 }
127 
128 RTLIL::SigSpec gen_mux(RTLIL::Module *mod, const RTLIL::SigSpec &signal, const std::vector<RTLIL::SigSpec> &compare, RTLIL::SigSpec when_signal, RTLIL::SigSpec else_signal, RTLIL::Cell *&last_mux_cell, RTLIL::SwitchRule *sw)
129 {
130  log_assert(when_signal.size() == else_signal.size());
131 
132  std::stringstream sstr;
133  sstr << "$procmux$" << (autoidx++);
134 
135  // the trivial cases
136  if (compare.size() == 0 || when_signal == else_signal)
137  return when_signal;
138 
139  // compare results
140  RTLIL::SigSpec ctrl_sig = gen_cmp(mod, signal, compare, sw);
141  if (ctrl_sig.size() == 0)
142  return when_signal;
143  log_assert(ctrl_sig.size() == 1);
144 
145  // prepare multiplexer output signal
146  RTLIL::Wire *result_wire = mod->addWire(sstr.str() + "_Y", when_signal.size());
147 
148  // create the multiplexer itself
149  RTLIL::Cell *mux_cell = mod->addCell(sstr.str(), "$mux");
150  mux_cell->attributes = sw->attributes;
151 
152  mux_cell->parameters["\\WIDTH"] = RTLIL::Const(when_signal.size());
153  mux_cell->setPort("\\A", else_signal);
154  mux_cell->setPort("\\B", when_signal);
155  mux_cell->setPort("\\S", ctrl_sig);
156  mux_cell->setPort("\\Y", RTLIL::SigSpec(result_wire));
157 
158  last_mux_cell = mux_cell;
159  return RTLIL::SigSpec(result_wire);
160 }
161 
162 void append_pmux(RTLIL::Module *mod, const RTLIL::SigSpec &signal, const std::vector<RTLIL::SigSpec> &compare, RTLIL::SigSpec when_signal, RTLIL::Cell *last_mux_cell, RTLIL::SwitchRule *sw)
163 {
164  log_assert(last_mux_cell != NULL);
165  log_assert(when_signal.size() == last_mux_cell->getPort("\\A").size());
166 
167  RTLIL::SigSpec ctrl_sig = gen_cmp(mod, signal, compare, sw);
168  log_assert(ctrl_sig.size() == 1);
169  last_mux_cell->type = "$pmux";
170 
171  RTLIL::SigSpec new_s = last_mux_cell->getPort("\\S");
172  new_s.append(ctrl_sig);
173  last_mux_cell->setPort("\\S", new_s);
174 
175  RTLIL::SigSpec new_b = last_mux_cell->getPort("\\B");
176  new_b.append(when_signal);
177  last_mux_cell->setPort("\\B", new_b);
178 
179  last_mux_cell->parameters["\\S_WIDTH"] = last_mux_cell->getPort("\\S").size();
180 }
181 
183 {
184  RTLIL::SigSpec result = defval;
185 
186  for (auto &action : cs->actions) {
187  sig.replace(action.first, action.second, &result);
188  action.first.remove2(sig, &action.second);
189  }
190 
191  for (auto sw : cs->switches)
192  {
193  // detect groups of parallel cases
194  std::vector<int> pgroups(sw->cases.size());
195  if (!sw->get_bool_attribute("\\parallel_case")) {
196  BitPatternPool pool(sw->signal.size());
197  bool extra_group_for_next_case = false;
198  for (size_t i = 0; i < sw->cases.size(); i++) {
199  RTLIL::CaseRule *cs2 = sw->cases[i];
200  if (i != 0) {
201  pgroups[i] = pgroups[i-1];
202  if (extra_group_for_next_case) {
203  pgroups[i] = pgroups[i-1]+1;
204  extra_group_for_next_case = false;
205  }
206  for (auto pat : cs2->compare)
207  if (!pat.is_fully_const() || !pool.has_all(pat))
208  pgroups[i] = pgroups[i-1]+1;
209  if (cs2->compare.empty())
210  pgroups[i] = pgroups[i-1]+1;
211  if (pgroups[i] != pgroups[i-1])
212  pool = BitPatternPool(sw->signal.size());
213  }
214  for (auto pat : cs2->compare)
215  if (!pat.is_fully_const())
216  extra_group_for_next_case = true;
217  else
218  pool.take(pat);
219  }
220  }
221 
222  // evaluate in reverse order to give the first entry the top priority
223  RTLIL::SigSpec initial_val = result;
224  RTLIL::Cell *last_mux_cell = NULL;
225  for (size_t i = 0; i < sw->cases.size(); i++) {
226  int case_idx = sw->cases.size() - i - 1;
227  RTLIL::CaseRule *cs2 = sw->cases[case_idx];
228  RTLIL::SigSpec value = signal_to_mux_tree(mod, cs2, sig, initial_val);
229  if (last_mux_cell && pgroups[case_idx] == pgroups[case_idx+1])
230  append_pmux(mod, sw->signal, cs2->compare, value, last_mux_cell, sw);
231  else
232  result = gen_mux(mod, sw->signal, cs2->compare, value, result, last_mux_cell, sw);
233  }
234  }
235 
236  return result;
237 }
238 
240 {
241  bool first = true;
242  while (1)
243  {
245 
246  if (sig.size() == 0)
247  break;
248 
249  if (first) {
250  log("Creating decoders for process `%s.%s'.\n", mod->name.c_str(), proc->name.c_str());
251  first = false;
252  }
253 
254  extract_core_signal(&proc->root_case, sig);
255 
256  log(" creating decoder for signal `%s'.\n", log_signal(sig));
257 
259  mod->connect(RTLIL::SigSig(sig, value));
260  }
261 }
262 
263 struct ProcMuxPass : public Pass {
264  ProcMuxPass() : Pass("proc_mux", "convert decision trees to multiplexers") { }
265  virtual void help()
266  {
267  // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
268  log("\n");
269  log(" proc_mux [selection]\n");
270  log("\n");
271  log("This pass converts the decision trees in processes (originating from if-else\n");
272  log("and case statements) to trees of multiplexer cells.\n");
273  log("\n");
274  }
275  virtual void execute(std::vector<std::string> args, RTLIL::Design *design)
276  {
277  log_header("Executing PROC_MUX pass (convert decision trees to multiplexers).\n");
278 
279  extra_args(args, 1, design);
280 
281  for (auto mod : design->modules())
282  if (design->selected(mod))
283  for (auto &proc_it : mod->processes)
284  if (design->selected(mod, proc_it.second))
285  proc_mux(mod, proc_it.second);
286  }
287 } ProcMuxPass;
288 
const char * c_str() const
Definition: rtlil.h:178
bool selected(T1 *module) const
Definition: rtlil.h:551
std::string stringf(const char *fmt,...)
Definition: yosys.cc:58
RTLIL::Cell * addCell(RTLIL::IdString name, RTLIL::IdString type)
Definition: rtlil.cc:1353
ProcMuxPass ProcMuxPass
void log_header(const char *format,...)
Definition: log.cc:188
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
RTLIL::SigSpec gen_cmp(RTLIL::Module *mod, const RTLIL::SigSpec &signal, const std::vector< RTLIL::SigSpec > &compare, RTLIL::SwitchRule *sw)
Definition: proc_mux.cc:60
RTLIL::IdString type
Definition: rtlil.h:854
std::map< RTLIL::IdString, RTLIL::Const > parameters
Definition: rtlil.h:856
void proc_mux(RTLIL::Module *mod, RTLIL::Process *proc)
Definition: proc_mux.cc:239
int size() const
Definition: rtlil.h:1019
void remove(const RTLIL::SigSpec &pattern)
Definition: rtlil.cc:2342
std::vector< RTLIL::SigSpec > compare
Definition: rtlil.h:1119
virtual void help()
Definition: proc_mux.cc:265
void append_pmux(RTLIL::Module *mod, const RTLIL::SigSpec &signal, const std::vector< RTLIL::SigSpec > &compare, RTLIL::SigSpec when_signal, RTLIL::Cell *last_mux_cell, RTLIL::SwitchRule *sw)
Definition: proc_mux.cc:162
void connect(const RTLIL::SigSig &conn)
Definition: rtlil.cc:1278
#define PRIVATE_NAMESPACE_BEGIN
Definition: yosys.h:97
RTLIL::SigSpec signal_to_mux_tree(RTLIL::Module *mod, RTLIL::CaseRule *cs, const RTLIL::SigSpec &sig, const RTLIL::SigSpec &defval)
Definition: proc_mux.cc:182
const RTLIL::SigSpec & getPort(RTLIL::IdString portname) const
Definition: rtlil.cc:1809
#define log_assert(_assert_expr_)
Definition: log.h:85
RTLIL::Wire * addWire(RTLIL::IdString name, int width=1)
Definition: rtlil.cc:1331
RTLIL::IdString name
Definition: rtlil.h:599
#define PRIVATE_NAMESPACE_END
Definition: yosys.h:98
Definition: register.h:27
RTLIL::IdString name
Definition: rtlil.h:1154
#define USING_YOSYS_NAMESPACE
Definition: yosys.h:102
RTLIL::ObjRange< RTLIL::Module * > modules()
Definition: rtlil.cc:249
void replace(const RTLIL::SigSpec &pattern, const RTLIL::SigSpec &with)
Definition: rtlil.cc:2297
void extract_core_signal(const RTLIL::CaseRule *cs, RTLIL::SigSpec &sig)
Definition: proc_mux.cc:47
#define NULL
USING_YOSYS_NAMESPACE PRIVATE_NAMESPACE_BEGIN RTLIL::SigSpec find_any_lvalue(const RTLIL::CaseRule *cs)
Definition: proc_mux.cc:30
void log(const char *format,...)
Definition: log.cc:180
RTLIL::SigSpec extract(const RTLIL::SigSpec &pattern, const RTLIL::SigSpec *other=NULL) const
Definition: rtlil.cc:2414
void append(const RTLIL::SigSpec &signal)
Definition: rtlil.cc:2523
std::vector< RTLIL::SigSig > actions
Definition: rtlil.h:1120
void extra_args(std::vector< std::string > args, size_t argidx, RTLIL::Design *design, bool select=true)
Definition: register.cc:128
bool take(RTLIL::SigSpec sig)
Definition: bitpattern.h:102
std::vector< RTLIL::SwitchRule * > switches
Definition: rtlil.h:1121
virtual void execute(std::vector< std::string > args, RTLIL::Design *design)
Definition: proc_mux.cc:275
std::pair< SigSpec, SigSpec > SigSig
Definition: rtlil.h:71
YOSYS_NAMESPACE_BEGIN int autoidx
Definition: yosys.cc:51
RTLIL::SigSpec gen_mux(RTLIL::Module *mod, const RTLIL::SigSpec &signal, const std::vector< RTLIL::SigSpec > &compare, RTLIL::SigSpec when_signal, RTLIL::SigSpec else_signal, RTLIL::Cell *&last_mux_cell, RTLIL::SwitchRule *sw)
Definition: proc_mux.cc:128
RTLIL_ATTRIBUTE_MEMBERS RTLIL::CaseRule root_case
Definition: rtlil.h:1156