mirror of https://github.com/YosysHQ/yosys.git
opt_mem: Remove constant-value bit lanes.
This commit is contained in:
parent
048170d376
commit
77b1dfd8c3
|
@ -20,6 +20,7 @@
|
||||||
#include "kernel/yosys.h"
|
#include "kernel/yosys.h"
|
||||||
#include "kernel/sigtools.h"
|
#include "kernel/sigtools.h"
|
||||||
#include "kernel/mem.h"
|
#include "kernel/mem.h"
|
||||||
|
#include "kernel/ff.h"
|
||||||
|
|
||||||
USING_YOSYS_NAMESPACE
|
USING_YOSYS_NAMESPACE
|
||||||
PRIVATE_NAMESPACE_BEGIN
|
PRIVATE_NAMESPACE_BEGIN
|
||||||
|
@ -54,32 +55,161 @@ struct OptMemPass : public Pass {
|
||||||
SigMap sigmap(module);
|
SigMap sigmap(module);
|
||||||
FfInitVals initvals(&sigmap, module);
|
FfInitVals initvals(&sigmap, module);
|
||||||
for (auto &mem : Mem::get_selected_memories(module)) {
|
for (auto &mem : Mem::get_selected_memories(module)) {
|
||||||
|
std::vector<bool> always_0(mem.width, true);
|
||||||
|
std::vector<bool> always_1(mem.width, true);
|
||||||
bool changed = false;
|
bool changed = false;
|
||||||
for (auto &port : mem.wr_ports) {
|
for (auto &port : mem.wr_ports) {
|
||||||
if (port.en.is_fully_zero()) {
|
if (port.en.is_fully_zero()) {
|
||||||
port.removed = true;
|
port.removed = true;
|
||||||
changed = true;
|
changed = true;
|
||||||
total_count++;
|
total_count++;
|
||||||
|
} else {
|
||||||
|
for (int sub = 0; sub < (1 << port.wide_log2); sub++) {
|
||||||
|
for (int i = 0; i < mem.width; i++) {
|
||||||
|
int bit = sub * mem.width + i;
|
||||||
|
if (port.en[bit] != State::S0) {
|
||||||
|
if (port.data[bit] != State::Sx && port.data[bit] != State::S0) {
|
||||||
|
always_0[i] = false;
|
||||||
|
}
|
||||||
|
if (port.data[bit] != State::Sx && port.data[bit] != State::S1) {
|
||||||
|
always_1[i] = false;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (port.data[bit] != State::Sx) {
|
||||||
|
port.data[bit] = State::Sx;
|
||||||
|
changed = true;
|
||||||
|
total_count++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
for (auto &init : mem.inits) {
|
||||||
|
for (int i = 0; i < GetSize(init.data); i++) {
|
||||||
|
State bit = init.data.bits[i];
|
||||||
|
int lane = i % mem.width;
|
||||||
|
if (bit != State::Sx && bit != State::S0) {
|
||||||
|
always_0[lane] = false;
|
||||||
|
}
|
||||||
|
if (bit != State::Sx && bit != State::S1) {
|
||||||
|
always_1[lane] = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
std::vector<int> swizzle;
|
||||||
|
for (int i = 0; i < mem.width; i++) {
|
||||||
|
if (!always_0[i] && !always_1[i]) {
|
||||||
|
swizzle.push_back(i);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
State bit;
|
||||||
|
if (!always_0[i]) {
|
||||||
|
log("%s.%s: removing const-1 lane %d\n", log_id(module->name), log_id(mem.memid), i);
|
||||||
|
bit = State::S1;
|
||||||
|
} else if (!always_1[i]) {
|
||||||
|
log("%s.%s: removing const-0 lane %d\n", log_id(module->name), log_id(mem.memid), i);
|
||||||
|
bit = State::S0;
|
||||||
|
} else {
|
||||||
|
log("%s.%s: removing const-x lane %d\n", log_id(module->name), log_id(mem.memid), i);
|
||||||
|
bit = State::Sx;
|
||||||
|
}
|
||||||
|
// Reconnect read port data.
|
||||||
|
for (auto &port: mem.rd_ports) {
|
||||||
|
for (int sub = 0; sub < (1 << port.wide_log2); sub++) {
|
||||||
|
int bidx = sub * mem.width + i;
|
||||||
|
if (!port.clk_enable) {
|
||||||
|
module->connect(port.data[bidx], bit);
|
||||||
|
} else {
|
||||||
|
// The FF will most likely be redundant, but it's up to opt_dff to deal with this.
|
||||||
|
FfData ff(module, &initvals, NEW_ID);
|
||||||
|
ff.width = 1;
|
||||||
|
ff.has_clk = true;
|
||||||
|
ff.sig_clk = port.clk;
|
||||||
|
ff.pol_clk = port.clk_polarity;
|
||||||
|
if (port.en != State::S1) {
|
||||||
|
ff.has_ce = true;
|
||||||
|
ff.pol_ce = true;
|
||||||
|
ff.sig_ce = port.en;
|
||||||
|
}
|
||||||
|
if (port.arst != State::S0) {
|
||||||
|
ff.has_arst = true;
|
||||||
|
ff.pol_arst = true;
|
||||||
|
ff.sig_arst = port.arst;
|
||||||
|
ff.val_arst = port.arst_value[bidx];
|
||||||
|
}
|
||||||
|
if (port.srst != State::S0) {
|
||||||
|
ff.has_srst = true;
|
||||||
|
ff.pol_srst = true;
|
||||||
|
ff.sig_srst = port.srst;
|
||||||
|
ff.val_srst = port.srst_value[bidx];
|
||||||
|
}
|
||||||
|
ff.sig_d = bit;
|
||||||
|
ff.sig_q = port.data[bidx];
|
||||||
|
ff.val_init = port.init_value[bidx];
|
||||||
|
ff.emit();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (GetSize(swizzle) == 0) {
|
||||||
|
mem.remove();
|
||||||
|
total_count++;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (GetSize(swizzle) != mem.width) {
|
||||||
|
for (auto &port: mem.wr_ports) {
|
||||||
|
SigSpec new_data;
|
||||||
|
SigSpec new_en;
|
||||||
|
for (int sub = 0; sub < (1 << port.wide_log2); sub++) {
|
||||||
|
for (auto i: swizzle) {
|
||||||
|
new_data.append(port.data[sub * mem.width + i]);
|
||||||
|
new_en.append(port.en[sub * mem.width + i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
port.data = new_data;
|
||||||
|
port.en = new_en;
|
||||||
|
}
|
||||||
|
for (auto &port: mem.rd_ports) {
|
||||||
|
SigSpec new_data;
|
||||||
|
Const new_init;
|
||||||
|
Const new_arst;
|
||||||
|
Const new_srst;
|
||||||
|
for (int sub = 0; sub < (1 << port.wide_log2); sub++) {
|
||||||
|
for (auto i: swizzle) {
|
||||||
|
int bidx = sub * mem.width + i;
|
||||||
|
new_data.append(port.data[bidx]);
|
||||||
|
new_init.bits.push_back(port.init_value.bits[bidx]);
|
||||||
|
new_arst.bits.push_back(port.arst_value.bits[bidx]);
|
||||||
|
new_srst.bits.push_back(port.srst_value.bits[bidx]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
port.data = new_data;
|
||||||
|
port.init_value = new_init;
|
||||||
|
port.arst_value = new_arst;
|
||||||
|
port.srst_value = new_srst;
|
||||||
|
}
|
||||||
|
for (auto &init: mem.inits) {
|
||||||
|
Const new_data;
|
||||||
|
Const new_en;
|
||||||
|
for (int s = 0; s < GetSize(init.data); s += mem.width) {
|
||||||
|
for (auto i: swizzle) {
|
||||||
|
new_data.bits.push_back(init.data.bits[s + i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (auto i: swizzle) {
|
||||||
|
new_en.bits.push_back(init.en.bits[i]);
|
||||||
|
}
|
||||||
|
init.data = new_data;
|
||||||
|
init.en = new_en;
|
||||||
|
}
|
||||||
|
mem.width = GetSize(swizzle);
|
||||||
|
changed = true;
|
||||||
|
total_count++;
|
||||||
|
}
|
||||||
if (changed) {
|
if (changed) {
|
||||||
mem.emit();
|
mem.emit();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (mem.wr_ports.empty() && mem.inits.empty()) {
|
|
||||||
// The whole memory array will contain
|
|
||||||
// only State::Sx, but the embedded read
|
|
||||||
// registers could have reset or init values.
|
|
||||||
// They will probably be optimized away by
|
|
||||||
// opt_dff later.
|
|
||||||
for (int i = 0; i < GetSize(mem.rd_ports); i++) {
|
|
||||||
mem.extract_rdff(i, &initvals);
|
|
||||||
auto &port = mem.rd_ports[i];
|
|
||||||
module->connect(port.data, Const(State::Sx, GetSize(port.data)));
|
|
||||||
}
|
|
||||||
mem.remove();
|
|
||||||
total_count++;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,2 +1,3 @@
|
||||||
*.log
|
*.log
|
||||||
|
*.out
|
||||||
/*.mk
|
/*.mk
|
||||||
|
|
|
@ -1,17 +1,3 @@
|
||||||
#!/bin/bash
|
#!/bin/bash
|
||||||
|
|
||||||
set -e
|
exec ../tools/autotest.sh -G -j $@ -p 'proc; opt; memory -nomap; techmap -map ../mem_simple_4x1_map.v;; techmap; opt; abc;; stat' mem_simple_4x1_uut.v
|
||||||
|
|
||||||
../../yosys -b 'verilog -noattr' -o mem_simple_4x1_synth.v -p 'read_verilog mem_simple_4x1_uut.v; proc; opt; memory -nomap; techmap -map mem_simple_4x1_map.v;; techmap; opt; abc;; stat'
|
|
||||||
|
|
||||||
iverilog -o mem_simple_4x1_gold_tb mem_simple_4x1_tb.v mem_simple_4x1_uut.v
|
|
||||||
iverilog -o mem_simple_4x1_gate_tb mem_simple_4x1_tb.v mem_simple_4x1_synth.v mem_simple_4x1_cells.v
|
|
||||||
|
|
||||||
./mem_simple_4x1_gold_tb > mem_simple_4x1_gold_tb.out
|
|
||||||
./mem_simple_4x1_gate_tb > mem_simple_4x1_gate_tb.out
|
|
||||||
|
|
||||||
diff -u mem_simple_4x1_gold_tb.out mem_simple_4x1_gate_tb.out
|
|
||||||
rm -f mem_simple_4x1_synth.v mem_simple_4x1_tb.vcd
|
|
||||||
rm -f mem_simple_4x1_{gold,gate}_tb{,.out}
|
|
||||||
: OK
|
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue