2 * yosys -- Yosys Open SYnthesis Suite
4 * Copyright (C) 2012 Clifford Wolf <clifford@clifford.at>
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 for (int i
= offset
+width
-1; i
>= offset
; i
--) {
55 log_assert(i
< (int)data
.bits
.size());
56 switch (data
.bits
[i
]) {
57 case State::S0
: f
<< stringf("0"); break;
58 case State::S1
: f
<< stringf("1"); break;
59 case RTLIL::Sx
: f
<< stringf("x"); break;
60 case RTLIL::Sz
: f
<< stringf("z"); break;
61 case RTLIL::Sa
: f
<< stringf("-"); break;
62 case RTLIL::Sm
: f
<< stringf("m"); break;
67 std::string str
= data
.decode_string();
68 for (size_t i
= 0; i
< str
.size(); i
++) {
71 else if (str
[i
] == '\t')
74 f
<< stringf("\\%03o", str
[i
]);
75 else if (str
[i
] == '"')
77 else if (str
[i
] == '\\')
86 void RTLIL_BACKEND::dump_sigchunk(std::ostream
&f
, const RTLIL::SigChunk
&chunk
, bool autoint
)
88 if (chunk
.wire
== NULL
) {
89 dump_const(f
, chunk
.data
, chunk
.width
, chunk
.offset
, autoint
);
91 if (chunk
.width
== chunk
.wire
->width
&& chunk
.offset
== 0)
92 f
<< stringf("%s", chunk
.wire
->name
.c_str());
93 else if (chunk
.width
== 1)
94 f
<< stringf("%s [%d]", chunk
.wire
->name
.c_str(), chunk
.offset
);
96 f
<< stringf("%s [%d:%d]", chunk
.wire
->name
.c_str(), chunk
.offset
+chunk
.width
-1, chunk
.offset
);
100 void RTLIL_BACKEND::dump_sigspec(std::ostream
&f
, const RTLIL::SigSpec
&sig
, bool autoint
)
102 if (sig
.is_chunk()) {
103 dump_sigchunk(f
, sig
.as_chunk(), autoint
);
106 for (auto it
= sig
.chunks().rbegin(); it
!= sig
.chunks().rend(); ++it
) {
107 dump_sigchunk(f
, *it
, false);
114 void RTLIL_BACKEND::dump_wire(std::ostream
&f
, std::string indent
, const RTLIL::Wire
*wire
)
116 for (auto &it
: wire
->attributes
) {
117 f
<< stringf("%s" "attribute %s ", indent
.c_str(), it
.first
.c_str());
118 dump_const(f
, it
.second
);
121 f
<< stringf("%s" "wire ", indent
.c_str());
122 if (wire
->width
!= 1)
123 f
<< stringf("width %d ", wire
->width
);
125 f
<< stringf("upto ");
126 if (wire
->start_offset
!= 0)
127 f
<< stringf("offset %d ", wire
->start_offset
);
128 if (wire
->port_input
&& !wire
->port_output
)
129 f
<< stringf("input %d ", wire
->port_id
);
130 if (!wire
->port_input
&& wire
->port_output
)
131 f
<< stringf("output %d ", wire
->port_id
);
132 if (wire
->port_input
&& wire
->port_output
)
133 f
<< stringf("inout %d ", wire
->port_id
);
135 f
<< stringf("signed ");
136 f
<< stringf("%s\n", wire
->name
.c_str());
139 void RTLIL_BACKEND::dump_memory(std::ostream
&f
, std::string indent
, const RTLIL::Memory
*memory
)
141 for (auto &it
: memory
->attributes
) {
142 f
<< stringf("%s" "attribute %s ", indent
.c_str(), it
.first
.c_str());
143 dump_const(f
, it
.second
);
146 f
<< stringf("%s" "memory ", indent
.c_str());
147 if (memory
->width
!= 1)
148 f
<< stringf("width %d ", memory
->width
);
149 if (memory
->size
!= 0)
150 f
<< stringf("size %d ", memory
->size
);
151 if (memory
->start_offset
!= 0)
152 f
<< stringf("offset %d ", memory
->start_offset
);
153 f
<< stringf("%s\n", memory
->name
.c_str());
156 void RTLIL_BACKEND::dump_cell(std::ostream
&f
, std::string indent
, const RTLIL::Cell
*cell
)
158 for (auto &it
: cell
->attributes
) {
159 f
<< stringf("%s" "attribute %s ", indent
.c_str(), it
.first
.c_str());
160 dump_const(f
, it
.second
);
163 f
<< stringf("%s" "cell %s %s\n", indent
.c_str(), cell
->type
.c_str(), cell
->name
.c_str());
164 for (auto &it
: cell
->parameters
) {
165 f
<< stringf("%s parameter%s%s %s ", indent
.c_str(),
166 (it
.second
.flags
& RTLIL::CONST_FLAG_SIGNED
) != 0 ? " signed" : "",
167 (it
.second
.flags
& RTLIL::CONST_FLAG_REAL
) != 0 ? " real" : "",
169 dump_const(f
, it
.second
);
172 for (auto &it
: cell
->connections()) {
173 f
<< stringf("%s connect %s ", indent
.c_str(), it
.first
.c_str());
174 dump_sigspec(f
, it
.second
);
177 f
<< stringf("%s" "end\n", indent
.c_str());
180 void RTLIL_BACKEND::dump_proc_case_body(std::ostream
&f
, std::string indent
, const RTLIL::CaseRule
*cs
)
182 for (auto it
= cs
->actions
.begin(); it
!= cs
->actions
.end(); ++it
)
184 f
<< stringf("%s" "assign ", indent
.c_str());
185 dump_sigspec(f
, it
->first
);
187 dump_sigspec(f
, it
->second
);
191 for (auto it
= cs
->switches
.begin(); it
!= cs
->switches
.end(); ++it
)
192 dump_proc_switch(f
, indent
, *it
);
195 void RTLIL_BACKEND::dump_proc_switch(std::ostream
&f
, std::string indent
, const RTLIL::SwitchRule
*sw
)
197 for (auto it
= sw
->attributes
.begin(); it
!= sw
->attributes
.end(); ++it
) {
198 f
<< stringf("%s" "attribute %s ", indent
.c_str(), it
->first
.c_str());
199 dump_const(f
, it
->second
);
203 f
<< stringf("%s" "switch ", indent
.c_str());
204 dump_sigspec(f
, sw
->signal
);
207 for (auto it
= sw
->cases
.begin(); it
!= sw
->cases
.end(); ++it
)
209 for (auto ait
= (*it
)->attributes
.begin(); ait
!= (*it
)->attributes
.end(); ++ait
) {
210 f
<< stringf("%s attribute %s ", indent
.c_str(), ait
->first
.c_str());
211 dump_const(f
, ait
->second
);
214 f
<< stringf("%s case ", indent
.c_str());
215 for (size_t i
= 0; i
< (*it
)->compare
.size(); i
++) {
218 dump_sigspec(f
, (*it
)->compare
[i
]);
222 dump_proc_case_body(f
, indent
+ " ", *it
);
225 f
<< stringf("%s" "end\n", indent
.c_str());
228 void RTLIL_BACKEND::dump_proc_sync(std::ostream
&f
, std::string indent
, const RTLIL::SyncRule
*sy
)
230 f
<< stringf("%s" "sync ", indent
.c_str());
232 case RTLIL::ST0
: f
<< stringf("low ");
233 if (0) case RTLIL::ST1
: f
<< stringf("high ");
234 if (0) case RTLIL::STp
: f
<< stringf("posedge ");
235 if (0) case RTLIL::STn
: f
<< stringf("negedge ");
236 if (0) case RTLIL::STe
: f
<< stringf("edge ");
237 dump_sigspec(f
, sy
->signal
);
240 case RTLIL::STa
: f
<< stringf("always\n"); break;
241 case RTLIL::STg
: f
<< stringf("global\n"); break;
242 case RTLIL::STi
: f
<< stringf("init\n"); break;
245 for (auto it
= sy
->actions
.begin(); it
!= sy
->actions
.end(); ++it
) {
246 f
<< stringf("%s update ", indent
.c_str());
247 dump_sigspec(f
, it
->first
);
249 dump_sigspec(f
, it
->second
);
254 void RTLIL_BACKEND::dump_proc(std::ostream
&f
, std::string indent
, const RTLIL::Process
*proc
)
256 for (auto it
= proc
->attributes
.begin(); it
!= proc
->attributes
.end(); ++it
) {
257 f
<< stringf("%s" "attribute %s ", indent
.c_str(), it
->first
.c_str());
258 dump_const(f
, it
->second
);
261 f
<< stringf("%s" "process %s\n", indent
.c_str(), proc
->name
.c_str());
262 dump_proc_case_body(f
, indent
+ " ", &proc
->root_case
);
263 for (auto it
= proc
->syncs
.begin(); it
!= proc
->syncs
.end(); ++it
)
264 dump_proc_sync(f
, indent
+ " ", *it
);
265 f
<< stringf("%s" "end\n", indent
.c_str());
268 void RTLIL_BACKEND::dump_conn(std::ostream
&f
, std::string indent
, const RTLIL::SigSpec
&left
, const RTLIL::SigSpec
&right
)
270 f
<< stringf("%s" "connect ", indent
.c_str());
271 dump_sigspec(f
, left
);
273 dump_sigspec(f
, right
);
277 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
)
279 bool print_header
= flag_m
|| design
->selected_whole_module(module
->name
);
280 bool print_body
= !flag_n
|| !design
->selected_whole_module(module
->name
);
284 for (auto it
= module
->attributes
.begin(); it
!= module
->attributes
.end(); ++it
) {
285 f
<< stringf("%s" "attribute %s ", indent
.c_str(), it
->first
.c_str());
286 dump_const(f
, it
->second
);
290 f
<< stringf("%s" "module %s\n", indent
.c_str(), module
->name
.c_str());
292 if (!module
->avail_parameters
.empty()) {
295 for (const auto &p
: module
->avail_parameters
) {
296 const auto &it
= module
->parameter_default_values
.find(p
);
297 if (it
== module
->parameter_default_values
.end()) {
298 f
<< stringf("%s" " parameter %s\n", indent
.c_str(), p
.c_str());
300 f
<< stringf("%s" " parameter %s ", indent
.c_str(), p
.c_str());
301 dump_const(f
, it
->second
);
310 for (auto it
: module
->wires())
311 if (!only_selected
|| design
->selected(module
, it
)) {
314 dump_wire(f
, indent
+ " ", it
);
317 for (auto it
: module
->memories
)
318 if (!only_selected
|| design
->selected(module
, it
.second
)) {
321 dump_memory(f
, indent
+ " ", it
.second
);
324 for (auto it
: module
->cells())
325 if (!only_selected
|| design
->selected(module
, it
)) {
328 dump_cell(f
, indent
+ " ", it
);
331 for (auto it
: module
->processes
)
332 if (!only_selected
|| design
->selected(module
, it
.second
)) {
335 dump_proc(f
, indent
+ " ", it
.second
);
338 bool first_conn_line
= true;
339 for (auto it
= module
->connections().begin(); it
!= module
->connections().end(); ++it
) {
340 bool show_conn
= !only_selected
;
342 RTLIL::SigSpec sigs
= it
->first
;
343 sigs
.append(it
->second
);
344 for (auto &c
: sigs
.chunks()) {
345 if (c
.wire
== NULL
|| !design
->selected(module
, c
.wire
))
351 if (only_selected
&& first_conn_line
)
353 dump_conn(f
, indent
+ " ", it
->first
, it
->second
);
354 first_conn_line
= false;
360 f
<< stringf("%s" "end\n", indent
.c_str());
363 void RTLIL_BACKEND::dump_design(std::ostream
&f
, RTLIL::Design
*design
, bool only_selected
, bool flag_m
, bool flag_n
)
365 int init_autoidx
= autoidx
;
368 int count_selected_mods
= 0;
369 for (auto module
: design
->modules()) {
370 if (design
->selected_whole_module(module
->name
))
372 if (design
->selected(module
))
373 count_selected_mods
++;
375 if (count_selected_mods
> 1)
379 if (!only_selected
|| flag_m
) {
382 f
<< stringf("autoidx %d\n", autoidx
);
385 for (auto module
: design
->modules()) {
386 if (!only_selected
|| design
->selected(module
)) {
389 dump_module(f
, "", module
, design
, only_selected
, flag_m
, flag_n
);
393 log_assert(init_autoidx
== autoidx
);
397 PRIVATE_NAMESPACE_BEGIN
399 struct RTLILBackend
: public Backend
{
400 RTLILBackend() : Backend("rtlil", "write design to RTLIL file") { }
403 // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
405 log(" write_rtlil [filename]\n");
407 log("Write the current design to an RTLIL file. (RTLIL is a text representation\n");
408 log("of a design in yosys's internal format.)\n");
411 log(" only write selected parts of the design.\n");
414 void execute(std::ostream
*&f
, std::string filename
, std::vector
<std::string
> args
, RTLIL::Design
*design
) override
416 bool selected
= false;
418 log_header(design
, "Executing RTLIL backend.\n");
421 for (argidx
= 1; argidx
< args
.size(); argidx
++) {
422 std::string arg
= args
[argidx
];
423 if (arg
== "-selected") {
429 extra_args(f
, filename
, args
, argidx
);
433 log("Output filename: %s\n", filename
.c_str());
434 *f
<< stringf("# Generated by %s\n", yosys_version_str
);
435 RTLIL_BACKEND::dump_design(*f
, design
, selected
, true, false);
439 struct IlangBackend
: public Backend
{
440 IlangBackend() : Backend("ilang", "(deprecated) alias of write_rtlil") { }
443 // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
445 log("See `help write_rtlil`.\n");
448 void execute(std::ostream
*&f
, std::string filename
, std::vector
<std::string
> args
, RTLIL::Design
*design
) override
450 RTLILBackend
.execute(f
, filename
, args
, design
);
454 struct DumpPass
: public Pass
{
455 DumpPass() : Pass("dump", "print parts of the design in RTLIL format") { }
458 // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
460 log(" dump [options] [selection]\n");
462 log("Write the selected parts of the design to the console or specified file in\n");
463 log("RTLIL format.\n");
466 log(" also dump the module headers, even if only parts of a single\n");
467 log(" module is selected\n");
470 log(" only dump the module headers if the entire module is selected\n");
472 log(" -o <filename>\n");
473 log(" write to the specified file.\n");
475 log(" -a <filename>\n");
476 log(" like -outfile but append instead of overwrite\n");
479 void execute(std::vector
<std::string
> args
, RTLIL::Design
*design
) override
481 std::string filename
;
482 bool flag_m
= false, flag_n
= false, append
= false;
485 for (argidx
= 1; argidx
< args
.size(); argidx
++)
487 std::string arg
= args
[argidx
];
488 if ((arg
== "-o" || arg
== "-outfile") && argidx
+1 < args
.size()) {
489 filename
= args
[++argidx
];
493 if ((arg
== "-a" || arg
== "-append") && argidx
+1 < args
.size()) {
494 filename
= args
[++argidx
];
508 extra_args(args
, argidx
, design
);
511 std::stringstream buf
;
513 if (!filename
.empty()) {
514 rewrite_filename(filename
);
515 std::ofstream
*ff
= new std::ofstream
;
516 ff
->open(filename
.c_str(), append
? std::ofstream::app
: std::ofstream::trunc
);
519 log_error("Can't open file `%s' for writing: %s\n", filename
.c_str(), strerror(errno
));
526 RTLIL_BACKEND::dump_design(*f
, design
, true, flag_m
, flag_n
);
528 if (!filename
.empty()) {
531 log("%s", buf
.str().c_str());
536 PRIVATE_NAMESPACE_END