Merge pull request #2626 from zachjs/param-no-default
[yosys.git] / kernel / mem.cc
1 /*
2 * yosys -- Yosys Open SYnthesis Suite
3 *
4 * Copyright (C) 2020 Marcelina Koƛcielnicka <mwk@0x04.net>
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/mem.h"
21
22 USING_YOSYS_NAMESPACE
23
24 void Mem::remove() {
25 if (cell) {
26 module->remove(cell);
27 cell = nullptr;
28 }
29 if (mem) {
30 module->memories.erase(mem->name);
31 delete mem;
32 mem = nullptr;
33 }
34 for (auto &port : rd_ports) {
35 if (port.cell) {
36 module->remove(port.cell);
37 port.cell = nullptr;
38 }
39 }
40 for (auto &port : wr_ports) {
41 if (port.cell) {
42 module->remove(port.cell);
43 port.cell = nullptr;
44 }
45 }
46 for (auto &init : inits) {
47 if (init.cell) {
48 module->remove(init.cell);
49 init.cell = nullptr;
50 }
51 }
52 }
53
54 void Mem::emit() {
55 if (packed) {
56 if (mem) {
57 module->memories.erase(mem->name);
58 delete mem;
59 mem = nullptr;
60 }
61 if (!cell) {
62 if (memid.empty())
63 memid = NEW_ID;
64 cell = module->addCell(memid, ID($mem));
65 }
66 cell->attributes = attributes;
67 cell->parameters[ID::MEMID] = Const(memid.str());
68 cell->parameters[ID::WIDTH] = Const(width);
69 cell->parameters[ID::OFFSET] = Const(start_offset);
70 cell->parameters[ID::SIZE] = Const(size);
71 cell->parameters[ID::RD_PORTS] = Const(GetSize(rd_ports));
72 cell->parameters[ID::WR_PORTS] = Const(GetSize(wr_ports));
73 Const rd_clk_enable, rd_clk_polarity, rd_transparent;
74 Const wr_clk_enable, wr_clk_polarity;
75 SigSpec rd_clk, rd_en, rd_addr, rd_data;
76 SigSpec wr_clk, wr_en, wr_addr, wr_data;
77 int abits = 0;
78 for (auto &port : rd_ports)
79 abits = std::max(abits, GetSize(port.addr));
80 for (auto &port : wr_ports)
81 abits = std::max(abits, GetSize(port.addr));
82 cell->parameters[ID::ABITS] = Const(abits);
83 for (auto &port : rd_ports) {
84 if (port.cell) {
85 module->remove(port.cell);
86 port.cell = nullptr;
87 }
88 rd_clk_enable.bits.push_back(State(port.clk_enable));
89 rd_clk_polarity.bits.push_back(State(port.clk_polarity));
90 rd_transparent.bits.push_back(State(port.transparent));
91 rd_clk.append(port.clk);
92 log_assert(GetSize(port.clk) == 1);
93 rd_en.append(port.en);
94 log_assert(GetSize(port.en) == 1);
95 SigSpec addr = port.addr;
96 addr.extend_u0(abits, false);
97 rd_addr.append(addr);
98 log_assert(GetSize(addr) == abits);
99 rd_data.append(port.data);
100 log_assert(GetSize(port.data) == width);
101 }
102 if (rd_ports.empty()) {
103 rd_clk_enable = State::S0;
104 rd_clk_polarity = State::S0;
105 rd_transparent = State::S0;
106 }
107 cell->parameters[ID::RD_CLK_ENABLE] = rd_clk_enable;
108 cell->parameters[ID::RD_CLK_POLARITY] = rd_clk_polarity;
109 cell->parameters[ID::RD_TRANSPARENT] = rd_transparent;
110 cell->setPort(ID::RD_CLK, rd_clk);
111 cell->setPort(ID::RD_EN, rd_en);
112 cell->setPort(ID::RD_ADDR, rd_addr);
113 cell->setPort(ID::RD_DATA, rd_data);
114 for (auto &port : wr_ports) {
115 if (port.cell) {
116 module->remove(port.cell);
117 port.cell = nullptr;
118 }
119 wr_clk_enable.bits.push_back(State(port.clk_enable));
120 wr_clk_polarity.bits.push_back(State(port.clk_polarity));
121 wr_clk.append(port.clk);
122 log_assert(GetSize(port.clk) == 1);
123 wr_en.append(port.en);
124 log_assert(GetSize(port.en) == width);
125 SigSpec addr = port.addr;
126 addr.extend_u0(abits, false);
127 wr_addr.append(addr);
128 log_assert(GetSize(addr) == abits);
129 wr_data.append(port.data);
130 log_assert(GetSize(port.data) == width);
131 }
132 if (wr_ports.empty()) {
133 wr_clk_enable = State::S0;
134 wr_clk_polarity = State::S0;
135 }
136 cell->parameters[ID::WR_CLK_ENABLE] = wr_clk_enable;
137 cell->parameters[ID::WR_CLK_POLARITY] = wr_clk_polarity;
138 cell->setPort(ID::WR_CLK, wr_clk);
139 cell->setPort(ID::WR_EN, wr_en);
140 cell->setPort(ID::WR_ADDR, wr_addr);
141 cell->setPort(ID::WR_DATA, wr_data);
142 for (auto &init : inits) {
143 if (init.cell) {
144 module->remove(init.cell);
145 init.cell = nullptr;
146 }
147 }
148 cell->parameters[ID::INIT] = get_init_data();
149 } else {
150 if (cell) {
151 module->remove(cell);
152 cell = nullptr;
153 }
154 if (!mem) {
155 if (memid.empty())
156 memid = NEW_ID;
157 mem = new RTLIL::Memory;
158 mem->name = memid;
159 module->memories[memid] = mem;
160 }
161 mem->width = width;
162 mem->start_offset = start_offset;
163 mem->size = size;
164 for (auto &port : rd_ports) {
165 if (!port.cell)
166 port.cell = module->addCell(NEW_ID, ID($memrd));
167 port.cell->parameters[ID::MEMID] = memid.str();
168 port.cell->parameters[ID::ABITS] = GetSize(port.addr);
169 port.cell->parameters[ID::WIDTH] = width;
170 port.cell->parameters[ID::CLK_ENABLE] = port.clk_enable;
171 port.cell->parameters[ID::CLK_POLARITY] = port.clk_polarity;
172 port.cell->parameters[ID::TRANSPARENT] = port.transparent;
173 port.cell->setPort(ID::CLK, port.clk);
174 port.cell->setPort(ID::EN, port.en);
175 port.cell->setPort(ID::ADDR, port.addr);
176 port.cell->setPort(ID::DATA, port.data);
177 }
178 int idx = 0;
179 for (auto &port : wr_ports) {
180 if (!port.cell)
181 port.cell = module->addCell(NEW_ID, ID($memwr));
182 port.cell->parameters[ID::MEMID] = memid.str();
183 port.cell->parameters[ID::ABITS] = GetSize(port.addr);
184 port.cell->parameters[ID::WIDTH] = width;
185 port.cell->parameters[ID::CLK_ENABLE] = port.clk_enable;
186 port.cell->parameters[ID::CLK_POLARITY] = port.clk_polarity;
187 port.cell->parameters[ID::PRIORITY] = idx++;
188 port.cell->setPort(ID::CLK, port.clk);
189 port.cell->setPort(ID::EN, port.en);
190 port.cell->setPort(ID::ADDR, port.addr);
191 port.cell->setPort(ID::DATA, port.data);
192 }
193 idx = 0;
194 for (auto &init : inits) {
195 if (!init.cell)
196 init.cell = module->addCell(NEW_ID, ID($meminit));
197 init.cell->parameters[ID::MEMID] = memid.str();
198 init.cell->parameters[ID::ABITS] = GetSize(init.addr);
199 init.cell->parameters[ID::WIDTH] = width;
200 init.cell->parameters[ID::WORDS] = GetSize(init.data) / width;
201 init.cell->parameters[ID::PRIORITY] = idx++;
202 init.cell->setPort(ID::ADDR, init.addr);
203 init.cell->setPort(ID::DATA, init.data);
204 }
205 }
206 }
207
208 void Mem::remove_wr_port(int idx) {
209 if (wr_ports[idx].cell) {
210 module->remove(wr_ports[idx].cell);
211 }
212 wr_ports.erase(wr_ports.begin() + idx);
213 }
214
215 void Mem::remove_rd_port(int idx) {
216 if (rd_ports[idx].cell) {
217 module->remove(rd_ports[idx].cell);
218 }
219 rd_ports.erase(rd_ports.begin() + idx);
220 }
221
222 void Mem::clear_inits() {
223 for (auto &init : inits)
224 if (init.cell)
225 module->remove(init.cell);
226 inits.clear();
227 }
228
229 Const Mem::get_init_data() const {
230 Const init_data(State::Sx, width * size);
231 for (auto &init : inits) {
232 int offset = (init.addr.as_int() - start_offset) * width;
233 for (int i = 0; i < GetSize(init.data); i++)
234 if (0 <= i+offset && i+offset < GetSize(init_data))
235 init_data.bits[i+offset] = init.data.bits[i];
236 }
237 return init_data;
238 }
239
240 namespace {
241
242 struct MemIndex {
243 dict<IdString, pool<Cell *>> rd_ports;
244 dict<IdString, pool<Cell *>> wr_ports;
245 dict<IdString, pool<Cell *>> inits;
246 MemIndex (Module *module) {
247 for (auto cell: module->cells()) {
248 if (cell->type == ID($memwr))
249 wr_ports[cell->parameters.at(ID::MEMID).decode_string()].insert(cell);
250 else if (cell->type == ID($memrd))
251 rd_ports[cell->parameters.at(ID::MEMID).decode_string()].insert(cell);
252 else if (cell->type == ID($meminit))
253 inits[cell->parameters.at(ID::MEMID).decode_string()].insert(cell);
254 }
255 }
256 };
257
258 Mem mem_from_memory(Module *module, RTLIL::Memory *mem, const MemIndex &index) {
259 Mem res(module, mem->name, mem->width, mem->start_offset, mem->size);
260 res.packed = false;
261 res.mem = mem;
262 res.attributes = mem->attributes;
263 if (index.rd_ports.count(mem->name)) {
264 for (auto cell : index.rd_ports.at(mem->name)) {
265 MemRd mrd;
266 mrd.cell = cell;
267 mrd.attributes = cell->attributes;
268 mrd.clk_enable = cell->parameters.at(ID::CLK_ENABLE).as_bool();
269 mrd.clk_polarity = cell->parameters.at(ID::CLK_POLARITY).as_bool();
270 mrd.transparent = cell->parameters.at(ID::TRANSPARENT).as_bool();
271 mrd.clk = cell->getPort(ID::CLK);
272 mrd.en = cell->getPort(ID::EN);
273 mrd.addr = cell->getPort(ID::ADDR);
274 mrd.data = cell->getPort(ID::DATA);
275 res.rd_ports.push_back(mrd);
276 }
277 }
278 if (index.wr_ports.count(mem->name)) {
279 std::vector<std::pair<int, MemWr>> ports;
280 for (auto cell : index.wr_ports.at(mem->name)) {
281 MemWr mwr;
282 mwr.cell = cell;
283 mwr.attributes = cell->attributes;
284 mwr.clk_enable = cell->parameters.at(ID::CLK_ENABLE).as_bool();
285 mwr.clk_polarity = cell->parameters.at(ID::CLK_POLARITY).as_bool();
286 mwr.clk = cell->getPort(ID::CLK);
287 mwr.en = cell->getPort(ID::EN);
288 mwr.addr = cell->getPort(ID::ADDR);
289 mwr.data = cell->getPort(ID::DATA);
290 ports.push_back(std::make_pair(cell->parameters.at(ID::PRIORITY).as_int(), mwr));
291 }
292 std::sort(ports.begin(), ports.end(), [](const std::pair<int, MemWr> &a, const std::pair<int, MemWr> &b) { return a.first < b.first; });
293 for (auto &it : ports)
294 res.wr_ports.push_back(it.second);
295 }
296 if (index.inits.count(mem->name)) {
297 std::vector<std::pair<int, MemInit>> inits;
298 for (auto cell : index.inits.at(mem->name)) {
299 MemInit init;
300 init.cell = cell;
301 init.attributes = cell->attributes;
302 auto addr = cell->getPort(ID::ADDR);
303 auto data = cell->getPort(ID::DATA);
304 if (!addr.is_fully_const())
305 log_error("Non-constant address %s in memory initialization %s.\n", log_signal(addr), log_id(cell));
306 if (!data.is_fully_const())
307 log_error("Non-constant data %s in memory initialization %s.\n", log_signal(data), log_id(cell));
308 init.addr = addr.as_const();
309 init.data = data.as_const();
310 inits.push_back(std::make_pair(cell->parameters.at(ID::PRIORITY).as_int(), init));
311 }
312 std::sort(inits.begin(), inits.end(), [](const std::pair<int, MemInit> &a, const std::pair<int, MemInit> &b) { return a.first < b.first; });
313 for (auto &it : inits)
314 res.inits.push_back(it.second);
315 }
316 return res;
317 }
318
319 Mem mem_from_cell(Cell *cell) {
320 Mem res(cell->module, cell->parameters.at(ID::MEMID).decode_string(),
321 cell->parameters.at(ID::WIDTH).as_int(),
322 cell->parameters.at(ID::OFFSET).as_int(),
323 cell->parameters.at(ID::SIZE).as_int()
324 );
325 int abits = cell->parameters.at(ID::ABITS).as_int();
326 res.packed = true;
327 res.cell = cell;
328 res.attributes = cell->attributes;
329 Const &init = cell->parameters.at(ID::INIT);
330 if (!init.is_fully_undef()) {
331 int pos = 0;
332 while (pos < res.size) {
333 Const word = init.extract(pos * res.width, res.width, State::Sx);
334 if (word.is_fully_undef()) {
335 pos++;
336 } else {
337 int epos;
338 for (epos = pos; epos < res.size; epos++) {
339 Const eword = init.extract(epos * res.width, res.width, State::Sx);
340 if (eword.is_fully_undef())
341 break;
342 }
343 MemInit minit;
344 minit.addr = res.start_offset + pos;
345 minit.data = init.extract(pos * res.width, (epos - pos) * res.width, State::Sx);
346 res.inits.push_back(minit);
347 pos = epos;
348 }
349 }
350 }
351 for (int i = 0; i < cell->parameters.at(ID::RD_PORTS).as_int(); i++) {
352 MemRd mrd;
353 mrd.clk_enable = cell->parameters.at(ID::RD_CLK_ENABLE).extract(i, 1).as_bool();
354 mrd.clk_polarity = cell->parameters.at(ID::RD_CLK_POLARITY).extract(i, 1).as_bool();
355 mrd.transparent = cell->parameters.at(ID::RD_TRANSPARENT).extract(i, 1).as_bool();
356 mrd.clk = cell->getPort(ID::RD_CLK).extract(i, 1);
357 mrd.en = cell->getPort(ID::RD_EN).extract(i, 1);
358 mrd.addr = cell->getPort(ID::RD_ADDR).extract(i * abits, abits);
359 mrd.data = cell->getPort(ID::RD_DATA).extract(i * res.width, res.width);
360 res.rd_ports.push_back(mrd);
361 }
362 for (int i = 0; i < cell->parameters.at(ID::WR_PORTS).as_int(); i++) {
363 MemWr mwr;
364 mwr.clk_enable = cell->parameters.at(ID::WR_CLK_ENABLE).extract(i, 1).as_bool();
365 mwr.clk_polarity = cell->parameters.at(ID::WR_CLK_POLARITY).extract(i, 1).as_bool();
366 mwr.clk = cell->getPort(ID::WR_CLK).extract(i, 1);
367 mwr.en = cell->getPort(ID::WR_EN).extract(i * res.width, res.width);
368 mwr.addr = cell->getPort(ID::WR_ADDR).extract(i * abits, abits);
369 mwr.data = cell->getPort(ID::WR_DATA).extract(i * res.width, res.width);
370 res.wr_ports.push_back(mwr);
371 }
372 return res;
373 }
374
375 }
376
377 std::vector<Mem> Mem::get_all_memories(Module *module) {
378 std::vector<Mem> res;
379 MemIndex index(module);
380 for (auto it: module->memories) {
381 res.push_back(mem_from_memory(module, it.second, index));
382 }
383 for (auto cell: module->cells()) {
384 if (cell->type == ID($mem))
385 res.push_back(mem_from_cell(cell));
386 }
387 return res;
388 }
389
390 std::vector<Mem> Mem::get_selected_memories(Module *module) {
391 std::vector<Mem> res;
392 MemIndex index(module);
393 for (auto it: module->memories) {
394 if (module->design->selected(module, it.second))
395 res.push_back(mem_from_memory(module, it.second, index));
396 }
397 for (auto cell: module->selected_cells()) {
398 if (cell->type == ID($mem))
399 res.push_back(mem_from_cell(cell));
400 }
401 return res;
402 }
403
404 Cell *Mem::extract_rdff(int idx) {
405 MemRd &port = rd_ports[idx];
406
407 if (!port.clk_enable)
408 return nullptr;
409
410 Cell *c;
411
412 if (port.transparent)
413 {
414 SigSpec sig_q = module->addWire(stringf("%s$rdreg[%d]$q", memid.c_str(), idx), GetSize(port.addr));
415 SigSpec sig_d = port.addr;
416 port.addr = sig_q;
417 c = module->addDffe(stringf("%s$rdreg[%d]", memid.c_str(), idx), port.clk, port.en, sig_d, sig_q, port.clk_polarity, true);
418 }
419 else
420 {
421 SigSpec sig_d = module->addWire(stringf("%s$rdreg[%d]$d", memid.c_str(), idx), width);
422 SigSpec sig_q = port.data;
423 port.data = sig_d;
424 c = module->addDffe(stringf("%s$rdreg[%d]", memid.c_str(), idx), port.clk, port.en, sig_d, sig_q, port.clk_polarity, true);
425 }
426
427 log("Extracted %s FF from read port %d of %s.%s: %s\n", port.transparent ? "addr" : "data",
428 idx, log_id(module), log_id(memid), log_id(c));
429
430 port.en = State::S1;
431 port.clk = State::S0;
432 port.clk_enable = false;
433 port.clk_polarity = true;
434
435 return c;
436 }