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 static void handle_iobufs(Module
*module
, bool clkbuf_mode
)
28 SigMap
sigmap(module
);
30 pool
<SigBit
> clk_bits
;
31 pool
<SigBit
> handled_io_bits
;
32 dict
<SigBit
, SigBit
> rewrite_bits
;
33 vector
<pair
<Cell
*, SigBit
>> pad_bits
;
35 for (auto cell
: module
->cells())
37 if (clkbuf_mode
&& cell
->type
== "\\SLE") {
38 for (auto bit
: sigmap(cell
->getPort("\\CLK")))
41 if (cell
->type
.in("\\INBUF", "\\OUTBUF", "\\TRIBUFF", "\\BIBUF", "\\CLKBUF", "\\CLKBIBUF",
42 "\\INBUF_DIFF", "\\OUTBUF_DIFF", "\\BIBUFF_DIFF", "\\TRIBUFF_DIFF", "\\CLKBUF_DIFF",
43 "\\GCLKBUF", "\\GCLKBUF_DIFF", "\\GCLKBIBUF")) {
44 for (auto bit
: sigmap(cell
->getPort("\\PAD")))
45 handled_io_bits
.insert(bit
);
49 for (auto wire
: vector
<Wire
*>(module
->wires()))
51 if (!wire
->port_input
&& !wire
->port_output
)
54 for (int index
= 0; index
< GetSize(wire
); index
++)
56 SigBit
bit(wire
, index
);
57 SigBit canonical_bit
= sigmap(bit
);
59 if (handled_io_bits
.count(canonical_bit
))
62 if (wire
->port_input
&& wire
->port_output
)
63 log_error("Failed to add buffer for inout port bit %s.\n", log_signal(bit
));
65 IdString buf_type
, buf_port
;
67 if (wire
->port_output
) {
68 buf_type
= "\\OUTBUF";
70 } else if (clkbuf_mode
&& clk_bits
.count(canonical_bit
)) {
71 buf_type
= "\\CLKBUF";
78 Cell
*c
= module
->addCell(NEW_ID
, buf_type
);
79 SigBit new_bit
= module
->addWire(NEW_ID
);
80 c
->setPort(buf_port
, new_bit
);
81 pad_bits
.push_back(make_pair(c
, bit
));
82 rewrite_bits
[canonical_bit
] = new_bit
;
84 log("Added %s cell %s for port bit %s.\n", log_id(c
->type
), log_id(c
), log_signal(bit
));
88 auto rewrite_function
= [&](SigSpec
&s
) {
90 SigBit canonical_bit
= sigmap(bit
);
91 if (rewrite_bits
.count(canonical_bit
))
92 bit
= rewrite_bits
.at(canonical_bit
);
96 module
->rewrite_sigspecs(rewrite_function
);
98 for (auto &it
: pad_bits
)
99 it
.first
->setPort("\\PAD", it
.second
);
102 static void handle_clkint(Module
*module
)
104 SigMap
sigmap(module
);
106 pool
<SigBit
> clk_bits
;
107 vector
<SigBit
> handled_clk_bits
;
109 for (auto cell
: module
->cells())
111 if (cell
->type
== "\\SLE") {
112 for (auto bit
: sigmap(cell
->getPort("\\CLK")))
113 clk_bits
.insert(bit
);
115 if (cell
->type
.in("\\CLKBUF", "\\CLKBIBUF", "\\CLKBUF_DIFF", "\\GCLKBUF", "\\GCLKBUF_DIFF", "\\GCLKBIBUF",
116 "\\CLKINT", "\\CLKINT_PRESERVE", "\\GCLKINT", "\\RCLKINT", "\\RGCLKINT")) {
117 for (auto bit
: sigmap(cell
->getPort("\\Y")))
118 handled_clk_bits
.push_back(bit
);
122 for (auto bit
: handled_clk_bits
)
125 for (auto cell
: vector
<Cell
*>(module
->cells()))
126 for (auto &conn
: cell
->connections())
128 if (!cell
->output(conn
.first
))
131 SigSpec sig
= conn
.second
;
132 bool did_something
= false;
134 for (auto &bit
: sig
) {
135 SigBit canonical_bit
= sigmap(bit
);
136 if (clk_bits
.count(canonical_bit
)) {
137 Cell
*c
= module
->addCell(NEW_ID
, "\\CLKINT");
138 SigBit new_bit
= module
->addWire(NEW_ID
);
139 c
->setPort("\\A", new_bit
);
140 c
->setPort("\\Y", bit
);
141 log("Added %s cell %s for clock signal %s.\n", log_id(c
->type
), log_id(c
), log_signal(bit
));
142 clk_bits
.erase(canonical_bit
);
143 did_something
= true;
149 cell
->setPort(conn
.first
, sig
);
152 for (auto bit
: clk_bits
)
153 log_error("Failed to insert CLKINT for clock signal %s.\n", log_signal(bit
));
156 struct Sf2IobsPass
: public Pass
{
157 Sf2IobsPass() : Pass("sf2_iobs", "SF2: insert IO buffers") { }
158 void help() YS_OVERRIDE
160 // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
162 log(" sf2_iobs [options] [selection]\n");
164 log("Add SF2 I/O buffers and global buffers to top module as needed.\n");
167 log(" Insert PAD->global_net clock buffers\n");
170 void execute(std::vector
<std::string
> args
, RTLIL::Design
*design
) YS_OVERRIDE
172 bool clkbuf_mode
= false;
174 log_header(design
, "Executing sf2_iobs pass (insert IO buffers).\n");
177 for (argidx
= 1; argidx
< args
.size(); argidx
++)
179 if (args
[argidx
] == "-clkbuf") {
185 extra_args(args
, argidx
, design
);
187 Module
*module
= design
->top_module();
189 if (module
== nullptr)
190 log_cmd_error("No top module found.\n");
192 handle_iobufs(module
, clkbuf_mode
);
193 handle_clkint(module
);
197 PRIVATE_NAMESPACE_END