Added memory_bram (not functional yet)
[yosys.git] / passes / memory / memory_bram.cc
1 /*
2 * yosys -- Yosys Open SYnthesis Suite
3 *
4 * Copyright (C) 2012 Clifford Wolf <clifford@clifford.at>
5 *
6 * Permission to use, copy, modify, and/or distribute this software for any
7 * purpose with or without fee is hereby granted, provided that the above
8 * copyright notice and this permission notice appear in all copies.
9 *
10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17 *
18 */
19
20 #include "kernel/yosys.h"
21
22 USING_YOSYS_NAMESPACE
23 PRIVATE_NAMESPACE_BEGIN
24
25 struct rules_t
26 {
27 struct bram_t {
28 IdString name;
29 int groups, abits, dbits, init;
30 vector<int> wports, rports, wenabl, transp, clocks, clkpol;
31 };
32
33 struct match_t {
34 IdString name;
35 dict<string, int> min_limits, max_limits;
36 };
37
38 dict<IdString, bram_t> brams;
39 vector<match_t> matches;
40
41 std::ifstream infile;
42 vector<string> tokens;
43 int linecount;
44 string line;
45
46 void syntax_error()
47 {
48 if (line.empty())
49 log_error("Unexpected end of rules file in line %d.\n", linecount);
50 log_error("Syntax error in rules file line %d: %s\n", linecount, line.c_str());
51 }
52
53 bool next_line()
54 {
55 linecount++;
56 tokens.clear();
57 while (std::getline(infile, line)) {
58 for (string tok = next_token(line); !tok.empty(); tok = next_token(line)) {
59 if (tok[0] == '#')
60 break;
61 tokens.push_back(tok);
62 }
63 if (!tokens.empty())
64 return true;
65 }
66 return false;
67 }
68
69 bool parse_single_int(const char *stmt, int &value)
70 {
71 if (GetSize(tokens) == 2 && tokens[0] == stmt) {
72 value = atoi(tokens[1].c_str());
73 return true;
74 }
75 return false;
76 }
77
78 bool parse_int_vect(const char *stmt, vector<int> &value)
79 {
80 if (GetSize(tokens) >= 2 && tokens[0] == stmt) {
81 value.resize(GetSize(tokens)-1);
82 for (int i = 1; i < GetSize(tokens); i++)
83 value[i] = atoi(tokens[i].c_str());
84 return true;
85 }
86 return false;
87 }
88
89 void parse_bram()
90 {
91 if (GetSize(tokens) != 2)
92 syntax_error();
93
94 bram_t data;
95 data.name = RTLIL::escape_id(tokens[1]);
96
97 while (next_line())
98 {
99 if (GetSize(tokens) == 1 && tokens[0] == "endbram") {
100 brams[data.name] = data;
101 return;
102 }
103
104 if (parse_single_int("groups", data.groups))
105 continue;
106
107 if (parse_single_int("abits", data.abits))
108 continue;
109
110 if (parse_single_int("dbits", data.dbits))
111 continue;
112
113 if (parse_single_int("init", data.init))
114 continue;
115
116 if (parse_int_vect("wports", data.wports))
117 continue;
118
119 if (parse_int_vect("rports", data.rports))
120 continue;
121
122 if (parse_int_vect("wenabl", data.wenabl))
123 continue;
124
125 if (parse_int_vect("transp", data.transp))
126 continue;
127
128 if (parse_int_vect("clocks", data.clocks))
129 continue;
130
131 if (parse_int_vect("clkpol", data.clkpol))
132 continue;
133
134 break;
135 }
136
137 syntax_error();
138 }
139
140 void parse_match()
141 {
142 if (GetSize(tokens) != 2)
143 syntax_error();
144
145 match_t data;
146 data.name = RTLIL::escape_id(tokens[1]);
147
148 while (next_line())
149 {
150 if (GetSize(tokens) == 1 && tokens[0] == "endmatch") {
151 matches.push_back(data);
152 return;
153 }
154
155 if (GetSize(tokens) == 3 && tokens[0] == "min") {
156 data.min_limits[tokens[1]] = atoi(tokens[2].c_str());
157 continue;
158 }
159
160 if (GetSize(tokens) == 3 && tokens[0] == "max") {
161 data.max_limits[tokens[1]] = atoi(tokens[2].c_str());
162 continue;
163 }
164
165 break;
166 }
167
168 syntax_error();
169 }
170
171 void parse(std::string filename)
172 {
173 infile.open(filename);
174 linecount = 0;
175
176 if (infile.fail())
177 log_error("Can't open rules file `%s'.\n", filename.c_str());
178
179 while (next_line())
180 {
181 if (tokens[0] == "bram") parse_bram();
182 else if (tokens[0] == "match") parse_match();
183 else syntax_error();
184 }
185
186 infile.close();
187 }
188 };
189
190 void replace_cell(Cell*, const rules_t::bram_t&, const rules_t::match_t&)
191 {
192 log(" FIXME: The core of memory_bram is not implemented yet.\n");
193 }
194
195 void handle_cell(Cell *cell, const rules_t &rules)
196 {
197 log("Processing %s.%s:\n", log_id(cell->module), log_id(cell));
198
199 dict<string, int> mem_properties;
200 mem_properties["words"] = cell->getParam("\\SIZE").as_int();
201 mem_properties["abits"] = cell->getParam("\\ABITS").as_int();
202 mem_properties["dbits"] = cell->getParam("\\WIDTH").as_int();
203 mem_properties["wports"] = cell->getParam("\\WR_PORTS").as_int();
204 mem_properties["rports"] = cell->getParam("\\RD_PORTS").as_int();
205 mem_properties["bits"] = mem_properties["words"] * mem_properties["dbits"];
206 mem_properties["ports"] = mem_properties["wports"] + mem_properties["rports"];
207
208 log(" Properties:");
209 for (auto &it : mem_properties)
210 log(" %s=%d", it.first.c_str(), it.second);
211 log("\n");
212
213 for (int i = 0; i < GetSize(rules.matches); i++)
214 {
215 for (auto it : rules.matches[i].min_limits) {
216 if (!mem_properties.count(it.first))
217 log_error("Unknown property '%s' in match rule for bram type %s.\n",
218 it.first.c_str(), log_id(rules.matches[i].name));
219 if (mem_properties[it.first] >= it.second)
220 continue;
221 log(" Rule #%d for bram type %s rejected: requirement 'min %s %d' not met.\n",
222 i, log_id(rules.matches[i].name), it.first.c_str(), it.second);
223 goto next_match_rule;
224 }
225 for (auto it : rules.matches[i].max_limits) {
226 if (!mem_properties.count(it.first))
227 log_error("Unknown property '%s' in match rule for bram type %s.\n",
228 it.first.c_str(), log_id(rules.matches[i].name));
229 if (mem_properties[it.first] <= it.second)
230 continue;
231 log(" Rule #%d for bram type %s rejected: requirement 'max %s %d' not met.\n",
232 i, log_id(rules.matches[i].name), it.first.c_str(), it.second);
233 goto next_match_rule;
234 }
235
236 log(" Rule #%d for bram type %s accepted.\n", i, log_id(rules.matches[i].name));
237 if (!rules.brams.count(rules.matches[i].name))
238 log_error("No bram description for resource %s found!\n", log_id(rules.matches[i].name));
239
240 replace_cell(cell, rules.brams.at(rules.matches[i].name), rules.matches[i]);
241 return;
242
243 next_match_rule:;
244 }
245
246 log(" No acceptable bram resources found.\n");
247 }
248
249 struct MemoryBramPass : public Pass {
250 MemoryBramPass() : Pass("memory_bram", "map memories to block rams") { }
251 virtual void help()
252 {
253 // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
254 log("\n");
255 log(" memory_bram -rules <rule_file> [selection]\n");
256 log("\n");
257 log("This pass converts the multi-port $mem memory cells into block ram instances.\n");
258 log("The given rules file describes the available resources and how they should be\n");
259 log("used.\n");
260 log("\n");
261 }
262 virtual void execute(vector<string> args, Design *design)
263 {
264 rules_t rules;
265
266 log_header("Executing MEMORY_BRAM pass (mapping $mem cells to block memories).\n");
267
268 size_t argidx;
269 for (argidx = 1; argidx < args.size(); argidx++) {
270 if (args[argidx] == "-rules" && argidx+1 < args.size()) {
271 rules.parse(args[++argidx]);
272 continue;
273 }
274 break;
275 }
276 extra_args(args, argidx, design);
277
278 for (auto mod : design->selected_modules())
279 for (auto cell : mod->selected_cells())
280 if (cell->type == "$mem")
281 handle_cell(cell, rules);
282 }
283 } MemoryBramPass;
284
285 PRIVATE_NAMESPACE_END