Use C++11 final/override keywords.
[yosys.git] / backends / protobuf / protobuf.cc
1 /*
2 * yosys -- Yosys Open SYnthesis Suite
3 *
4 * Copyright (C) 2012 Clifford Wolf <clifford@clifford.at>
5 * Copyright (C) 2018 Serge Bazanski <q3k@symbioticeda.com>
6 *
7 * Permission to use, copy, modify, and/or distribute this software for any
8 * purpose with or without fee is hereby granted, provided that the above
9 * copyright notice and this permission notice appear in all copies.
10 *
11 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
12 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
13 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
14 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
15 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
16 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
17 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
18 *
19 */
20
21 #include <google/protobuf/text_format.h>
22
23 #include "kernel/rtlil.h"
24 #include "kernel/register.h"
25 #include "kernel/sigtools.h"
26 #include "kernel/celltypes.h"
27 #include "kernel/cellaigs.h"
28 #include "kernel/log.h"
29 #include "yosys.pb.h"
30
31 USING_YOSYS_NAMESPACE
32 PRIVATE_NAMESPACE_BEGIN
33
34 struct ProtobufDesignSerializer
35 {
36 bool aig_mode_;
37 bool use_selection_;
38 yosys::pb::Design *pb_;
39
40 Design *design_;
41 Module *module_;
42
43 SigMap sigmap_;
44 int sigidcounter_;
45 dict<SigBit, uint64_t> sigids_;
46 pool<Aig> aig_models_;
47
48
49 ProtobufDesignSerializer(bool use_selection, bool aig_mode) :
50 aig_mode_(aig_mode), use_selection_(use_selection) { }
51
52 string get_name(IdString name)
53 {
54 return RTLIL::unescape_id(name);
55 }
56
57
58 void serialize_parameters(google::protobuf::Map<std::string, yosys::pb::Parameter> *out,
59 const dict<IdString, Const> &parameters)
60 {
61 for (auto &param : parameters) {
62 std::string key = get_name(param.first);
63
64
65 yosys::pb::Parameter pb_param;
66
67 if ((param.second.flags & RTLIL::ConstFlags::CONST_FLAG_STRING) != 0) {
68 pb_param.set_str(param.second.decode_string());
69 } else if (GetSize(param.second.bits) > 64) {
70 pb_param.set_str(param.second.as_string());
71 } else {
72 pb_param.set_int_(param.second.as_int());
73 }
74
75 (*out)[key] = pb_param;
76 }
77 }
78
79 void get_bits(yosys::pb::BitVector *out, SigSpec sig)
80 {
81 for (auto bit : sigmap_(sig)) {
82 auto sig = out->add_signal();
83
84 // Constant driver.
85 if (bit.wire == nullptr) {
86 if (bit == State::S0) sig->set_constant(sig->CONSTANT_DRIVER_LOW);
87 else if (bit == State::S1) sig->set_constant(sig->CONSTANT_DRIVER_HIGH);
88 else if (bit == State::Sz) sig->set_constant(sig->CONSTANT_DRIVER_Z);
89 else sig->set_constant(sig->CONSTANT_DRIVER_X);
90 continue;
91 }
92
93 // Signal - give it a unique identifier.
94 if (sigids_.count(bit) == 0) {
95 sigids_[bit] = sigidcounter_++;
96 }
97 sig->set_id(sigids_[bit]);
98 }
99 }
100
101 void serialize_module(yosys::pb::Module* out, Module *module)
102 {
103 module_ = module;
104 log_assert(module_->design == design_);
105 sigmap_.set(module_);
106 sigids_.clear();
107 sigidcounter_ = 0;
108
109 serialize_parameters(out->mutable_attribute(), module_->attributes);
110
111 for (auto n : module_->ports) {
112 Wire *w = module->wire(n);
113 if (use_selection_ && !module_->selected(w))
114 continue;
115
116 yosys::pb::Module::Port pb_port;
117 pb_port.set_direction(w->port_input ? w->port_output ?
118 yosys::pb::DIRECTION_INOUT : yosys::pb::DIRECTION_INPUT : yosys::pb::DIRECTION_OUTPUT);
119 get_bits(pb_port.mutable_bits(), w);
120 (*out->mutable_port())[get_name(n)] = pb_port;
121 }
122
123 for (auto c : module_->cells()) {
124 if (use_selection_ && !module_->selected(c))
125 continue;
126
127 yosys::pb::Module::Cell pb_cell;
128 pb_cell.set_hide_name(c->name[0] == '$');
129 pb_cell.set_type(get_name(c->type));
130
131 if (aig_mode_) {
132 Aig aig(c);
133 if (aig.name.empty())
134 continue;
135 pb_cell.set_model(aig.name);
136 aig_models_.insert(aig);
137 }
138 serialize_parameters(pb_cell.mutable_parameter(), c->parameters);
139 serialize_parameters(pb_cell.mutable_attribute(), c->attributes);
140
141 if (c->known()) {
142 for (auto &conn : c->connections()) {
143 yosys::pb::Direction direction = yosys::pb::DIRECTION_OUTPUT;
144 if (c->input(conn.first))
145 direction = c->output(conn.first) ? yosys::pb::DIRECTION_INOUT : yosys::pb::DIRECTION_INPUT;
146 (*pb_cell.mutable_port_direction())[get_name(conn.first)] = direction;
147 }
148 }
149 for (auto &conn : c->connections()) {
150 yosys::pb::BitVector vec;
151 get_bits(&vec, conn.second);
152 (*pb_cell.mutable_connection())[get_name(conn.first)] = vec;
153 }
154
155 (*out->mutable_cell())[get_name(c->name)] = pb_cell;
156 }
157
158 for (auto w : module_->wires()) {
159 if (use_selection_ && !module_->selected(w))
160 continue;
161
162 auto netname = out->add_netname();
163 netname->set_hide_name(w->name[0] == '$');
164 get_bits(netname->mutable_bits(), w);
165 serialize_parameters(netname->mutable_attributes(), w->attributes);
166 }
167 }
168
169
170 void serialize_models(google::protobuf::Map<string, yosys::pb::Model> *models)
171 {
172 for (auto &aig : aig_models_) {
173 yosys::pb::Model pb_model;
174 for (auto &node : aig.nodes) {
175 auto pb_node = pb_model.add_node();
176 if (node.portbit >= 0) {
177 if (node.inverter) {
178 pb_node->set_type(pb_node->TYPE_NPORT);
179 } else {
180 pb_node->set_type(pb_node->TYPE_PORT);
181 }
182 auto port = pb_node->mutable_port();
183 port->set_portname(log_id(node.portname));
184 port->set_bitindex(node.portbit);
185 } else if (node.left_parent < 0 && node.right_parent < 0) {
186 if (node.inverter) {
187 pb_node->set_type(pb_node->TYPE_TRUE);
188 } else {
189 pb_node->set_type(pb_node->TYPE_FALSE);
190 }
191 } else {
192 if (node.inverter) {
193 pb_node->set_type(pb_node->TYPE_NAND);
194 } else {
195 pb_node->set_type(pb_node->TYPE_AND);
196 }
197 auto gate = pb_node->mutable_gate();
198 gate->set_left(node.left_parent);
199 gate->set_right(node.right_parent);
200 }
201 for (auto &op : node.outports) {
202 auto pb_op = pb_node->add_out_port();
203 pb_op->set_name(log_id(op.first));
204 pb_op->set_bit_index(op.second);
205 }
206 }
207 (*models)[aig.name] = pb_model;
208 }
209 }
210
211 void serialize_design(yosys::pb::Design *pb, Design *design)
212 {
213 GOOGLE_PROTOBUF_VERIFY_VERSION;
214 pb_ = pb;
215 pb_->Clear();
216 pb_->set_creator(yosys_version_str);
217
218 design_ = design;
219 design_->sort();
220
221 auto modules = use_selection_ ? design_->selected_modules() : design_->modules();
222 for (auto mod : modules) {
223 yosys::pb::Module pb_mod;
224 serialize_module(&pb_mod, mod);
225 (*pb->mutable_modules())[mod->name.str()] = pb_mod;
226 }
227
228 serialize_models(pb_->mutable_models());
229 }
230 };
231
232 struct ProtobufBackend : public Backend {
233 ProtobufBackend(): Backend("protobuf", "write design to a Protocol Buffer file") { }
234 void help() override
235 {
236 // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
237 log("\n");
238 log(" write_protobuf [options] [filename]\n");
239 log("\n");
240 log("Write a JSON netlist of the current design.\n");
241 log("\n");
242 log(" -aig\n");
243 log(" include AIG models for the different gate types\n");
244 log("\n");
245 log(" -text\n");
246 log(" output protobuf in Text/ASCII representation\n");
247 log("\n");
248 log("The schema of the output Protocol Buffer is defined in misc/yosys.pb in the\n");
249 log("Yosys source code distribution.\n");
250 log("\n");
251 }
252 void execute(std::ostream *&f, std::string filename, std::vector<std::string> args, RTLIL::Design *design) override
253 {
254 bool aig_mode = false;
255 bool text_mode = false;
256
257 size_t argidx;
258 for (argidx = 1; argidx < args.size(); argidx++) {
259 if (args[argidx] == "-aig") {
260 aig_mode = true;
261 continue;
262 }
263 if (args[argidx] == "-text") {
264 text_mode = true;
265 continue;
266 }
267 break;
268 }
269 extra_args(f, filename, args, argidx, !text_mode);
270
271 log_header(design, "Executing Protobuf backend.\n");
272
273 yosys::pb::Design pb;
274 ProtobufDesignSerializer serializer(false, aig_mode);
275 serializer.serialize_design(&pb, design);
276
277 if (text_mode) {
278 string out;
279 google::protobuf::TextFormat::PrintToString(pb, &out);
280 *f << out;
281 } else {
282 pb.SerializeToOstream(f);
283 }
284 }
285 } ProtobufBackend;
286
287 struct ProtobufPass : public Pass {
288 ProtobufPass() : Pass("protobuf", "write design in Protobuf format") { }
289 void help() override
290 {
291 // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
292 log("\n");
293 log(" protobuf [options] [selection]\n");
294 log("\n");
295 log("Write a JSON netlist of all selected objects.\n");
296 log("\n");
297 log(" -o <filename>\n");
298 log(" write to the specified file.\n");
299 log("\n");
300 log(" -aig\n");
301 log(" include AIG models for the different gate types\n");
302 log("\n");
303 log(" -text\n");
304 log(" output protobuf in Text/ASCII representation\n");
305 log("\n");
306 log("The schema of the output Protocol Buffer is defined in misc/yosys.pb in the\n");
307 log("Yosys source code distribution.\n");
308 log("\n");
309 }
310 void execute(std::vector<std::string> args, RTLIL::Design *design) override
311 {
312 std::string filename;
313 bool aig_mode = false;
314 bool text_mode = false;
315
316 size_t argidx;
317 for (argidx = 1; argidx < args.size(); argidx++)
318 {
319 if (args[argidx] == "-o" && argidx+1 < args.size()) {
320 filename = args[++argidx];
321 continue;
322 }
323 if (args[argidx] == "-aig") {
324 aig_mode = true;
325 continue;
326 }
327 if (args[argidx] == "-text") {
328 text_mode = true;
329 continue;
330 }
331 break;
332 }
333 extra_args(args, argidx, design);
334
335 std::ostream *f;
336 std::stringstream buf;
337
338 if (!filename.empty()) {
339 rewrite_filename(filename);
340 std::ofstream *ff = new std::ofstream;
341 ff->open(filename.c_str(), text_mode ? std::ofstream::trunc : (std::ofstream::trunc | std::ofstream::binary));
342 if (ff->fail()) {
343 delete ff;
344 log_error("Can't open file `%s' for writing: %s\n", filename.c_str(), strerror(errno));
345 }
346 f = ff;
347 } else {
348 f = &buf;
349 }
350
351 yosys::pb::Design pb;
352 ProtobufDesignSerializer serializer(true, aig_mode);
353 serializer.serialize_design(&pb, design);
354
355 if (text_mode) {
356 string out;
357 google::protobuf::TextFormat::PrintToString(pb, &out);
358 *f << out;
359 } else {
360 pb.SerializeToOstream(f);
361 }
362
363 if (!filename.empty()) {
364 delete f;
365 } else {
366 log("%s", buf.str().c_str());
367 }
368 }
369 } ProtobufPass;
370
371 PRIVATE_NAMESPACE_END;