| /* | |
| * 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/sigtools.h" | |
| #include "kernel/yosys.h" | |
| #include <bitset> | |
| #include <stdio.h> | |
| #include <stdlib.h> | |
| USING_YOSYS_NAMESPACE | |
| PRIVATE_NAMESPACE_BEGIN | |
| static void run_pp3_braminit(Module *module) | |
| { | |
| for (auto cell : module->selected_cells()) { | |
| uint32_t mem[2048]; | |
| int32_t ramDataWidth = 32; | |
| int32_t ramDataDepth = 512; | |
| log("cell type %s\n", RTLIL::id2cstr(cell->name)); | |
| /* Only consider cells we're interested in */ | |
| if (cell->type != ID(RAM_16K_BLK) && cell->type != ID(RAM_8K_BLK)) | |
| continue; | |
| log("found ram block\n"); | |
| if (!cell->hasParam(ID(INIT_FILE))) | |
| continue; | |
| std::string init_file = cell->getParam(ID(INIT_FILE)).decode_string(); | |
| cell->unsetParam(ID(INIT_FILE)); | |
| if (init_file == "") | |
| continue; | |
| /* Open file */ | |
| log("Processing %s : %s\n", RTLIL::id2cstr(cell->name), init_file.c_str()); | |
| ramDataWidth = cell->getParam(ID(data_width_int)).as_int(); | |
| ramDataDepth = cell->getParam(ID(data_depth_int)).as_int(); | |
| 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 < ramDataDepth) | |
| mem[cursor++] = value; | |
| else | |
| log("Attempt to initialize non existent address %d\n", cursor); | |
| } | |
| } | |
| // TODO: Support RAM initialization for other widths than 8, 16 and 32 | |
| if (ramDataWidth != 8 && ramDataWidth != 16 && ramDataWidth != 32) { | |
| log("WARNING: The RAM cell '%s' has data width of %d. Initialization of this width from a file is not supported yet!\n", | |
| RTLIL::id2cstr(cell->name), ramDataWidth); | |
| continue; | |
| } | |
| /* Set attributes */ | |
| std::string val = ""; | |
| for (int i = ramDataDepth - 1; i >= 0; i--) { | |
| if (ramDataWidth == 8) | |
| val += std::bitset<8>(mem[i]).to_string(); | |
| else if (ramDataWidth == 16) | |
| val += std::bitset<16>(mem[i]).to_string(); | |
| else if (ramDataWidth == 32) | |
| val += std::bitset<32>(mem[i]).to_string(); | |
| } | |
| cell->setParam(RTLIL::escape_id("INIT"), RTLIL::Const::from_string(val)); | |
| } | |
| } | |
| struct PP3BRAMInitPass : public Pass { | |
| PP3BRAMInitPass() : Pass("pp3_braminit", "PP3: perform RAM Block initialization from file") {} | |
| void help() override | |
| { | |
| // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---| | |
| log("\n"); | |
| log(" pp3_braminit\n"); | |
| log("\n"); | |
| log("This command processes all PP3 RAM blocks with a non-empty INIT_FILE\n"); | |
| log("parameter and converts it into the required INIT attributes\n"); | |
| log("\n"); | |
| } | |
| void execute(std::vector<std::string> args, RTLIL::Design *design) override | |
| { | |
| log_header(design, "Executing PP3_BRAMINIT pass.\n"); | |
| extra_args(args, 1, design); | |
| for (auto module : design->selected_modules()) | |
| run_pp3_braminit(module); | |
| } | |
| } PP3BRAMInitPass; | |
| PRIVATE_NAMESPACE_END |