Improvements and bugfixes in clk2fflogic
[yosys.git] / passes / sat / clk2fflogic.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 struct Clk2fflogicPass : public Pass {
27 Clk2fflogicPass() : Pass("clk2fflogic", "convert clocked FFs to generic $ff cells") { }
28 virtual void help()
29 {
30 // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
31 log("\n");
32 log(" clk2fflogic [options] [selection]\n");
33 log("\n");
34 log("This command replaces clocked flip-flops with generic $ff cells that use the\n");
35 log("implicit global clock. This is useful for formal verification of designs with\n");
36 log("multiple clocks.\n");
37 log("\n");
38 }
39 virtual void execute(std::vector<std::string> args, RTLIL::Design *design)
40 {
41 // bool flag_noinit = false;
42
43 log_header(design, "Executing CLK2FFLOGIC pass (convert clocked FFs to generic $ff cells).\n");
44
45 size_t argidx;
46 for (argidx = 1; argidx < args.size(); argidx++)
47 {
48 // if (args[argidx] == "-noinit") {
49 // flag_noinit = true;
50 // continue;
51 // }
52 break;
53 }
54 extra_args(args, argidx, design);
55
56 for (auto module : design->selected_modules())
57 {
58 SigMap sigmap(module);
59 dict<SigBit, State> initbits;
60 pool<SigBit> del_initbits;
61
62 for (auto wire : module->wires())
63 if (wire->attributes.count("\\init") > 0)
64 {
65 Const initval = wire->attributes.at("\\init");
66 SigSpec initsig = sigmap(wire);
67
68 for (int i = 0; i < GetSize(initval) && i < GetSize(initsig); i++)
69 if (initval[i] == State::S0 || initval[i] == State::S1)
70 initbits[initsig[i]] = initval[i];
71 }
72
73 for (auto cell : vector<Cell*>(module->selected_cells()))
74 {
75 if (cell->type.in("$dff", "$adff"))
76 {
77 bool clkpol = cell->parameters["\\CLK_POLARITY"].as_bool();
78
79 SigSpec clk = cell->getPort("\\CLK");
80 Wire *past_clk = module->addWire(NEW_ID);
81 past_clk->attributes["\\init"] = clkpol ? State::S1 : State::S0;
82 module->addFf(NEW_ID, clk, past_clk);
83
84 SigSpec sig_d = cell->getPort("\\D");
85 SigSpec sig_q = cell->getPort("\\Q");
86
87 log("Replacing %s.%s (%s): CLK=%s, D=%s, Q=%s\n",
88 log_id(module), log_id(cell), log_id(cell->type),
89 log_signal(clk), log_signal(sig_d), log_signal(sig_q));
90
91 SigSpec clock_edge_pattern;
92
93 if (clkpol) {
94 clock_edge_pattern.append_bit(State::S0);
95 clock_edge_pattern.append_bit(State::S1);
96 } else {
97 clock_edge_pattern.append_bit(State::S1);
98 clock_edge_pattern.append_bit(State::S0);
99 }
100
101 SigSpec clock_edge = module->Eqx(NEW_ID, {clk, SigSpec(past_clk)}, clock_edge_pattern);
102
103 Wire *past_d = module->addWire(NEW_ID, GetSize(sig_d));
104 Wire *past_q = module->addWire(NEW_ID, GetSize(sig_q));
105 module->addFf(NEW_ID, sig_d, past_d);
106 module->addFf(NEW_ID, sig_q, past_q);
107
108 if (cell->type == "$adff")
109 {
110 SigSpec arst = cell->getPort("\\ARST");
111 SigSpec qval = module->Mux(NEW_ID, past_q, past_d, clock_edge);
112 Const rstval = cell->parameters["\\ARST_VALUE"];
113
114 if (cell->parameters["\\ARST_POLARITY"].as_bool())
115 module->addMux(NEW_ID, qval, rstval, arst, sig_q);
116 else
117 module->addMux(NEW_ID, rstval, qval, arst, sig_q);
118 }
119 else
120 {
121 module->addMux(NEW_ID, past_q, past_d, clock_edge, sig_q);
122 }
123
124 Const initval;
125 bool assign_initval = false;
126 for (int i = 0; i < GetSize(sig_d); i++) {
127 SigBit qbit = sigmap(sig_q[i]);
128 if (initbits.count(qbit)) {
129 initval.bits.push_back(initbits.at(qbit));
130 del_initbits.insert(qbit);
131 } else
132 initval.bits.push_back(State::Sx);
133 if (initval.bits.back() != State::Sx)
134 assign_initval = true;
135 }
136
137 if (assign_initval) {
138 past_d->attributes["\\init"] = initval;
139 past_q->attributes["\\init"] = initval;
140 }
141
142 module->remove(cell);
143 continue;
144 }
145 }
146
147 for (auto wire : module->wires())
148 if (wire->attributes.count("\\init") > 0)
149 {
150 bool delete_initattr = true;
151 Const initval = wire->attributes.at("\\init");
152 SigSpec initsig = sigmap(wire);
153
154 for (int i = 0; i < GetSize(initval) && i < GetSize(initsig); i++)
155 if (del_initbits.count(initsig[i]) > 0)
156 initval[i] = State::Sx;
157 else if (initval[i] != State::Sx)
158 delete_initattr = false;
159
160 if (delete_initattr)
161 wire->attributes.erase("\\init");
162 else
163 wire->attributes.at("\\init") = initval;
164 }
165 }
166
167 }
168 } Clk2fflogicPass;
169
170 PRIVATE_NAMESPACE_END