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 // [[CITE]] EDIF Version 2 0 0 Grammar
21 // http://web.archive.org/web/20050730021644/http://www.edif.org/documentation/BNF_GRAMMAR/index.html
23 #include "kernel/rtlil.h"
24 #include "kernel/register.h"
25 #include "kernel/sigtools.h"
26 #include "kernel/celltypes.h"
27 #include "kernel/log.h"
31 #define EDIF_DEF(_id) edif_names(RTLIL::unescape_id(_id), true).c_str()
32 #define EDIF_REF(_id) edif_names(RTLIL::unescape_id(_id), false).c_str()
39 std::set
<std::string
> generated_names
, used_names
;
40 std::map
<std::string
, std::string
> name_map
;
42 EdifNames() : counter(1) { }
44 std::string
operator()(std::string id
, bool define
)
47 std::string new_id
= operator()(id
, false);
48 return new_id
!= id
? stringf("(rename %s \"%s\")", new_id
.c_str(), id
.c_str()) : id
;
51 if (name_map
.count(id
) > 0)
52 return name_map
.at(id
);
53 if (generated_names
.count(id
) > 0)
55 if (id
== "GND" || id
== "VCC")
58 for (size_t i
= 0; i
< id
.size(); i
++) {
59 if ('A' <= id
[i
] && id
[i
] <= 'Z')
61 if ('a' <= id
[i
] && id
[i
] <= 'z')
63 if ('0' <= id
[i
] && id
[i
] <= '9' && i
> 0)
65 if (id
[i
] == '_' && i
> 0 && i
!= id
.size()-1)
70 used_names
.insert(id
);
76 gen_name
= stringf("id%05d", counter
++);
77 if (generated_names
.count(gen_name
) == 0 &&
78 used_names
.count(gen_name
) == 0)
81 generated_names
.insert(gen_name
);
82 name_map
[id
] = gen_name
;
88 struct EdifBackend
: public Backend
{
89 EdifBackend() : Backend("edif", "write design to EDIF netlist file") { }
92 // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
94 log(" write_edif [options] [filename]\n");
96 log("Write the current design to an EDIF netlist file.\n");
98 log(" -top top_module\n");
99 log(" set the specified module as design top module\n");
101 log("Unfortunately there are different \"flavors\" of the EDIF file format. This\n");
102 log("command generates EDIF files for the Xilinx place&route tools. It might be\n");
103 log("necessary to make small modifications to this command when a different tool\n");
104 log("is targeted.\n");
107 virtual void execute(FILE *&f
, std::string filename
, std::vector
<std::string
> args
, RTLIL::Design
*design
)
109 log_header("Executing EDIF backend.\n");
111 std::string top_module_name
;
112 std::map
<std::string
, std::set
<std::string
>> lib_cell_ports
;
113 CellTypes
ct(design
);
114 EdifNames edif_names
;
117 for (argidx
= 1; argidx
< args
.size(); argidx
++)
119 if (args
[argidx
] == "-top" && argidx
+1 < args
.size()) {
120 top_module_name
= args
[++argidx
];
125 extra_args(f
, filename
, args
, argidx
);
127 if (top_module_name
.empty())
128 for (auto & mod_it
:design
->modules
)
129 if (mod_it
.second
->get_bool_attribute("\\top"))
130 top_module_name
= mod_it
.first
;
132 for (auto module_it
: design
->modules
)
134 RTLIL::Module
*module
= module_it
.second
;
135 if (module
->get_bool_attribute("\\blackbox"))
138 if (top_module_name
.empty())
139 top_module_name
= module
->name
;
141 if (module
->processes
.size() != 0)
142 log_error("Found unmapped processes in module %s: unmapped processes are not supported in EDIF backend!\n", RTLIL::id2cstr(module
->name
));
143 if (module
->memories
.size() != 0)
144 log_error("Found munmapped emories in module %s: unmapped memories are not supported in EDIF backend!\n", RTLIL::id2cstr(module
->name
));
146 for (auto cell_it
: module
->cells
)
148 RTLIL::Cell
*cell
= cell_it
.second
;
149 if (!design
->modules
.count(cell
->type
) || design
->modules
.at(cell
->type
)->get_bool_attribute("\\blackbox")) {
150 lib_cell_ports
[cell
->type
];
151 for (auto p
: cell
->connections_
) {
152 if (p
.second
.size() > 1)
153 log_error("Found multi-bit port %s on library cell %s.%s (%s): not supported in EDIF backend!\n",
154 RTLIL::id2cstr(p
.first
), RTLIL::id2cstr(module
->name
), RTLIL::id2cstr(cell
->name
), RTLIL::id2cstr(cell
->type
));
155 lib_cell_ports
[cell
->type
].insert(p
.first
);
161 if (top_module_name
.empty())
162 log_error("No module found in design!\n");
164 fprintf(f
, "(edif %s\n", EDIF_DEF(top_module_name
));
165 fprintf(f
, " (edifVersion 2 0 0)\n");
166 fprintf(f
, " (edifLevel 0)\n");
167 fprintf(f
, " (keywordMap (keywordLevel 0))\n");
168 fprintf(f
, " (comment \"Generated by %s\")\n", yosys_version_str
);
170 fprintf(f
, " (external LIB\n");
171 fprintf(f
, " (edifLevel 0)\n");
172 fprintf(f
, " (technology (numberDefinition))\n");
174 fprintf(f
, " (cell GND\n");
175 fprintf(f
, " (cellType GENERIC)\n");
176 fprintf(f
, " (view VIEW_NETLIST\n");
177 fprintf(f
, " (viewType NETLIST)\n");
178 fprintf(f
, " (interface (port G (direction OUTPUT)))\n");
182 fprintf(f
, " (cell VCC\n");
183 fprintf(f
, " (cellType GENERIC)\n");
184 fprintf(f
, " (view VIEW_NETLIST\n");
185 fprintf(f
, " (viewType NETLIST)\n");
186 fprintf(f
, " (interface (port P (direction OUTPUT)))\n");
190 for (auto &cell_it
: lib_cell_ports
) {
191 fprintf(f
, " (cell %s\n", EDIF_DEF(cell_it
.first
));
192 fprintf(f
, " (cellType GENERIC)\n");
193 fprintf(f
, " (view VIEW_NETLIST\n");
194 fprintf(f
, " (viewType NETLIST)\n");
195 fprintf(f
, " (interface\n");
196 for (auto &port_it
: cell_it
.second
) {
197 const char *dir
= "INOUT";
198 if (ct
.cell_known(cell_it
.first
)) {
199 if (!ct
.cell_output(cell_it
.first
, port_it
))
201 else if (!ct
.cell_input(cell_it
.first
, port_it
))
204 fprintf(f
, " (port %s (direction %s))\n", EDIF_DEF(port_it
), dir
);
212 std::vector
<RTLIL::Module
*> sorted_modules
;
214 // extract module dependencies
215 std::map
<RTLIL::Module
*, std::set
<RTLIL::Module
*>> module_deps
;
216 for (auto &mod_it
: design
->modules
) {
217 module_deps
[mod_it
.second
] = std::set
<RTLIL::Module
*>();
218 for (auto &cell_it
: mod_it
.second
->cells
)
219 if (design
->modules
.count(cell_it
.second
->type
) > 0)
220 module_deps
[mod_it
.second
].insert(design
->modules
.at(cell_it
.second
->type
));
223 // simple good-enough topological sort
224 // (O(n*m) on n elements and depth m)
225 while (module_deps
.size() > 0) {
226 size_t sorted_modules_idx
= sorted_modules
.size();
227 for (auto &it
: module_deps
) {
228 for (auto &dep
: it
.second
)
229 if (module_deps
.count(dep
) > 0)
231 // log("Next in topological sort: %s\n", RTLIL::id2cstr(it.first->name));
232 sorted_modules
.push_back(it
.first
);
235 if (sorted_modules_idx
== sorted_modules
.size())
236 log_error("Cyclic dependency between modules found! Cycle includes module %s.\n", RTLIL::id2cstr(module_deps
.begin()->first
->name
));
237 while (sorted_modules_idx
< sorted_modules
.size())
238 module_deps
.erase(sorted_modules
.at(sorted_modules_idx
++));
242 fprintf(f
, " (library DESIGN\n");
243 fprintf(f
, " (edifLevel 0)\n");
244 fprintf(f
, " (technology (numberDefinition))\n");
245 for (auto module
: sorted_modules
)
247 if (module
->get_bool_attribute("\\blackbox"))
250 SigMap
sigmap(module
);
251 std::map
<RTLIL::SigSpec
, std::set
<std::string
>> net_join_db
;
253 fprintf(f
, " (cell %s\n", EDIF_DEF(module
->name
));
254 fprintf(f
, " (cellType GENERIC)\n");
255 fprintf(f
, " (view VIEW_NETLIST\n");
256 fprintf(f
, " (viewType NETLIST)\n");
257 fprintf(f
, " (interface\n");
258 for (auto &wire_it
: module
->wires
) {
259 RTLIL::Wire
*wire
= wire_it
.second
;
260 if (wire
->port_id
== 0)
262 const char *dir
= "INOUT";
263 if (!wire
->port_output
)
265 else if (!wire
->port_input
)
267 if (wire
->width
== 1) {
268 fprintf(f
, " (port %s (direction %s))\n", EDIF_DEF(wire
->name
), dir
);
269 RTLIL::SigSpec sig
= sigmap(RTLIL::SigSpec(wire
));
270 net_join_db
[sig
].insert(stringf("(portRef %s)", EDIF_REF(wire
->name
)));
272 fprintf(f
, " (port (array %s %d) (direction %s))\n", EDIF_DEF(wire
->name
), wire
->width
, dir
);
273 for (int i
= 0; i
< wire
->width
; i
++) {
274 RTLIL::SigSpec sig
= sigmap(RTLIL::SigSpec(wire
, i
));
275 net_join_db
[sig
].insert(stringf("(portRef (member %s %d))", EDIF_REF(wire
->name
), i
));
280 fprintf(f
, " (contents\n");
281 fprintf(f
, " (instance GND (viewRef VIEW_NETLIST (cellRef GND (libraryRef LIB))))\n");
282 fprintf(f
, " (instance VCC (viewRef VIEW_NETLIST (cellRef VCC (libraryRef LIB))))\n");
283 for (auto &cell_it
: module
->cells
) {
284 RTLIL::Cell
*cell
= cell_it
.second
;
285 fprintf(f
, " (instance %s\n", EDIF_DEF(cell
->name
));
286 fprintf(f
, " (viewRef VIEW_NETLIST (cellRef %s%s))", EDIF_REF(cell
->type
),
287 lib_cell_ports
.count(cell
->type
) > 0 ? " (libraryRef LIB)" : "");
288 for (auto &p
: cell
->parameters
)
289 if ((p
.second
.flags
& RTLIL::CONST_FLAG_STRING
) != 0)
290 fprintf(f
, "\n (property %s (string \"%s\"))", EDIF_DEF(p
.first
), p
.second
.decode_string().c_str());
291 else if (p
.second
.bits
.size() <= 32 && RTLIL::SigSpec(p
.second
).is_fully_def())
292 fprintf(f
, "\n (property %s (integer %u))", EDIF_DEF(p
.first
), p
.second
.as_int());
294 std::string hex_string
= "";
295 for (size_t i
= 0; i
< p
.second
.bits
.size(); i
+= 4) {
297 if (i
+0 < p
.second
.bits
.size() && p
.second
.bits
.at(i
+0) == RTLIL::State::S1
) digit_value
|= 1;
298 if (i
+1 < p
.second
.bits
.size() && p
.second
.bits
.at(i
+1) == RTLIL::State::S1
) digit_value
|= 2;
299 if (i
+2 < p
.second
.bits
.size() && p
.second
.bits
.at(i
+2) == RTLIL::State::S1
) digit_value
|= 4;
300 if (i
+3 < p
.second
.bits
.size() && p
.second
.bits
.at(i
+3) == RTLIL::State::S1
) digit_value
|= 8;
301 char digit_str
[2] = { "0123456789abcdef"[digit_value
], 0 };
302 hex_string
= std::string(digit_str
) + hex_string
;
304 fprintf(f
, "\n (property %s (string \"%s\"))", EDIF_DEF(p
.first
), hex_string
.c_str());
307 for (auto &p
: cell
->connections_
) {
308 RTLIL::SigSpec sig
= sigmap(p
.second
);
309 for (int i
= 0; i
< SIZE(sig
); i
++)
311 net_join_db
[sig
[i
]].insert(stringf("(portRef %s (instanceRef %s))", EDIF_REF(p
.first
), EDIF_REF(cell
->name
)));
313 net_join_db
[sig
[i
]].insert(stringf("(portRef (member %s %d) (instanceRef %s))", EDIF_REF(p
.first
), i
, EDIF_REF(cell
->name
)));
316 for (auto &it
: net_join_db
) {
317 RTLIL::SigBit sig
= it
.first
;
318 if (sig
.wire
== NULL
&& sig
!= RTLIL::State::S0
&& sig
!= RTLIL::State::S1
)
320 std::string netname
= log_signal(sig
);
321 for (size_t i
= 0; i
< netname
.size(); i
++)
322 if (netname
[i
] == ' ' || netname
[i
] == '\\')
323 netname
.erase(netname
.begin() + i
--);
324 fprintf(f
, " (net %s (joined\n", EDIF_DEF(netname
));
325 for (auto &ref
: it
.second
)
326 fprintf(f
, " %s\n", ref
.c_str());
327 if (sig
.wire
== NULL
) {
328 if (sig
== RTLIL::State::S0
)
329 fprintf(f
, " (portRef G (instanceRef GND))\n");
330 if (sig
== RTLIL::State::S1
)
331 fprintf(f
, " (portRef P (instanceRef VCC))\n");
341 fprintf(f
, " (design %s\n", EDIF_DEF(top_module_name
));
342 fprintf(f
, " (cellRef %s (libraryRef DESIGN))\n", EDIF_REF(top_module_name
));