abc9: generate $abc9_holes design instead of <name>$holes
[yosys.git] / passes / techmap / nlutmap.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 NlutmapConfig
27 {
28 vector<int> luts;
29 bool assert_mode = false;
30 };
31
32 struct NlutmapWorker
33 {
34 const NlutmapConfig &config;
35 pool<Cell*> mapped_cells;
36 Module *module;
37
38 NlutmapWorker(const NlutmapConfig &config, Module *module) :
39 config(config), module(module)
40 {
41 }
42
43 RTLIL::Selection get_selection()
44 {
45 RTLIL::Selection sel(false);
46 for (auto cell : module->cells())
47 if (!mapped_cells.count(cell))
48 sel.select(module, cell);
49 return sel;
50 }
51
52 void run_abc(int lut_size)
53 {
54 Pass::call_on_selection(module->design, get_selection(), "lut2mux");
55
56 if (lut_size > 0)
57 Pass::call_on_selection(module->design, get_selection(), stringf("abc -lut 1:%d", lut_size));
58 else
59 Pass::call_on_selection(module->design, get_selection(), "abc");
60
61 Pass::call_on_module(module->design, module, "opt_clean");
62 }
63
64 void run()
65 {
66 vector<int> available_luts = config.luts;
67
68 while (GetSize(available_luts) > 1)
69 {
70 int n_luts = available_luts.back();
71 int lut_size = GetSize(available_luts);
72 available_luts.pop_back();
73
74 if (n_luts == 0)
75 continue;
76
77 run_abc(lut_size);
78
79 SigMap sigmap(module);
80 dict<Cell*, int> candidate_ratings;
81 dict<SigBit, int> bit_lut_count;
82
83 for (auto cell : module->cells())
84 {
85 if (cell->type != ID($lut) || mapped_cells.count(cell))
86 continue;
87
88 if (GetSize(cell->getPort(ID::A)) == lut_size || lut_size == 2)
89 candidate_ratings[cell] = 0;
90
91 for (auto &conn : cell->connections())
92 for (auto bit : sigmap(conn.second))
93 bit_lut_count[bit]++;
94 }
95
96 for (auto &cand : candidate_ratings)
97 {
98 for (auto &conn : cand.first->connections())
99 for (auto bit : sigmap(conn.second))
100 cand.second -= bit_lut_count[bit];
101 }
102
103 vector<pair<int, IdString>> rated_candidates;
104
105 for (auto &cand : candidate_ratings)
106 rated_candidates.push_back(pair<int, IdString>(cand.second, cand.first->name));
107
108 std::sort(rated_candidates.begin(), rated_candidates.end());
109
110 while (n_luts > 0 && !rated_candidates.empty()) {
111 mapped_cells.insert(module->cell(rated_candidates.back().second));
112 rated_candidates.pop_back();
113 n_luts--;
114 }
115
116 if (!available_luts.empty())
117 available_luts.back() += n_luts;
118 }
119
120 if (config.assert_mode) {
121 for (auto cell : module->cells())
122 if (cell->type == ID($lut) && !mapped_cells.count(cell))
123 log_error("Insufficient number of LUTs to map all logic cells!\n");
124 }
125
126 run_abc(0);
127 }
128 };
129
130 struct NlutmapPass : public Pass {
131 NlutmapPass() : Pass("nlutmap", "map to LUTs of different sizes") { }
132 void help() YS_OVERRIDE
133 {
134 // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
135 log("\n");
136 log(" nlutmap [options] [selection]\n");
137 log("\n");
138 log("This pass uses successive calls to 'abc' to map to an architecture. That\n");
139 log("provides a small number of differently sized LUTs.\n");
140 log("\n");
141 log(" -luts N_1,N_2,N_3,...\n");
142 log(" The number of LUTs with 1, 2, 3, ... inputs that are\n");
143 log(" available in the target architecture.\n");
144 log("\n");
145 log(" -assert\n");
146 log(" Create an error if not all logic can be mapped\n");
147 log("\n");
148 log("Excess logic that does not fit into the specified LUTs is mapped back\n");
149 log("to generic logic gates ($_AND_, etc.).\n");
150 log("\n");
151 }
152 void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
153 {
154 NlutmapConfig config;
155
156 log_header(design, "Executing NLUTMAP pass (mapping to constant drivers).\n");
157 log_push();
158
159 size_t argidx;
160 for (argidx = 1; argidx < args.size(); argidx++)
161 {
162 if (args[argidx] == "-luts" && argidx+1 < args.size()) {
163 vector<string> tokens = split_tokens(args[++argidx], ",");
164 config.luts.clear();
165 for (auto &token : tokens)
166 config.luts.push_back(atoi(token.c_str()));
167 continue;
168 }
169 if (args[argidx] == "-assert") {
170 config.assert_mode = true;
171 continue;
172 }
173 break;
174 }
175 extra_args(args, argidx, design);
176
177 for (auto module : design->selected_whole_modules_warn())
178 {
179 NlutmapWorker worker(config, module);
180 worker.run();
181 }
182
183 log_pop();
184 }
185 } NlutmapPass;
186
187 PRIVATE_NAMESPACE_END