From 13b901bf1c5ac7d25ea061fc129d944ea0317150 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marcelina=20Ko=C5=9Bcielnicka?= Date: Mon, 31 May 2021 15:53:18 +0200 Subject: [PATCH] memory_map: Improve start_offset handling. Fixes #2775. --- passes/memory/memory_map.cc | 66 ++++++++++------------ tests/opt/memory_map_offset.ys | 100 +++++++++++++++++++++++++++++++++ 2 files changed, 131 insertions(+), 35 deletions(-) create mode 100644 tests/opt/memory_map_offset.ys diff --git a/passes/memory/memory_map.cc b/passes/memory/memory_map.cc index 92bbd8c15..b5ebf012e 100644 --- a/passes/memory/memory_map.cc +++ b/passes/memory/memory_map.cc @@ -155,7 +155,7 @@ struct MemoryMapWorker if (!port.clk_enable) { if (port.addr.is_fully_const() && port.en.is_fully_ones()) { for (int sub = 0; sub < (1 << port.wide_log2); sub++) - static_cells_map[port.addr.as_int() - mem.start_offset + sub] = port.data.extract(sub * mem.width, mem.width); + static_cells_map[port.addr.as_int() + sub] = port.data.extract(sub * mem.width, mem.width); static_ports.insert(i); continue; } @@ -176,22 +176,24 @@ struct MemoryMapWorker log("Mapping memory %s in module %s:\n", mem.memid.c_str(), module->name.c_str()); - std::vector data_reg_in; - std::vector data_reg_out; + int abits = ceil_log2(mem.size); + std::vector data_reg_in(1 << abits); + std::vector data_reg_out(1 << abits); int count_static = 0; for (int i = 0; i < mem.size; i++) { - if (static_cells_map.count(i) > 0) + int addr = i + mem.start_offset; + int idx = addr & ((1 << abits) - 1); + if (static_cells_map.count(addr) > 0) { - data_reg_in.push_back(RTLIL::SigSpec(RTLIL::State::Sz, mem.width)); - data_reg_out.push_back(static_cells_map[i]); + data_reg_out[idx] = static_cells_map[addr]; count_static++; } else { - RTLIL::Cell *c = module->addCell(genid(mem.memid, "", i), ID($dff)); + RTLIL::Cell *c = module->addCell(genid(mem.memid, "", addr), ID($dff)); c->parameters[ID::WIDTH] = mem.width; if (GetSize(refclock) != 0) { c->parameters[ID::CLK_POLARITY] = RTLIL::Const(refclock_pol); @@ -201,13 +203,13 @@ struct MemoryMapWorker c->setPort(ID::CLK, RTLIL::SigSpec(RTLIL::State::S0)); } - RTLIL::Wire *w_in = module->addWire(genid(mem.memid, "", i, "$d"), mem.width); - data_reg_in.push_back(RTLIL::SigSpec(w_in)); - c->setPort(ID::D, data_reg_in.back()); + RTLIL::Wire *w_in = module->addWire(genid(mem.memid, "", addr, "$d"), mem.width); + data_reg_in[idx] = w_in; + c->setPort(ID::D, w_in); - std::string w_out_name = stringf("%s[%d]", mem.memid.c_str(), i); + std::string w_out_name = stringf("%s[%d]", mem.memid.c_str(), addr); if (module->wires_.count(w_out_name) > 0) - w_out_name = genid(mem.memid, "", i, "$q"); + w_out_name = genid(mem.memid, "", addr, "$q"); RTLIL::Wire *w_out = module->addWire(w_out_name, mem.width); SigSpec w_init = init_data.extract(i*mem.width, mem.width); @@ -215,8 +217,8 @@ struct MemoryMapWorker if (!w_init.is_fully_undef()) w_out->attributes[ID::init] = w_init.as_const(); - data_reg_out.push_back(RTLIL::SigSpec(w_out)); - c->setPort(ID::Q, data_reg_out.back()); + data_reg_out[idx] = w_out; + c->setPort(ID::Q, w_out); } } @@ -224,7 +226,6 @@ struct MemoryMapWorker int count_dff = 0, count_mux = 0, count_wrmux = 0; - int abits = ceil_log2(mem.size); for (int i = 0; i < GetSize(mem.rd_ports); i++) { auto &port = mem.rd_ports[i]; @@ -233,9 +234,6 @@ struct MemoryMapWorker RTLIL::SigSpec rd_addr = port.addr; rd_addr.extend_u0(abits, false); - if (mem.start_offset) - rd_addr = module->Sub(NEW_ID, rd_addr, SigSpec(mem.start_offset, abits)); - std::vector rd_signals; rd_signals.push_back(port.data); @@ -261,31 +259,29 @@ struct MemoryMapWorker next_rd_signals.swap(rd_signals); } - for (int j = 0; j < mem.size; j++) - module->connect(RTLIL::SigSig(rd_signals[j >> port.wide_log2].extract((j & ((1 << port.wide_log2) - 1)) * mem.width, mem.width), data_reg_out[j])); + for (int j = 0; j < (1 << abits); j++) + if (data_reg_out[j] != SigSpec()) + module->connect(RTLIL::SigSig(rd_signals[j >> port.wide_log2].extract((j & ((1 << port.wide_log2) - 1)) * mem.width, mem.width), data_reg_out[j])); } log(" read interface: %d $dff and %d $mux cells.\n", count_dff, count_mux); for (int i = 0; i < mem.size; i++) { - if (static_cells_map.count(i) > 0) + int addr = i + mem.start_offset; + int idx = addr & ((1 << abits) - 1); + if (static_cells_map.count(addr) > 0) continue; - RTLIL::SigSpec sig = data_reg_out[i]; + RTLIL::SigSpec sig = data_reg_out[idx]; for (int j = 0; j < GetSize(mem.wr_ports); j++) { auto &port = mem.wr_ports[j]; - RTLIL::SigSpec wr_addr = port.addr; + RTLIL::SigSpec wr_addr = port.addr.extract_end(port.wide_log2); + RTLIL::Wire *w_seladdr = addr_decode(wr_addr, RTLIL::SigSpec(addr >> port.wide_log2, GetSize(wr_addr))); - if (mem.start_offset) - wr_addr = module->Sub(NEW_ID, wr_addr, SigSpec(mem.start_offset, GetSize(wr_addr))); - - wr_addr = wr_addr.extract_end(port.wide_log2); - RTLIL::Wire *w_seladdr = addr_decode(wr_addr, RTLIL::SigSpec(i >> port.wide_log2, GetSize(wr_addr))); - - int sub = i & ((1 << port.wide_log2) - 1); + int sub = addr & ((1 << port.wide_log2) - 1); int wr_offset = 0; while (wr_offset < mem.width) @@ -304,7 +300,7 @@ struct MemoryMapWorker if (wr_bit != State::S1) { - RTLIL::Cell *c = module->addCell(genid(mem.memid, "$wren", i, "", j, "", wr_offset), ID($and)); + RTLIL::Cell *c = module->addCell(genid(mem.memid, "$wren", addr, "", j, "", wr_offset), ID($and)); c->parameters[ID::A_SIGNED] = RTLIL::Const(0); c->parameters[ID::B_SIGNED] = RTLIL::Const(0); c->parameters[ID::A_WIDTH] = RTLIL::Const(1); @@ -313,17 +309,17 @@ struct MemoryMapWorker c->setPort(ID::A, w); c->setPort(ID::B, wr_bit); - w = module->addWire(genid(mem.memid, "$wren", i, "", j, "", wr_offset, "$y")); + w = module->addWire(genid(mem.memid, "$wren", addr, "", j, "", wr_offset, "$y")); c->setPort(ID::Y, RTLIL::SigSpec(w)); } - RTLIL::Cell *c = module->addCell(genid(mem.memid, "$wrmux", i, "", j, "", wr_offset), ID($mux)); + RTLIL::Cell *c = module->addCell(genid(mem.memid, "$wrmux", addr, "", j, "", wr_offset), ID($mux)); c->parameters[ID::WIDTH] = wr_width; c->setPort(ID::A, sig.extract(wr_offset, wr_width)); c->setPort(ID::B, port.data.extract(wr_offset + sub * mem.width, wr_width)); c->setPort(ID::S, RTLIL::SigSpec(w)); - w = module->addWire(genid(mem.memid, "$wrmux", i, "", j, "", wr_offset, "$y"), wr_width); + w = module->addWire(genid(mem.memid, "$wrmux", addr, "", j, "", wr_offset, "$y"), wr_width); c->setPort(ID::Y, w); sig.replace(wr_offset, w); @@ -332,7 +328,7 @@ struct MemoryMapWorker } } - module->connect(RTLIL::SigSig(data_reg_in[i], sig)); + module->connect(RTLIL::SigSig(data_reg_in[idx], sig)); } log(" write interface: %d write mux blocks.\n", count_wrmux); diff --git a/tests/opt/memory_map_offset.ys b/tests/opt/memory_map_offset.ys new file mode 100644 index 000000000..06969922d --- /dev/null +++ b/tests/opt/memory_map_offset.ys @@ -0,0 +1,100 @@ +read_verilog << EOT + +module top(...); + +input [3:0] ra; +input [3:0] wa; + +input [15:0] wd; +output [15:0] rd; +input en, clk; + +reg [15:0] mem[3:9]; + +always @(posedge clk) + if (en) + mem[wa] <= wd; + +assign rd = mem[ra]; + +endmodule + +EOT + +hierarchy -auto-top +proc +opt_clean +memory_map + +design -stash gate + +read_verilog << EOT + +module top(...); + +input [3:0] ra; +input [3:0] wa; + +input [15:0] wd; +output reg [15:0] rd; +input en, clk; + +reg [15:0] \mem[3] ; +reg [15:0] \mem[4] ; +reg [15:0] \mem[5] ; +reg [15:0] \mem[6] ; +reg [15:0] \mem[7] ; +reg [15:0] \mem[8] ; +reg [15:0] \mem[9] ; + +always @(posedge clk) begin + if (en && wa == 3) + \mem[3] <= wd; + if (en && wa == 4) + \mem[4] <= wd; + if (en && wa == 5) + \mem[5] <= wd; + if (en && wa == 6) + \mem[6] <= wd; + if (en && wa == 7) + \mem[7] <= wd; + if (en && wa == 8) + \mem[8] <= wd; + if (en && wa == 9) + \mem[9] <= wd; +end + +always @* begin + rd = 16'bx; + if (ra == 3) + rd = \mem[3] ; + if (ra == 4) + rd = \mem[4] ; + if (ra == 5) + rd = \mem[5] ; + if (ra == 6) + rd = \mem[6] ; + if (ra == 7) + rd = \mem[7] ; + if (ra == 8) + rd = \mem[8] ; + if (ra == 9) + rd = \mem[9] ; +end + +endmodule + +EOT + +hierarchy -auto-top +proc +opt_clean + +design -stash gold + +design -copy-from gold -as gold A:top +design -copy-from gate -as gate A:top + +equiv_make gold gate equiv +equiv_induct -undef equiv +equiv_status -assert equiv