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
== ID($_NOT_
))
52 auto not_input
= sigmap(cell
->getPort(ID::A
)[0]);
53 auto not_output
= sigmap(cell
->getPort(ID::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
*, IdString
>>> special_pterms_no_inv
;
60 dict
<SigBit
, pool
<tuple
<Cell
*, IdString
>>> special_pterms_inv
;
61 for (auto cell
: module
->selected_cells())
63 if (cell
->type
.in(ID(FDCP
), ID(FDCP_N
), ID(FDDCP
), ID(FTCP
), ID(FTCP_N
), ID(FTDCP
),
64 ID(FDCPE
), ID(FDCPE_N
), ID(FDDCPE
), ID(LDCP
), ID(LDCP_N
)))
66 if (cell
->hasPort(ID(PRE
)))
67 special_pterms_no_inv
[sigmap(cell
->getPort(ID(PRE
))[0])].insert(
68 make_tuple(cell
, ID(PRE
)));
69 if (cell
->hasPort(ID::CLR
))
70 special_pterms_no_inv
[sigmap(cell
->getPort(ID::CLR
)[0])].insert(
71 make_tuple(cell
, ID::CLR
));
72 if (cell
->hasPort(ID(CE
)))
73 special_pterms_no_inv
[sigmap(cell
->getPort(ID(CE
))[0])].insert(
74 make_tuple(cell
, ID(CE
)));
76 if (cell
->hasPort(ID::C
))
77 special_pterms_inv
[sigmap(cell
->getPort(ID::C
)[0])].insert(
78 make_tuple(cell
, ID::C
));
79 if (cell
->hasPort(ID::G
))
80 special_pterms_inv
[sigmap(cell
->getPort(ID::G
)[0])].insert(
81 make_tuple(cell
, ID::G
));
86 for (auto cell
: module
->selected_cells())
88 if (cell
->type
== ID($sop
))
90 // Read the inputs/outputs/parameters of the $sop cell
91 auto sop_inputs
= sigmap(cell
->getPort(ID::A
));
92 auto sop_output
= sigmap(cell
->getPort(ID::Y
))[0];
93 auto sop_depth
= cell
->getParam(ID::DEPTH
).as_int();
94 auto sop_width
= cell
->getParam(ID::WIDTH
).as_int();
95 auto sop_table
= cell
->getParam(ID::TABLE
);
97 auto sop_output_wire_name
= sop_output
.wire
->name
.c_str();
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
=
114 special_pterms_no_inv
.count(sop_output
) || special_pterms_inv
.count(sop_output
);
116 // Construct AND cells
117 pool
<SigBit
> intermed_wires
;
118 for (int i
= 0; i
< sop_depth
; i
++) {
119 // Wire for the output
120 auto and_out
= module
->addWire(
121 module
->uniquify(stringf("$xc2sop$%s_AND%d_OUT", sop_output_wire_name
, i
)));
122 intermed_wires
.insert(and_out
);
124 // Signals for the inputs
125 pool
<SigBit
> and_in_true
;
126 pool
<SigBit
> and_in_comp
;
127 for (int j
= 0; j
< sop_width
; j
++)
129 if (sop_table
[2 * (i
* sop_width
+ j
) + 0])
131 and_in_comp
.insert(sop_inputs
[j
]);
133 if (sop_table
[2 * (i
* sop_width
+ j
) + 1])
135 and_in_true
.insert(sop_inputs
[j
]);
139 // Construct the cell
140 auto and_cell
= module
->addCell(
141 module
->uniquify(stringf("$xc2sop$%s_AND%d", sop_output_wire_name
, i
)),
143 and_cell
->setParam(ID(TRUE_INP
), GetSize(and_in_true
));
144 and_cell
->setParam(ID(COMP_INP
), GetSize(and_in_comp
));
145 and_cell
->setPort(ID(OUT
), and_out
);
146 and_cell
->setPort(ID(IN
), and_in_true
);
147 and_cell
->setPort(ID(IN_B
), and_in_comp
);
152 // If there is only one term, don't construct an OR cell. Directly construct the XOR gate
153 auto xor_cell
= module
->addCell(
154 module
->uniquify(stringf("$xc2sop$%s_XOR", sop_output_wire_name
)),
156 xor_cell
->setParam(ID(INVERT_OUT
), has_invert
);
157 xor_cell
->setPort(ID(IN_PTC
), *intermed_wires
.begin());
158 xor_cell
->setPort(ID(OUT
), sop_output
);
160 // Special P-term handling
161 if (is_special_pterm
)
163 // Can always connect the P-term directly if it's going
164 // into something invert-capable
165 for (const auto &x
: special_pterms_inv
[sop_output
])
167 std::get
<0>(x
)->setPort(std::get
<1>(x
), *intermed_wires
.begin());
169 // If this signal is indeed inverted, flip the cell polarity
172 auto cell
= std::get
<0>(x
);
173 if (cell
->type
== ID(FDCP
)) cell
->type
= ID(FDCP_N
);
174 else if (cell
->type
== ID(FDCP_N
)) cell
->type
= ID(FDCP
);
175 else if (cell
->type
== ID(FTCP
)) cell
->type
= ID(FTCP_N
);
176 else if (cell
->type
== ID(FTCP_N
)) cell
->type
= ID(FTCP
);
177 else if (cell
->type
== ID(FDCPE
)) cell
->type
= ID(FDCPE_N
);
178 else if (cell
->type
== ID(FDCPE_N
)) cell
->type
= ID(FDCPE
);
179 else if (cell
->type
== ID(LDCP
)) cell
->type
= ID(LDCP_N
);
180 else if (cell
->type
== ID(LDCP_N
)) cell
->type
= ID(LDCP
);
181 else log_assert(!"Internal error! Bad cell type!");
185 // If it's going into something that's not invert-capable,
186 // connect it directly only if this signal isn't inverted
189 for (auto x
: special_pterms_no_inv
[sop_output
])
190 std::get
<0>(x
)->setPort(std::get
<1>(x
), *intermed_wires
.begin());
193 // Otherwise, a feedthrough P-term has to be created. Leave that to happen
194 // in the coolrunner2_fixup pass.
199 // Wire from OR to XOR
200 auto or_to_xor_wire
= module
->addWire(
201 module
->uniquify(stringf("$xc2sop$%s_OR_OUT", sop_output_wire_name
)));
203 // Construct the OR cell
204 auto or_cell
= module
->addCell(
205 module
->uniquify(stringf("$xc2sop$%s_OR", sop_output_wire_name
)),
207 or_cell
->setParam(ID::WIDTH
, sop_depth
);
208 or_cell
->setPort(ID(IN
), intermed_wires
);
209 or_cell
->setPort(ID(OUT
), or_to_xor_wire
);
211 // Construct the XOR cell
212 auto xor_cell
= module
->addCell(
213 module
->uniquify(stringf("$xc2sop$%s_XOR", sop_output_wire_name
)),
215 xor_cell
->setParam(ID(INVERT_OUT
), has_invert
);
216 xor_cell
->setPort(ID(IN_ORTERM
), or_to_xor_wire
);
217 xor_cell
->setPort(ID(OUT
), sop_output
);
220 // Finally, remove the $sop cell
221 cells_to_remove
.insert(cell
);
225 // Actually do the removal now that we aren't iterating
226 for (auto cell
: cells_to_remove
)
228 module
->remove(cell
);
232 } Coolrunner2SopPass
;
234 PRIVATE_NAMESPACE_END