2 * yosys -- Yosys Open SYnthesis Suite
4 * Copyright (C) 2012 Clifford Wolf <clifford@clifford.at>
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.
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.
20 #include "kernel/yosys.h"
23 PRIVATE_NAMESPACE_BEGIN
29 int groups
, abits
, dbits
, init
;
30 vector
<int> wports
, rports
, wenabl
, transp
, clocks
, clkpol
;
35 dict
<string
, int> min_limits
, max_limits
;
38 dict
<IdString
, bram_t
> brams
;
39 vector
<match_t
> matches
;
42 vector
<string
> tokens
;
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());
57 while (std::getline(infile
, line
)) {
58 for (string tok
= next_token(line
); !tok
.empty(); tok
= next_token(line
)) {
61 tokens
.push_back(tok
);
69 bool parse_single_int(const char *stmt
, int &value
)
71 if (GetSize(tokens
) == 2 && tokens
[0] == stmt
) {
72 value
= atoi(tokens
[1].c_str());
78 bool parse_int_vect(const char *stmt
, vector
<int> &value
)
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());
91 if (GetSize(tokens
) != 2)
95 data
.name
= RTLIL::escape_id(tokens
[1]);
99 if (GetSize(tokens
) == 1 && tokens
[0] == "endbram") {
100 brams
[data
.name
] = data
;
104 if (parse_single_int("groups", data
.groups
))
107 if (parse_single_int("abits", data
.abits
))
110 if (parse_single_int("dbits", data
.dbits
))
113 if (parse_single_int("init", data
.init
))
116 if (parse_int_vect("wports", data
.wports
))
119 if (parse_int_vect("rports", data
.rports
))
122 if (parse_int_vect("wenabl", data
.wenabl
))
125 if (parse_int_vect("transp", data
.transp
))
128 if (parse_int_vect("clocks", data
.clocks
))
131 if (parse_int_vect("clkpol", data
.clkpol
))
142 if (GetSize(tokens
) != 2)
146 data
.name
= RTLIL::escape_id(tokens
[1]);
150 if (GetSize(tokens
) == 1 && tokens
[0] == "endmatch") {
151 matches
.push_back(data
);
155 if (GetSize(tokens
) == 3 && tokens
[0] == "min") {
156 data
.min_limits
[tokens
[1]] = atoi(tokens
[2].c_str());
160 if (GetSize(tokens
) == 3 && tokens
[0] == "max") {
161 data
.max_limits
[tokens
[1]] = atoi(tokens
[2].c_str());
171 void parse(std::string filename
)
173 infile
.open(filename
);
177 log_error("Can't open rules file `%s'.\n", filename
.c_str());
181 if (tokens
[0] == "bram") parse_bram();
182 else if (tokens
[0] == "match") parse_match();
190 void replace_cell(Cell
*, const rules_t::bram_t
&, const rules_t::match_t
&)
192 log(" FIXME: The core of memory_bram is not implemented yet.\n");
195 void handle_cell(Cell
*cell
, const rules_t
&rules
)
197 log("Processing %s.%s:\n", log_id(cell
->module
), log_id(cell
));
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"];
209 for (auto &it
: mem_properties
)
210 log(" %s=%d", it
.first
.c_str(), it
.second
);
213 for (int i
= 0; i
< GetSize(rules
.matches
); i
++)
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
)
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
;
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
)
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
;
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
));
240 replace_cell(cell
, rules
.brams
.at(rules
.matches
[i
].name
), rules
.matches
[i
]);
246 log(" No acceptable bram resources found.\n");
249 struct MemoryBramPass
: public Pass
{
250 MemoryBramPass() : Pass("memory_bram", "map memories to block rams") { }
253 // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
255 log(" memory_bram -rules <rule_file> [selection]\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");
262 virtual void execute(vector
<string
> args
, Design
*design
)
266 log_header("Executing MEMORY_BRAM pass (mapping $mem cells to block memories).\n");
269 for (argidx
= 1; argidx
< args
.size(); argidx
++) {
270 if (args
[argidx
] == "-rules" && argidx
+1 < args
.size()) {
271 rules
.parse(args
[++argidx
]);
276 extra_args(args
, argidx
, design
);
278 for (auto mod
: design
->selected_modules())
279 for (auto cell
: mod
->selected_cells())
280 if (cell
->type
== "$mem")
281 handle_cell(cell
, rules
);
285 PRIVATE_NAMESPACE_END