2 * yosys -- Yosys Open SYnthesis Suite
4 * Copyright (C) 2020 Marcelina KoĆcielnicka <mwk@0x04.net>
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/mem.h"
30 module
->memories
.erase(mem
->name
);
34 for (auto &port
: rd_ports
) {
36 module
->remove(port
.cell
);
40 for (auto &port
: wr_ports
) {
42 module
->remove(port
.cell
);
46 for (auto &init
: inits
) {
48 module
->remove(init
.cell
);
56 std::vector
<int> rd_left
;
57 for (int i
= 0; i
< GetSize(rd_ports
); i
++) {
58 auto &port
= rd_ports
[i
];
61 module
->remove(port
.cell
);
67 std::vector
<int> wr_left
;
68 for (int i
= 0; i
< GetSize(wr_ports
); i
++) {
69 auto &port
= wr_ports
[i
];
72 module
->remove(port
.cell
);
78 for (int i
= 0; i
< GetSize(rd_left
); i
++)
80 std::swap(rd_ports
[i
], rd_ports
[rd_left
[i
]]);
81 rd_ports
.resize(GetSize(rd_left
));
82 for (int i
= 0; i
< GetSize(wr_left
); i
++)
84 std::swap(wr_ports
[i
], wr_ports
[wr_left
[i
]]);
85 wr_ports
.resize(GetSize(wr_left
));
87 // for future: handle transparency mask here
89 for (auto &port
: wr_ports
) {
90 for (int i
= 0; i
< GetSize(wr_left
); i
++)
91 port
.priority_mask
[i
] = port
.priority_mask
[wr_left
[i
]];
92 port
.priority_mask
.resize(GetSize(wr_left
));
97 module
->memories
.erase(mem
->name
);
104 cell
= module
->addCell(memid
, ID($mem
));
106 cell
->attributes
= attributes
;
107 cell
->parameters
[ID::MEMID
] = Const(memid
.str());
108 cell
->parameters
[ID::WIDTH
] = Const(width
);
109 cell
->parameters
[ID::OFFSET
] = Const(start_offset
);
110 cell
->parameters
[ID::SIZE
] = Const(size
);
111 cell
->parameters
[ID::RD_PORTS
] = Const(GetSize(rd_ports
));
112 cell
->parameters
[ID::WR_PORTS
] = Const(GetSize(wr_ports
));
113 Const rd_clk_enable
, rd_clk_polarity
, rd_transparent
;
114 Const wr_clk_enable
, wr_clk_polarity
;
115 SigSpec rd_clk
, rd_en
, rd_addr
, rd_data
;
116 SigSpec wr_clk
, wr_en
, wr_addr
, wr_data
;
118 for (auto &port
: rd_ports
)
119 abits
= std::max(abits
, GetSize(port
.addr
));
120 for (auto &port
: wr_ports
)
121 abits
= std::max(abits
, GetSize(port
.addr
));
122 cell
->parameters
[ID::ABITS
] = Const(abits
);
123 for (auto &port
: rd_ports
) {
125 log_assert(port
.wide_log2
== 0);
127 module
->remove(port
.cell
);
130 rd_clk_enable
.bits
.push_back(State(port
.clk_enable
));
131 rd_clk_polarity
.bits
.push_back(State(port
.clk_polarity
));
132 rd_transparent
.bits
.push_back(State(port
.transparent
));
133 rd_clk
.append(port
.clk
);
134 log_assert(GetSize(port
.clk
) == 1);
135 rd_en
.append(port
.en
);
136 log_assert(GetSize(port
.en
) == 1);
137 SigSpec addr
= port
.addr
;
138 addr
.extend_u0(abits
, false);
139 rd_addr
.append(addr
);
140 log_assert(GetSize(addr
) == abits
);
141 rd_data
.append(port
.data
);
142 log_assert(GetSize(port
.data
) == width
);
144 if (rd_ports
.empty()) {
145 rd_clk_enable
= State::S0
;
146 rd_clk_polarity
= State::S0
;
147 rd_transparent
= State::S0
;
149 cell
->parameters
[ID::RD_CLK_ENABLE
] = rd_clk_enable
;
150 cell
->parameters
[ID::RD_CLK_POLARITY
] = rd_clk_polarity
;
151 cell
->parameters
[ID::RD_TRANSPARENT
] = rd_transparent
;
152 cell
->setPort(ID::RD_CLK
, rd_clk
);
153 cell
->setPort(ID::RD_EN
, rd_en
);
154 cell
->setPort(ID::RD_ADDR
, rd_addr
);
155 cell
->setPort(ID::RD_DATA
, rd_data
);
156 for (auto &port
: wr_ports
) {
158 log_assert(port
.wide_log2
== 0);
160 module
->remove(port
.cell
);
163 wr_clk_enable
.bits
.push_back(State(port
.clk_enable
));
164 wr_clk_polarity
.bits
.push_back(State(port
.clk_polarity
));
165 wr_clk
.append(port
.clk
);
166 log_assert(GetSize(port
.clk
) == 1);
167 wr_en
.append(port
.en
);
168 log_assert(GetSize(port
.en
) == width
);
169 SigSpec addr
= port
.addr
;
170 addr
.extend_u0(abits
, false);
171 wr_addr
.append(addr
);
172 log_assert(GetSize(addr
) == abits
);
173 wr_data
.append(port
.data
);
174 log_assert(GetSize(port
.data
) == width
);
176 if (wr_ports
.empty()) {
177 wr_clk_enable
= State::S0
;
178 wr_clk_polarity
= State::S0
;
180 cell
->parameters
[ID::WR_CLK_ENABLE
] = wr_clk_enable
;
181 cell
->parameters
[ID::WR_CLK_POLARITY
] = wr_clk_polarity
;
182 cell
->setPort(ID::WR_CLK
, wr_clk
);
183 cell
->setPort(ID::WR_EN
, wr_en
);
184 cell
->setPort(ID::WR_ADDR
, wr_addr
);
185 cell
->setPort(ID::WR_DATA
, wr_data
);
186 for (auto &init
: inits
) {
188 module
->remove(init
.cell
);
192 cell
->parameters
[ID::INIT
] = get_init_data();
195 module
->remove(cell
);
201 mem
= new RTLIL::Memory
;
203 module
->memories
[memid
] = mem
;
206 mem
->start_offset
= start_offset
;
208 for (auto &port
: rd_ports
) {
210 port
.cell
= module
->addCell(NEW_ID
, ID($memrd
));
211 port
.cell
->parameters
[ID::MEMID
] = memid
.str();
212 port
.cell
->parameters
[ID::ABITS
] = GetSize(port
.addr
);
213 port
.cell
->parameters
[ID::WIDTH
] = width
<< port
.wide_log2
;
214 port
.cell
->parameters
[ID::CLK_ENABLE
] = port
.clk_enable
;
215 port
.cell
->parameters
[ID::CLK_POLARITY
] = port
.clk_polarity
;
216 port
.cell
->parameters
[ID::TRANSPARENT
] = port
.transparent
;
217 port
.cell
->setPort(ID::CLK
, port
.clk
);
218 port
.cell
->setPort(ID::EN
, port
.en
);
219 port
.cell
->setPort(ID::ADDR
, port
.addr
);
220 port
.cell
->setPort(ID::DATA
, port
.data
);
223 for (auto &port
: wr_ports
) {
225 port
.cell
= module
->addCell(NEW_ID
, ID($memwr
));
226 port
.cell
->parameters
[ID::MEMID
] = memid
.str();
227 port
.cell
->parameters
[ID::ABITS
] = GetSize(port
.addr
);
228 port
.cell
->parameters
[ID::WIDTH
] = width
<< port
.wide_log2
;
229 port
.cell
->parameters
[ID::CLK_ENABLE
] = port
.clk_enable
;
230 port
.cell
->parameters
[ID::CLK_POLARITY
] = port
.clk_polarity
;
231 port
.cell
->parameters
[ID::PRIORITY
] = idx
++;
232 port
.cell
->setPort(ID::CLK
, port
.clk
);
233 port
.cell
->setPort(ID::EN
, port
.en
);
234 port
.cell
->setPort(ID::ADDR
, port
.addr
);
235 port
.cell
->setPort(ID::DATA
, port
.data
);
238 for (auto &init
: inits
) {
240 init
.cell
= module
->addCell(NEW_ID
, ID($meminit
));
241 init
.cell
->parameters
[ID::MEMID
] = memid
.str();
242 init
.cell
->parameters
[ID::ABITS
] = GetSize(init
.addr
);
243 init
.cell
->parameters
[ID::WIDTH
] = width
;
244 init
.cell
->parameters
[ID::WORDS
] = GetSize(init
.data
) / width
;
245 init
.cell
->parameters
[ID::PRIORITY
] = idx
++;
246 init
.cell
->setPort(ID::ADDR
, init
.addr
);
247 init
.cell
->setPort(ID::DATA
, init
.data
);
252 void Mem::clear_inits() {
253 for (auto &init
: inits
)
255 module
->remove(init
.cell
);
259 Const
Mem::get_init_data() const {
260 Const
init_data(State::Sx
, width
* size
);
261 for (auto &init
: inits
) {
262 int offset
= (init
.addr
.as_int() - start_offset
) * width
;
263 for (int i
= 0; i
< GetSize(init
.data
); i
++)
264 if (0 <= i
+offset
&& i
+offset
< GetSize(init_data
))
265 init_data
.bits
[i
+offset
] = init
.data
.bits
[i
];
271 int max_wide_log2
= 0;
272 for (auto &port
: rd_ports
) {
275 log_assert(GetSize(port
.clk
) == 1);
276 log_assert(GetSize(port
.en
) == 1);
277 log_assert(GetSize(port
.data
) == (width
<< port
.wide_log2
));
278 if (!port
.clk_enable
) {
279 log_assert(!port
.transparent
);
281 for (int j
= 0; j
< port
.wide_log2
; j
++) {
282 log_assert(port
.addr
[j
] == State::S0
);
284 max_wide_log2
= std::max(max_wide_log2
, port
.wide_log2
);
286 for (int i
= 0; i
< GetSize(wr_ports
); i
++) {
287 auto &port
= wr_ports
[i
];
290 log_assert(GetSize(port
.clk
) == 1);
291 log_assert(GetSize(port
.en
) == (width
<< port
.wide_log2
));
292 log_assert(GetSize(port
.data
) == (width
<< port
.wide_log2
));
293 for (int j
= 0; j
< port
.wide_log2
; j
++) {
294 log_assert(port
.addr
[j
] == State::S0
);
296 max_wide_log2
= std::max(max_wide_log2
, port
.wide_log2
);
297 log_assert(GetSize(port
.priority_mask
) == GetSize(wr_ports
));
298 for (int j
= 0; j
< GetSize(wr_ports
); j
++) {
299 auto &wport
= wr_ports
[j
];
300 if (port
.priority_mask
[j
] && !wport
.removed
) {
302 log_assert(port
.clk_enable
== wport
.clk_enable
);
303 if (port
.clk_enable
) {
304 log_assert(port
.clk
== wport
.clk
);
305 log_assert(port
.clk_polarity
== wport
.clk_polarity
);
310 int mask
= (1 << max_wide_log2
) - 1;
311 log_assert(!(start_offset
& mask
));
312 log_assert(!(size
& mask
));
318 dict
<IdString
, pool
<Cell
*>> rd_ports
;
319 dict
<IdString
, pool
<Cell
*>> wr_ports
;
320 dict
<IdString
, pool
<Cell
*>> inits
;
321 MemIndex (Module
*module
) {
322 for (auto cell
: module
->cells()) {
323 if (cell
->type
== ID($memwr
))
324 wr_ports
[cell
->parameters
.at(ID::MEMID
).decode_string()].insert(cell
);
325 else if (cell
->type
== ID($memrd
))
326 rd_ports
[cell
->parameters
.at(ID::MEMID
).decode_string()].insert(cell
);
327 else if (cell
->type
== ID($meminit
))
328 inits
[cell
->parameters
.at(ID::MEMID
).decode_string()].insert(cell
);
333 Mem
mem_from_memory(Module
*module
, RTLIL::Memory
*mem
, const MemIndex
&index
) {
334 Mem
res(module
, mem
->name
, mem
->width
, mem
->start_offset
, mem
->size
);
337 res
.attributes
= mem
->attributes
;
338 if (index
.rd_ports
.count(mem
->name
)) {
339 for (auto cell
: index
.rd_ports
.at(mem
->name
)) {
342 mrd
.attributes
= cell
->attributes
;
343 mrd
.clk_enable
= cell
->parameters
.at(ID::CLK_ENABLE
).as_bool();
344 mrd
.clk_polarity
= cell
->parameters
.at(ID::CLK_POLARITY
).as_bool();
345 mrd
.transparent
= cell
->parameters
.at(ID::TRANSPARENT
).as_bool();
346 mrd
.clk
= cell
->getPort(ID::CLK
);
347 mrd
.en
= cell
->getPort(ID::EN
);
348 mrd
.addr
= cell
->getPort(ID::ADDR
);
349 mrd
.data
= cell
->getPort(ID::DATA
);
350 mrd
.wide_log2
= ceil_log2(GetSize(mrd
.data
) / mem
->width
);
351 res
.rd_ports
.push_back(mrd
);
354 if (index
.wr_ports
.count(mem
->name
)) {
355 std::vector
<std::pair
<int, MemWr
>> ports
;
356 for (auto cell
: index
.wr_ports
.at(mem
->name
)) {
359 mwr
.attributes
= cell
->attributes
;
360 mwr
.clk_enable
= cell
->parameters
.at(ID::CLK_ENABLE
).as_bool();
361 mwr
.clk_polarity
= cell
->parameters
.at(ID::CLK_POLARITY
).as_bool();
362 mwr
.clk
= cell
->getPort(ID::CLK
);
363 mwr
.en
= cell
->getPort(ID::EN
);
364 mwr
.addr
= cell
->getPort(ID::ADDR
);
365 mwr
.data
= cell
->getPort(ID::DATA
);
366 mwr
.wide_log2
= ceil_log2(GetSize(mwr
.data
) / mem
->width
);
367 ports
.push_back(std::make_pair(cell
->parameters
.at(ID::PRIORITY
).as_int(), mwr
));
369 std::sort(ports
.begin(), ports
.end(), [](const std::pair
<int, MemWr
> &a
, const std::pair
<int, MemWr
> &b
) { return a
.first
< b
.first
; });
370 for (auto &it
: ports
)
371 res
.wr_ports
.push_back(it
.second
);
373 if (index
.inits
.count(mem
->name
)) {
374 std::vector
<std::pair
<int, MemInit
>> inits
;
375 for (auto cell
: index
.inits
.at(mem
->name
)) {
378 init
.attributes
= cell
->attributes
;
379 auto addr
= cell
->getPort(ID::ADDR
);
380 auto data
= cell
->getPort(ID::DATA
);
381 if (!addr
.is_fully_const())
382 log_error("Non-constant address %s in memory initialization %s.\n", log_signal(addr
), log_id(cell
));
383 if (!data
.is_fully_const())
384 log_error("Non-constant data %s in memory initialization %s.\n", log_signal(data
), log_id(cell
));
385 init
.addr
= addr
.as_const();
386 init
.data
= data
.as_const();
387 inits
.push_back(std::make_pair(cell
->parameters
.at(ID::PRIORITY
).as_int(), init
));
389 std::sort(inits
.begin(), inits
.end(), [](const std::pair
<int, MemInit
> &a
, const std::pair
<int, MemInit
> &b
) { return a
.first
< b
.first
; });
390 for (auto &it
: inits
)
391 res
.inits
.push_back(it
.second
);
393 for (int i
= 0; i
< GetSize(res
.wr_ports
); i
++) {
394 auto &port
= res
.wr_ports
[i
];
395 port
.priority_mask
.resize(GetSize(res
.wr_ports
));
396 for (int j
= 0; j
< i
; j
++) {
397 auto &oport
= res
.wr_ports
[j
];
398 if (port
.clk_enable
!= oport
.clk_enable
)
400 if (port
.clk_enable
&& port
.clk
!= oport
.clk
)
402 if (port
.clk_enable
&& port
.clk_polarity
!= oport
.clk_polarity
)
404 port
.priority_mask
[j
] = true;
411 Mem
mem_from_cell(Cell
*cell
) {
412 Mem
res(cell
->module
, cell
->parameters
.at(ID::MEMID
).decode_string(),
413 cell
->parameters
.at(ID::WIDTH
).as_int(),
414 cell
->parameters
.at(ID::OFFSET
).as_int(),
415 cell
->parameters
.at(ID::SIZE
).as_int()
417 int abits
= cell
->parameters
.at(ID::ABITS
).as_int();
420 res
.attributes
= cell
->attributes
;
421 Const
&init
= cell
->parameters
.at(ID::INIT
);
422 if (!init
.is_fully_undef()) {
424 while (pos
< res
.size
) {
425 Const word
= init
.extract(pos
* res
.width
, res
.width
, State::Sx
);
426 if (word
.is_fully_undef()) {
430 for (epos
= pos
; epos
< res
.size
; epos
++) {
431 Const eword
= init
.extract(epos
* res
.width
, res
.width
, State::Sx
);
432 if (eword
.is_fully_undef())
436 minit
.addr
= res
.start_offset
+ pos
;
437 minit
.data
= init
.extract(pos
* res
.width
, (epos
- pos
) * res
.width
, State::Sx
);
438 res
.inits
.push_back(minit
);
443 for (int i
= 0; i
< cell
->parameters
.at(ID::RD_PORTS
).as_int(); i
++) {
446 mrd
.clk_enable
= cell
->parameters
.at(ID::RD_CLK_ENABLE
).extract(i
, 1).as_bool();
447 mrd
.clk_polarity
= cell
->parameters
.at(ID::RD_CLK_POLARITY
).extract(i
, 1).as_bool();
448 mrd
.transparent
= cell
->parameters
.at(ID::RD_TRANSPARENT
).extract(i
, 1).as_bool();
449 mrd
.clk
= cell
->getPort(ID::RD_CLK
).extract(i
, 1);
450 mrd
.en
= cell
->getPort(ID::RD_EN
).extract(i
, 1);
451 mrd
.addr
= cell
->getPort(ID::RD_ADDR
).extract(i
* abits
, abits
);
452 mrd
.data
= cell
->getPort(ID::RD_DATA
).extract(i
* res
.width
, res
.width
);
453 res
.rd_ports
.push_back(mrd
);
455 for (int i
= 0; i
< cell
->parameters
.at(ID::WR_PORTS
).as_int(); i
++) {
458 mwr
.clk_enable
= cell
->parameters
.at(ID::WR_CLK_ENABLE
).extract(i
, 1).as_bool();
459 mwr
.clk_polarity
= cell
->parameters
.at(ID::WR_CLK_POLARITY
).extract(i
, 1).as_bool();
460 mwr
.clk
= cell
->getPort(ID::WR_CLK
).extract(i
, 1);
461 mwr
.en
= cell
->getPort(ID::WR_EN
).extract(i
* res
.width
, res
.width
);
462 mwr
.addr
= cell
->getPort(ID::WR_ADDR
).extract(i
* abits
, abits
);
463 mwr
.data
= cell
->getPort(ID::WR_DATA
).extract(i
* res
.width
, res
.width
);
464 res
.wr_ports
.push_back(mwr
);
466 for (int i
= 0; i
< GetSize(res
.wr_ports
); i
++) {
467 auto &port
= res
.wr_ports
[i
];
468 port
.priority_mask
.resize(GetSize(res
.wr_ports
));
469 for (int j
= 0; j
< i
; j
++) {
470 auto &oport
= res
.wr_ports
[j
];
471 if (port
.clk_enable
!= oport
.clk_enable
)
473 if (port
.clk_enable
&& port
.clk
!= oport
.clk
)
475 if (port
.clk_enable
&& port
.clk_polarity
!= oport
.clk_polarity
)
477 port
.priority_mask
[j
] = true;
486 std::vector
<Mem
> Mem::get_all_memories(Module
*module
) {
487 std::vector
<Mem
> res
;
488 MemIndex
index(module
);
489 for (auto it
: module
->memories
) {
490 res
.push_back(mem_from_memory(module
, it
.second
, index
));
492 for (auto cell
: module
->cells()) {
493 if (cell
->type
== ID($mem
))
494 res
.push_back(mem_from_cell(cell
));
499 std::vector
<Mem
> Mem::get_selected_memories(Module
*module
) {
500 std::vector
<Mem
> res
;
501 MemIndex
index(module
);
502 for (auto it
: module
->memories
) {
503 if (module
->design
->selected(module
, it
.second
))
504 res
.push_back(mem_from_memory(module
, it
.second
, index
));
506 for (auto cell
: module
->selected_cells()) {
507 if (cell
->type
== ID($mem
))
508 res
.push_back(mem_from_cell(cell
));
513 Cell
*Mem::extract_rdff(int idx
, FfInitVals
*initvals
) {
514 MemRd
&port
= rd_ports
[idx
];
516 if (!port
.clk_enable
)
521 if (port
.transparent
)
523 SigSpec sig_q
= module
->addWire(stringf("%s$rdreg[%d]$q", memid
.c_str(), idx
), GetSize(port
.addr
));
524 SigSpec sig_d
= port
.addr
;
526 c
= module
->addDffe(stringf("%s$rdreg[%d]", memid
.c_str(), idx
), port
.clk
, port
.en
, sig_d
, sig_q
, port
.clk_polarity
, true);
530 SigSpec sig_d
= module
->addWire(stringf("%s$rdreg[%d]$d", memid
.c_str(), idx
), GetSize(port
.data
));
531 SigSpec sig_q
= port
.data
;
533 c
= module
->addDffe(stringf("%s$rdreg[%d]", memid
.c_str(), idx
), port
.clk
, port
.en
, sig_d
, sig_q
, port
.clk_polarity
, true);
536 log("Extracted %s FF from read port %d of %s.%s: %s\n", port
.transparent
? "addr" : "data",
537 idx
, log_id(module
), log_id(memid
), log_id(c
));
540 port
.clk
= State::S0
;
541 port
.clk_enable
= false;
542 port
.clk_polarity
= true;
543 port
.transparent
= false;