| /* | |
| * 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.compare(i, 2, "*/") == 0) { | |
| line[i] = ' '; | |
| line[i+1] = ' '; | |
| in_comment = false; | |
| continue; | |
| } | |
| if (!in_comment && line.compare(i, 2, "/*") == 0) | |
| 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.compare(0, 2, "//") == 0) | |
| 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 into 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 |