yosys-master
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros
proc_arst.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/sigtools.h"
22 #include "kernel/log.h"
23 #include <stdlib.h>
24 #include <stdio.h>
25 
27 extern void proc_clean_case(RTLIL::CaseRule *cs, bool &did_something, int &count, int max_depth);
29 
32 
33 bool check_signal(RTLIL::Module *mod, RTLIL::SigSpec signal, RTLIL::SigSpec ref, bool &polarity)
34 {
35  if (signal.size() != 1)
36  return false;
37  if (signal == ref)
38  return true;
39 
40  for (auto cell : mod->cells())
41  {
42  if (cell->type == "$reduce_or" && cell->getPort("\\Y") == signal)
43  return check_signal(mod, cell->getPort("\\A"), ref, polarity);
44 
45  if (cell->type == "$reduce_bool" && cell->getPort("\\Y") == signal)
46  return check_signal(mod, cell->getPort("\\A"), ref, polarity);
47 
48  if (cell->type == "$logic_not" && cell->getPort("\\Y") == signal) {
49  polarity = !polarity;
50  return check_signal(mod, cell->getPort("\\A"), ref, polarity);
51  }
52 
53  if (cell->type == "$not" && cell->getPort("\\Y") == signal) {
54  polarity = !polarity;
55  return check_signal(mod, cell->getPort("\\A"), ref, polarity);
56  }
57 
58  if ((cell->type == "$eq" || cell->type == "$eqx") && cell->getPort("\\Y") == signal) {
59  if (cell->getPort("\\A").is_fully_const()) {
60  if (!cell->getPort("\\A").as_bool())
61  polarity = !polarity;
62  return check_signal(mod, cell->getPort("\\B"), ref, polarity);
63  }
64  if (cell->getPort("\\B").is_fully_const()) {
65  if (!cell->getPort("\\B").as_bool())
66  polarity = !polarity;
67  return check_signal(mod, cell->getPort("\\A"), ref, polarity);
68  }
69  }
70 
71  if ((cell->type == "$ne" || cell->type == "$nex") && cell->getPort("\\Y") == signal) {
72  if (cell->getPort("\\A").is_fully_const()) {
73  if (cell->getPort("\\A").as_bool())
74  polarity = !polarity;
75  return check_signal(mod, cell->getPort("\\B"), ref, polarity);
76  }
77  if (cell->getPort("\\B").is_fully_const()) {
78  if (cell->getPort("\\B").as_bool())
79  polarity = !polarity;
80  return check_signal(mod, cell->getPort("\\A"), ref, polarity);
81  }
82  }
83  }
84 
85  return false;
86 }
87 
88 void apply_const(RTLIL::Module *mod, const RTLIL::SigSpec rspec, RTLIL::SigSpec &rval, RTLIL::CaseRule *cs, RTLIL::SigSpec const_sig, bool polarity, bool unknown)
89 {
90  for (auto &action : cs->actions) {
91  if (unknown)
92  rspec.replace(action.first, RTLIL::SigSpec(RTLIL::State::Sm, action.second.size()), &rval);
93  else
94  rspec.replace(action.first, action.second, &rval);
95  }
96 
97  for (auto sw : cs->switches) {
98  if (sw->signal.size() == 0) {
99  for (auto cs2 : sw->cases)
100  apply_const(mod, rspec, rval, cs2, const_sig, polarity, unknown);
101  }
102  bool this_polarity = polarity;
103  if (check_signal(mod, sw->signal, const_sig, this_polarity)) {
104  for (auto cs2 : sw->cases) {
105  for (auto comp : cs2->compare)
106  if (comp == RTLIL::SigSpec(this_polarity, 1))
107  goto matched_case;
108  if (cs2->compare.size() == 0) {
109  matched_case:
110  apply_const(mod, rspec, rval, cs2, const_sig, polarity, false);
111  break;
112  }
113  }
114  } else {
115  for (auto cs2 : sw->cases)
116  apply_const(mod, rspec, rval, cs2, const_sig, polarity, true);
117  }
118  }
119 }
120 
121 void eliminate_const(RTLIL::Module *mod, RTLIL::CaseRule *cs, RTLIL::SigSpec const_sig, bool polarity)
122 {
123  for (auto sw : cs->switches) {
124  bool this_polarity = polarity;
125  if (check_signal(mod, sw->signal, const_sig, this_polarity)) {
126  bool found_rem_path = false;
127  for (size_t i = 0; i < sw->cases.size(); i++) {
128  RTLIL::CaseRule *cs2 = sw->cases[i];
129  for (auto comp : cs2->compare)
130  if (comp == RTLIL::SigSpec(this_polarity, 1))
131  goto matched_case;
132  if (found_rem_path) {
133  matched_case:
134  sw->cases.erase(sw->cases.begin() + (i--));
135  delete cs2;
136  continue;
137  }
138  found_rem_path = true;
139  cs2->compare.clear();
140  }
141  sw->signal = RTLIL::SigSpec();
142  } else {
143  for (auto cs2 : sw->cases)
144  eliminate_const(mod, cs2, const_sig, polarity);
145  }
146  }
147 
148  int dummy_count = 0;
149  bool did_something = true;
150  while (did_something) {
151  did_something = false;
152  proc_clean_case(cs, did_something, dummy_count, 1);
153  }
154 }
155 
157 {
158 restart_proc_arst:
159  if (proc->root_case.switches.size() != 1)
160  return;
161 
162  RTLIL::SigSpec root_sig = proc->root_case.switches[0]->signal;
163 
164  for (auto &sync : proc->syncs) {
165  if (sync->type == RTLIL::SyncType::STp || sync->type == RTLIL::SyncType::STn) {
166  bool polarity = sync->type == RTLIL::SyncType::STp;
167  if (check_signal(mod, root_sig, sync->signal, polarity)) {
168  if (proc->syncs.size() == 1) {
169  log("Found VHDL-style edge-trigger %s in `%s.%s'.\n", log_signal(sync->signal), mod->name.c_str(), proc->name.c_str());
170  } else {
171  log("Found async reset %s in `%s.%s'.\n", log_signal(sync->signal), mod->name.c_str(), proc->name.c_str());
172  sync->type = sync->type == RTLIL::SyncType::STp ? RTLIL::SyncType::ST1 : RTLIL::SyncType::ST0;
173  }
174  for (auto &action : sync->actions) {
175  RTLIL::SigSpec rspec = action.second;
177  for (int i = 0; i < GetSize(rspec); i++)
178  if (rspec[i].wire == NULL)
179  rval[i] = rspec[i];
180  RTLIL::SigSpec last_rval;
181  for (int count = 0; rval != last_rval; count++) {
182  last_rval = rval;
183  apply_const(mod, rspec, rval, &proc->root_case, root_sig, polarity, false);
184  assign_map.apply(rval);
185  if (rval.is_fully_const())
186  break;
187  if (count > 100)
188  log_error("Async reset %s yields endless loop at value %s for signal %s.\n",
189  log_signal(sync->signal), log_signal(rval), log_signal(action.first));
190  rspec = rval;
191  }
192  if (rval.has_marked_bits())
193  log_error("Async reset %s yields non-constant value %s for signal %s.\n",
194  log_signal(sync->signal), log_signal(rval), log_signal(action.first));
195  action.second = rval;
196  }
197  eliminate_const(mod, &proc->root_case, root_sig, polarity);
198  goto restart_proc_arst;
199  }
200  }
201  }
202 }
203 
204 struct ProcArstPass : public Pass {
205  ProcArstPass() : Pass("proc_arst", "detect asynchronous resets") { }
206  virtual void help()
207  {
208  // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
209  log("\n");
210  log(" proc_arst [-global_arst [!]<netname>] [selection]\n");
211  log("\n");
212  log("This pass identifies asynchronous resets in the processes and converts them\n");
213  log("to a different internal representation that is suitable for generating\n");
214  log("flip-flop cells with asynchronous resets.\n");
215  log("\n");
216  log(" -global_arst [!]<netname>\n");
217  log(" In modules that have a net with the given name, use this net as async\n");
218  log(" reset for registers that have been assign initial values in their\n");
219  log(" declaration ('reg foobar = constant_value;'). Use the '!' modifier for\n");
220  log(" active low reset signals. Note: the frontend stores the default value\n");
221  log(" in the 'init' attribute on the net.\n");
222  log("\n");
223  }
224  virtual void execute(std::vector<std::string> args, RTLIL::Design *design)
225  {
226  std::string global_arst;
227  bool global_arst_neg = false;
228 
229  log_header("Executing PROC_ARST pass (detect async resets in processes).\n");
230 
231  size_t argidx;
232  for (argidx = 1; argidx < args.size(); argidx++)
233  {
234  if (args[argidx] == "-global_arst" && argidx+1 < args.size()) {
235  global_arst = args[++argidx];
236  if (!global_arst.empty() && global_arst[0] == '!') {
237  global_arst_neg = true;
238  global_arst = global_arst.substr(1);
239  }
240  global_arst = RTLIL::escape_id(global_arst);
241  continue;
242  }
243  break;
244  }
245 
246  extra_args(args, argidx, design);
247 
248  for (auto mod : design->modules())
249  if (design->selected(mod)) {
250  SigMap assign_map(mod);
251  for (auto &proc_it : mod->processes) {
252  if (!design->selected(mod, proc_it.second))
253  continue;
254  proc_arst(mod, proc_it.second, assign_map);
255  if (global_arst.empty() || mod->wire(global_arst) == nullptr)
256  continue;
257  std::vector<RTLIL::SigSig> arst_actions;
258  for (auto sync : proc_it.second->syncs)
259  if (sync->type == RTLIL::SyncType::STp || sync->type == RTLIL::SyncType::STn)
260  for (auto &act : sync->actions) {
261  RTLIL::SigSpec arst_sig, arst_val;
262  for (auto &chunk : act.first.chunks())
263  if (chunk.wire && chunk.wire->attributes.count("\\init")) {
264  RTLIL::SigSpec value = chunk.wire->attributes.at("\\init");
265  value.extend(chunk.wire->width, false);
266  arst_sig.append(chunk);
267  arst_val.append(value.extract(chunk.offset, chunk.width));
268  }
269  if (arst_sig.size()) {
270  log("Added global reset to process %s: %s <- %s\n",
271  proc_it.first.c_str(), log_signal(arst_sig), log_signal(arst_val));
272  arst_actions.push_back(RTLIL::SigSig(arst_sig, arst_val));
273  }
274  }
275  if (!arst_actions.empty()) {
276  RTLIL::SyncRule *sync = new RTLIL::SyncRule;
277  sync->type = global_arst_neg ? RTLIL::SyncType::ST0 : RTLIL::SyncType::ST1;
278  sync->signal = mod->wire(global_arst);
279  sync->actions = arst_actions;
280  proc_it.second->syncs.push_back(sync);
281  }
282  }
283  }
284  }
285 } ProcArstPass;
286 
const char * c_str() const
Definition: rtlil.h:178
bool selected(T1 *module) const
Definition: rtlil.h:551
virtual void help()
Definition: proc_arst.cc:206
void log_header(const char *format,...)
Definition: log.cc:188
#define YOSYS_NAMESPACE_END
Definition: yosys.h:100
RTLIL::SyncType type
Definition: rtlil.h:1144
YOSYS_NAMESPACE_END USING_YOSYS_NAMESPACE PRIVATE_NAMESPACE_BEGIN bool check_signal(RTLIL::Module *mod, RTLIL::SigSpec signal, RTLIL::SigSpec ref, bool &polarity)
Definition: proc_arst.cc:33
const char * log_signal(const RTLIL::SigSpec &sig, bool autoint)
Definition: log.cc:269
void log_error(const char *format,...)
Definition: log.cc:204
RTLIL::SigSpec signal
Definition: rtlil.h:1145
int size() const
Definition: rtlil.h:1019
std::vector< RTLIL::SigSpec > compare
Definition: rtlil.h:1119
void apply(RTLIL::SigBit &bit) const
Definition: sigtools.h:383
SigMap assign_map
Definition: abc.cc:93
static std::string escape_id(std::string str)
Definition: rtlil.h:251
void eliminate_const(RTLIL::Module *mod, RTLIL::CaseRule *cs, RTLIL::SigSpec const_sig, bool polarity)
Definition: proc_arst.cc:121
USING_YOSYS_NAMESPACE PRIVATE_NAMESPACE_BEGIN bool did_something
Definition: opt_const.cc:32
void proc_arst(RTLIL::Module *mod, RTLIL::Process *proc, SigMap &assign_map)
Definition: proc_arst.cc:156
void apply_const(RTLIL::Module *mod, const RTLIL::SigSpec rspec, RTLIL::SigSpec &rval, RTLIL::CaseRule *cs, RTLIL::SigSpec const_sig, bool polarity, bool unknown)
Definition: proc_arst.cc:88
ProcArstPass ProcArstPass
#define PRIVATE_NAMESPACE_BEGIN
Definition: yosys.h:97
int GetSize(RTLIL::Wire *wire)
Definition: yosys.cc:334
bool is_fully_const() const
Definition: rtlil.cc:2763
RTLIL::IdString name
Definition: rtlil.h:599
YOSYS_NAMESPACE_BEGIN void proc_clean_case(RTLIL::CaseRule *cs, bool &did_something, int &count, int max_depth)
Definition: proc_clean.cc:99
#define PRIVATE_NAMESPACE_END
Definition: yosys.h:98
Definition: register.h:27
std::vector< RTLIL::SigSig > actions
Definition: rtlil.h:1146
RTLIL::IdString name
Definition: rtlil.h:1154
#define USING_YOSYS_NAMESPACE
Definition: yosys.h:102
RTLIL::ObjRange< RTLIL::Cell * > cells()
Definition: rtlil.h:641
RTLIL::ObjRange< RTLIL::Module * > modules()
Definition: rtlil.cc:249
void replace(const RTLIL::SigSpec &pattern, const RTLIL::SigSpec &with)
Definition: rtlil.cc:2297
#define NULL
#define YOSYS_NAMESPACE_BEGIN
Definition: yosys.h:99
void log(const char *format,...)
Definition: log.cc:180
std::vector< RTLIL::SyncRule * > syncs
Definition: rtlil.h:1157
RTLIL::SigSpec extract(const RTLIL::SigSpec &pattern, const RTLIL::SigSpec *other=NULL) const
Definition: rtlil.cc:2414
virtual void execute(std::vector< std::string > args, RTLIL::Design *design)
Definition: proc_arst.cc:224
void append(const RTLIL::SigSpec &signal)
Definition: rtlil.cc:2523
void extend(int width, bool is_signed=false)
Definition: rtlil.cc:2593
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
std::vector< RTLIL::SwitchRule * > switches
Definition: rtlil.h:1121
std::pair< SigSpec, SigSpec > SigSig
Definition: rtlil.h:71
bool has_marked_bits() const
Definition: rtlil.cc:2804
RTLIL_ATTRIBUTE_MEMBERS RTLIL::CaseRule root_case
Definition: rtlil.h:1156