Merge pull request #1789 from YosysHQ/eddie/opt_expr_alu
[yosys.git] / passes / cmds / add.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
22 USING_YOSYS_NAMESPACE
23 PRIVATE_NAMESPACE_BEGIN
24
25 static bool is_formal_celltype(const std::string &celltype)
26 {
27 if(celltype == "assert" || celltype == "assume" || celltype == "live" || celltype == "fair" || celltype == "cover")
28 return true;
29 else
30 return false;
31 }
32
33 static void add_formal(RTLIL::Module *module, const std::string &celltype, const std::string &name, const std::string &enable_name)
34 {
35 std::string escaped_name = RTLIL::escape_id(name);
36 std::string escaped_enable_name = (enable_name != "") ? RTLIL::escape_id(enable_name) : "";
37 RTLIL::Wire *wire = module->wire(escaped_name);
38 log_assert(is_formal_celltype(celltype));
39
40 if (wire == nullptr) {
41 log_error("Could not find wire with name \"%s\".\n", name.c_str());
42 }
43 else {
44 RTLIL::Cell *formal_cell = module->addCell(NEW_ID, "$" + celltype);
45 formal_cell->setPort(ID(A), wire);
46 if(enable_name == "") {
47 formal_cell->setPort(ID(EN), State::S1);
48 log("Added $%s cell for wire \"%s.%s\"\n", celltype.c_str(), module->name.str().c_str(), name.c_str());
49 }
50 else {
51 RTLIL::Wire *enable_wire = module->wire(escaped_enable_name);
52 if(enable_wire == nullptr)
53 log_error("Could not find enable wire with name \"%s\".\n", enable_name.c_str());
54
55 formal_cell->setPort(ID(EN), enable_wire);
56 log("Added $%s cell for wire \"%s.%s\" enabled by wire \"%s.%s\".\n", celltype.c_str(), module->name.str().c_str(), name.c_str(), module->name.str().c_str(), enable_name.c_str());
57 }
58 }
59 }
60
61 static void add_wire(RTLIL::Design *design, RTLIL::Module *module, std::string name, int width, bool flag_input, bool flag_output, bool flag_global)
62 {
63 RTLIL::Wire *wire = nullptr;
64 name = RTLIL::escape_id(name);
65
66 if (module->count_id(name) != 0)
67 {
68 wire = module->wire(name);
69
70 if (wire != nullptr && wire->width != width)
71 wire = nullptr;
72
73 if (wire != nullptr && wire->port_input != flag_input)
74 wire = nullptr;
75
76 if (wire != nullptr && wire->port_output != flag_output)
77 wire = nullptr;
78
79 if (wire == nullptr)
80 log_cmd_error("Found incompatible object with same name in module %s!\n", module->name.c_str());
81
82 log("Module %s already has such an object.\n", module->name.c_str());
83 }
84 else
85 {
86 wire = module->addWire(name, width);
87 wire->port_input = flag_input;
88 wire->port_output = flag_output;
89
90 if (flag_input || flag_output) {
91 module->fixup_ports();
92 }
93
94 log("Added wire %s to module %s.\n", name.c_str(), module->name.c_str());
95 }
96
97 if (!flag_global)
98 return;
99
100 for (auto cell : module->cells())
101 {
102 RTLIL::Module *mod = design->module(cell->type);
103 if (mod == nullptr)
104 continue;
105 if (!design->selected_whole_module(mod->name))
106 continue;
107 if (mod->get_blackbox_attribute())
108 continue;
109 if (cell->hasPort(name))
110 continue;
111
112 cell->setPort(name, wire);
113 log("Added connection %s to cell %s.%s (%s).\n", name.c_str(), module->name.c_str(), cell->name.c_str(), cell->type.c_str());
114 }
115 }
116
117 struct AddPass : public Pass {
118 AddPass() : Pass("add", "add objects to the design") { }
119 void help() YS_OVERRIDE
120 {
121 // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
122 log("\n");
123 log(" add <command> [selection]\n");
124 log("\n");
125 log("This command adds objects to the design. It operates on all fully selected\n");
126 log("modules. So e.g. 'add -wire foo' will add a wire foo to all selected modules.\n");
127 log("\n");
128 log("\n");
129 log(" add {-wire|-input|-inout|-output} <name> <width> [selection]\n");
130 log("\n");
131 log("Add a wire (input, inout, output port) with the given name and width. The\n");
132 log("command will fail if the object exists already and has different properties\n");
133 log("than the object to be created.\n");
134 log("\n");
135 log("\n");
136 log(" add -global_input <name> <width> [selection]\n");
137 log("\n");
138 log("Like 'add -input', but also connect the signal between instances of the\n");
139 log("selected modules.\n");
140 log("\n");
141 log("\n");
142 log(" add {-assert|-assume|-live|-fair|-cover} <name1> [-if <name2>]\n");
143 log("\n");
144 log("Add an $assert, $assume, etc. cell connected to a wire named name1, with its\n");
145 log("enable signal optionally connected to a wire named name2 (default: 1'b1).\n");
146 log("\n");
147 log("\n");
148 log(" add -mod <name[s]>\n");
149 log("\n");
150 log("Add module[s] with the specified name[s].\n");
151 log("\n");
152 }
153 void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
154 {
155 std::string command;
156 std::string arg_name;
157 std::string enable_name = "";
158 bool arg_flag_input = false;
159 bool arg_flag_output = false;
160 bool arg_flag_global = false;
161 bool mod_mode = false;
162 int arg_width = 0;
163
164 size_t argidx;
165 for (argidx = 1; argidx < args.size(); argidx++)
166 {
167 std::string arg = args[argidx];
168 if (arg == "-wire" || arg == "-input" || arg == "-inout" || arg == "-output" || arg == "-global_input") {
169 if (argidx+2 >= args.size())
170 break;
171 command = "wire";
172 if (arg == "-input" || arg == "-inout" || arg == "-global_input")
173 arg_flag_input = true;
174 if (arg == "-output" || arg == "-inout")
175 arg_flag_output = true;
176 if (arg == "-global_input")
177 arg_flag_global = true;
178 arg_name = args[++argidx];
179 arg_width = atoi(args[++argidx].c_str());
180 continue;
181 }
182 if (arg == "-mod") {
183 mod_mode = true;
184 argidx++;
185 break;
186 }
187 if (arg.length() > 0 && arg[0] == '-' && is_formal_celltype(arg.substr(1))) {
188 if (argidx + 1 >= args.size())
189 break;
190 command = arg.substr(1);
191 arg_name = args[++argidx];
192 if (argidx + 2 < args.size() && args[argidx + 1] == "-if") {
193 enable_name = args[argidx + 2];
194 argidx += 2;
195 }
196 continue;
197 }
198 break;
199 }
200
201 if (mod_mode) {
202 for (; argidx < args.size(); argidx++)
203 design->addModule(RTLIL::escape_id(args[argidx]));
204 return;
205 }
206
207 extra_args(args, argidx, design);
208
209 bool selected_anything = false;
210 for (auto module : design->modules())
211 {
212 log_assert(module != nullptr);
213 if (!design->selected_whole_module(module->name))
214 continue;
215 if (module->get_bool_attribute("\\blackbox"))
216 continue;
217
218 selected_anything = true;
219 if (is_formal_celltype(command))
220 add_formal(module, command, arg_name, enable_name);
221 else if (command == "wire")
222 add_wire(design, module, arg_name, arg_width, arg_flag_input, arg_flag_output, arg_flag_global);
223 }
224 if (!selected_anything)
225 log_warning("No modules selected, or only blackboxes. Nothing was added.\n");
226 }
227 } AddPass;
228
229 PRIVATE_NAMESPACE_END