1 /*
2 * yosys -- Yosys Open SYnthesis Suite
3 *
4 * Copyright (C) 2012 Claire Xenia Wolf <claire@yosyshq.com>
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 "blifparse.h"
21
22 YOSYS_NAMESPACE_BEGIN
23
read_next_line(char * & buffer,size_t & buffer_size,int & line_count,std::istream & f)24 static bool read_next_line(char *&buffer, size_t &buffer_size, int &line_count, std::istream &f)
25 {
26 string strbuf;
27 int buffer_len = 0;
28 buffer[0] = 0;
29
30 while (1)
31 {
32 buffer_len += strlen(buffer + buffer_len);
33 while (buffer_len > 0 && (buffer[buffer_len-1] == ' ' || buffer[buffer_len-1] == '\t' ||
34 buffer[buffer_len-1] == '\r' || buffer[buffer_len-1] == '\n'))
35 buffer[--buffer_len] = 0;
36
37 if (buffer_size-buffer_len < 4096) {
38 buffer_size *= 2;
39 buffer = (char*)realloc(buffer, buffer_size);
40 }
41
42 if (buffer_len == 0 || buffer[buffer_len-1] == '\\') {
43 if (buffer_len > 0 && buffer[buffer_len-1] == '\\')
44 buffer[--buffer_len] = 0;
45 line_count++;
46 if (!std::getline(f, strbuf))
47 return false;
48 while (buffer_size-buffer_len < strbuf.size()+1) {
49 buffer_size *= 2;
50 buffer = (char*)realloc(buffer, buffer_size);
51 }
52 strcpy(buffer+buffer_len, strbuf.c_str());
53 } else
54 return true;
55 }
56 }
57
wideports_split(std::string name)58 static std::pair<RTLIL::IdString, int> wideports_split(std::string name)
59 {
60 int pos = -1;
61
62 if (name.empty() || name.back() != ']')
63 goto failed;
64
65 for (int i = 0; i+1 < GetSize(name); i++) {
66 if (name[i] == '[')
67 pos = i;
68 else if (name[i] != '-' && (name[i] < '0' || name[i] > '9'))
69 pos = -1;
70 else if (name[i] == '-' && ((i != pos+1) || name[i+1] == ']'))
71 pos = -1;
72 else if (i == pos+2 && name[i] == '0' && name[i-1] == '-')
73 pos = -1;
74 else if (i == pos+1 && name[i] == '0' && name[i+1] != ']')
75 pos = -1;
76 }
77
78 if (pos >= 0)
79 return std::pair<RTLIL::IdString, int>("\\" + name.substr(0, pos), atoi(name.c_str() + pos+1));
80
81 failed:
82 return std::pair<RTLIL::IdString, int>(RTLIL::IdString(), 0);
83 }
84
parse_blif(RTLIL::Design * design,std::istream & f,IdString dff_name,bool run_clean,bool sop_mode,bool wideports)85 void parse_blif(RTLIL::Design *design, std::istream &f, IdString dff_name, bool run_clean, bool sop_mode, bool wideports)
86 {
87 RTLIL::Module *module = nullptr;
88 RTLIL::Const *lutptr = NULL;
89 RTLIL::Cell *sopcell = NULL;
90 RTLIL::Cell *lastcell = nullptr;
91 RTLIL::State lut_default_state = RTLIL::State::Sx;
92 std::string err_reason;
93 int blif_maxnum = 0, sopmode = -1;
94
95 auto blif_wire = [&](const std::string &wire_name) -> Wire*
96 {
97 if (wire_name[0] == '$')
98 {
99 for (int i = 0; i+1 < GetSize(wire_name); i++)
100 {
101 if (wire_name[i] != '$')
102 continue;
103
104 int len = 0;
105 while (i+len+1 < GetSize(wire_name) && '0' <= wire_name[i+len+1] && wire_name[i+len+1] <= '9')
106 len++;
107
108 if (len > 0) {
109 string num_str = wire_name.substr(i+1, len);
110 int num = atoi(num_str.c_str()) & 0x0fffffff;
111 blif_maxnum = std::max(blif_maxnum, num);
112 }
113 }
114 }
115
116 IdString wire_id = RTLIL::escape_id(wire_name);
117 Wire *wire = module->wire(wire_id);
118
119 if (wire == nullptr)
120 wire = module->addWire(wire_id);
121
122 return wire;
123 };
124
125 dict<RTLIL::IdString, RTLIL::Const> *obj_attributes = nullptr;
126 dict<RTLIL::IdString, RTLIL::Const> *obj_parameters = nullptr;
127
128 dict<RTLIL::IdString, std::pair<int, bool>> wideports_cache;
129
130 size_t buffer_size = 4096;
131 char *buffer = (char*)malloc(buffer_size);
132 int line_count = 0;
133
134 while (1)
135 {
136 if (!read_next_line(buffer, buffer_size, line_count, f)) {
137 if (module != nullptr)
138 goto error;
139 free(buffer);
140 return;
141 }
142
143 continue_without_read:
144 if (buffer[0] == '#')
145 continue;
146
147 if (buffer[0] == '.')
148 {
149 if (lutptr) {
150 for (auto &bit : lutptr->bits)
151 if (bit == RTLIL::State::Sx)
152 bit = lut_default_state;
153 lutptr = NULL;
154 lut_default_state = RTLIL::State::Sx;
155 }
156
157 if (sopcell) {
158 sopcell = NULL;
159 sopmode = -1;
160 }
161
162 char *cmd = strtok(buffer, " \t\r\n");
163
164 if (!strcmp(cmd, ".model")) {
165 if (module != nullptr)
166 goto error;
167 module = new RTLIL::Module;
168 lastcell = nullptr;
169 module->name = RTLIL::escape_id(strtok(NULL, " \t\r\n"));
170 obj_attributes = &module->attributes;
171 obj_parameters = nullptr;
172 if (design->module(module->name))
173 log_error("Duplicate definition of module %s in line %d!\n", log_id(module->name), line_count);
174 design->add(module);
175 continue;
176 }
177
178 if (module == nullptr)
179 goto error;
180
181 if (!strcmp(cmd, ".blackbox"))
182 {
183 module->attributes[ID::blackbox] = RTLIL::Const(1);
184 continue;
185 }
186
187 if (!strcmp(cmd, ".end"))
188 {
189 for (auto &wp : wideports_cache)
190 {
191 auto name = wp.first;
192 int width = wp.second.first;
193 bool isinput = wp.second.second;
194
195 RTLIL::Wire *wire = module->addWire(name, width);
196 wire->port_input = isinput;
197 wire->port_output = !isinput;
198
199 for (int i = 0; i < width; i++) {
200 RTLIL::IdString other_name = name.str() + stringf("[%d]", i);
201 RTLIL::Wire *other_wire = module->wire(other_name);
202 if (other_wire) {
203 other_wire->port_input = false;
204 other_wire->port_output = false;
205 if (isinput)
206 module->connect(other_wire, SigSpec(wire, i));
207 else
208 module->connect(SigSpec(wire, i), other_wire);
209 }
210 }
211 }
212
213 module->fixup_ports();
214 wideports_cache.clear();
215
216 if (run_clean)
217 {
218 Const buffer_lut(vector<RTLIL::State>({State::S0, State::S1}));
219 vector<Cell*> remove_cells;
220
221 for (auto cell : module->cells())
222 if (cell->type == ID($lut) && cell->getParam(ID::LUT) == buffer_lut) {
223 module->connect(cell->getPort(ID::Y), cell->getPort(ID::A));
224 remove_cells.push_back(cell);
225 }
226
227 for (auto cell : remove_cells)
228 module->remove(cell);
229
230 Wire *true_wire = module->wire(ID($true));
231 Wire *false_wire = module->wire(ID($false));
232 Wire *undef_wire = module->wire(ID($undef));
233
234 if (true_wire != nullptr)
235 module->rename(true_wire, stringf("$true$%d", ++blif_maxnum));
236
237 if (false_wire != nullptr)
238 module->rename(false_wire, stringf("$false$%d", ++blif_maxnum));
239
240 if (undef_wire != nullptr)
241 module->rename(undef_wire, stringf("$undef$%d", ++blif_maxnum));
242
243 autoidx = std::max(autoidx, blif_maxnum+1);
244 blif_maxnum = 0;
245 }
246
247 module = nullptr;
248 lastcell = nullptr;
249 obj_attributes = nullptr;
250 obj_parameters = nullptr;
251 continue;
252 }
253
254 if (!strcmp(cmd, ".inputs") || !strcmp(cmd, ".outputs"))
255 {
256 char *p;
257 while ((p = strtok(NULL, " \t\r\n")) != NULL)
258 {
259 RTLIL::IdString wire_name(stringf("\\%s", p));
260 RTLIL::Wire *wire = module->wire(wire_name);
261 if (wire == nullptr)
262 wire = module->addWire(wire_name);
263 if (!strcmp(cmd, ".inputs"))
264 wire->port_input = true;
265 else
266 wire->port_output = true;
267
268 if (wideports) {
269 std::pair<RTLIL::IdString, int> wp = wideports_split(p);
270 if (!wp.first.empty() && wp.second >= 0) {
271 wideports_cache[wp.first].first = std::max(wideports_cache[wp.first].first, wp.second + 1);
272 wideports_cache[wp.first].second = !strcmp(cmd, ".inputs");
273 }
274 }
275 }
276 obj_attributes = nullptr;
277 obj_parameters = nullptr;
278 continue;
279 }
280
281 if (!strcmp(cmd, ".cname"))
282 {
283 char *p = strtok(NULL, " \t\r\n");
284 if (p == NULL)
285 goto error;
286
287 if(lastcell == nullptr || module == nullptr)
288 {
289 err_reason = stringf("No primitive object to attach .cname %s.", p);
290 goto error_with_reason;
291 }
292
293 module->rename(lastcell, RTLIL::escape_id(p));
294 continue;
295 }
296
297 if (!strcmp(cmd, ".attr") || !strcmp(cmd, ".param")) {
298 char *n = strtok(NULL, " \t\r\n");
299 char *v = strtok(NULL, "\r\n");
300 IdString id_n = RTLIL::escape_id(n);
301 Const const_v;
302 if (v[0] == '"') {
303 std::string str(v+1);
304 if (str.back() == '"')
305 str.resize(str.size()-1);
306 const_v = Const(str);
307 } else {
308 int n = strlen(v);
309 const_v.bits.resize(n);
310 for (int i = 0; i < n; i++)
311 const_v.bits[i] = v[n-i-1] != '0' ? State::S1 : State::S0;
312 }
313 if (!strcmp(cmd, ".attr")) {
314 if (obj_attributes == nullptr) {
315 err_reason = stringf("No object to attach .attr too.");
316 goto error_with_reason;
317 }
318 (*obj_attributes)[id_n] = const_v;
319 } else {
320 if (obj_parameters == nullptr) {
321 err_reason = stringf("No object to attach .param too.");
322 goto error_with_reason;
323 }
324 (*obj_parameters)[id_n] = const_v;
325 }
326 continue;
327 }
328
329 if (!strcmp(cmd, ".latch"))
330 {
331 char *d = strtok(NULL, " \t\r\n");
332 char *q = strtok(NULL, " \t\r\n");
333 char *edge = strtok(NULL, " \t\r\n");
334 char *clock = strtok(NULL, " \t\r\n");
335 char *init = strtok(NULL, " \t\r\n");
336 RTLIL::Cell *cell = nullptr;
337
338 if (clock == nullptr && edge != nullptr) {
339 init = edge;
340 edge = nullptr;
341 }
342
343 if (init != nullptr && (init[0] == '0' || init[0] == '1'))
344 blif_wire(q)->attributes[ID::init] = Const(init[0] == '1' ? 1 : 0, 1);
345
346 if (clock == nullptr)
347 goto no_latch_clock;
348
349 if (!strcmp(edge, "re"))
350 cell = module->addDff(NEW_ID, blif_wire(clock), blif_wire(d), blif_wire(q));
351 else if (!strcmp(edge, "fe"))
352 cell = module->addDff(NEW_ID, blif_wire(clock), blif_wire(d), blif_wire(q), false);
353 else if (!strcmp(edge, "ah"))
354 cell = module->addDlatch(NEW_ID, blif_wire(clock), blif_wire(d), blif_wire(q));
355 else if (!strcmp(edge, "al"))
356 cell = module->addDlatch(NEW_ID, blif_wire(clock), blif_wire(d), blif_wire(q), false);
357 else {
358 no_latch_clock:
359 if (dff_name.empty()) {
360 cell = module->addFf(NEW_ID, blif_wire(d), blif_wire(q));
361 } else {
362 cell = module->addCell(NEW_ID, dff_name);
363 cell->setPort(ID::D, blif_wire(d));
364 cell->setPort(ID::Q, blif_wire(q));
365 }
366 }
367
368 lastcell = cell;
369 obj_attributes = &cell->attributes;
370 obj_parameters = &cell->parameters;
371 continue;
372 }
373
374 if (!strcmp(cmd, ".gate") || !strcmp(cmd, ".subckt"))
375 {
376 char *p = strtok(NULL, " \t\r\n");
377 if (p == NULL)
378 goto error;
379
380 IdString celltype = RTLIL::escape_id(p);
381 RTLIL::Cell *cell = module->addCell(NEW_ID, celltype);
382 RTLIL::Module *cell_mod = design->module(celltype);
383
384 dict<RTLIL::IdString, dict<int, SigBit>> cell_wideports_cache;
385
386 while ((p = strtok(NULL, " \t\r\n")) != NULL)
387 {
388 char *q = strchr(p, '=');
389 if (q == NULL || !q[0])
390 goto error;
391 *(q++) = 0;
392
393 if (wideports) {
394 std::pair<RTLIL::IdString, int> wp = wideports_split(p);
395 if (wp.first.empty())
396 cell->setPort(RTLIL::escape_id(p), *q ? blif_wire(q) : SigSpec());
397 else
398 cell_wideports_cache[wp.first][wp.second] = blif_wire(q);
399 } else {
400 cell->setPort(RTLIL::escape_id(p), *q ? blif_wire(q) : SigSpec());
401 }
402 }
403
404 for (auto &it : cell_wideports_cache)
405 {
406 int width = 0;
407 int offset = 0;
408 bool upto = false;
409 for (auto &b : it.second)
410 width = std::max(width, b.first + 1);
411
412 if (cell_mod) {
413 Wire *cell_port = cell_mod->wire(it.first);
414 if (cell_port && (cell_port->port_input || cell_port->port_output)) {
415 offset = cell_port->start_offset;
416 upto = cell_port->upto;
417 width = cell_port->width;
418 }
419 }
420
421 SigSpec sig;
422
423 for (int i = 0; i < width; i++) {
424 int idx = offset + (upto ? width - 1 - i: i);
425 if (it.second.count(idx))
426 sig.append(it.second.at(idx));
427 else
428 sig.append(module->addWire(NEW_ID));
429 }
430
431 cell->setPort(it.first, sig);
432 }
433
434 lastcell = cell;
435 obj_attributes = &cell->attributes;
436 obj_parameters = &cell->parameters;
437 continue;
438 }
439
440 obj_attributes = nullptr;
441 obj_parameters = nullptr;
442
443 if (!strcmp(cmd, ".barbuf") || !strcmp(cmd, ".conn"))
444 {
445 char *p = strtok(NULL, " \t\r\n");
446 if (p == NULL)
447 goto error;
448
449 char *q = strtok(NULL, " \t\r\n");
450 if (q == NULL)
451 goto error;
452
453 module->connect(blif_wire(q), blif_wire(p));
454 continue;
455 }
456
457 if (!strcmp(cmd, ".names"))
458 {
459 char *p;
460 RTLIL::SigSpec input_sig, output_sig;
461 while ((p = strtok(NULL, " \t\r\n")) != NULL)
462 input_sig.append(blif_wire(p));
463 output_sig = input_sig.extract(input_sig.size()-1, 1);
464 input_sig = input_sig.extract(0, input_sig.size()-1);
465
466 if (input_sig.size() == 0)
467 {
468 RTLIL::State state = RTLIL::State::Sa;
469 while (1) {
470 if (!read_next_line(buffer, buffer_size, line_count, f))
471 goto error;
472 for (int i = 0; buffer[i]; i++) {
473 if (buffer[i] == ' ' || buffer[i] == '\t')
474 continue;
475 if (i == 0 && buffer[i] == '.')
476 goto finished_parsing_constval;
477 if (buffer[i] == '0') {
478 if (state == RTLIL::State::S1)
479 goto error;
480 state = RTLIL::State::S0;
481 continue;
482 }
483 if (buffer[i] == '1') {
484 if (state == RTLIL::State::S0)
485 goto error;
486 state = RTLIL::State::S1;
487 continue;
488 }
489 goto error;
490 }
491 }
492
493 finished_parsing_constval:
494 if (state == RTLIL::State::Sa)
495 state = RTLIL::State::S0;
496 if (output_sig.as_wire()->name == ID($undef))
497 state = RTLIL::State::Sx;
498 module->connect(RTLIL::SigSig(output_sig, state));
499 goto continue_without_read;
500 }
501
502 if (sop_mode)
503 {
504 sopcell = module->addCell(NEW_ID, ID($sop));
505 sopcell->parameters[ID::WIDTH] = RTLIL::Const(input_sig.size());
506 sopcell->parameters[ID::DEPTH] = 0;
507 sopcell->parameters[ID::TABLE] = RTLIL::Const();
508 sopcell->setPort(ID::A, input_sig);
509 sopcell->setPort(ID::Y, output_sig);
510 sopmode = -1;
511 lastcell = sopcell;
512 }
513 else
514 {
515 RTLIL::Cell *cell = module->addCell(NEW_ID, ID($lut));
516 cell->parameters[ID::WIDTH] = RTLIL::Const(input_sig.size());
517 cell->parameters[ID::LUT] = RTLIL::Const(RTLIL::State::Sx, 1 << input_sig.size());
518 cell->setPort(ID::A, input_sig);
519 cell->setPort(ID::Y, output_sig);
520 lutptr = &cell->parameters.at(ID::LUT);
521 lut_default_state = RTLIL::State::Sx;
522 lastcell = cell;
523 }
524 continue;
525 }
526
527 goto error;
528 }
529
530 if (lutptr == NULL && sopcell == NULL)
531 goto error;
532
533 char *input = strtok(buffer, " \t\r\n");
534 char *output = strtok(NULL, " \t\r\n");
535
536 if (input == NULL || output == NULL || (strcmp(output, "0") && strcmp(output, "1")))
537 goto error;
538
539 int input_len = strlen(input);
540
541 if (sopcell)
542 {
543 log_assert(sopcell->parameters[ID::WIDTH].as_int() == input_len);
544 sopcell->parameters[ID::DEPTH] = sopcell->parameters[ID::DEPTH].as_int() + 1;
545
546 for (int i = 0; i < input_len; i++)
547 switch (input[i]) {
548 case '0':
549 sopcell->parameters[ID::TABLE].bits.push_back(State::S1);
550 sopcell->parameters[ID::TABLE].bits.push_back(State::S0);
551 break;
552 case '1':
553 sopcell->parameters[ID::TABLE].bits.push_back(State::S0);
554 sopcell->parameters[ID::TABLE].bits.push_back(State::S1);
555 break;
556 default:
557 sopcell->parameters[ID::TABLE].bits.push_back(State::S0);
558 sopcell->parameters[ID::TABLE].bits.push_back(State::S0);
559 break;
560 }
561
562 if (sopmode == -1) {
563 sopmode = (*output == '1');
564 if (!sopmode) {
565 SigSpec outnet = sopcell->getPort(ID::Y);
566 SigSpec tempnet = module->addWire(NEW_ID);
567 module->addNotGate(NEW_ID, tempnet, outnet);
568 sopcell->setPort(ID::Y, tempnet);
569 }
570 } else
571 log_assert(sopmode == (*output == '1'));
572 }
573
574 if (lutptr)
575 {
576 if (input_len > 12)
577 goto error;
578
579 for (int i = 0; i < (1 << input_len); i++) {
580 for (int j = 0; j < input_len; j++) {
581 char c1 = input[j];
582 if (c1 != '-') {
583 char c2 = (i & (1 << j)) != 0 ? '1' : '0';
584 if (c1 != c2)
585 goto try_next_value;
586 }
587 }
588 lutptr->bits.at(i) = !strcmp(output, "0") ? RTLIL::State::S0 : RTLIL::State::S1;
589 try_next_value:;
590 }
591
592 lut_default_state = !strcmp(output, "0") ? RTLIL::State::S1 : RTLIL::State::S0;
593 }
594 }
595
596 return;
597
598 error:
599 log_error("Syntax error in line %d!\n", line_count);
600 error_with_reason:
601 log_error("Syntax error in line %d: %s\n", line_count, err_reason.c_str());
602 }
603
604 struct BlifFrontend : public Frontend {
BlifFrontendBlifFrontend605 BlifFrontend() : Frontend("blif", "read BLIF file") { }
helpBlifFrontend606 void help() override
607 {
608 // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
609 log("\n");
610 log(" read_blif [options] [filename]\n");
611 log("\n");
612 log("Load modules from a BLIF file into the current design.\n");
613 log("\n");
614 log(" -sop\n");
615 log(" Create $sop cells instead of $lut cells\n");
616 log("\n");
617 log(" -wideports\n");
618 log(" Merge ports that match the pattern 'name[int]' into a single\n");
619 log(" multi-bit port 'name'.\n");
620 log("\n");
621 }
executeBlifFrontend622 void execute(std::istream *&f, std::string filename, std::vector<std::string> args, RTLIL::Design *design) override
623 {
624 bool sop_mode = false;
625 bool wideports = false;
626
627 log_header(design, "Executing BLIF frontend.\n");
628
629 size_t argidx;
630 for (argidx = 1; argidx < args.size(); argidx++) {
631 std::string arg = args[argidx];
632 if (arg == "-sop") {
633 sop_mode = true;
634 continue;
635 }
636 if (arg == "-wideports") {
637 wideports = true;
638 continue;
639 }
640 break;
641 }
642 extra_args(f, filename, args, argidx);
643
644 parse_blif(design, *f, "", true, sop_mode, wideports);
645 }
646 } BlifFrontend;
647
648 YOSYS_NAMESPACE_END
649
650