dee48597fbef6513b4d212b585425b4a44eb6ef3
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"
26 static void normalize_sig(RTLIL::Module
*module
, RTLIL::SigSpec
&sig
)
28 for (auto &conn
: module
->connections
)
29 sig
.replace(conn
.first
, conn
.second
);
32 static bool find_sig_before_dff(RTLIL::Module
*module
, RTLIL::SigSpec
&sig
, RTLIL::SigSpec
&clk
, bool &clk_polarity
, bool after
= false)
34 normalize_sig(module
, sig
);
37 for (size_t i
= 0; i
< sig
.chunks().size(); i
++)
39 RTLIL::SigChunk
&chunk
= sig
.chunks_rw()[i
];
41 if (chunk
.wire
== NULL
)
44 for (auto &cell_it
: module
->cells
)
46 RTLIL::Cell
*cell
= cell_it
.second
;
48 if (cell
->type
!= "$dff")
51 if (clk
!= RTLIL::SigSpec(RTLIL::State::Sx
)) {
52 if (cell
->connections
["\\CLK"] != clk
)
54 if (cell
->parameters
["\\CLK_POLARITY"].as_bool() != clk_polarity
)
58 RTLIL::SigSpec q_norm
= cell
->connections
[after
? "\\D" : "\\Q"];
59 normalize_sig(module
, q_norm
);
61 RTLIL::SigSpec d
= q_norm
.extract(chunk
, &cell
->connections
[after
? "\\Q" : "\\D"]);
65 assert(d
.chunks().size() == 1);
66 chunk
= d
.chunks()[0];
67 clk
= cell
->connections
["\\CLK"];
68 clk_polarity
= cell
->parameters
["\\CLK_POLARITY"].as_bool();
69 goto replaced_this_bit
;
80 static void handle_wr_cell(RTLIL::Module
*module
, RTLIL::Cell
*cell
)
82 log("Checking cell `%s' in module `%s': ", cell
->name
.c_str(), module
->name
.c_str());
84 RTLIL::SigSpec clk
= RTLIL::SigSpec(RTLIL::State::Sx
);
85 bool clk_polarity
= 0;
87 RTLIL::SigSpec sig_addr
= cell
->connections
["\\ADDR"];
88 if (!find_sig_before_dff(module
, sig_addr
, clk
, clk_polarity
)) {
89 log("no (compatible) $dff for address input found.\n");
93 RTLIL::SigSpec sig_data
= cell
->connections
["\\DATA"];
94 if (!find_sig_before_dff(module
, sig_data
, clk
, clk_polarity
)) {
95 log("no (compatible) $dff for data input found.\n");
99 RTLIL::SigSpec sig_en
= cell
->connections
["\\EN"];
100 if (!find_sig_before_dff(module
, sig_en
, clk
, clk_polarity
)) {
101 log("no (compatible) $dff for enable input found.\n");
105 if (clk
!= RTLIL::SigSpec(RTLIL::State::Sx
)) {
106 cell
->connections
["\\CLK"] = clk
;
107 cell
->connections
["\\ADDR"] = sig_addr
;
108 cell
->connections
["\\DATA"] = sig_data
;
109 cell
->connections
["\\EN"] = sig_en
;
110 cell
->parameters
["\\CLK_ENABLE"] = RTLIL::Const(1);
111 cell
->parameters
["\\CLK_POLARITY"] = RTLIL::Const(clk_polarity
);
112 log("merged $dff to cell.\n");
115 log("no (compatible) $dff found.\n");
118 static void disconnect_dff(RTLIL::Module
*module
, RTLIL::SigSpec sig
)
120 normalize_sig(module
, sig
);
121 sig
.sort_and_unify();
123 std::stringstream sstr
;
124 sstr
<< "$memory_dff_disconnected$" << (RTLIL::autoidx
++);
126 RTLIL::Wire
*wire
= new RTLIL::Wire
;
127 wire
->name
= sstr
.str();
128 wire
->width
= sig
.size();
129 module
->wires
[wire
->name
] = wire
;
131 RTLIL::SigSpec
newsig(wire
);
133 for (auto &cell_it
: module
->cells
) {
134 RTLIL::Cell
*cell
= cell_it
.second
;
135 if (cell
->type
== "$dff")
136 cell
->connections
["\\Q"].replace(sig
, newsig
);
140 static void handle_rd_cell(RTLIL::Module
*module
, RTLIL::Cell
*cell
)
142 log("Checking cell `%s' in module `%s': ", cell
->name
.c_str(), module
->name
.c_str());
144 bool clk_polarity
= 0;
146 RTLIL::SigSpec clk_data
= RTLIL::SigSpec(RTLIL::State::Sx
);
147 RTLIL::SigSpec sig_data
= cell
->connections
["\\DATA"];
148 if (find_sig_before_dff(module
, sig_data
, clk_data
, clk_polarity
, true) &&
149 clk_data
!= RTLIL::SigSpec(RTLIL::State::Sx
))
151 disconnect_dff(module
, sig_data
);
152 cell
->connections
["\\CLK"] = clk_data
;
153 cell
->connections
["\\DATA"] = sig_data
;
154 cell
->parameters
["\\CLK_ENABLE"] = RTLIL::Const(1);
155 cell
->parameters
["\\CLK_POLARITY"] = RTLIL::Const(clk_polarity
);
156 cell
->parameters
["\\TRANSPARENT"] = RTLIL::Const(0);
157 log("merged data $dff to cell.\n");
161 RTLIL::SigSpec clk_addr
= RTLIL::SigSpec(RTLIL::State::Sx
);
162 RTLIL::SigSpec sig_addr
= cell
->connections
["\\ADDR"];
163 if (find_sig_before_dff(module
, sig_addr
, clk_addr
, clk_polarity
) &&
164 clk_addr
!= RTLIL::SigSpec(RTLIL::State::Sx
))
166 cell
->connections
["\\CLK"] = clk_addr
;
167 cell
->connections
["\\ADDR"] = sig_addr
;
168 cell
->parameters
["\\CLK_ENABLE"] = RTLIL::Const(1);
169 cell
->parameters
["\\CLK_POLARITY"] = RTLIL::Const(clk_polarity
);
170 cell
->parameters
["\\TRANSPARENT"] = RTLIL::Const(1);
171 log("merged address $dff to cell.\n");
175 log("no (compatible) $dff found.\n");
178 static void handle_module(RTLIL::Design
*design
, RTLIL::Module
*module
, bool flag_wr_only
)
180 for (auto &cell_it
: module
->cells
) {
181 if (!design
->selected(module
, cell_it
.second
))
183 if (cell_it
.second
->type
== "$memwr" && !cell_it
.second
->parameters
["\\CLK_ENABLE"].as_bool())
184 handle_wr_cell(module
, cell_it
.second
);
185 if (!flag_wr_only
&& cell_it
.second
->type
== "$memrd" && !cell_it
.second
->parameters
["\\CLK_ENABLE"].as_bool())
186 handle_rd_cell(module
, cell_it
.second
);
190 struct MemoryDffPass
: public Pass
{
191 MemoryDffPass() : Pass("memory_dff", "merge input/output DFFs into memories") { }
194 // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
196 log(" memory_dff [options] [selection]\n");
198 log("This pass detects DFFs at memory ports and merges them into the memory port.\n");
199 log("I.e. it consumes an asynchronous memory port and the flip-flops at its\n");
200 log("interface and yields a synchronous memory port.\n");
203 log(" do not merge registers on read ports\n");
206 virtual void execute(std::vector
<std::string
> args
, RTLIL::Design
*design
)
208 bool flag_wr_only
= false;
210 log_header("Executing MEMORY_DFF pass (merging $dff cells to $memrd and $memwr).\n");
213 for (argidx
= 1; argidx
< args
.size(); argidx
++) {
214 if (args
[argidx
] == "-wr_only") {
220 extra_args(args
, argidx
, design
);
222 for (auto &mod_it
: design
->modules
)
223 if (design
->selected(mod_it
.second
))
224 handle_module(design
, mod_it
.second
, flag_wr_only
);