Merge branch 'const-func-block-var' of https://github.com/zachjs/yosys into zachjs...
[yosys.git] / passes / sat / async2sync.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/yosys.h"
21 #include "kernel/sigtools.h"
22 #include "kernel/ffinit.h"
23 #include "kernel/ff.h"
24
25 USING_YOSYS_NAMESPACE
26 PRIVATE_NAMESPACE_BEGIN
27
28 struct Async2syncPass : public Pass {
29 Async2syncPass() : Pass("async2sync", "convert async FF inputs to sync circuits") { }
30 void help() override
31 {
32 // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
33 log("\n");
34 log(" async2sync [options] [selection]\n");
35 log("\n");
36 log("This command replaces async FF inputs with sync circuits emulating the same\n");
37 log("behavior for when the async signals are actually synchronized to the clock.\n");
38 log("\n");
39 log("This pass assumes negative hold time for the async FF inputs. For example when\n");
40 log("a reset deasserts with the clock edge, then the FF output will still drive the\n");
41 log("reset value in the next cycle regardless of the data-in value at the time of\n");
42 log("the clock edge.\n");
43 log("\n");
44 log("Currently only $adff, $dffsr, and $dlatch cells are supported by this pass.\n");
45 log("\n");
46 }
47 void execute(std::vector<std::string> args, RTLIL::Design *design) override
48 {
49 // bool flag_noinit = false;
50
51 log_header(design, "Executing ASYNC2SYNC pass.\n");
52
53 size_t argidx;
54 for (argidx = 1; argidx < args.size(); argidx++)
55 {
56 // if (args[argidx] == "-noinit") {
57 // flag_noinit = true;
58 // continue;
59 // }
60 break;
61 }
62 extra_args(args, argidx, design);
63
64 for (auto module : design->selected_modules())
65 {
66 SigMap sigmap(module);
67 FfInitVals initvals(&sigmap, module);
68
69 for (auto cell : vector<Cell*>(module->selected_cells()))
70 {
71 if (!RTLIL::builtin_ff_cell_types().count(cell->type))
72 continue;
73
74 FfData ff(&initvals, cell);
75
76 // Skip for $_FF_ and $ff cells.
77 if (ff.has_d && !ff.has_clk && !ff.has_en)
78 continue;
79
80 if (ff.has_clk)
81 {
82 if (!ff.has_sr && !ff.has_arst)
83 continue;
84
85 if (ff.has_sr) {
86 ff.unmap_ce_srst(module);
87
88 log("Replacing %s.%s (%s): SET=%s, CLR=%s, D=%s, Q=%s\n",
89 log_id(module), log_id(cell), log_id(cell->type),
90 log_signal(ff.sig_set), log_signal(ff.sig_clr), log_signal(ff.sig_d), log_signal(ff.sig_q));
91
92 initvals.remove_init(ff.sig_q);
93
94 Wire *new_d = module->addWire(NEW_ID, ff.width);
95 Wire *new_q = module->addWire(NEW_ID, ff.width);
96
97 SigSpec sig_set = ff.sig_set;
98 SigSpec sig_clr = ff.sig_clr;
99
100 if (!ff.pol_set) {
101 if (!ff.is_fine)
102 sig_set = module->Not(NEW_ID, sig_set);
103 else
104 sig_set = module->NotGate(NEW_ID, sig_set);
105 }
106
107 if (ff.pol_clr) {
108 if (!ff.is_fine)
109 sig_clr = module->Not(NEW_ID, sig_clr);
110 else
111 sig_clr = module->NotGate(NEW_ID, sig_clr);
112 }
113
114 if (!ff.is_fine) {
115 SigSpec tmp = module->Or(NEW_ID, ff.sig_d, sig_set);
116 module->addAnd(NEW_ID, tmp, sig_clr, new_d);
117
118 tmp = module->Or(NEW_ID, new_q, sig_set);
119 module->addAnd(NEW_ID, tmp, sig_clr, ff.sig_q);
120 } else {
121 SigSpec tmp = module->OrGate(NEW_ID, ff.sig_d, sig_set);
122 module->addAndGate(NEW_ID, tmp, sig_clr, new_d);
123
124 tmp = module->OrGate(NEW_ID, new_q, sig_set);
125 module->addAndGate(NEW_ID, tmp, sig_clr, ff.sig_q);
126 }
127
128 ff.sig_d = new_d;
129 ff.sig_q = new_q;
130 ff.has_sr = false;
131 } else if (ff.has_arst) {
132 ff.unmap_srst(module);
133
134 log("Replacing %s.%s (%s): ARST=%s, D=%s, Q=%s\n",
135 log_id(module), log_id(cell), log_id(cell->type),
136 log_signal(ff.sig_arst), log_signal(ff.sig_d), log_signal(ff.sig_q));
137
138 initvals.remove_init(ff.sig_q);
139
140 Wire *new_q = module->addWire(NEW_ID, ff.width);
141
142 if (ff.pol_arst) {
143 if (!ff.is_fine)
144 module->addMux(NEW_ID, new_q, ff.val_arst, ff.sig_arst, ff.sig_q);
145 else
146 module->addMuxGate(NEW_ID, new_q, ff.val_arst[0], ff.sig_arst, ff.sig_q);
147 } else {
148 if (!ff.is_fine)
149 module->addMux(NEW_ID, ff.val_arst, new_q, ff.sig_arst, ff.sig_q);
150 else
151 module->addMuxGate(NEW_ID, ff.val_arst[0], new_q, ff.sig_arst, ff.sig_q);
152 }
153
154 ff.sig_q = new_q;
155 ff.has_arst = false;
156 ff.has_srst = true;
157 ff.val_srst = ff.val_arst;
158 ff.sig_srst = ff.sig_arst;
159 ff.pol_srst = ff.pol_arst;
160 }
161 }
162 else
163 {
164 // Latch.
165 log("Replacing %s.%s (%s): EN=%s, D=%s, Q=%s\n",
166 log_id(module), log_id(cell), log_id(cell->type),
167 log_signal(ff.sig_en), log_signal(ff.sig_d), log_signal(ff.sig_q));
168
169 initvals.remove_init(ff.sig_q);
170
171 Wire *new_q = module->addWire(NEW_ID, ff.width);
172 Wire *new_d;
173
174 if (ff.has_d) {
175 new_d = module->addWire(NEW_ID, ff.width);
176 if (ff.pol_en) {
177 if (!ff.is_fine)
178 module->addMux(NEW_ID, new_q, ff.sig_d, ff.sig_en, new_d);
179 else
180 module->addMuxGate(NEW_ID, new_q, ff.sig_d, ff.sig_en, new_d);
181 } else {
182 if (!ff.is_fine)
183 module->addMux(NEW_ID, ff.sig_d, new_q, ff.sig_en, new_d);
184 else
185 module->addMuxGate(NEW_ID, ff.sig_d, new_q, ff.sig_en, new_d);
186 }
187 } else {
188 new_d = new_q;
189 }
190
191 if (ff.has_sr) {
192 SigSpec sig_set = ff.sig_set;
193 SigSpec sig_clr = ff.sig_clr;
194
195 if (!ff.pol_set) {
196 if (!ff.is_fine)
197 sig_set = module->Not(NEW_ID, sig_set);
198 else
199 sig_set = module->NotGate(NEW_ID, sig_set);
200 }
201
202 if (ff.pol_clr) {
203 if (!ff.is_fine)
204 sig_clr = module->Not(NEW_ID, sig_clr);
205 else
206 sig_clr = module->NotGate(NEW_ID, sig_clr);
207 }
208
209 if (!ff.is_fine) {
210 SigSpec tmp = module->Or(NEW_ID, new_d, sig_set);
211 module->addAnd(NEW_ID, tmp, sig_clr, ff.sig_q);
212 } else {
213 SigSpec tmp = module->OrGate(NEW_ID, new_d, sig_set);
214 module->addAndGate(NEW_ID, tmp, sig_clr, ff.sig_q);
215 }
216 } else if (ff.has_arst) {
217 if (ff.pol_arst) {
218 if (!ff.is_fine)
219 module->addMux(NEW_ID, new_d, ff.val_arst, ff.sig_arst, ff.sig_q);
220 else
221 module->addMuxGate(NEW_ID, new_d, ff.val_arst[0], ff.sig_arst, ff.sig_q);
222 } else {
223 if (!ff.is_fine)
224 module->addMux(NEW_ID, ff.val_arst, new_d, ff.sig_arst, ff.sig_q);
225 else
226 module->addMuxGate(NEW_ID, ff.val_arst[0], new_d, ff.sig_arst, ff.sig_q);
227 }
228 } else {
229 module->connect(ff.sig_q, new_d);
230 }
231
232 ff.sig_d = new_d;
233 ff.sig_q = new_q;
234 ff.has_en = false;
235 ff.has_arst = false;
236 ff.has_sr = false;
237 ff.has_d = true;
238 }
239
240 IdString name = cell->name;
241 module->remove(cell);
242 ff.emit(module, name);
243 }
244 }
245 }
246 } Async2syncPass;
247
248 PRIVATE_NAMESPACE_END