]>
Witch of Git - nan-gate/blob - nangate.cc
70df222a6081aa064c2543f9e2a368cfc76c4e1b
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"
8 PRIVATE_NAMESPACE_BEGIN
10 struct NandToNaNWorker
12 int nand_count
= 0, not_count
= 0, b2f_count
= 0, f2b_count
= 0;
13 RTLIL::Design
*design
;
14 RTLIL::Module
*module
;
17 NandToNaNWorker(RTLIL::Design
*design
, RTLIL::Module
*module
, size_t width
) :
18 design(design
), module(module
), width(width
)
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");
24 for (auto cell
: module
->selected_cells()) {
25 if (cell
->type
== "$_NAND_") {
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
);
48 } else if (cell
->type
== "$_NOT_") {
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
);
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");
77 Pass::call(design
, "read_verilog -lib -sv +/plugins/nangate/techlib.sv");
82 for (; argidx
< args
.size(); ++argidx
) {
83 if (args
[argidx
] == "-width" and argidx
+ 1 < args
.size()) {
85 width
= std::stoi(args
[++argidx
]);
87 cmd_error(args
, argidx
, "Invalid number");
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
);
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");
113 for (; argidx
< args
.size(); ++argidx
) {
114 if (args
[argidx
] == "-width" and argidx
+ 1 < args
.size()) {
116 width
= std::stoi(args
[++argidx
]);
118 cmd_error(args
, argidx
, "Invalid number");
122 extra_args(args
, argidx
, design
, false);
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");
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
]);
152 log("Converted %d flip-flops to hold floats\n", GetSize(dffs
));
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");
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
;
167 module
->connect(pm
.st
.base
->getPort("\\A"), pm
.st
.target
->getPort("\\Y"));
168 eraseCells
.insert(pm
.st
.target
);
170 for (auto cell
: eraseCells
) {
171 module
->remove(cell
);
173 log("Removed %d bit_to_fp# nodes\n", GetSize(eraseCells
));
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");
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
); });
189 for (auto &entry
: sharedCells
) {
190 auto &main
= sharedCells
.find(entry
);
191 if (entry
== main
) continue;
193 module
->connect(main
->getPort("\\Y"), entry
->getPort("\\Y"));
194 module
->remove(entry
);
196 log("Merged %d conversion cells\n", merged
);
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");
208 struct SynthNaN
: public Pass
{
209 SynthNaN() : Pass("synth_nan", "synthesize to tom7 logic") {}
210 void help() override
{
212 log(" synth_nan [options]\n\n");
214 log("This command synthesizes a design into NaN gates.");
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.");
220 log(" -pre-flatten");
221 log(" flatten duing the initial coarse synthesis");
224 log(" do retiming in ABC");
226 log(" -top <module>");
227 log(" use the specified module as top module (default='top')");
229 log(" -width <width>");
230 log(" synthesize with a given floating-point with (default=3)");
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");
237 log(" dff_nan [-width <width>]\n");
238 log(" simplify_nan\n");
240 log(" techmap_nan\n");
242 void execute(vector
<string
> args
, Design
*design
) override
{
246 log_header(design
, "Executing SYNTH_NaN pass (synthesizing to tom7 logic).\n");
251 for (; argidx
< args
.size(); ++argidx
) {
252 if (args
[argidx
] == "-nosynth") {
256 if (args
[argidx
] == "-pre-flatten") {
257 synth_args
+= " -flatten";
260 if (args
[argidx
] == "-retime") {
261 abc_args
+= " -dff -D 1";
264 if (args
[argidx
] == "-top" and argidx
+ 1 < args
.size()) {
265 synth_args
+= " -top ";
266 synth_args
+= args
[++argidx
];
269 if (args
[argidx
] == "-width" and argidx
+ 1 < args
.size()) {
270 width_args
+= " -width ";
271 width_args
+= args
[++argidx
];
276 extra_args(args
, argidx
, design
, false);
279 Pass::call(design
, "synth" + synth_args
);
280 Pass::call(design
, "abc -g NAND" + abc_args
);
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");
292 PRIVATE_NAMESPACE_END