Make MUXF{7,8} and CARRY4 whitebox
[yosys.git] / techlibs / sf2 / sf2_iobs.cc
1 /*
2 * yosys -- Yosys Open SYnthesis Suite
3 *
4 * Copyright (C) 2012 Clifford Wolf <clifford@clifford.at>
5 *
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.
9 *
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.
17 *
18 */
19
20 #include "kernel/yosys.h"
21 #include "kernel/sigtools.h"
22
23 USING_YOSYS_NAMESPACE
24 PRIVATE_NAMESPACE_BEGIN
25
26 static void handle_iobufs(Module *module, bool clkbuf_mode)
27 {
28 SigMap sigmap(module);
29
30 pool<SigBit> clk_bits;
31 pool<SigBit> handled_io_bits;
32 dict<SigBit, SigBit> rewrite_bits;
33 vector<pair<Cell*, SigBit>> pad_bits;
34
35 for (auto cell : module->cells())
36 {
37 if (clkbuf_mode && cell->type == "\\SLE") {
38 for (auto bit : sigmap(cell->getPort("\\CLK")))
39 clk_bits.insert(bit);
40 }
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);
46 }
47 }
48
49 for (auto wire : vector<Wire*>(module->wires()))
50 {
51 if (!wire->port_input && !wire->port_output)
52 continue;
53
54 for (int index = 0; index < GetSize(wire); index++)
55 {
56 SigBit bit(wire, index);
57 SigBit canonical_bit = sigmap(bit);
58
59 if (handled_io_bits.count(canonical_bit))
60 continue;
61
62 if (wire->port_input && wire->port_output)
63 log_error("Failed to add buffer for inout port bit %s.\n", log_signal(bit));
64
65 IdString buf_type, buf_port;
66
67 if (wire->port_output) {
68 buf_type = "\\OUTBUF";
69 buf_port = "\\D";
70 } else if (clkbuf_mode && clk_bits.count(canonical_bit)) {
71 buf_type = "\\CLKBUF";
72 buf_port = "\\Y";
73 } else {
74 buf_type = "\\INBUF";
75 buf_port = "\\Y";
76 }
77
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;
83
84 log("Added %s cell %s for port bit %s.\n", log_id(c->type), log_id(c), log_signal(bit));
85 }
86 }
87
88 auto rewrite_function = [&](SigSpec &s) {
89 for (auto &bit : s) {
90 SigBit canonical_bit = sigmap(bit);
91 if (rewrite_bits.count(canonical_bit))
92 bit = rewrite_bits.at(canonical_bit);
93 }
94 };
95
96 module->rewrite_sigspecs(rewrite_function);
97
98 for (auto &it : pad_bits)
99 it.first->setPort("\\PAD", it.second);
100 }
101
102 static void handle_clkint(Module *module)
103 {
104 SigMap sigmap(module);
105
106 pool<SigBit> clk_bits;
107 vector<SigBit> handled_clk_bits;
108
109 for (auto cell : module->cells())
110 {
111 if (cell->type == "\\SLE") {
112 for (auto bit : sigmap(cell->getPort("\\CLK")))
113 clk_bits.insert(bit);
114 }
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);
119 }
120 }
121
122 for (auto bit : handled_clk_bits)
123 clk_bits.erase(bit);
124
125 for (auto cell : vector<Cell*>(module->cells()))
126 for (auto &conn : cell->connections())
127 {
128 if (!cell->output(conn.first))
129 continue;
130
131 SigSpec sig = conn.second;
132 bool did_something = false;
133
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;
144 bit = new_bit;
145 }
146 }
147
148 if (did_something)
149 cell->setPort(conn.first, sig);
150 }
151
152 for (auto bit : clk_bits)
153 log_error("Failed to insert CLKINT for clock signal %s.\n", log_signal(bit));
154 }
155
156 struct Sf2IobsPass : public Pass {
157 Sf2IobsPass() : Pass("sf2_iobs", "SF2: insert IO buffers") { }
158 void help() YS_OVERRIDE
159 {
160 // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
161 log("\n");
162 log(" sf2_iobs [options] [selection]\n");
163 log("\n");
164 log("Add SF2 I/O buffers and global buffers to top module as needed.\n");
165 log("\n");
166 log(" -clkbuf\n");
167 log(" Insert PAD->global_net clock buffers\n");
168 log("\n");
169 }
170 void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
171 {
172 bool clkbuf_mode = false;
173
174 log_header(design, "Executing sf2_iobs pass (insert IO buffers).\n");
175
176 size_t argidx;
177 for (argidx = 1; argidx < args.size(); argidx++)
178 {
179 if (args[argidx] == "-clkbuf") {
180 clkbuf_mode = true;
181 continue;
182 }
183 break;
184 }
185 extra_args(args, argidx, design);
186
187 Module *module = design->top_module();
188
189 if (module == nullptr)
190 log_cmd_error("No top module found.\n");
191
192 handle_iobufs(module, clkbuf_mode);
193 handle_clkint(module);
194 }
195 } Sf2IobsPass;
196
197 PRIVATE_NAMESPACE_END