From dcf2e242406d563254013ea7db4b29b55be96eff Mon Sep 17 00:00:00 2001 From: Clifford Wolf Date: Sat, 14 Feb 2015 12:55:03 +0100 Subject: [PATCH] Added $meminit support to "memory" command --- kernel/rtlil.cc | 1 + passes/memory/memory_bram.cc | 5 ++ passes/memory/memory_collect.cc | 83 ++++++++++++++++++++---------- passes/memory/memory_map.cc | 11 +++- techlibs/common/simlib.v | 18 +++++-- tests/simple/memory.v | 23 +++------ tests/techmap/mem_simple_4x1_map.v | 5 ++ 7 files changed, 98 insertions(+), 48 deletions(-) diff --git a/kernel/rtlil.cc b/kernel/rtlil.cc index 9fd3d2959..c10261b23 100644 --- a/kernel/rtlil.cc +++ b/kernel/rtlil.cc @@ -917,6 +917,7 @@ namespace { param("\\MEMID"); param("\\SIZE"); param("\\OFFSET"); + param("\\INIT"); param_bits("\\RD_CLK_ENABLE", param("\\RD_PORTS")); param_bits("\\RD_CLK_POLARITY", param("\\RD_PORTS")); param_bits("\\RD_TRANSPARENT", param("\\RD_PORTS")); diff --git a/passes/memory/memory_bram.cc b/passes/memory/memory_bram.cc index 8f4214027..958cc88b4 100644 --- a/passes/memory/memory_bram.cc +++ b/passes/memory/memory_bram.cc @@ -905,6 +905,11 @@ void handle_cell(Cell *cell, const rules_t &rules) { log("Processing %s.%s:\n", log_id(cell->module), log_id(cell)); + if (!SigSpec(cell->getParam("\\INIT")).is_fully_undef()) { + log(" initialized memories are not supported yet."); + return; + } + dict match_properties; match_properties["words"] = cell->getParam("\\SIZE").as_int(); match_properties["abits"] = cell->getParam("\\ABITS").as_int(); diff --git a/passes/memory/memory_collect.cc b/passes/memory/memory_collect.cc index ccc196202..d0d32f504 100644 --- a/passes/memory/memory_collect.cc +++ b/passes/memory/memory_collect.cc @@ -17,11 +17,8 @@ * */ -#include "kernel/register.h" -#include "kernel/log.h" -#include -#include -#include +#include "kernel/yosys.h" +#include "kernel/sigtools.h" USING_YOSYS_NAMESPACE PRIVATE_NAMESPACE_BEGIN @@ -37,13 +34,16 @@ bool memcells_cmp(RTLIL::Cell *a, RTLIL::Cell *b) void handle_memory(RTLIL::Module *module, RTLIL::Memory *memory) { - log("Collecting $memrd and $memwr for memory `%s' in module `%s':\n", + log("Collecting $memrd, $memwr and $meminit for memory `%s' in module `%s':\n", memory->name.c_str(), module->name.c_str()); int addr_bits = 0; while ((1 << addr_bits) < memory->size) addr_bits++; + Const init_data(State::Sx, memory->size * memory->width); + SigMap sigmap(module); + int wr_ports = 0; RTLIL::SigSpec sig_wr_clk; RTLIL::SigSpec sig_wr_clk_enable; @@ -60,12 +60,11 @@ void handle_memory(RTLIL::Module *module, RTLIL::Memory *memory) RTLIL::SigSpec sig_rd_addr; RTLIL::SigSpec sig_rd_data; - std::vector del_cells; std::vector memcells; for (auto &cell_it : module->cells_) { RTLIL::Cell *cell = cell_it.second; - if ((cell->type == "$memwr" || cell->type == "$memrd") && memory->name == cell->parameters["\\MEMID"].decode_string()) + if (cell->type.in("$memrd", "$memwr", "$meminit") && memory->name == cell->parameters["\\MEMID"].decode_string()) memcells.push_back(cell); } @@ -73,17 +72,38 @@ void handle_memory(RTLIL::Module *module, RTLIL::Memory *memory) for (auto cell : memcells) { - if (cell->type == "$memwr" && memory->name == cell->parameters["\\MEMID"].decode_string()) + log(" %s (%s)\n", log_id(cell), log_id(cell->type)); + + if (cell->type == "$meminit") { - wr_ports++; - del_cells.push_back(cell); + SigSpec addr = sigmap(cell->getPort("\\ADDR")); + SigSpec data = sigmap(cell->getPort("\\DATA")); + + if (!addr.is_fully_const()) + log_error("Non-constant address %s in memory initialization %s.\n", log_signal(addr), log_id(cell)); + if (!data.is_fully_const()) + log_error("Non-constant data %s in memory initialization %s.\n", log_signal(data), log_id(cell)); + + int offset = (addr.as_int() - memory->start_offset) * memory->width; - RTLIL::SigSpec clk = cell->getPort("\\CLK"); - RTLIL::SigSpec clk_enable = RTLIL::SigSpec(cell->parameters["\\CLK_ENABLE"]); - RTLIL::SigSpec clk_polarity = RTLIL::SigSpec(cell->parameters["\\CLK_POLARITY"]); - RTLIL::SigSpec addr = cell->getPort("\\ADDR"); - RTLIL::SigSpec data = cell->getPort("\\DATA"); - RTLIL::SigSpec en = cell->getPort("\\EN"); + if (offset < 0 || offset + GetSize(data) > GetSize(init_data)) + log_warning("Address %s in memory initialization %s is out-of-bounds.\n", log_signal(addr), log_id(cell)); + + for (int i = 0; i < GetSize(data); i++) + if (0 <= i+offset && i+offset < GetSize(init_data)) + init_data.bits[i+offset] = data[i].data; + + continue; + } + + if (cell->type == "$memwr") + { + SigSpec clk = sigmap(cell->getPort("\\CLK")); + SigSpec clk_enable = RTLIL::SigSpec(cell->parameters["\\CLK_ENABLE"]); + SigSpec clk_polarity = RTLIL::SigSpec(cell->parameters["\\CLK_POLARITY"]); + SigSpec addr = sigmap(cell->getPort("\\ADDR")); + SigSpec data = sigmap(cell->getPort("\\DATA")); + SigSpec en = sigmap(cell->getPort("\\EN")); clk.extend_u0(1, false); clk_enable.extend_u0(1, false); @@ -98,19 +118,19 @@ void handle_memory(RTLIL::Module *module, RTLIL::Memory *memory) sig_wr_addr.append(addr); sig_wr_data.append(data); sig_wr_en.append(en); + + wr_ports++; + continue; } - if (cell->type == "$memrd" && memory->name == cell->parameters["\\MEMID"].decode_string()) + if (cell->type == "$memrd") { - rd_ports++; - del_cells.push_back(cell); - - RTLIL::SigSpec clk = cell->getPort("\\CLK"); - RTLIL::SigSpec clk_enable = RTLIL::SigSpec(cell->parameters["\\CLK_ENABLE"]); - RTLIL::SigSpec clk_polarity = RTLIL::SigSpec(cell->parameters["\\CLK_POLARITY"]); - RTLIL::SigSpec transparent = RTLIL::SigSpec(cell->parameters["\\TRANSPARENT"]); - RTLIL::SigSpec addr = cell->getPort("\\ADDR"); - RTLIL::SigSpec data = cell->getPort("\\DATA"); + SigSpec clk = sigmap(cell->getPort("\\CLK")); + SigSpec clk_enable = RTLIL::SigSpec(cell->parameters["\\CLK_ENABLE"]); + SigSpec clk_polarity = RTLIL::SigSpec(cell->parameters["\\CLK_POLARITY"]); + SigSpec transparent = RTLIL::SigSpec(cell->parameters["\\TRANSPARENT"]); + SigSpec addr = sigmap(cell->getPort("\\ADDR")); + SigSpec data = sigmap(cell->getPort("\\DATA")); clk.extend_u0(1, false); clk_enable.extend_u0(1, false); @@ -125,6 +145,9 @@ void handle_memory(RTLIL::Module *module, RTLIL::Memory *memory) sig_rd_transparent.append(transparent); sig_rd_addr.append(addr); sig_rd_data.append(data); + + rd_ports++; + continue; } } @@ -138,6 +161,10 @@ void handle_memory(RTLIL::Module *module, RTLIL::Memory *memory) mem->parameters["\\SIZE"] = RTLIL::Const(memory->size); mem->parameters["\\ABITS"] = RTLIL::Const(addr_bits); + while (GetSize(init_data) > 1 && init_data.bits.back() == State::Sx && init_data.bits[GetSize(init_data)-2] == State::Sx) + init_data.bits.pop_back(); + mem->parameters["\\INIT"] = init_data; + log_assert(sig_wr_clk.size() == wr_ports); log_assert(sig_wr_clk_enable.size() == wr_ports && sig_wr_clk_enable.is_fully_const()); log_assert(sig_wr_clk_polarity.size() == wr_ports && sig_wr_clk_polarity.is_fully_const()); @@ -169,7 +196,7 @@ void handle_memory(RTLIL::Module *module, RTLIL::Memory *memory) mem->setPort("\\RD_ADDR", sig_rd_addr); mem->setPort("\\RD_DATA", sig_rd_data); - for (auto c : del_cells) + for (auto c : memcells) module->remove(c); } diff --git a/passes/memory/memory_map.cc b/passes/memory/memory_map.cc index 4fb10a989..18c60ea07 100644 --- a/passes/memory/memory_map.cc +++ b/passes/memory/memory_map.cc @@ -80,11 +80,15 @@ struct MemoryMapWorker { std::set static_ports; std::map static_cells_map; + int mem_size = cell->parameters["\\SIZE"].as_int(); int mem_width = cell->parameters["\\WIDTH"].as_int(); - int mem_offset = cell->parameters["\\OFFSET"].as_int(); + // int mem_offset = cell->parameters["\\OFFSET"].as_int(); int mem_abits = cell->parameters["\\ABITS"].as_int(); + SigSpec init_data = cell->getParam("\\INIT"); + init_data.extend_u0(mem_size*mem_width, true); + // delete unused memory cell if (cell->parameters["\\RD_PORTS"].as_int() == 0 && cell->parameters["\\WR_PORTS"].as_int() == 0) { module->remove(cell); @@ -165,7 +169,10 @@ struct MemoryMapWorker w_out_name = genid(cell->name, "", i, "$q"); RTLIL::Wire *w_out = module->addWire(w_out_name, mem_width); - w_out->start_offset = mem_offset; + SigSpec w_init = init_data.extract(i*mem_width, mem_width); + + if (!w_init.is_fully_undef()) + w_out->attributes["\\init"] = w_init.as_const(); data_reg_out.push_back(RTLIL::SigSpec(w_out)); c->setPort("\\Q", data_reg_out.back()); diff --git a/techlibs/common/simlib.v b/techlibs/common/simlib.v index 6707e190b..ee024051b 100644 --- a/techlibs/common/simlib.v +++ b/techlibs/common/simlib.v @@ -1543,6 +1543,7 @@ parameter SIZE = 256; parameter OFFSET = 0; parameter ABITS = 8; parameter WIDTH = 8; +parameter signed INIT = 1'bx; parameter RD_PORTS = 1; parameter RD_CLK_ENABLE = 1'b1; @@ -1583,25 +1584,36 @@ function port_active; end endfunction +initial begin + for (i = 0; i < SIZE; i = i+1) + memory[i] = INIT >>> (i*WIDTH); +end + always @(RD_CLK, RD_ADDR, RD_DATA, WR_CLK, WR_EN, WR_ADDR, WR_DATA) begin `ifdef SIMLIB_MEMDELAY #`SIMLIB_MEMDELAY; `endif for (i = 0; i < RD_PORTS; i = i+1) begin - if ((!RD_TRANSPARENT[i] && RD_CLK_ENABLE[i]) && port_active(RD_CLK_ENABLE[i], RD_CLK_POLARITY[i], LAST_RD_CLK[i], RD_CLK[i])) + if ((!RD_TRANSPARENT[i] && RD_CLK_ENABLE[i]) && port_active(RD_CLK_ENABLE[i], RD_CLK_POLARITY[i], LAST_RD_CLK[i], RD_CLK[i])) begin + // $display("Read from %s: addr=%b data=%b", MEMID, RD_ADDR[i*ABITS +: ABITS], memory[RD_ADDR[i*ABITS +: ABITS] - OFFSET]); RD_DATA[i*WIDTH +: WIDTH] <= memory[RD_ADDR[i*ABITS +: ABITS] - OFFSET]; + end end for (i = 0; i < WR_PORTS; i = i+1) begin if (port_active(WR_CLK_ENABLE[i], WR_CLK_POLARITY[i], LAST_WR_CLK[i], WR_CLK[i])) for (j = 0; j < WIDTH; j = j+1) - if (WR_EN[i*WIDTH+j]) + if (WR_EN[i*WIDTH+j]) begin + // $display("Write to %s: addr=%b data=%b", MEMID, WR_ADDR[i*ABITS +: ABITS], WR_DATA[i*WIDTH+j]); memory[WR_ADDR[i*ABITS +: ABITS] - OFFSET][j] = WR_DATA[i*WIDTH+j]; + end end for (i = 0; i < RD_PORTS; i = i+1) begin - if ((RD_TRANSPARENT[i] || !RD_CLK_ENABLE[i]) && port_active(RD_CLK_ENABLE[i], RD_CLK_POLARITY[i], LAST_RD_CLK[i], RD_CLK[i])) + if ((RD_TRANSPARENT[i] || !RD_CLK_ENABLE[i]) && port_active(RD_CLK_ENABLE[i], RD_CLK_POLARITY[i], LAST_RD_CLK[i], RD_CLK[i])) begin + // $display("Transparent read from %s: addr=%b data=%b", MEMID, RD_ADDR[i*ABITS +: ABITS], memory[RD_ADDR[i*ABITS +: ABITS] - OFFSET]); RD_DATA[i*WIDTH +: WIDTH] <= memory[RD_ADDR[i*ABITS +: ABITS] - OFFSET]; + end end LAST_RD_CLK <= RD_CLK; diff --git a/tests/simple/memory.v b/tests/simple/memory.v index f7c37309c..23e93ac91 100644 --- a/tests/simple/memory.v +++ b/tests/simple/memory.v @@ -209,29 +209,22 @@ endmodule module memtest09 ( input clk, - input [1:0] a_addr, a_din, b_addr, b_din, + input [3:0] a_addr, a_din, b_addr, b_din, input a_wen, b_wen, - output reg [1:0] a_dout, b_dout + output reg [3:0] a_dout, b_dout ); - reg [1:0] memory [0:3]; - - initial begin - memory[0] <= 0; - memory[1] <= 1; - memory[2] <= 2; - memory[3] <= 3; - end + reg [3:0] memory [0:35]; always @(posedge clk) begin if (a_wen) - memory[a_addr] <= a_din; - a_dout <= memory[a_addr]; + memory[10 + a_addr] <= a_din; + a_dout <= memory[10 + a_addr]; end always @(posedge clk) begin - if (b_wen) - memory[b_addr] <= b_din; - b_dout <= memory[b_addr]; + if (b_wen && (10 + a_addr != 20 + b_addr)) + memory[20 + b_addr] <= b_din; + b_dout <= memory[20 + b_addr]; end endmodule diff --git a/tests/techmap/mem_simple_4x1_map.v b/tests/techmap/mem_simple_4x1_map.v index 820f89de4..868f5d00c 100644 --- a/tests/techmap/mem_simple_4x1_map.v +++ b/tests/techmap/mem_simple_4x1_map.v @@ -5,6 +5,7 @@ module \$mem (RD_CLK, RD_ADDR, RD_DATA, WR_CLK, WR_EN, WR_ADDR, WR_DATA); parameter OFFSET = 0; parameter ABITS = 8; parameter WIDTH = 8; + parameter signed INIT = 1'bx; parameter RD_PORTS = 1; parameter RD_CLK_ENABLE = 1'b1; @@ -37,6 +38,10 @@ module \$mem (RD_CLK, RD_ADDR, RD_DATA, WR_CLK, WR_EN, WR_ADDR, WR_DATA); initial begin _TECHMAP_FAIL_ <= 0; + // no initialized memories + if (INIT !== 1'bx) + _TECHMAP_FAIL_ <= 1; + // only map cells with only one read and one write port if (RD_PORTS > 1 || WR_PORTS > 1) _TECHMAP_FAIL_ <= 1; -- 2.30.2