opt_mem: Remove constant-value bit lanes.
[yosys.git] / passes / opt / opt_mem.cc
1 /*
2 * yosys -- Yosys Open SYnthesis Suite
3 *
4 * Copyright (C) 2012 Claire Xenia Wolf <claire@yosyshq.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 #include "kernel/mem.h"
23 #include "kernel/ff.h"
24
25 USING_YOSYS_NAMESPACE
26 PRIVATE_NAMESPACE_BEGIN
27
28 struct OptMemPass : public Pass {
29 OptMemPass() : Pass("opt_mem", "optimize memories") { }
30 void help() override
31 {
32 // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
33 log("\n");
34 log(" opt_mem [options] [selection]\n");
35 log("\n");
36 log("This pass performs various optimizations on memories in the design.\n");
37 log("\n");
38 }
39 void execute(std::vector<std::string> args, RTLIL::Design *design) override
40 {
41 log_header(design, "Executing OPT_MEM pass (optimize memories).\n");
42
43 size_t argidx;
44 for (argidx = 1; argidx < args.size(); argidx++) {
45 // if (args[argidx] == "-nomux") {
46 // mode_nomux = true;
47 // continue;
48 // }
49 break;
50 }
51 extra_args(args, argidx, design);
52
53 int total_count = 0;
54 for (auto module : design->selected_modules()) {
55 SigMap sigmap(module);
56 FfInitVals initvals(&sigmap, module);
57 for (auto &mem : Mem::get_selected_memories(module)) {
58 std::vector<bool> always_0(mem.width, true);
59 std::vector<bool> always_1(mem.width, true);
60 bool changed = false;
61 for (auto &port : mem.wr_ports) {
62 if (port.en.is_fully_zero()) {
63 port.removed = true;
64 changed = true;
65 total_count++;
66 } else {
67 for (int sub = 0; sub < (1 << port.wide_log2); sub++) {
68 for (int i = 0; i < mem.width; i++) {
69 int bit = sub * mem.width + i;
70 if (port.en[bit] != State::S0) {
71 if (port.data[bit] != State::Sx && port.data[bit] != State::S0) {
72 always_0[i] = false;
73 }
74 if (port.data[bit] != State::Sx && port.data[bit] != State::S1) {
75 always_1[i] = false;
76 }
77 } else {
78 if (port.data[bit] != State::Sx) {
79 port.data[bit] = State::Sx;
80 changed = true;
81 total_count++;
82 }
83 }
84 }
85 }
86 }
87 }
88 for (auto &init : mem.inits) {
89 for (int i = 0; i < GetSize(init.data); i++) {
90 State bit = init.data.bits[i];
91 int lane = i % mem.width;
92 if (bit != State::Sx && bit != State::S0) {
93 always_0[lane] = false;
94 }
95 if (bit != State::Sx && bit != State::S1) {
96 always_1[lane] = false;
97 }
98 }
99 }
100 std::vector<int> swizzle;
101 for (int i = 0; i < mem.width; i++) {
102 if (!always_0[i] && !always_1[i]) {
103 swizzle.push_back(i);
104 continue;
105 }
106 State bit;
107 if (!always_0[i]) {
108 log("%s.%s: removing const-1 lane %d\n", log_id(module->name), log_id(mem.memid), i);
109 bit = State::S1;
110 } else if (!always_1[i]) {
111 log("%s.%s: removing const-0 lane %d\n", log_id(module->name), log_id(mem.memid), i);
112 bit = State::S0;
113 } else {
114 log("%s.%s: removing const-x lane %d\n", log_id(module->name), log_id(mem.memid), i);
115 bit = State::Sx;
116 }
117 // Reconnect read port data.
118 for (auto &port: mem.rd_ports) {
119 for (int sub = 0; sub < (1 << port.wide_log2); sub++) {
120 int bidx = sub * mem.width + i;
121 if (!port.clk_enable) {
122 module->connect(port.data[bidx], bit);
123 } else {
124 // The FF will most likely be redundant, but it's up to opt_dff to deal with this.
125 FfData ff(module, &initvals, NEW_ID);
126 ff.width = 1;
127 ff.has_clk = true;
128 ff.sig_clk = port.clk;
129 ff.pol_clk = port.clk_polarity;
130 if (port.en != State::S1) {
131 ff.has_ce = true;
132 ff.pol_ce = true;
133 ff.sig_ce = port.en;
134 }
135 if (port.arst != State::S0) {
136 ff.has_arst = true;
137 ff.pol_arst = true;
138 ff.sig_arst = port.arst;
139 ff.val_arst = port.arst_value[bidx];
140 }
141 if (port.srst != State::S0) {
142 ff.has_srst = true;
143 ff.pol_srst = true;
144 ff.sig_srst = port.srst;
145 ff.val_srst = port.srst_value[bidx];
146 }
147 ff.sig_d = bit;
148 ff.sig_q = port.data[bidx];
149 ff.val_init = port.init_value[bidx];
150 ff.emit();
151 }
152 }
153 }
154 }
155 if (GetSize(swizzle) == 0) {
156 mem.remove();
157 total_count++;
158 continue;
159 }
160 if (GetSize(swizzle) != mem.width) {
161 for (auto &port: mem.wr_ports) {
162 SigSpec new_data;
163 SigSpec new_en;
164 for (int sub = 0; sub < (1 << port.wide_log2); sub++) {
165 for (auto i: swizzle) {
166 new_data.append(port.data[sub * mem.width + i]);
167 new_en.append(port.en[sub * mem.width + i]);
168 }
169 }
170 port.data = new_data;
171 port.en = new_en;
172 }
173 for (auto &port: mem.rd_ports) {
174 SigSpec new_data;
175 Const new_init;
176 Const new_arst;
177 Const new_srst;
178 for (int sub = 0; sub < (1 << port.wide_log2); sub++) {
179 for (auto i: swizzle) {
180 int bidx = sub * mem.width + i;
181 new_data.append(port.data[bidx]);
182 new_init.bits.push_back(port.init_value.bits[bidx]);
183 new_arst.bits.push_back(port.arst_value.bits[bidx]);
184 new_srst.bits.push_back(port.srst_value.bits[bidx]);
185 }
186 }
187 port.data = new_data;
188 port.init_value = new_init;
189 port.arst_value = new_arst;
190 port.srst_value = new_srst;
191 }
192 for (auto &init: mem.inits) {
193 Const new_data;
194 Const new_en;
195 for (int s = 0; s < GetSize(init.data); s += mem.width) {
196 for (auto i: swizzle) {
197 new_data.bits.push_back(init.data.bits[s + i]);
198 }
199 }
200 for (auto i: swizzle) {
201 new_en.bits.push_back(init.en.bits[i]);
202 }
203 init.data = new_data;
204 init.en = new_en;
205 }
206 mem.width = GetSize(swizzle);
207 changed = true;
208 total_count++;
209 }
210 if (changed) {
211 mem.emit();
212 }
213 }
214 }
215
216 if (total_count)
217 design->scratchpad_set_bool("opt.did_something", true);
218 log("Performed a total of %d transformations.\n", total_count);
219 }
220 } OptMemPass;
221
222 PRIVATE_NAMESPACE_END