]> Witch of Git - nan-gate/blob - nangate.cc
70df222a6081aa064c2543f9e2a368cfc76c4e1b
[nan-gate] / nangate.cc
1 #include "kernel/yosys.h"
2 #include "kernel/celltypes.h"
3 #include "erase_b2f_pm.h"
4 #include "dff_nan_pm.h"
5 #include "share_nan_pm.h"
6
7 USING_YOSYS_NAMESPACE
8 PRIVATE_NAMESPACE_BEGIN
9
10 struct NandToNaNWorker
11 {
12 int nand_count = 0, not_count = 0, b2f_count = 0, f2b_count = 0;
13 RTLIL::Design *design;
14 RTLIL::Module *module;
15 size_t width;
16
17 NandToNaNWorker(RTLIL::Design *design, RTLIL::Module *module, size_t width) :
18 design(design), module(module), width(width)
19 {
20 IdString b2f_cell("\\bit_to_fp" + std::to_string(width));
21 IdString nan_cell("\\nan_fp" + std::to_string(width));
22 IdString f2b_cell("\\fp" + std::to_string(width) + "_to_bit");
23
24 for (auto cell : module->selected_cells()) {
25 if (cell->type == "$_NAND_") {
26 b2f_count += 2;
27 nand_count += 1;
28 f2b_count += 1;
29 RTLIL::Cell *b2fA = module->addCell(NEW_ID, b2f_cell);
30 RTLIL::Cell *b2fB = module->addCell(NEW_ID, b2f_cell);
31 RTLIL::Cell *nan = module->addCell(NEW_ID, nan_cell);
32 RTLIL::Cell *f2b = module->addCell(NEW_ID, f2b_cell);
33 b2fA->attributes[ID(nan_b2f)] = width;
34 b2fB->attributes[ID(nan_b2f)] = width;
35 nan->attributes[ID(nan_cell)] = width;
36 f2b->attributes[ID(nan_f2b)] = width;
37 b2fA->setPort("\\A", cell->getPort("\\A"));
38 b2fA->setPort("\\Y", module->addWire(NEW_ID, width));
39 b2fB->setPort("\\A", cell->getPort("\\B"));
40 b2fB->setPort("\\Y", module->addWire(NEW_ID, width));
41 f2b->setPort("\\A", module->addWire(NEW_ID, width));
42 f2b->setPort("\\Y", cell->getPort("\\Y"));
43 nan->setPort("\\A", b2fA->getPort("\\Y"));
44 nan->setPort("\\B", b2fB->getPort("\\Y"));
45 nan->setPort("\\Y", f2b->getPort("\\A"));
46 module->swap_names(cell, nan);
47 module->remove(cell);
48 } else if (cell->type == "$_NOT_") {
49 b2f_count += 1;
50 not_count += 1;
51 f2b_count += 1;
52 RTLIL::Cell *b2f = module->addCell(NEW_ID, b2f_cell);
53 RTLIL::Cell *nan = module->addCell(NEW_ID, nan_cell);
54 RTLIL::Cell *f2b = module->addCell(NEW_ID, f2b_cell);
55 b2f->attributes[ID(nan_b2f)] = width;
56 nan->attributes[ID(nan_cell)] = width;
57 f2b->attributes[ID(nan_f2b)] = width;
58 b2f->setPort("\\A", cell->getPort("\\A"));
59 b2f->setPort("\\Y", module->addWire(NEW_ID, width));
60 f2b->setPort("\\A", module->addWire(NEW_ID, width));
61 f2b->setPort("\\Y", cell->getPort("\\Y"));
62 nan->setPort("\\A", b2f->getPort("\\Y"));
63 nan->setPort("\\B", b2f->getPort("\\Y"));
64 nan->setPort("\\Y", f2b->getPort("\\A"));
65 module->swap_names(cell, nan);
66 module->remove(cell);
67 }
68 }
69 }
70 };
71
72 struct NandToNaNPass : public Pass {
73 NandToNaNPass() : Pass("nand_to_nan") {}
74 void execute(vector<string> args, Design *design) override {
75 log_header(design, "Executing NAND_TO_NaN pass (implementing tom7 logic)\n");
76 log_push();
77 Pass::call(design, "read_verilog -lib -sv +/plugins/nangate/techlib.sv");
78 log_pop();
79
80 int width = 3;
81 size_t argidx = 1;
82 for (; argidx < args.size(); ++argidx) {
83 if (args[argidx] == "-width" and argidx + 1 < args.size()) {
84 try {
85 width = std::stoi(args[++argidx]);
86 } catch (...) {
87 cmd_error(args, argidx, "Invalid number");
88 }
89 continue;
90 }
91 break;
92 }
93
94 for (auto module : design->selected_modules()) {
95 log("Replacing NAND with NaN in module %s...\n", log_id(module));
96 NandToNaNWorker worker(design, module, width);
97 log("Replaced %d NAND gates and %d NOT gates.\n",
98 worker.nand_count, worker.not_count);
99 log("Inserted:\n nan_fp#: %5d\n bit_to_fp#: %5d\n fp#_to_bit: %5d\n",
100 worker.nand_count + worker.not_count,
101 worker.b2f_count, worker.f2b_count);
102 }
103 }
104 } NandToNaNPass;
105
106 struct DffToFpPass : public Pass {
107 DffToFpPass() : Pass("dff_nan") {}
108 void execute(vector<string> args, Design *design) override {
109 log_header(design, "Executing DFF_NaN pass (widening flipflops to hold floats)\n");
110
111 int width = 3;
112 size_t argidx = 1;
113 for (; argidx < args.size(); ++argidx) {
114 if (args[argidx] == "-width" and argidx + 1 < args.size()) {
115 try {
116 width = std::stoi(args[++argidx]);
117 } catch (...) {
118 cmd_error(args, argidx, "Invalid number");
119 }
120 }
121 }
122 extra_args(args, argidx, design, false);
123
124 IdString b2f_cell("\\bit_to_fp" + std::to_string(width));
125 IdString nan_cell("\\nan_fp" + std::to_string(width));
126 IdString f2b_cell("\\fp" + std::to_string(width) + "_to_bit");
127
128 for (auto module : design->selected_modules()) {
129 log(" Module %s\n", log_id(module));
130 dff_nan_pm pm(module, module->selected_cells());
131 pool<RTLIL::Cell*> dffs;
132 pm.run([&]() { dffs.insert(pm.st.dff); });
133 for (auto &dff : dffs) {
134 RTLIL::Cell *f2b = module->addCell(NEW_ID, f2b_cell);
135 f2b->attributes[ID(nan_f2b)] = width;
136 f2b->setPort("\\A", module->addWire(NEW_ID, width));
137 f2b->setPort("\\Y", dff->getPort("\\Q"));
138 RTLIL::Cell *b2f = module->addCell(NEW_ID, b2f_cell);
139 b2f->attributes[ID(nan_b2f)] = width;
140 b2f->setPort("\\A", dff->getPort("\\D"));
141 b2f->setPort("\\Y", module->addWire(NEW_ID, width));
142 for (int i = 0; i < width; i++) {
143 // @TODO: Support more DFF types
144 assert(dff->type == "$_DFF_P_");
145 RTLIL::Cell *new_ff = module->addCell(NEW_ID, "$_DFF_P_");
146 new_ff->setPort("\\C", dff->getPort("\\C"));
147 new_ff->setPort("\\D", b2f->getPort("\\Y")[i]);
148 new_ff->setPort("\\Q", f2b->getPort("\\A")[i]);
149 }
150 module->remove(dff);
151 }
152 log("Converted %d flip-flops to hold floats\n", GetSize(dffs));
153 }
154 }
155 } DffToFpPass;
156
157 struct EraseFpBitPass : public Pass {
158 EraseFpBitPass() : Pass("simplify_nan") {}
159 void execute(vector<string> args, Design *design) override {
160 log_header(design, "Executing SIMPLIFY_NaN pass (erasing useless conversion chains)\n");
161 (void) args;
162 for (auto module : design->selected_modules()) {
163 log("Simplifying NaN conversions in module %s\n", log_id(module));
164 erase_b2f_pm pm(module, module->selected_cells());
165 pool<RTLIL::Cell*> eraseCells;
166 pm.run([&]() {
167 module->connect(pm.st.base->getPort("\\A"), pm.st.target->getPort("\\Y"));
168 eraseCells.insert(pm.st.target);
169 });
170 for (auto cell : eraseCells) {
171 module->remove(cell);
172 }
173 log("Removed %d bit_to_fp# nodes\n", GetSize(eraseCells));
174 }
175 }
176 } EraseFpBitPass;
177
178 struct ShareNaN : public Pass {
179 ShareNaN() : Pass("share_nan") {}
180 void execute(vector <string> args, Design *design) override {
181 log_header(design, "Executing SHARE_NAN pass (merging conversion cells).\n");
182 (void)args;
183 for (auto module : design->selected_modules()) {
184 log("Module %s\n", log_id(module));
185 share_nan_pm pm(module, module->selected_cells());
186 mfp<RTLIL::Cell*> sharedCells;
187 pm.run([&]() { sharedCells.merge(pm.st.cvt_a, pm.st.cvt_b); });
188 int merged = 0;
189 for (auto &entry : sharedCells) {
190 auto &main = sharedCells.find(entry);
191 if (entry == main) continue;
192 merged += 1;
193 module->connect(main->getPort("\\Y"), entry->getPort("\\Y"));
194 module->remove(entry);
195 }
196 log("Merged %d conversion cells\n", merged);
197 }
198 }
199 } ShareNaNPass;
200
201 struct TechmapNaN : public Pass {
202 TechmapNaN() : Pass("techmap_nan", "techmap NaN gates") {}
203 void execute(vector<string>, Design *design) override {
204 Pass::call(design, "techmap -autoproc -extern -map +/plugins/nangate/techlib.sv");
205 }
206 } TechmapNaNPass;
207
208 struct SynthNaN : public Pass {
209 SynthNaN() : Pass("synth_nan", "synthesize to tom7 logic") {}
210 void help() override {
211 log("");
212 log(" synth_nan [options]\n\n");
213 log("");
214 log("This command synthesizes a design into NaN gates.");
215 log("");
216 log(" -nosynth <width>");
217 log(" skip the pre-run synthesis step. Requires that the circuit");
218 log(" has already been synthesized down to NAND and NOT gates.");
219 log("");
220 log(" -pre-flatten");
221 log(" flatten duing the initial coarse synthesis");
222 log("");
223 log(" -retime");
224 log(" do retiming in ABC");
225 log("");
226 log(" -top <module>");
227 log(" use the specified module as top module (default='top')");
228 log("");
229 log(" -width <width>");
230 log(" synthesize with a given floating-point with (default=3)");
231 log("");
232 log("Runs the equivalent of the following script:\n\n");
233 log(" synth [-flatten] [-top <module>] (unless -nosynth)\n");
234 log(" abc -g NAND [-dff -D 1] (unless -nosynth)\n");
235 log(" nand_to_nan [-width <width>]\n");
236 log(" share_nan\n");
237 log(" dff_nan [-width <width>]\n");
238 log(" simplify_nan\n");
239 log(" clean\n");
240 log(" techmap_nan\n");
241 }
242 void execute(vector <string> args, Design *design) override {
243 string abc_args;
244 string synth_args;
245 string width_args;
246 log_header(design, "Executing SYNTH_NaN pass (synthesizing to tom7 logic).\n");
247 log_push();
248
249 size_t argidx = 1;
250 bool synth = true;
251 for (; argidx < args.size(); ++argidx) {
252 if (args[argidx] == "-nosynth") {
253 synth = false;
254 continue;
255 }
256 if (args[argidx] == "-pre-flatten") {
257 synth_args += " -flatten";
258 continue;
259 }
260 if (args[argidx] == "-retime") {
261 abc_args += " -dff -D 1";
262 continue;
263 }
264 if (args[argidx] == "-top" and argidx + 1 < args.size()) {
265 synth_args += " -top ";
266 synth_args += args[++argidx];
267 continue;
268 }
269 if (args[argidx] == "-width" and argidx + 1 < args.size()) {
270 width_args += " -width ";
271 width_args += args[++argidx];
272 continue;
273 }
274 break;
275 }
276 extra_args(args, argidx, design, false);
277
278 if (synth) {
279 Pass::call(design, "synth" + synth_args);
280 Pass::call(design, "abc -g NAND" + abc_args);
281 }
282 Pass::call(design, "nand_to_nan" + width_args);
283 Pass::call(design, "share_nan");
284 Pass::call(design, "dff_nan" + width_args);
285 Pass::call(design, "simplify_nan");
286 Pass::call(design, "clean");
287 Pass::call(design, "techmap_nan");
288 log_pop();
289 }
290 } SynthNaNPass;
291
292 PRIVATE_NAMESPACE_END
293