0d3f32bf5fa7f8b1f80cb2ae4d5341e3c2898110
2 * yosys -- Yosys Open SYnthesis Suite
4 * Copyright (C) 2012 Aki "lethalbit" Van Ness <aki@yosyshq.com> <aki@lethalbit.net>
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.
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.
20 #include "kernel/rtlil.h"
21 #include "kernel/register.h"
22 #include "kernel/sigtools.h"
23 #include "kernel/celltypes.h"
24 #include "kernel/cellaigs.h"
25 #include "kernel/log.h"
27 #include <unordered_map>
31 PRIVATE_NAMESPACE_BEGIN
39 std::unordered_map
<std::string
, std::vector
<Cell
*>> _cells
{};
41 bool _include_connections
;
42 bool _include_attributes
;
43 bool _include_properties
;
45 // XXX(aki): this was pulled from the json backend, needs to be pulled
46 // out possibly into some sort of utilities file, or integrated into rtlil.h
48 string
get_string(string str
)
59 // XXX(aki): I know this is far from ideal but i'm out of spoons and cant focus so
60 // it'll have to do for now,
61 void coalesce_cells(Module
* mod
)
63 for (auto cell
: mod
->cells()) {
64 const auto cell_type
= get_string(RTLIL::unescape_id(cell
->type
));
66 if (_cells
.find(cell_type
) == _cells
.end())
67 _cells
.emplace(cell_type
, std::vector
<Cell
*>());
69 _cells
.at(cell_type
).push_back(cell
);
73 // XXX(aki): this is a lazy way to do this i know,,,
74 std::string
gen_indent(const uint16_t level
)
77 for (uint16_t i
= 0; i
<= level
; ++i
)
85 JnyWriter(std::ostream
&f
, bool use_selection
, bool connections
, bool attributes
, bool properties
) noexcept
:
86 f
{f
}, _use_selection
{use_selection
},
87 _include_connections
{connections
}, _include_attributes
{attributes
}, _include_properties
{properties
}
90 void write_metadata(Design
*design
, uint16_t indent_level
= 0)
92 log_assert(design
!= nullptr);
97 f
<< stringf(" \"generator\": %s,\n", get_string(yosys_version_str
).c_str());
98 // XXX(aki): Replace this with a proper version info eventually:tm:
99 f
<< " \"version\": \"0.0.0\",\n";
101 f
<< " \"features\": [";
104 if (_include_connections
) {
106 f
<< "\"connections\"";
109 if (_include_attributes
) {
113 f
<< "\"attributes\"";
116 if (_include_properties
) {
120 f
<< "\"properties\"";
125 f
<< " \"modules\": [\n";
128 for (auto mod
: _use_selection
? design
->selected_modules() : design
->modules()) {
131 write_module(mod
, indent_level
+ 2);
140 void write_module(Module
* mod
, uint16_t indent_level
= 0) {
141 log_assert(mod
!= nullptr);
145 const auto _indent
= gen_indent(indent_level
);
147 f
<< _indent
<< "{\n";
148 f
<< stringf(" %s\"name\": %s,\n", _indent
.c_str(), get_string(RTLIL::unescape_id(mod
->name
)).c_str());
149 f
<< _indent
<< " \"cell_sorts\": [\n";
151 bool first_sort
{true};
152 for (auto& sort
: _cells
) {
155 write_cell_sort(sort
, indent_level
+ 2);
160 f
<< _indent
<< " ]";
161 if (_include_connections
) {
162 f
<< _indent
<< ",\n \"connections\": [\n";
164 f
<< _indent
<< " ]";
166 if (_include_attributes
) {
167 f
<< _indent
<< ",\n \"attributes\": {\n";
169 write_prams(mod
->attributes
, indent_level
+ 2);
172 f
<< _indent
<< " }";
174 f
<< "\n" << _indent
<< "}";
177 void write_cell_ports(RTLIL::Cell
* port_cell
, uint64_t indent_level
= 0) {
178 const auto _indent
= gen_indent(indent_level
);
180 bool first_port
{true};
181 for (auto con
: port_cell
->connections()) {
185 f
<< _indent
<< " {\n";
186 f
<< stringf(" %s\"name\": %s,\n", _indent
.c_str(), get_string(RTLIL::unescape_id(con
.first
)).c_str());
187 f
<< _indent
<< " \"direction\": \"";
188 if (port_cell
->input(con
.first
))
190 if (port_cell
->input(con
.first
))
193 if (con
.second
.size() == 1)
194 f
<< _indent
<< " \"range\": [0, 0]\n";
196 f
<< stringf(" %s\"range\": [%d, %d]\n", _indent
.c_str(), con
.second
.size(), 0);
197 f
<< _indent
<< " }";
205 void write_cell_sort(std::pair
<const std::string
, std::vector
<Cell
*>>& sort
, uint16_t indent_level
= 0) {
206 const auto port_cell
= sort
.second
.front();
207 const auto _indent
= gen_indent(indent_level
);
209 f
<< _indent
<< "{\n";
210 f
<< stringf(" %s\"type\": %s,\n", _indent
.c_str(), sort
.first
.c_str());
211 f
<< _indent
<< " \"ports\": [\n";
213 write_cell_ports(port_cell
, indent_level
+ 2);
215 f
<< _indent
<< " ],\n" << _indent
<< " \"cells\": [\n";
217 bool first_cell
{true};
218 for (auto& cell
: sort
.second
) {
222 write_cell(cell
, indent_level
+ 2);
228 f
<< _indent
<< " ]\n";
232 void write_param_val(const Const
& v
) {
233 if ((v
.flags
& RTLIL::ConstFlags::CONST_FLAG_STRING
) == RTLIL::ConstFlags::CONST_FLAG_STRING
) {
234 const auto str
= v
.decode_string();
236 // XXX(aki): TODO, uh, yeah
238 f
<< get_string(str
);
239 } else if ((v
.flags
& RTLIL::ConstFlags::CONST_FLAG_SIGNED
) == RTLIL::ConstFlags::CONST_FLAG_SIGNED
) {
240 f
<< stringf("\"%dsd %d\"", v
.size(), v
.as_int());
241 } else if ((v
.flags
& RTLIL::ConstFlags::CONST_FLAG_REAL
) == RTLIL::ConstFlags::CONST_FLAG_REAL
) {
244 f
<< get_string(v
.as_string());
248 void write_prams(dict
<RTLIL::IdString
, RTLIL::Const
>& params
, uint16_t indent_level
= 0) {
249 const auto _indent
= gen_indent(indent_level
);
251 bool first_param
{true};
252 for (auto& param
: params
) {
255 const auto param_val
= param
.second
;
256 if (!param_val
.empty()) {
257 f
<< stringf(" %s%s: ", _indent
.c_str(), get_string(RTLIL::unescape_id(param
.first
)).c_str());
258 write_param_val(param_val
);
260 f
<< stringf(" %s%s: true", _indent
.c_str(), get_string(RTLIL::unescape_id(param
.first
)).c_str());
267 void write_cell(Cell
* cell
, uint16_t indent_level
= 0) {
268 const auto _indent
= gen_indent(indent_level
);
269 log_assert(cell
!= nullptr);
271 f
<< _indent
<< " {\n";
272 f
<< stringf(" %s\"name\": %s", _indent
.c_str(), get_string(RTLIL::unescape_id(cell
->name
)).c_str());
274 if (_include_attributes
) {
275 f
<< _indent
<< ",\n \"attributes\": {\n";
277 write_prams(cell
->attributes
, indent_level
+ 2);
280 f
<< _indent
<< " }";
283 if (_include_properties
) {
284 f
<< _indent
<< ",\n \"parameters\": {\n";
286 write_prams(cell
->parameters
, indent_level
+ 2);
289 f
<< _indent
<< " }";
292 f
<< "\n" << _indent
<< " }";
296 struct JnyBackend
: public Backend
{
297 JnyBackend() : Backend("jny", "generate design metadata") { }
298 void help() override
{
299 // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
301 log(" jny [options] [selection]\n");
303 log(" -connections\n");
304 log(" Include connection information in the netlist output.\n");
306 log(" -attributes\n");
307 log(" Include attributed information in the netlist output.\n");
309 log(" -properties\n");
310 log(" Include property information in the netlist output.\n");
312 log("Write a JSON metadata for the current design\n");
317 void execute(std::ostream
*&f
, std::string filename
, std::vector
<std::string
> args
, RTLIL::Design
*design
) override
{
319 bool connections
{false};
320 bool attributes
{false};
321 bool properties
{false};
324 for (; argidx
< args
.size(); argidx
++) {
325 if (args
[argidx
] == "-connections") {
330 if (args
[argidx
] == "-attributes") {
335 if (args
[argidx
] == "-properties") {
342 extra_args(f
, filename
, args
, argidx
);
344 log_header(design
, "Executing jny backend.\n");
346 JnyWriter
jny_writer(*f
, false, connections
, attributes
, properties
);
347 jny_writer
.write_metadata(design
);
353 struct JnyPass
: public Pass
{
354 JnyPass() : Pass("jny", "write design and metadata") { }
356 void help() override
{
357 // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
359 log(" jny [options] [selection]\n");
361 log("Write a JSON netlist metadata for the current design\n");
363 log(" -o <filename>\n");
364 log(" write to the specified file.\n");
366 log(" -connections\n");
367 log(" Include connection information in the netlist output.\n");
369 log(" -attributes\n");
370 log(" Include attributed information in the netlist output.\n");
372 log(" -properties\n");
373 log(" Include property information in the netlist output.\n");
375 log("See 'help write_jny' for a description of the JSON format used.\n");
378 void execute(std::vector
<std::string
> args
, RTLIL::Design
*design
) override
{
379 std::string filename
{};
381 bool connections
{false};
382 bool attributes
{false};
383 bool properties
{false};
386 for (; argidx
< args
.size(); argidx
++) {
387 if (args
[argidx
] == "-o" && argidx
+1 < args
.size()) {
388 filename
= args
[++argidx
];
392 if (args
[argidx
] == "-connections") {
397 if (args
[argidx
] == "-attributes") {
402 if (args
[argidx
] == "-properties") {
409 extra_args(args
, argidx
, design
);
412 std::stringstream buf
;
414 if (!filename
.empty()) {
415 rewrite_filename(filename
);
416 std::ofstream
*ff
= new std::ofstream
;
417 ff
->open(filename
.c_str(), std::ofstream::trunc
);
420 log_error("Can't open file `%s' for writing: %s\n", filename
.c_str(), strerror(errno
));
428 JnyWriter
jny_writer(*f
, false, connections
, attributes
, properties
);
429 jny_writer
.write_metadata(design
);
431 if (!filename
.empty()) {
434 log("%s", buf
.str().c_str());
440 PRIVATE_NAMESPACE_END