Added memory_bram (not functional yet)
authorClifford Wolf <clifford@clifford.at>
Wed, 31 Dec 2014 15:53:53 +0000 (16:53 +0100)
committerClifford Wolf <clifford@clifford.at>
Wed, 31 Dec 2014 15:53:53 +0000 (16:53 +0100)
kernel/yosys.h
passes/memory/Makefile.inc
passes/memory/memory_bram.cc [new file with mode: 0644]
techlibs/xilinx/brams.txt [new file with mode: 0644]

index 2c9ca0dd92cbb91023d363cf3a89ce5d19771b1c..88f060a52ed4d81ebffed49d92276fc21ab6cff9 100644 (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 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");
index 026c5ff8598626766f317e257869cf72ba52dcaf..aeff225d8fa8f0265d428428a7de9412c4184f72 100644 (file)
@@ -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 (file)
index 0000000..9c02866
--- /dev/null
@@ -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
diff --git a/techlibs/xilinx/brams.txt b/techlibs/xilinx/brams.txt
new file mode 100644 (file)
index 0000000..03bd2b2
--- /dev/null
@@ -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
+