ad5c50cd6adff1e78c333b7ceb0c9a698ef1316c
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 struct ShregmapOptions
30 int keep_before
, keep_after
;
47 const ShregmapOptions
&opts
;
48 int dff_count
, shreg_count
;
50 // next is set to NULL for sigbits that drive non-DFFs
51 dict
<SigBit
, Cell
*> sigbit_chain_next
;
52 dict
<SigBit
, Cell
*> sigbit_chain_prev
;
53 pool
<Cell
*> chain_start_cells
;
55 void make_sigbit_chain_next_prev()
57 for (auto wire
: module
->wires()) {
58 if (!wire
->port_output
)
60 for (auto bit
: sigmap(wire
))
61 sigbit_chain_next
[bit
] = nullptr;
64 for (auto cell
: module
->cells())
66 if ((opts
.clkpol
!= "pos" && cell
->type
== "$_DFF_N_") ||
67 (opts
.clkpol
!= "neg" && cell
->type
== "$_DFF_P_"))
69 SigBit d_bit
= sigmap(cell
->getPort("\\D").as_bit());
70 if (sigbit_chain_next
.count(d_bit
))
71 sigbit_chain_next
[d_bit
] = nullptr;
73 sigbit_chain_next
[d_bit
] = cell
;
75 SigBit q_bit
= sigmap(cell
->getPort("\\Q").as_bit());
76 sigbit_chain_prev
[q_bit
] = cell
;
80 for (auto conn
: cell
->connections())
81 if (cell
->input(conn
.first
))
82 for (auto bit
: sigmap(conn
.second
))
83 sigbit_chain_next
[bit
] = nullptr;
87 void find_chain_start_cells()
89 for (auto it
: sigbit_chain_next
)
91 if (it
.second
== nullptr)
94 if (sigbit_chain_prev
.count(it
.first
) != 0)
96 Cell
*c1
= sigbit_chain_prev
.at(it
.first
);
99 if (c1
->type
!= c2
->type
)
102 if (sigmap(c1
->getPort("\\C")) != c2
->getPort("\\C"))
109 chain_start_cells
.insert(it
.second
);
113 vector
<Cell
*> create_chain(Cell
*start_cell
)
117 Cell
*c
= start_cell
;
122 SigBit q_bit
= sigmap(c
->getPort("\\Q").as_bit());
124 if (sigbit_chain_next
.count(q_bit
) == 0)
127 c
= sigbit_chain_next
.at(q_bit
);
128 if (chain_start_cells
.count(c
) != 0)
135 void process_chain(vector
<Cell
*> &chain
)
137 if (GetSize(chain
) < opts
.keep_before
+ opts
.minlen
+ opts
.keep_after
)
140 int cursor
= opts
.keep_before
;
141 while (cursor
< GetSize(chain
) - opts
.keep_after
)
143 int depth
= GetSize(chain
) - opts
.keep_after
- cursor
;
146 depth
= std::min(opts
.maxlen
, depth
);
148 Cell
*first_cell
= chain
[cursor
], *last_cell
= chain
[cursor
+depth
-1];
153 log("Converting %s.%s ... %s.%s to a shift register with depth %d.\n",
154 log_id(module
), log_id(first_cell
), log_id(module
), log_id(last_cell
), depth
);
156 first_cell
->type
= "$__DFF_SHREG_" + first_cell
->type
.substr(6);
157 first_cell
->setPort("\\Q", last_cell
->getPort("\\Q"));
158 first_cell
->setParam("\\DEPTH", depth
);
160 for (int i
= 1; i
< depth
; i
++)
161 module
->remove(chain
[cursor
+i
]);
166 ShregmapWorker(Module
*module
, const ShregmapOptions
&opts
) :
167 module(module
), sigmap(module
), opts(opts
), dff_count(0), shreg_count(0)
169 make_sigbit_chain_next_prev();
171 find_chain_start_cells();
173 for (auto c
: chain_start_cells
) {
174 vector
<Cell
*> chain
= create_chain(c
);
175 process_chain(chain
);
180 struct ShregmapPass
: public Pass
{
181 ShregmapPass() : Pass("shregmap", "map shift registers") { }
184 // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
186 log(" shregmap [options] [selection]\n");
188 log("This pass converts chains of $_DFF_[NP]_ gates to target specific shift register.\n");
189 log("primitives. The generated shift register will be of type $__DFF_SHREG_[NP]_ and\n");
190 log("will use the same interface as the original $_DFF_*_ cells. The cell parameter\n");
191 log("'DEPTH' will contain the depth of the shift register. Use a target-specific\n");
192 log("'techmap' map file to convert those cells to the actual target cells.\n");
195 log(" minimum length of shift register (default = 2)\n");
196 log(" (this is the length after -keep_before and -keep_after)\n");
199 log(" maximum length of shift register (default = no limit)\n");
200 log(" larger chains will be mapped to multiple shift register instances\n");
202 log(" -keep_before N\n");
203 log(" number of DFFs to keep before the shift register (default = 0)\n");
205 log(" -keep_after N\n");
206 log(" number of DFFs to keep after the shift register (default = 0)\n");
208 log(" -clkpol pos|neg|any\n");
209 log(" limit match to only positive or negative edge clocks. (default = any)\n");
212 virtual void execute(std::vector
<std::string
> args
, RTLIL::Design
*design
)
214 ShregmapOptions opts
;
216 log_header("Executing SHREGMAP pass (map shift registers).\n");
219 for (argidx
= 1; argidx
< args
.size(); argidx
++)
221 if (args
[argidx
] == "-clkpol" && argidx
+1 < args
.size()) {
222 opts
.clkpol
= args
[++argidx
];
225 if (args
[argidx
] == "-minlen" && argidx
+1 < args
.size()) {
226 opts
.minlen
= atoi(args
[++argidx
].c_str());
229 if (args
[argidx
] == "-maxlen" && argidx
+1 < args
.size()) {
230 opts
.maxlen
= atoi(args
[++argidx
].c_str());
233 if (args
[argidx
] == "-keep_before" && argidx
+1 < args
.size()) {
234 opts
.keep_before
= atoi(args
[++argidx
].c_str());
237 if (args
[argidx
] == "-keep_after" && argidx
+1 < args
.size()) {
238 opts
.keep_after
= atoi(args
[++argidx
].c_str());
243 extra_args(args
, argidx
, design
);
245 if (opts
.clkpol
!= "pos" && opts
.clkpol
!= "neg" && opts
.clkpol
!= "any")
246 log_cmd_error("Invalid value for -clkpol: %s\n", opts
.clkpol
.c_str());
251 for (auto module
: design
->selected_modules()) {
252 ShregmapWorker
worker(module
, opts
);
253 dff_count
+= worker
.dff_count
;
254 shreg_count
+= worker
.shreg_count
;
257 log("Converted %d dff cells into %d shift registers.\n", dff_count
, shreg_count
);
261 PRIVATE_NAMESPACE_END