mirror of https://github.com/YosysHQ/yosys.git
Added memory_bram (not functional yet)
This commit is contained in:
parent
1e08621e7e
commit
94e6b70736
|
@ -199,7 +199,7 @@ inline void memhasher() { if (memhasher_active) memhasher_do(); }
|
|||
std::string stringf(const char *fmt, ...) YS_ATTRIBUTE(format(printf, 1, 2));
|
||||
std::string vstringf(const char *fmt, va_list ap);
|
||||
int readsome(std::istream &f, char *s, int n);
|
||||
std::string next_token(std::string &text, const char *sep);
|
||||
std::string next_token(std::string &text, const char *sep = " \t\r\n");
|
||||
bool patmatch(const char *pattern, const char *string);
|
||||
int run_command(const std::string &command, std::function<void(const std::string&)> process_line = std::function<void(const std::string&)>());
|
||||
std::string make_temp_file(std::string template_str = "/tmp/yosys_XXXXXX");
|
||||
|
|
|
@ -4,5 +4,6 @@ OBJS += passes/memory/memory_dff.o
|
|||
OBJS += passes/memory/memory_share.o
|
||||
OBJS += passes/memory/memory_collect.o
|
||||
OBJS += passes/memory/memory_unpack.o
|
||||
OBJS += passes/memory/memory_bram.o
|
||||
OBJS += passes/memory/memory_map.o
|
||||
|
||||
|
|
|
@ -0,0 +1,285 @@
|
|||
/*
|
||||
* 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"
|
||||
|
||||
USING_YOSYS_NAMESPACE
|
||||
PRIVATE_NAMESPACE_BEGIN
|
||||
|
||||
struct rules_t
|
||||
{
|
||||
struct bram_t {
|
||||
IdString name;
|
||||
int groups, abits, dbits, init;
|
||||
vector<int> wports, rports, wenabl, transp, clocks, clkpol;
|
||||
};
|
||||
|
||||
struct match_t {
|
||||
IdString name;
|
||||
dict<string, int> min_limits, max_limits;
|
||||
};
|
||||
|
||||
dict<IdString, bram_t> brams;
|
||||
vector<match_t> matches;
|
||||
|
||||
std::ifstream infile;
|
||||
vector<string> tokens;
|
||||
int linecount;
|
||||
string line;
|
||||
|
||||
void syntax_error()
|
||||
{
|
||||
if (line.empty())
|
||||
log_error("Unexpected end of rules file in line %d.\n", linecount);
|
||||
log_error("Syntax error in rules file line %d: %s\n", linecount, line.c_str());
|
||||
}
|
||||
|
||||
bool next_line()
|
||||
{
|
||||
linecount++;
|
||||
tokens.clear();
|
||||
while (std::getline(infile, line)) {
|
||||
for (string tok = next_token(line); !tok.empty(); tok = next_token(line)) {
|
||||
if (tok[0] == '#')
|
||||
break;
|
||||
tokens.push_back(tok);
|
||||
}
|
||||
if (!tokens.empty())
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool parse_single_int(const char *stmt, int &value)
|
||||
{
|
||||
if (GetSize(tokens) == 2 && tokens[0] == stmt) {
|
||||
value = atoi(tokens[1].c_str());
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool parse_int_vect(const char *stmt, vector<int> &value)
|
||||
{
|
||||
if (GetSize(tokens) >= 2 && tokens[0] == stmt) {
|
||||
value.resize(GetSize(tokens)-1);
|
||||
for (int i = 1; i < GetSize(tokens); i++)
|
||||
value[i] = atoi(tokens[i].c_str());
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void parse_bram()
|
||||
{
|
||||
if (GetSize(tokens) != 2)
|
||||
syntax_error();
|
||||
|
||||
bram_t data;
|
||||
data.name = RTLIL::escape_id(tokens[1]);
|
||||
|
||||
while (next_line())
|
||||
{
|
||||
if (GetSize(tokens) == 1 && tokens[0] == "endbram") {
|
||||
brams[data.name] = data;
|
||||
return;
|
||||
}
|
||||
|
||||
if (parse_single_int("groups", data.groups))
|
||||
continue;
|
||||
|
||||
if (parse_single_int("abits", data.abits))
|
||||
continue;
|
||||
|
||||
if (parse_single_int("dbits", data.dbits))
|
||||
continue;
|
||||
|
||||
if (parse_single_int("init", data.init))
|
||||
continue;
|
||||
|
||||
if (parse_int_vect("wports", data.wports))
|
||||
continue;
|
||||
|
||||
if (parse_int_vect("rports", data.rports))
|
||||
continue;
|
||||
|
||||
if (parse_int_vect("wenabl", data.wenabl))
|
||||
continue;
|
||||
|
||||
if (parse_int_vect("transp", data.transp))
|
||||
continue;
|
||||
|
||||
if (parse_int_vect("clocks", data.clocks))
|
||||
continue;
|
||||
|
||||
if (parse_int_vect("clkpol", data.clkpol))
|
||||
continue;
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
syntax_error();
|
||||
}
|
||||
|
||||
void parse_match()
|
||||
{
|
||||
if (GetSize(tokens) != 2)
|
||||
syntax_error();
|
||||
|
||||
match_t data;
|
||||
data.name = RTLIL::escape_id(tokens[1]);
|
||||
|
||||
while (next_line())
|
||||
{
|
||||
if (GetSize(tokens) == 1 && tokens[0] == "endmatch") {
|
||||
matches.push_back(data);
|
||||
return;
|
||||
}
|
||||
|
||||
if (GetSize(tokens) == 3 && tokens[0] == "min") {
|
||||
data.min_limits[tokens[1]] = atoi(tokens[2].c_str());
|
||||
continue;
|
||||
}
|
||||
|
||||
if (GetSize(tokens) == 3 && tokens[0] == "max") {
|
||||
data.max_limits[tokens[1]] = atoi(tokens[2].c_str());
|
||||
continue;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
syntax_error();
|
||||
}
|
||||
|
||||
void parse(std::string filename)
|
||||
{
|
||||
infile.open(filename);
|
||||
linecount = 0;
|
||||
|
||||
if (infile.fail())
|
||||
log_error("Can't open rules file `%s'.\n", filename.c_str());
|
||||
|
||||
while (next_line())
|
||||
{
|
||||
if (tokens[0] == "bram") parse_bram();
|
||||
else if (tokens[0] == "match") parse_match();
|
||||
else syntax_error();
|
||||
}
|
||||
|
||||
infile.close();
|
||||
}
|
||||
};
|
||||
|
||||
void replace_cell(Cell*, const rules_t::bram_t&, const rules_t::match_t&)
|
||||
{
|
||||
log(" FIXME: The core of memory_bram is not implemented yet.\n");
|
||||
}
|
||||
|
||||
void handle_cell(Cell *cell, const rules_t &rules)
|
||||
{
|
||||
log("Processing %s.%s:\n", log_id(cell->module), log_id(cell));
|
||||
|
||||
dict<string, int> mem_properties;
|
||||
mem_properties["words"] = cell->getParam("\\SIZE").as_int();
|
||||
mem_properties["abits"] = cell->getParam("\\ABITS").as_int();
|
||||
mem_properties["dbits"] = cell->getParam("\\WIDTH").as_int();
|
||||
mem_properties["wports"] = cell->getParam("\\WR_PORTS").as_int();
|
||||
mem_properties["rports"] = cell->getParam("\\RD_PORTS").as_int();
|
||||
mem_properties["bits"] = mem_properties["words"] * mem_properties["dbits"];
|
||||
mem_properties["ports"] = mem_properties["wports"] + mem_properties["rports"];
|
||||
|
||||
log(" Properties:");
|
||||
for (auto &it : mem_properties)
|
||||
log(" %s=%d", it.first.c_str(), it.second);
|
||||
log("\n");
|
||||
|
||||
for (int i = 0; i < GetSize(rules.matches); i++)
|
||||
{
|
||||
for (auto it : rules.matches[i].min_limits) {
|
||||
if (!mem_properties.count(it.first))
|
||||
log_error("Unknown property '%s' in match rule for bram type %s.\n",
|
||||
it.first.c_str(), log_id(rules.matches[i].name));
|
||||
if (mem_properties[it.first] >= it.second)
|
||||
continue;
|
||||
log(" Rule #%d for bram type %s rejected: requirement 'min %s %d' not met.\n",
|
||||
i, log_id(rules.matches[i].name), it.first.c_str(), it.second);
|
||||
goto next_match_rule;
|
||||
}
|
||||
for (auto it : rules.matches[i].max_limits) {
|
||||
if (!mem_properties.count(it.first))
|
||||
log_error("Unknown property '%s' in match rule for bram type %s.\n",
|
||||
it.first.c_str(), log_id(rules.matches[i].name));
|
||||
if (mem_properties[it.first] <= it.second)
|
||||
continue;
|
||||
log(" Rule #%d for bram type %s rejected: requirement 'max %s %d' not met.\n",
|
||||
i, log_id(rules.matches[i].name), it.first.c_str(), it.second);
|
||||
goto next_match_rule;
|
||||
}
|
||||
|
||||
log(" Rule #%d for bram type %s accepted.\n", i, log_id(rules.matches[i].name));
|
||||
if (!rules.brams.count(rules.matches[i].name))
|
||||
log_error("No bram description for resource %s found!\n", log_id(rules.matches[i].name));
|
||||
|
||||
replace_cell(cell, rules.brams.at(rules.matches[i].name), rules.matches[i]);
|
||||
return;
|
||||
|
||||
next_match_rule:;
|
||||
}
|
||||
|
||||
log(" No acceptable bram resources found.\n");
|
||||
}
|
||||
|
||||
struct MemoryBramPass : public Pass {
|
||||
MemoryBramPass() : Pass("memory_bram", "map memories to block rams") { }
|
||||
virtual void help()
|
||||
{
|
||||
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
|
||||
log("\n");
|
||||
log(" memory_bram -rules <rule_file> [selection]\n");
|
||||
log("\n");
|
||||
log("This pass converts the multi-port $mem memory cells into block ram instances.\n");
|
||||
log("The given rules file describes the available resources and how they should be\n");
|
||||
log("used.\n");
|
||||
log("\n");
|
||||
}
|
||||
virtual void execute(vector<string> args, Design *design)
|
||||
{
|
||||
rules_t rules;
|
||||
|
||||
log_header("Executing MEMORY_BRAM pass (mapping $mem cells to block memories).\n");
|
||||
|
||||
size_t argidx;
|
||||
for (argidx = 1; argidx < args.size(); argidx++) {
|
||||
if (args[argidx] == "-rules" && argidx+1 < args.size()) {
|
||||
rules.parse(args[++argidx]);
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
}
|
||||
extra_args(args, argidx, design);
|
||||
|
||||
for (auto mod : design->selected_modules())
|
||||
for (auto cell : mod->selected_cells())
|
||||
if (cell->type == "$mem")
|
||||
handle_cell(cell, rules);
|
||||
}
|
||||
} MemoryBramPass;
|
||||
|
||||
PRIVATE_NAMESPACE_END
|
|
@ -0,0 +1,20 @@
|
|||
|
||||
# This is a very simplified description of the capabilities of
|
||||
# the Xilinx RAMB36 core. But it is a start..
|
||||
#
|
||||
bram XILINX_RAMB36_SDP32
|
||||
init 1
|
||||
abits 10
|
||||
dbits 32
|
||||
groups 2
|
||||
wports 1 0
|
||||
rports 0 1
|
||||
wenabl 2 0
|
||||
transp 0 2
|
||||
clocks 1 2
|
||||
endbram
|
||||
|
||||
match XILINX_RAMB36_SDP32
|
||||
min bits 1024
|
||||
endmatch
|
||||
|
Loading…
Reference in New Issue