Added $meminit support to "memory" command
authorClifford Wolf <clifford@clifford.at>
Sat, 14 Feb 2015 11:55:03 +0000 (12:55 +0100)
committerClifford Wolf <clifford@clifford.at>
Sat, 14 Feb 2015 11:55:03 +0000 (12:55 +0100)
kernel/rtlil.cc
passes/memory/memory_bram.cc
passes/memory/memory_collect.cc
passes/memory/memory_map.cc
techlibs/common/simlib.v
tests/simple/memory.v
tests/techmap/mem_simple_4x1_map.v

index 9fd3d29593dbf6d3fd018d3f9e110e0e4df1cc08..c10261b23772524d3736a13749a10509bf5697fd 100644 (file)
@@ -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"));
index 8f421402787ee302781edafde6b28c1ade84255b..958cc88b4d2a22694a6506fdbd7d6ffc1b2ea6d9 100644 (file)
@@ -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();
index ccc19620200a2c26b01166f313e7fe12835e474c..d0d32f504d3b116df4680e8637133707d45fa812 100644 (file)
  *
  */
 
-#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);
 }
 
index 4fb10a989a8fc52fe37640ac10c92e39e22db283..18c60ea074b052d033f2914779f966ba417abd79 100644 (file)
@@ -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());
index 6707e190bdd98d1b93133b055e26f0520c2491d7..ee024051b13cb33ec7fef077d09037c6cb038e39 100644 (file)
@@ -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;
index f7c37309c7eef0ce503e9bcaff95409e93e49d80..23e93ac91a38acb391ee4962c6ea7bd8a6168b74 100644 (file)
@@ -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
 
index 820f89de4bda450e5273a982ea19dda5472a4d62..868f5d00cdade2fee8011e8af4c1109948df74dc 100644 (file)
@@ -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;