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/register.h"
21 #include "kernel/log.h"
27 PRIVATE_NAMESPACE_BEGIN
29 struct MemoryMapWorker
31 RTLIL::Design
*design
;
32 RTLIL::Module
*module
;
34 std::map
<std::pair
<RTLIL::SigSpec
, RTLIL::SigSpec
>, RTLIL::SigBit
> decoder_cache
;
36 std::string
genid(RTLIL::IdString name
, std::string token1
= "", int i
= -1, std::string token2
= "", int j
= -1, std::string token3
= "", int k
= -1, std::string token4
= "")
38 std::stringstream sstr
;
39 sstr
<< "$memory" << name
.str() << token1
;
42 sstr
<< "[" << i
<< "]";
47 sstr
<< "[" << j
<< "]";
52 sstr
<< "[" << k
<< "]";
54 sstr
<< token4
<< "$" << (autoidx
++);
58 RTLIL::Wire
*addr_decode(RTLIL::SigSpec addr_sig
, RTLIL::SigSpec addr_val
)
60 std::pair
<RTLIL::SigSpec
, RTLIL::SigSpec
> key(addr_sig
, addr_val
);
61 log_assert(GetSize(addr_sig
) == GetSize(addr_val
));
63 if (decoder_cache
.count(key
) == 0) {
64 if (GetSize(addr_sig
) < 2) {
65 decoder_cache
[key
] = module
->Eq(NEW_ID
, addr_sig
, addr_val
);
67 int split_at
= GetSize(addr_sig
) / 2;
68 RTLIL::SigBit left_eq
= addr_decode(addr_sig
.extract(0, split_at
), addr_val
.extract(0, split_at
));
69 RTLIL::SigBit right_eq
= addr_decode(addr_sig
.extract(split_at
, GetSize(addr_sig
) - split_at
), addr_val
.extract(split_at
, GetSize(addr_val
) - split_at
));
70 decoder_cache
[key
] = module
->And(NEW_ID
, left_eq
, right_eq
);
74 RTLIL::SigBit bit
= decoder_cache
.at(key
);
75 log_assert(bit
.wire
!= nullptr && GetSize(bit
.wire
) == 1);
79 void handle_cell(RTLIL::Cell
*cell
)
81 std::set
<int> static_ports
;
82 std::map
<int, RTLIL::SigSpec
> static_cells_map
;
84 int wr_ports
= cell
->parameters
["\\WR_PORTS"].as_int();
85 int rd_ports
= cell
->parameters
["\\RD_PORTS"].as_int();
87 int mem_size
= cell
->parameters
["\\SIZE"].as_int();
88 int mem_width
= cell
->parameters
["\\WIDTH"].as_int();
89 int mem_offset
= cell
->parameters
["\\OFFSET"].as_int();
90 int mem_abits
= cell
->parameters
["\\ABITS"].as_int();
92 SigSpec init_data
= cell
->getParam("\\INIT");
93 init_data
.extend_u0(mem_size
*mem_width
, true);
95 // delete unused memory cell
96 if (wr_ports
== 0 && rd_ports
== 0) {
101 // all write ports must share the same clock
102 RTLIL::SigSpec clocks
= cell
->getPort("\\WR_CLK");
103 RTLIL::Const clocks_pol
= cell
->parameters
["\\WR_CLK_POLARITY"];
104 RTLIL::Const clocks_en
= cell
->parameters
["\\WR_CLK_ENABLE"];
105 clocks_pol
.bits
.resize(wr_ports
);
106 clocks_en
.bits
.resize(wr_ports
);
107 RTLIL::SigSpec refclock
;
108 RTLIL::State refclock_pol
= RTLIL::State::Sx
;
109 for (int i
= 0; i
< clocks
.size(); i
++) {
110 RTLIL::SigSpec wr_en
= cell
->getPort("\\WR_EN").extract(i
* mem_width
, mem_width
);
111 if (wr_en
.is_fully_const() && !wr_en
.as_bool()) {
112 static_ports
.insert(i
);
115 if (clocks_en
.bits
[i
] != RTLIL::State::S1
) {
116 RTLIL::SigSpec wr_addr
= cell
->getPort("\\WR_ADDR").extract(i
*mem_abits
, mem_abits
);
117 RTLIL::SigSpec wr_data
= cell
->getPort("\\WR_DATA").extract(i
*mem_width
, mem_width
);
118 if (wr_addr
.is_fully_const()) {
119 // FIXME: Actually we should check for wr_en.is_fully_const() also and
120 // create a $adff cell with this ports wr_en input as reset pin when wr_en
121 // is not a simple static 1.
122 static_cells_map
[wr_addr
.as_int() - mem_offset
] = wr_data
;
123 static_ports
.insert(i
);
126 log("Not mapping memory cell %s in module %s (write port %d has no clock).\n",
127 cell
->name
.c_str(), module
->name
.c_str(), i
);
130 if (refclock
.size() == 0) {
131 refclock
= clocks
.extract(i
, 1);
132 refclock_pol
= clocks_pol
.bits
[i
];
134 if (clocks
.extract(i
, 1) != refclock
|| clocks_pol
.bits
[i
] != refclock_pol
) {
135 log("Not mapping memory cell %s in module %s (write clock %d is incompatible with other clocks).\n",
136 cell
->name
.c_str(), module
->name
.c_str(), i
);
141 log("Mapping memory cell %s in module %s:\n", cell
->name
.c_str(), module
->name
.c_str());
143 std::vector
<RTLIL::SigSpec
> data_reg_in
;
144 std::vector
<RTLIL::SigSpec
> data_reg_out
;
146 int count_static
= 0;
148 for (int i
= 0; i
< mem_size
; i
++)
150 if (static_cells_map
.count(i
) > 0)
152 data_reg_in
.push_back(RTLIL::SigSpec(RTLIL::State::Sz
, mem_width
));
153 data_reg_out
.push_back(static_cells_map
[i
]);
158 RTLIL::Cell
*c
= module
->addCell(genid(cell
->name
, "", i
), "$dff");
159 c
->parameters
["\\WIDTH"] = cell
->parameters
["\\WIDTH"];
160 if (clocks_pol
.bits
.size() > 0) {
161 c
->parameters
["\\CLK_POLARITY"] = RTLIL::Const(clocks_pol
.bits
[0]);
162 c
->setPort("\\CLK", clocks
.extract(0, 1));
164 c
->parameters
["\\CLK_POLARITY"] = RTLIL::Const(RTLIL::State::S1
);
165 c
->setPort("\\CLK", RTLIL::SigSpec(RTLIL::State::S0
));
168 RTLIL::Wire
*w_in
= module
->addWire(genid(cell
->name
, "", i
, "$d"), mem_width
);
169 data_reg_in
.push_back(RTLIL::SigSpec(w_in
));
170 c
->setPort("\\D", data_reg_in
.back());
172 std::string w_out_name
= stringf("%s[%d]", cell
->parameters
["\\MEMID"].decode_string().c_str(), i
);
173 if (module
->wires_
.count(w_out_name
) > 0)
174 w_out_name
= genid(cell
->name
, "", i
, "$q");
176 RTLIL::Wire
*w_out
= module
->addWire(w_out_name
, mem_width
);
177 SigSpec w_init
= init_data
.extract(i
*mem_width
, mem_width
);
179 if (!w_init
.is_fully_undef())
180 w_out
->attributes
["\\init"] = w_init
.as_const();
182 data_reg_out
.push_back(RTLIL::SigSpec(w_out
));
183 c
->setPort("\\Q", data_reg_out
.back());
187 log(" created %d $dff cells and %d static cells of width %d.\n", mem_size
-count_static
, count_static
, mem_width
);
189 int count_dff
= 0, count_mux
= 0, count_wrmux
= 0;
191 for (int i
= 0; i
< cell
->parameters
["\\RD_PORTS"].as_int(); i
++)
193 RTLIL::SigSpec rd_addr
= cell
->getPort("\\RD_ADDR").extract(i
*mem_abits
, mem_abits
);
196 rd_addr
= module
->Sub(NEW_ID
, rd_addr
, SigSpec(mem_offset
, GetSize(rd_addr
)));
198 std::vector
<RTLIL::SigSpec
> rd_signals
;
199 rd_signals
.push_back(cell
->getPort("\\RD_DATA").extract(i
*mem_width
, mem_width
));
201 if (cell
->parameters
["\\RD_CLK_ENABLE"].bits
[i
] == RTLIL::State::S1
)
203 RTLIL::Cell
*dff_cell
= nullptr;
205 if (cell
->parameters
["\\RD_TRANSPARENT"].bits
[i
] == RTLIL::State::S1
)
207 dff_cell
= module
->addCell(genid(cell
->name
, "$rdreg", i
), "$dff");
208 dff_cell
->parameters
["\\WIDTH"] = RTLIL::Const(mem_abits
);
209 dff_cell
->parameters
["\\CLK_POLARITY"] = RTLIL::Const(cell
->parameters
["\\RD_CLK_POLARITY"].bits
[i
]);
210 dff_cell
->setPort("\\CLK", cell
->getPort("\\RD_CLK").extract(i
, 1));
211 dff_cell
->setPort("\\D", rd_addr
);
214 RTLIL::Wire
*w
= module
->addWire(genid(cell
->name
, "$rdreg", i
, "$q"), mem_abits
);
216 dff_cell
->setPort("\\Q", RTLIL::SigSpec(w
));
217 rd_addr
= RTLIL::SigSpec(w
);
221 dff_cell
= module
->addCell(genid(cell
->name
, "$rdreg", i
), "$dff");
222 dff_cell
->parameters
["\\WIDTH"] = cell
->parameters
["\\WIDTH"];
223 dff_cell
->parameters
["\\CLK_POLARITY"] = RTLIL::Const(cell
->parameters
["\\RD_CLK_POLARITY"].bits
[i
]);
224 dff_cell
->setPort("\\CLK", cell
->getPort("\\RD_CLK").extract(i
, 1));
225 dff_cell
->setPort("\\Q", rd_signals
.back());
228 RTLIL::Wire
*w
= module
->addWire(genid(cell
->name
, "$rdreg", i
, "$d"), mem_width
);
231 rd_signals
.push_back(RTLIL::SigSpec(w
));
232 dff_cell
->setPort("\\D", rd_signals
.back());
235 SigBit en_bit
= cell
->getPort("\\RD_EN").extract(i
);
236 if (en_bit
!= State::S1
) {
237 SigSpec new_d
= module
->Mux(genid(cell
->name
, "$rdenmux", i
),
238 dff_cell
->getPort("\\Q"), dff_cell
->getPort("\\D"), en_bit
);
239 dff_cell
->setPort("\\D", new_d
);
243 for (int j
= 0; j
< mem_abits
; j
++)
245 std::vector
<RTLIL::SigSpec
> next_rd_signals
;
247 for (size_t k
= 0; k
< rd_signals
.size(); k
++)
249 RTLIL::Cell
*c
= module
->addCell(genid(cell
->name
, "$rdmux", i
, "", j
, "", k
), "$mux");
250 c
->parameters
["\\WIDTH"] = cell
->parameters
["\\WIDTH"];
251 c
->setPort("\\Y", rd_signals
[k
]);
252 c
->setPort("\\S", rd_addr
.extract(mem_abits
-j
-1, 1));
255 c
->setPort("\\A", module
->addWire(genid(cell
->name
, "$rdmux", i
, "", j
, "", k
, "$a"), mem_width
));
256 c
->setPort("\\B", module
->addWire(genid(cell
->name
, "$rdmux", i
, "", j
, "", k
, "$b"), mem_width
));
258 next_rd_signals
.push_back(c
->getPort("\\A"));
259 next_rd_signals
.push_back(c
->getPort("\\B"));
262 next_rd_signals
.swap(rd_signals
);
265 for (int j
= 0; j
< mem_size
; j
++)
266 module
->connect(RTLIL::SigSig(rd_signals
[j
], data_reg_out
[j
]));
269 log(" read interface: %d $dff and %d $mux cells.\n", count_dff
, count_mux
);
271 for (int i
= 0; i
< mem_size
; i
++)
273 if (static_cells_map
.count(i
) > 0)
276 RTLIL::SigSpec sig
= data_reg_out
[i
];
278 for (int j
= 0; j
< cell
->parameters
["\\WR_PORTS"].as_int(); j
++)
280 RTLIL::SigSpec wr_addr
= cell
->getPort("\\WR_ADDR").extract(j
*mem_abits
, mem_abits
);
281 RTLIL::SigSpec wr_data
= cell
->getPort("\\WR_DATA").extract(j
*mem_width
, mem_width
);
282 RTLIL::SigSpec wr_en
= cell
->getPort("\\WR_EN").extract(j
*mem_width
, mem_width
);
285 wr_addr
= module
->Sub(NEW_ID
, wr_addr
, SigSpec(mem_offset
, GetSize(wr_addr
)));
287 RTLIL::Wire
*w_seladdr
= addr_decode(wr_addr
, RTLIL::SigSpec(i
, mem_abits
));
290 while (wr_offset
< wr_en
.size())
293 RTLIL::SigSpec wr_bit
= wr_en
.extract(wr_offset
, 1);
295 while (wr_offset
+ wr_width
< wr_en
.size()) {
296 RTLIL::SigSpec next_wr_bit
= wr_en
.extract(wr_offset
+ wr_width
, 1);
297 if (next_wr_bit
!= wr_bit
)
302 RTLIL::Wire
*w
= w_seladdr
;
304 if (wr_bit
!= RTLIL::SigSpec(1, 1))
306 RTLIL::Cell
*c
= module
->addCell(genid(cell
->name
, "$wren", i
, "", j
, "", wr_offset
), "$and");
307 c
->parameters
["\\A_SIGNED"] = RTLIL::Const(0);
308 c
->parameters
["\\B_SIGNED"] = RTLIL::Const(0);
309 c
->parameters
["\\A_WIDTH"] = RTLIL::Const(1);
310 c
->parameters
["\\B_WIDTH"] = RTLIL::Const(1);
311 c
->parameters
["\\Y_WIDTH"] = RTLIL::Const(1);
312 c
->setPort("\\A", w
);
313 c
->setPort("\\B", wr_bit
);
315 w
= module
->addWire(genid(cell
->name
, "$wren", i
, "", j
, "", wr_offset
, "$y"));
316 c
->setPort("\\Y", RTLIL::SigSpec(w
));
319 RTLIL::Cell
*c
= module
->addCell(genid(cell
->name
, "$wrmux", i
, "", j
, "", wr_offset
), "$mux");
320 c
->parameters
["\\WIDTH"] = wr_width
;
321 c
->setPort("\\A", sig
.extract(wr_offset
, wr_width
));
322 c
->setPort("\\B", wr_data
.extract(wr_offset
, wr_width
));
323 c
->setPort("\\S", RTLIL::SigSpec(w
));
325 w
= module
->addWire(genid(cell
->name
, "$wrmux", i
, "", j
, "", wr_offset
, "$y"), wr_width
);
326 c
->setPort("\\Y", w
);
328 sig
.replace(wr_offset
, w
);
329 wr_offset
+= wr_width
;
334 module
->connect(RTLIL::SigSig(data_reg_in
[i
], sig
));
337 log(" write interface: %d write mux blocks.\n", count_wrmux
);
339 module
->remove(cell
);
342 MemoryMapWorker(RTLIL::Design
*design
, RTLIL::Module
*module
) : design(design
), module(module
)
344 std::vector
<RTLIL::Cell
*> cells
;
345 for (auto cell
: module
->selected_cells())
346 if (cell
->type
== "$mem" && design
->selected(module
, cell
))
347 cells
.push_back(cell
);
348 for (auto cell
: cells
)
353 struct MemoryMapPass
: public Pass
{
354 MemoryMapPass() : Pass("memory_map", "translate multiport memories to basic cells") { }
355 void help() YS_OVERRIDE
357 // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
359 log(" memory_map [selection]\n");
361 log("This pass converts multiport memory cells as generated by the memory_collect\n");
362 log("pass to word-wide DFFs and address decoders.\n");
365 void execute(std::vector
<std::string
> args
, RTLIL::Design
*design
) YS_OVERRIDE
{
366 log_header(design
, "Executing MEMORY_MAP pass (converting $mem cells to logic and flip-flops).\n");
367 extra_args(args
, 1, design
);
368 for (auto mod
: design
->selected_modules())
369 MemoryMapWorker(design
, mod
);
373 PRIVATE_NAMESPACE_END