From: Eddie Hung Date: Wed, 12 Jun 2019 15:50:39 +0000 (-0700) Subject: Merge remote-tracking branch 'origin/master' into xaig X-Git-Tag: working-ls180~1237^2~159 X-Git-Url: https://git.libre-soc.org/?a=commitdiff_plain;h=f7a9769c140f6a56e51d7384dfd8e76bf2aef66d;p=yosys.git Merge remote-tracking branch 'origin/master' into xaig --- f7a9769c140f6a56e51d7384dfd8e76bf2aef66d diff --cc frontends/aiger/aigerparse.cc index 904a1079d,68552fd06..4c19ec171 --- a/frontends/aiger/aigerparse.cc +++ b/frontends/aiger/aigerparse.cc @@@ -35,703 -33,240 +35,402 @@@ YOSYS_NAMESPACE_BEGIN -AigerReader::AigerReader(RTLIL::Design *design, std::istream &f, RTLIL::IdString module_name, RTLIL::IdString clk_name) - : design(design), f(f), clk_name(clk_name) +AigerReader::AigerReader(RTLIL::Design *design, std::istream &f, RTLIL::IdString module_name, RTLIL::IdString clk_name, std::string map_filename, bool wideports) - : design(design), f(f), clk_name(clk_name), map_filename(map_filename), wideports(wideports) ++ : design(design), f(f), clk_name(clk_name), map_filename(map_filename), wideports(wideports) { - module = new RTLIL::Module; - module->name = module_name; - if (design->module(module->name)) - log_error("Duplicate definition of module %s!\n", log_id(module->name)); + module = new RTLIL::Module; + module->name = module_name; + if (design->module(module->name)) + log_error("Duplicate definition of module %s!\n", log_id(module->name)); } void AigerReader::parse_aiger() { - std::string header; - f >> header; - if (header != "aag" && header != "aig") - log_error("Unsupported AIGER file!\n"); - - // Parse rest of header - if (!(f >> M >> I >> L >> O >> A)) - log_error("Invalid AIGER header\n"); - - // Optional values - B = C = J = F = 0; - for (auto &i : std::array,4>{B, C, J, F}) { - if (f.peek() != ' ') break; - if (!(f >> i)) - log_error("Invalid AIGER header\n"); - } - - std::string line; - std::getline(f, line); // Ignore up to start of next line, as standard - // says anything that follows could be used for - // optional sections - - log_debug("M=%u I=%u L=%u O=%u A=%u B=%u C=%u J=%u F=%u\n", M, I, L, O, A, B, C, J, F); - - line_count = 1; - - if (header == "aag") - parse_aiger_ascii(); - else if (header == "aig") - parse_aiger_binary(); - else - log_abort(); - - // Parse footer (symbol table, comments, etc.) - unsigned l1; - std::string s; - for (int c = f.peek(); c != EOF; c = f.peek(), ++line_count) { - 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(); - - module->rename(wire, stringf("\\%s", s.c_str())); - } - else if (c == 'b' || c == 'j' || c == 'f') { - // TODO - } - else if (c == 'c') { - f.ignore(1); - if (f.peek() == '\n') - break; - // Else constraint (TODO) - } - else - log_error("Line %u: cannot interpret first character '%c'!\n", line_count, c); - std::getline(f, line); // Ignore up to start of next line - } - - dict 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(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(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)); - } + std::string header; + f >> header; + if (header != "aag" && header != "aig") + log_error("Unsupported AIGER file!\n"); + + // Parse rest of header + if (!(f >> M >> I >> L >> O >> A)) + log_error("Invalid AIGER header\n"); + + // Optional values + B = C = J = F = 0; + 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 + // says anything that follows could be used for + // optional sections + + log_debug("M=%u I=%u L=%u O=%u A=%u B=%u C=%u J=%u F=%u\n", M, I, L, O, A, B, C, J, F); + + line_count = 1; ++ piNum = 0; ++ flopNum = 0; + + if (header == "aag") + parse_aiger_ascii(); + else if (header == "aig") + parse_aiger_binary(); + else + log_abort(); + - RTLIL::Wire* n0 = module->wire("\\n0"); ++ RTLIL::Wire* n0 = module->wire("\\__0__"); + if (n0) + module->connect(n0, RTLIL::S0); + - for (unsigned i = 0; i < outputs.size(); ++i) { - RTLIL::Wire *wire = outputs[i]; - if (wire->port_input) { - RTLIL::Wire *o_wire = module->addWire(wire->name.str() + "_o"); - o_wire->port_output = true; - wire->port_output = false; - module->connect(o_wire, wire); - outputs[i] = o_wire; - } - } - + // Parse footer (symbol table, comments, etc.) + unsigned l1; + std::string s; + for (int c = f.peek(); c != EOF; c = f.peek(), ++line_count) { + if (c == 'i' || c == 'l' || c == 'o' || c == 'b') { + 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 if (c == 'b') wire = bad_properties[l1]; + else log_abort(); + + module->rename(wire, stringf("\\%s", s.c_str())); + } + else if (c == 'j' || c == 'f') { + // TODO + } + else if (c == 'c') { + f.ignore(1); + if (f.peek() == '\n') + break; + // Else constraint (TODO) + } + else + log_error("Line %u: cannot interpret first character '%c'!\n", line_count, c); + std::getline(f, line); // Ignore up to start of next line + } + - module->fixup_ports(); - design->add(module); ++ post_process(); +} + +static uint32_t parse_xaiger_literal(std::istream &f) +{ - uint32_t l; - f.read(reinterpret_cast(&l), sizeof(l)); - if (f.gcount() != sizeof(l)) - log_error("Offset %ld: unable to read literal!\n", static_cast(f.tellg())); - // TODO: Don't assume we're on little endian ++ uint32_t l; ++ f.read(reinterpret_cast(&l), sizeof(l)); ++ if (f.gcount() != sizeof(l)) ++ log_error("Offset %ld: unable to read literal!\n", static_cast(f.tellg())); ++ // TODO: Don't assume we're on little endian +#ifdef _WIN32 - return _byteswap_ulong(l); ++ return _byteswap_ulong(l); +#else - return __builtin_bswap32(l); ++ return __builtin_bswap32(l); +#endif } static RTLIL::Wire* createWireIfNotExists(RTLIL::Module *module, unsigned literal) { - const unsigned variable = literal >> 1; - const bool invert = literal & 1; - RTLIL::IdString wire_name(stringf("\\__%d%s__", variable, invert ? "b" : "")); // FIXME: is "b" the right suffix? - RTLIL::Wire *wire = module->wire(wire_name); - if (wire) return wire; - log_debug("Creating %s\n", wire_name.c_str()); - wire = module->addWire(wire_name); - wire->port_input = wire->port_output = false; - if (!invert) return wire; - RTLIL::IdString wire_inv_name(stringf("\\__%d__", variable)); - RTLIL::Wire *wire_inv = module->wire(wire_inv_name); - if (wire_inv) { - if (module->cell(wire_inv_name)) return wire; - } - else { - log_debug("Creating %s\n", wire_inv_name.c_str()); - wire_inv = module->addWire(wire_inv_name); - wire_inv->port_input = wire_inv->port_output = false; - } - - log_debug("Creating %s = ~%s\n", wire_name.c_str(), wire_inv_name.c_str()); - module->addNotGate(stringf("\\__%d__$not", variable), wire_inv, wire); // FIXME: is "$not" the right suffix? - - return wire; - } - - static std::pair 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; + const unsigned variable = literal >> 1; + const bool invert = literal & 1; - RTLIL::IdString wire_name(stringf("\\n%d%s", variable, invert ? "_inv" : "")); // FIXME: is "_inv" the right suffix? ++ RTLIL::IdString wire_name(stringf("\\__%d%s__", variable, invert ? "b" : "")); // FIXME: is "b" the right suffix? + RTLIL::Wire *wire = module->wire(wire_name); + if (wire) return wire; + log_debug("Creating %s\n", wire_name.c_str()); + wire = module->addWire(wire_name); ++ wire->port_input = wire->port_output = false; + if (!invert) return wire; - RTLIL::IdString wire_inv_name(stringf("\\n%d", variable)); ++ RTLIL::IdString wire_inv_name(stringf("\\__%d__", variable)); + RTLIL::Wire *wire_inv = module->wire(wire_inv_name); + if (wire_inv) { + if (module->cell(wire_inv_name)) return wire; + } + else { + log_debug("Creating %s\n", wire_inv_name.c_str()); + wire_inv = module->addWire(wire_inv_name); ++ wire_inv->port_input = wire_inv->port_output = false; } - if (pos >= 0) - return std::pair(RTLIL::escape_id(name.substr(0, pos)), atoi(name.c_str() + pos+1)); + log_debug("Creating %s = ~%s\n", wire_name.c_str(), wire_inv_name.c_str()); - module->addNotGate(stringf("\\n%d_not", variable), wire_inv, wire); // FIXME: is "_not" the right suffix? ++ module->addNotGate(stringf("\\__%d__$not", variable), wire_inv, wire); // FIXME: is "$not" the right suffix? - failed: - return std::pair(name, 0); + return wire; } +void AigerReader::parse_xaiger() +{ - std::string header; - f >> header; - if (header != "aag" && header != "aig") - log_error("Unsupported AIGER file!\n"); - - // Parse rest of header - if (!(f >> M >> I >> L >> O >> A)) - log_error("Invalid AIGER header\n"); - - // Optional values - B = C = J = F = 0; - - std::string line; - std::getline(f, line); // Ignore up to start of next line, as standard - // says anything that follows could be used for - // optional sections - - log_debug("M=%u I=%u L=%u O=%u A=%u\n", M, I, L, O, A); - - line_count = 1; - - if (header == "aag") - parse_aiger_ascii(); - else if (header == "aig") - parse_aiger_binary(); - else - log_abort(); - - // Parse footer (symbol table, comments, etc.) - unsigned l1; - std::string s; - bool comment_seen = false; - std::vector> deferred_renames; - std::vector> 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) { - f.ignore(1); - c = f.peek(); - comment_seen = true; - } - if (c == '\n') - break; - f.ignore(1); - // XAIGER extensions - if (c == 'm') { - uint32_t dataSize = parse_xaiger_literal(f); - uint32_t lutNum = parse_xaiger_literal(f); - uint32_t lutSize = parse_xaiger_literal(f); - log_debug("m: dataSize=%u lutNum=%u lutSize=%u\n", dataSize, lutNum, lutSize); - ConstEval ce(module); - for (unsigned i = 0; i < lutNum; ++i) { - uint32_t rootNodeID = parse_xaiger_literal(f); - uint32_t cutLeavesM = parse_xaiger_literal(f); - log_debug("rootNodeID=%d cutLeavesM=%d\n", rootNodeID, cutLeavesM); - RTLIL::Wire *output_sig = module->wire(stringf("\\__%d__", rootNodeID)); - uint32_t nodeID; - RTLIL::SigSpec input_sig; - for (unsigned j = 0; j < cutLeavesM; ++j) { - nodeID = parse_xaiger_literal(f); - log_debug("\t%u\n", nodeID); - RTLIL::Wire *wire = module->wire(stringf("\\__%d__", nodeID)); - log_assert(wire); - input_sig.append(wire); - } - RTLIL::Const lut_mask(RTLIL::State::Sx, 1 << input_sig.size()); - for (int j = 0; j < (1 << cutLeavesM); ++j) { - ce.push(); - ce.set(input_sig, RTLIL::Const{j, static_cast(cutLeavesM)}); - RTLIL::SigSpec o(output_sig); - ce.eval(o); - lut_mask[j] = o.as_const()[0]; - ce.pop(); - } - RTLIL::Cell *output_cell = module->cell(stringf("\\__%d__$and", rootNodeID)); - log_assert(output_cell); - module->remove(output_cell); - module->addLut(stringf("\\__%d__$lut", rootNodeID), input_sig, output_sig, std::move(lut_mask)); - } - } - else if (c == 'r') { - /*uint32_t dataSize =*/ parse_xaiger_literal(f); - uint32_t flopNum = parse_xaiger_literal(f); - f.ignore(flopNum * sizeof(uint32_t)); - log_assert(inputs.size() >= flopNum); - for (auto it = inputs.end() - flopNum; it != inputs.end(); ++it) { - log_assert((*it)->port_input); - (*it)->port_input = false; - } - inputs.erase(inputs.end() - flopNum, inputs.end()); - log_assert(outputs.size() >= flopNum); - for (auto it = outputs.end() - flopNum; it != outputs.end(); ++it) { - log_assert((*it)->port_output); - (*it)->port_output = false; - } - outputs.erase(outputs.end() - flopNum, outputs.end()); - module->fixup_ports(); - } - else if (c == 'n') { - parse_xaiger_literal(f); - f >> s; - log_debug("n: '%s'\n", s.c_str()); - } - else if (c == 'a' || c == 'i' || c == 'o' || c == 'h') { - uint32_t dataSize = parse_xaiger_literal(f); - f.ignore(dataSize); - } - else { - 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 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(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(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)); - } ++ std::string header; ++ f >> header; ++ if (header != "aag" && header != "aig") ++ log_error("Unsupported AIGER file!\n"); ++ ++ // Parse rest of header ++ if (!(f >> M >> I >> L >> O >> A)) ++ log_error("Invalid AIGER header\n"); ++ ++ // Optional values ++ B = C = J = F = 0; ++ ++ std::string line; ++ std::getline(f, line); // Ignore up to start of next line, as standard ++ // says anything that follows could be used for ++ // optional sections ++ ++ log_debug("M=%u I=%u L=%u O=%u A=%u\n", M, I, L, O, A); ++ ++ line_count = 1; ++ piNum = 0; ++ flopNum = 0; ++ ++ if (header == "aag") ++ parse_aiger_ascii(); ++ else if (header == "aig") ++ parse_aiger_binary(); ++ else ++ log_abort(); ++ ++ RTLIL::Wire* n0 = module->wire("\\__0__"); ++ if (n0) ++ module->connect(n0, RTLIL::S0); ++ ++ dict box_lookup; ++ for (auto m : design->modules()) { ++ auto it = m->attributes.find("\\abc_box_id"); ++ if (it == m->attributes.end()) ++ continue; ++ if (m->name[0] == '$') continue; ++ auto r = box_lookup.insert(std::make_pair(it->second.as_int(), m->name)); ++ log_assert(r.second); ++ } ++ ++ // Parse footer (symbol table, comments, etc.) ++ std::string s; ++ bool comment_seen = false; ++ for (int c = f.peek(); c != EOF; c = f.peek()) { ++ if (comment_seen || c == 'c') { ++ if (!comment_seen) { ++ f.ignore(1); ++ c = f.peek(); ++ comment_seen = true; ++ } ++ if (c == '\n') ++ break; ++ f.ignore(1); ++ // XAIGER extensions ++ if (c == 'm') { ++ uint32_t dataSize = parse_xaiger_literal(f); ++ uint32_t lutNum = parse_xaiger_literal(f); ++ uint32_t lutSize = parse_xaiger_literal(f); ++ log_debug("m: dataSize=%u lutNum=%u lutSize=%u\n", dataSize, lutNum, lutSize); ++ ConstEval ce(module); ++ for (unsigned i = 0; i < lutNum; ++i) { ++ uint32_t rootNodeID = parse_xaiger_literal(f); ++ uint32_t cutLeavesM = parse_xaiger_literal(f); ++ log_debug("rootNodeID=%d cutLeavesM=%d\n", rootNodeID, cutLeavesM); ++ RTLIL::Wire *output_sig = module->wire(stringf("\\__%d__", rootNodeID)); ++ uint32_t nodeID; ++ RTLIL::SigSpec input_sig; ++ for (unsigned j = 0; j < cutLeavesM; ++j) { ++ nodeID = parse_xaiger_literal(f); ++ log_debug("\t%u\n", nodeID); ++ RTLIL::Wire *wire = module->wire(stringf("\\__%d__", nodeID)); ++ log_assert(wire); ++ input_sig.append(wire); ++ } ++ RTLIL::Const lut_mask(RTLIL::State::Sx, 1 << input_sig.size()); ++ for (int j = 0; j < (1 << cutLeavesM); ++j) { ++ ce.push(); ++ ce.set(input_sig, RTLIL::Const{j, static_cast(cutLeavesM)}); ++ RTLIL::SigSpec o(output_sig); ++ ce.eval(o); ++ lut_mask[j] = o.as_const()[0]; ++ ce.pop(); ++ } ++ RTLIL::Cell *output_cell = module->cell(stringf("\\__%d__$and", rootNodeID)); ++ log_assert(output_cell); ++ module->remove(output_cell); ++ module->addLut(stringf("\\__%d__$lut", rootNodeID), input_sig, output_sig, std::move(lut_mask)); ++ } ++ } ++ else if (c == 'r') { ++ uint32_t dataSize = parse_xaiger_literal(f); ++ flopNum = parse_xaiger_literal(f); ++ log_assert(dataSize == (flopNum+1) * sizeof(uint32_t)); ++ f.ignore(flopNum * sizeof(uint32_t)); ++ } ++ else if (c == 'n') { ++ parse_xaiger_literal(f); ++ f >> s; ++ log_debug("n: '%s'\n", s.c_str()); ++ } ++ else if (c == 'h') { ++ f.ignore(sizeof(uint32_t)); ++ uint32_t version = parse_xaiger_literal(f); ++ log_assert(version == 1); ++ uint32_t ciNum = parse_xaiger_literal(f); ++ log_debug("ciNum = %u\n", ciNum); ++ uint32_t coNum = parse_xaiger_literal(f); ++ log_debug("coNum = %u\n", coNum); ++ piNum = parse_xaiger_literal(f); ++ log_debug("piNum = %u\n", piNum); ++ uint32_t poNum = parse_xaiger_literal(f); ++ log_debug("poNum = %u\n", poNum); ++ uint32_t boxNum = parse_xaiger_literal(f); ++ log_debug("boxNum = %u\n", poNum); ++ 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); ++ RTLIL::Cell* cell = module->addCell(stringf("$__box%u__", oldBoxNum), box_lookup.at(boxUniqueId)); ++ boxes.emplace_back(cell); ++ } ++ } ++ else if (c == 'a' || c == 'i' || c == 'o') { ++ uint32_t dataSize = parse_xaiger_literal(f); ++ f.ignore(dataSize); ++ } ++ else { ++ break; ++ } ++ } ++ else ++ log_error("Line %u: cannot interpret first character '%c'!\n", line_count, c); ++ } ++ ++ post_process(); +} + void AigerReader::parse_aiger_ascii() { - std::string line; - std::stringstream ss; - - unsigned l1, l2, l3; - - // Parse inputs - for (unsigned i = 0; i < I; ++i, ++line_count) { - if (!(f >> l1)) - log_error("Line %u cannot be interpreted as an input!\n", line_count); - log_debug("%d is an input\n", l1); - log_assert(!(l1 & 1)); // Inputs can't be inverted - RTLIL::Wire *wire = createWireIfNotExists(module, l1); - wire->port_input = true; - inputs.push_back(wire); - } - - // Parse latches - RTLIL::Wire *clk_wire = nullptr; - if (L > 0) { - log_assert(clk_name != ""); - clk_wire = module->wire(clk_name); - log_assert(!clk_wire); - log_debug("Creating %s\n", clk_name.c_str()); - clk_wire = module->addWire(clk_name); - clk_wire->port_input = true; - clk_wire->port_output = false; - } - for (unsigned i = 0; i < L; ++i, ++line_count) { - if (!(f >> l1 >> l2)) - log_error("Line %u cannot be interpreted as a latch!\n", line_count); - log_debug("%d %d is a latch\n", l1, l2); - log_assert(!(l1 & 1)); // TODO: Latch outputs can't be inverted? - RTLIL::Wire *q_wire = createWireIfNotExists(module, l1); - RTLIL::Wire *d_wire = createWireIfNotExists(module, l2); - - module->addDffGate(NEW_ID, clk_wire, d_wire, q_wire); - - // Reset logic is optional in AIGER 1.9 - if (f.peek() == ' ') { - if (!(f >> l3)) - log_error("Line %u cannot be interpreted as a latch!\n", line_count); - - if (l3 == 0 || l3 == 1) - q_wire->attributes["\\init"] = RTLIL::Const(l3); - else if (l3 == l1) { - //q_wire->attributes["\\init"] = RTLIL::Const(RTLIL::State::Sx); - } - else - log_error("Line %u has invalid reset literal for latch!\n", line_count); - } - else { - // AIGER latches are assumed to be initialized to zero - q_wire->attributes["\\init"] = RTLIL::Const(0); - } - latches.push_back(q_wire); - } - - // Parse outputs - for (unsigned i = 0; i < O; ++i, ++line_count) { - if (!(f >> l1)) - log_error("Line %u cannot be interpreted as an output!\n", line_count); - - RTLIL::Wire *wire; - if (l1 == 0 || l1 == 1) { - wire = module->addWire(NEW_ID); - if (l1 == 0) - module->connect(wire, RTLIL::State::S0); - else if (l1 == 1) - module->connect(wire, RTLIL::State::S1); - else - log_abort(); - } - else { - 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 "b" the right suffix? - wire = module->wire(wire_name); - if (!wire) - wire = createWireIfNotExists(module, l1); - else { - if (wire->port_input || wire->port_output) { - RTLIL::Wire *new_wire = module->addWire(NEW_ID); - module->connect(new_wire, wire); - wire = new_wire; - } - } - } - wire->port_output = true; - outputs.push_back(wire); - } - std::getline(f, line); // Ignore up to start of next line - - // TODO: Parse bad state properties - for (unsigned i = 0; i < B; ++i, ++line_count) - std::getline(f, line); // Ignore up to start of next line - - // TODO: Parse invariant constraints - for (unsigned i = 0; i < C; ++i, ++line_count) - std::getline(f, line); // Ignore up to start of next line - - // TODO: Parse justice properties - for (unsigned i = 0; i < J; ++i, ++line_count) - std::getline(f, line); // Ignore up to start of next line - - // TODO: Parse fairness constraints - for (unsigned i = 0; i < F; ++i, ++line_count) - std::getline(f, line); // Ignore up to start of next line - - // Parse AND - for (unsigned i = 0; i < A; ++i) { - if (!(f >> l1 >> l2 >> l3)) - log_error("Line %u cannot be interpreted as an AND!\n", line_count); - - log_debug("%d %d %d is an AND\n", l1, l2, l3); - log_assert(!(l1 & 1)); - RTLIL::Wire *o_wire = createWireIfNotExists(module, l1); - RTLIL::Wire *i1_wire = createWireIfNotExists(module, l2); - RTLIL::Wire *i2_wire = createWireIfNotExists(module, l3); - module->addAndGate(o_wire->name.str() + "$and", i1_wire, i2_wire, o_wire); - } - std::getline(f, line); // Ignore up to start of next line + std::string line; + std::stringstream ss; + + unsigned l1, l2, l3; + + // Parse inputs + for (unsigned i = 1; i <= I; ++i, ++line_count) { + if (!(f >> l1)) + log_error("Line %u cannot be interpreted as an input!\n", line_count); + log_debug("%d is an input\n", l1); - log_assert(!(l1 & 1)); // TODO: Inputs can't be inverted? ++ log_assert(!(l1 & 1)); // Inputs can't be inverted + RTLIL::Wire *wire = createWireIfNotExists(module, l1); + wire->port_input = true; + inputs.push_back(wire); + } + + // Parse latches + RTLIL::Wire *clk_wire = nullptr; + if (L > 0) { ++ log_assert(clk_name != ""); + clk_wire = module->wire(clk_name); + log_assert(!clk_wire); + log_debug("Creating %s\n", clk_name.c_str()); + clk_wire = module->addWire(clk_name); + clk_wire->port_input = true; ++ clk_wire->port_output = false; + } + for (unsigned i = 0; i < L; ++i, ++line_count) { + if (!(f >> l1 >> l2)) + log_error("Line %u cannot be interpreted as a latch!\n", line_count); + log_debug("%d %d is a latch\n", l1, l2); + log_assert(!(l1 & 1)); // TODO: Latch outputs can't be inverted? + RTLIL::Wire *q_wire = createWireIfNotExists(module, l1); + RTLIL::Wire *d_wire = createWireIfNotExists(module, l2); + + module->addDffGate(NEW_ID, clk_wire, d_wire, q_wire); + + // Reset logic is optional in AIGER 1.9 + if (f.peek() == ' ') { + if (!(f >> l3)) + log_error("Line %u cannot be interpreted as a latch!\n", line_count); + + if (l3 == 0) + q_wire->attributes["\\init"] = RTLIL::S0; + else if (l3 == 1) + q_wire->attributes["\\init"] = RTLIL::S1; + else if (l3 == l1) { - //q_wire->attributes["\\init"] = RTLIL::Const(RTLIL::State::Sx); ++ //q_wire->attributes["\\init"] = RTLIL::Sx; + } + else + log_error("Line %u has invalid reset literal for latch!\n", line_count); + } + else { + // AIGER latches are assumed to be initialized to zero + q_wire->attributes["\\init"] = RTLIL::S0; + } + latches.push_back(q_wire); + } + + // Parse outputs + for (unsigned i = 0; i < O; ++i, ++line_count) { + if (!(f >> l1)) + log_error("Line %u cannot be interpreted as an output!\n", line_count); + + log_debug("%d is an output\n", l1); - RTLIL::Wire *wire = createWireIfNotExists(module, l1); ++ const unsigned variable = l1 >> 1; ++ const bool invert = l1 & 1; ++ RTLIL::IdString wire_name(stringf("\\__%d%s__", variable, invert ? "b" : "")); // FIXME: is "b" the right suffix? ++ RTLIL::Wire *wire = module->wire(wire_name); ++ if (!wire) ++ wire = createWireIfNotExists(module, l1); ++ else if (wire->port_input || wire->port_output) { ++ RTLIL::Wire *new_wire = module->addWire(NEW_ID); ++ module->connect(new_wire, wire); ++ wire = new_wire; ++ } + wire->port_output = true; + outputs.push_back(wire); + } + + // Parse bad properties + for (unsigned i = 0; i < B; ++i, ++line_count) { + if (!(f >> l1)) + log_error("Line %u cannot be interpreted as a bad state property!\n", line_count); + + log_debug("%d is a bad state property\n", l1); + RTLIL::Wire *wire = createWireIfNotExists(module, l1); + wire->port_output = true; + bad_properties.push_back(wire); + } + + // TODO: Parse invariant constraints + for (unsigned i = 0; i < C; ++i, ++line_count) + std::getline(f, line); // Ignore up to start of next line + + // TODO: Parse justice properties + for (unsigned i = 0; i < J; ++i, ++line_count) + std::getline(f, line); // Ignore up to start of next line + + // TODO: Parse fairness constraints + for (unsigned i = 0; i < F; ++i, ++line_count) + std::getline(f, line); // Ignore up to start of next line + + // Parse AND + for (unsigned i = 0; i < A; ++i) { + if (!(f >> l1 >> l2 >> l3)) + log_error("Line %u cannot be interpreted as an AND!\n", line_count); + + log_debug("%d %d %d is an AND\n", l1, l2, l3); - log_assert(!(l1 & 1)); // TODO: Output of ANDs can't be inverted? ++ log_assert(!(l1 & 1)); + RTLIL::Wire *o_wire = createWireIfNotExists(module, l1); + RTLIL::Wire *i1_wire = createWireIfNotExists(module, l2); + RTLIL::Wire *i2_wire = createWireIfNotExists(module, l3); - module->addAndGate(NEW_ID, i1_wire, i2_wire, o_wire); ++ module->addAndGate(o_wire->name.str() + "$and", i1_wire, i2_wire, o_wire); + } + std::getline(f, line); // Ignore up to start of next line } static unsigned parse_next_delta_literal(std::istream &f, unsigned ref) @@@ -745,198 -280,172 +444,473 @@@ void AigerReader::parse_aiger_binary() { - unsigned l1, l2, l3; - std::string line; - - // Parse inputs - for (unsigned i = 1; i <= I; ++i) { - log_debug("%d is an input\n", i); - RTLIL::Wire *wire = createWireIfNotExists(module, i << 1); - wire->port_input = true; - log_assert(!wire->port_output); - inputs.push_back(wire); - } - - // Parse latches - RTLIL::Wire *clk_wire = nullptr; - if (L > 0) { - log_assert(clk_name != ""); - clk_wire = module->wire(clk_name); - log_assert(!clk_wire); - log_debug("Creating %s\n", clk_name.c_str()); - clk_wire = module->addWire(clk_name); - clk_wire->port_input = true; - clk_wire->port_output = false; - } - l1 = (I+1) * 2; - for (unsigned i = 0; i < L; ++i, ++line_count, l1 += 2) { - if (!(f >> l2)) - log_error("Line %u cannot be interpreted as a latch!\n", line_count); - log_debug("%d %d is a latch\n", l1, l2); - RTLIL::Wire *q_wire = createWireIfNotExists(module, l1); - RTLIL::Wire *d_wire = createWireIfNotExists(module, l2); - - module->addDff(NEW_ID, clk_wire, d_wire, q_wire); - - // Reset logic is optional in AIGER 1.9 - if (f.peek() == ' ') { - if (!(f >> l3)) - log_error("Line %u cannot be interpreted as a latch!\n", line_count); - - if (l3 == 0 || l3 == 1) - q_wire->attributes["\\init"] = RTLIL::Const(l3); - else if (l3 == l1) { - //q_wire->attributes["\\init"] = RTLIL::Const(RTLIL::State::Sx); - } - else - log_error("Line %u has invalid reset literal for latch!\n", line_count); - } - else { - // AIGER latches are assumed to be initialized to zero - q_wire->attributes["\\init"] = RTLIL::Const(0); - } - latches.push_back(q_wire); - } - - // Parse outputs - for (unsigned i = 0; i < O; ++i, ++line_count) { - if (!(f >> l1)) - log_error("Line %u cannot be interpreted as an output!\n", line_count); - - RTLIL::Wire *wire; - if (l1 == 0 || l1 == 1) { - wire = module->addWire(NEW_ID); - if (l1 == 0) - module->connect(wire, RTLIL::State::S0); - else if (l1 == 1) - module->connect(wire, RTLIL::State::S1); - else - log_abort(); - } - else { - 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? - wire = module->wire(wire_name); - if (!wire) - wire = createWireIfNotExists(module, l1); - else { - if (wire->port_input || wire->port_output) { - RTLIL::Wire *new_wire = module->addWire(NEW_ID); - module->connect(new_wire, wire); - wire = new_wire; - } - } - } - wire->port_output = true; - outputs.push_back(wire); - } - std::getline(f, line); // Ignore up to start of next line - - // TODO: Parse bad state properties - for (unsigned i = 0; i < B; ++i, ++line_count) - std::getline(f, line); // Ignore up to start of next line - - // TODO: Parse invariant constraints - for (unsigned i = 0; i < C; ++i, ++line_count) - std::getline(f, line); // Ignore up to start of next line - - // TODO: Parse justice properties - for (unsigned i = 0; i < J; ++i, ++line_count) - std::getline(f, line); // Ignore up to start of next line - - // TODO: Parse fairness constraints - for (unsigned i = 0; i < F; ++i, ++line_count) - std::getline(f, line); // Ignore up to start of next line - - // Parse AND - l1 = (I+L+1) << 1; - for (unsigned i = 0; i < A; ++i, ++line_count, l1 += 2) { - l2 = parse_next_delta_literal(f, l1); - l3 = parse_next_delta_literal(f, l2); - - log_debug("%d %d %d is an AND\n", l1, l2, l3); - log_assert(!(l1 & 1)); - RTLIL::Wire *o_wire = createWireIfNotExists(module, l1); - RTLIL::Wire *i1_wire = createWireIfNotExists(module, l2); - RTLIL::Wire *i2_wire = createWireIfNotExists(module, l3); - module->addAndGate(o_wire->name.str() + "$and", i1_wire, i2_wire, o_wire); - } + unsigned l1, l2, l3; + std::string line; + + // Parse inputs + for (unsigned i = 1; i <= I; ++i) { ++ log_debug("%d is an input\n", i); + RTLIL::Wire *wire = createWireIfNotExists(module, i << 1); + wire->port_input = true; ++ log_assert(!wire->port_output); + inputs.push_back(wire); + } + + // Parse latches + RTLIL::Wire *clk_wire = nullptr; + if (L > 0) { ++ log_assert(clk_name != ""); + clk_wire = module->wire(clk_name); + log_assert(!clk_wire); + log_debug("Creating %s\n", clk_name.c_str()); + clk_wire = module->addWire(clk_name); + clk_wire->port_input = true; ++ clk_wire->port_output = false; + } + l1 = (I+1) * 2; + for (unsigned i = 0; i < L; ++i, ++line_count, l1 += 2) { + if (!(f >> l2)) + log_error("Line %u cannot be interpreted as a latch!\n", line_count); + log_debug("%d %d is a latch\n", l1, l2); + RTLIL::Wire *q_wire = createWireIfNotExists(module, l1); + RTLIL::Wire *d_wire = createWireIfNotExists(module, l2); + + module->addDff(NEW_ID, clk_wire, d_wire, q_wire); + + // Reset logic is optional in AIGER 1.9 + if (f.peek() == ' ') { + if (!(f >> l3)) + log_error("Line %u cannot be interpreted as a latch!\n", line_count); + + if (l3 == 0) + q_wire->attributes["\\init"] = RTLIL::S0; + else if (l3 == 1) + q_wire->attributes["\\init"] = RTLIL::S1; + else if (l3 == l1) { - //q_wire->attributes["\\init"] = RTLIL::Const(RTLIL::State::Sx); ++ //q_wire->attributes["\\init"] = RTLIL::Sx; + } + else + log_error("Line %u has invalid reset literal for latch!\n", line_count); + } + else { + // AIGER latches are assumed to be initialized to zero + q_wire->attributes["\\init"] = RTLIL::S0; + } + latches.push_back(q_wire); + } + + // Parse outputs + for (unsigned i = 0; i < O; ++i, ++line_count) { + if (!(f >> l1)) + log_error("Line %u cannot be interpreted as an output!\n", line_count); + + log_debug("%d is an output\n", l1); - RTLIL::Wire *wire = createWireIfNotExists(module, l1); ++ const unsigned variable = l1 >> 1; ++ const bool invert = l1 & 1; ++ RTLIL::IdString wire_name(stringf("\\__%d%s__", variable, invert ? "b" : "")); // FIXME: is "_b" the right suffix? ++ RTLIL::Wire *wire = module->wire(wire_name); ++ if (!wire) ++ wire = createWireIfNotExists(module, l1); ++ else if (wire->port_input || wire->port_output) { ++ RTLIL::Wire *new_wire = module->addWire(NEW_ID); ++ module->connect(new_wire, wire); ++ wire = new_wire; ++ } + wire->port_output = true; + outputs.push_back(wire); + } + std::getline(f, line); // Ignore up to start of next line + + // Parse bad properties + for (unsigned i = 0; i < B; ++i, ++line_count) { + if (!(f >> l1)) + log_error("Line %u cannot be interpreted as a bad state property!\n", line_count); + + log_debug("%d is a bad state property\n", l1); + RTLIL::Wire *wire = createWireIfNotExists(module, l1); + wire->port_output = true; + bad_properties.push_back(wire); + } + if (B > 0) + std::getline(f, line); // Ignore up to start of next line + + // TODO: Parse invariant constraints + for (unsigned i = 0; i < C; ++i, ++line_count) + std::getline(f, line); // Ignore up to start of next line + + // TODO: Parse justice properties + for (unsigned i = 0; i < J; ++i, ++line_count) + std::getline(f, line); // Ignore up to start of next line + + // TODO: Parse fairness constraints + for (unsigned i = 0; i < F; ++i, ++line_count) + std::getline(f, line); // Ignore up to start of next line + + // Parse AND + l1 = (I+L+1) << 1; + for (unsigned i = 0; i < A; ++i, ++line_count, l1 += 2) { + l2 = parse_next_delta_literal(f, l1); + l3 = parse_next_delta_literal(f, l2); + + log_debug("%d %d %d is an AND\n", l1, l2, l3); - log_assert(!(l1 & 1)); // TODO: Output of ANDs can't be inverted? ++ log_assert(!(l1 & 1)); + RTLIL::Wire *o_wire = createWireIfNotExists(module, l1); + RTLIL::Wire *i1_wire = createWireIfNotExists(module, l2); + RTLIL::Wire *i2_wire = createWireIfNotExists(module, l3); ++ module->addAndGate(o_wire->name.str() + "$and", i1_wire, i2_wire, o_wire); ++ } ++} + - RTLIL::Cell *and_cell = module->addCell(NEW_ID, "$_AND_"); - and_cell->setPort("\\A", i1_wire); - and_cell->setPort("\\B", i2_wire); - and_cell->setPort("\\Y", o_wire); ++void AigerReader::post_process() ++{ ++ pool abc_carry_modules; ++ unsigned ci_count = 0, co_count = 0, flop_count = 0; ++ for (auto cell : boxes) { ++ 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); ++ } ++ } ++ ++ bool flop = box_module->attributes.count("\\abc_flop"); ++ log_assert(!flop || flop_count < flopNum); ++ ++ // 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(co_count < outputs.size()); ++ wire = outputs[co_count++]; ++ log_assert(wire); ++ log_assert(wire->port_output); ++ wire->port_output = false; ++ ++ if (flop && w->attributes.count("\\abc_flop_d")) { ++ RTLIL::Wire* d = outputs[outputs.size() - flopNum + flop_count]; ++ log_assert(d); ++ log_assert(d->port_output); ++ d->port_output = false; ++ } ++ } ++ if (w->port_output) { ++ log_assert((piNum + ci_count) < inputs.size()); ++ wire = inputs[piNum + ci_count++]; ++ log_assert(wire); ++ log_assert(wire->port_input); ++ wire->port_input = false; ++ ++ if (flop && w->attributes.count("\\abc_flop_q")) { ++ wire = inputs[piNum - flopNum + flop_count]; ++ log_assert(wire); ++ log_assert(wire->port_input); ++ wire->port_input = false; ++ } ++ } ++ rhs.append(wire); ++ } ++ cell->setPort(port_name, rhs); ++ } ++ ++ if (flop) flop_count++; ++ } ++ ++ dict 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_s = RTLIL::escape_id(symbol); ++ if (type == "input") { ++ log_assert(static_cast(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(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) { // ABC could have optimised this box away ++ module->rename(cell, escaped_s); ++ RTLIL::Module* box_module = design->module(cell->type); ++ log_assert(box_module); ++ ++ for (const auto &i : cell->connections()) { ++ RTLIL::IdString port_name = i.first; ++ RTLIL::SigSpec rhs = i.second; ++ int index = 0; ++ for (auto bit : rhs.bits()) { ++ RTLIL::Wire* wire = bit.wire; ++ RTLIL::IdString escaped_s = RTLIL::escape_id(stringf("%s.%s", log_id(cell), log_id(port_name))); ++ if (index == 0) ++ module->rename(wire, escaped_s); ++ else if (index > 0) { ++ module->rename(wire, stringf("%s[%d]", escaped_s.c_str(), index)); ++ if (wideports) ++ wideports_cache[escaped_s] = std::max(wideports_cache[escaped_s], index); ++ } ++ 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); ++ ++ 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 - { - // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---| - log("\n"); - log(" read_aiger [options] [filename]\n"); - log("\n"); - log("Load module from an AIGER file into the current design.\n"); - log("\n"); - log(" -module_name \n"); - log(" Name of module to be created (default: )\n"); - log("\n"); - log(" -clk_name \n"); - log(" AIGER latches to be transformed into posedge DFFs clocked by wire of"); - log(" this name (default: clk)\n"); - log("\n"); - log(" -map \n"); - log(" read file with port and latch symbols\n"); - log("\n"); - log(" -wideports\n"); - log(" Merge ports that match the pattern 'name[int]' into a single\n"); - log(" multi-bit port 'name'.\n"); - log("\n"); - } - void execute(std::istream *&f, std::string filename, std::vector args, RTLIL::Design *design) YS_OVERRIDE - { - log_header(design, "Executing AIGER frontend.\n"); - - RTLIL::IdString clk_name = "\\clk"; - RTLIL::IdString module_name; - std::string map_filename; - bool wideports = false; - - size_t argidx; - for (argidx = 1; argidx < args.size(); argidx++) { - std::string arg = args[argidx]; - if (arg == "-module_name" && argidx+1 < args.size()) { - module_name = RTLIL::escape_id(args[++argidx]); - continue; - } - if (arg == "-clk_name" && argidx+1 < args.size()) { - clk_name = RTLIL::escape_id(args[++argidx]); - continue; - } - if (map_filename.empty() && arg == "-map" && argidx+1 < args.size()) { - map_filename = args[++argidx]; - continue; - } - if (arg == "-wideports") { - wideports = true; - continue; - } - break; - } - extra_args(f, filename, args, argidx); - - if (module_name.empty()) { + AigerFrontend() : Frontend("aiger", "read AIGER file") { } + void help() YS_OVERRIDE + { + // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---| + log("\n"); + log(" read_aiger [options] [filename]\n"); + log("\n"); + log("Load module from an AIGER file into the current design.\n"); + log("\n"); + log(" -module_name \n"); - log(" Name of module to be created (default: " -#ifdef _WIN32 - "top" // FIXME -#else - "" -#endif - ")\n"); ++ log(" Name of module to be created (default: )\n"); + log("\n"); + log(" -clk_name \n"); + log(" AIGER latches to be transformed into posedge DFFs clocked by wire of"); + log(" this name (default: clk)\n"); + log("\n"); ++ log(" -map \n"); ++ log(" read file with port and latch symbols\n"); ++ log("\n"); ++ log(" -wideports\n"); ++ log(" Merge ports that match the pattern 'name[int]' into a single\n"); ++ log(" multi-bit port 'name'.\n"); ++ log("\n"); + } + void execute(std::istream *&f, std::string filename, std::vector args, RTLIL::Design *design) YS_OVERRIDE + { + log_header(design, "Executing AIGER frontend.\n"); + + RTLIL::IdString clk_name = "\\clk"; + RTLIL::IdString module_name; ++ std::string map_filename; ++ bool wideports = false; + + size_t argidx; + for (argidx = 1; argidx < args.size(); argidx++) { + std::string arg = args[argidx]; + if (arg == "-module_name" && argidx+1 < args.size()) { + module_name = RTLIL::escape_id(args[++argidx]); + continue; + } + if (arg == "-clk_name" && argidx+1 < args.size()) { + clk_name = RTLIL::escape_id(args[++argidx]); + continue; + } ++ if (map_filename.empty() && arg == "-map" && argidx+1 < args.size()) { ++ map_filename = args[++argidx]; ++ continue; ++ } ++ if (arg == "-wideports") { ++ wideports = true; ++ continue; ++ } + break; + } + extra_args(f, filename, args, argidx); + + if (module_name.empty()) { #ifdef _WIN32 - char fname[_MAX_FNAME]; - _splitpath(filename.c_str(), NULL /* drive */, NULL /* dir */, fname, NULL /* ext */) - module_name = fname; - module_name = "top"; // FIXME: basename equivalent on Win32? ++ char fname[_MAX_FNAME]; ++ _splitpath(filename.c_str(), NULL /* drive */, NULL /* dir */, fname, NULL /* ext */) ++ module_name = fname; #else - char* bn = strdup(filename.c_str()); - module_name = RTLIL::escape_id(bn); - free(bn); + char* bn = strdup(filename.c_str()); + module_name = RTLIL::escape_id(bn); + free(bn); #endif - } + } - AigerReader reader(design, *f, module_name, clk_name, map_filename, wideports); - reader.parse_aiger(); - } - AigerReader reader(design, *f, module_name, clk_name); ++ AigerReader reader(design, *f, module_name, clk_name, map_filename, wideports); + reader.parse_aiger(); + } } AigerFrontend; YOSYS_NAMESPACE_END diff --cc frontends/aiger/aigerparse.h index 39757545f,0e3719cc4..7d6d70b2c --- a/frontends/aiger/aigerparse.h +++ b/frontends/aiger/aigerparse.h @@@ -37,16 -35,16 +37,20 @@@ struct AigerReade unsigned M, I, L, O, A; unsigned B, C, J, F; // Optional in AIGER 1.9 unsigned line_count; ++ uint32_t piNum, flopNum; std::vector inputs; std::vector latches; std::vector outputs; + std::vector bad_properties; ++ std::vector boxes; - AigerReader(RTLIL::Design *design, std::istream &f, RTLIL::IdString module_name, RTLIL::IdString clk_name); + AigerReader(RTLIL::Design *design, std::istream &f, RTLIL::IdString module_name, RTLIL::IdString clk_name, std::string map_filename, bool wideports); void parse_aiger(); + void parse_xaiger(); void parse_aiger_ascii(); void parse_aiger_binary(); ++ void post_process(); }; YOSYS_NAMESPACE_END diff --cc techlibs/xilinx/synth_xilinx.cc index 5820d6d61,a293081f1..f966115cd --- a/techlibs/xilinx/synth_xilinx.cc +++ b/techlibs/xilinx/synth_xilinx.cc @@@ -63,6 -58,6 +58,9 @@@ struct SynthXilinxPass : public ScriptP log(" generate an output netlist (and BLIF file) suitable for VPR\n"); log(" (this feature is experimental and incomplete)\n"); log("\n"); ++ log(" -nocarry\n"); ++ log(" disable inference of carry chains\n"); ++ log("\n"); log(" -nobram\n"); log(" disable inference of block rams\n"); log("\n"); @@@ -72,6 -67,6 +70,9 @@@ log(" -nosrl\n"); log(" disable inference of shift registers\n"); log("\n"); ++ log(" -nomux\n"); ++ log(" disable inference of wide multiplexers\n"); ++ log("\n"); log(" -run :\n"); log(" only run the commands between the labels (see below). an empty\n"); log(" from label is synonymous to 'begin', and empty to label is\n"); @@@ -83,85 -78,33 +84,39 @@@ log(" -retime\n"); log(" run 'abc' with -dff option\n"); log("\n"); + log(" -abc9\n"); + log(" use abc9 instead of abc\n"); + log("\n"); log("\n"); log("The following commands are executed by this synthesis command:\n"); - log("\n"); - log(" begin:\n"); - log(" read_verilog -lib +/xilinx/cells_sim.v\n"); - log(" read_verilog -lib +/xilinx/cells_xtra.v\n"); - log(" read_verilog -lib +/xilinx/brams_bb.v\n"); - log(" hierarchy -check -top \n"); - log("\n"); - log(" flatten: (only if -flatten)\n"); - log(" proc\n"); - log(" flatten\n"); - log("\n"); - log(" coarse:\n"); - log(" synth -run coarse\n"); - log("\n"); - log(" bram: (only executed when '-nobram' is not given)\n"); - log(" memory_bram -rules +/xilinx/brams.txt\n"); - log(" techmap -map +/xilinx/brams_map.v\n"); - log("\n"); - log(" dram: (only executed when '-nodram' is not given)\n"); - log(" memory_bram -rules +/xilinx/drams.txt\n"); - log(" techmap -map +/xilinx/drams_map.v\n"); - log("\n"); - log(" fine:\n"); - log(" opt -fast\n"); - log(" memory_map\n"); - log(" dffsr2dff\n"); - log(" dff2dffe\n"); - log(" techmap -map +/xilinx/arith_map.v\n"); - log(" opt -fast\n"); - log("\n"); - log(" map_cells:\n"); - log(" simplemap t:$dff t:$dffe (without '-nosrl' only)\n"); - log(" pmux2shiftx (without '-nosrl' only)\n"); - log(" opt_expr -mux_undef (without '-nosrl' only)\n"); - log(" shregmap -tech xilinx -minlen 3 (without '-nosrl' only)\n"); - log(" techmap -map +/xilinx/cells_map.v\n"); - log(" clean\n"); - log("\n"); - log(" map_luts:\n"); - log(" opt -full\n"); - log(" techmap -map +/techmap.v -D _NO_POS_SR -map +/xilinx/ff_map.v\n"); - log(" abc -luts 2:2,3,6:5,10,20 [-dff]\n"); - log(" clean\n"); - log(" shregmap -minlen 3 -init -params -enpol any_or_none (without '-nosrl' only)\n"); - log(" techmap -map +/xilinx/lut_map.v -map +/xilinx/ff_map.v -map +/xilinx/cells_map.v"); - log(" dffinit -ff FDRE Q INIT -ff FDCE Q INIT -ff FDPE Q INIT -ff FDSE Q INIT \\\n"); - log(" -ff FDRE_1 Q INIT -ff FDCE_1 Q INIT -ff FDPE_1 Q INIT -ff FDSE_1 Q INIT\n"); - log(" clean\n"); - log("\n"); - log(" check:\n"); - log(" hierarchy -check\n"); - log(" stat\n"); - log(" check -noinit\n"); - log("\n"); - log(" edif: (only if -edif)\n"); - log(" write_edif \n"); - log("\n"); - log(" blif: (only if -blif)\n"); - log(" write_blif \n"); + help_script(); log("\n"); } + - std::string top_opt, edif_file, blif_file, arch; - bool flatten, retime, vpr, nobram, nodram, nosrl; ++ std::string top_opt, edif_file, blif_file, abc, arch; ++ bool flatten, retime, vpr, nocarry, nobram, nodram, nosrl, nomux; + + void clear_flags() YS_OVERRIDE + { + top_opt = "-auto-top"; + edif_file.clear(); + blif_file.clear(); ++ abc = "abc"; + flatten = false; + retime = false; + vpr = false; ++ nocarry = false; + nobram = false; + nodram = false; + nosrl = false; ++ nomux = false; + arch = "xc7"; + } + void execute(std::vector args, RTLIL::Design *design) YS_OVERRIDE { - std::string top_opt = "-auto-top"; - std::string edif_file; - std::string blif_file; std::string run_from, run_to; - std::string abc = "abc"; - bool flatten = false; - bool retime = false; - bool vpr = false; - bool nobram = false; - bool nodram = false; - bool nosrl = false; + clear_flags(); size_t argidx; for (argidx = 1; argidx < args.size(); argidx++) @@@ -198,6 -145,6 +157,10 @@@ vpr = true; continue; } ++ if (args[argidx] == "-nocarry") { ++ nocarry = true; ++ continue; ++ } if (args[argidx] == "-nobram") { nobram = true; continue; @@@ -209,11 -156,7 +172,15 @@@ if (args[argidx] == "-nosrl") { nosrl = true; continue; - } + } ++ if (args[argidx] == "-nomux") { ++ nomux = true; ++ continue; ++ } + if (args[argidx] == "-abc9") { + abc = "abc9"; + continue; + } break; } extra_args(args, argidx, design); @@@ -224,125 -170,117 +194,141 @@@ log_header(design, "Executing SYNTH_XILINX pass.\n"); log_push(); - if (check_label(active, run_from, run_to, "begin")) - { - if (vpr) { - Pass::call(design, "read_verilog -lib -D_EXPLICIT_CARRY +/xilinx/cells_sim.v"); - } else { - Pass::call(design, "read_verilog -lib +/xilinx/cells_sim.v"); - } + run_script(design, run_from, run_to); - Pass::call(design, "read_verilog -lib +/xilinx/cells_xtra.v"); + log_pop(); + } - if (!nobram) { - Pass::call(design, "read_verilog -lib +/xilinx/brams_bb.v"); - } + void script() YS_OVERRIDE + { + if (check_label("begin")) { + if (vpr) - run("read_verilog -lib -D_EXPLICIT_CARRY +/xilinx/cells_sim.v"); ++ run("read_verilog -lib -D _ABC -D_EXPLICIT_CARRY +/xilinx/cells_sim.v"); + else - run("read_verilog -lib +/xilinx/cells_sim.v"); ++ run("read_verilog -lib -D _ABC +/xilinx/cells_sim.v"); - Pass::call(design, stringf("hierarchy -check %s", top_opt.c_str())); - } + run("read_verilog -lib +/xilinx/cells_xtra.v"); - if (flatten && check_label(active, run_from, run_to, "flatten")) - { - Pass::call(design, "proc"); - Pass::call(design, "flatten"); - } + if (!nobram || help_mode) + run("read_verilog -lib +/xilinx/brams_bb.v", "(skip if '-nobram')"); - if (check_label(active, run_from, run_to, "coarse")) - { - Pass::call(design, "synth -run coarse"); + run(stringf("hierarchy -check %s", top_opt.c_str())); } - if (check_label(active, run_from, run_to, "bram")) - { - if (!nobram) { - Pass::call(design, "memory_bram -rules +/xilinx/brams.txt"); - Pass::call(design, "techmap -map +/xilinx/brams_map.v"); + if (check_label("flatten", "(with '-flatten' only)")) { + if (flatten || help_mode) { + run("proc"); + run("flatten"); } } - if (check_label(active, run_from, run_to, "dram")) - { - if (!nodram) { - Pass::call(design, "memory_bram -rules +/xilinx/drams.txt"); - Pass::call(design, "techmap -map +/xilinx/drams_map.v"); - } + if (check_label("coarse")) { + run("synth -run coarse"); ++ ++ //if (!nomux || help_mode) ++ // run("muxpack", "(skip if '-nomux')"); ++ ++ // shregmap -tech xilinx can cope with $shiftx and $mux ++ // cells for identifying variable-length shift registers, ++ // so attempt to convert $pmux-es to the former ++ // Also: wide multiplexer inference benefits from this too ++ if (!(nosrl && nomux) || help_mode) ++ run("pmux2shiftx", "(skip if '-nosrl' and '-nomux')"); ++ ++ // Run a number of peephole optimisations, including one ++ // that optimises $mul cells driving $shiftx's B input ++ // and that aids wide mux analysis ++ run("peepopt"); } - if (check_label(active, run_from, run_to, "fine")) - { - Pass::call(design, "opt -fast"); - Pass::call(design, "memory_map"); - Pass::call(design, "dffsr2dff"); - Pass::call(design, "dff2dffe"); - - if (vpr) { - Pass::call(design, "techmap -map +/xilinx/arith_map.v -D _EXPLICIT_CARRY"); - } else { - Pass::call(design, "techmap -map +/xilinx/arith_map.v"); + if (check_label("bram", "(skip if '-nobram')")) { + if (!nobram || help_mode) { + run("memory_bram -rules +/xilinx/brams.txt"); + run("techmap -map +/xilinx/brams_map.v"); } + } - Pass::call(design, "hierarchy -check"); - Pass::call(design, "opt -fast"); + if (check_label("dram", "(skip if '-nodram')")) { + if (!nodram || help_mode) { + run("memory_bram -rules +/xilinx/drams.txt"); + run("techmap -map +/xilinx/drams_map.v"); + } } - if (check_label(active, run_from, run_to, "map_cells")) - { - if (!nosrl) { + if (check_label("fine")) { - // shregmap -tech xilinx can cope with $shiftx and $mux - // cells for identifiying variable-length shift registers, - // so attempt to convert $pmux-es to the former - if (!nosrl || help_mode) - run("pmux2shiftx", "(skip if '-nosrl')"); - + run("opt -fast -full"); + run("memory_map"); + run("dffsr2dff"); + run("dff2dffe"); + run("opt -full"); + + if (!nosrl || help_mode) { // shregmap operates on bit-level flops, not word-level, // so break those down here - Pass::call(design, "simplemap t:$dff t:$dffe"); - // shregmap -tech xilinx can cope with $shiftx and $mux - // cells for identifiying variable-length shift registers, - // so attempt to convert $pmux-es to the former - Pass::call(design, "pmux2shiftx"); - // pmux2shiftx can leave behind a $pmux with a single entry - // -- need this to clean that up before shregmap - Pass::call(design, "opt_expr -mux_undef"); + run("simplemap t:$dff t:$dffe", "(skip if '-nosrl')"); // shregmap with '-tech xilinx' infers variable length shift regs - Pass::call(design, "shregmap -tech xilinx -minlen 3"); + run("shregmap -tech xilinx -minlen 3", "(skip if '-nosrl')"); } - Pass::call(design, "techmap -map +/xilinx/cells_map.v"); - Pass::call(design, "clean"); - if (!vpr || help_mode) - run("techmap -map +/techmap.v -map +/xilinx/arith_map.v"); - else - run("techmap -map +/techmap.v +/xilinx/arith_map.v -D _EXPLICIT_CARRY"); - ++ std::string techmap_files = " -map +/techmap.v"; ++ if (help_mode) ++ techmap_files += " [-map +/xilinx/mux_map.v]"; ++ else if (!nomux) ++ techmap_files += " -map +/xilinx/mux_map.v"; ++ if (help_mode) ++ techmap_files += " [-map +/xilinx/arith_map.v]"; ++ else if (!nocarry) { ++ techmap_files += " -map +/xilinx/arith_map.v"; ++ if (vpr) ++ techmap_files += " -D _EXPLICIT_CARRY"; ++ else if (abc == "abc9") ++ techmap_files += " -D _CLB_CARRY"; ++ } ++ run("techmap " + techmap_files); + run("opt -fast"); } - if (check_label(active, run_from, run_to, "map_luts")) - { - Pass::call(design, "opt -full"); - Pass::call(design, "techmap -map +/techmap.v -D _NO_POS_SR -map +/xilinx/ff_map.v"); - Pass::call(design, abc + " -luts 2:2,3,6:5,10,20" + string(retime ? " -dff" : "")); - Pass::call(design, "clean"); + if (check_label("map_cells")) { ++ if (!nomux || help_mode) ++ run("muxcover -mux8 -mux16", "(skip if '-nomux')"); + run("techmap -map +/techmap.v -map +/xilinx/cells_map.v"); + run("clean"); + } + + if (check_label("map_luts")) { - if (help_mode) - run("abc -luts 2:2,3,6:5,10,20 [-dff]"); ++ if (abc == "abc9") ++ run(abc + " -lut +/xilinx/abc.lut -box +/xilinx/abc.box -W 160" + string(retime ? " -dff" : "")); ++ else if (help_mode) ++ run(abc + " -luts 2:2,3,6:5,10,20 [-dff]"); + else - run("abc -luts 2:2,3,6:5,10,20" + string(retime ? " -dff" : "")); ++ run(abc + " -luts 2:2,3,6:5,10,20" + string(retime ? " -dff" : "")); + run("clean"); ++ // This shregmap call infers fixed length shift registers after abc // has performed any necessary retiming - if (!nosrl) - Pass::call(design, "shregmap -minlen 3 -init -params -enpol any_or_none"); - Pass::call(design, "techmap -map +/xilinx/lut_map.v -map +/xilinx/ff_map.v -map +/xilinx/cells_map.v"); - Pass::call(design, "dffinit -ff FDRE Q INIT -ff FDCE Q INIT -ff FDPE Q INIT -ff FDSE Q INIT " + if (!nosrl || help_mode) + run("shregmap -minlen 3 -init -params -enpol any_or_none", "(skip if '-nosrl')"); - run("techmap -map +/xilinx/lut_map.v -map +/xilinx/ff_map.v -map +/xilinx/cells_map.v"); ++ run("techmap -map +/xilinx/lut_map.v -map +/xilinx/cells_map.v -map +/xilinx/ff_map.v"); + run("dffinit -ff FDRE Q INIT -ff FDCE Q INIT -ff FDPE Q INIT -ff FDSE Q INIT " "-ff FDRE_1 Q INIT -ff FDCE_1 Q INIT -ff FDPE_1 Q INIT -ff FDSE_1 Q INIT"); - Pass::call(design, "clean"); + run("clean"); } - if (check_label(active, run_from, run_to, "check")) - { - Pass::call(design, "hierarchy -check"); - Pass::call(design, "stat"); - Pass::call(design, "check -noinit"); + if (check_label("check")) { + run("hierarchy -check"); + run("stat -tech xilinx"); + run("check -noinit"); } - if (check_label(active, run_from, run_to, "edif")) - { - if (!edif_file.empty()) - Pass::call(design, stringf("write_edif -pvector bra %s", edif_file.c_str())); - } - if (check_label(active, run_from, run_to, "blif")) - { - if (!blif_file.empty()) - Pass::call(design, stringf("write_blif %s", edif_file.c_str())); + if (check_label("edif")) { + if (!edif_file.empty() || help_mode) + run(stringf("write_edif -pvector bra %s", edif_file.c_str())); } - log_pop(); + if (check_label("blif")) { + if (!blif_file.empty() || help_mode) + run(stringf("write_blif %s", edif_file.c_str())); + } } } SynthXilinxPass; diff --cc tests/tools/autotest.sh index 86a90793e,23964a751..c394b9817 --- a/tests/tools/autotest.sh +++ b/tests/tools/autotest.sh @@@ -132,13 -143,14 +143,14 @@@ d fn=$(basename $fn) bn=$(basename $bn) - rm -f ${bn}_ref.fir if [[ "$ext" == "v" ]]; then egrep -v '^\s*`timescale' ../$fn > ${bn}_ref.${ext} + elif [[ "$ext" == "aig" ]] || [[ "$ext" == "aag" ]]; then + "$toolsdir"/../../yosys-abc -c "read_aiger ../${fn}; write ${bn}_ref.v" else - "$toolsdir"/../../yosys -f "$frontend $include_opts" -b "verilog" -o ${bn}_ref.v ../${fn} - frontend="verilog -noblackbox" + cp ../${fn} ${bn}_ref.${ext} fi + rm -f ${bn}_ref.fir if [ ! -f ../${bn}_tb.v ]; then "$toolsdir"/../../yosys -f "$frontend $include_opts" -b "test_autotb $autotb_opts" -o ${bn}_tb.v ${bn}_ref.v