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 // XXX(aki): this was pulled from the json backend, needs to be pulled
42 // out possibly into some sort of utilities file, or integrated into rtlil.h
44 string
get_string(string str
)
55 // XXX(aki): I know this is far from ideal but i'm out of spoons and cant focus so
56 // it'll have to do for now,
57 void coalesce_cells(Module
* mod
)
59 for (auto cell
: mod
->cells()) {
60 const auto cell_type
= get_string(RTLIL::unescape_id(cell
->type
));
62 if (_cells
.find(cell_type
) == _cells
.end())
63 _cells
.emplace(cell_type
, std::vector
<Cell
*>());
65 _cells
.at(cell_type
).push_back(cell
);
69 // XXX(aki): this is a lazy way to do this i know,,,
70 std::string
gen_indent(const uint16_t level
)
73 for (uint16_t i
= 0; i
<= level
; ++i
)
81 JnyWriter(std::ostream
&f
, bool use_selection
) noexcept
: f(f
), _use_selection(use_selection
) { }
83 void write_metadata(Design
*design
, uint16_t indent_level
= 0)
85 log_assert(design
!= nullptr);
90 f
<< stringf(" \"generator\": %s,\n", get_string(yosys_version_str
).c_str());
91 // XXX(aki): Replace this with a proper version info eventually:tm:
92 f
<< " \"version\": \"0.0.0\",\n";
93 f
<< " \"modules\": [\n";
96 for (auto mod
: _use_selection
? design
->selected_modules() : design
->modules()) {
99 write_module(mod
, indent_level
+ 2);
108 void write_module(Module
* mod
, uint16_t indent_level
= 0) {
109 log_assert(mod
!= nullptr);
113 const auto _indent
= gen_indent(indent_level
);
115 f
<< _indent
<< "{\n";
116 f
<< stringf(" %s\"name\": %s,\n", _indent
.c_str(), get_string(RTLIL::unescape_id(mod
->name
)).c_str());
117 f
<< _indent
<< " \"cell_sorts\": [\n";
119 bool first_sort
{true};
120 for (auto& sort
: _cells
) {
123 write_cell_sort(sort
, indent_level
+ 2);
128 f
<< _indent
<< " ],\n";
129 f
<< _indent
<< " \"connections\": [\n";
131 f
<< _indent
<< " ],\n";
132 f
<< _indent
<< " \"attributes\": {\n";
134 write_prams(mod
->attributes
, indent_level
+ 2);
138 f
<< _indent
<< " }\n";
142 void write_cell_ports(RTLIL::Cell
* port_cell
, uint64_t indent_level
= 0) {
143 const auto _indent
= gen_indent(indent_level
);
145 bool first_port
{true};
146 for (auto con
: port_cell
->connections()) {
150 f
<< _indent
<< " {\n";
151 f
<< stringf(" %s\"name\": %s,\n", _indent
.c_str(), get_string(RTLIL::unescape_id(con
.first
)).c_str());
152 f
<< _indent
<< " \"direction\": \"";
153 if (port_cell
->input(con
.first
))
155 if (port_cell
->input(con
.first
))
158 if (con
.second
.size() == 1)
159 f
<< _indent
<< " \"range\": [0, 0]\n";
161 f
<< stringf(" %s\"range\": [%d, %d]\n", _indent
.c_str(), con
.second
.size(), 0);
162 f
<< _indent
<< " }";
170 void write_cell_sort(std::pair
<const std::string
, std::vector
<Cell
*>>& sort
, uint16_t indent_level
= 0) {
171 const auto port_cell
= sort
.second
.front();
172 const auto _indent
= gen_indent(indent_level
);
174 f
<< _indent
<< "{\n";
175 f
<< stringf(" %s\"type\": %s,\n", _indent
.c_str(), sort
.first
.c_str());
176 f
<< _indent
<< " \"ports\": [\n";
178 write_cell_ports(port_cell
, indent_level
+ 2);
180 f
<< _indent
<< " ],\n" << _indent
<< " \"cells\": [\n";
182 bool first_cell
{true};
183 for (auto& cell
: sort
.second
) {
187 write_cell(cell
, indent_level
+ 2);
193 f
<< _indent
<< " ]\n";
197 void write_param_val(const Const
& v
) {
198 if ((v
.flags
& RTLIL::ConstFlags::CONST_FLAG_STRING
) == RTLIL::ConstFlags::CONST_FLAG_STRING
) {
199 const auto str
= v
.decode_string();
201 // XXX(aki): TODO, uh, yeah
203 f
<< get_string(str
);
204 } else if ((v
.flags
& RTLIL::ConstFlags::CONST_FLAG_SIGNED
) == RTLIL::ConstFlags::CONST_FLAG_SIGNED
) {
205 f
<< stringf("\"%dsd %d\"", v
.size(), v
.as_int());
206 } else if ((v
.flags
& RTLIL::ConstFlags::CONST_FLAG_REAL
) == RTLIL::ConstFlags::CONST_FLAG_REAL
) {
209 f
<< get_string(v
.as_string());
213 void write_prams(dict
<RTLIL::IdString
, RTLIL::Const
>& params
, uint16_t indent_level
= 0) {
214 const auto _indent
= gen_indent(indent_level
);
216 bool first_param
{true};
217 for (auto& param
: params
) {
220 const auto param_val
= param
.second
;
221 if (!param_val
.empty()) {
222 f
<< stringf(" %s%s: ", _indent
.c_str(), get_string(RTLIL::unescape_id(param
.first
)).c_str());
223 write_param_val(param_val
);
225 f
<< stringf(" %s%s: true", _indent
.c_str(), get_string(RTLIL::unescape_id(param
.first
)).c_str());
232 void write_cell(Cell
* cell
, uint16_t indent_level
= 0) {
233 const auto _indent
= gen_indent(indent_level
);
234 log_assert(cell
!= nullptr);
236 f
<< _indent
<< " {\n";
237 f
<< stringf(" %s\"name\": %s,\n", _indent
.c_str(), get_string(RTLIL::unescape_id(cell
->name
)).c_str());
238 f
<< _indent
<< " \"attributes\": {\n";
240 write_prams(cell
->attributes
, indent_level
+ 2);
244 f
<< _indent
<< " },\n";
245 f
<< _indent
<< " \"parameters\": {\n";
247 write_prams(cell
->parameters
, indent_level
+ 2);
251 f
<< _indent
<< " }\n";
252 f
<< _indent
<< " }";
256 struct JnyBackend
: public Backend
{
257 JnyBackend() : Backend("jny", "generate design metadata") { }
258 void help() override
{
259 // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
261 log(" jny [options] [selection]\n");
263 log("Write a JSON metadata for the current design\n");
268 void execute(std::ostream
*&f
, std::string filename
, std::vector
<std::string
> args
, RTLIL::Design
*design
) override
{
270 extra_args(f
, filename
, args
, argidx
);
272 log_header(design
, "Executing jny backend.\n");
274 JnyWriter
jny_writer(*f
, false);
275 jny_writer
.write_metadata(design
);
281 struct JnyPass
: public Pass
{
282 JnyPass() : Pass("jny", "write design and metadata") { }
284 void help() override
{
285 // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
287 log(" jny [options] [selection]\n");
289 log("Write a JSON netlist metadata for the current design\n");
291 log(" -o <filename>\n");
292 log(" write to the specified file.\n");
294 log("See 'help write_jny' for a description of the JSON format used.\n");
297 void execute(std::vector
<std::string
> args
, RTLIL::Design
*design
) override
{
298 std::string filename
{};
301 for (argidx
= 1; argidx
< args
.size(); argidx
++)
303 if (args
[argidx
] == "-o" && argidx
+1 < args
.size()) {
304 filename
= args
[++argidx
];
309 extra_args(args
, argidx
, design
);
312 std::stringstream buf
;
314 if (!filename
.empty()) {
315 rewrite_filename(filename
);
316 std::ofstream
*ff
= new std::ofstream
;
317 ff
->open(filename
.c_str(), std::ofstream::trunc
);
320 log_error("Can't open file `%s' for writing: %s\n", filename
.c_str(), strerror(errno
));
328 JnyWriter
jny_writer(*f
, false);
329 jny_writer
.write_metadata(design
);
331 if (!filename
.empty()) {
334 log("%s", buf
.str().c_str());
340 PRIVATE_NAMESPACE_END