mirror of
https://github.com/YosysHQ/yosys
synced 2025-08-03 09:50:24 +00:00
Merge d786262ad6
into 262b00d5e5
This commit is contained in:
commit
22e50bee4d
3 changed files with 85 additions and 19 deletions
|
@ -31,7 +31,7 @@ struct MemoryPass : public Pass {
|
||||||
{
|
{
|
||||||
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
|
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
|
||||||
log("\n");
|
log("\n");
|
||||||
log(" memory [-norom] [-nomap] [-nordff] [-nowiden] [-nosat] [-memx] [-no-rw-check] [-bram <bram_rules>] [selection]\n");
|
log(" memory [-external-init] [-norom] [-nomap] [-nordff] [-nowiden] [-nosat] [-memx] [-no-rw-check] [-bram <bram_rules>] [selection]\n");
|
||||||
log("\n");
|
log("\n");
|
||||||
log("This pass calls all the other memory_* passes in a useful order:\n");
|
log("This pass calls all the other memory_* passes in a useful order:\n");
|
||||||
log("\n");
|
log("\n");
|
||||||
|
@ -59,6 +59,7 @@ struct MemoryPass : public Pass {
|
||||||
bool flag_nomap = false;
|
bool flag_nomap = false;
|
||||||
bool flag_nordff = false;
|
bool flag_nordff = false;
|
||||||
bool flag_memx = false;
|
bool flag_memx = false;
|
||||||
|
string opt_mem_opts;
|
||||||
string memory_dff_opts;
|
string memory_dff_opts;
|
||||||
string memory_bram_opts;
|
string memory_bram_opts;
|
||||||
string memory_share_opts;
|
string memory_share_opts;
|
||||||
|
@ -68,6 +69,10 @@ struct MemoryPass : public Pass {
|
||||||
|
|
||||||
size_t argidx;
|
size_t argidx;
|
||||||
for (argidx = 1; argidx < args.size(); argidx++) {
|
for (argidx = 1; argidx < args.size(); argidx++) {
|
||||||
|
if (args[argidx] == "-external-init") {
|
||||||
|
opt_mem_opts += " -external-init";
|
||||||
|
continue;
|
||||||
|
}
|
||||||
if (args[argidx] == "-norom") {
|
if (args[argidx] == "-norom") {
|
||||||
flag_norom = true;
|
flag_norom = true;
|
||||||
continue;
|
continue;
|
||||||
|
@ -105,7 +110,7 @@ struct MemoryPass : public Pass {
|
||||||
}
|
}
|
||||||
extra_args(args, argidx, design);
|
extra_args(args, argidx, design);
|
||||||
|
|
||||||
Pass::call(design, "opt_mem");
|
Pass::call(design, "opt_mem" + opt_mem_opts);
|
||||||
Pass::call(design, "opt_mem_priority");
|
Pass::call(design, "opt_mem_priority");
|
||||||
Pass::call(design, "opt_mem_feedback");
|
Pass::call(design, "opt_mem_feedback");
|
||||||
if (!flag_norom)
|
if (!flag_norom)
|
||||||
|
|
|
@ -17,16 +17,16 @@
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "kernel/yosys.h"
|
|
||||||
#include "kernel/sigtools.h"
|
|
||||||
#include "kernel/mem.h"
|
|
||||||
#include "kernel/ff.h"
|
#include "kernel/ff.h"
|
||||||
|
#include "kernel/mem.h"
|
||||||
|
#include "kernel/sigtools.h"
|
||||||
|
#include "kernel/yosys.h"
|
||||||
|
|
||||||
USING_YOSYS_NAMESPACE
|
USING_YOSYS_NAMESPACE
|
||||||
PRIVATE_NAMESPACE_BEGIN
|
PRIVATE_NAMESPACE_BEGIN
|
||||||
|
|
||||||
struct OptMemPass : public Pass {
|
struct OptMemPass : public Pass {
|
||||||
OptMemPass() : Pass("opt_mem", "optimize memories") { }
|
OptMemPass() : Pass("opt_mem", "optimize memories") {}
|
||||||
void help() override
|
void help() override
|
||||||
{
|
{
|
||||||
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
|
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
|
||||||
|
@ -35,17 +35,23 @@ struct OptMemPass : public Pass {
|
||||||
log("\n");
|
log("\n");
|
||||||
log("This pass performs various optimizations on memories in the design.\n");
|
log("This pass performs various optimizations on memories in the design.\n");
|
||||||
log("\n");
|
log("\n");
|
||||||
|
log(" -external-init\n");
|
||||||
|
log(" Assume memories are initialised externally, i.e. the memory\n");
|
||||||
|
log(" is pre-populated so content is available even when there is no\n");
|
||||||
|
log(" write within the circuit.\n");
|
||||||
|
log("\n");
|
||||||
}
|
}
|
||||||
void execute(std::vector<std::string> args, RTLIL::Design *design) override
|
void execute(std::vector<std::string> args, RTLIL::Design *design) override
|
||||||
{
|
{
|
||||||
log_header(design, "Executing OPT_MEM pass (optimize memories).\n");
|
log_header(design, "Executing OPT_MEM pass (optimize memories).\n");
|
||||||
|
bool external_init = false;
|
||||||
|
|
||||||
size_t argidx;
|
size_t argidx;
|
||||||
for (argidx = 1; argidx < args.size(); argidx++) {
|
for (argidx = 1; argidx < args.size(); argidx++) {
|
||||||
// if (args[argidx] == "-nomux") {
|
if (args[argidx] == "-external-init") {
|
||||||
// mode_nomux = true;
|
external_init = true;
|
||||||
// continue;
|
continue;
|
||||||
// }
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
extra_args(args, argidx, design);
|
extra_args(args, argidx, design);
|
||||||
|
@ -102,7 +108,7 @@ struct OptMemPass : public Pass {
|
||||||
}
|
}
|
||||||
std::vector<int> swizzle;
|
std::vector<int> swizzle;
|
||||||
for (int i = 0; i < mem.width; i++) {
|
for (int i = 0; i < mem.width; i++) {
|
||||||
if (!always_0[i] && !always_1[i]) {
|
if ((!always_0[i] && !always_1[i]) || external_init) {
|
||||||
swizzle.push_back(i);
|
swizzle.push_back(i);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
@ -118,7 +124,7 @@ struct OptMemPass : public Pass {
|
||||||
bit = State::Sx;
|
bit = State::Sx;
|
||||||
}
|
}
|
||||||
// Reconnect read port data.
|
// Reconnect read port data.
|
||||||
for (auto &port: mem.rd_ports) {
|
for (auto &port : mem.rd_ports) {
|
||||||
for (int sub = 0; sub < (1 << port.wide_log2); sub++) {
|
for (int sub = 0; sub < (1 << port.wide_log2); sub++) {
|
||||||
int bidx = sub * mem.width + i;
|
int bidx = sub * mem.width + i;
|
||||||
if (!port.clk_enable) {
|
if (!port.clk_enable) {
|
||||||
|
@ -161,11 +167,11 @@ struct OptMemPass : public Pass {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (GetSize(swizzle) != mem.width) {
|
if (GetSize(swizzle) != mem.width) {
|
||||||
for (auto &port: mem.wr_ports) {
|
for (auto &port : mem.wr_ports) {
|
||||||
SigSpec new_data;
|
SigSpec new_data;
|
||||||
SigSpec new_en;
|
SigSpec new_en;
|
||||||
for (int sub = 0; sub < (1 << port.wide_log2); sub++) {
|
for (int sub = 0; sub < (1 << port.wide_log2); sub++) {
|
||||||
for (auto i: swizzle) {
|
for (auto i : swizzle) {
|
||||||
new_data.append(port.data[sub * mem.width + i]);
|
new_data.append(port.data[sub * mem.width + i]);
|
||||||
new_en.append(port.en[sub * mem.width + i]);
|
new_en.append(port.en[sub * mem.width + i]);
|
||||||
}
|
}
|
||||||
|
@ -173,13 +179,13 @@ struct OptMemPass : public Pass {
|
||||||
port.data = new_data;
|
port.data = new_data;
|
||||||
port.en = new_en;
|
port.en = new_en;
|
||||||
}
|
}
|
||||||
for (auto &port: mem.rd_ports) {
|
for (auto &port : mem.rd_ports) {
|
||||||
SigSpec new_data;
|
SigSpec new_data;
|
||||||
Const new_init;
|
Const new_init;
|
||||||
Const new_arst;
|
Const new_arst;
|
||||||
Const new_srst;
|
Const new_srst;
|
||||||
for (int sub = 0; sub < (1 << port.wide_log2); sub++) {
|
for (int sub = 0; sub < (1 << port.wide_log2); sub++) {
|
||||||
for (auto i: swizzle) {
|
for (auto i : swizzle) {
|
||||||
int bidx = sub * mem.width + i;
|
int bidx = sub * mem.width + i;
|
||||||
new_data.append(port.data[bidx]);
|
new_data.append(port.data[bidx]);
|
||||||
new_init.bits().push_back(port.init_value[bidx]);
|
new_init.bits().push_back(port.init_value[bidx]);
|
||||||
|
@ -192,15 +198,15 @@ struct OptMemPass : public Pass {
|
||||||
port.arst_value = new_arst;
|
port.arst_value = new_arst;
|
||||||
port.srst_value = new_srst;
|
port.srst_value = new_srst;
|
||||||
}
|
}
|
||||||
for (auto &init: mem.inits) {
|
for (auto &init : mem.inits) {
|
||||||
Const new_data;
|
Const new_data;
|
||||||
Const new_en;
|
Const new_en;
|
||||||
for (int s = 0; s < GetSize(init.data); s += mem.width) {
|
for (int s = 0; s < GetSize(init.data); s += mem.width) {
|
||||||
for (auto i: swizzle) {
|
for (auto i : swizzle) {
|
||||||
new_data.bits().push_back(init.data[s + i]);
|
new_data.bits().push_back(init.data[s + i]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for (auto i: swizzle) {
|
for (auto i : swizzle) {
|
||||||
new_en.bits().push_back(init.en[i]);
|
new_en.bits().push_back(init.en[i]);
|
||||||
}
|
}
|
||||||
init.data = new_data;
|
init.data = new_data;
|
||||||
|
|
55
tests/opt/opt_mem_external.ys
Normal file
55
tests/opt/opt_mem_external.ys
Normal file
|
@ -0,0 +1,55 @@
|
||||||
|
read_verilog << EOF
|
||||||
|
module Mem #(
|
||||||
|
parameter WIDTH = 8,
|
||||||
|
parameter SIZE = 16,
|
||||||
|
parameter IDX_SIZE = 16
|
||||||
|
) (
|
||||||
|
input wire [WIDTH-1:0] addr,
|
||||||
|
input wire [WIDTH-1:0] write_data,
|
||||||
|
input wire write_en,
|
||||||
|
|
||||||
|
input wire clk,
|
||||||
|
|
||||||
|
output reg [WIDTH-1:0] read_data,
|
||||||
|
|
||||||
|
);
|
||||||
|
reg [WIDTH-1:0] mem[SIZE-1:0];
|
||||||
|
|
||||||
|
always @(posedge clk) begin
|
||||||
|
if (write_en)
|
||||||
|
mem[addr0[IDX_SIZE-1:0]] <= write_data;
|
||||||
|
|
||||||
|
read_data <= mem[addr0[IDX_SIZE-1:0]];
|
||||||
|
end
|
||||||
|
|
||||||
|
endmodule
|
||||||
|
|
||||||
|
module test_keep_at_instance (clk, addr, data);
|
||||||
|
|
||||||
|
input wire clk;
|
||||||
|
input wire [15:0] addr;
|
||||||
|
output wire[7:0] data;
|
||||||
|
|
||||||
|
Mem mem (
|
||||||
|
.clk(clk),
|
||||||
|
.addr(addr),
|
||||||
|
.read_data(data),
|
||||||
|
.write_en(1'b0),
|
||||||
|
.write_data()
|
||||||
|
);
|
||||||
|
|
||||||
|
endmodule
|
||||||
|
|
||||||
|
EOF
|
||||||
|
|
||||||
|
hierarchy -auto-top;
|
||||||
|
flatten;
|
||||||
|
proc;
|
||||||
|
|
||||||
|
select -assert-any t:$mem*
|
||||||
|
opt_mem -external-init
|
||||||
|
select -assert-any t:$mem*
|
||||||
|
|
||||||
|
select -assert-any t:$mem*
|
||||||
|
opt_mem
|
||||||
|
select -assert-none t:$mem*
|
Loading…
Add table
Add a link
Reference in a new issue