Transform "$.*" to ID("$.*") in passes/techmap
[yosys.git] / passes / techmap / deminout.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 struct DeminoutPass : public Pass {
27 DeminoutPass() : Pass("deminout", "demote inout ports to input or output") { }
28 void help() YS_OVERRIDE
29 {
30 log("\n");
31 log(" deminout [options] [selection]\n");
32 log("\n");
33 log("\"Demote\" inout ports to input or output ports, if possible.\n");
34 log("\n");
35 }
36 void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
37 {
38 log_header(design, "Executing DEMINOUT pass (demote inout ports to input or output).\n");
39
40 size_t argidx;
41 for (argidx = 1; argidx < args.size(); argidx++)
42 {
43 // if (args[argidx] == "-bits") {
44 // flag_bits = true;
45 // continue;
46 // }
47 break;
48 }
49 extra_args(args, argidx, design);
50
51 bool keep_running = true;
52
53 while (keep_running)
54 {
55 keep_running = false;
56
57 for (auto module : design->selected_modules())
58 {
59 SigMap sigmap(module);
60 pool<SigBit> bits_written, bits_used, bits_inout, bits_tribuf;
61 dict<SigBit, int> bits_numports;
62
63 for (auto wire : module->wires())
64 if (wire->port_id)
65 for (auto bit : sigmap(wire))
66 bits_numports[bit]++;
67
68 for (auto cell : module->cells())
69 for (auto &conn : cell->connections())
70 {
71 bool cellport_out = cell->output(conn.first) || !cell->known();
72 bool cellport_in = cell->input(conn.first) || !cell->known();
73
74 if (cellport_out && cellport_in)
75 for (auto bit : sigmap(conn.second))
76 bits_inout.insert(bit);
77
78 if (cellport_out)
79 for (auto bit : sigmap(conn.second))
80 bits_written.insert(bit);
81
82 if (cellport_in)
83 for (auto bit : sigmap(conn.second))
84 bits_used.insert(bit);
85
86 if (conn.first == "\\Y" && cell->type.in(ID($mux), ID($pmux), ID($_MUX_), ID($_TBUF_), ID($tribuf)))
87 {
88 bool tribuf = cell->type.in(ID($_TBUF_), ID($tribuf));
89
90 if (!tribuf) {
91 for (auto &c : cell->connections()) {
92 if (!c.first.in("\\A", "\\B"))
93 continue;
94 for (auto b : sigmap(c.second))
95 if (b == State::Sz)
96 tribuf = true;
97 }
98 }
99
100 if (tribuf)
101 for (auto bit : sigmap(conn.second))
102 bits_tribuf.insert(bit);
103 }
104 }
105
106 for (auto wire : module->selected_wires())
107 if (wire->port_input && wire->port_output)
108 {
109 bool new_input = false;
110 bool new_output = false;
111
112 for (auto bit : sigmap(wire))
113 {
114 if (bits_numports[bit] > 1 || bits_inout.count(bit))
115 new_input = true, new_output = true;
116 if (bit == State::S0 || bit == State::S1)
117 new_output = true;
118 if (bits_written.count(bit)) {
119 new_output = true;
120 if (bits_tribuf.count(bit))
121 goto tribuf_bit;
122 } else {
123 tribuf_bit:
124 if (bits_used.count(bit))
125 new_input = true;
126 }
127 }
128
129 if (new_input != new_output) {
130 log("Demoting inout port %s.%s to %s.\n", log_id(module), log_id(wire), new_input ? "input" : "output");
131 wire->port_input = new_input;
132 wire->port_output = new_output;
133 keep_running = true;
134 }
135 }
136 }
137 }
138 }
139 } DeminoutPass;
140
141 PRIVATE_NAMESPACE_END