diff --git a/frontends/aiger2/xaiger.cc b/frontends/aiger2/xaiger.cc index d2c2aa4b2..b60cd0c88 100644 --- a/frontends/aiger2/xaiger.cc +++ b/frontends/aiger2/xaiger.cc @@ -95,6 +95,8 @@ struct Xaiger2Frontend : public Frontend { outputs.push_back(po); } + std::vector> boxes; + std::vector retained_boxes; std::vector bits(2 + 2*M, RTLIL::Sm); bits[0] = RTLIL::S0; bits[1] = RTLIL::S1; @@ -115,6 +117,34 @@ struct Xaiger2Frontend : public Frontend { log_error("Map file references non-existent signal bit %s[%d]\n", name.c_str(), woffset); bits[lit] = SigBit(w, woffset); + } else if (type == "box") { + int box_seq; + std::string name; + if (!(map_file >> box_seq >> name)) + log_error("Bad map file (20)\n"); + if (box_seq < 0) + log_error("Bad map file (21)\n"); + + Cell *box = module->cell(RTLIL::escape_id(name)); + if (!box) + log_error("Map file references non-existent box %s\n", + name.c_str()); + + Module *def = design->module(box->type); + if (def && !box->parameters.empty()) { + // TODO: This is potentially costly even if a cached derivation exists + def = design->module(def->derive(design, box->parameters)); + log_assert(def); + } + + if (!def) + log_error("Bad map file (22)\n"); + + if (box_seq >= boxes.size()) { + boxes.resize(box_seq + 1); + retained_boxes.resize(box_seq + 1); + } + boxes[box_seq] = std::make_pair(box, def); } else { std::string scratch; std::getline(map_file, scratch); @@ -130,7 +160,73 @@ struct Xaiger2Frontend : public Frontend { log_error("Missing 'c' ahead of extensions\n"); if (f->peek() == '\n') f->get(); + auto extensions_start = f->tellg(); + log_debug("reading 'h' (first pass)\n"); + for (int c = f->get(); c != EOF; c = f->get()) { + if (c == 'h') { + uint32_t len, ci_num, co_num, pi_num, po_num, no_boxes; + len = read_be32(*f); + read_be32(*f); + ci_num = read_be32(*f); + co_num = read_be32(*f); + pi_num = read_be32(*f); + po_num = read_be32(*f); + no_boxes = read_be32(*f); + + log_debug("len=%u ci_num=%u co_num=%u pi_num=%u po_nun=%u no_boxes=%u\n", + len, ci_num, co_num, pi_num, po_num, no_boxes); + + int ci_counter = 0; + for (uint32_t i = 0; i < no_boxes; i++) { + uint32_t box_inputs, box_outputs, box_id, box_seq; + box_inputs = read_be32(*f); + box_outputs = read_be32(*f); + box_id = read_be32(*f); + box_seq = read_be32(*f); + + log("box_seq=%d boxes.size=%d\n", box_seq, boxes.size()); + log_assert(box_seq < boxes.size()); + + auto [cell, def] = boxes[box_seq]; + log_assert(cell && def); + retained_boxes[box_seq] = true; + + int box_ci_idx = 0; + for (auto port_id : def->ports) { + Wire *port = def->wire(port_id); + if (port->port_output) { + if (!cell->hasPort(port_id) || cell->getPort(port_id).size() != port->width) + log_error("Malformed design (1)\n"); + + SigSpec &conn = cell->connections_[port_id]; + for (int j = 0; j < port->width; j++) { + if (conn[j].wire && conn[j].wire->port_output) + conn[j] = module->addWire(module->uniquify( + stringf("$box$%s$%s$%d", + cell->name.isPublic() ? cell->name.c_str() + 1 : cell->name.c_str(), + port_id.isPublic() ? port_id.c_str() + 1 : port_id.c_str(), + j))); + + bits[2*(pi_num + ci_counter + box_ci_idx++) + 2] = conn[j]; + } + } + } + + log_assert(box_ci_idx == box_outputs); + ci_counter += box_ci_idx; + } + log_assert(pi_num + ci_counter == ci_num); + } else if (c == '\n') { + break; + } else { + uint32_t len = read_be32(*f); + f->ignore(len); + log_debug("section '%c' (%d): ignoring %d bytes\n", c, c, len); + } + } + + f->seekg(extensions_start); bool read_mapping = false; uint32_t no_cells, no_instances; for (int c = f->get(); c != EOF; c = f->get()) { @@ -172,10 +268,11 @@ struct Xaiger2Frontend : public Frontend { log_assert(bits[out_lit] == RTLIL::Sm); log_assert(cell_id < cells.size()); auto &cell = cells[cell_id]; - Cell *instance = module->addCell(NEW_ID, cell.type); - auto out_w = module->addWire(NEW_ID); + Cell *instance = module->addCell(module->uniquify(stringf("$sc%d", out_lit)), cell.type); + auto out_w = module->addWire(module->uniquify(stringf("$lit%d", out_lit))); instance->setPort(cell.out, out_w); bits[out_lit] = out_w; + log_debug("setting %d (driven by %s)\n", out_lit, log_id(cell.type)); for (auto in : cell.ins) { uint32_t in_lit = read_be32(*f); log_assert(out_lit < bits.size()); @@ -195,6 +292,74 @@ struct Xaiger2Frontend : public Frontend { if (!read_mapping) log_error("Missing mapping (no 'M' section)\n"); + log("Read %d instances with cell library of size %d.\n", + no_instances, no_cells); + + f->seekg(extensions_start); + log_debug("reading 'h' (second pass)\n"); + int co_counter = 0; + for (int c = f->get(); c != EOF; c = f->get()) { + if (c == 'h') { + uint32_t len, ci_num, co_num, pi_num, po_num, no_boxes; + len = read_be32(*f); + read_be32(*f); + ci_num = read_be32(*f); + co_num = read_be32(*f); + pi_num = read_be32(*f); + po_num = read_be32(*f); + no_boxes = read_be32(*f); + + log_debug("len=%u ci_num=%u co_num=%u pi_num=%u po_nun=%u no_boxes=%u\n", + len, ci_num, co_num, pi_num, po_num, no_boxes); + + for (uint32_t i = 0; i < no_boxes; i++) { + uint32_t box_inputs, box_outputs, box_id, box_seq; + box_inputs = read_be32(*f); + box_outputs = read_be32(*f); + box_id = read_be32(*f); + box_seq = read_be32(*f); + + log("box_seq=%d boxes.size=%d\n", box_seq, boxes.size()); + log_assert(box_seq < boxes.size()); + + auto [cell, def] = boxes[box_seq]; + log_assert(cell && def); + + int box_co_idx = 0; + for (auto port_id : def->ports) { + Wire *port = def->wire(port_id); + SigSpec conn; + if (port->port_input) { + if (!cell->hasPort(port_id) || cell->getPort(port_id).size() != port->width) + log_error("Malformed design (2)\n"); + + SigSpec conn; + for (int j = 0; j < port->width; j++) { + log_assert(co_counter + box_co_idx < outputs.size()); + int lit = outputs[co_counter + box_co_idx++]; + log_assert(lit >= 0 && lit < bits.size()); + SigBit bit = bits[lit]; + if (bit == RTLIL::Sm) + log_error("Malformed mapping (1)\n"); + conn.append(bit); + } + cell->setPort(port_id, conn); + } + } + + log_assert(box_co_idx == box_inputs); + co_counter += box_co_idx; + } + log_assert(po_num + co_counter == co_num); + } else if (c == '\n') { + break; + } else { + uint32_t len = read_be32(*f); + f->ignore(len); + log_debug("section '%c' (%d): ignoring %d bytes\n", c, c, len); + } + } + while (true) { std::string scratch; std::getline(*f, scratch); @@ -204,10 +369,9 @@ struct Xaiger2Frontend : public Frontend { log("input file: %s\n", scratch.c_str()); } - log("Read %d instances with cell library of size %d.\n", - no_instances, no_cells); + log_debug("co_counter=%d\n", co_counter); - // TODO + // TODO: seek without close/open map_file.close(); map_file.open(map_filename); while (map_file >> type) { @@ -217,11 +381,13 @@ struct Xaiger2Frontend : public Frontend { std::string name; if (!(map_file >> po_idx >> woffset >> name)) log_error("Bad map file (3)\n"); + po_idx += co_counter; if (po_idx < 0 || po_idx >= outputs.size()) log_error("Bad map file (4)\n"); int lit = outputs[po_idx]; if (lit < 0 || lit >= bits.size()) log_error("Bad map file (5)\n"); + log("output=%d lit=%d\n", po_idx, lit); if (bits[lit] == RTLIL::Sm) log_error("Bad map file (6)\n"); Wire *w = module->wire(name); @@ -236,6 +402,7 @@ struct Xaiger2Frontend : public Frontend { std::string box_port; if (!(map_file >> po_idx >> poffset >> box_name >> box_port)) log_error("Bad map file (7)\n"); + po_idx += co_counter; if (po_idx < 0 || po_idx >= outputs.size()) log_error("Bad map file (8)\n"); int lit = outputs[po_idx]; @@ -257,6 +424,12 @@ struct Xaiger2Frontend : public Frontend { std::getline(map_file, scratch); } } + + int box_seq = 0; + for (auto [cell, def] : boxes) { + if (!retained_boxes[box_seq++]) + module->remove(cell); + } } void execute(std::istream *&f, std::string filename, std::vector args, Design *design) override