summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorClifford Wolf <clifford@clifford.at>2015-02-14 12:55:03 +0100
committerClifford Wolf <clifford@clifford.at>2015-02-14 12:55:03 +0100
commitdcf2e242406d563254013ea7db4b29b55be96eff (patch)
treead242e2b5273a775752a2398171c178df89f9e2a
parent913c304fe62cb962e32fa0eb024fa4fc3110639c (diff)
Added $meminit support to "memory" command
-rw-r--r--kernel/rtlil.cc1
-rw-r--r--passes/memory/memory_bram.cc5
-rw-r--r--passes/memory/memory_collect.cc83
-rw-r--r--passes/memory/memory_map.cc11
-rw-r--r--techlibs/common/simlib.v18
-rw-r--r--tests/simple/memory.v23
-rw-r--r--tests/techmap/mem_simple_4x1_map.v5
7 files changed, 98 insertions, 48 deletions
diff --git a/kernel/rtlil.cc b/kernel/rtlil.cc
index 9fd3d295..c10261b2 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 8f421402..958cc88b 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<string, int> 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 ccc19620..d0d32f50 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 <sstream>
-#include <algorithm>
-#include <stdlib.h>
+#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<RTLIL::Cell*> del_cells;
std::vector<RTLIL::Cell*> 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 4fb10a98..18c60ea0 100644
--- a/passes/memory/memory_map.cc
+++ b/passes/memory/memory_map.cc
@@ -80,11 +80,15 @@ struct MemoryMapWorker
{
std::set<int> static_ports;
std::map<int, RTLIL::SigSpec> 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 6707e190..ee024051 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 f7c37309..23e93ac9 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 820f89de..868f5d00 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;