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/sigtools.h"
|
||||
#include "kernel/mem.h"
|
||||
#include "kernel/ff.h"
|
||||
|
||||
USING_YOSYS_NAMESPACE
|
||||
PRIVATE_NAMESPACE_BEGIN
|
||||
|
@ -54,32 +55,161 @@ struct OptMemPass : public Pass {
|
|||
SigMap sigmap(module);
|
||||
FfInitVals initvals(&sigmap, 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;
|
||||
for (auto &port : mem.wr_ports) {
|
||||
if (port.en.is_fully_zero()) {
|
||||
port.removed = true;
|
||||
changed = true;
|
||||
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) {
|
||||
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
|
||||
*.out
|
||||
/*.mk
|
||||
|
|
|
@ -1,17 +1,3 @@
|
|||
#!/bin/bash
|
||||
|
||||
set -e
|
||||
|
||||
../../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
|
||||
|
||||
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
|
||||
|
|
Loading…
Reference in New Issue