Merge branch 'master' into pr_reg_wire_error
[yosys.git] / techlibs / greenpak4 / greenpak4_dffinv.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/yosys.h"
21 #include "kernel/sigtools.h"
22
23 USING_YOSYS_NAMESPACE
24 PRIVATE_NAMESPACE_BEGIN
25
26 void invert_gp_dff(Cell *cell, bool invert_input)
27 {
28 string cell_type = cell->type.str();
29 bool cell_type_latch = cell_type.find("LATCH") != string::npos;
30 bool cell_type_i = cell_type.find('I') != string::npos;
31 bool cell_type_r = cell_type.find('R') != string::npos;
32 bool cell_type_s = cell_type.find('S') != string::npos;
33
34 if (!invert_input)
35 {
36 Const initval = cell->getParam("\\INIT");
37 if (GetSize(initval) >= 1) {
38 if (initval.bits[0] == State::S0)
39 initval.bits[0] = State::S1;
40 else if (initval.bits[0] == State::S1)
41 initval.bits[0] = State::S0;
42 cell->setParam("\\INIT", initval);
43 }
44
45 if (cell_type_r && cell_type_s)
46 {
47 Const srmode = cell->getParam("\\SRMODE");
48 if (GetSize(srmode) >= 1) {
49 if (srmode.bits[0] == State::S0)
50 srmode.bits[0] = State::S1;
51 else if (srmode.bits[0] == State::S1)
52 srmode.bits[0] = State::S0;
53 cell->setParam("\\SRMODE", srmode);
54 }
55 }
56 else
57 {
58 if (cell_type_r) {
59 cell->setPort("\\nSET", cell->getPort("\\nRST"));
60 cell->unsetPort("\\nRST");
61 cell_type_r = false;
62 cell_type_s = true;
63 } else
64 if (cell_type_s) {
65 cell->setPort("\\nRST", cell->getPort("\\nSET"));
66 cell->unsetPort("\\nSET");
67 cell_type_r = true;
68 cell_type_s = false;
69 }
70 }
71 }
72
73 if (cell_type_i) {
74 cell->setPort("\\Q", cell->getPort("\\nQ"));
75 cell->unsetPort("\\nQ");
76 cell_type_i = false;
77 } else {
78 cell->setPort("\\nQ", cell->getPort("\\Q"));
79 cell->unsetPort("\\Q");
80 cell_type_i = true;
81 }
82
83 if(cell_type_latch)
84 cell->type = stringf("\\GP_DLATCH%s%s%s", cell_type_s ? "S" : "", cell_type_r ? "R" : "", cell_type_i ? "I" : "");
85 else
86 cell->type = stringf("\\GP_DFF%s%s%s", cell_type_s ? "S" : "", cell_type_r ? "R" : "", cell_type_i ? "I" : "");
87
88 log("Merged %s inverter into cell %s.%s: %s -> %s\n", invert_input ? "input" : "output",
89 log_id(cell->module), log_id(cell), cell_type.c_str()+1, log_id(cell->type));
90 }
91
92 struct Greenpak4DffInvPass : public Pass {
93 Greenpak4DffInvPass() : Pass("greenpak4_dffinv", "merge greenpak4 inverters and DFF/latches") { }
94 void help() YS_OVERRIDE
95 {
96 log("\n");
97 log(" greenpak4_dffinv [options] [selection]\n");
98 log("\n");
99 log("Merge GP_INV cells with GP_DFF* and GP_DLATCH* cells.\n");
100 log("\n");
101 }
102 void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
103 {
104 log_header(design, "Executing GREENPAK4_DFFINV pass (merge input/output inverters into FF/latch cells).\n");
105
106 size_t argidx;
107 for (argidx = 1; argidx < args.size(); argidx++)
108 {
109 // if (args[argidx] == "-singleton") {
110 // singleton_mode = true;
111 // continue;
112 // }
113 break;
114 }
115 extra_args(args, argidx, design);
116
117 pool<IdString> gp_dff_types;
118 gp_dff_types.insert("\\GP_DFF");
119 gp_dff_types.insert("\\GP_DFFI");
120 gp_dff_types.insert("\\GP_DFFR");
121 gp_dff_types.insert("\\GP_DFFRI");
122 gp_dff_types.insert("\\GP_DFFS");
123 gp_dff_types.insert("\\GP_DFFSI");
124 gp_dff_types.insert("\\GP_DFFSR");
125 gp_dff_types.insert("\\GP_DFFSRI");
126
127 gp_dff_types.insert("\\GP_DLATCH");
128 gp_dff_types.insert("\\GP_DLATCHI");
129 gp_dff_types.insert("\\GP_DLATCHR");
130 gp_dff_types.insert("\\GP_DLATCHRI");
131 gp_dff_types.insert("\\GP_DLATCHS");
132 gp_dff_types.insert("\\GP_DLATCHSI");
133 gp_dff_types.insert("\\GP_DLATCHSR");
134 gp_dff_types.insert("\\GP_DLATCHSRI");
135
136 for (auto module : design->selected_modules())
137 {
138 SigMap sigmap(module);
139 dict<SigBit, int> sig_use_cnt;
140 dict<SigBit, SigBit> inv_in2out, inv_out2in;
141 dict<SigBit, Cell*> inv_in2cell;
142 pool<Cell*> dff_cells;
143
144 for (auto wire : module->wires())
145 {
146 if (!wire->port_output)
147 continue;
148
149 for (auto bit : sigmap(wire))
150 sig_use_cnt[bit]++;
151 }
152
153 for (auto cell : module->cells())
154 for (auto &conn : cell->connections())
155 if (cell->input(conn.first) || !cell->known())
156 for (auto bit : sigmap(conn.second))
157 sig_use_cnt[bit]++;
158
159 for (auto cell : module->selected_cells())
160 {
161 if (gp_dff_types.count(cell->type)) {
162 dff_cells.insert(cell);
163 continue;
164 }
165
166 if (cell->type == "\\GP_INV") {
167 SigBit in_bit = sigmap(cell->getPort("\\IN"));
168 SigBit out_bit = sigmap(cell->getPort("\\OUT"));
169 inv_in2out[in_bit] = out_bit;
170 inv_out2in[out_bit] = in_bit;
171 inv_in2cell[in_bit] = cell;
172 continue;
173 }
174 }
175
176 for (auto cell : dff_cells)
177 {
178 SigBit d_bit = sigmap(cell->getPort("\\D"));
179 SigBit q_bit = sigmap(cell->hasPort("\\Q") ? cell->getPort("\\Q") : cell->getPort("\\nQ"));
180
181 while (inv_out2in.count(d_bit))
182 {
183 sig_use_cnt[d_bit]--;
184 invert_gp_dff(cell, true);
185 d_bit = inv_out2in.at(d_bit);
186 cell->setPort("\\D", d_bit);
187 sig_use_cnt[d_bit]++;
188 }
189
190 while (inv_in2out.count(q_bit) && sig_use_cnt[q_bit] == 1)
191 {
192 SigBit new_q_bit = inv_in2out.at(q_bit);
193 module->remove(inv_in2cell.at(q_bit));
194 sig_use_cnt.erase(q_bit);
195 inv_in2out.erase(q_bit);
196 inv_out2in.erase(new_q_bit);
197 inv_in2cell.erase(q_bit);
198
199 invert_gp_dff(cell, false);
200 if (cell->hasPort("\\Q"))
201 cell->setPort("\\Q", new_q_bit);
202 else
203 cell->setPort("\\nQ", new_q_bit);
204 }
205 }
206 }
207 }
208 } Greenpak4DffInvPass;
209
210 PRIVATE_NAMESPACE_END