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