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
21 * representation (as understood by the 'ilang' frontend).
25 #include "ilang_backend.h"
26 #include "kernel/yosys.h"
30 using namespace ILANG_BACKEND
;
33 void ILANG_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 RTLIL::S0
: break;
44 case RTLIL::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 RTLIL::S0
: f
<< stringf("0"); break;
58 case RTLIL::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 ILANG_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 ILANG_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 ILANG_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
);
134 f
<< stringf("%s\n", wire
->name
.c_str());
137 void ILANG_BACKEND::dump_memory(std::ostream
&f
, std::string indent
, const RTLIL::Memory
*memory
)
139 for (auto &it
: memory
->attributes
) {
140 f
<< stringf("%s" "attribute %s ", indent
.c_str(), it
.first
.c_str());
141 dump_const(f
, it
.second
);
144 f
<< stringf("%s" "memory ", indent
.c_str());
145 if (memory
->width
!= 1)
146 f
<< stringf("width %d ", memory
->width
);
147 if (memory
->size
!= 0)
148 f
<< stringf("size %d ", memory
->size
);
149 if (memory
->start_offset
!= 0)
150 f
<< stringf("offset %d ", memory
->start_offset
);
151 f
<< stringf("%s\n", memory
->name
.c_str());
154 void ILANG_BACKEND::dump_cell(std::ostream
&f
, std::string indent
, const RTLIL::Cell
*cell
)
156 for (auto &it
: cell
->attributes
) {
157 f
<< stringf("%s" "attribute %s ", indent
.c_str(), it
.first
.c_str());
158 dump_const(f
, it
.second
);
161 f
<< stringf("%s" "cell %s %s\n", indent
.c_str(), cell
->type
.c_str(), cell
->name
.c_str());
162 for (auto &it
: cell
->parameters
) {
163 f
<< stringf("%s parameter%s %s ", indent
.c_str(), (it
.second
.flags
& RTLIL::CONST_FLAG_SIGNED
) != 0 ? " signed" : "", it
.first
.c_str());
164 dump_const(f
, it
.second
);
167 for (auto &it
: cell
->connections()) {
168 f
<< stringf("%s connect %s ", indent
.c_str(), it
.first
.c_str());
169 dump_sigspec(f
, it
.second
);
172 f
<< stringf("%s" "end\n", indent
.c_str());
175 void ILANG_BACKEND::dump_proc_case_body(std::ostream
&f
, std::string indent
, const RTLIL::CaseRule
*cs
)
177 for (auto it
= cs
->actions
.begin(); it
!= cs
->actions
.end(); ++it
)
179 f
<< stringf("%s" "assign ", indent
.c_str());
180 dump_sigspec(f
, it
->first
);
182 dump_sigspec(f
, it
->second
);
186 for (auto it
= cs
->switches
.begin(); it
!= cs
->switches
.end(); ++it
)
187 dump_proc_switch(f
, indent
, *it
);
190 void ILANG_BACKEND::dump_proc_switch(std::ostream
&f
, std::string indent
, const RTLIL::SwitchRule
*sw
)
192 for (auto it
= sw
->attributes
.begin(); it
!= sw
->attributes
.end(); ++it
) {
193 f
<< stringf("%s" "attribute %s ", indent
.c_str(), it
->first
.c_str());
194 dump_const(f
, it
->second
);
198 f
<< stringf("%s" "switch ", indent
.c_str());
199 dump_sigspec(f
, sw
->signal
);
202 for (auto it
= sw
->cases
.begin(); it
!= sw
->cases
.end(); ++it
)
204 f
<< stringf("%s case ", indent
.c_str());
205 for (size_t i
= 0; i
< (*it
)->compare
.size(); i
++) {
208 dump_sigspec(f
, (*it
)->compare
[i
]);
212 dump_proc_case_body(f
, indent
+ " ", *it
);
215 f
<< stringf("%s" "end\n", indent
.c_str());
218 void ILANG_BACKEND::dump_proc_sync(std::ostream
&f
, std::string indent
, const RTLIL::SyncRule
*sy
)
220 f
<< stringf("%s" "sync ", indent
.c_str());
222 case RTLIL::ST0
: f
<< stringf("low ");
223 if (0) case RTLIL::ST1
: f
<< stringf("high ");
224 if (0) case RTLIL::STp
: f
<< stringf("posedge ");
225 if (0) case RTLIL::STn
: f
<< stringf("negedge ");
226 if (0) case RTLIL::STe
: f
<< stringf("edge ");
227 dump_sigspec(f
, sy
->signal
);
230 case RTLIL::STa
: f
<< stringf("always\n"); break;
231 case RTLIL::STg
: f
<< stringf("global\n"); break;
232 case RTLIL::STi
: f
<< stringf("init\n"); break;
235 for (auto it
= sy
->actions
.begin(); it
!= sy
->actions
.end(); ++it
) {
236 f
<< stringf("%s update ", indent
.c_str());
237 dump_sigspec(f
, it
->first
);
239 dump_sigspec(f
, it
->second
);
244 void ILANG_BACKEND::dump_proc(std::ostream
&f
, std::string indent
, const RTLIL::Process
*proc
)
246 for (auto it
= proc
->attributes
.begin(); it
!= proc
->attributes
.end(); ++it
) {
247 f
<< stringf("%s" "attribute %s ", indent
.c_str(), it
->first
.c_str());
248 dump_const(f
, it
->second
);
251 f
<< stringf("%s" "process %s\n", indent
.c_str(), proc
->name
.c_str());
252 dump_proc_case_body(f
, indent
+ " ", &proc
->root_case
);
253 for (auto it
= proc
->syncs
.begin(); it
!= proc
->syncs
.end(); ++it
)
254 dump_proc_sync(f
, indent
+ " ", *it
);
255 f
<< stringf("%s" "end\n", indent
.c_str());
258 void ILANG_BACKEND::dump_conn(std::ostream
&f
, std::string indent
, const RTLIL::SigSpec
&left
, const RTLIL::SigSpec
&right
)
260 f
<< stringf("%s" "connect ", indent
.c_str());
261 dump_sigspec(f
, left
);
263 dump_sigspec(f
, right
);
267 void ILANG_BACKEND::dump_module(std::ostream
&f
, std::string indent
, RTLIL::Module
*module
, RTLIL::Design
*design
, bool only_selected
, bool flag_m
, bool flag_n
)
269 bool print_header
= flag_m
|| design
->selected_whole_module(module
->name
);
270 bool print_body
= !flag_n
|| !design
->selected_whole_module(module
->name
);
274 for (auto it
= module
->attributes
.begin(); it
!= module
->attributes
.end(); ++it
) {
275 f
<< stringf("%s" "attribute %s ", indent
.c_str(), it
->first
.c_str());
276 dump_const(f
, it
->second
);
280 f
<< stringf("%s" "module %s\n", indent
.c_str(), module
->name
.c_str());
282 if (!module
->avail_parameters
.empty()) {
285 for (auto &p
: module
->avail_parameters
)
286 f
<< stringf("%s" " parameter %s\n", indent
.c_str(), p
.c_str());
292 for (auto it
: module
->wires())
293 if (!only_selected
|| design
->selected(module
, it
)) {
296 dump_wire(f
, indent
+ " ", it
);
299 for (auto it
: module
->memories
)
300 if (!only_selected
|| design
->selected(module
, it
.second
)) {
303 dump_memory(f
, indent
+ " ", it
.second
);
306 for (auto it
: module
->cells())
307 if (!only_selected
|| design
->selected(module
, it
)) {
310 dump_cell(f
, indent
+ " ", it
);
313 for (auto it
: module
->processes
)
314 if (!only_selected
|| design
->selected(module
, it
.second
)) {
317 dump_proc(f
, indent
+ " ", it
.second
);
320 bool first_conn_line
= true;
321 for (auto it
= module
->connections().begin(); it
!= module
->connections().end(); ++it
) {
322 bool show_conn
= !only_selected
;
324 RTLIL::SigSpec sigs
= it
->first
;
325 sigs
.append(it
->second
);
326 for (auto &c
: sigs
.chunks()) {
327 if (c
.wire
== NULL
|| !design
->selected(module
, c
.wire
))
333 if (only_selected
&& first_conn_line
)
335 dump_conn(f
, indent
+ " ", it
->first
, it
->second
);
336 first_conn_line
= false;
342 f
<< stringf("%s" "end\n", indent
.c_str());
345 void ILANG_BACKEND::dump_design(std::ostream
&f
, RTLIL::Design
*design
, bool only_selected
, bool flag_m
, bool flag_n
)
348 int init_autoidx
= autoidx
;
352 int count_selected_mods
= 0;
353 for (auto it
= design
->modules_
.begin(); it
!= design
->modules_
.end(); ++it
) {
354 if (design
->selected_whole_module(it
->first
))
356 if (design
->selected(it
->second
))
357 count_selected_mods
++;
359 if (count_selected_mods
> 1)
363 if (!only_selected
|| flag_m
) {
366 f
<< stringf("autoidx %d\n", autoidx
);
369 for (auto it
= design
->modules_
.begin(); it
!= design
->modules_
.end(); ++it
) {
370 if (!only_selected
|| design
->selected(it
->second
)) {
373 dump_module(f
, "", it
->second
, design
, only_selected
, flag_m
, flag_n
);
377 log_assert(init_autoidx
== autoidx
);
381 PRIVATE_NAMESPACE_BEGIN
383 struct IlangBackend
: public Backend
{
384 IlangBackend() : Backend("ilang", "write design to ilang file") { }
385 void help() YS_OVERRIDE
387 // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
389 log(" write_ilang [filename]\n");
391 log("Write the current design to an 'ilang' file. (ilang is a text representation\n");
392 log("of a design in yosys's internal format.)\n");
395 log(" only write selected parts of the design.\n");
398 void execute(std::ostream
*&f
, std::string filename
, std::vector
<std::string
> args
, RTLIL::Design
*design
) YS_OVERRIDE
400 bool selected
= false;
402 log_header(design
, "Executing ILANG backend.\n");
405 for (argidx
= 1; argidx
< args
.size(); argidx
++) {
406 std::string arg
= args
[argidx
];
407 if (arg
== "-selected") {
413 extra_args(f
, filename
, args
, argidx
);
417 log("Output filename: %s\n", filename
.c_str());
418 *f
<< stringf("# Generated by %s\n", yosys_version_str
);
419 ILANG_BACKEND::dump_design(*f
, design
, selected
, true, false);
423 struct DumpPass
: public Pass
{
424 DumpPass() : Pass("dump", "print parts of the design in ilang format") { }
425 void help() YS_OVERRIDE
427 // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
429 log(" dump [options] [selection]\n");
431 log("Write the selected parts of the design to the console or specified file in\n");
432 log("ilang format.\n");
435 log(" also dump the module headers, even if only parts of a single\n");
436 log(" module is selected\n");
439 log(" only dump the module headers if the entire module is selected\n");
441 log(" -o <filename>\n");
442 log(" write to the specified file.\n");
444 log(" -a <filename>\n");
445 log(" like -outfile but append instead of overwrite\n");
448 void execute(std::vector
<std::string
> args
, RTLIL::Design
*design
) YS_OVERRIDE
450 std::string filename
;
451 bool flag_m
= false, flag_n
= false, append
= false;
454 for (argidx
= 1; argidx
< args
.size(); argidx
++)
456 std::string arg
= args
[argidx
];
457 if ((arg
== "-o" || arg
== "-outfile") && argidx
+1 < args
.size()) {
458 filename
= args
[++argidx
];
462 if ((arg
== "-a" || arg
== "-append") && argidx
+1 < args
.size()) {
463 filename
= args
[++argidx
];
477 extra_args(args
, argidx
, design
);
480 std::stringstream buf
;
482 if (!filename
.empty()) {
483 std::ofstream
*ff
= new std::ofstream
;
484 ff
->open(filename
.c_str(), append
? std::ofstream::app
: std::ofstream::trunc
);
487 log_error("Can't open file `%s' for writing: %s\n", filename
.c_str(), strerror(errno
));
494 ILANG_BACKEND::dump_design(*f
, design
, true, flag_m
, flag_n
);
496 if (!filename
.empty()) {
499 log("%s", buf
.str().c_str());
504 PRIVATE_NAMESPACE_END