2 * yosys -- Yosys Open SYnthesis Suite
4 * Copyright (C) 2012 Clifford Wolf <clifford@clifford.at>
5 * Copyright (C) 2018 Serge Bazanski <q3k@symbioticeda.com>
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.
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.
21 #include <google/protobuf/text_format.h>
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"
32 PRIVATE_NAMESPACE_BEGIN
34 struct ProtobufDesignSerializer
38 yosys::pb::Design
*pb_
;
45 dict
<SigBit
, uint64_t> sigids_
;
46 pool
<Aig
> aig_models_
;
49 ProtobufDesignSerializer(bool use_selection
, bool aig_mode
) :
50 aig_mode_(aig_mode
), use_selection_(use_selection
) { }
52 string
get_name(IdString name
)
54 return RTLIL::unescape_id(name
);
58 void serialize_parameters(google::protobuf::Map
<std::string
, yosys::pb::Parameter
> *out
,
59 const dict
<IdString
, Const
> ¶meters
)
61 for (auto ¶m
: parameters
) {
62 std::string key
= get_name(param
.first
);
65 yosys::pb::Parameter pb_param
;
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());
72 pb_param
.set_int_(param
.second
.as_int());
75 (*out
)[key
] = pb_param
;
79 void get_bits(yosys::pb::BitVector
*out
, SigSpec sig
)
81 for (auto bit
: sigmap_(sig
)) {
82 auto sig
= out
->add_signal();
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
);
93 // Signal - give it a unique identifier.
94 if (sigids_
.count(bit
) == 0) {
95 sigids_
[bit
] = sigidcounter_
++;
97 sig
->set_id(sigids_
[bit
]);
101 void serialize_module(yosys::pb::Module
* out
, Module
*module
)
104 log_assert(module_
->design
== design_
);
105 sigmap_
.set(module_
);
109 serialize_parameters(out
->mutable_attribute(), module_
->attributes
);
111 for (auto n
: module_
->ports
) {
112 Wire
*w
= module
->wire(n
);
113 if (use_selection_
&& !module_
->selected(w
))
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
;
123 for (auto c
: module_
->cells()) {
124 if (use_selection_
&& !module_
->selected(c
))
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
));
133 if (aig
.name
.empty())
135 pb_cell
.set_model(aig
.name
);
136 aig_models_
.insert(aig
);
138 serialize_parameters(pb_cell
.mutable_parameter(), c
->parameters
);
139 serialize_parameters(pb_cell
.mutable_attribute(), c
->attributes
);
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
;
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
;
155 (*out
->mutable_cell())[get_name(c
->name
)] = pb_cell
;
158 for (auto w
: module_
->wires()) {
159 if (use_selection_
&& !module_
->selected(w
))
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
);
170 void serialize_models(google::protobuf::Map
<string
, yosys::pb::Model
> *models
)
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) {
178 pb_node
->set_type(pb_node
->TYPE_NPORT
);
180 pb_node
->set_type(pb_node
->TYPE_PORT
);
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) {
187 pb_node
->set_type(pb_node
->TYPE_TRUE
);
189 pb_node
->set_type(pb_node
->TYPE_FALSE
);
193 pb_node
->set_type(pb_node
->TYPE_NAND
);
195 pb_node
->set_type(pb_node
->TYPE_AND
);
197 auto gate
= pb_node
->mutable_gate();
198 gate
->set_left(node
.left_parent
);
199 gate
->set_right(node
.right_parent
);
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
);
207 (*models
)[aig
.name
] = pb_model
;
211 void serialize_design(yosys::pb::Design
*pb
, Design
*design
)
213 GOOGLE_PROTOBUF_VERIFY_VERSION
;
216 pb_
->set_creator(yosys_version_str
);
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
;
228 serialize_models(pb_
->mutable_models());
232 struct ProtobufBackend
: public Backend
{
233 ProtobufBackend(): Backend("protobuf", "write design to a Protocol Buffer file") { }
234 void help() YS_OVERRIDE
236 // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
238 log(" write_protobuf [options] [filename]\n");
240 log("Write a JSON netlist of the current design.\n");
243 log(" include AIG models for the different gate types\n");
246 log(" output protobuf in Text/ASCII representation\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");
252 void execute(std::ostream
*&f
, std::string filename
, std::vector
<std::string
> args
, RTLIL::Design
*design
) YS_OVERRIDE
254 bool aig_mode
= false;
255 bool text_mode
= false;
258 for (argidx
= 1; argidx
< args
.size(); argidx
++) {
259 if (args
[argidx
] == "-aig") {
263 if (args
[argidx
] == "-text") {
269 extra_args(f
, filename
, args
, argidx
);
271 log_header(design
, "Executing Protobuf backend.\n");
273 yosys::pb::Design pb
;
274 ProtobufDesignSerializer
serializer(false, aig_mode
);
275 serializer
.serialize_design(&pb
, design
);
279 google::protobuf::TextFormat::PrintToString(pb
, &out
);
282 pb
.SerializeToOstream(f
);
287 struct ProtobufPass
: public Pass
{
288 ProtobufPass() : Pass("protobuf", "write design in Protobuf format") { }
289 void help() YS_OVERRIDE
291 // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
293 log(" protobuf [options] [selection]\n");
295 log("Write a JSON netlist of all selected objects.\n");
297 log(" -o <filename>\n");
298 log(" write to the specified file.\n");
301 log(" include AIG models for the different gate types\n");
304 log(" output protobuf in Text/ASCII representation\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");
310 void execute(std::vector
<std::string
> args
, RTLIL::Design
*design
) YS_OVERRIDE
312 std::string filename
;
313 bool aig_mode
= false;
314 bool text_mode
= false;
317 for (argidx
= 1; argidx
< args
.size(); argidx
++)
319 if (args
[argidx
] == "-o" && argidx
+1 < args
.size()) {
320 filename
= args
[++argidx
];
323 if (args
[argidx
] == "-aig") {
327 if (args
[argidx
] == "-text") {
333 extra_args(args
, argidx
, design
);
336 std::stringstream buf
;
338 if (!filename
.empty()) {
339 std::ofstream
*ff
= new std::ofstream
;
340 ff
->open(filename
.c_str(), std::ofstream::trunc
);
343 log_error("Can't open file `%s' for writing: %s\n", filename
.c_str(), strerror(errno
));
350 yosys::pb::Design pb
;
351 ProtobufDesignSerializer
serializer(true, aig_mode
);
352 serializer
.serialize_design(&pb
, design
);
356 google::protobuf::TextFormat::PrintToString(pb
, &out
);
359 pb
.SerializeToOstream(f
);
362 if (!filename
.empty()) {
365 log("%s", buf
.str().c_str());
370 PRIVATE_NAMESPACE_END
;