Added memory_bram (not functional yet)

This commit is contained in:
Clifford Wolf 2014-12-31 16:53:53 +01:00
parent 1e08621e7e
commit 94e6b70736
4 changed files with 307 additions and 1 deletions

View File

@ -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 stringf(const char *fmt, ...) YS_ATTRIBUTE(format(printf, 1, 2));
std::string vstringf(const char *fmt, va_list ap); std::string vstringf(const char *fmt, va_list ap);
int readsome(std::istream &f, char *s, int n); 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); 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&)>()); 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"); std::string make_temp_file(std::string template_str = "/tmp/yosys_XXXXXX");

View File

@ -4,5 +4,6 @@ OBJS += passes/memory/memory_dff.o
OBJS += passes/memory/memory_share.o OBJS += passes/memory/memory_share.o
OBJS += passes/memory/memory_collect.o OBJS += passes/memory/memory_collect.o
OBJS += passes/memory/memory_unpack.o OBJS += passes/memory/memory_unpack.o
OBJS += passes/memory/memory_bram.o
OBJS += passes/memory/memory_map.o OBJS += passes/memory/memory_map.o

View File

@ -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

20
techlibs/xilinx/brams.txt Normal file
View File

@ -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