From: Clifford Wolf Date: Wed, 31 Dec 2014 15:53:53 +0000 (+0100) Subject: Added memory_bram (not functional yet) X-Git-Tag: yosys-0.5~158 X-Git-Url: https://git.libre-soc.org/?a=commitdiff_plain;h=94e6b70736934bd8ebb09c7cc74cfd443bd1d9eb;p=yosys.git Added memory_bram (not functional yet) --- diff --git a/kernel/yosys.h b/kernel/yosys.h index 2c9ca0dd9..88f060a52 100644 --- a/kernel/yosys.h +++ b/kernel/yosys.h @@ -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 process_line = std::function()); std::string make_temp_file(std::string template_str = "/tmp/yosys_XXXXXX"); diff --git a/passes/memory/Makefile.inc b/passes/memory/Makefile.inc index 026c5ff85..aeff225d8 100644 --- a/passes/memory/Makefile.inc +++ b/passes/memory/Makefile.inc @@ -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 diff --git a/passes/memory/memory_bram.cc b/passes/memory/memory_bram.cc new file mode 100644 index 000000000..9c02866e9 --- /dev/null +++ b/passes/memory/memory_bram.cc @@ -0,0 +1,285 @@ +/* + * yosys -- Yosys Open SYnthesis Suite + * + * Copyright (C) 2012 Clifford Wolf + * + * 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 wports, rports, wenabl, transp, clocks, clkpol; + }; + + struct match_t { + IdString name; + dict min_limits, max_limits; + }; + + dict brams; + vector matches; + + std::ifstream infile; + vector 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 &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 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 [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 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 diff --git a/techlibs/xilinx/brams.txt b/techlibs/xilinx/brams.txt new file mode 100644 index 000000000..03bd2b2b3 --- /dev/null +++ b/techlibs/xilinx/brams.txt @@ -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 +