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