Using simplemap mappers from techmap
[yosys.git] / passes / techmap / simplemap.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/register.h"
21 #include "kernel/sigtools.h"
22 #include "kernel/log.h"
23 #include <stdlib.h>
24 #include <assert.h>
25 #include <stdio.h>
26 #include <string.h>
27
28 extern void simplemap_get_mappers(std::map<std::string, void(*)(RTLIL::Module*, RTLIL::Cell*)> &mappers);
29
30 static void simplemap_not(RTLIL::Module *module, RTLIL::Cell *cell)
31 {
32 int width = cell->parameters.at("\\Y_WIDTH").as_int();
33
34 RTLIL::SigSpec sig_a = cell->connections.at("\\A");
35 sig_a.extend(width, cell->parameters.at("\\A_SIGNED").as_bool());
36 sig_a.expand();
37
38 RTLIL::SigSpec sig_y = cell->connections.at("\\Y");
39 sig_y.expand();
40
41 for (int i = 0; i < width; i++) {
42 RTLIL::Cell *gate = new RTLIL::Cell;
43 gate->name = NEW_ID;
44 gate->type = "$_INV_";
45 gate->connections["\\A"] = sig_a.chunks.at(i);
46 gate->connections["\\Y"] = sig_y.chunks.at(i);
47 module->add(gate);
48 }
49 }
50
51 static void simplemap_pos(RTLIL::Module *module, RTLIL::Cell *cell)
52 {
53 int width = cell->parameters.at("\\Y_WIDTH").as_int();
54
55 RTLIL::SigSpec sig_a = cell->connections.at("\\A");
56 sig_a.extend(width, cell->parameters.at("\\A_SIGNED").as_bool());
57
58 RTLIL::SigSpec sig_y = cell->connections.at("\\Y");
59
60 module->connections.push_back(RTLIL::SigSig(sig_y, sig_a));
61 }
62
63 static void simplemap_bitop(RTLIL::Module *module, RTLIL::Cell *cell)
64 {
65 int width = cell->parameters.at("\\Y_WIDTH").as_int();
66
67 RTLIL::SigSpec sig_a = cell->connections.at("\\A");
68 sig_a.extend(width, cell->parameters.at("\\A_SIGNED").as_bool());
69 sig_a.expand();
70
71 RTLIL::SigSpec sig_b = cell->connections.at("\\B");
72 sig_b.extend(width, cell->parameters.at("\\B_SIGNED").as_bool());
73 sig_b.expand();
74
75 RTLIL::SigSpec sig_y = cell->connections.at("\\Y");
76 sig_y.expand();
77
78 if (cell->type == "$xnor")
79 {
80 RTLIL::SigSpec sig_t = module->new_wire(width, NEW_ID);
81 sig_t.expand();
82
83 for (int i = 0; i < width; i++) {
84 RTLIL::Cell *gate = new RTLIL::Cell;
85 gate->name = NEW_ID;
86 gate->type = "$_INV_";
87 gate->connections["\\A"] = sig_t.chunks.at(i);
88 gate->connections["\\Y"] = sig_y.chunks.at(i);
89 module->add(gate);
90 }
91
92 sig_y = sig_t;
93 }
94
95 std::string gate_type;
96 if (cell->type == "$and") gate_type = "$_AND_";
97 if (cell->type == "$or") gate_type = "$_OR_";
98 if (cell->type == "$xor") gate_type = "$_XOR_";
99 if (cell->type == "$xnor") gate_type = "$_XOR_";
100 log_assert(!gate_type.empty());
101
102 for (int i = 0; i < width; i++) {
103 RTLIL::Cell *gate = new RTLIL::Cell;
104 gate->name = NEW_ID;
105 gate->type = gate_type;
106 gate->connections["\\A"] = sig_a.chunks.at(i);
107 gate->connections["\\B"] = sig_b.chunks.at(i);
108 gate->connections["\\Y"] = sig_y.chunks.at(i);
109 module->add(gate);
110 }
111 }
112
113 static void simplemap_reduce(RTLIL::Module *module, RTLIL::Cell *cell)
114 {
115 RTLIL::SigSpec sig_a = cell->connections.at("\\A");
116 sig_a.expand();
117
118 RTLIL::SigSpec sig_y = cell->connections.at("\\Y");
119
120 if (sig_y.width == 0)
121 return;
122
123 if (sig_a.width == 0) {
124 if (cell->type == "$reduce_and") module->connections.push_back(RTLIL::SigSig(sig_y, RTLIL::SigSpec(1, sig_y.width)));
125 if (cell->type == "$reduce_or") module->connections.push_back(RTLIL::SigSig(sig_y, RTLIL::SigSpec(0, sig_y.width)));
126 if (cell->type == "$reduce_xor") module->connections.push_back(RTLIL::SigSig(sig_y, RTLIL::SigSpec(0, sig_y.width)));
127 if (cell->type == "$reduce_xnor") module->connections.push_back(RTLIL::SigSig(sig_y, RTLIL::SigSpec(1, sig_y.width)));
128 if (cell->type == "$reduce_bool") module->connections.push_back(RTLIL::SigSig(sig_y, RTLIL::SigSpec(0, sig_y.width)));
129 return;
130 }
131
132 if (sig_y.width > 1) {
133 module->connections.push_back(RTLIL::SigSig(sig_y.extract(1, sig_y.width-1), RTLIL::SigSpec(0, sig_y.width-1)));
134 sig_y = sig_y.extract(0, 1);
135 }
136
137 std::string gate_type;
138 if (cell->type == "$reduce_and") gate_type = "$_AND_";
139 if (cell->type == "$reduce_or") gate_type = "$_OR_";
140 if (cell->type == "$reduce_xor") gate_type = "$_XOR_";
141 if (cell->type == "$reduce_xnor") gate_type = "$_XOR_";
142 if (cell->type == "$reduce_bool") gate_type = "$_OR_";
143 log_assert(!gate_type.empty());
144
145 RTLIL::SigSpec *last_output = NULL;
146
147 while (sig_a.width > 1)
148 {
149 RTLIL::SigSpec sig_t = module->new_wire(sig_a.width / 2, NEW_ID);
150 sig_t.expand();
151
152 for (int i = 0; i < sig_a.width; i += 2)
153 {
154 if (i+1 == sig_a.width) {
155 sig_t.append(sig_a.chunks.at(i));
156 continue;
157 }
158
159 RTLIL::Cell *gate = new RTLIL::Cell;
160 gate->name = NEW_ID;
161 gate->type = gate_type;
162 gate->connections["\\A"] = sig_a.chunks.at(i);
163 gate->connections["\\B"] = sig_a.chunks.at(i+1);
164 gate->connections["\\Y"] = sig_t.chunks.at(i/2);
165 last_output = &gate->connections["\\Y"];
166 module->add(gate);
167 }
168
169 sig_a = sig_t;
170 }
171
172 if (cell->type == "$reduce_xnor") {
173 RTLIL::SigSpec sig_t = module->new_wire(1, NEW_ID);
174 RTLIL::Cell *gate = new RTLIL::Cell;
175 gate->name = NEW_ID;
176 gate->type = "$_INV_";
177 gate->connections["\\A"] = sig_a;
178 gate->connections["\\Y"] = sig_t;
179 last_output = &gate->connections["\\Y"];
180 module->add(gate);
181 sig_a = sig_t;
182 }
183
184 if (last_output == NULL) {
185 module->connections.push_back(RTLIL::SigSig(sig_y, sig_a));
186 } else {
187 *last_output = sig_y;
188 }
189 }
190
191 static void logic_reduce(RTLIL::Module *module, RTLIL::SigSpec &sig)
192 {
193 sig.expand();
194
195 while (sig.width > 1)
196 {
197 RTLIL::SigSpec sig_t = module->new_wire(sig.width / 2, NEW_ID);
198 sig_t.expand();
199
200 for (int i = 0; i < sig.width; i += 2)
201 {
202 if (i+1 == sig.width) {
203 sig_t.append(sig.chunks.at(i));
204 continue;
205 }
206
207 RTLIL::Cell *gate = new RTLIL::Cell;
208 gate->name = NEW_ID;
209 gate->type = "$_OR_";
210 gate->connections["\\A"] = sig.chunks.at(i);
211 gate->connections["\\B"] = sig.chunks.at(i+1);
212 gate->connections["\\Y"] = sig_t.chunks.at(i/2);
213 module->add(gate);
214 }
215
216 sig = sig_t;
217 }
218
219 if (sig.width == 0)
220 sig = RTLIL::SigSpec(0, 1);
221 }
222
223 static void simplemap_lognot(RTLIL::Module *module, RTLIL::Cell *cell)
224 {
225 RTLIL::SigSpec sig_a = cell->connections.at("\\A");
226 logic_reduce(module, sig_a);
227
228 RTLIL::SigSpec sig_y = cell->connections.at("\\Y");
229
230 if (sig_y.width == 0)
231 return;
232
233 if (sig_y.width > 1) {
234 module->connections.push_back(RTLIL::SigSig(sig_y.extract(1, sig_y.width-1), RTLIL::SigSpec(0, sig_y.width-1)));
235 sig_y = sig_y.extract(0, 1);
236 }
237
238 RTLIL::Cell *gate = new RTLIL::Cell;
239 gate->name = NEW_ID;
240 gate->type = "$_INV_";
241 gate->connections["\\A"] = sig_a;
242 gate->connections["\\Y"] = sig_y;
243 module->add(gate);
244 }
245
246 static void simplemap_logbin(RTLIL::Module *module, RTLIL::Cell *cell)
247 {
248 RTLIL::SigSpec sig_a = cell->connections.at("\\A");
249 logic_reduce(module, sig_a);
250
251 RTLIL::SigSpec sig_b = cell->connections.at("\\B");
252 logic_reduce(module, sig_b);
253
254 RTLIL::SigSpec sig_y = cell->connections.at("\\Y");
255
256 if (sig_y.width == 0)
257 return;
258
259 if (sig_y.width > 1) {
260 module->connections.push_back(RTLIL::SigSig(sig_y.extract(1, sig_y.width-1), RTLIL::SigSpec(0, sig_y.width-1)));
261 sig_y = sig_y.extract(0, 1);
262 }
263
264 std::string gate_type;
265 if (cell->type == "$logic_and") gate_type = "$_AND_";
266 if (cell->type == "$logic_or") gate_type = "$_OR_";
267 log_assert(!gate_type.empty());
268
269 RTLIL::Cell *gate = new RTLIL::Cell;
270 gate->name = NEW_ID;
271 gate->type = gate_type;
272 gate->connections["\\A"] = sig_a;
273 gate->connections["\\B"] = sig_b;
274 gate->connections["\\Y"] = sig_y;
275 module->add(gate);
276 }
277
278 static void simplemap_mux(RTLIL::Module *module, RTLIL::Cell *cell)
279 {
280 int width = cell->parameters.at("\\WIDTH").as_int();
281
282 RTLIL::SigSpec sig_a = cell->connections.at("\\A");
283 sig_a.expand();
284
285 RTLIL::SigSpec sig_b = cell->connections.at("\\B");
286 sig_b.expand();
287
288 RTLIL::SigSpec sig_y = cell->connections.at("\\Y");
289 sig_y.expand();
290
291 for (int i = 0; i < width; i++) {
292 RTLIL::Cell *gate = new RTLIL::Cell;
293 gate->name = NEW_ID;
294 gate->type = "$_MUX_";
295 gate->connections["\\A"] = sig_a.chunks.at(i);
296 gate->connections["\\B"] = sig_b.chunks.at(i);
297 gate->connections["\\S"] = cell->connections.at("\\S");
298 gate->connections["\\Y"] = sig_y.chunks.at(i);
299 module->add(gate);
300 }
301 }
302
303 static void simplemap_sr(RTLIL::Module *module, RTLIL::Cell *cell)
304 {
305 int width = cell->parameters.at("\\WIDTH").as_int();
306 char set_pol = cell->parameters.at("\\SET_POLARITY").as_bool() ? 'P' : 'N';
307 char clr_pol = cell->parameters.at("\\CLR_POLARITY").as_bool() ? 'P' : 'N';
308
309 RTLIL::SigSpec sig_s = cell->connections.at("\\SET");
310 sig_s.expand();
311
312 RTLIL::SigSpec sig_r = cell->connections.at("\\CLR");
313 sig_r.expand();
314
315 RTLIL::SigSpec sig_q = cell->connections.at("\\Q");
316 sig_q.expand();
317
318 std::string gate_type = stringf("$_SR_%c%c_", set_pol, clr_pol);
319
320 for (int i = 0; i < width; i++) {
321 RTLIL::Cell *gate = new RTLIL::Cell;
322 gate->name = NEW_ID;
323 gate->type = gate_type;
324 gate->connections["\\S"] = sig_s.chunks.at(i);
325 gate->connections["\\R"] = sig_r.chunks.at(i);
326 gate->connections["\\Q"] = sig_q.chunks.at(i);
327 module->add(gate);
328 }
329 }
330
331 static void simplemap_dff(RTLIL::Module *module, RTLIL::Cell *cell)
332 {
333 int width = cell->parameters.at("\\WIDTH").as_int();
334 char clk_pol = cell->parameters.at("\\CLK_POLARITY").as_bool() ? 'P' : 'N';
335
336 RTLIL::SigSpec sig_clk = cell->connections.at("\\CLK");
337
338 RTLIL::SigSpec sig_d = cell->connections.at("\\D");
339 sig_d.expand();
340
341 RTLIL::SigSpec sig_q = cell->connections.at("\\Q");
342 sig_q.expand();
343
344 std::string gate_type = stringf("$_DFF_%c_", clk_pol);
345
346 for (int i = 0; i < width; i++) {
347 RTLIL::Cell *gate = new RTLIL::Cell;
348 gate->name = NEW_ID;
349 gate->type = gate_type;
350 gate->connections["\\C"] = sig_clk;
351 gate->connections["\\D"] = sig_d.chunks.at(i);
352 gate->connections["\\Q"] = sig_q.chunks.at(i);
353 module->add(gate);
354 }
355 }
356
357 static void simplemap_dffsr(RTLIL::Module *module, RTLIL::Cell *cell)
358 {
359 int width = cell->parameters.at("\\WIDTH").as_int();
360 char clk_pol = cell->parameters.at("\\CLK_POLARITY").as_bool() ? 'P' : 'N';
361 char set_pol = cell->parameters.at("\\SET_POLARITY").as_bool() ? 'P' : 'N';
362 char clr_pol = cell->parameters.at("\\CLR_POLARITY").as_bool() ? 'P' : 'N';
363
364 RTLIL::SigSpec sig_clk = cell->connections.at("\\CLK");
365
366 RTLIL::SigSpec sig_s = cell->connections.at("\\SET");
367 sig_s.expand();
368
369 RTLIL::SigSpec sig_r = cell->connections.at("\\CLR");
370 sig_r.expand();
371
372 RTLIL::SigSpec sig_d = cell->connections.at("\\D");
373 sig_d.expand();
374
375 RTLIL::SigSpec sig_q = cell->connections.at("\\Q");
376 sig_q.expand();
377
378 std::string gate_type = stringf("$_DFFSR_%c%c%c_", clk_pol, set_pol, clr_pol);
379
380 for (int i = 0; i < width; i++) {
381 RTLIL::Cell *gate = new RTLIL::Cell;
382 gate->name = NEW_ID;
383 gate->type = gate_type;
384 gate->connections["\\C"] = sig_clk;
385 gate->connections["\\S"] = sig_s.chunks.at(i);
386 gate->connections["\\R"] = sig_r.chunks.at(i);
387 gate->connections["\\D"] = sig_d.chunks.at(i);
388 gate->connections["\\Q"] = sig_q.chunks.at(i);
389 module->add(gate);
390 }
391 }
392
393 static void simplemap_adff(RTLIL::Module *module, RTLIL::Cell *cell)
394 {
395 int width = cell->parameters.at("\\WIDTH").as_int();
396 char clk_pol = cell->parameters.at("\\CLK_POLARITY").as_bool() ? 'P' : 'N';
397 char rst_pol = cell->parameters.at("\\ARST_POLARITY").as_bool() ? 'P' : 'N';
398
399 std::vector<RTLIL::State> rst_val = cell->parameters.at("\\ARST_VALUE").bits;
400 while (int(rst_val.size()) < width)
401 rst_val.push_back(RTLIL::State::S0);
402
403 RTLIL::SigSpec sig_clk = cell->connections.at("\\CLK");
404 RTLIL::SigSpec sig_rst = cell->connections.at("\\ARST");
405
406 RTLIL::SigSpec sig_d = cell->connections.at("\\D");
407 sig_d.expand();
408
409 RTLIL::SigSpec sig_q = cell->connections.at("\\Q");
410 sig_q.expand();
411
412 std::string gate_type_0 = stringf("$_DFF_%c%c0_", clk_pol, rst_pol);
413 std::string gate_type_1 = stringf("$_DFF_%c%c1_", clk_pol, rst_pol);
414
415 for (int i = 0; i < width; i++) {
416 RTLIL::Cell *gate = new RTLIL::Cell;
417 gate->name = NEW_ID;
418 gate->type = rst_val.at(i) == RTLIL::State::S1 ? gate_type_1 : gate_type_0;
419 gate->connections["\\C"] = sig_clk;
420 gate->connections["\\R"] = sig_rst;
421 gate->connections["\\D"] = sig_d.chunks.at(i);
422 gate->connections["\\Q"] = sig_q.chunks.at(i);
423 module->add(gate);
424 }
425 }
426
427 static void simplemap_dlatch(RTLIL::Module *module, RTLIL::Cell *cell)
428 {
429 int width = cell->parameters.at("\\WIDTH").as_int();
430 char en_pol = cell->parameters.at("\\EN_POLARITY").as_bool() ? 'P' : 'N';
431
432 RTLIL::SigSpec sig_en = cell->connections.at("\\EN");
433
434 RTLIL::SigSpec sig_d = cell->connections.at("\\D");
435 sig_d.expand();
436
437 RTLIL::SigSpec sig_q = cell->connections.at("\\Q");
438 sig_q.expand();
439
440 std::string gate_type = stringf("$_DLATCH_%c_", en_pol);
441
442 for (int i = 0; i < width; i++) {
443 RTLIL::Cell *gate = new RTLIL::Cell;
444 gate->name = NEW_ID;
445 gate->type = gate_type;
446 gate->connections["\\E"] = sig_en;
447 gate->connections["\\D"] = sig_d.chunks.at(i);
448 gate->connections["\\Q"] = sig_q.chunks.at(i);
449 module->add(gate);
450 }
451 }
452
453 void simplemap_get_mappers(std::map<std::string, void(*)(RTLIL::Module*, RTLIL::Cell*)> &mappers)
454 {
455 mappers["$not"] = simplemap_not;
456 mappers["$pos"] = simplemap_pos;
457 mappers["$and"] = simplemap_bitop;
458 mappers["$or"] = simplemap_bitop;
459 mappers["$xor"] = simplemap_bitop;
460 mappers["$xnor"] = simplemap_bitop;
461 mappers["$reduce_and"] = simplemap_reduce;
462 mappers["$reduce_or"] = simplemap_reduce;
463 mappers["$reduce_xor"] = simplemap_reduce;
464 mappers["$reduce_xnor"] = simplemap_reduce;
465 mappers["$reduce_bool"] = simplemap_reduce;
466 mappers["$logic_not"] = simplemap_lognot;
467 mappers["$logic_and"] = simplemap_logbin;
468 mappers["$logic_or"] = simplemap_logbin;
469 mappers["$mux"] = simplemap_mux;
470 mappers["$sr"] = simplemap_sr;
471 mappers["$dff"] = simplemap_dff;
472 mappers["$dffsr"] = simplemap_dffsr;
473 mappers["$adff"] = simplemap_adff;
474 mappers["$dlatch"] = simplemap_dlatch;
475 }
476
477 struct SimplemapPass : public Pass {
478 SimplemapPass() : Pass("simplemap", "mapping simple coarse-grain cells") { }
479 virtual void help()
480 {
481 // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
482 log("\n");
483 log(" simplemap [selection]\n");
484 log("\n");
485 log("This pass maps a small selection of simple coarse-grain cells to yosys gate\n");
486 log("primitives. The following internal cell types are mapped by this pass:\n");
487 log("\n");
488 log(" $not, $pos, $and, $or, $xor, $xnor\n");
489 log(" $reduce_and, $reduce_or, $reduce_xor, $reduce_xnor, $reduce_bool\n");
490 log(" $logic_not, $logic_and, $logic_or, $mux\n");
491 log(" $sr, $dff, $dffsr, $adff, $dlatch\n");
492 log("\n");
493 }
494 virtual void execute(std::vector<std::string> args, RTLIL::Design *design)
495 {
496 log_header("Executing SIMPLEMAP pass (map simple cells to gate primitives).\n");
497 extra_args(args, 1, design);
498
499 std::map<std::string, void(*)(RTLIL::Module*, RTLIL::Cell*)> mappers;
500 simplemap_get_mappers(mappers);
501
502 for (auto &mod_it : design->modules) {
503 if (!design->selected(mod_it.second))
504 continue;
505 std::vector<RTLIL::Cell*> delete_cells;
506 for (auto &cell_it : mod_it.second->cells) {
507 if (mappers.count(cell_it.second->type) == 0)
508 continue;
509 if (!design->selected(mod_it.second, cell_it.second))
510 continue;
511 log("Mapping %s.%s (%s).\n", RTLIL::id2cstr(mod_it.first), RTLIL::id2cstr(cell_it.first), RTLIL::id2cstr(cell_it.second->type));
512 mappers.at(cell_it.second->type)(mod_it.second, cell_it.second);
513 delete_cells.push_back(cell_it.second);
514 }
515 for (auto &it : delete_cells) {
516 mod_it.second->cells.erase(it->name);
517 delete it;
518 }
519 }
520 }
521 } SimplemapPass;
522