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 %s ", indent
.c_str(),
164 (it
.second
.flags
& RTLIL::CONST_FLAG_SIGNED
) != 0 ? " signed" : "",
165 (it
.second
.flags
& RTLIL::CONST_FLAG_REAL
) != 0 ? " real" : "",
167 dump_const(f
, it
.second
);
170 for (auto &it
: cell
->connections()) {
171 f
<< stringf("%s connect %s ", indent
.c_str(), it
.first
.c_str());
172 dump_sigspec(f
, it
.second
);
175 f
<< stringf("%s" "end\n", indent
.c_str());
178 void ILANG_BACKEND::dump_proc_case_body(std::ostream
&f
, std::string indent
, const RTLIL::CaseRule
*cs
)
180 for (auto it
= cs
->actions
.begin(); it
!= cs
->actions
.end(); ++it
)
182 f
<< stringf("%s" "assign ", indent
.c_str());
183 dump_sigspec(f
, it
->first
);
185 dump_sigspec(f
, it
->second
);
189 for (auto it
= cs
->switches
.begin(); it
!= cs
->switches
.end(); ++it
)
190 dump_proc_switch(f
, indent
, *it
);
193 void ILANG_BACKEND::dump_proc_switch(std::ostream
&f
, std::string indent
, const RTLIL::SwitchRule
*sw
)
195 for (auto it
= sw
->attributes
.begin(); it
!= sw
->attributes
.end(); ++it
) {
196 f
<< stringf("%s" "attribute %s ", indent
.c_str(), it
->first
.c_str());
197 dump_const(f
, it
->second
);
201 f
<< stringf("%s" "switch ", indent
.c_str());
202 dump_sigspec(f
, sw
->signal
);
205 for (auto it
= sw
->cases
.begin(); it
!= sw
->cases
.end(); ++it
)
207 f
<< stringf("%s case ", indent
.c_str());
208 for (size_t i
= 0; i
< (*it
)->compare
.size(); i
++) {
211 dump_sigspec(f
, (*it
)->compare
[i
]);
215 dump_proc_case_body(f
, indent
+ " ", *it
);
218 f
<< stringf("%s" "end\n", indent
.c_str());
221 void ILANG_BACKEND::dump_proc_sync(std::ostream
&f
, std::string indent
, const RTLIL::SyncRule
*sy
)
223 f
<< stringf("%s" "sync ", indent
.c_str());
225 case RTLIL::ST0
: f
<< stringf("low ");
226 if (0) case RTLIL::ST1
: f
<< stringf("high ");
227 if (0) case RTLIL::STp
: f
<< stringf("posedge ");
228 if (0) case RTLIL::STn
: f
<< stringf("negedge ");
229 if (0) case RTLIL::STe
: f
<< stringf("edge ");
230 dump_sigspec(f
, sy
->signal
);
233 case RTLIL::STa
: f
<< stringf("always\n"); break;
234 case RTLIL::STg
: f
<< stringf("global\n"); break;
235 case RTLIL::STi
: f
<< stringf("init\n"); break;
238 for (auto it
= sy
->actions
.begin(); it
!= sy
->actions
.end(); ++it
) {
239 f
<< stringf("%s update ", indent
.c_str());
240 dump_sigspec(f
, it
->first
);
242 dump_sigspec(f
, it
->second
);
247 void ILANG_BACKEND::dump_proc(std::ostream
&f
, std::string indent
, const RTLIL::Process
*proc
)
249 for (auto it
= proc
->attributes
.begin(); it
!= proc
->attributes
.end(); ++it
) {
250 f
<< stringf("%s" "attribute %s ", indent
.c_str(), it
->first
.c_str());
251 dump_const(f
, it
->second
);
254 f
<< stringf("%s" "process %s\n", indent
.c_str(), proc
->name
.c_str());
255 dump_proc_case_body(f
, indent
+ " ", &proc
->root_case
);
256 for (auto it
= proc
->syncs
.begin(); it
!= proc
->syncs
.end(); ++it
)
257 dump_proc_sync(f
, indent
+ " ", *it
);
258 f
<< stringf("%s" "end\n", indent
.c_str());
261 void ILANG_BACKEND::dump_conn(std::ostream
&f
, std::string indent
, const RTLIL::SigSpec
&left
, const RTLIL::SigSpec
&right
)
263 f
<< stringf("%s" "connect ", indent
.c_str());
264 dump_sigspec(f
, left
);
266 dump_sigspec(f
, right
);
270 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
)
272 bool print_header
= flag_m
|| design
->selected_whole_module(module
->name
);
273 bool print_body
= !flag_n
|| !design
->selected_whole_module(module
->name
);
277 for (auto it
= module
->attributes
.begin(); it
!= module
->attributes
.end(); ++it
) {
278 f
<< stringf("%s" "attribute %s ", indent
.c_str(), it
->first
.c_str());
279 dump_const(f
, it
->second
);
283 f
<< stringf("%s" "module %s\n", indent
.c_str(), module
->name
.c_str());
285 if (!module
->avail_parameters
.empty()) {
288 for (auto &p
: module
->avail_parameters
)
289 f
<< stringf("%s" " parameter %s\n", indent
.c_str(), p
.c_str());
295 for (auto it
: module
->wires())
296 if (!only_selected
|| design
->selected(module
, it
)) {
299 dump_wire(f
, indent
+ " ", it
);
302 for (auto it
: module
->memories
)
303 if (!only_selected
|| design
->selected(module
, it
.second
)) {
306 dump_memory(f
, indent
+ " ", it
.second
);
309 for (auto it
: module
->cells())
310 if (!only_selected
|| design
->selected(module
, it
)) {
313 dump_cell(f
, indent
+ " ", it
);
316 for (auto it
: module
->processes
)
317 if (!only_selected
|| design
->selected(module
, it
.second
)) {
320 dump_proc(f
, indent
+ " ", it
.second
);
323 bool first_conn_line
= true;
324 for (auto it
= module
->connections().begin(); it
!= module
->connections().end(); ++it
) {
325 bool show_conn
= !only_selected
;
327 RTLIL::SigSpec sigs
= it
->first
;
328 sigs
.append(it
->second
);
329 for (auto &c
: sigs
.chunks()) {
330 if (c
.wire
== NULL
|| !design
->selected(module
, c
.wire
))
336 if (only_selected
&& first_conn_line
)
338 dump_conn(f
, indent
+ " ", it
->first
, it
->second
);
339 first_conn_line
= false;
345 f
<< stringf("%s" "end\n", indent
.c_str());
348 void ILANG_BACKEND::dump_design(std::ostream
&f
, RTLIL::Design
*design
, bool only_selected
, bool flag_m
, bool flag_n
)
351 int init_autoidx
= autoidx
;
355 int count_selected_mods
= 0;
356 for (auto it
= design
->modules_
.begin(); it
!= design
->modules_
.end(); ++it
) {
357 if (design
->selected_whole_module(it
->first
))
359 if (design
->selected(it
->second
))
360 count_selected_mods
++;
362 if (count_selected_mods
> 1)
366 if (!only_selected
|| flag_m
) {
369 f
<< stringf("autoidx %d\n", autoidx
);
372 for (auto it
= design
->modules_
.begin(); it
!= design
->modules_
.end(); ++it
) {
373 if (!only_selected
|| design
->selected(it
->second
)) {
376 dump_module(f
, "", it
->second
, design
, only_selected
, flag_m
, flag_n
);
380 log_assert(init_autoidx
== autoidx
);
384 PRIVATE_NAMESPACE_BEGIN
386 struct IlangBackend
: public Backend
{
387 IlangBackend() : Backend("ilang", "write design to ilang file") { }
388 void help() YS_OVERRIDE
390 // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
392 log(" write_ilang [filename]\n");
394 log("Write the current design to an 'ilang' file. (ilang is a text representation\n");
395 log("of a design in yosys's internal format.)\n");
398 log(" only write selected parts of the design.\n");
401 void execute(std::ostream
*&f
, std::string filename
, std::vector
<std::string
> args
, RTLIL::Design
*design
) YS_OVERRIDE
403 bool selected
= false;
405 log_header(design
, "Executing ILANG backend.\n");
408 for (argidx
= 1; argidx
< args
.size(); argidx
++) {
409 std::string arg
= args
[argidx
];
410 if (arg
== "-selected") {
416 extra_args(f
, filename
, args
, argidx
);
420 log("Output filename: %s\n", filename
.c_str());
421 *f
<< stringf("# Generated by %s\n", yosys_version_str
);
422 ILANG_BACKEND::dump_design(*f
, design
, selected
, true, false);
426 struct DumpPass
: public Pass
{
427 DumpPass() : Pass("dump", "print parts of the design in ilang format") { }
428 void help() YS_OVERRIDE
430 // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
432 log(" dump [options] [selection]\n");
434 log("Write the selected parts of the design to the console or specified file in\n");
435 log("ilang format.\n");
438 log(" also dump the module headers, even if only parts of a single\n");
439 log(" module is selected\n");
442 log(" only dump the module headers if the entire module is selected\n");
444 log(" -o <filename>\n");
445 log(" write to the specified file.\n");
447 log(" -a <filename>\n");
448 log(" like -outfile but append instead of overwrite\n");
451 void execute(std::vector
<std::string
> args
, RTLIL::Design
*design
) YS_OVERRIDE
453 std::string filename
;
454 bool flag_m
= false, flag_n
= false, append
= false;
457 for (argidx
= 1; argidx
< args
.size(); argidx
++)
459 std::string arg
= args
[argidx
];
460 if ((arg
== "-o" || arg
== "-outfile") && argidx
+1 < args
.size()) {
461 filename
= args
[++argidx
];
465 if ((arg
== "-a" || arg
== "-append") && argidx
+1 < args
.size()) {
466 filename
= args
[++argidx
];
480 extra_args(args
, argidx
, design
);
483 std::stringstream buf
;
485 if (!filename
.empty()) {
486 rewrite_filename(filename
);
487 std::ofstream
*ff
= new std::ofstream
;
488 ff
->open(filename
.c_str(), append
? std::ofstream::app
: std::ofstream::trunc
);
491 log_error("Can't open file `%s' for writing: %s\n", filename
.c_str(), strerror(errno
));
498 ILANG_BACKEND::dump_design(*f
, design
, true, flag_m
, flag_n
);
500 if (!filename
.empty()) {
503 log("%s", buf
.str().c_str());
508 PRIVATE_NAMESPACE_END