ice40: Add ice40_braminit pass to allow initialization of BRAM from file
authorSylvain Munaut <tnt@246tNt.com>
Thu, 7 Mar 2019 22:48:10 +0000 (23:48 +0100)
committerSylvain Munaut <tnt@246tNt.com>
Thu, 7 Mar 2019 23:15:46 +0000 (00:15 +0100)
This adds a INIT_FILE attribute to the SB_RAM40_4K blocks that will
initialize content from a hex file. Same behavior is imlemented in the
simulation model and in a new pass for actual synthesis

Signed-off-by: Sylvain Munaut <tnt@246tNt.com>
techlibs/ice40/Makefile.inc
techlibs/ice40/cells_sim.v
techlibs/ice40/ice40_braminit.cc [new file with mode: 0644]

index 2750901c8bcc3b419726c658b552c3a444ea021f..723b59d6f661b8e7e16477031b68373a43e35524 100644 (file)
@@ -1,5 +1,6 @@
 
 OBJS += techlibs/ice40/synth_ice40.o
+OBJS += techlibs/ice40/ice40_braminit.o
 OBJS += techlibs/ice40/ice40_ffssr.o
 OBJS += techlibs/ice40/ice40_ffinit.o
 OBJS += techlibs/ice40/ice40_opt.o
index 2041693cc6c213fd577e0b6a4952219559272e84..bc36cdd14624837ab16a39c8bacb9a7b2a6e3061 100644 (file)
@@ -326,6 +326,8 @@ module SB_RAM40_4K (
        parameter INIT_E = 256'h0000000000000000000000000000000000000000000000000000000000000000;
        parameter INIT_F = 256'h0000000000000000000000000000000000000000000000000000000000000000;
 
+       parameter INIT_FILE = "";
+
 `ifndef BLACKBOX
        wire [15:0] WMASK_I;
        wire [15:0] RMASK_I;
@@ -408,43 +410,46 @@ module SB_RAM40_4K (
        reg [15:0] memory [0:255];
 
        initial begin
-               for (i=0; i<16; i=i+1) begin
+               if (INIT_FILE != "")
+                       $readmemh(INIT_FILE, memory);
+               else
+                       for (i=0; i<16; i=i+1) begin
 `ifdef YOSYS
-                       memory[ 0*16 + i] <= INIT_0[16*i +: 16];
-                       memory[ 1*16 + i] <= INIT_1[16*i +: 16];
-                       memory[ 2*16 + i] <= INIT_2[16*i +: 16];
-                       memory[ 3*16 + i] <= INIT_3[16*i +: 16];
-                       memory[ 4*16 + i] <= INIT_4[16*i +: 16];
-                       memory[ 5*16 + i] <= INIT_5[16*i +: 16];
-                       memory[ 6*16 + i] <= INIT_6[16*i +: 16];
-                       memory[ 7*16 + i] <= INIT_7[16*i +: 16];
-                       memory[ 8*16 + i] <= INIT_8[16*i +: 16];
-                       memory[ 9*16 + i] <= INIT_9[16*i +: 16];
-                       memory[10*16 + i] <= INIT_A[16*i +: 16];
-                       memory[11*16 + i] <= INIT_B[16*i +: 16];
-                       memory[12*16 + i] <= INIT_C[16*i +: 16];
-                       memory[13*16 + i] <= INIT_D[16*i +: 16];
-                       memory[14*16 + i] <= INIT_E[16*i +: 16];
-                       memory[15*16 + i] <= INIT_F[16*i +: 16];
+                               memory[ 0*16 + i] <= INIT_0[16*i +: 16];
+                               memory[ 1*16 + i] <= INIT_1[16*i +: 16];
+                               memory[ 2*16 + i] <= INIT_2[16*i +: 16];
+                               memory[ 3*16 + i] <= INIT_3[16*i +: 16];
+                               memory[ 4*16 + i] <= INIT_4[16*i +: 16];
+                               memory[ 5*16 + i] <= INIT_5[16*i +: 16];
+                               memory[ 6*16 + i] <= INIT_6[16*i +: 16];
+                               memory[ 7*16 + i] <= INIT_7[16*i +: 16];
+                               memory[ 8*16 + i] <= INIT_8[16*i +: 16];
+                               memory[ 9*16 + i] <= INIT_9[16*i +: 16];
+                               memory[10*16 + i] <= INIT_A[16*i +: 16];
+                               memory[11*16 + i] <= INIT_B[16*i +: 16];
+                               memory[12*16 + i] <= INIT_C[16*i +: 16];
+                               memory[13*16 + i] <= INIT_D[16*i +: 16];
+                               memory[14*16 + i] <= INIT_E[16*i +: 16];
+                               memory[15*16 + i] <= INIT_F[16*i +: 16];
 `else
-                       memory[ 0*16 + i] = INIT_0[16*i +: 16];
-                       memory[ 1*16 + i] = INIT_1[16*i +: 16];
-                       memory[ 2*16 + i] = INIT_2[16*i +: 16];
-                       memory[ 3*16 + i] = INIT_3[16*i +: 16];
-                       memory[ 4*16 + i] = INIT_4[16*i +: 16];
-                       memory[ 5*16 + i] = INIT_5[16*i +: 16];
-                       memory[ 6*16 + i] = INIT_6[16*i +: 16];
-                       memory[ 7*16 + i] = INIT_7[16*i +: 16];
-                       memory[ 8*16 + i] = INIT_8[16*i +: 16];
-                       memory[ 9*16 + i] = INIT_9[16*i +: 16];
-                       memory[10*16 + i] = INIT_A[16*i +: 16];
-                       memory[11*16 + i] = INIT_B[16*i +: 16];
-                       memory[12*16 + i] = INIT_C[16*i +: 16];
-                       memory[13*16 + i] = INIT_D[16*i +: 16];
-                       memory[14*16 + i] = INIT_E[16*i +: 16];
-                       memory[15*16 + i] = INIT_F[16*i +: 16];
+                               memory[ 0*16 + i] = INIT_0[16*i +: 16];
+                               memory[ 1*16 + i] = INIT_1[16*i +: 16];
+                               memory[ 2*16 + i] = INIT_2[16*i +: 16];
+                               memory[ 3*16 + i] = INIT_3[16*i +: 16];
+                               memory[ 4*16 + i] = INIT_4[16*i +: 16];
+                               memory[ 5*16 + i] = INIT_5[16*i +: 16];
+                               memory[ 6*16 + i] = INIT_6[16*i +: 16];
+                               memory[ 7*16 + i] = INIT_7[16*i +: 16];
+                               memory[ 8*16 + i] = INIT_8[16*i +: 16];
+                               memory[ 9*16 + i] = INIT_9[16*i +: 16];
+                               memory[10*16 + i] = INIT_A[16*i +: 16];
+                               memory[11*16 + i] = INIT_B[16*i +: 16];
+                               memory[12*16 + i] = INIT_C[16*i +: 16];
+                               memory[13*16 + i] = INIT_D[16*i +: 16];
+                               memory[14*16 + i] = INIT_E[16*i +: 16];
+                               memory[15*16 + i] = INIT_F[16*i +: 16];
 `endif
-               end
+                       end
        end
 
        always @(posedge WCLK) begin
@@ -504,6 +509,8 @@ module SB_RAM40_4KNR (
        parameter INIT_E = 256'h0000000000000000000000000000000000000000000000000000000000000000;
        parameter INIT_F = 256'h0000000000000000000000000000000000000000000000000000000000000000;
 
+       parameter INIT_FILE = "";
+
        SB_RAM40_4K #(
                .WRITE_MODE(WRITE_MODE),
                .READ_MODE (READ_MODE ),
@@ -522,7 +529,8 @@ module SB_RAM40_4KNR (
                .INIT_C    (INIT_C    ),
                .INIT_D    (INIT_D    ),
                .INIT_E    (INIT_E    ),
-               .INIT_F    (INIT_F    )
+               .INIT_F    (INIT_F    ),
+               .INIT_FILE (INIT_FILE )
        ) RAM (
                .RDATA(RDATA),
                .RCLK (~RCLKN),
@@ -566,6 +574,8 @@ module SB_RAM40_4KNW (
        parameter INIT_E = 256'h0000000000000000000000000000000000000000000000000000000000000000;
        parameter INIT_F = 256'h0000000000000000000000000000000000000000000000000000000000000000;
 
+       parameter INIT_FILE = "";
+
        SB_RAM40_4K #(
                .WRITE_MODE(WRITE_MODE),
                .READ_MODE (READ_MODE ),
@@ -584,7 +594,8 @@ module SB_RAM40_4KNW (
                .INIT_C    (INIT_C    ),
                .INIT_D    (INIT_D    ),
                .INIT_E    (INIT_E    ),
-               .INIT_F    (INIT_F    )
+               .INIT_F    (INIT_F    ),
+               .INIT_FILE (INIT_FILE )
        ) RAM (
                .RDATA(RDATA),
                .RCLK (RCLK ),
@@ -628,6 +639,8 @@ module SB_RAM40_4KNRNW (
        parameter INIT_E = 256'h0000000000000000000000000000000000000000000000000000000000000000;
        parameter INIT_F = 256'h0000000000000000000000000000000000000000000000000000000000000000;
 
+       parameter INIT_FILE = "";
+
        SB_RAM40_4K #(
                .WRITE_MODE(WRITE_MODE),
                .READ_MODE (READ_MODE ),
@@ -646,7 +659,8 @@ module SB_RAM40_4KNRNW (
                .INIT_C    (INIT_C    ),
                .INIT_D    (INIT_D    ),
                .INIT_E    (INIT_E    ),
-               .INIT_F    (INIT_F    )
+               .INIT_F    (INIT_F    ),
+               .INIT_FILE (INIT_FILE )
        ) RAM (
                .RDATA(RDATA),
                .RCLK (~RCLKN),
diff --git a/techlibs/ice40/ice40_braminit.cc b/techlibs/ice40/ice40_braminit.cc
new file mode 100644 (file)
index 0000000..bf12f91
--- /dev/null
@@ -0,0 +1,159 @@
+/*
+ *  yosys -- Yosys Open SYnthesis Suite
+ *
+ *  Copyright (C) 2012  Clifford Wolf <clifford@clifford.at>
+ *
+ *  Permission to use, copy, modify, and/or distribute this software for any
+ *  purpose with or without fee is hereby granted, provided that the above
+ *  copyright notice and this permission notice appear in all copies.
+ *
+ *  THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ *  WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ *  MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ *  ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ *  WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ *  ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ *  OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ */
+
+#include "kernel/yosys.h"
+#include "kernel/sigtools.h"
+#include <stdlib.h>
+#include <stdio.h>
+#include <bitset>
+
+USING_YOSYS_NAMESPACE
+PRIVATE_NAMESPACE_BEGIN
+
+static void run_ice40_braminit(Module *module)
+{
+       for (auto cell : module->selected_cells())
+       {
+               uint16_t mem[256];
+
+               /* Only consider cells we're interested in */
+               if (cell->type != "\\SB_RAM40_4K" &&
+                   cell->type != "\\SB_RAM40_4KNR" &&
+                   cell->type != "\\SB_RAM40_4KNW" &&
+                   cell->type != "\\SB_RAM40_4KNRNW")
+                       continue;
+               if (!cell->hasParam("\\INIT_FILE"))
+                       continue;
+               std::string init_file = cell->getParam("\\INIT_FILE").decode_string();
+               cell->unsetParam("\\INIT_FILE");
+               if (init_file == "")
+                       continue;
+
+               /* Open file */
+               log("Processing %s : %s\n", RTLIL::id2cstr(cell->name), init_file.c_str());
+
+               std::ifstream f;
+               f.open(init_file.c_str());
+               if (f.fail()) {
+                       log("Can not open file `%s`.\n", init_file.c_str());
+                       continue;
+               }
+
+               /* Defaults to 0 */
+               memset(mem, 0x00, sizeof(mem));
+
+               /* Process each line */
+               bool in_comment = false;
+               int cursor = 0;
+
+               while (!f.eof())
+               {
+                       std::string line, token;
+                       std::getline(f, line);
+
+                       for (int i = 0; i < GetSize(line); i++)
+                       {
+                               if (in_comment && line.substr(i, 2) == "*/") {
+                                       line[i] = ' ';
+                                       line[i+1] = ' ';
+                                       in_comment = false;
+                                       continue;
+                               }
+                               if (!in_comment && line.substr(i, 2) == "/*")
+                                       in_comment = true;
+                               if (in_comment)
+                                       line[i] = ' ';
+                       }
+
+                       while (1)
+                       {
+                               bool set_cursor = false;
+                               long value;
+
+                               token = next_token(line, " \t\r\n");
+                               if (token.empty() || token.substr(0, 2) == "//")
+                                       break;
+
+                               if (token[0] == '@') {
+                                       token = token.substr(1);
+                                       set_cursor = true;
+                               }
+
+                               const char *nptr = token.c_str();
+                               char *endptr;
+                               value = strtol(nptr, &endptr, 16);
+                               if (!*nptr || *endptr) {
+                                       log("Can not parse %s `%s` for %s.\n",
+                                               set_cursor ? "address" : "value",
+                                               nptr, token.c_str()
+                                       );
+                                       continue;
+                               }
+
+                               if (set_cursor)
+                                       cursor = value;
+                               else if (cursor >= 0 && cursor < 256)
+                                       mem[cursor++] = value;
+                               else
+                                       log("Attempt to initialize non existent address %d\n", cursor);
+                       }
+               }
+
+               /* Set attributes */
+               const char *hex = "0123456789ABCDEF";
+               for (int i=0; i<16; i++) {
+                       std::string val = "";
+                       for (int j=15; j>=0; j--)
+                               val += std::bitset<16>(mem[i*16+j]).to_string();
+                       cell->setParam("\\INIT_" + std::string(1, hex[i]), RTLIL::Const::from_string(val));
+               }
+       }
+}
+
+struct Ice40BRAMInitPass : public Pass {
+       Ice40BRAMInitPass() : Pass("ice40_braminit", "iCE40: perform SB_RAM40_4K initialization from file") { }
+       void help() YS_OVERRIDE
+       {
+               //   |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
+               log("\n");
+               log("    ice40_braminit\n");
+               log("\n");
+               log("This command processes all SB_RAM40_4K blocks with a non-empty INIT_FILE\n");
+               log("parameter and converts it inti the required INIT_x attributes\n");
+               log("\n");
+       }
+       void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
+       {
+               log_header(design, "Executing ICE40_BRAMINIT pass.\n");
+
+               size_t argidx;
+               for (argidx = 1; argidx < args.size(); argidx++) {
+                       // if (args[argidx] == "-???") {
+                       //  continue;
+                       // }
+                       break;
+               }
+               extra_args(args, argidx, design);
+
+               for (auto module : design->selected_modules())
+                       run_ice40_braminit(module);
+       }
+} Ice40BRAMInitPass;
+
+PRIVATE_NAMESPACE_END