Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions ql-qlf-plugin/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ SOURCES = synth_quicklogic.cc \
ql-edif.cc \
ql-dsp-simd.cc \
ql-dsp-macc.cc \
ql-bram-initfile.cc \
ql-bram-split.cc \
ql-bram-merge.cc \
ql-dsp-io-regs.cc \
Expand Down
201 changes: 201 additions & 0 deletions ql-qlf-plugin/ql-bram-initfile.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,201 @@
/*
* yosys -- Yosys Open SYnthesis Suite
*
* Copyright (C) 2023 Martin Povišer <[email protected]>
*
* 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/register.h"

USING_YOSYS_NAMESPACE
PRIVATE_NAMESPACE_BEGIN

#define QL_HEXFILE_BITSTRIDE 36

std::string hexdump(std::vector<State>::iterator start, std::vector<State>::iterator end)
{
std::string ret;
ret.reserve(9);
for (auto p = start; p != end;) {
auto ne = p + 4;
int nibble = 0;
for (int i = 0; p != end && p != ne; p++, i++)
if (*p == State::S1)
nibble |= 1 << i;
ret += (nibble < 10 ? '0' + nibble : 'A' - 10 + nibble);
}
return ret;
}

void write_hex(const char *name, std::ostream &s, Const data)
{
log_assert(data.size() % QL_HEXFILE_BITSTRIDE == 0);
for (auto p = data.bits.begin(); p != data.bits.end(); p += QL_HEXFILE_BITSTRIDE)
s << hexdump(p, p + 36) << "\n";

if (s.fail())
log_error("Failed to write to %s\n", name);
}

void read_hex(const char *name, std::istream &s, Const &data)
{
log_assert(data.size() % QL_HEXFILE_BITSTRIDE == 0);
char line[16];
int lineno = 0;
int p = 0;
while (!s.getline(line, sizeof(line)).fail() &&
lineno < data.size() / QL_HEXFILE_BITSTRIDE) {
lineno++;
int i;
for (i = 0; i < 9; i++) {
int nibble;
switch (line[i]) {
case '0' ... '9':
nibble = line[i] - '0';
break;
case 'A' ... 'F':
nibble = line[i] - 'A' + 10;
break;
default:
goto bad_data;
}

for (int k = 0; k < 4; k++)
data[(lineno - 1) * 36 + i * 4 + k] = nibble & 1 << k ? State::S1 : State::S0;
}

if (!line[i])
continue;

bad_data:
log_error("Bad data on line %d of %s: %s", lineno, name, line);
}

if (s.eof())
return;

if (s.fail())
log_error("Failed to read %s\n", name);

lineno++;
log_error("Overrun data on line %d in %s\n", lineno, name);
}

struct QlBramInitfilePass : Pass {
QlBramInitfilePass() : Pass("ql_bram_initfile", "read or write RAM init files in QuickLogic flows") {}

void help() override
{
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
log("\n");
log(" ql_bram_initfile {-read|-write} [-path <dir-path>] [selection]\n");
log("\n");
log("This pass reads/writes initialization data on QuickLogic BRAM primitives from/to\n");
log("an external file. The filename is stored in the RAM_INIT_FILE parameter, the\n");
log("value of which will be generated if not set.\n");
log("\n");
log(" -read -write\n");
log(" select a read or write mode\n");
log("\n");
log(" -path <dir-path>\n");
log(" set the base directory path relative to which the RAM_INIT_FILE filenames\n");
log(" are interpreted\n");
log("\n");
}

void execute(std::vector<std::string> args, RTLIL::Design *design) override
{
log_header(design, "Executing QL_BRAM_INITFILE pass. (read or write RAM init files in QuickLogic flows)\n");
std::string dir_path;
bool read = false, write = false;

size_t argidx;
for (argidx = 1; argidx < args.size(); argidx++) {
if (args[argidx] == "-read")
read = true;
else if (args[argidx] == "-write")
write = true;
else if (args[argidx] == "-path" && argidx + 1 < args.size())
dir_path = args[++argidx];
else
break;
}
extra_args(args, argidx, design);

if ((!read && !write) || (read && write))
log_error("One of read or write modes needs to be selected.\n");

pool<std::string> used_filenames;

for (auto module : design->selected_modules()) {
for (auto cell : module->selected_cells()) {
if (!cell->type.in(ID(TDP36K)))
continue;

if (!cell->hasParam(ID(RAM_INIT))) {
log_warning("%s cell %s lacks RAM_DATA parameter, cell skipped.\n",
log_id(cell->type), log_id(cell));
continue;
}

if (write && !cell->hasParam(ID(RAM_INIT_FILE))) {
std::string fn = RTLIL::unescape_id(cell->name.str());
std::replace(fn.begin(), fn.end(), '\\', '_');
std::replace(fn.begin(), fn.end(), ':', '_');

while (used_filenames.count(fn))
fn += "_";

log("Setting parameter %s.RAM_DATA_FILE = %s\n",
log_id(cell->name), fn.c_str());
cell->setParam(ID(RAM_INIT_FILE), fn);
}

if (!cell->hasParam(ID(RAM_INIT_FILE))) {
log_warning("%s cell %s lacks RAM_DATA_FILE parameter, cell skipped.\n",
log_id(cell->type), log_id(cell));
continue;
}
// TODO: secure joining of the path parts
std::string param_path = cell->getParam(ID(RAM_INIT_FILE)).decode_string();
std::string path = dir_path.empty() ? param_path : (dir_path + "/" + param_path);

int datalen = 36 * 1024;
if (read) {
std::ifstream f;
f.open(path);
if (f.fail())
log_error("Failed to open file: %s\n", path.c_str());
Const data(State::Sx, datalen);
read_hex(path.c_str(), f, data);
cell->setParam(ID(RAM_INIT), data);
}

if (write) {
std::ofstream f;
f.open(path);
if (f.fail())
log_error("Failed to open file: %s\n", path.c_str());
Const data = cell->getParam(ID(RAM_INIT));
if (data.size() != datalen)
log_error("Invalid length of %s.RAM_INIT: %d\n", log_id(cell->name), data.size());
write_hex(path.c_str(), f, data);
}
}
}
}
} QlBramInitfilePass;

PRIVATE_NAMESPACE_END
17 changes: 15 additions & 2 deletions ql-qlf-plugin/synth_quicklogic.cc
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,10 @@ struct SynthQuickLogicPass : public ScriptPass {
log(" write the design to the specified verilog file. Writing of an output\n");
log(" file is omitted if this parameter is not specified.\n");
log("\n");
log(" -meminit <dir-path>\n");
log(" write block memory initialization data into files created below\n");
log(" the specified path (qlf_k6n10f only).\n");
log("\n");
log(" -no_dsp\n");
log(" By default use DSP blocks in output netlist.\n");
log(" do not use DSP blocks to implement multipliers and associated logic\n");
Expand Down Expand Up @@ -107,7 +111,7 @@ struct SynthQuickLogicPass : public ScriptPass {
log("\n");
}

string top_opt, edif_file, blif_file, family, currmodule, verilog_file, use_dsp_cfg_params, lib_path;
string top_opt, edif_file, blif_file, meminit_dir, family, currmodule, verilog_file, use_dsp_cfg_params, lib_path;
bool nodsp;
bool inferAdder;
bool inferBram;
Expand All @@ -124,6 +128,7 @@ struct SynthQuickLogicPass : public ScriptPass {
edif_file = "";
blif_file = "";
verilog_file = "";
meminit_dir = "";
currmodule = "";
family = "qlf_k4n8";
inferAdder = true;
Expand Down Expand Up @@ -178,6 +183,10 @@ struct SynthQuickLogicPass : public ScriptPass {
verilog_file = args[++argidx];
continue;
}
if (args[argidx] == "-meminit" && argidx + 1 < args.size()) {
meminit_dir = args[++argidx];
continue;
}
if (args[argidx] == "-no_dsp") {
nodsp = true;
continue;
Expand Down Expand Up @@ -581,7 +590,7 @@ struct SynthQuickLogicPass : public ScriptPass {
if (help_mode || abcOpt) {
if (help_mode || family == "qlf_k6n10" || family == "qlf_k6n10f") {
if (abc9) {
run("read_verilog -lib -specify -icells +/quicklogic/pp3/abc9_model.v");
run("read_verilog -lib -specify -icells " + lib_path + "/pp3/abc9_model.v");
//run("techmap -map +/quicklogic/pp3/abc9_map.v");
//run("abc9 -maxlut 6 -dff");
run("abc9 -maxlut 6");
Expand Down Expand Up @@ -655,6 +664,10 @@ struct SynthQuickLogicPass : public ScriptPass {
run("blackbox =A:whitebox");
}

if (check_label("meminit", "(if -meminit, for qlf_k6n10f)") && (help_mode || (family == "qlf_k6n10f" && !meminit_dir.empty()))) {
run("ql_bram_initfile -write -path " + (help_mode ? "<dir-path>" : meminit_dir));
}

if (check_label("blif", "(if -blif)")) {
if (help_mode || !blif_file.empty()) {
run(stringf("write_blif -param %s", help_mode ? "<file-name>" : blif_file.c_str()));
Expand Down