Merge pull request #829 from abdelrahmanhosny/master
[yosys.git] / passes / techmap / dffinit.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 DffinitPass : public Pass {
27 DffinitPass() : Pass("dffinit", "set INIT param on FF cells") { }
28 void help() YS_OVERRIDE
29 {
30 // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
31 log("\n");
32 log(" dffinit [options] [selection]\n");
33 log("\n");
34 log("This pass sets an FF cell parameter to the the initial value of the net it\n");
35 log("drives. (This is primarily used in FPGA flows.)\n");
36 log("\n");
37 log(" -ff <cell_name> <output_port> <init_param>\n");
38 log(" operate on the specified cell type. this option can be used\n");
39 log(" multiple times.\n");
40 log("\n");
41 log(" -highlow\n");
42 log(" use the string values \"high\" and \"low\" to represent a single-bit\n");
43 log(" initial value of 1 or 0. (multi-bit values are not supported in this\n");
44 log(" mode.)\n");
45 log("\n");
46 log(" -strinit <string for high> <string for low> \n");
47 log(" use string values in the command line to represent a single-bit\n");
48 log(" initial value of 1 or 0. (multi-bit values are not supported in this\n");
49 log(" mode.)\n");
50 log("\n");
51 log(" -noreinit\n");
52 log(" fail if the FF cell has already a defined initial value set in other\n");
53 log(" passes and the initial value of the net it drives is not equal to\n");
54 log(" the already defined initial value.\n");
55 log("\n");
56 }
57 void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
58 {
59 log_header(design, "Executing DFFINIT pass (set INIT param on FF cells).\n");
60
61 dict<IdString, dict<IdString, IdString>> ff_types;
62 bool highlow_mode = false, noreinit = false;
63 std::string high_string, low_string;
64
65 size_t argidx;
66 for (argidx = 1; argidx < args.size(); argidx++) {
67 if (args[argidx] == "-highlow") {
68 highlow_mode = true;
69 high_string = "high";
70 low_string = "low";
71 continue;
72 }
73 if (args[argidx] == "-strinit" && argidx+2 < args.size()) {
74 highlow_mode = true;
75 high_string = args[++argidx];
76 low_string = args[++argidx];
77 continue;
78 }
79 if (args[argidx] == "-ff" && argidx+3 < args.size()) {
80 IdString cell_name = RTLIL::escape_id(args[++argidx]);
81 IdString output_port = RTLIL::escape_id(args[++argidx]);
82 IdString init_param = RTLIL::escape_id(args[++argidx]);
83 ff_types[cell_name][output_port] = init_param;
84 continue;
85 }
86 if (args[argidx] == "-noreinit") {
87 noreinit = true;
88 continue;
89 }
90 break;
91 }
92 extra_args(args, argidx, design);
93
94 for (auto module : design->selected_modules())
95 {
96 SigMap sigmap(module);
97 dict<SigBit, State> init_bits;
98 pool<SigBit> cleanup_bits;
99 pool<SigBit> used_bits;
100
101 for (auto wire : module->selected_wires()) {
102 if (wire->attributes.count("\\init")) {
103 Const value = wire->attributes.at("\\init");
104 for (int i = 0; i < min(GetSize(value), GetSize(wire)); i++)
105 if (value[i] != State::Sx)
106 init_bits[sigmap(SigBit(wire, i))] = value[i];
107 }
108 if (wire->port_output)
109 for (auto bit : sigmap(wire))
110 used_bits.insert(bit);
111 }
112
113 for (auto cell : module->selected_cells())
114 {
115 for (auto it : cell->connections())
116 if (!cell->known() || cell->input(it.first))
117 for (auto bit : sigmap(it.second))
118 used_bits.insert(bit);
119
120 if (ff_types.count(cell->type) == 0)
121 continue;
122
123 for (auto &it : ff_types[cell->type])
124 {
125 if (!cell->hasPort(it.first))
126 continue;
127
128 SigSpec sig = sigmap(cell->getPort(it.first));
129 Const value;
130
131 if (cell->hasParam(it.second))
132 value = cell->getParam(it.second);
133
134 for (int i = 0; i < GetSize(sig); i++) {
135 if (init_bits.count(sig[i]) == 0)
136 continue;
137 while (GetSize(value.bits) <= i)
138 value.bits.push_back(State::S0);
139 if (noreinit && value.bits[i] != State::Sx && value.bits[i] != init_bits.at(sig[i]))
140 log_error("Trying to assign a different init value for %s.%s.%s which technically "
141 "have a conflicted init value.\n",
142 log_id(module), log_id(cell), log_id(it.second));
143 value.bits[i] = init_bits.at(sig[i]);
144 cleanup_bits.insert(sig[i]);
145 }
146
147 if (highlow_mode && GetSize(value) != 0) {
148 if (GetSize(value) != 1)
149 log_error("Multi-bit init value for %s.%s.%s is incompatible with -highlow mode.\n",
150 log_id(module), log_id(cell), log_id(it.second));
151 if (value[0] == State::S1)
152 value = Const(high_string);
153 else
154 value = Const(low_string);
155 }
156
157 log("Setting %s.%s.%s (port=%s, net=%s) to %s.\n", log_id(module), log_id(cell), log_id(it.second),
158 log_id(it.first), log_signal(sig), log_signal(value));
159 cell->setParam(it.second, value);
160 }
161 }
162
163 for (auto wire : module->selected_wires())
164 if (wire->attributes.count("\\init")) {
165 Const &value = wire->attributes.at("\\init");
166 bool do_cleanup = true;
167 for (int i = 0; i < min(GetSize(value), GetSize(wire)); i++) {
168 SigBit bit = sigmap(SigBit(wire, i));
169 if (cleanup_bits.count(bit) || !used_bits.count(bit))
170 value[i] = State::Sx;
171 else if (value[i] != State::Sx)
172 do_cleanup = false;
173 }
174 if (do_cleanup) {
175 log("Removing init attribute from wire %s.%s.\n", log_id(module), log_id(wire));
176 wire->attributes.erase("\\init");
177 }
178 }
179 }
180 }
181 } DffinitPass;
182
183 PRIVATE_NAMESPACE_END