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"
22 #include "kernel/mem.h"
23 #include "kernel/ff.h"
26 PRIVATE_NAMESPACE_BEGIN
28 struct OptMemPass
: public Pass
{
29 OptMemPass() : Pass("opt_mem", "optimize memories") { }
32 // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
34 log(" opt_mem [options] [selection]\n");
36 log("This pass performs various optimizations on memories in the design.\n");
39 void execute(std::vector
<std::string
> args
, RTLIL::Design
*design
) override
41 log_header(design
, "Executing OPT_MEM pass (optimize memories).\n");
44 for (argidx
= 1; argidx
< args
.size(); argidx
++) {
45 // if (args[argidx] == "-nomux") {
51 extra_args(args
, argidx
, design
);
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);
61 for (auto &port
: mem
.wr_ports
) {
62 if (port
.en
.is_fully_zero()) {
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
) {
74 if (port
.data
[bit
] != State::Sx
&& port
.data
[bit
] != State::S1
) {
78 if (port
.data
[bit
] != State::Sx
) {
79 port
.data
[bit
] = State::Sx
;
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;
95 if (bit
!= State::Sx
&& bit
!= State::S1
) {
96 always_1
[lane
] = false;
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
);
108 log("%s.%s: removing const-1 lane %d\n", log_id(module
->name
), log_id(mem
.memid
), i
);
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
);
114 log("%s.%s: removing const-x lane %d\n", log_id(module
->name
), log_id(mem
.memid
), i
);
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
);
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
);
128 ff
.sig_clk
= port
.clk
;
129 ff
.pol_clk
= port
.clk_polarity
;
130 if (port
.en
!= State::S1
) {
135 if (port
.arst
!= State::S0
) {
138 ff
.sig_arst
= port
.arst
;
139 ff
.val_arst
= port
.arst_value
[bidx
];
141 if (port
.srst
!= State::S0
) {
144 ff
.sig_srst
= port
.srst
;
145 ff
.val_srst
= port
.srst_value
[bidx
];
148 ff
.sig_q
= port
.data
[bidx
];
149 ff
.val_init
= port
.init_value
[bidx
];
155 if (GetSize(swizzle
) == 0) {
160 if (GetSize(swizzle
) != mem
.width
) {
161 for (auto &port
: mem
.wr_ports
) {
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
]);
170 port
.data
= new_data
;
173 for (auto &port
: mem
.rd_ports
) {
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
]);
187 port
.data
= new_data
;
188 port
.init_value
= new_init
;
189 port
.arst_value
= new_arst
;
190 port
.srst_value
= new_srst
;
192 for (auto &init
: mem
.inits
) {
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
]);
200 for (auto i
: swizzle
) {
201 new_en
.bits
.push_back(init
.en
.bits
[i
]);
203 init
.data
= new_data
;
206 mem
.width
= GetSize(swizzle
);
217 design
->scratchpad_set_bool("opt.did_something", true);
218 log("Performed a total of %d transformations.\n", total_count
);
222 PRIVATE_NAMESPACE_END