diff options
Diffstat (limited to 'frontends/aiger')
-rw-r--r-- | frontends/aiger/aigerparse.cc | 618 | ||||
-rw-r--r-- | frontends/aiger/aigerparse.h | 1 |
2 files changed, 277 insertions, 342 deletions
diff --git a/frontends/aiger/aigerparse.cc b/frontends/aiger/aigerparse.cc index 904a1079d..69404b19d 100644 --- a/frontends/aiger/aigerparse.cc +++ b/frontends/aiger/aigerparse.cc @@ -57,11 +57,15 @@ void AigerReader::parse_aiger() // Optional values B = C = J = F = 0; - for (auto &i : std::array<std::reference_wrapper<unsigned>,4>{B, C, J, F}) { - if (f.peek() != ' ') break; - if (!(f >> i)) - log_error("Invalid AIGER header\n"); - } + if (f.peek() != ' ') goto end_of_header; + if (!(f >> B)) log_error("Invalid AIGER header\n"); + if (f.peek() != ' ') goto end_of_header; + if (!(f >> C)) log_error("Invalid AIGER header\n"); + if (f.peek() != ' ') goto end_of_header; + if (!(f >> J)) log_error("Invalid AIGER header\n"); + if (f.peek() != ' ') goto end_of_header; + if (!(f >> F)) log_error("Invalid AIGER header\n"); +end_of_header: std::string line; std::getline(f, line); // Ignore up to start of next line, as standard @@ -113,103 +117,7 @@ void AigerReader::parse_aiger() std::getline(f, line); // Ignore up to start of next line } - dict<RTLIL::IdString, int> wideports_cache; - - if (!map_filename.empty()) { - std::ifstream mf(map_filename); - std::string type, symbol; - int variable, index; - while (mf >> type >> variable >> index >> symbol) { - RTLIL::IdString escaped_symbol = RTLIL::escape_id(symbol); - if (type == "input") { - log_assert(static_cast<unsigned>(variable) < inputs.size()); - RTLIL::Wire* wire = inputs[variable]; - log_assert(wire); - log_assert(wire->port_input); - - if (index == 0) - module->rename(wire, RTLIL::escape_id(symbol)); - else if (index > 0) { - module->rename(wire, RTLIL::escape_id(stringf("%s[%d]", symbol.c_str(), index))); - if (wideports) - wideports_cache[escaped_symbol] = std::max(wideports_cache[escaped_symbol], index); - } - } - else if (type == "output") { - log_assert(static_cast<unsigned>(variable) < outputs.size()); - RTLIL::Wire* wire = outputs[variable]; - log_assert(wire); - // Ignore direct output -> input connections - if (!wire->port_output) - continue; - log_assert(wire->port_output); - - if (index == 0) - module->rename(wire, RTLIL::escape_id(symbol)); - else if (index > 0) { - module->rename(wire, RTLIL::escape_id(stringf("%s[%d]", symbol.c_str(), index))); - if (wideports) - wideports_cache[escaped_symbol] = std::max(wideports_cache[escaped_symbol], index); - } - } - else - log_error("Symbol type '%s' not recognised.\n", type.c_str()); - } - } - - for (auto &wp : wideports_cache) { - auto name = wp.first; - int width = wp.second + 1; - - RTLIL::Wire *wire = module->wire(name); - if (wire) - module->rename(wire, RTLIL::escape_id(stringf("%s[%d]", name.c_str(), 0))); - - // Do not make ports with a mix of input/output into - // wide ports - bool port_input = false, port_output = false; - for (int i = 0; i < width; i++) { - RTLIL::IdString other_name = name.str() + stringf("[%d]", i); - RTLIL::Wire *other_wire = module->wire(other_name); - if (other_wire) { - port_input = port_input || other_wire->port_input; - port_output = port_output || other_wire->port_output; - } - } - if ((port_input && port_output) || (!port_input && !port_output)) - continue; - - wire = module->addWire(name, width); - wire->port_input = port_input; - wire->port_output = port_output; - - for (int i = 0; i < width; i++) { - RTLIL::IdString other_name = name.str() + stringf("[%d]", i); - RTLIL::Wire *other_wire = module->wire(other_name); - if (other_wire) { - other_wire->port_input = false; - other_wire->port_output = false; - if (wire->port_input) - module->connect(other_wire, SigSpec(wire, i)); - else - module->connect(SigSpec(wire, i), other_wire); - } - } - } - - module->fixup_ports(); - design->add(module); - - Pass::call(design, "clean"); - - for (auto cell : module->cells().to_vector()) { - if (cell->type != "$lut") continue; - auto y_port = cell->getPort("\\Y").as_bit(); - if (y_port.wire->width == 1) - module->rename(cell, stringf("%s$lut", y_port.wire->name.c_str())); - else - module->rename(cell, stringf("%s[%d]$lut", y_port.wire->name.c_str(), y_port.offset)); - } + post_process(); } static uint32_t parse_xaiger_literal(std::istream &f) @@ -254,29 +162,6 @@ static RTLIL::Wire* createWireIfNotExists(RTLIL::Module *module, unsigned litera return wire; } -static std::pair<RTLIL::IdString, int> wideports_split(std::string name) -{ - int pos = -1; - - if (name.empty() || name.back() != ']') - goto failed; - - for (int i = 0; i+1 < GetSize(name); i++) { - if (name[i] == '[') - pos = i; - else if (name[i] < '0' || name[i] > '9') - pos = -1; - else if (i == pos+1 && name[i] == '0' && name[i+1] != ']') - pos = -1; - } - - if (pos >= 0) - return std::pair<RTLIL::IdString, int>(RTLIL::escape_id(name.substr(0, pos)), atoi(name.c_str() + pos+1)); - -failed: - return std::pair<RTLIL::IdString, int>(name, 0); -} - void AigerReader::parse_xaiger() { std::string header; @@ -307,13 +192,17 @@ void AigerReader::parse_xaiger() else log_abort(); + dict<int,IdString> box_lookup; + for (auto m : design->modules()) { + auto it = m->attributes.find("\\abc_box_id"); + if (it == m->attributes.end()) + continue; + box_lookup[it->second.as_int()] = m->name; + } + // Parse footer (symbol table, comments, etc.) - unsigned l1; std::string s; bool comment_seen = false; - std::vector<std::pair<RTLIL::Wire*,RTLIL::IdString>> deferred_renames; - std::vector<std::pair<RTLIL::Wire*,RTLIL::IdString>> deferred_inouts; - deferred_renames.reserve(inputs.size() + latches.size() + outputs.size()); for (int c = f.peek(); c != EOF; c = f.peek()) { if (comment_seen || c == 'c') { if (!comment_seen) { @@ -383,7 +272,21 @@ void AigerReader::parse_xaiger() f >> s; log_debug("n: '%s'\n", s.c_str()); } - else if (c == 'a' || c == 'i' || c == 'o' || c == 'h') { + else if (c == 'h') { + f.ignore(sizeof(uint32_t)); + uint32_t version = parse_xaiger_literal(f); + log_assert(version == 1); + f.ignore(4*sizeof(uint32_t)); + uint32_t boxNum = parse_xaiger_literal(f); + for (unsigned i = 0; i < boxNum; i++) { + f.ignore(2*sizeof(uint32_t)); + uint32_t boxUniqueId = parse_xaiger_literal(f); + log_assert(boxUniqueId > 0); + uint32_t oldBoxNum = parse_xaiger_literal(f); + module->addCell(stringf("$__box%u__", oldBoxNum), box_lookup.at(boxUniqueId)); + } + } + else if (c == 'a' || c == 'i' || c == 'o') { uint32_t dataSize = parse_xaiger_literal(f); f.ignore(dataSize); } @@ -391,221 +294,11 @@ void AigerReader::parse_xaiger() break; } } - else if (c == 'i' || c == 'l' || c == 'o') { - f.ignore(1); - if (!(f >> l1 >> s)) - log_error("Line %u cannot be interpreted as a symbol entry!\n", line_count); - - if ((c == 'i' && l1 > inputs.size()) || (c == 'l' && l1 > latches.size()) || (c == 'o' && l1 > outputs.size())) - log_error("Line %u has invalid symbol position!\n", line_count); - - RTLIL::Wire* wire; - if (c == 'i') wire = inputs[l1]; - else if (c == 'l') wire = latches[l1]; - else if (c == 'o') wire = outputs[l1]; - else log_abort(); - - RTLIL::IdString escaped_s = RTLIL::escape_id(s); - - if (escaped_s.ends_with("$inout.out")) { - deferred_inouts.emplace_back(wire, escaped_s.substr(0, escaped_s.size()-10)); - goto next_line; - } - else if (wideports && (wire->port_input || wire->port_output)) { - RTLIL::IdString wide_symbol; - int index; - std::tie(wide_symbol,index) = wideports_split(escaped_s.str()); - if (wide_symbol.ends_with("$inout.out")) { - deferred_inouts.emplace_back(wire, stringf("%s[%d]", wide_symbol.substr(0, wide_symbol.size()-10).c_str(), index)); - goto next_line; - } - } - deferred_renames.emplace_back(wire, escaped_s); - -next_line: - std::getline(f, line); // Ignore up to start of next line - ++line_count; - } else log_error("Line %u: cannot interpret first character '%c'!\n", line_count, c); } - dict<RTLIL::IdString, int> wideports_cache; - for (const auto &i : deferred_renames) { - RTLIL::Wire *wire = i.first; - - module->rename(wire, i.second); - - if (wideports && (wire->port_input || wire->port_output)) { - RTLIL::IdString escaped_symbol; - int index; - std::tie(escaped_symbol,index) = wideports_split(wire->name.str()); - if (index > 0) - wideports_cache[escaped_symbol] = std::max(wideports_cache[escaped_symbol], index); - } - } - - for (const auto &i : deferred_inouts) { - RTLIL::Wire *out_wire = i.first; - log_assert(out_wire->port_output); - out_wire->port_output = false; - RTLIL::Wire *wire = module->wire(i.second); - log_assert(wire); - log_assert(wire->port_input && !wire->port_output); - wire->port_output = true; - module->connect(wire, out_wire); - } - - if (!map_filename.empty()) { - std::ifstream mf(map_filename); - std::string type, symbol; - int variable, index; - while (mf >> type >> variable >> index >> symbol) { - RTLIL::IdString escaped_s = RTLIL::escape_id(symbol); - if (type == "input") { - log_assert(static_cast<unsigned>(variable) < inputs.size()); - RTLIL::Wire* wire = inputs[variable]; - log_assert(wire); - log_assert(wire->port_input); - - if (index == 0) { - // Cope with the fact that a CI might be identical - // to a PI (necessary due to ABC); in those cases - // simply connect the latter to the former - RTLIL::Wire* existing = module->wire(escaped_s); - if (!existing) - module->rename(wire, escaped_s); - else { - wire->port_input = false; - module->connect(wire, existing); - } - } - else if (index > 0) { - std::string indexed_name = stringf("%s[%d]", escaped_s.c_str(), index); - RTLIL::Wire* existing = module->wire(indexed_name); - if (!existing) { - module->rename(wire, indexed_name); - if (wideports) - wideports_cache[escaped_s] = std::max(wideports_cache[escaped_s], index); - } - else { - module->connect(wire, existing); - wire->port_input = false; - } - } - } - else if (type == "output") { - log_assert(static_cast<unsigned>(variable) < outputs.size()); - RTLIL::Wire* wire = outputs[variable]; - log_assert(wire); - log_assert(wire->port_output); - if (escaped_s.in("\\__dummy_o__", "\\__const0__", "\\__const1__")) { - wire->port_output = false; - continue; - } - - if (index == 0) { - // Cope with the fact that a CO might be identical - // to a PO (necessary due to ABC); in those cases - // simply connect the latter to the former - RTLIL::Wire* existing = module->wire(escaped_s); - if (!existing) { - if (escaped_s.ends_with("$inout.out")) { - wire->port_output = false; - RTLIL::Wire *in_wire = module->wire(escaped_s.substr(0, escaped_s.size()-10)); - log_assert(in_wire); - log_assert(in_wire->port_input && !in_wire->port_output); - in_wire->port_output = true; - module->connect(in_wire, wire); - } - else - module->rename(wire, escaped_s); - } - else { - wire->port_output = false; - module->connect(wire, existing); - } - } - else if (index > 0) { - std::string indexed_name = stringf("%s[%d]", escaped_s.c_str(), index); - RTLIL::Wire* existing = module->wire(indexed_name); - if (!existing) { - if (escaped_s.ends_with("$inout.out")) { - wire->port_output = false; - RTLIL::Wire *in_wire = module->wire(stringf("%s[%d]", escaped_s.substr(0, escaped_s.size()-10).c_str(), index)); - log_assert(in_wire); - log_assert(in_wire->port_input && !in_wire->port_output); - in_wire->port_output = true; - module->connect(in_wire, wire); - } - else { - module->rename(wire, indexed_name); - if (wideports) - wideports_cache[escaped_s] = std::max(wideports_cache[escaped_s], index); - } - } - else { - module->connect(wire, existing); - wire->port_output = false; - } - } - } - else - log_error("Symbol type '%s' not recognised.\n", type.c_str()); - } - } - - for (auto &wp : wideports_cache) { - auto name = wp.first; - int width = wp.second + 1; - - RTLIL::Wire *wire = module->wire(name); - if (wire) - module->rename(wire, RTLIL::escape_id(stringf("%s[%d]", name.c_str(), 0))); - - // Do not make ports with a mix of input/output into - // wide ports - bool port_input = false, port_output = false; - for (int i = 0; i < width; i++) { - RTLIL::IdString other_name = name.str() + stringf("[%d]", i); - RTLIL::Wire *other_wire = module->wire(other_name); - if (other_wire) { - port_input = port_input || other_wire->port_input; - port_output = port_output || other_wire->port_output; - } - } - if ((port_input && port_output) || (!port_input && !port_output)) - continue; - - wire = module->addWire(name, width); - wire->port_input = port_input; - wire->port_output = port_output; - - for (int i = 0; i < width; i++) { - RTLIL::IdString other_name = name.str() + stringf("[%d]", i); - RTLIL::Wire *other_wire = module->wire(other_name); - if (other_wire) { - other_wire->port_input = false; - other_wire->port_output = false; - if (wire->port_input) - module->connect(other_wire, SigSpec(wire, i)); - else - module->connect(SigSpec(wire, i), other_wire); - } - } - } - - module->fixup_ports(); - design->add(module); - - for (auto cell : module->cells().to_vector()) { - if (cell->type != "$lut") continue; - auto y_port = cell->getPort("\\Y").as_bit(); - if (y_port.wire->width == 1) - module->rename(cell, stringf("%s$lut", y_port.wire->name.c_str())); - else - module->rename(cell, stringf("%s[%d]$lut", y_port.wire->name.c_str(), y_port.offset)); - } + post_process(); } void AigerReader::parse_aiger_ascii() @@ -817,7 +510,7 @@ void AigerReader::parse_aiger_binary() log_debug("%d is an output\n", l1); const unsigned variable = l1 >> 1; const bool invert = l1 & 1; - RTLIL::IdString wire_name(stringf("\\__%d%s__", variable, invert ? "b" : "")); // FIXME: is "_inv" the right suffix? + RTLIL::IdString wire_name(stringf("\\__%d%s__", variable, invert ? "b" : "")); // FIXME: is "_b" the right suffix? wire = module->wire(wire_name); if (!wire) wire = createWireIfNotExists(module, l1); @@ -865,6 +558,247 @@ void AigerReader::parse_aiger_binary() } } +void AigerReader::post_process() +{ + dict<RTLIL::IdString, int> wideports_cache; + + if (!map_filename.empty()) { + std::ifstream mf(map_filename); + std::string type, symbol; + int variable, index; + int pi_count = 0, ci_count = 0, co_count = 0; + pool<RTLIL::Module*> abc_carry_modules; + while (mf >> type >> variable >> index >> symbol) { + RTLIL::IdString escaped_s = RTLIL::escape_id(symbol); + if (type == "input") { + log_assert(static_cast<unsigned>(variable) < inputs.size()); + RTLIL::Wire* wire = inputs[variable]; + log_assert(wire); + log_assert(wire->port_input); + pi_count++; + + if (index == 0) { + // Cope with the fact that a CI might be identical + // to a PI (necessary due to ABC); in those cases + // simply connect the latter to the former + RTLIL::Wire* existing = module->wire(escaped_s); + if (!existing) + module->rename(wire, escaped_s); + else { + wire->port_input = false; + module->connect(wire, existing); + } + } + else if (index > 0) { + std::string indexed_name = stringf("%s[%d]", escaped_s.c_str(), index); + RTLIL::Wire* existing = module->wire(indexed_name); + if (!existing) { + module->rename(wire, indexed_name); + if (wideports) + wideports_cache[escaped_s] = std::max(wideports_cache[escaped_s], index); + } + else { + module->connect(wire, existing); + wire->port_input = false; + } + } + } + else if (type == "output") { + log_assert(static_cast<unsigned>(variable + co_count) < outputs.size()); + RTLIL::Wire* wire = outputs[variable + co_count]; + log_assert(wire); + log_assert(wire->port_output); + if (escaped_s.in("\\__dummy_o__", "\\__const0__", "\\__const1__")) { + wire->port_output = false; + continue; + } + + if (index == 0) { + // Cope with the fact that a CO might be identical + // to a PO (necessary due to ABC); in those cases + // simply connect the latter to the former + RTLIL::Wire* existing = module->wire(escaped_s); + if (!existing) { + if (escaped_s.ends_with("$inout.out")) { + wire->port_output = false; + RTLIL::Wire *in_wire = module->wire(escaped_s.substr(0, escaped_s.size()-10)); + log_assert(in_wire); + log_assert(in_wire->port_input && !in_wire->port_output); + in_wire->port_output = true; + module->connect(in_wire, wire); + } + else + module->rename(wire, escaped_s); + } + else { + wire->port_output = false; + module->connect(wire, existing); + } + } + else if (index > 0) { + std::string indexed_name = stringf("%s[%d]", escaped_s.c_str(), index); + RTLIL::Wire* existing = module->wire(indexed_name); + if (!existing) { + if (escaped_s.ends_with("$inout.out")) { + wire->port_output = false; + RTLIL::Wire *in_wire = module->wire(stringf("%s[%d]", escaped_s.substr(0, escaped_s.size()-10).c_str(), index)); + log_assert(in_wire); + log_assert(in_wire->port_input && !in_wire->port_output); + in_wire->port_output = true; + module->connect(in_wire, wire); + } + else { + module->rename(wire, indexed_name); + if (wideports) + wideports_cache[escaped_s] = std::max(wideports_cache[escaped_s], index); + } + } + else { + module->connect(wire, existing); + wire->port_output = false; + } + } + } + else if (type == "box") { + RTLIL::Cell* cell = module->cell(stringf("$__box%d__", variable)); + if (cell) { + module->rename(cell, escaped_s); + RTLIL::Module* box_module = design->module(cell->type); + log_assert(box_module); + + if (box_module->attributes.count("\\abc_carry") && !abc_carry_modules.count(box_module)) { + RTLIL::Wire* carry_in = nullptr, *carry_out = nullptr; + RTLIL::Wire* last_in = nullptr, *last_out = nullptr; + for (const auto &port_name : box_module->ports) { + RTLIL::Wire* w = box_module->wire(port_name); + log_assert(w); + if (w->port_input) { + if (w->attributes.count("\\abc_carry_in")) { + log_assert(!carry_in); + carry_in = w; + } + log_assert(!last_in || last_in->port_id < w->port_id); + last_in = w; + } + if (w->port_output) { + if (w->attributes.count("\\abc_carry_out")) { + log_assert(!carry_out); + carry_out = w; + } + log_assert(!last_out || last_out->port_id < w->port_id); + last_out = w; + } + } + + if (carry_in != last_in) { + std::swap(box_module->ports[carry_in->port_id], box_module->ports[last_in->port_id]); + std::swap(carry_in->port_id, last_in->port_id); + } + if (carry_out != last_out) { + log_assert(last_out); + std::swap(box_module->ports[carry_out->port_id], box_module->ports[last_out->port_id]); + std::swap(carry_out->port_id, last_out->port_id); + } + } + + // NB: Assume box_module->ports are sorted alphabetically + // (as RTLIL::Module::fixup_ports() would do) + for (auto port_name : box_module->ports) { + RTLIL::Wire* w = box_module->wire(port_name); + log_assert(w); + RTLIL::SigSpec rhs; + RTLIL::Wire* wire = nullptr; + for (int i = 0; i < GetSize(w); i++) { + if (w->port_input) { + log_assert(static_cast<unsigned>(co_count) < outputs.size()); + wire = outputs[co_count++]; + log_assert(wire); + log_assert(wire->port_output); + wire->port_output = false; + } + if (w->port_output) { + log_assert(static_cast<unsigned>(pi_count + ci_count) < inputs.size()); + wire = inputs[pi_count + ci_count++]; + log_assert(wire); + log_assert(wire->port_input); + wire->port_input = false; + } + rhs.append(wire); + if (GetSize(w) == 1) + module->rename(wire, RTLIL::escape_id(stringf("%s.%s", log_id(cell), log_id(port_name)))); + else + module->rename(wire, RTLIL::escape_id(stringf("%s.%s[%d]", log_id(cell), log_id(port_name), i))); + } + cell->setPort(port_name, rhs); + } + } + } + else + log_error("Symbol type '%s' not recognised.\n", type.c_str()); + } + } + + for (auto &wp : wideports_cache) { + auto name = wp.first; + int width = wp.second + 1; + + RTLIL::Wire *wire = module->wire(name); + if (wire) + module->rename(wire, RTLIL::escape_id(stringf("%s[%d]", name.c_str(), 0))); + + // Do not make ports with a mix of input/output into + // wide ports + bool port_input = false, port_output = false; + for (int i = 0; i < width; i++) { + RTLIL::IdString other_name = name.str() + stringf("[%d]", i); + RTLIL::Wire *other_wire = module->wire(other_name); + if (other_wire) { + port_input = port_input || other_wire->port_input; + port_output = port_output || other_wire->port_output; + } + } + if ((port_input && port_output) || (!port_input && !port_output)) + continue; + + wire = module->addWire(name, width); + wire->port_input = port_input; + wire->port_output = port_output; + + for (int i = 0; i < width; i++) { + RTLIL::IdString other_name = name.str() + stringf("[%d]", i); + RTLIL::Wire *other_wire = module->wire(other_name); + if (other_wire) { + other_wire->port_input = false; + other_wire->port_output = false; + if (wire->port_input) + module->connect(other_wire, SigSpec(wire, i)); + else + module->connect(SigSpec(wire, i), other_wire); + } + } + } + + module->fixup_ports(); + design->add(module); + + design->selection_stack.emplace_back(false); + RTLIL::Selection& sel = design->selection_stack.back(); + sel.select(module); + + Pass::call(design, "clean"); + + design->selection_stack.pop_back(); + + for (auto cell : module->cells().to_vector()) { + if (cell->type != "$lut") continue; + auto y_port = cell->getPort("\\Y").as_bit(); + if (y_port.wire->width == 1) + module->rename(cell, stringf("%s$lut", y_port.wire->name.c_str())); + else + module->rename(cell, stringf("%s[%d]$lut", y_port.wire->name.c_str(), y_port.offset)); + } +} + struct AigerFrontend : public Frontend { AigerFrontend() : Frontend("aiger", "read AIGER file") { } void help() YS_OVERRIDE diff --git a/frontends/aiger/aigerparse.h b/frontends/aiger/aigerparse.h index 39757545f..8c9f3a0c9 100644 --- a/frontends/aiger/aigerparse.h +++ b/frontends/aiger/aigerparse.h @@ -47,6 +47,7 @@ struct AigerReader void parse_xaiger(); void parse_aiger_ascii(); void parse_aiger_binary(); + void post_process(); }; YOSYS_NAMESPACE_END |