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
.in("\\FDCP", "\\FDCP_N", "\\FDDCP", "\\FTCP", "\\FTCP_N", "\\FTDCP",
64 "\\FDCPE", "\\FDCPE_N", "\\FDDCPE", "\\LDCP", "\\LDCP_N"))
66 if (cell
->hasPort("\\PRE"))
67 special_pterms_no_inv
[sigmap(cell
->getPort("\\PRE")[0])].insert(
68 tuple
<Cell
*, const char *>(cell
, "\\PRE"));
69 if (cell
->hasPort("\\CLR"))
70 special_pterms_no_inv
[sigmap(cell
->getPort("\\CLR")[0])].insert(
71 tuple
<Cell
*, const char *>(cell
, "\\CLR"));
72 if (cell
->hasPort("\\CE"))
73 special_pterms_no_inv
[sigmap(cell
->getPort("\\CE")[0])].insert(
74 tuple
<Cell
*, const char *>(cell
, "\\CE"));
76 if (cell
->hasPort("\\C"))
77 special_pterms_inv
[sigmap(cell
->getPort("\\C")[0])].insert(
78 tuple
<Cell
*, const char *>(cell
, "\\C"));
79 if (cell
->hasPort("\\G"))
80 special_pterms_inv
[sigmap(cell
->getPort("\\G")[0])].insert(
81 tuple
<Cell
*, const char *>(cell
, "\\G"));
86 for (auto cell
: module
->selected_cells())
88 if (cell
->type
== "$sop")
90 // Read the inputs/outputs/parameters of the $sop cell
91 auto sop_inputs
= sigmap(cell
->getPort("\\A"));
92 auto sop_output
= sigmap(cell
->getPort("\\Y"))[0];
93 auto sop_depth
= cell
->getParam("\\DEPTH").as_int();
94 auto sop_width
= cell
->getParam("\\WIDTH").as_int();
95 auto sop_table
= cell
->getParam("\\TABLE");
97 // Check for a $_NOT_ at the output
98 bool has_invert
= false;
99 if (not_cells
.count(sop_output
))
101 auto not_cell
= not_cells
.at(sop_output
);
104 sop_output
= std::get
<0>(not_cell
);
106 // remove the $_NOT_ cell because it gets folded into the xor
107 cells_to_remove
.insert(std::get
<1>(not_cell
));
110 // Check for special P-term usage
111 bool is_special_pterm
= false;
112 bool special_pterm_can_invert
= false;
113 if (special_pterms_no_inv
.count(sop_output
) || special_pterms_inv
.count(sop_output
))
115 is_special_pterm
= true;
116 if (!special_pterms_no_inv
[sop_output
].size())
117 special_pterm_can_invert
= true;
120 // Construct AND cells
121 pool
<SigBit
> intermed_wires
;
122 for (int i
= 0; i
< sop_depth
; i
++) {
123 // Wire for the output
124 auto and_out
= module
->addWire(NEW_ID
);
125 intermed_wires
.insert(and_out
);
127 // Signals for the inputs
128 pool
<SigBit
> and_in_true
;
129 pool
<SigBit
> and_in_comp
;
130 for (int j
= 0; j
< sop_width
; j
++)
132 if (sop_table
[2 * (i
* sop_width
+ j
) + 0])
134 and_in_comp
.insert(sop_inputs
[j
]);
136 if (sop_table
[2 * (i
* sop_width
+ j
) + 1])
138 and_in_true
.insert(sop_inputs
[j
]);
142 // Construct the cell
143 auto and_cell
= module
->addCell(NEW_ID
, "\\ANDTERM");
144 and_cell
->setParam("\\TRUE_INP", GetSize(and_in_true
));
145 and_cell
->setParam("\\COMP_INP", GetSize(and_in_comp
));
146 and_cell
->setPort("\\OUT", and_out
);
147 and_cell
->setPort("\\IN", and_in_true
);
148 and_cell
->setPort("\\IN_B", and_in_comp
);
153 // If there is only one term, don't construct an OR cell. Directly construct the XOR gate
154 auto xor_cell
= module
->addCell(NEW_ID
, "\\MACROCELL_XOR");
155 xor_cell
->setParam("\\INVERT_OUT", has_invert
);
156 xor_cell
->setPort("\\IN_PTC", *intermed_wires
.begin());
157 xor_cell
->setPort("\\OUT", sop_output
);
159 // Special P-term handling
160 if (is_special_pterm
)
162 if (!has_invert
|| special_pterm_can_invert
)
164 // Can connect the P-term directly to the special term sinks
165 for (auto x
: special_pterms_inv
[sop_output
])
166 std::get
<0>(x
)->setPort(std::get
<1>(x
), *intermed_wires
.begin());
167 for (auto x
: special_pterms_no_inv
[sop_output
])
168 std::get
<0>(x
)->setPort(std::get
<1>(x
), *intermed_wires
.begin());
173 if (special_pterm_can_invert
)
175 log_assert(special_pterms_no_inv
[sop_output
].size() == 0);
177 for (auto x
: special_pterms_inv
[sop_output
])
179 auto cell
= std::get
<0>(x
);
180 // Need to invert the polarity of the cell
181 if (cell
->type
== "\\FDCP") cell
->type
= "\\FDCP_N";
182 else if (cell
->type
== "\\FDCP_N") cell
->type
= "\\FDCP";
183 else if (cell
->type
== "\\FTCP") cell
->type
= "\\FTCP_N";
184 else if (cell
->type
== "\\FTCP_N") cell
->type
= "\\FTCP";
185 else if (cell
->type
== "\\FDCPE") cell
->type
= "\\FDCPE_N";
186 else if (cell
->type
== "\\FDCPE_N") cell
->type
= "\\FDCPE";
187 else if (cell
->type
== "\\LDCP") cell
->type
= "\\LDCP_N";
188 else if (cell
->type
== "\\LDCP_N") cell
->type
= "\\LDCP";
189 else log_assert(!"Internal error! Bad cell type!");
194 // Need to construct a feed-through term
195 auto feedthrough_out
= module
->addWire(NEW_ID
);
196 auto feedthrough_cell
= module
->addCell(NEW_ID
, "\\ANDTERM");
197 feedthrough_cell
->setParam("\\TRUE_INP", 1);
198 feedthrough_cell
->setParam("\\COMP_INP", 0);
199 feedthrough_cell
->setPort("\\OUT", feedthrough_out
);
200 feedthrough_cell
->setPort("\\IN", sop_output
);
201 feedthrough_cell
->setPort("\\IN_B", SigSpec());
203 for (auto x
: special_pterms_inv
[sop_output
])
204 std::get
<0>(x
)->setPort(std::get
<1>(x
), feedthrough_out
);
205 for (auto x
: special_pterms_no_inv
[sop_output
])
206 std::get
<0>(x
)->setPort(std::get
<1>(x
), feedthrough_out
);
213 // Wire from OR to XOR
214 auto or_to_xor_wire
= module
->addWire(NEW_ID
);
216 // Construct the OR cell
217 auto or_cell
= module
->addCell(NEW_ID
, "\\ORTERM");
218 or_cell
->setParam("\\WIDTH", sop_depth
);
219 or_cell
->setPort("\\IN", intermed_wires
);
220 or_cell
->setPort("\\OUT", or_to_xor_wire
);
222 // Construct the XOR cell
223 auto xor_cell
= module
->addCell(NEW_ID
, "\\MACROCELL_XOR");
224 xor_cell
->setParam("\\INVERT_OUT", has_invert
);
225 xor_cell
->setPort("\\IN_ORTERM", or_to_xor_wire
);
226 xor_cell
->setPort("\\OUT", sop_output
);
228 if (is_special_pterm
)
230 // Need to construct a feed-through term
231 auto feedthrough_out
= module
->addWire(NEW_ID
);
232 auto feedthrough_cell
= module
->addCell(NEW_ID
, "\\ANDTERM");
233 feedthrough_cell
->setParam("\\TRUE_INP", 1);
234 feedthrough_cell
->setParam("\\COMP_INP", 0);
235 feedthrough_cell
->setPort("\\OUT", feedthrough_out
);
236 feedthrough_cell
->setPort("\\IN", sop_output
);
237 feedthrough_cell
->setPort("\\IN_B", SigSpec());
239 for (auto x
: special_pterms_inv
[sop_output
])
240 std::get
<0>(x
)->setPort(std::get
<1>(x
), feedthrough_out
);
241 for (auto x
: special_pterms_no_inv
[sop_output
])
242 std::get
<0>(x
)->setPort(std::get
<1>(x
), feedthrough_out
);
246 // Finally, remove the $sop cell
247 cells_to_remove
.insert(cell
);
251 // In some cases we can get a FF feeding straight into an FF. This is not possible, so we need to insert
252 // some AND/XOR cells in the middle to make it actually work.
254 // Find all the FF outputs
255 pool
<SigBit
> sig_fed_by_ff
;
256 for (auto cell
: module
->selected_cells())
258 if (cell
->type
.in("\\FDCP", "\\FDCP_N", "\\FDDCP", "\\LDCP", "\\LDCP_N",
259 "\\FTCP", "\\FTCP_N", "\\FTDCP", "\\FDCPE", "\\FDCPE_N", "\\FDDCPE"))
261 auto output
= sigmap(cell
->getPort("\\Q")[0]);
262 sig_fed_by_ff
.insert(output
);
266 // Look at all the FF inputs
267 for (auto cell
: module
->selected_cells())
269 if (cell
->type
.in("\\FDCP", "\\FDCP_N", "\\FDDCP", "\\LDCP", "\\LDCP_N",
270 "\\FTCP", "\\FTCP_N", "\\FTDCP", "\\FDCPE", "\\FDCPE_N", "\\FDDCPE"))
273 if (cell
->type
.in("\\FTCP", "\\FTCP_N", "\\FTDCP"))
274 input
= sigmap(cell
->getPort("\\T")[0]);
276 input
= sigmap(cell
->getPort("\\D")[0]);
278 if (sig_fed_by_ff
[input
])
280 printf("Buffering input to \"%s\"\n", cell
->name
.c_str());
282 auto and_to_xor_wire
= module
->addWire(NEW_ID
);
283 auto xor_to_ff_wire
= module
->addWire(NEW_ID
);
285 auto and_cell
= module
->addCell(NEW_ID
, "\\ANDTERM");
286 and_cell
->setParam("\\TRUE_INP", 1);
287 and_cell
->setParam("\\COMP_INP", 0);
288 and_cell
->setPort("\\OUT", and_to_xor_wire
);
289 and_cell
->setPort("\\IN", input
);
290 and_cell
->setPort("\\IN_B", SigSpec());
292 auto xor_cell
= module
->addCell(NEW_ID
, "\\MACROCELL_XOR");
293 xor_cell
->setParam("\\INVERT_OUT", false);
294 xor_cell
->setPort("\\IN_PTC", and_to_xor_wire
);
295 xor_cell
->setPort("\\OUT", xor_to_ff_wire
);
297 if (cell
->type
.in("\\FTCP", "\\FTCP_N", "\\FTDCP"))
298 cell
->setPort("\\T", xor_to_ff_wire
);
300 cell
->setPort("\\D", xor_to_ff_wire
);
305 // Actually do the removal now that we aren't iterating
306 for (auto cell
: cells_to_remove
)
308 module
->remove(cell
);
312 } Coolrunner2SopPass
;
314 PRIVATE_NAMESPACE_END