2 * yosys -- Yosys Open SYnthesis Suite
4 * Copyright (C) 2017 Robert Ou <rqou@robertou.com>
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.
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.
20 #include "kernel/yosys.h"
21 #include "kernel/sigtools.h"
24 PRIVATE_NAMESPACE_BEGIN
26 struct Coolrunner2SopPass
: public Pass
{
27 Coolrunner2SopPass() : Pass("coolrunner2_sop", "break $sop cells into ANDTERM/ORTERM cells") { }
28 void help() YS_OVERRIDE
31 log(" coolrunner2_sop [options] [selection]\n");
33 log("Break $sop cells into ANDTERM/ORTERM cells.\n");
36 void execute(std::vector
<std::string
> args
, RTLIL::Design
*design
) YS_OVERRIDE
38 log_header(design
, "Executing COOLRUNNER2_SOP pass (break $sop cells into ANDTERM/ORTERM cells).\n");
39 extra_args(args
, 1, design
);
41 for (auto module
: design
->selected_modules())
43 pool
<Cell
*> cells_to_remove
;
44 SigMap
sigmap(module
);
46 // Find all the $_NOT_ cells
47 dict
<SigBit
, tuple
<SigBit
, Cell
*>> not_cells
;
48 for (auto cell
: module
->selected_cells())
50 if (cell
->type
== "$_NOT_")
52 auto not_input
= sigmap(cell
->getPort("\\A")[0]);
53 auto not_output
= sigmap(cell
->getPort("\\Y")[0]);
54 not_cells
[not_input
] = tuple
<SigBit
, Cell
*>(not_output
, cell
);
58 // Find wires that need to become special product terms
59 dict
<SigBit
, pool
<tuple
<Cell
*, std::string
>>> special_pterms_no_inv
;
60 dict
<SigBit
, pool
<tuple
<Cell
*, std::string
>>> special_pterms_inv
;
61 for (auto cell
: module
->selected_cells())
63 if (cell
->type
== "\\FDCP" || cell
->type
== "\\FDCP_N" || cell
->type
== "\\FDDCP" ||
64 cell
->type
== "\\FTCP" || cell
->type
== "\\FTCP_N" || cell
->type
== "\\FTDCP" ||
65 cell
->type
== "\\FDCPE" || cell
->type
== "\\FDCPE_N" || cell
->type
== "\\FDDCPE" ||
66 cell
->type
== "\\LDCP" || cell
->type
== "\\LDCP_N")
68 if (cell
->hasPort("\\PRE"))
69 special_pterms_no_inv
[sigmap(cell
->getPort("\\PRE")[0])].insert(
70 tuple
<Cell
*, const char *>(cell
, "\\PRE"));
71 if (cell
->hasPort("\\CLR"))
72 special_pterms_no_inv
[sigmap(cell
->getPort("\\CLR")[0])].insert(
73 tuple
<Cell
*, const char *>(cell
, "\\CLR"));
74 if (cell
->hasPort("\\CE"))
75 special_pterms_no_inv
[sigmap(cell
->getPort("\\CE")[0])].insert(
76 tuple
<Cell
*, const char *>(cell
, "\\CE"));
78 if (cell
->hasPort("\\C"))
79 special_pterms_inv
[sigmap(cell
->getPort("\\C")[0])].insert(
80 tuple
<Cell
*, const char *>(cell
, "\\C"));
81 if (cell
->hasPort("\\G"))
82 special_pterms_inv
[sigmap(cell
->getPort("\\G")[0])].insert(
83 tuple
<Cell
*, const char *>(cell
, "\\G"));
88 for (auto cell
: module
->selected_cells())
90 if (cell
->type
== "$sop")
92 // Read the inputs/outputs/parameters of the $sop cell
93 auto sop_inputs
= sigmap(cell
->getPort("\\A"));
94 auto sop_output
= sigmap(cell
->getPort("\\Y"))[0];
95 auto sop_depth
= cell
->getParam("\\DEPTH").as_int();
96 auto sop_width
= cell
->getParam("\\WIDTH").as_int();
97 auto sop_table
= cell
->getParam("\\TABLE");
99 // Check for a $_NOT_ at the output
100 bool has_invert
= false;
101 if (not_cells
.count(sop_output
))
103 auto not_cell
= not_cells
.at(sop_output
);
106 sop_output
= std::get
<0>(not_cell
);
108 // remove the $_NOT_ cell because it gets folded into the xor
109 cells_to_remove
.insert(std::get
<1>(not_cell
));
112 // Check for special P-term usage
113 bool is_special_pterm
= false;
114 bool special_pterm_can_invert
= false;
115 if (special_pterms_no_inv
.count(sop_output
) || special_pterms_inv
.count(sop_output
))
117 is_special_pterm
= true;
118 if (!special_pterms_no_inv
[sop_output
].size())
119 special_pterm_can_invert
= true;
122 // Construct AND cells
123 pool
<SigBit
> intermed_wires
;
124 for (int i
= 0; i
< sop_depth
; i
++) {
125 // Wire for the output
126 auto and_out
= module
->addWire(NEW_ID
);
127 intermed_wires
.insert(and_out
);
129 // Signals for the inputs
130 pool
<SigBit
> and_in_true
;
131 pool
<SigBit
> and_in_comp
;
132 for (int j
= 0; j
< sop_width
; j
++)
134 if (sop_table
[2 * (i
* sop_width
+ j
) + 0])
136 and_in_comp
.insert(sop_inputs
[j
]);
138 if (sop_table
[2 * (i
* sop_width
+ j
) + 1])
140 and_in_true
.insert(sop_inputs
[j
]);
144 // Construct the cell
145 auto and_cell
= module
->addCell(NEW_ID
, "\\ANDTERM");
146 and_cell
->setParam("\\TRUE_INP", GetSize(and_in_true
));
147 and_cell
->setParam("\\COMP_INP", GetSize(and_in_comp
));
148 and_cell
->setPort("\\OUT", and_out
);
149 and_cell
->setPort("\\IN", and_in_true
);
150 and_cell
->setPort("\\IN_B", and_in_comp
);
155 // If there is only one term, don't construct an OR cell. Directly construct the XOR gate
156 auto xor_cell
= module
->addCell(NEW_ID
, "\\MACROCELL_XOR");
157 xor_cell
->setParam("\\INVERT_OUT", has_invert
);
158 xor_cell
->setPort("\\IN_PTC", *intermed_wires
.begin());
159 xor_cell
->setPort("\\OUT", sop_output
);
161 // Special P-term handling
162 if (is_special_pterm
)
164 if (!has_invert
|| special_pterm_can_invert
)
166 // Can connect the P-term directly to the special term sinks
167 for (auto x
: special_pterms_inv
[sop_output
])
168 std::get
<0>(x
)->setPort(std::get
<1>(x
), *intermed_wires
.begin());
169 for (auto x
: special_pterms_no_inv
[sop_output
])
170 std::get
<0>(x
)->setPort(std::get
<1>(x
), *intermed_wires
.begin());
175 if (special_pterm_can_invert
)
177 log_assert(special_pterms_no_inv
[sop_output
].size() == 0);
179 for (auto x
: special_pterms_inv
[sop_output
])
181 auto cell
= std::get
<0>(x
);
182 // Need to invert the polarity of the cell
183 if (cell
->type
== "\\FDCP") cell
->type
= "\\FDCP_N";
184 else if (cell
->type
== "\\FDCP_N") cell
->type
= "\\FDCP";
185 else if (cell
->type
== "\\FTCP") cell
->type
= "\\FTCP_N";
186 else if (cell
->type
== "\\FTCP_N") cell
->type
= "\\FTCP";
187 else if (cell
->type
== "\\FDCPE") cell
->type
= "\\FDCPE_N";
188 else if (cell
->type
== "\\FDCPE_N") cell
->type
= "\\FDCPE";
189 else if (cell
->type
== "\\LDCP") cell
->type
= "\\LDCP_N";
190 else if (cell
->type
== "\\LDCP_N") cell
->type
= "\\LDCP";
191 else log_assert(!"Internal error! Bad cell type!");
196 // Need to construct a feed-through term
197 auto feedthrough_out
= module
->addWire(NEW_ID
);
198 auto feedthrough_cell
= module
->addCell(NEW_ID
, "\\ANDTERM");
199 feedthrough_cell
->setParam("\\TRUE_INP", 1);
200 feedthrough_cell
->setParam("\\COMP_INP", 0);
201 feedthrough_cell
->setPort("\\OUT", feedthrough_out
);
202 feedthrough_cell
->setPort("\\IN", sop_output
);
203 feedthrough_cell
->setPort("\\IN_B", SigSpec());
205 for (auto x
: special_pterms_inv
[sop_output
])
206 std::get
<0>(x
)->setPort(std::get
<1>(x
), feedthrough_out
);
207 for (auto x
: special_pterms_no_inv
[sop_output
])
208 std::get
<0>(x
)->setPort(std::get
<1>(x
), feedthrough_out
);
215 // Wire from OR to XOR
216 auto or_to_xor_wire
= module
->addWire(NEW_ID
);
218 // Construct the OR cell
219 auto or_cell
= module
->addCell(NEW_ID
, "\\ORTERM");
220 or_cell
->setParam("\\WIDTH", sop_depth
);
221 or_cell
->setPort("\\IN", intermed_wires
);
222 or_cell
->setPort("\\OUT", or_to_xor_wire
);
224 // Construct the XOR cell
225 auto xor_cell
= module
->addCell(NEW_ID
, "\\MACROCELL_XOR");
226 xor_cell
->setParam("\\INVERT_OUT", has_invert
);
227 xor_cell
->setPort("\\IN_ORTERM", or_to_xor_wire
);
228 xor_cell
->setPort("\\OUT", sop_output
);
230 if (is_special_pterm
)
232 // Need to construct a feed-through term
233 auto feedthrough_out
= module
->addWire(NEW_ID
);
234 auto feedthrough_cell
= module
->addCell(NEW_ID
, "\\ANDTERM");
235 feedthrough_cell
->setParam("\\TRUE_INP", 1);
236 feedthrough_cell
->setParam("\\COMP_INP", 0);
237 feedthrough_cell
->setPort("\\OUT", feedthrough_out
);
238 feedthrough_cell
->setPort("\\IN", sop_output
);
239 feedthrough_cell
->setPort("\\IN_B", SigSpec());
241 for (auto x
: special_pterms_inv
[sop_output
])
242 std::get
<0>(x
)->setPort(std::get
<1>(x
), feedthrough_out
);
243 for (auto x
: special_pterms_no_inv
[sop_output
])
244 std::get
<0>(x
)->setPort(std::get
<1>(x
), feedthrough_out
);
248 // Finally, remove the $sop cell
249 cells_to_remove
.insert(cell
);
253 // In some cases we can get a FF feeding straight into an FF. This is not possible, so we need to insert
254 // some AND/XOR cells in the middle to make it actually work.
256 // Find all the FF outputs
257 pool
<SigBit
> sig_fed_by_ff
;
258 for (auto cell
: module
->selected_cells())
260 if (cell
->type
== "\\FDCP" || cell
->type
== "\\FDCP_N" || cell
->type
== "\\FDDCP" ||
261 cell
->type
== "\\LDCP" || cell
->type
== "\\LDCP_N" ||
262 cell
->type
== "\\FTCP" || cell
->type
== "\\FTCP_N" || cell
->type
== "\\FTDCP" ||
263 cell
->type
== "\\FDCPE" || cell
->type
== "\\FDCPE_N" || cell
->type
== "\\FDDCPE")
265 auto output
= sigmap(cell
->getPort("\\Q")[0]);
266 sig_fed_by_ff
.insert(output
);
270 // Look at all the FF inputs
271 for (auto cell
: module
->selected_cells())
273 if (cell
->type
== "\\FDCP" || cell
->type
== "\\FDCP_N" || cell
->type
== "\\FDDCP" ||
274 cell
->type
== "\\LDCP" || cell
->type
== "\\LDCP_N" ||
275 cell
->type
== "\\FTCP" || cell
->type
== "\\FTCP_N" || cell
->type
== "\\FTDCP" ||
276 cell
->type
== "\\FDCPE" || cell
->type
== "\\FDCPE_N" || cell
->type
== "\\FDDCPE")
279 if (cell
->type
== "\\FTCP" || cell
->type
== "\\FTCP_N" || cell
->type
== "\\FTDCP")
280 input
= sigmap(cell
->getPort("\\T")[0]);
282 input
= sigmap(cell
->getPort("\\D")[0]);
284 if (sig_fed_by_ff
[input
])
286 printf("Buffering input to \"%s\"\n", cell
->name
.c_str());
288 auto and_to_xor_wire
= module
->addWire(NEW_ID
);
289 auto xor_to_ff_wire
= module
->addWire(NEW_ID
);
291 auto and_cell
= module
->addCell(NEW_ID
, "\\ANDTERM");
292 and_cell
->setParam("\\TRUE_INP", 1);
293 and_cell
->setParam("\\COMP_INP", 0);
294 and_cell
->setPort("\\OUT", and_to_xor_wire
);
295 and_cell
->setPort("\\IN", input
);
296 and_cell
->setPort("\\IN_B", SigSpec());
298 auto xor_cell
= module
->addCell(NEW_ID
, "\\MACROCELL_XOR");
299 xor_cell
->setParam("\\INVERT_OUT", false);
300 xor_cell
->setPort("\\IN_PTC", and_to_xor_wire
);
301 xor_cell
->setPort("\\OUT", xor_to_ff_wire
);
303 if (cell
->type
== "\\FTCP" || cell
->type
== "\\FTCP_N" || cell
->type
== "\\FTDCP")
304 cell
->setPort("\\T", xor_to_ff_wire
);
306 cell
->setPort("\\D", xor_to_ff_wire
);
311 // Actually do the removal now that we aren't iterating
312 for (auto cell
: cells_to_remove
)
314 module
->remove(cell
);
318 } Coolrunner2SopPass
;
320 PRIVATE_NAMESPACE_END