blob: 459f3cfc6f57ff17be20d35e3e1731be12a23784 [file] [log] [blame]
/*
* Copyright 2020-2022 F4PGA Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* SPDX-License-Identifier: Apache-2.0
*
*/
#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