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"
21 #include "kernel/sigtools.h"
24 PRIVATE_NAMESPACE_BEGIN
26 bool memcells_cmp(Cell
*a
, Cell
*b
)
28 if (a
->type
== "$memrd" && b
->type
== "$memrd")
29 return a
->name
< b
->name
;
30 if (a
->type
== "$memrd" || b
->type
== "$memrd")
31 return (a
->type
== "$memrd") < (b
->type
== "$memrd");
32 return a
->parameters
.at("\\PRIORITY").as_int() < b
->parameters
.at("\\PRIORITY").as_int();
35 Cell
*handle_memory(Module
*module
, RTLIL::Memory
*memory
)
37 log("Collecting $memrd, $memwr and $meminit for memory `%s' in module `%s':\n",
38 memory
->name
.c_str(), module
->name
.c_str());
40 Const
init_data(State::Sx
, memory
->size
* memory
->width
);
41 SigMap
sigmap(module
);
45 SigSpec sig_wr_clk_enable
;
46 SigSpec sig_wr_clk_polarity
;
53 SigSpec sig_rd_clk_enable
;
54 SigSpec sig_rd_clk_polarity
;
55 SigSpec sig_rd_transparent
;
61 std::vector
<Cell
*> memcells
;
63 for (auto &cell_it
: module
->cells_
) {
64 Cell
*cell
= cell_it
.second
;
65 if (cell
->type
.in("$memrd", "$memwr", "$meminit") && memory
->name
== cell
->parameters
["\\MEMID"].decode_string()) {
66 SigSpec addr
= sigmap(cell
->getPort("\\ADDR"));
67 for (int i
= 0; i
< GetSize(addr
); i
++)
68 if (addr
[i
] != State::S0
)
69 addr_bits
= std::max(addr_bits
, i
+1);
70 memcells
.push_back(cell
);
74 if (memory
->start_offset
== 0 && addr_bits
< 30 && (1 << addr_bits
) < memory
->size
)
75 memory
->size
= 1 << addr_bits
;
77 if (memory
->start_offset
>= 0)
78 addr_bits
= std::min(addr_bits
, ceil_log2(memory
->size
+ memory
->start_offset
));
80 addr_bits
= std::max(addr_bits
, 1);
82 if (memcells
.empty()) {
83 log(" no cells found. removing memory.\n");
87 std::sort(memcells
.begin(), memcells
.end(), memcells_cmp
);
89 for (auto cell
: memcells
)
91 log(" %s (%s)\n", log_id(cell
), log_id(cell
->type
));
93 if (cell
->type
== "$meminit")
95 SigSpec addr
= sigmap(cell
->getPort("\\ADDR"));
96 SigSpec data
= sigmap(cell
->getPort("\\DATA"));
98 if (!addr
.is_fully_const())
99 log_error("Non-constant address %s in memory initialization %s.\n", log_signal(addr
), log_id(cell
));
100 if (!data
.is_fully_const())
101 log_error("Non-constant data %s in memory initialization %s.\n", log_signal(data
), log_id(cell
));
103 int offset
= (addr
.as_int() - memory
->start_offset
) * memory
->width
;
105 if (offset
< 0 || offset
+ GetSize(data
) > GetSize(init_data
))
106 log_warning("Address %s in memory initialization %s is out-of-bounds.\n", log_signal(addr
), log_id(cell
));
108 for (int i
= 0; i
< GetSize(data
); i
++)
109 if (0 <= i
+offset
&& i
+offset
< GetSize(init_data
))
110 init_data
.bits
[i
+offset
] = data
[i
].data
;
115 if (cell
->type
== "$memwr")
117 SigSpec clk
= sigmap(cell
->getPort("\\CLK"));
118 SigSpec clk_enable
= SigSpec(cell
->parameters
["\\CLK_ENABLE"]);
119 SigSpec clk_polarity
= SigSpec(cell
->parameters
["\\CLK_POLARITY"]);
120 SigSpec addr
= sigmap(cell
->getPort("\\ADDR"));
121 SigSpec data
= sigmap(cell
->getPort("\\DATA"));
122 SigSpec en
= sigmap(cell
->getPort("\\EN"));
124 if (!en
.is_fully_zero())
126 clk
.extend_u0(1, false);
127 clk_enable
.extend_u0(1, false);
128 clk_polarity
.extend_u0(1, false);
129 addr
.extend_u0(addr_bits
, false);
130 data
.extend_u0(memory
->width
, false);
131 en
.extend_u0(memory
->width
, false);
133 sig_wr_clk
.append(clk
);
134 sig_wr_clk_enable
.append(clk_enable
);
135 sig_wr_clk_polarity
.append(clk_polarity
);
136 sig_wr_addr
.append(addr
);
137 sig_wr_data
.append(data
);
138 sig_wr_en
.append(en
);
145 if (cell
->type
== "$memrd")
147 SigSpec clk
= sigmap(cell
->getPort("\\CLK"));
148 SigSpec clk_enable
= SigSpec(cell
->parameters
["\\CLK_ENABLE"]);
149 SigSpec clk_polarity
= SigSpec(cell
->parameters
["\\CLK_POLARITY"]);
150 SigSpec transparent
= SigSpec(cell
->parameters
["\\TRANSPARENT"]);
151 SigSpec addr
= sigmap(cell
->getPort("\\ADDR"));
152 SigSpec data
= sigmap(cell
->getPort("\\DATA"));
153 SigSpec en
= sigmap(cell
->getPort("\\EN"));
155 if (!en
.is_fully_zero())
157 clk
.extend_u0(1, false);
158 clk_enable
.extend_u0(1, false);
159 clk_polarity
.extend_u0(1, false);
160 transparent
.extend_u0(1, false);
161 addr
.extend_u0(addr_bits
, false);
162 data
.extend_u0(memory
->width
, false);
164 sig_rd_clk
.append(clk
);
165 sig_rd_clk_enable
.append(clk_enable
);
166 sig_rd_clk_polarity
.append(clk_polarity
);
167 sig_rd_transparent
.append(transparent
);
168 sig_rd_addr
.append(addr
);
169 sig_rd_data
.append(data
);
170 sig_rd_en
.append(en
);
178 std::stringstream sstr
;
179 sstr
<< "$mem$" << memory
->name
.str() << "$" << (autoidx
++);
181 Cell
*mem
= module
->addCell(sstr
.str(), "$mem");
182 mem
->parameters
["\\MEMID"] = Const(memory
->name
.str());
183 mem
->parameters
["\\WIDTH"] = Const(memory
->width
);
184 mem
->parameters
["\\OFFSET"] = Const(memory
->start_offset
);
185 mem
->parameters
["\\SIZE"] = Const(memory
->size
);
186 mem
->parameters
["\\ABITS"] = Const(addr_bits
);
187 mem
->parameters
["\\INIT"] = init_data
;
189 log_assert(sig_wr_clk
.size() == wr_ports
);
190 log_assert(sig_wr_clk_enable
.size() == wr_ports
&& sig_wr_clk_enable
.is_fully_const());
191 log_assert(sig_wr_clk_polarity
.size() == wr_ports
&& sig_wr_clk_polarity
.is_fully_const());
192 log_assert(sig_wr_addr
.size() == wr_ports
* addr_bits
);
193 log_assert(sig_wr_data
.size() == wr_ports
* memory
->width
);
194 log_assert(sig_wr_en
.size() == wr_ports
* memory
->width
);
196 mem
->parameters
["\\WR_PORTS"] = Const(wr_ports
);
197 mem
->parameters
["\\WR_CLK_ENABLE"] = wr_ports
? sig_wr_clk_enable
.as_const() : Const(0, 1);
198 mem
->parameters
["\\WR_CLK_POLARITY"] = wr_ports
? sig_wr_clk_polarity
.as_const() : Const(0, 1);
200 mem
->setPort("\\WR_CLK", sig_wr_clk
);
201 mem
->setPort("\\WR_ADDR", sig_wr_addr
);
202 mem
->setPort("\\WR_DATA", sig_wr_data
);
203 mem
->setPort("\\WR_EN", sig_wr_en
);
205 log_assert(sig_rd_clk
.size() == rd_ports
);
206 log_assert(sig_rd_clk_enable
.size() == rd_ports
&& sig_rd_clk_enable
.is_fully_const());
207 log_assert(sig_rd_clk_polarity
.size() == rd_ports
&& sig_rd_clk_polarity
.is_fully_const());
208 log_assert(sig_rd_addr
.size() == rd_ports
* addr_bits
);
209 log_assert(sig_rd_data
.size() == rd_ports
* memory
->width
);
211 mem
->parameters
["\\RD_PORTS"] = Const(rd_ports
);
212 mem
->parameters
["\\RD_CLK_ENABLE"] = rd_ports
? sig_rd_clk_enable
.as_const() : Const(0, 1);
213 mem
->parameters
["\\RD_CLK_POLARITY"] = rd_ports
? sig_rd_clk_polarity
.as_const() : Const(0, 1);
214 mem
->parameters
["\\RD_TRANSPARENT"] = rd_ports
? sig_rd_transparent
.as_const() : Const(0, 1);
216 mem
->setPort("\\RD_CLK", sig_rd_clk
);
217 mem
->setPort("\\RD_ADDR", sig_rd_addr
);
218 mem
->setPort("\\RD_DATA", sig_rd_data
);
219 mem
->setPort("\\RD_EN", sig_rd_en
);
221 for (auto c
: memcells
)
227 static void handle_module(Design
*design
, Module
*module
)
229 std::vector
<pair
<Cell
*, IdString
>> finqueue
;
231 for (auto &mem_it
: module
->memories
)
232 if (design
->selected(module
, mem_it
.second
)) {
233 Cell
*c
= handle_memory(module
, mem_it
.second
);
234 finqueue
.push_back(pair
<Cell
*, IdString
>(c
, mem_it
.first
));
236 for (auto &it
: finqueue
) {
237 delete module
->memories
.at(it
.second
);
238 module
->memories
.erase(it
.second
);
240 module
->rename(it
.first
, it
.second
);
244 struct MemoryCollectPass
: public Pass
{
245 MemoryCollectPass() : Pass("memory_collect", "creating multi-port memory cells") { }
246 void help() YS_OVERRIDE
248 // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
250 log(" memory_collect [selection]\n");
252 log("This pass collects memories and memory ports and creates generic multiport\n");
253 log("memory cells.\n");
256 void execute(std::vector
<std::string
> args
, RTLIL::Design
*design
) YS_OVERRIDE
{
257 log_header(design
, "Executing MEMORY_COLLECT pass (generating $mem cells).\n");
258 extra_args(args
, 1, design
);
259 for (auto &mod_it
: design
->modules_
)
260 if (design
->selected(mod_it
.second
))
261 handle_module(design
, mod_it
.second
);
265 PRIVATE_NAMESPACE_END