1b11de5ec39454df7e759c8a9e111acc1b1984ef
2 * yosys -- Yosys Open SYnthesis Suite
4 * Copyright (C) 2012 Claire Xenia Wolf <claire@yosyshq.com>
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 * A very simple and straightforward backend for the RTLIL text
25 #include "rtlil_backend.h"
26 #include "kernel/yosys.h"
30 using namespace RTLIL_BACKEND
;
33 void RTLIL_BACKEND::dump_const(std::ostream
&f
, const RTLIL::Const
&data
, int width
, int offset
, bool autoint
)
36 width
= data
.bits
.size() - offset
;
37 if ((data
.flags
& RTLIL::CONST_FLAG_STRING
) == 0 || width
!= (int)data
.bits
.size()) {
38 if (width
== 32 && autoint
) {
40 for (int i
= 0; i
< width
; i
++) {
41 log_assert(offset
+i
< (int)data
.bits
.size());
42 switch (data
.bits
[offset
+i
]) {
43 case State::S0
: break;
44 case State::S1
: val
|= 1 << i
; break;
45 default: val
= -1; break;
49 f
<< stringf("%d", val
);
53 f
<< stringf("%d'", width
);
54 if (data
.is_fully_undef()) {
57 for (int i
= offset
+width
-1; i
>= offset
; i
--) {
58 log_assert(i
< (int)data
.bits
.size());
59 switch (data
.bits
[i
]) {
60 case State::S0
: f
<< stringf("0"); break;
61 case State::S1
: f
<< stringf("1"); break;
62 case RTLIL::Sx
: f
<< stringf("x"); break;
63 case RTLIL::Sz
: f
<< stringf("z"); break;
64 case RTLIL::Sa
: f
<< stringf("-"); break;
65 case RTLIL::Sm
: f
<< stringf("m"); break;
71 std::string str
= data
.decode_string();
72 for (size_t i
= 0; i
< str
.size(); i
++) {
75 else if (str
[i
] == '\t')
78 f
<< stringf("\\%03o", str
[i
]);
79 else if (str
[i
] == '"')
81 else if (str
[i
] == '\\')
90 void RTLIL_BACKEND::dump_sigchunk(std::ostream
&f
, const RTLIL::SigChunk
&chunk
, bool autoint
)
92 if (chunk
.wire
== NULL
) {
93 dump_const(f
, chunk
.data
, chunk
.width
, chunk
.offset
, autoint
);
95 if (chunk
.width
== chunk
.wire
->width
&& chunk
.offset
== 0)
96 f
<< stringf("%s", chunk
.wire
->name
.c_str());
97 else if (chunk
.width
== 1)
98 f
<< stringf("%s [%d]", chunk
.wire
->name
.c_str(), chunk
.offset
);
100 f
<< stringf("%s [%d:%d]", chunk
.wire
->name
.c_str(), chunk
.offset
+chunk
.width
-1, chunk
.offset
);
104 void RTLIL_BACKEND::dump_sigspec(std::ostream
&f
, const RTLIL::SigSpec
&sig
, bool autoint
)
106 if (sig
.is_chunk()) {
107 dump_sigchunk(f
, sig
.as_chunk(), autoint
);
110 for (auto it
= sig
.chunks().rbegin(); it
!= sig
.chunks().rend(); ++it
) {
111 dump_sigchunk(f
, *it
, false);
118 void RTLIL_BACKEND::dump_wire(std::ostream
&f
, std::string indent
, const RTLIL::Wire
*wire
)
120 for (auto &it
: wire
->attributes
) {
121 f
<< stringf("%s" "attribute %s ", indent
.c_str(), it
.first
.c_str());
122 dump_const(f
, it
.second
);
125 f
<< stringf("%s" "wire ", indent
.c_str());
126 if (wire
->width
!= 1)
127 f
<< stringf("width %d ", wire
->width
);
129 f
<< stringf("upto ");
130 if (wire
->start_offset
!= 0)
131 f
<< stringf("offset %d ", wire
->start_offset
);
132 if (wire
->port_input
&& !wire
->port_output
)
133 f
<< stringf("input %d ", wire
->port_id
);
134 if (!wire
->port_input
&& wire
->port_output
)
135 f
<< stringf("output %d ", wire
->port_id
);
136 if (wire
->port_input
&& wire
->port_output
)
137 f
<< stringf("inout %d ", wire
->port_id
);
139 f
<< stringf("signed ");
140 f
<< stringf("%s\n", wire
->name
.c_str());
143 void RTLIL_BACKEND::dump_memory(std::ostream
&f
, std::string indent
, const RTLIL::Memory
*memory
)
145 for (auto &it
: memory
->attributes
) {
146 f
<< stringf("%s" "attribute %s ", indent
.c_str(), it
.first
.c_str());
147 dump_const(f
, it
.second
);
150 f
<< stringf("%s" "memory ", indent
.c_str());
151 if (memory
->width
!= 1)
152 f
<< stringf("width %d ", memory
->width
);
153 if (memory
->size
!= 0)
154 f
<< stringf("size %d ", memory
->size
);
155 if (memory
->start_offset
!= 0)
156 f
<< stringf("offset %d ", memory
->start_offset
);
157 f
<< stringf("%s\n", memory
->name
.c_str());
160 void RTLIL_BACKEND::dump_cell(std::ostream
&f
, std::string indent
, const RTLIL::Cell
*cell
)
162 for (auto &it
: cell
->attributes
) {
163 f
<< stringf("%s" "attribute %s ", indent
.c_str(), it
.first
.c_str());
164 dump_const(f
, it
.second
);
167 f
<< stringf("%s" "cell %s %s\n", indent
.c_str(), cell
->type
.c_str(), cell
->name
.c_str());
168 for (auto &it
: cell
->parameters
) {
169 f
<< stringf("%s parameter%s%s %s ", indent
.c_str(),
170 (it
.second
.flags
& RTLIL::CONST_FLAG_SIGNED
) != 0 ? " signed" : "",
171 (it
.second
.flags
& RTLIL::CONST_FLAG_REAL
) != 0 ? " real" : "",
173 dump_const(f
, it
.second
);
176 for (auto &it
: cell
->connections()) {
177 f
<< stringf("%s connect %s ", indent
.c_str(), it
.first
.c_str());
178 dump_sigspec(f
, it
.second
);
181 f
<< stringf("%s" "end\n", indent
.c_str());
184 void RTLIL_BACKEND::dump_proc_case_body(std::ostream
&f
, std::string indent
, const RTLIL::CaseRule
*cs
)
186 for (auto it
= cs
->actions
.begin(); it
!= cs
->actions
.end(); ++it
)
188 f
<< stringf("%s" "assign ", indent
.c_str());
189 dump_sigspec(f
, it
->first
);
191 dump_sigspec(f
, it
->second
);
195 for (auto it
= cs
->switches
.begin(); it
!= cs
->switches
.end(); ++it
)
196 dump_proc_switch(f
, indent
, *it
);
199 void RTLIL_BACKEND::dump_proc_switch(std::ostream
&f
, std::string indent
, const RTLIL::SwitchRule
*sw
)
201 for (auto it
= sw
->attributes
.begin(); it
!= sw
->attributes
.end(); ++it
) {
202 f
<< stringf("%s" "attribute %s ", indent
.c_str(), it
->first
.c_str());
203 dump_const(f
, it
->second
);
207 f
<< stringf("%s" "switch ", indent
.c_str());
208 dump_sigspec(f
, sw
->signal
);
211 for (auto it
= sw
->cases
.begin(); it
!= sw
->cases
.end(); ++it
)
213 for (auto ait
= (*it
)->attributes
.begin(); ait
!= (*it
)->attributes
.end(); ++ait
) {
214 f
<< stringf("%s attribute %s ", indent
.c_str(), ait
->first
.c_str());
215 dump_const(f
, ait
->second
);
218 f
<< stringf("%s case ", indent
.c_str());
219 for (size_t i
= 0; i
< (*it
)->compare
.size(); i
++) {
222 dump_sigspec(f
, (*it
)->compare
[i
]);
226 dump_proc_case_body(f
, indent
+ " ", *it
);
229 f
<< stringf("%s" "end\n", indent
.c_str());
232 void RTLIL_BACKEND::dump_proc_sync(std::ostream
&f
, std::string indent
, const RTLIL::SyncRule
*sy
)
234 f
<< stringf("%s" "sync ", indent
.c_str());
236 case RTLIL::ST0
: f
<< stringf("low ");
237 if (0) case RTLIL::ST1
: f
<< stringf("high ");
238 if (0) case RTLIL::STp
: f
<< stringf("posedge ");
239 if (0) case RTLIL::STn
: f
<< stringf("negedge ");
240 if (0) case RTLIL::STe
: f
<< stringf("edge ");
241 dump_sigspec(f
, sy
->signal
);
244 case RTLIL::STa
: f
<< stringf("always\n"); break;
245 case RTLIL::STg
: f
<< stringf("global\n"); break;
246 case RTLIL::STi
: f
<< stringf("init\n"); break;
249 for (auto &it
: sy
->actions
) {
250 f
<< stringf("%s update ", indent
.c_str());
251 dump_sigspec(f
, it
.first
);
253 dump_sigspec(f
, it
.second
);
257 for (auto &it
: sy
->mem_write_actions
) {
258 for (auto it2
= it
.attributes
.begin(); it2
!= it
.attributes
.end(); ++it2
) {
259 f
<< stringf("%s attribute %s ", indent
.c_str(), it2
->first
.c_str());
260 dump_const(f
, it2
->second
);
263 f
<< stringf("%s memwr %s ", indent
.c_str(), it
.memid
.c_str());
264 dump_sigspec(f
, it
.address
);
266 dump_sigspec(f
, it
.data
);
268 dump_sigspec(f
, it
.enable
);
270 dump_const(f
, it
.priority_mask
);
275 void RTLIL_BACKEND::dump_proc(std::ostream
&f
, std::string indent
, const RTLIL::Process
*proc
)
277 for (auto it
= proc
->attributes
.begin(); it
!= proc
->attributes
.end(); ++it
) {
278 f
<< stringf("%s" "attribute %s ", indent
.c_str(), it
->first
.c_str());
279 dump_const(f
, it
->second
);
282 f
<< stringf("%s" "process %s\n", indent
.c_str(), proc
->name
.c_str());
283 dump_proc_case_body(f
, indent
+ " ", &proc
->root_case
);
284 for (auto it
= proc
->syncs
.begin(); it
!= proc
->syncs
.end(); ++it
)
285 dump_proc_sync(f
, indent
+ " ", *it
);
286 f
<< stringf("%s" "end\n", indent
.c_str());
289 void RTLIL_BACKEND::dump_conn(std::ostream
&f
, std::string indent
, const RTLIL::SigSpec
&left
, const RTLIL::SigSpec
&right
)
291 f
<< stringf("%s" "connect ", indent
.c_str());
292 dump_sigspec(f
, left
);
294 dump_sigspec(f
, right
);
298 void RTLIL_BACKEND::dump_module(std::ostream
&f
, std::string indent
, RTLIL::Module
*module
, RTLIL::Design
*design
, bool only_selected
, bool flag_m
, bool flag_n
)
300 bool print_header
= flag_m
|| design
->selected_whole_module(module
->name
);
301 bool print_body
= !flag_n
|| !design
->selected_whole_module(module
->name
);
305 for (auto it
= module
->attributes
.begin(); it
!= module
->attributes
.end(); ++it
) {
306 f
<< stringf("%s" "attribute %s ", indent
.c_str(), it
->first
.c_str());
307 dump_const(f
, it
->second
);
311 f
<< stringf("%s" "module %s\n", indent
.c_str(), module
->name
.c_str());
313 if (!module
->avail_parameters
.empty()) {
316 for (const auto &p
: module
->avail_parameters
) {
317 const auto &it
= module
->parameter_default_values
.find(p
);
318 if (it
== module
->parameter_default_values
.end()) {
319 f
<< stringf("%s" " parameter %s\n", indent
.c_str(), p
.c_str());
321 f
<< stringf("%s" " parameter %s ", indent
.c_str(), p
.c_str());
322 dump_const(f
, it
->second
);
331 for (auto it
: module
->wires())
332 if (!only_selected
|| design
->selected(module
, it
)) {
335 dump_wire(f
, indent
+ " ", it
);
338 for (auto it
: module
->memories
)
339 if (!only_selected
|| design
->selected(module
, it
.second
)) {
342 dump_memory(f
, indent
+ " ", it
.second
);
345 for (auto it
: module
->cells())
346 if (!only_selected
|| design
->selected(module
, it
)) {
349 dump_cell(f
, indent
+ " ", it
);
352 for (auto it
: module
->processes
)
353 if (!only_selected
|| design
->selected(module
, it
.second
)) {
356 dump_proc(f
, indent
+ " ", it
.second
);
359 bool first_conn_line
= true;
360 for (auto it
= module
->connections().begin(); it
!= module
->connections().end(); ++it
) {
361 bool show_conn
= !only_selected
|| design
->selected_whole_module(module
->name
);
363 RTLIL::SigSpec sigs
= it
->first
;
364 sigs
.append(it
->second
);
365 for (auto &c
: sigs
.chunks()) {
366 if (c
.wire
== NULL
|| !design
->selected(module
, c
.wire
))
372 if (only_selected
&& first_conn_line
)
374 dump_conn(f
, indent
+ " ", it
->first
, it
->second
);
375 first_conn_line
= false;
381 f
<< stringf("%s" "end\n", indent
.c_str());
384 void RTLIL_BACKEND::dump_design(std::ostream
&f
, RTLIL::Design
*design
, bool only_selected
, bool flag_m
, bool flag_n
)
386 int init_autoidx
= autoidx
;
389 int count_selected_mods
= 0;
390 for (auto module
: design
->modules()) {
391 if (design
->selected_whole_module(module
->name
))
393 if (design
->selected(module
))
394 count_selected_mods
++;
396 if (count_selected_mods
> 1)
400 if (!only_selected
|| flag_m
) {
403 f
<< stringf("autoidx %d\n", autoidx
);
406 for (auto module
: design
->modules()) {
407 if (!only_selected
|| design
->selected(module
)) {
410 dump_module(f
, "", module
, design
, only_selected
, flag_m
, flag_n
);
414 log_assert(init_autoidx
== autoidx
);
418 PRIVATE_NAMESPACE_BEGIN
420 struct RTLILBackend
: public Backend
{
421 RTLILBackend() : Backend("rtlil", "write design to RTLIL file") { }
424 // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
426 log(" write_rtlil [filename]\n");
428 log("Write the current design to an RTLIL file. (RTLIL is a text representation\n");
429 log("of a design in yosys's internal format.)\n");
432 log(" only write selected parts of the design.\n");
435 void execute(std::ostream
*&f
, std::string filename
, std::vector
<std::string
> args
, RTLIL::Design
*design
) override
437 bool selected
= false;
439 log_header(design
, "Executing RTLIL backend.\n");
442 for (argidx
= 1; argidx
< args
.size(); argidx
++) {
443 std::string arg
= args
[argidx
];
444 if (arg
== "-selected") {
450 extra_args(f
, filename
, args
, argidx
);
454 log("Output filename: %s\n", filename
.c_str());
455 *f
<< stringf("# Generated by %s\n", yosys_version_str
);
456 RTLIL_BACKEND::dump_design(*f
, design
, selected
, true, false);
460 struct IlangBackend
: public Backend
{
461 IlangBackend() : Backend("ilang", "(deprecated) alias of write_rtlil") { }
464 // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
466 log("See `help write_rtlil`.\n");
469 void execute(std::ostream
*&f
, std::string filename
, std::vector
<std::string
> args
, RTLIL::Design
*design
) override
471 RTLILBackend
.execute(f
, filename
, args
, design
);
475 struct DumpPass
: public Pass
{
476 DumpPass() : Pass("dump", "print parts of the design in RTLIL format") { }
479 // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
481 log(" dump [options] [selection]\n");
483 log("Write the selected parts of the design to the console or specified file in\n");
484 log("RTLIL format.\n");
487 log(" also dump the module headers, even if only parts of a single\n");
488 log(" module is selected\n");
491 log(" only dump the module headers if the entire module is selected\n");
493 log(" -o <filename>\n");
494 log(" write to the specified file.\n");
496 log(" -a <filename>\n");
497 log(" like -outfile but append instead of overwrite\n");
500 void execute(std::vector
<std::string
> args
, RTLIL::Design
*design
) override
502 std::string filename
;
503 bool flag_m
= false, flag_n
= false, append
= false;
506 for (argidx
= 1; argidx
< args
.size(); argidx
++)
508 std::string arg
= args
[argidx
];
509 if ((arg
== "-o" || arg
== "-outfile") && argidx
+1 < args
.size()) {
510 filename
= args
[++argidx
];
514 if ((arg
== "-a" || arg
== "-append") && argidx
+1 < args
.size()) {
515 filename
= args
[++argidx
];
529 extra_args(args
, argidx
, design
);
532 std::stringstream buf
;
534 if (!filename
.empty()) {
535 rewrite_filename(filename
);
536 std::ofstream
*ff
= new std::ofstream
;
537 ff
->open(filename
.c_str(), append
? std::ofstream::app
: std::ofstream::trunc
);
540 log_error("Can't open file `%s' for writing: %s\n", filename
.c_str(), strerror(errno
));
547 RTLIL_BACKEND::dump_design(*f
, design
, true, flag_m
, flag_n
);
549 if (!filename
.empty()) {
552 log("%s", buf
.str().c_str());
557 PRIVATE_NAMESPACE_END