async2sync: Refactor to use FfInitVals.
[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
24 USING_YOSYS_NAMESPACE
25 PRIVATE_NAMESPACE_BEGIN
26
27 struct Async2syncPass : public Pass {
28 Async2syncPass() : Pass("async2sync", "convert async FF inputs to sync circuits") { }
29 void help() override
30 {
31 // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
32 log("\n");
33 log(" async2sync [options] [selection]\n");
34 log("\n");
35 log("This command replaces async FF inputs with sync circuits emulating the same\n");
36 log("behavior for when the async signals are actually synchronized to the clock.\n");
37 log("\n");
38 log("This pass assumes negative hold time for the async FF inputs. For example when\n");
39 log("a reset deasserts with the clock edge, then the FF output will still drive the\n");
40 log("reset value in the next cycle regardless of the data-in value at the time of\n");
41 log("the clock edge.\n");
42 log("\n");
43 log("Currently only $adff, $dffsr, and $dlatch cells are supported by this pass.\n");
44 log("\n");
45 }
46 void execute(std::vector<std::string> args, RTLIL::Design *design) override
47 {
48 // bool flag_noinit = false;
49
50 log_header(design, "Executing ASYNC2SYNC pass.\n");
51
52 size_t argidx;
53 for (argidx = 1; argidx < args.size(); argidx++)
54 {
55 // if (args[argidx] == "-noinit") {
56 // flag_noinit = true;
57 // continue;
58 // }
59 break;
60 }
61 extra_args(args, argidx, design);
62
63 for (auto module : design->selected_modules())
64 {
65 SigMap sigmap(module);
66 FfInitVals initvals(&sigmap, module);
67
68 for (auto cell : vector<Cell*>(module->selected_cells()))
69 {
70 if (cell->type.in(ID($adff)))
71 {
72 // bool clk_pol = cell->parameters[ID::CLK_POLARITY].as_bool();
73 bool arst_pol = cell->parameters[ID::ARST_POLARITY].as_bool();
74 Const arst_val = cell->parameters[ID::ARST_VALUE];
75
76 // SigSpec sig_clk = cell->getPort(ID::CLK);
77 SigSpec sig_arst = cell->getPort(ID::ARST);
78 SigSpec sig_d = cell->getPort(ID::D);
79 SigSpec sig_q = cell->getPort(ID::Q);
80
81 log("Replacing %s.%s (%s): ARST=%s, D=%s, Q=%s\n",
82 log_id(module), log_id(cell), log_id(cell->type),
83 log_signal(sig_arst), log_signal(sig_d), log_signal(sig_q));
84
85 Const init_val = initvals(sig_q);
86 initvals.remove_init(sig_q);
87
88 Wire *new_d = module->addWire(NEW_ID, GetSize(sig_d));
89 Wire *new_q = module->addWire(NEW_ID, GetSize(sig_q));
90 initvals.set_init(new_q, init_val);
91
92 if (arst_pol) {
93 module->addMux(NEW_ID, sig_d, arst_val, sig_arst, new_d);
94 module->addMux(NEW_ID, new_q, arst_val, sig_arst, sig_q);
95 } else {
96 module->addMux(NEW_ID, arst_val, sig_d, sig_arst, new_d);
97 module->addMux(NEW_ID, arst_val, new_q, sig_arst, sig_q);
98 }
99
100 cell->setPort(ID::D, new_d);
101 cell->setPort(ID::Q, new_q);
102 cell->unsetPort(ID::ARST);
103 cell->unsetParam(ID::ARST_POLARITY);
104 cell->unsetParam(ID::ARST_VALUE);
105 cell->type = ID($dff);
106 continue;
107 }
108
109 if (cell->type.in(ID($dffsr)))
110 {
111 // bool clk_pol = cell->parameters[ID::CLK_POLARITY].as_bool();
112 bool set_pol = cell->parameters[ID::SET_POLARITY].as_bool();
113 bool clr_pol = cell->parameters[ID::CLR_POLARITY].as_bool();
114
115 // SigSpec sig_clk = cell->getPort(ID::CLK);
116 SigSpec sig_set = cell->getPort(ID::SET);
117 SigSpec sig_clr = cell->getPort(ID::CLR);
118 SigSpec sig_d = cell->getPort(ID::D);
119 SigSpec sig_q = cell->getPort(ID::Q);
120
121 log("Replacing %s.%s (%s): SET=%s, CLR=%s, D=%s, Q=%s\n",
122 log_id(module), log_id(cell), log_id(cell->type),
123 log_signal(sig_set), log_signal(sig_clr), log_signal(sig_d), log_signal(sig_q));
124
125 Const init_val = initvals(sig_q);
126 initvals.remove_init(sig_q);
127
128 Wire *new_d = module->addWire(NEW_ID, GetSize(sig_d));
129 Wire *new_q = module->addWire(NEW_ID, GetSize(sig_q));
130 initvals.set_init(new_q, init_val);
131
132 if (!set_pol)
133 sig_set = module->Not(NEW_ID, sig_set);
134
135 if (clr_pol)
136 sig_clr = module->Not(NEW_ID, sig_clr);
137
138 SigSpec tmp = module->Or(NEW_ID, sig_d, sig_set);
139 module->addAnd(NEW_ID, tmp, sig_clr, new_d);
140
141 tmp = module->Or(NEW_ID, new_q, sig_set);
142 module->addAnd(NEW_ID, tmp, sig_clr, sig_q);
143
144 cell->setPort(ID::D, new_d);
145 cell->setPort(ID::Q, new_q);
146 cell->unsetPort(ID::SET);
147 cell->unsetPort(ID::CLR);
148 cell->unsetParam(ID::SET_POLARITY);
149 cell->unsetParam(ID::CLR_POLARITY);
150 cell->type = ID($dff);
151 continue;
152 }
153
154 if (cell->type.in(ID($dlatch)))
155 {
156 bool en_pol = cell->parameters[ID::EN_POLARITY].as_bool();
157
158 SigSpec sig_en = cell->getPort(ID::EN);
159 SigSpec sig_d = cell->getPort(ID::D);
160 SigSpec sig_q = cell->getPort(ID::Q);
161
162 log("Replacing %s.%s (%s): EN=%s, D=%s, Q=%s\n",
163 log_id(module), log_id(cell), log_id(cell->type),
164 log_signal(sig_en), log_signal(sig_d), log_signal(sig_q));
165
166 Const init_val = initvals(sig_q);
167 initvals.remove_init(sig_q);
168
169 Wire *new_q = module->addWire(NEW_ID, GetSize(sig_q));
170 initvals.set_init(new_q, init_val);
171
172 if (en_pol) {
173 module->addMux(NEW_ID, new_q, sig_d, sig_en, sig_q);
174 } else {
175 module->addMux(NEW_ID, sig_d, new_q, sig_en, sig_q);
176 }
177
178 cell->setPort(ID::D, sig_q);
179 cell->setPort(ID::Q, new_q);
180 cell->unsetPort(ID::EN);
181 cell->unsetParam(ID::EN_POLARITY);
182 cell->type = ID($ff);
183 continue;
184 }
185 }
186 }
187 }
188 } Async2syncPass;
189
190 PRIVATE_NAMESPACE_END