Merge pull request #2006 from jersey99/signed-in-rtlil-wire
[yosys.git] / techlibs / coolrunner2 / coolrunner2_sop.cc
1 /*
2 * yosys -- Yosys Open SYnthesis Suite
3 *
4 * Copyright (C) 2017 Robert Ou <rqou@robertou.com>
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/yosys.h"
21 #include "kernel/sigtools.h"
22
23 USING_YOSYS_NAMESPACE
24 PRIVATE_NAMESPACE_BEGIN
25
26 struct Coolrunner2SopPass : public Pass {
27 Coolrunner2SopPass() : Pass("coolrunner2_sop", "break $sop cells into ANDTERM/ORTERM cells") { }
28 void help() YS_OVERRIDE
29 {
30 log("\n");
31 log(" coolrunner2_sop [options] [selection]\n");
32 log("\n");
33 log("Break $sop cells into ANDTERM/ORTERM cells.\n");
34 log("\n");
35 }
36 void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
37 {
38 log_header(design, "Executing COOLRUNNER2_SOP pass (break $sop cells into ANDTERM/ORTERM cells).\n");
39 extra_args(args, 1, design);
40
41 for (auto module : design->selected_modules())
42 {
43 pool<Cell*> cells_to_remove;
44 SigMap sigmap(module);
45
46 // Find all the $_NOT_ cells
47 dict<SigBit, tuple<SigBit, Cell*>> not_cells;
48 for (auto cell : module->selected_cells())
49 {
50 if (cell->type == ID($_NOT_))
51 {
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);
55 }
56 }
57
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())
62 {
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)))
65 {
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)));
75
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));
82 }
83 }
84
85 // Process $sop cells
86 for (auto cell : module->selected_cells())
87 {
88 if (cell->type == ID($sop))
89 {
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);
96
97 auto sop_output_wire_name = sop_output.wire->name.c_str();
98
99 // Check for a $_NOT_ at the output
100 bool has_invert = false;
101 if (not_cells.count(sop_output))
102 {
103 auto not_cell = not_cells.at(sop_output);
104
105 has_invert = true;
106 sop_output = std::get<0>(not_cell);
107
108 // remove the $_NOT_ cell because it gets folded into the xor
109 cells_to_remove.insert(std::get<1>(not_cell));
110 }
111
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);
115
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);
123
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++)
128 {
129 if (sop_table[2 * (i * sop_width + j) + 0])
130 {
131 and_in_comp.insert(sop_inputs[j]);
132 }
133 if (sop_table[2 * (i * sop_width + j) + 1])
134 {
135 and_in_true.insert(sop_inputs[j]);
136 }
137 }
138
139 // Construct the cell
140 auto and_cell = module->addCell(
141 module->uniquify(stringf("$xc2sop$%s_AND%d", sop_output_wire_name, i)),
142 ID(ANDTERM));
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);
148 }
149
150 if (sop_depth == 1)
151 {
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)),
155 ID(MACROCELL_XOR));
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);
159
160 // Special P-term handling
161 if (is_special_pterm)
162 {
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])
166 {
167 std::get<0>(x)->setPort(std::get<1>(x), *intermed_wires.begin());
168
169 // If this signal is indeed inverted, flip the cell polarity
170 if (has_invert)
171 {
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!");
182 }
183 }
184
185 // If it's going into something that's not invert-capable,
186 // connect it directly only if this signal isn't inverted
187 if (!has_invert)
188 {
189 for (auto x : special_pterms_no_inv[sop_output])
190 std::get<0>(x)->setPort(std::get<1>(x), *intermed_wires.begin());
191 }
192
193 // Otherwise, a feedthrough P-term has to be created. Leave that to happen
194 // in the coolrunner2_fixup pass.
195 }
196 }
197 else
198 {
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)));
202
203 // Construct the OR cell
204 auto or_cell = module->addCell(
205 module->uniquify(stringf("$xc2sop$%s_OR", sop_output_wire_name)),
206 ID(ORTERM));
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);
210
211 // Construct the XOR cell
212 auto xor_cell = module->addCell(
213 module->uniquify(stringf("$xc2sop$%s_XOR", sop_output_wire_name)),
214 ID(MACROCELL_XOR));
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);
218 }
219
220 // Finally, remove the $sop cell
221 cells_to_remove.insert(cell);
222 }
223 }
224
225 // Actually do the removal now that we aren't iterating
226 for (auto cell : cells_to_remove)
227 {
228 module->remove(cell);
229 }
230 }
231 }
232 } Coolrunner2SopPass;
233
234 PRIVATE_NAMESPACE_END