2 * yosys -- Yosys Open SYnthesis Suite
4 * Copyright (C) 2012 Claire Xenia Wolf <claire@yosyshq.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 void invert_gp_dff(Cell
*cell
, bool invert_input
)
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
;
36 Const initval
= cell
->getParam(ID::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(ID::INIT
, initval
);
45 if (cell_type_r
&& cell_type_s
)
47 Const srmode
= cell
->getParam(ID(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(ID(SRMODE
), srmode
);
59 cell
->setPort(ID(nSET
), cell
->getPort(ID(nRST
)));
60 cell
->unsetPort(ID(nRST
));
65 cell
->setPort(ID(nRST
), cell
->getPort(ID(nSET
)));
66 cell
->unsetPort(ID(nSET
));
74 cell
->setPort(ID::Q
, cell
->getPort(ID(nQ
)));
75 cell
->unsetPort(ID(nQ
));
78 cell
->setPort(ID(nQ
), cell
->getPort(ID::Q
));
79 cell
->unsetPort(ID::Q
);
84 cell
->type
= stringf("\\GP_DLATCH%s%s%s", cell_type_s
? "S" : "", cell_type_r
? "R" : "", cell_type_i
? "I" : "");
86 cell
->type
= stringf("\\GP_DFF%s%s%s", cell_type_s
? "S" : "", cell_type_r
? "R" : "", cell_type_i
? "I" : "");
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
));
92 struct Greenpak4DffInvPass
: public Pass
{
93 Greenpak4DffInvPass() : Pass("greenpak4_dffinv", "merge greenpak4 inverters and DFF/latches") { }
97 log(" greenpak4_dffinv [options] [selection]\n");
99 log("Merge GP_INV cells with GP_DFF* and GP_DLATCH* cells.\n");
102 void execute(std::vector
<std::string
> args
, RTLIL::Design
*design
) override
104 log_header(design
, "Executing GREENPAK4_DFFINV pass (merge input/output inverters into FF/latch cells).\n");
107 for (argidx
= 1; argidx
< args
.size(); argidx
++)
109 // if (args[argidx] == "-singleton") {
110 // singleton_mode = true;
115 extra_args(args
, argidx
, design
);
117 pool
<IdString
> gp_dff_types
;
118 gp_dff_types
.insert(ID(GP_DFF
));
119 gp_dff_types
.insert(ID(GP_DFFI
));
120 gp_dff_types
.insert(ID(GP_DFFR
));
121 gp_dff_types
.insert(ID(GP_DFFRI
));
122 gp_dff_types
.insert(ID(GP_DFFS
));
123 gp_dff_types
.insert(ID(GP_DFFSI
));
124 gp_dff_types
.insert(ID(GP_DFFSR
));
125 gp_dff_types
.insert(ID(GP_DFFSRI
));
127 gp_dff_types
.insert(ID(GP_DLATCH
));
128 gp_dff_types
.insert(ID(GP_DLATCHI
));
129 gp_dff_types
.insert(ID(GP_DLATCHR
));
130 gp_dff_types
.insert(ID(GP_DLATCHRI
));
131 gp_dff_types
.insert(ID(GP_DLATCHS
));
132 gp_dff_types
.insert(ID(GP_DLATCHSI
));
133 gp_dff_types
.insert(ID(GP_DLATCHSR
));
134 gp_dff_types
.insert(ID(GP_DLATCHSRI
));
136 for (auto module
: design
->selected_modules())
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
;
144 for (auto wire
: module
->wires())
146 if (!wire
->port_output
)
149 for (auto bit
: sigmap(wire
))
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
))
159 for (auto cell
: module
->selected_cells())
161 if (gp_dff_types
.count(cell
->type
)) {
162 dff_cells
.insert(cell
);
166 if (cell
->type
== ID(GP_INV
)) {
167 SigBit in_bit
= sigmap(cell
->getPort(ID(IN
)));
168 SigBit out_bit
= sigmap(cell
->getPort(ID(OUT
)));
169 inv_in2out
[in_bit
] = out_bit
;
170 inv_out2in
[out_bit
] = in_bit
;
171 inv_in2cell
[in_bit
] = cell
;
176 for (auto cell
: dff_cells
)
178 SigBit d_bit
= sigmap(cell
->getPort(ID::D
));
179 SigBit q_bit
= sigmap(cell
->hasPort(ID::Q
) ? cell
->getPort(ID::Q
) : cell
->getPort(ID(nQ
)));
181 while (inv_out2in
.count(d_bit
))
183 sig_use_cnt
[d_bit
]--;
184 invert_gp_dff(cell
, true);
185 d_bit
= inv_out2in
.at(d_bit
);
186 cell
->setPort(ID::D
, d_bit
);
187 sig_use_cnt
[d_bit
]++;
190 while (inv_in2out
.count(q_bit
) && sig_use_cnt
[q_bit
] == 1)
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
);
199 invert_gp_dff(cell
, false);
200 if (cell
->hasPort(ID::Q
))
201 cell
->setPort(ID::Q
, new_q_bit
);
203 cell
->setPort(ID(nQ
), new_q_bit
);
208 } Greenpak4DffInvPass
;
210 PRIVATE_NAMESPACE_END