From: Eddie Hung Date: Tue, 14 Jan 2020 20:57:56 +0000 (-0800) Subject: Merge remote-tracking branch 'origin/eddie/abc9_refactor' into eddie/abc9_required X-Git-Tag: working-ls180~822^2~18 X-Git-Url: https://git.libre-soc.org/?a=commitdiff_plain;h=915e7dde734094e21803f83e37f8827b8ff2fe32;p=yosys.git Merge remote-tracking branch 'origin/eddie/abc9_refactor' into eddie/abc9_required --- 915e7dde734094e21803f83e37f8827b8ff2fe32 diff --cc backends/aiger/xaiger.cc index d934a9aa9,f9890a592..d3415e45d --- a/backends/aiger/xaiger.cc +++ b/backends/aiger/xaiger.cc @@@ -184,88 -184,77 +184,95 @@@ struct XAigerWrite } } - std::vector arrivals; - dict> arrival_cache; ++ dict>> arrivals_cache; for (auto cell : module->cells()) { - if (cell->type == "$_NOT_") - { - SigBit A = sigmap(cell->getPort("\\A").as_bit()); - SigBit Y = sigmap(cell->getPort("\\Y").as_bit()); - unused_bits.erase(A); - undriven_bits.erase(Y); - not_map[Y] = A; - continue; - } - - if (cell->type == "$_AND_") - { - SigBit A = sigmap(cell->getPort("\\A").as_bit()); - SigBit B = sigmap(cell->getPort("\\B").as_bit()); - SigBit Y = sigmap(cell->getPort("\\Y").as_bit()); - unused_bits.erase(A); - unused_bits.erase(B); - undriven_bits.erase(Y); - and_map[Y] = make_pair(A, B); - continue; - } + RTLIL::Module* inst_module = module->design->module(cell->type); + if (!cell->has_keep_attr()) { + if (cell->type == "$_NOT_") + { + SigBit A = sigmap(cell->getPort("\\A").as_bit()); + SigBit Y = sigmap(cell->getPort("\\Y").as_bit()); + unused_bits.erase(A); + undriven_bits.erase(Y); + not_map[Y] = A; + continue; + } - if (cell->type == "$__ABC9_FF_" && - // The presence of an abc9_mergeability attribute indicates - // that we do want to pass this flop to ABC - cell->attributes.count("\\abc9_mergeability")) - { - SigBit D = sigmap(cell->getPort("\\D").as_bit()); - SigBit Q = sigmap(cell->getPort("\\Q").as_bit()); - unused_bits.erase(D); - undriven_bits.erase(Q); - alias_map[Q] = D; - auto r YS_ATTRIBUTE(unused) = ff_bits.insert(std::make_pair(D, cell)); - log_assert(r.second); - continue; - } + if (cell->type == "$_AND_") + { + SigBit A = sigmap(cell->getPort("\\A").as_bit()); + SigBit B = sigmap(cell->getPort("\\B").as_bit()); + SigBit Y = sigmap(cell->getPort("\\Y").as_bit()); + unused_bits.erase(A); + unused_bits.erase(B); + undriven_bits.erase(Y); + and_map[Y] = make_pair(A, B); + continue; + } - RTLIL::Module* inst_module = module->design->module(cell->type); - if (inst_module && inst_module->get_blackbox_attribute()) { - auto it = cell->attributes.find("\\abc9_box_seq"); - if (it != cell->attributes.end()) { - int abc9_box_seq = it->second.as_int(); - if (GetSize(box_list) <= abc9_box_seq) - box_list.resize(abc9_box_seq+1); - box_list[abc9_box_seq] = cell; - // Only flop boxes may have arrival times - // (all others are combinatorial) - if (!inst_module->get_bool_attribute("\\abc9_flop")) - continue; + if (cell->type == "$__ABC9_FF_" && + // The presence of an abc9_mergeability attribute indicates + // that we do want to pass this flop to ABC + cell->attributes.count("\\abc9_mergeability")) + { + SigBit D = sigmap(cell->getPort("\\D").as_bit()); + SigBit Q = sigmap(cell->getPort("\\Q").as_bit()); + unused_bits.erase(D); + undriven_bits.erase(Q); + alias_map[Q] = D; + auto r YS_ATTRIBUTE(unused) = ff_bits.insert(std::make_pair(D, cell)); + log_assert(r.second); + continue; } - for (const auto &conn : cell->connections()) { - auto port_wire = inst_module->wire(conn.first); - if (port_wire->port_output) { - arrivals.clear(); - auto it = port_wire->attributes.find("\\abc9_arrival"); - if (it == port_wire->attributes.end()) + if (inst_module) { + auto it = cell->attributes.find("\\abc9_box_seq"); + if (it != cell->attributes.end()) { + int abc9_box_seq = it->second.as_int(); + if (GetSize(box_list) <= abc9_box_seq) + box_list.resize(abc9_box_seq+1); + box_list[abc9_box_seq] = cell; + // Only flop boxes may have arrival times ++ // (all others are combinatorial) + if (!inst_module->get_bool_attribute("\\abc9_flop")) continue; - if (it->second.flags == 0) - arrivals.emplace_back(it->second.as_int()); - else - for (const auto &tok : split_tokens(it->second.decode_string())) - arrivals.push_back(atoi(tok.c_str())); + } + - auto &cell_arrivals = arrival_cache[cell->type]; ++ auto &cell_arrivals = arrivals_cache[cell->type]; + for (const auto &conn : cell->connections()) { ++ auto port_wire = inst_module->wire(conn.first); ++ if (!port_wire->port_output) ++ continue; ++ + auto r = cell_arrivals.insert(conn.first); - auto &arrival = r.first->second; ++ auto &arrivals = r.first->second; + if (r.second) { - auto port_wire = inst_module->wire(conn.first); - if (port_wire->port_output) { - auto it = port_wire->attributes.find("\\abc9_arrival"); - if (it != port_wire->attributes.end()) { - if (it->second.flags != 0) - log_error("Attribute 'abc9_arrival' on port '%s' of module '%s' is not an integer.\n", log_id(port_wire), log_id(cell->type)); - arrival = it->second.as_int(); - } - } ++ auto it = port_wire->attributes.find("\\abc9_arrival"); ++ if (it == port_wire->attributes.end()) ++ continue; ++ if (it->second.flags == 0) ++ arrivals.emplace_back(it->second.as_int()); ++ else ++ for (const auto &tok : split_tokens(it->second.decode_string())) ++ arrivals.push_back(atoi(tok.c_str())); ++ } ++ + if (GetSize(arrivals) > 1 && GetSize(arrivals) != GetSize(port_wire)) + log_error("%s.%s is %d bits wide but abc9_arrival = %s has %d value(s)!\n", log_id(cell->type), log_id(conn.first), + GetSize(port_wire), log_signal(it->second), GetSize(arrivals)); - auto jt = arrivals.begin(); + ++ auto jt = arrivals.begin(); +#ifndef NDEBUG + if (ys_debug(1)) { + static std::set> seen; + if (seen.emplace(cell->type, conn.first).second) log("%s.%s abc9_arrival = %d\n", log_id(cell->type), log_id(conn.first), *jt); + } +#endif - + for (auto bit : sigmap(conn.second)) { + arrival_times[bit] = *jt; + if (arrivals.size() > 1) + jt++; } - if (arrival) - for (auto bit : sigmap(conn.second)) - arrival_times[bit] = arrival; } } } diff --cc passes/techmap/abc9.cc index 1be7519b7,6a296bfe7..5ba87fa88 --- a/passes/techmap/abc9.cc +++ b/passes/techmap/abc9.cc @@@ -165,10 -222,14 +224,18 @@@ struct Abc9Pass : public ScriptPas cleanup = false; continue; } + if (arg == "-box" && argidx+1 < args.size()) { + box_file = args[++argidx]; + continue; + } + if (arg == "-run" && argidx+1 < args.size()) { + size_t pos = args[argidx+1].find(':'); + if (pos == std::string::npos) + break; + run_from = args[++argidx].substr(0, pos); + run_to = args[argidx].substr(pos+1); + continue; + } break; } extra_args(args, argidx, design); @@@ -181,12 -242,11 +248,12 @@@ void script() YS_OVERRIDE { if (check_label("pre")) { + run("abc9_ops -check"); run("scc -set_attr abc9_scc_id {}"); if (help_mode) - run("abc9_ops -break_scc -prep_times -prep_holes [-dff]", "(option for -dff)"); - run("abc9_ops -mark_scc -prep_xaiger [-dff]", "(option for -dff)"); ++ run("abc9_ops -mark_scc -prep_times -prep_xaiger [-dff]", "(option for -dff)"); else - run("abc9_ops -break_scc -prep_times -prep_holes" + std::string(dff_mode ? " -dff" : ""), "(option for -dff)"); - run("abc9_ops -mark_scc -prep_xaiger" + std::string(dff_mode ? " -dff" : ""), "(option for -dff)"); ++ run("abc9_ops -mark_scc -prep_times -prep_xaiger" + std::string(dff_mode ? " -dff" : ""), "(option for -dff)"); run("select -set abc9_holes A:abc9_holes"); run("flatten -wb @abc9_holes"); run("techmap @abc9_holes"); @@@ -200,9 -260,8 +267,9 @@@ if (check_label("map")) { if (help_mode) { run("foreach module in selection"); - run(" abc9_ops -write_box [(-box value)|(null)] /input.box"); ++ run(" abc9_ops -write_box [(-box )|(null)] /input.box"); run(" write_xaiger -map /input.sym /input.xaig"); - run(" abc9_exe -cwd [options]"); + run(" abc9_exe [options] -cwd -box /input.box"); run(" read_aiger -xaiger -wideports -module_name $abc9 -map /input.sym /output.aig"); run(" abc9_ops -reintegrate"); } @@@ -240,8 -297,8 +309,8 @@@ active_design->scratchpad_get_int("write_xaiger.num_inputs"), num_outputs); if (num_outputs) { - run(stringf("%s -cwd %s", exe_cmd.str().c_str(), tempdir_name.c_str())); + run(stringf("%s -cwd %s -box %s/input.box", exe_cmd.str().c_str(), tempdir_name.c_str(), tempdir_name.c_str())); - run(stringf("read_aiger -xaiger -wideports -module_name %s$abc9 -map %s/input.sym %s/output.aig", log_id(mod->name), tempdir_name.c_str(), tempdir_name.c_str())); + run(stringf("read_aiger -xaiger -wideports -module_name %s$abc9 -map %s/input.sym %s/output.aig", log_id(mod), tempdir_name.c_str(), tempdir_name.c_str())); run("abc9_ops -reintegrate"); } else diff --cc passes/techmap/abc9_ops.cc index 7f3bbc7ad,463941b0b..04a54fd63 --- a/passes/techmap/abc9_ops.cc +++ b/passes/techmap/abc9_ops.cc @@@ -35,63 -33,7 +35,63 @@@ inline std::string remap_name(RTLIL::Id return stringf("$abc$%d$%s", map_autoidx, abc9_name.c_str()+1); } +void check(RTLIL::Design *design) +{ + dict box_lookup; + for (auto m : design->modules()) { + auto flop = m->get_bool_attribute(ID(abc9_flop)); + auto it = m->attributes.find(ID(abc9_box_id)); + if (it == m->attributes.end()) { + if (flop) + log_error("Module '%s' contains (* abc9_flop *) but not (* abc9_box_id= *).\n", log_id(m)); + continue; + } + if (m->name.begins_with("$paramod")) + continue; + auto id = it->second.as_int(); + auto r = box_lookup.insert(std::make_pair(stringf("$__boxid%d", id), m->name)); + if (!r.second) + log_error("Module '%s' has the same abc9_box_id = %d value as '%s'.\n", + log_id(m), id, log_id(r.first->second)); + + // Make carry in the last PI, and carry out the last PO + // since ABC requires it this way + IdString carry_in, carry_out; + for (const auto &port_name : m->ports) { + auto w = m->wire(port_name); + log_assert(w); + if (w->get_bool_attribute("\\abc9_carry")) { + if (w->port_input) { + if (carry_in != IdString()) + log_error("Module '%s' contains more than one (* abc9_carry *) input port.\n", log_id(m)); + carry_in = port_name; + } + if (w->port_output) { + if (carry_out != IdString()) + log_error("Module '%s' contains more than one (* abc9_carry *) output port.\n", log_id(m)); + carry_out = port_name; + } + } + } + + if (carry_in != IdString() && carry_out == IdString()) + log_error("Module '%s' contains an (* abc9_carry *) input port but no output port.\n", log_id(m)); + if (carry_in == IdString() && carry_out != IdString()) + log_error("Module '%s' contains an (* abc9_carry *) output port but no input port.\n", log_id(m)); + + if (flop) { + int num_outputs = 0; + for (auto port_name : m->ports) { + auto wire = m->wire(port_name); + if (wire->port_output) num_outputs++; + } + if (num_outputs != 1) + log_error("Module '%s' with (* abc_flop *) has %d outputs (expect 1).\n", log_id(m), num_outputs); + } + } +} + - void break_scc(RTLIL::Module *module) + void mark_scc(RTLIL::Module *module) { // For every unique SCC found, (arbitrarily) find the first // cell in the component, and convert all wires driven by @@@ -648,19 -356,53 +568,21 @@@ void reintegrate(RTLIL::Module *module if (m->name.begins_with("$paramod")) continue; auto id = it->second.as_int(); - auto r = box_lookup.insert(std::make_pair(stringf("$__boxid%d", id), m->name)); - if (!r.second) - log_error("Module '%s' has the same abc9_box_id = %d value as '%s'.\n", - log_id(m), id, log_id(r.first->second)); + auto r YS_ATTRIBUTE(unused) = box_lookup.insert(std::make_pair(stringf("$__boxid%d", id), m->name)); log_assert(r.second); - - auto r2 = box_ports.insert(m->name); - if (r2.second) { - // Make carry in the last PI, and carry out the last PO - // since ABC requires it this way - IdString carry_in, carry_out; - for (const auto &port_name : m->ports) { - auto w = m->wire(port_name); - log_assert(w); - if (w->get_bool_attribute("\\abc9_carry")) { - if (w->port_input) { - if (carry_in != IdString()) - log_error("Module '%s' contains more than one 'abc9_carry' input port.\n", log_id(m)); - carry_in = port_name; - } - if (w->port_output) { - if (carry_out != IdString()) - log_error("Module '%s' contains more than one 'abc9_carry' output port.\n", log_id(m)); - carry_out = port_name; - } - } - else - r2.first->second.push_back(port_name); - } - - if (carry_in != IdString() && carry_out == IdString()) - log_error("Module '%s' contains an 'abc9_carry' input port but no output port.\n", log_id(m)); - if (carry_in == IdString() && carry_out != IdString()) - log_error("Module '%s' contains an 'abc9_carry' output port but no input port.\n", log_id(m)); - if (carry_in != IdString()) { - r2.first->second.push_back(carry_in); - r2.first->second.push_back(carry_out); - } - } } + pool delay_boxes; std::vector boxes; for (auto cell : module->cells().to_vector()) { + if (cell->has_keep_attr()) + continue; if (cell->type.in(ID($_AND_), ID($_NOT_), ID($__ABC9_FF_))) module->remove(cell); + else if (cell->type.begins_with("$paramod$__ABC9_DELAY\\DELAY=")) { + delay_boxes.insert(cell->name); + module->remove(cell); + } else if (cell->attributes.erase("\\abc9_box_seq")) boxes.emplace_back(cell); } @@@ -745,19 -498,11 +669,21 @@@ } if (cell->output(mapped_conn.first)) for (auto i : mapped_conn.second) - bit_drivers[i].insert(mapped_cell->name); + // Ignore inouts for topo ordering + if (i.wire && !(i.wire->port_input && i.wire->port_output)) + bit_drivers[i].insert(mapped_cell->name); } } + else if (delay_boxes.count(mapped_cell->name)) { + SigBit I = mapped_cell->getPort(ID(i)); + SigBit O = mapped_cell->getPort(ID(o)); + if (I.wire) + I.wire = module->wires_.at(remap_name(I.wire->name)); + log_assert(O.wire); + O.wire = module->wires_.at(remap_name(O.wire->name)); + module->connect(O, I); + continue; + } else { RTLIL::Cell *existing_cell = module->cell(mapped_cell->name); log_assert(existing_cell); @@@ -788,33 -533,11 +714,35 @@@ for (const auto &i : inputs) bit_users[i].insert(mapped_cell->name); for (const auto &i : outputs) - bit_drivers[i].insert(mapped_cell->name); + // Ignore inouts for topo ordering + if (i.wire && !(i.wire->port_input && i.wire->port_output)) + bit_drivers[i].insert(mapped_cell->name); } + auto r2 = box_ports.insert(cell->type); + if (r2.second) { + // Make carry in the last PI, and carry out the last PO + // since ABC requires it this way + IdString carry_in, carry_out; + for (const auto &port_name : box_module->ports) { + auto w = box_module->wire(port_name); + log_assert(w); + if (w->get_bool_attribute("\\abc9_carry")) { + if (w->port_input) + carry_in = port_name; + if (w->port_output) + carry_out = port_name; + } + else + r2.first->second.push_back(port_name); + } + + if (carry_in != IdString()) { + r2.first->second.push_back(carry_in); + r2.first->second.push_back(carry_out); + } + } + int input_count = 0, output_count = 0; for (const auto &port_name : box_ports.at(cell->type)) { RTLIL::Wire *w = box_module->wire(port_name); @@@ -1001,50 -757,27 +962,45 @@@ struct Abc9OpsPass : public Pass { log_header(design, "Executing ABC9_OPS pass (helper functions for ABC9).\n"); + bool check_mode = false; + bool prep_times_mode = false; - bool break_scc_mode = false; - bool unbreak_scc_mode = false; - bool prep_holes_mode = false; + bool mark_scc_mode = false; bool prep_dff_mode = false; - std::string write_box_src, write_box_dst; + bool prep_xaiger_mode = false; bool reintegrate_mode = false; bool dff_mode = false; ++ std::string write_box_src, write_box_dst; size_t argidx; for (argidx = 1; argidx < args.size(); argidx++) { std::string arg = args[argidx]; + if (arg == "-check") { + check_mode = true; + continue; + } - if (arg == "-break_scc") { - break_scc_mode = true; - continue; - } - if (arg == "-unbreak_scc") { - unbreak_scc_mode = true; + if (arg == "-mark_scc") { + mark_scc_mode = true; continue; } if (arg == "-prep_dff") { prep_dff_mode = true; continue; } - if (arg == "-prep_holes") { - prep_holes_mode = true; + if (arg == "-prep_xaiger") { + prep_xaiger_mode = true; continue; } + if (arg == "-prep_times") { + prep_times_mode = true; + continue; + } + if (arg == "-write_box" && argidx+2 < args.size()) { + write_box_src = args[++argidx]; + write_box_dst = args[++argidx]; + rewrite_filename(write_box_src); + rewrite_filename(write_box_dst); + continue; + } if (arg == "-reintegrate") { reintegrate_mode = true; continue; @@@ -1057,17 -790,12 +1013,17 @@@ } extra_args(args, argidx, design); - if (!(check_mode || break_scc_mode || unbreak_scc_mode || prep_times_mode || prep_holes_mode || prep_dff_mode || !write_box_src.empty() || reintegrate_mode)) - log_cmd_error("At least one of -check, -{,un}break_scc, -prep_{times,holes,dff}, -write_box, -reintegrate must be specified.\n"); - if (!(mark_scc_mode || prep_dff_mode || reintegrate_mode)) - log_cmd_error("At least one of -mark_scc, -prep_{xaiger,dff}, -reintegrate must be specified.\n"); ++ if (!(check_mode || mark_scc_mode || prep_times_mode || prep_xaiger_mode || prep_dff_mode || !write_box_src.empty() || reintegrate_mode)) ++ log_cmd_error("At least one of -check, -mark_scc, -prep_{times,xaiger,dff}, -write_box, -reintegrate must be specified.\n"); - if (dff_mode && !prep_holes_mode) - log_cmd_error("'-dff' option is only relevant for -prep_holes.\n"); + if (dff_mode && !prep_xaiger_mode) + log_cmd_error("'-dff' option is only relevant for -prep_xaiger.\n"); + if (check_mode) + check(design); + if (prep_times_mode) + prep_times(design); + for (auto mod : design->selected_modules()) { if (mod->get_bool_attribute("\\abc9_holes")) continue; @@@ -1080,16 -808,12 +1036,14 @@@ if (!design->selected_whole_module(mod)) log_error("Can't handle partially selected module %s!\n", log_id(mod)); - if (break_scc_mode) - break_scc(mod); - if (unbreak_scc_mode) - unbreak_scc(mod); - if (prep_holes_mode) - prep_holes(mod, dff_mode); - if (prep_dff_mode) - prep_dff(mod); + if (!write_box_src.empty()) + write_box(mod, write_box_src, write_box_dst); + if (mark_scc_mode) + mark_scc(mod); + if (prep_dff_mode) + prep_dff(mod); + if (prep_xaiger_mode) + prep_xaiger(mod, dff_mode); if (reintegrate_mode) reintegrate(mod); }