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
);
57 module
->memories
.erase(mem
->name
);
64 cell
= module
->addCell(memid
, ID($mem
));
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
;
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
) {
85 module
->remove(port
.cell
);
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);
98 log_assert(GetSize(addr
) == abits
);
99 rd_data
.append(port
.data
);
100 log_assert(GetSize(port
.data
) == width
);
102 if (rd_ports
.empty()) {
103 rd_clk_enable
= State::S0
;
104 rd_clk_polarity
= State::S0
;
105 rd_transparent
= State::S0
;
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
) {
116 module
->remove(port
.cell
);
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
);
132 if (wr_ports
.empty()) {
133 wr_clk_enable
= State::S0
;
134 wr_clk_polarity
= State::S0
;
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
) {
144 module
->remove(init
.cell
);
148 cell
->parameters
[ID::INIT
] = get_init_data();
151 module
->remove(cell
);
157 mem
= new RTLIL::Memory
;
159 module
->memories
[memid
] = mem
;
162 mem
->start_offset
= start_offset
;
164 for (auto &port
: rd_ports
) {
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
);
179 for (auto &port
: wr_ports
) {
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
);
194 for (auto &init
: inits
) {
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
);
208 void Mem::remove_wr_port(int idx
) {
209 if (wr_ports
[idx
].cell
) {
210 module
->remove(wr_ports
[idx
].cell
);
212 wr_ports
.erase(wr_ports
.begin() + idx
);
215 void Mem::remove_rd_port(int idx
) {
216 if (rd_ports
[idx
].cell
) {
217 module
->remove(rd_ports
[idx
].cell
);
219 rd_ports
.erase(rd_ports
.begin() + idx
);
222 void Mem::clear_inits() {
223 for (auto &init
: inits
)
225 module
->remove(init
.cell
);
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
];
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
);
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
);
262 res
.attributes
= mem
->attributes
;
263 if (index
.rd_ports
.count(mem
->name
)) {
264 for (auto cell
: index
.rd_ports
.at(mem
->name
)) {
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
);
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
)) {
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
));
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
);
296 if (index
.inits
.count(mem
->name
)) {
297 std::vector
<std::pair
<int, MemInit
>> inits
;
298 for (auto cell
: index
.inits
.at(mem
->name
)) {
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
));
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
);
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()
325 int abits
= cell
->parameters
.at(ID::ABITS
).as_int();
328 res
.attributes
= cell
->attributes
;
329 Const
&init
= cell
->parameters
.at(ID::INIT
);
330 if (!init
.is_fully_undef()) {
332 while (pos
< res
.size
) {
333 Const word
= init
.extract(pos
* res
.width
, res
.width
, State::Sx
);
334 if (word
.is_fully_undef()) {
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())
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
);
351 for (int i
= 0; i
< cell
->parameters
.at(ID::RD_PORTS
).as_int(); i
++) {
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
);
362 for (int i
= 0; i
< cell
->parameters
.at(ID::WR_PORTS
).as_int(); i
++) {
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
);
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
));
383 for (auto cell
: module
->cells()) {
384 if (cell
->type
== ID($mem
))
385 res
.push_back(mem_from_cell(cell
));
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
));
397 for (auto cell
: module
->selected_cells()) {
398 if (cell
->type
== ID($mem
))
399 res
.push_back(mem_from_cell(cell
));
404 Cell
*Mem::extract_rdff(int idx
) {
405 MemRd
&port
= rd_ports
[idx
];
407 if (!port
.clk_enable
)
412 if (port
.transparent
)
414 SigSpec sig_q
= module
->addWire(stringf("%s$rdreg[%d]$q", memid
.c_str(), idx
), GetSize(port
.addr
));
415 SigSpec sig_d
= port
.addr
;
417 c
= module
->addDffe(stringf("%s$rdreg[%d]", memid
.c_str(), idx
), port
.clk
, port
.en
, sig_d
, sig_q
, port
.clk_polarity
, true);
421 SigSpec sig_d
= module
->addWire(stringf("%s$rdreg[%d]$d", memid
.c_str(), idx
), width
);
422 SigSpec sig_q
= port
.data
;
424 c
= module
->addDffe(stringf("%s$rdreg[%d]", memid
.c_str(), idx
), port
.clk
, port
.en
, sig_d
, sig_q
, port
.clk_polarity
, true);
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
));
431 port
.clk
= State::S0
;
432 port
.clk_enable
= false;
433 port
.clk_polarity
= true;