Add upto and offset to JSON ports
[yosys.git] / frontends / liberty / liberty.cc
1 /*
2 * yosys -- Yosys Open SYnthesis Suite
3 *
4 * Copyright (C) 2012 Clifford Wolf <clifford@clifford.at>
5 *
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.
9 *
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.
17 *
18 */
19
20 #include "passes/techmap/libparse.h"
21 #include "kernel/register.h"
22 #include "kernel/log.h"
23
24 YOSYS_NAMESPACE_BEGIN
25
26 struct token_t {
27 char type;
28 RTLIL::SigSpec sig;
29 token_t (char t) : type(t) { }
30 token_t (char t, RTLIL::SigSpec s) : type(t), sig(s) { }
31 };
32
33 static RTLIL::SigSpec parse_func_identifier(RTLIL::Module *module, const char *&expr)
34 {
35 log_assert(*expr != 0);
36
37 int id_len = 0;
38 while (('a' <= expr[id_len] && expr[id_len] <= 'z') || ('A' <= expr[id_len] && expr[id_len] <= 'Z') ||
39 ('0' <= expr[id_len] && expr[id_len] <= '9') || expr[id_len] == '.' ||
40 expr[id_len] == '_' || expr[id_len] == '[' || expr[id_len] == ']') id_len++;
41
42 if (id_len == 0)
43 log_error("Expected identifier at `%s'.\n", expr);
44
45 if (id_len == 1 && (*expr == '0' || *expr == '1'))
46 return *(expr++) == '0' ? RTLIL::State::S0 : RTLIL::State::S1;
47
48 std::string id = RTLIL::escape_id(std::string(expr, id_len));
49 if (!module->wires_.count(id))
50 log_error("Can't resolve wire name %s.\n", RTLIL::unescape_id(id).c_str());
51
52 expr += id_len;
53 return module->wires_.at(id);
54 }
55
56 static RTLIL::SigSpec create_inv_cell(RTLIL::Module *module, RTLIL::SigSpec A)
57 {
58 RTLIL::Cell *cell = module->addCell(NEW_ID, "$_NOT_");
59 cell->setPort("\\A", A);
60 cell->setPort("\\Y", module->addWire(NEW_ID));
61 return cell->getPort("\\Y");
62 }
63
64 static RTLIL::SigSpec create_xor_cell(RTLIL::Module *module, RTLIL::SigSpec A, RTLIL::SigSpec B)
65 {
66 RTLIL::Cell *cell = module->addCell(NEW_ID, "$_XOR_");
67 cell->setPort("\\A", A);
68 cell->setPort("\\B", B);
69 cell->setPort("\\Y", module->addWire(NEW_ID));
70 return cell->getPort("\\Y");
71 }
72
73 static RTLIL::SigSpec create_and_cell(RTLIL::Module *module, RTLIL::SigSpec A, RTLIL::SigSpec B)
74 {
75 RTLIL::Cell *cell = module->addCell(NEW_ID, "$_AND_");
76 cell->setPort("\\A", A);
77 cell->setPort("\\B", B);
78 cell->setPort("\\Y", module->addWire(NEW_ID));
79 return cell->getPort("\\Y");
80 }
81
82 static RTLIL::SigSpec create_or_cell(RTLIL::Module *module, RTLIL::SigSpec A, RTLIL::SigSpec B)
83 {
84 RTLIL::Cell *cell = module->addCell(NEW_ID, "$_OR_");
85 cell->setPort("\\A", A);
86 cell->setPort("\\B", B);
87 cell->setPort("\\Y", module->addWire(NEW_ID));
88 return cell->getPort("\\Y");
89 }
90
91 static bool parse_func_reduce(RTLIL::Module *module, std::vector<token_t> &stack, token_t next_token)
92 {
93 int top = int(stack.size())-1;
94
95 if (0 <= top-1 && stack[top].type == 0 && stack[top-1].type == '!') {
96 token_t t = token_t(0, create_inv_cell(module, stack[top].sig));
97 stack.pop_back();
98 stack.pop_back();
99 stack.push_back(t);
100 return true;
101 }
102
103 if (0 <= top-1 && stack[top].type == '\'' && stack[top-1].type == 0) {
104 token_t t = token_t(0, create_inv_cell(module, stack[top-1].sig));
105 stack.pop_back();
106 stack.pop_back();
107 stack.push_back(t);
108 return true;
109 }
110
111 if (0 <= top && stack[top].type == 0) {
112 if (next_token.type == '\'')
113 return false;
114 stack[top].type = 1;
115 return true;
116 }
117
118 if (0 <= top-2 && stack[top-2].type == 1 && stack[top-1].type == '^' && stack[top].type == 1) {
119 token_t t = token_t(1, create_xor_cell(module, stack[top-2].sig, stack[top].sig));
120 stack.pop_back();
121 stack.pop_back();
122 stack.pop_back();
123 stack.push_back(t);
124 return true;
125 }
126
127 if (0 <= top && stack[top].type == 1) {
128 if (next_token.type == '^')
129 return false;
130 stack[top].type = 2;
131 return true;
132 }
133
134 if (0 <= top-1 && stack[top-1].type == 2 && stack[top].type == 2) {
135 token_t t = token_t(2, create_and_cell(module, stack[top-1].sig, stack[top].sig));
136 stack.pop_back();
137 stack.pop_back();
138 stack.push_back(t);
139 return true;
140 }
141
142 if (0 <= top-2 && stack[top-2].type == 2 && (stack[top-1].type == '*' || stack[top-1].type == '&') && stack[top].type == 2) {
143 token_t t = token_t(2, create_and_cell(module, stack[top-2].sig, stack[top].sig));
144 stack.pop_back();
145 stack.pop_back();
146 stack.pop_back();
147 stack.push_back(t);
148 return true;
149 }
150
151 if (0 <= top && stack[top].type == 2) {
152 if (next_token.type == '*' || next_token.type == '&' || next_token.type == 0 || next_token.type == '(' || next_token.type == '!')
153 return false;
154 stack[top].type = 3;
155 return true;
156 }
157
158 if (0 <= top-2 && stack[top-2].type == 3 && (stack[top-1].type == '+' || stack[top-1].type == '|') && stack[top].type == 3) {
159 token_t t = token_t(3, create_or_cell(module, stack[top-2].sig, stack[top].sig));
160 stack.pop_back();
161 stack.pop_back();
162 stack.pop_back();
163 stack.push_back(t);
164 return true;
165 }
166
167 if (0 <= top-2 && stack[top-2].type == '(' && stack[top-1].type == 3 && stack[top].type == ')') {
168 token_t t = token_t(0, stack[top-1].sig);
169 stack.pop_back();
170 stack.pop_back();
171 stack.pop_back();
172 stack.push_back(t);
173 return true;
174 }
175
176 return false;
177 }
178
179 static RTLIL::SigSpec parse_func_expr(RTLIL::Module *module, const char *expr)
180 {
181 const char *orig_expr = expr;
182 std::vector<token_t> stack;
183
184 while (*expr)
185 {
186 if (*expr == ' ' || *expr == '\t' || *expr == '\r' || *expr == '\n' || *expr == '"') {
187 expr++;
188 continue;
189 }
190
191 token_t next_token(0);
192 if (*expr == '(' || *expr == ')' || *expr == '\'' || *expr == '!' || *expr == '^' || *expr == '*' || *expr == '+' || *expr == '|' || *expr == '&')
193 next_token = token_t(*(expr++));
194 else
195 next_token = token_t(0, parse_func_identifier(module, expr));
196
197 while (parse_func_reduce(module, stack, next_token)) {}
198 stack.push_back(next_token);
199 }
200
201 while (parse_func_reduce(module, stack, token_t('.'))) {}
202
203 #if 0
204 for (size_t i = 0; i < stack.size(); i++)
205 if (stack[i].type < 16)
206 log("%3d: %d %s\n", int(i), stack[i].type, log_signal(stack[i].sig));
207 else
208 log("%3d: %c\n", int(i), stack[i].type);
209 #endif
210
211 if (stack.size() != 1 || stack.back().type != 3)
212 log_error("Parser error in function expr `%s'.\n", orig_expr);
213
214 return stack.back().sig;
215 }
216
217 static void create_ff(RTLIL::Module *module, LibertyAst *node)
218 {
219 RTLIL::SigSpec iq_sig(module->addWire(RTLIL::escape_id(node->args.at(0))));
220 RTLIL::SigSpec iqn_sig(module->addWire(RTLIL::escape_id(node->args.at(1))));
221
222 RTLIL::SigSpec clk_sig, data_sig, clear_sig, preset_sig;
223 bool clk_polarity = true, clear_polarity = true, preset_polarity = true;
224
225 for (auto child : node->children) {
226 if (child->id == "clocked_on")
227 clk_sig = parse_func_expr(module, child->value.c_str());
228 if (child->id == "next_state")
229 data_sig = parse_func_expr(module, child->value.c_str());
230 if (child->id == "clear")
231 clear_sig = parse_func_expr(module, child->value.c_str());
232 if (child->id == "preset")
233 preset_sig = parse_func_expr(module, child->value.c_str());
234 }
235
236 if (clk_sig.size() == 0 || data_sig.size() == 0)
237 log_error("FF cell %s has no next_state and/or clocked_on attribute.\n", log_id(module->name));
238
239 for (bool rerun_invert_rollback = true; rerun_invert_rollback;)
240 {
241 rerun_invert_rollback = false;
242
243 for (auto &it : module->cells_) {
244 if (it.second->type == "$_NOT_" && it.second->getPort("\\Y") == clk_sig) {
245 clk_sig = it.second->getPort("\\A");
246 clk_polarity = !clk_polarity;
247 rerun_invert_rollback = true;
248 }
249 if (it.second->type == "$_NOT_" && it.second->getPort("\\Y") == clear_sig) {
250 clear_sig = it.second->getPort("\\A");
251 clear_polarity = !clear_polarity;
252 rerun_invert_rollback = true;
253 }
254 if (it.second->type == "$_NOT_" && it.second->getPort("\\Y") == preset_sig) {
255 preset_sig = it.second->getPort("\\A");
256 preset_polarity = !preset_polarity;
257 rerun_invert_rollback = true;
258 }
259 }
260 }
261
262 RTLIL::Cell *cell = module->addCell(NEW_ID, "$_NOT_");
263 cell->setPort("\\A", iq_sig);
264 cell->setPort("\\Y", iqn_sig);
265
266 cell = module->addCell(NEW_ID, "");
267 cell->setPort("\\D", data_sig);
268 cell->setPort("\\Q", iq_sig);
269 cell->setPort("\\C", clk_sig);
270
271 if (clear_sig.size() == 0 && preset_sig.size() == 0) {
272 cell->type = stringf("$_DFF_%c_", clk_polarity ? 'P' : 'N');
273 }
274
275 if (clear_sig.size() == 1 && preset_sig.size() == 0) {
276 cell->type = stringf("$_DFF_%c%c0_", clk_polarity ? 'P' : 'N', clear_polarity ? 'P' : 'N');
277 cell->setPort("\\R", clear_sig);
278 }
279
280 if (clear_sig.size() == 0 && preset_sig.size() == 1) {
281 cell->type = stringf("$_DFF_%c%c1_", clk_polarity ? 'P' : 'N', preset_polarity ? 'P' : 'N');
282 cell->setPort("\\R", preset_sig);
283 }
284
285 if (clear_sig.size() == 1 && preset_sig.size() == 1) {
286 cell->type = stringf("$_DFFSR_%c%c%c_", clk_polarity ? 'P' : 'N', preset_polarity ? 'P' : 'N', clear_polarity ? 'P' : 'N');
287 cell->setPort("\\S", preset_sig);
288 cell->setPort("\\R", clear_sig);
289 }
290
291 log_assert(!cell->type.empty());
292 }
293
294 static bool create_latch(RTLIL::Module *module, LibertyAst *node, bool flag_ignore_miss_data_latch)
295 {
296 RTLIL::SigSpec iq_sig(module->addWire(RTLIL::escape_id(node->args.at(0))));
297 RTLIL::SigSpec iqn_sig(module->addWire(RTLIL::escape_id(node->args.at(1))));
298
299 RTLIL::SigSpec enable_sig, data_sig, clear_sig, preset_sig;
300 bool enable_polarity = true, clear_polarity = true, preset_polarity = true;
301
302 for (auto child : node->children) {
303 if (child->id == "enable")
304 enable_sig = parse_func_expr(module, child->value.c_str());
305 if (child->id == "data_in")
306 data_sig = parse_func_expr(module, child->value.c_str());
307 if (child->id == "clear")
308 clear_sig = parse_func_expr(module, child->value.c_str());
309 if (child->id == "preset")
310 preset_sig = parse_func_expr(module, child->value.c_str());
311 }
312
313 if (enable_sig.size() == 0 || data_sig.size() == 0) {
314 if (!flag_ignore_miss_data_latch)
315 log_error("Latch cell %s has no data_in and/or enable attribute.\n", log_id(module->name));
316 else
317 log("Ignored latch cell %s with no data_in and/or enable attribute.\n", log_id(module->name));
318
319 return false;
320 }
321
322 for (bool rerun_invert_rollback = true; rerun_invert_rollback;)
323 {
324 rerun_invert_rollback = false;
325
326 for (auto &it : module->cells_) {
327 if (it.second->type == "$_NOT_" && it.second->getPort("\\Y") == enable_sig) {
328 enable_sig = it.second->getPort("\\A");
329 enable_polarity = !enable_polarity;
330 rerun_invert_rollback = true;
331 }
332 if (it.second->type == "$_NOT_" && it.second->getPort("\\Y") == clear_sig) {
333 clear_sig = it.second->getPort("\\A");
334 clear_polarity = !clear_polarity;
335 rerun_invert_rollback = true;
336 }
337 if (it.second->type == "$_NOT_" && it.second->getPort("\\Y") == preset_sig) {
338 preset_sig = it.second->getPort("\\A");
339 preset_polarity = !preset_polarity;
340 rerun_invert_rollback = true;
341 }
342 }
343 }
344
345 RTLIL::Cell *cell = module->addCell(NEW_ID, "$_NOT_");
346 cell->setPort("\\A", iq_sig);
347 cell->setPort("\\Y", iqn_sig);
348
349 if (clear_sig.size() == 1)
350 {
351 RTLIL::SigSpec clear_negative = clear_sig;
352 RTLIL::SigSpec clear_enable = clear_sig;
353
354 if (clear_polarity == true || clear_polarity != enable_polarity)
355 {
356 RTLIL::Cell *inv = module->addCell(NEW_ID, "$_NOT_");
357 inv->setPort("\\A", clear_sig);
358 inv->setPort("\\Y", module->addWire(NEW_ID));
359
360 if (clear_polarity == true)
361 clear_negative = inv->getPort("\\Y");
362 if (clear_polarity != enable_polarity)
363 clear_enable = inv->getPort("\\Y");
364 }
365
366 RTLIL::Cell *data_gate = module->addCell(NEW_ID, "$_AND_");
367 data_gate->setPort("\\A", data_sig);
368 data_gate->setPort("\\B", clear_negative);
369 data_gate->setPort("\\Y", data_sig = module->addWire(NEW_ID));
370
371 RTLIL::Cell *enable_gate = module->addCell(NEW_ID, enable_polarity ? "$_OR_" : "$_AND_");
372 enable_gate->setPort("\\A", enable_sig);
373 enable_gate->setPort("\\B", clear_enable);
374 enable_gate->setPort("\\Y", data_sig = module->addWire(NEW_ID));
375 }
376
377 if (preset_sig.size() == 1)
378 {
379 RTLIL::SigSpec preset_positive = preset_sig;
380 RTLIL::SigSpec preset_enable = preset_sig;
381
382 if (preset_polarity == false || preset_polarity != enable_polarity)
383 {
384 RTLIL::Cell *inv = module->addCell(NEW_ID, "$_NOT_");
385 inv->setPort("\\A", preset_sig);
386 inv->setPort("\\Y", module->addWire(NEW_ID));
387
388 if (preset_polarity == false)
389 preset_positive = inv->getPort("\\Y");
390 if (preset_polarity != enable_polarity)
391 preset_enable = inv->getPort("\\Y");
392 }
393
394 RTLIL::Cell *data_gate = module->addCell(NEW_ID, "$_OR_");
395 data_gate->setPort("\\A", data_sig);
396 data_gate->setPort("\\B", preset_positive);
397 data_gate->setPort("\\Y", data_sig = module->addWire(NEW_ID));
398
399 RTLIL::Cell *enable_gate = module->addCell(NEW_ID, enable_polarity ? "$_OR_" : "$_AND_");
400 enable_gate->setPort("\\A", enable_sig);
401 enable_gate->setPort("\\B", preset_enable);
402 enable_gate->setPort("\\Y", data_sig = module->addWire(NEW_ID));
403 }
404
405 cell = module->addCell(NEW_ID, stringf("$_DLATCH_%c_", enable_polarity ? 'P' : 'N'));
406 cell->setPort("\\D", data_sig);
407 cell->setPort("\\Q", iq_sig);
408 cell->setPort("\\E", enable_sig);
409
410 return true;
411 }
412
413 void parse_type_map(std::map<std::string, std::tuple<int, int, bool>> &type_map, LibertyAst *ast)
414 {
415 for (auto type_node : ast->children)
416 {
417 if (type_node->id != "type" || type_node->args.size() != 1)
418 continue;
419
420 std::string type_name = type_node->args.at(0);
421 int bit_width = -1, bit_from = -1, bit_to = -1;
422 bool upto = false;
423
424 for (auto child : type_node->children)
425 {
426 if (child->id == "base_type" && child->value != "array")
427 goto next_type;
428
429 if (child->id == "data_type" && child->value != "bit")
430 goto next_type;
431
432 if (child->id == "bit_width")
433 bit_width = atoi(child->value.c_str());
434
435 if (child->id == "bit_from")
436 bit_from = atoi(child->value.c_str());
437
438 if (child->id == "bit_to")
439 bit_to = atoi(child->value.c_str());
440
441 if (child->id == "downto" && (child->value == "0" || child->value == "false" || child->value == "FALSE"))
442 upto = true;
443 }
444
445 if (bit_width != (std::max(bit_from, bit_to) - std::min(bit_from, bit_to) + 1))
446 log_error("Incompatible array type '%s': bit_width=%d, bit_from=%d, bit_to=%d.\n",
447 type_name.c_str(), bit_width, bit_from, bit_to);
448
449 type_map[type_name] = std::tuple<int, int, bool>(bit_width, std::min(bit_from, bit_to), upto);
450 next_type:;
451 }
452 }
453
454 struct LibertyFrontend : public Frontend {
455 LibertyFrontend() : Frontend("liberty", "read cells from liberty file") { }
456 void help() YS_OVERRIDE
457 {
458 // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
459 log("\n");
460 log(" read_liberty [filename]\n");
461 log("\n");
462 log("Read cells from liberty file as modules into current design.\n");
463 log("\n");
464 log(" -lib\n");
465 log(" only create empty blackbox modules\n");
466 log("\n");
467 log(" -nooverwrite\n");
468 log(" ignore re-definitions of modules. (the default behavior is to\n");
469 log(" create an error message if the existing module is not a blackbox\n");
470 log(" module, and overwrite the existing module if it is a blackbox module.)\n");
471 log("\n");
472 log(" -overwrite\n");
473 log(" overwrite existing modules with the same name\n");
474 log("\n");
475 log(" -ignore_miss_func\n");
476 log(" ignore cells with missing function specification of outputs\n");
477 log("\n");
478 log(" -ignore_miss_dir\n");
479 log(" ignore cells with a missing or invalid direction\n");
480 log(" specification on a pin\n");
481 log("\n");
482 log(" -ignore_miss_data_latch\n");
483 log(" ignore latches with missing data and/or enable pins\n");
484 log("\n");
485 log(" -setattr <attribute_name>\n");
486 log(" set the specified attribute (to the value 1) on all loaded modules\n");
487 log("\n");
488 }
489 void execute(std::istream *&f, std::string filename, std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
490 {
491 bool flag_lib = false;
492 bool flag_nooverwrite = false;
493 bool flag_overwrite = false;
494 bool flag_ignore_miss_func = false;
495 bool flag_ignore_miss_dir = false;
496 bool flag_ignore_miss_data_latch = false;
497 std::vector<std::string> attributes;
498
499 log_header(design, "Executing Liberty frontend.\n");
500
501 size_t argidx;
502 for (argidx = 1; argidx < args.size(); argidx++) {
503 std::string arg = args[argidx];
504 if (arg == "-lib") {
505 flag_lib = true;
506 continue;
507 }
508 if (arg == "-ignore_redef" || arg == "-nooverwrite") {
509 flag_nooverwrite = true;
510 flag_overwrite = false;
511 continue;
512 }
513 if (arg == "-overwrite") {
514 flag_nooverwrite = false;
515 flag_overwrite = true;
516 continue;
517 }
518 if (arg == "-ignore_miss_func") {
519 flag_ignore_miss_func = true;
520 continue;
521 }
522 if (arg == "-ignore_miss_dir") {
523 flag_ignore_miss_dir = true;
524 continue;
525 }
526 if (arg == "-ignore_miss_data_latch") {
527 flag_ignore_miss_data_latch = true;
528 continue;
529 }
530 if (arg == "-setattr" && argidx+1 < args.size()) {
531 attributes.push_back(RTLIL::escape_id(args[++argidx]));
532 continue;
533 }
534 break;
535 }
536 extra_args(f, filename, args, argidx);
537
538 LibertyParser parser(*f);
539 int cell_count = 0;
540
541 std::map<std::string, std::tuple<int, int, bool>> global_type_map;
542 parse_type_map(global_type_map, parser.ast);
543
544 for (auto cell : parser.ast->children)
545 {
546 if (cell->id != "cell" || cell->args.size() != 1)
547 continue;
548
549 std::string cell_name = RTLIL::escape_id(cell->args.at(0));
550
551 if (design->has(cell_name)) {
552 Module *existing_mod = design->module(cell_name);
553 if (!flag_nooverwrite && !flag_overwrite && !existing_mod->get_bool_attribute("\\blackbox")) {
554 log_error("Re-definition of of cell/module %s!\n", log_id(cell_name));
555 } else if (flag_nooverwrite) {
556 log("Ignoring re-definition of module %s.\n", log_id(cell_name));
557 continue;
558 } else {
559 log("Replacing existing%s module %s.\n", existing_mod->get_bool_attribute("\\blackbox") ? " blackbox" : "", log_id(cell_name));
560 design->remove(existing_mod);
561 }
562 }
563
564 // log("Processing cell type %s.\n", RTLIL::unescape_id(cell_name).c_str());
565
566 std::map<std::string, std::tuple<int, int, bool>> type_map = global_type_map;
567 parse_type_map(type_map, cell);
568
569 RTLIL::Module *module = new RTLIL::Module;
570 module->name = cell_name;
571
572 if (flag_lib)
573 module->set_bool_attribute("\\blackbox");
574
575 for (auto &attr : attributes)
576 module->attributes[attr] = 1;
577
578 for (auto node : cell->children)
579 {
580 if (node->id == "pin" && node->args.size() == 1) {
581 LibertyAst *dir = node->find("direction");
582 if (!dir || (dir->value != "input" && dir->value != "output" && dir->value != "inout" && dir->value != "internal"))
583 {
584 if (!flag_ignore_miss_dir)
585 {
586 log_error("Missing or invalid direction for pin %s on cell %s.\n", node->args.at(0).c_str(), log_id(module->name));
587 } else {
588 log("Ignoring cell %s with missing or invalid direction for pin %s.\n", log_id(module->name), node->args.at(0).c_str());
589 delete module;
590 goto skip_cell;
591 }
592 }
593 if (!flag_lib || dir->value != "internal")
594 module->addWire(RTLIL::escape_id(node->args.at(0)));
595 }
596
597 if (node->id == "bus" && node->args.size() == 1)
598 {
599 if (!flag_lib)
600 log_error("Error in cell %s: bus interfaces are only supported in -lib mode.\n", log_id(cell_name));
601
602 LibertyAst *dir = node->find("direction");
603
604 if (dir == nullptr) {
605 LibertyAst *pin = node->find("pin");
606 if (pin != nullptr)
607 dir = pin->find("direction");
608 }
609
610 if (!dir || (dir->value != "input" && dir->value != "output" && dir->value != "inout" && dir->value != "internal"))
611 log_error("Missing or invalid direction for bus %s on cell %s.\n", node->args.at(0).c_str(), log_id(module->name));
612
613 if (dir->value == "internal")
614 continue;
615
616 LibertyAst *bus_type_node = node->find("bus_type");
617
618 if (!bus_type_node || !type_map.count(bus_type_node->value))
619 log_error("Unknown or unsupported type for bus interface %s on cell %s.\n",
620 node->args.at(0).c_str(), log_id(cell_name));
621
622 int bus_type_width = std::get<0>(type_map.at(bus_type_node->value));
623 int bus_type_offset = std::get<1>(type_map.at(bus_type_node->value));
624 bool bus_type_upto = std::get<2>(type_map.at(bus_type_node->value));
625
626 Wire *wire = module->addWire(RTLIL::escape_id(node->args.at(0)), bus_type_width);
627 wire->start_offset = bus_type_offset;
628 wire->upto = bus_type_upto;
629
630 if (dir->value == "input" || dir->value == "inout")
631 wire->port_input = true;
632
633 if (dir->value == "output" || dir->value == "inout")
634 wire->port_output = true;
635 }
636 }
637
638 if (!flag_lib)
639 {
640 // some liberty files do not put ff/latch at the beginning of a cell
641 // try to find "ff" or "latch" and create FF/latch _before_ processing all other nodes
642 for (auto node : cell->children)
643 {
644 if (node->id == "ff" && node->args.size() == 2)
645 create_ff(module, node);
646 if (node->id == "latch" && node->args.size() == 2)
647 if (!create_latch(module, node, flag_ignore_miss_data_latch)) {
648 delete module;
649 goto skip_cell;
650 }
651 }
652 }
653
654 for (auto node : cell->children)
655 {
656 if (node->id == "pin" && node->args.size() == 1)
657 {
658 LibertyAst *dir = node->find("direction");
659
660 if (flag_lib && dir->value == "internal")
661 continue;
662
663 RTLIL::Wire *wire = module->wires_.at(RTLIL::escape_id(node->args.at(0)));
664
665 if (dir && dir->value == "inout") {
666 wire->port_input = true;
667 wire->port_output = true;
668 }
669
670 if (dir && dir->value == "input") {
671 wire->port_input = true;
672 continue;
673 }
674
675 if (dir && dir->value == "output")
676 wire->port_output = true;
677
678 if (flag_lib)
679 continue;
680
681 LibertyAst *func = node->find("function");
682 if (func == NULL)
683 {
684 if (!flag_ignore_miss_func)
685 {
686 log_error("Missing function on output %s of cell %s.\n", log_id(wire->name), log_id(module->name));
687 } else {
688 log("Ignoring cell %s with missing function on output %s.\n", log_id(module->name), log_id(wire->name));
689 delete module;
690 goto skip_cell;
691 }
692 }
693
694 RTLIL::SigSpec out_sig = parse_func_expr(module, func->value.c_str());
695 module->connect(RTLIL::SigSig(wire, out_sig));
696 }
697 }
698
699 module->fixup_ports();
700 design->add(module);
701 cell_count++;
702 skip_cell:;
703 }
704
705 log("Imported %d cell types from liberty file.\n", cell_count);
706 }
707 } LibertyFrontend;
708
709 YOSYS_NAMESPACE_END
710