]> Witch of Git - nan-gate/blob - nangate.cc
Do NaN synthesis pattern matching via attributes
[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
16 NandToNaNWorker(RTLIL::Design *design, RTLIL::Module *module) :
17 design(design), module(module)
18 {
19 for (auto cell : module->selected_cells()) {
20 if (cell->type == "$_NAND_") {
21 b2f_count += 2;
22 nand_count += 1;
23 f2b_count += 1;
24 RTLIL::Cell *b2fA = module->addCell(NEW_ID, "\\bit_to_fp3");
25 RTLIL::Cell *b2fB = module->addCell(NEW_ID, "\\bit_to_fp3");
26 RTLIL::Cell *nan = module->addCell(NEW_ID, "\\nan_fp3");
27 RTLIL::Cell *f2b = module->addCell(NEW_ID, "\\fp3_to_bit");
28 b2fA->attributes[ID(nan_b2f)] = 3;
29 b2fB->attributes[ID(nan_b2f)] = 3;
30 nan->attributes[ID(nan_cell)] = 3;
31 f2b->attributes[ID(nan_f2b)] = 3;
32 b2fA->setPort("\\A", cell->getPort("\\A"));
33 b2fA->setPort("\\Y", module->addWire(NEW_ID, 3));
34 b2fB->setPort("\\A", cell->getPort("\\B"));
35 b2fB->setPort("\\Y", module->addWire(NEW_ID, 3));
36 f2b->setPort("\\A", module->addWire(NEW_ID, 3));
37 f2b->setPort("\\Y", cell->getPort("\\Y"));
38 nan->setPort("\\A", b2fA->getPort("\\Y"));
39 nan->setPort("\\B", b2fB->getPort("\\Y"));
40 nan->setPort("\\Y", f2b->getPort("\\A"));
41 module->swap_names(cell, nan);
42 module->remove(cell);
43 } else if (cell->type == "$_NOT_") {
44 b2f_count += 1;
45 not_count += 1;
46 f2b_count += 1;
47 RTLIL::Cell *b2f = module->addCell(NEW_ID, "\\bit_to_fp3");
48 RTLIL::Cell *nan = module->addCell(NEW_ID, "\\nan_fp3");
49 RTLIL::Cell *f2b = module->addCell(NEW_ID, "\\fp3_to_bit");
50 b2f->attributes[ID(nan_b2f)] = 3;
51 nan->attributes[ID(nan_cell)] = 3;
52 f2b->attributes[ID(nan_f2b)] = 3;
53 b2f->setPort("\\A", cell->getPort("\\A"));
54 b2f->setPort("\\Y", module->addWire(NEW_ID, 3));
55 f2b->setPort("\\A", module->addWire(NEW_ID, 3));
56 f2b->setPort("\\Y", cell->getPort("\\Y"));
57 nan->setPort("\\A", b2f->getPort("\\Y"));
58 nan->setPort("\\B", b2f->getPort("\\Y"));
59 nan->setPort("\\Y", f2b->getPort("\\A"));
60 module->swap_names(cell, nan);
61 module->remove(cell);
62 }
63 }
64 }
65 };
66
67 struct NandToNaNPass : public Pass {
68 NandToNaNPass() : Pass("nand_to_nan") {}
69 void execute(vector<string> args, Design *design) override {
70 log_header(design, "Executing NAND_TO_NaN pass (implementing tom7 logic)\n");
71 log_push();
72 Pass::call(design, "read_verilog -lib -sv +/nangate/techlib.sv");
73 log_pop();
74
75 (void) args;
76 for (auto module : design->selected_modules()) {
77 log("Replacing NAND with NaN in module %s...\n", log_id(module));
78 NandToNaNWorker worker(design, module);
79 log("Replaced %d NAND gates and %d NOT gates.\n",
80 worker.nand_count, worker.not_count);
81 log("Inserted:\n nan_fp3: %5d\n bit_to_fp3: %5d\n fp3_to_bit: %5d\n",
82 worker.nand_count + worker.not_count,
83 worker.b2f_count, worker.f2b_count);
84 }
85 }
86 } NandToNaNPass;
87
88 struct DffToFp3Pass : public Pass {
89 DffToFp3Pass() : Pass("dff_nan") {}
90 void execute(vector<string> args, Design *design) override {
91 log_header(design, "Executing DFF_NaN pass (widening flipflops to hold floats)\n");
92 (void) args;
93 for (auto module : design->selected_modules()) {
94 log(" Module %s\n", log_id(module));
95 dff_nan_pm pm(module, module->selected_cells());
96 pool<RTLIL::Cell*> dffs;
97 pm.run([&]() { dffs.insert(pm.st.dff); });
98 for (auto &dff : dffs) {
99 RTLIL::Cell *f2b = module->addCell(NEW_ID, "\\fp3_to_bit");
100 f2b->attributes[ID(nan_f2b)] = 3;
101 f2b->setPort("\\A", module->addWire(NEW_ID, 3));
102 f2b->setPort("\\Y", dff->getPort("\\Q"));
103 RTLIL::Cell *b2f = module->addCell(NEW_ID, "\\bit_to_fp3");
104 b2f->attributes[ID(nan_b2f)] = 3;
105 b2f->setPort("\\A", dff->getPort("\\D"));
106 b2f->setPort("\\Y", module->addWire(NEW_ID, 3));
107 for (int i = 0; i < 3; i++) {
108 // @TODO: Support more DFF types
109 assert(dff->type == "$_DFF_P_");
110 RTLIL::Cell *new_ff = module->addCell(NEW_ID, "$_DFF_P_");
111 new_ff->setPort("\\C", dff->getPort("\\C"));
112 new_ff->setPort("\\D", b2f->getPort("\\Y")[i]);
113 new_ff->setPort("\\Q", f2b->getPort("\\A")[i]);
114 }
115 module->remove(dff);
116 }
117 log("Converted %d flip-flops to hold floats\n", GetSize(dffs));
118 }
119 }
120 } DffToFp3Pass;
121
122 struct EraseFpBitPass : public Pass {
123 EraseFpBitPass() : Pass("simplify_nan") {}
124 void execute(vector<string> args, Design *design) override {
125 log_header(design, "Executing SIMPLIFY_NaN pass (erasing useless conversion chains)\n");
126 (void) args;
127 for (auto module : design->selected_modules()) {
128 log("Simplifying NaN conversions in module %s\n", log_id(module));
129 erase_b2f_pm pm(module, module->selected_cells());
130 pool<RTLIL::Cell*> eraseCells;
131 pm.run([&]() {
132 module->connect(pm.st.base->getPort("\\A"), pm.st.target->getPort("\\Y"));
133 eraseCells.insert(pm.st.target);
134 });
135 for (auto cell : eraseCells) {
136 module->remove(cell);
137 }
138 log("Removed %d bit_to_fp3 nodes\n", GetSize(eraseCells));
139 }
140 }
141 } EraseFpBitPass;
142
143 struct ShareNaN : public Pass {
144 ShareNaN() : Pass("share_nan") {}
145 void execute(vector <string> args, Design *design) override {
146 log_header(design, "Executing SHARE_NAN pass (merging conversion cells).\n");
147 (void) args;
148 for (auto module : design->selected_modules()) {
149 log("Module %s\n", log_id(module));
150 share_nan_pm pm(module, module->selected_cells());
151 mfp<RTLIL::Cell*> sharedCells;
152 pm.run([&]() { sharedCells.merge(pm.st.cvt_a, pm.st.cvt_b); });
153 int merged = 0;
154 for (auto &entry : sharedCells) {
155 auto &main = sharedCells.find(entry);
156 if (entry == main) continue;
157 merged += 1;
158 module->connect(main->getPort("\\Y"), entry->getPort("\\Y"));
159 module->remove(entry);
160 }
161 log("Merged %d conversion cells\n", merged);
162 }
163 }
164 } ShareNaNPass;
165
166 struct TechmapNaN : public Pass {
167 TechmapNaN() : Pass("techmap_nan", "techmap NaN gates") {}
168 void execute(vector<string>, Design *design) override {
169 Pass::call(design, "techmap -autoproc -extern -map +/nangate/techlib.sv");
170 }
171 } TechmapNaNPass;
172
173 struct SynthNaN : public Pass {
174 SynthNaN() : Pass("synth_nan", "synthesize to tom7 logic") {}
175 void help() override {
176 log("synth_nan [options]\n\n");
177 log("Runs the equivalent of the following script:\n\n");
178 log(" synth [-top <module>]\n");
179 log(" abc -g NAND\n");
180 log(" nand_to_nan\n");
181 log(" share_nan\n");
182 log(" dff_nan\n");
183 log(" simplify_nan\n");
184 log(" clean\n");
185 log(" techmap_nan\n");
186 }
187 void execute(vector <string> args, Design *design) override {
188 string synth_args;
189 log_header(design, "Executing SYNTH_NaN pass (synthesizing to tom7 logic).\n");
190 log_push();
191 for (size_t i = 0; i < args.size(); i++) {
192 if (args[i] == "-top") {
193 synth_args += " -top ";
194 synth_args += args[i+1];
195 i += 1;
196 continue;
197 }
198 }
199 Pass::call(design, "synth" + synth_args);
200 Pass::call(design, "abc -g NAND");
201 Pass::call(design, "nand_to_nan");
202 Pass::call(design, "share_nan");
203 Pass::call(design, "dff_nan");
204 Pass::call(design, "simplify_nan");
205 Pass::call(design, "clean");
206 Pass::call(design, "techmap_nan");
207 log_pop();
208 }
209 } SynthNaNPass;
210
211 PRIVATE_NAMESPACE_END
212