From 55a3638c71229e2730e1d0f7340f6c9d4087522d Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Tue, 16 Apr 2019 15:01:45 -0700 Subject: [PATCH] Port from xc7mux branch --- backends/aiger/xaiger.cc | 146 +++++++++++++++++++++++++++++---------- passes/cmds/stat.cc | 3 + passes/techmap/abc9.cc | 72 ++++++++++++++----- 3 files changed, 167 insertions(+), 54 deletions(-) diff --git a/backends/aiger/xaiger.cc b/backends/aiger/xaiger.cc index d3384e136..66ab3878e 100644 --- a/backends/aiger/xaiger.cc +++ b/backends/aiger/xaiger.cc @@ -212,6 +212,9 @@ struct XAigerWriter continue; } + RTLIL::Module* box_module = module->design->module(cell->type); + bool abc_box = box_module && box_module->attributes.count("\\abc_box_id"); + for (const auto &c : cell->connections()) { /*if (c.second.is_fully_const()) continue;*/ for (auto b : c.second.bits()) { @@ -224,20 +227,33 @@ struct XAigerWriter if (I != b) alias_map[b] = I; /*if (!output_bits.count(b))*/ + if (abc_box) co_bits.emplace_back(b, 0); + else if (b.wire) { + output_bits.insert(b); + if (!b.wire->port_input) + unused_bits.erase(b); + } } } if (is_output) { SigBit O = sigmap(b); /*if (!input_bits.count(O))*/ + if (abc_box) ci_bits.emplace_back(O, 0); + else { + input_bits.insert(O); + if (!O.wire->port_output) + undriven_bits.erase(O); + } } } if (!type_map.count(cell->type)) type_map[cell->type] = type_map.size()+1; } - box_list.emplace_back(cell); + if (abc_box) + box_list.emplace_back(cell); //log_warning("Unsupported cell type: %s (%s)\n", log_id(cell->type), log_id(cell)); } @@ -537,49 +553,105 @@ struct XAigerWriter f << "c"; - std::stringstream h_buffer; - auto write_h_buffer = [&h_buffer](int i32) { - // TODO: Don't assume we're on little endian + if (!box_list.empty()) { + std::stringstream h_buffer; + auto write_h_buffer = [&h_buffer](int i32) { + // TODO: Don't assume we're on little endian #ifdef _WIN32 - int i32_be = _byteswap_ulong(i32); + int i32_be = _byteswap_ulong(i32); #else - int i32_be = __builtin_bswap32(i32); + int i32_be = __builtin_bswap32(i32); #endif - h_buffer.write(reinterpret_cast(&i32_be), sizeof(i32_be)); - }; - int num_outputs = output_bits.size(); - if (omode && num_outputs == 0) - num_outputs = 1; - write_h_buffer(1); - write_h_buffer(input_bits.size() + ci_bits.size()); - write_h_buffer(num_outputs + co_bits.size()); - write_h_buffer(input_bits.size()); - write_h_buffer(num_outputs); - write_h_buffer(box_list.size()); - int box_id = 0; - for (auto cell : box_list) { - int box_inputs = 0, box_outputs = 0; - for (const auto &c : cell->connections()) { - if (cell->input(c.first)) - box_inputs += c.second.size(); - if (cell->output(c.first)) - box_outputs += c.second.size(); + h_buffer.write(reinterpret_cast(&i32_be), sizeof(i32_be)); + }; + int num_outputs = output_bits.size(); + if (omode && num_outputs == 0) + num_outputs = 1; + write_h_buffer(1); + write_h_buffer(input_bits.size() + ci_bits.size()); + write_h_buffer(num_outputs + co_bits.size()); + write_h_buffer(input_bits.size()); + write_h_buffer(num_outputs); + write_h_buffer(box_list.size()); + + RTLIL::Module *holes_module = nullptr; + holes_module = module->design->addModule("\\__holes__"); + + for (auto cell : box_list) { + int box_inputs = 0, box_outputs = 0; + int box_id = module->design->module(cell->type)->attributes.at("\\abc_box_id").as_int(); + Cell *holes_cell = nullptr; + if (holes_module && !holes_module->cell(stringf("\\u%d", box_id))) + holes_cell = holes_module->addCell(stringf("\\u%d", box_id), cell->type); + RTLIL::Wire *holes_wire; + int num_inputs = 0; + for (const auto &c : cell->connections()) { + if (cell->input(c.first)) { + box_inputs += c.second.size(); + if (holes_cell) { + holes_wire = holes_module->wire(stringf("\\i%d", num_inputs)); + if (!holes_wire) { + holes_wire = holes_module->addWire(stringf("\\i%d", num_inputs)); + holes_wire->port_input = true; + } + ++num_inputs; + holes_cell->setPort(c.first, holes_wire); + } + } + if (cell->output(c.first)) { + box_outputs += c.second.size(); + if (holes_cell) { + holes_wire = holes_module->addWire(stringf("\\%s.%s", cell->type.c_str(), c.first.c_str())); + holes_wire->port_output = true; + holes_cell->setPort(c.first, holes_wire); + } + } + } + write_h_buffer(box_inputs); + write_h_buffer(box_outputs); + write_h_buffer(box_id); + write_h_buffer(0 /* OldBoxNum */); } - write_h_buffer(box_inputs); - write_h_buffer(box_outputs); - write_h_buffer(box_id++); - write_h_buffer(0 /* OldBoxNum */); - } - std::string h_buffer_str = h_buffer.str(); - // TODO: Don't assume we're on little endian + + f << "h"; + std::string buffer_str = h_buffer.str(); + // TODO: Don't assume we're on little endian #ifdef _WIN32 - int h_buffer_size_be = _byteswap_ulong(h_buffer_str.size()); + int buffer_size_be = _byteswap_ulong(buffer_str.size()); #else - int h_buffer_size_be = __builtin_bswap32(h_buffer_str.size()); + int buffer_size_be = __builtin_bswap32(buffer_str.size()); #endif - f << "h"; - f.write(reinterpret_cast(&h_buffer_size_be), sizeof(h_buffer_size_be)); - f.write(h_buffer_str.data(), h_buffer_str.size()); + f.write(reinterpret_cast(&buffer_size_be), sizeof(buffer_size_be)); + f.write(buffer_str.data(), buffer_str.size()); + + if (holes_module) { + holes_module->fixup_ports(); + + holes_module->design->selection_stack.emplace_back(false); + RTLIL::Selection& sel = holes_module->design->selection_stack.back(); + sel.select(holes_module); + + Pass::call(holes_module->design, "flatten; aigmap"); + + holes_module->design->selection_stack.pop_back(); + + std::stringstream a_buffer; + XAigerWriter writer(holes_module, false /*zinit_mode*/, false /*imode*/, false /*omode*/, false /*bmode*/); + writer.write_aiger(a_buffer, false /*ascii_mode*/, false /*miter_mode*/, false /*symbols_mode*/, false /*omode*/); + + f << "a"; + std::string buffer_str = a_buffer.str(); + // TODO: Don't assume we're on little endian +#ifdef _WIN32 + int buffer_size_be = _byteswap_ulong(buffer_str.size()); +#else + int buffer_size_be = __builtin_bswap32(buffer_str.size()); +#endif + f.write(reinterpret_cast(&buffer_size_be), sizeof(buffer_size_be)); + f.write(buffer_str.data(), buffer_str.size()); + holes_module->design->remove(holes_module); + } + } f << stringf("Generated by %s\n", yosys_version_str); } diff --git a/passes/cmds/stat.cc b/passes/cmds/stat.cc index 54f4ea817..3909c4c8c 100644 --- a/passes/cmds/stat.cc +++ b/passes/cmds/stat.cc @@ -269,6 +269,9 @@ struct StatPass : public Pass { if (mod->get_bool_attribute("\\top")) top_mod = mod; + if (mod->attributes.count("\\abc_box_id")) + continue; + statdata_t data(design, mod, width_mode, cell_area); mod_stat[mod->name] = data; diff --git a/passes/techmap/abc9.cc b/passes/techmap/abc9.cc index 3c4919b1f..b14eef485 100644 --- a/passes/techmap/abc9.cc +++ b/passes/techmap/abc9.cc @@ -272,7 +272,7 @@ failed: void abc9_module(RTLIL::Design *design, RTLIL::Module *current_module, std::string script_file, std::string exe_file, std::string liberty_file, std::string constr_file, bool cleanup, vector lut_costs, bool dff_mode, std::string clk_str, bool keepff, std::string delay_target, std::string sop_inputs, std::string sop_products, std::string lutin_shared, bool fast_mode, - const std::vector &cells, bool show_tempdir, bool sop_mode) + const std::vector &cells, bool show_tempdir, bool sop_mode, std::string box_file, std::string lut_file) { module = current_module; map_autoidx = autoidx++; @@ -322,18 +322,29 @@ void abc9_module(RTLIL::Design *design, RTLIL::Module *current_module, std::stri log_header(design, "Extracting gate netlist of module `%s' to `%s/input.xaig'..\n", module->name.c_str(), replace_tempdir(tempdir_name, tempdir_name, show_tempdir).c_str()); - std::string abc_script = stringf("&read %s/input.xaig; &ps ", tempdir_name.c_str()); + std::string abc_script; if (!liberty_file.empty()) { abc_script += stringf("read_lib -w %s; ", liberty_file.c_str()); if (!constr_file.empty()) abc_script += stringf("read_constr -v %s; ", constr_file.c_str()); } else - if (!lut_costs.empty()) + if (!lut_costs.empty()) { abc_script += stringf("read_lut %s/lutdefs.txt; ", tempdir_name.c_str()); + if (!box_file.empty()) + abc_script += stringf("read_box -v %s; ", box_file.c_str()); + } + else + if (!lut_file.empty()) { + abc_script += stringf("read_lut %s; ", lut_file.c_str()); + if (!box_file.empty()) + abc_script += stringf("read_box -v %s; ", box_file.c_str()); + } else abc_script += stringf("read_library %s/stdcells.genlib; ", tempdir_name.c_str()); + abc_script += stringf("&read %s/input.xaig; &ps ", tempdir_name.c_str()); + if (!script_file.empty()) { if (script_file[0] == '+') { for (size_t i = 1; i < script_file.size(); i++) @@ -345,11 +356,11 @@ void abc9_module(RTLIL::Design *design, RTLIL::Module *current_module, std::stri abc_script += script_file[i]; } else abc_script += stringf("source %s", script_file.c_str()); - } else if (!lut_costs.empty()) { - bool all_luts_cost_same = true; - for (int this_cost : lut_costs) - if (this_cost != lut_costs.front()) - all_luts_cost_same = false; + } else if (!lut_costs.empty() || !lut_file.empty()) { + //bool all_luts_cost_same = true; + //for (int this_cost : lut_costs) + // if (this_cost != lut_costs.front()) + // all_luts_cost_same = false; abc_script += fast_mode ? ABC_FAST_COMMAND_LUT : ABC_COMMAND_LUT; //if (all_luts_cost_same && !fast_mode) // abc_script += "; lutpack {S}"; @@ -576,7 +587,7 @@ void abc9_module(RTLIL::Design *design, RTLIL::Module *current_module, std::stri RTLIL::Cell *cell; RTLIL::SigBit a_bit = c->getPort("\\A").as_bit(); RTLIL::SigBit y_bit = c->getPort("\\Y").as_bit(); - if (!lut_costs.empty()) { + if (!lut_costs.empty() || !lut_file.empty()) { // ABC can return NOT gates that drive POs if (a_bit.wire->port_input) { // If it's a NOT gate that comes from a primary input directly @@ -1004,7 +1015,7 @@ struct Abc9Pass : public Pass { log(" file format).\n"); log("\n"); log(" -constr \n"); - log(" pass this file with timing constraints to ABC. use with -liberty.\n"); + log(" pass this file with timing constraints to ABC. Use with -liberty.\n"); log("\n"); log(" a constr file contains two lines:\n"); log(" set_driving_cell \n"); @@ -1041,6 +1052,9 @@ struct Abc9Pass : public Pass { log(" the area cost doubles with each additional input bit. the delay cost\n"); log(" is still constant for all lut widths.\n"); log("\n"); + log(" -lut \n"); + log(" pass this file with lut library to ABC.\n"); + log("\n"); log(" -luts ,,,:,..\n"); log(" generate netlist using luts. Use the specified costs for luts with 1,\n"); log(" 2, 3, .. inputs.\n"); @@ -1094,6 +1108,9 @@ struct Abc9Pass : public Pass { log(" this attribute is a unique integer for each ABC process started. This\n"); log(" is useful for debugging the partitioning of clock domains.\n"); log("\n"); + log(" -box \n"); + log(" pass this file with box library to ABC. Use with -lut.\n"); + log("\n"); log("When neither -liberty nor -lut is used, the Yosys standard cell library is\n"); log("loaded into ABC before the ABC script is executed.\n"); log("\n"); @@ -1123,7 +1140,7 @@ struct Abc9Pass : public Pass { #else std::string exe_file = proc_self_dirname() + "yosys-abc"; #endif - std::string script_file, liberty_file, constr_file, clk_str; + std::string script_file, liberty_file, constr_file, clk_str, box_file, lut_file; std::string delay_target, sop_inputs, sop_products, lutin_shared = "-S 1"; bool fast_mode = false, dff_mode = false, keepff = false, cleanup = true; bool show_tempdir = false, sop_mode = false; @@ -1169,8 +1186,8 @@ struct Abc9Pass : public Pass { continue; } if (arg == "-constr" && argidx+1 < args.size()) { - rewrite_filename(constr_file); constr_file = args[++argidx]; + rewrite_filename(constr_file); if (!constr_file.empty() && !is_absolute_path(constr_file)) constr_file = std::string(pwd) + "/" + constr_file; continue; @@ -1199,8 +1216,17 @@ struct Abc9Pass : public Pass { lut_mode = atoi(arg.substr(0, pos).c_str()); lut_mode2 = atoi(arg.substr(pos+1).c_str()); } else { - lut_mode = atoi(arg.c_str()); - lut_mode2 = lut_mode; + pos = arg.find_first_of('.'); + if (pos != string::npos) { + lut_file = arg; + rewrite_filename(lut_file); + if (!lut_file.empty() && !is_absolute_path(lut_file)) + lut_file = std::string(pwd) + "/" + lut_file; + } + else { + lut_mode = atoi(arg.c_str()); + lut_mode2 = lut_mode; + } } lut_costs.clear(); for (int i = 0; i < lut_mode; i++) @@ -1357,11 +1383,18 @@ struct Abc9Pass : public Pass { markgroups = true; continue; } + if (arg == "-box" && argidx+1 < args.size()) { + box_file = args[++argidx]; + rewrite_filename(box_file); + if (!box_file.empty() && !is_absolute_path(box_file)) + box_file = std::string(pwd) + "/" + box_file; + continue; + } break; } extra_args(args, argidx, design); - if (!lut_costs.empty() && !liberty_file.empty()) + if ((!lut_costs.empty() || !lut_file.empty()) && !liberty_file.empty()) log_cmd_error("Got -lut and -liberty! This two options are exclusive.\n"); if (!constr_file.empty() && liberty_file.empty()) log_cmd_error("Got -constr but no -liberty!\n"); @@ -1373,6 +1406,9 @@ struct Abc9Pass : public Pass { continue; } + if (mod->attributes.count("\\abc_box_id")) + continue; + assign_map.set(mod); signal_init.clear(); @@ -1395,7 +1431,8 @@ struct Abc9Pass : public Pass { if (!dff_mode || !clk_str.empty()) { abc9_module(design, mod, script_file, exe_file, liberty_file, constr_file, cleanup, lut_costs, dff_mode, clk_str, keepff, - delay_target, sop_inputs, sop_products, lutin_shared, fast_mode, mod->selected_cells(), show_tempdir, sop_mode); + delay_target, sop_inputs, sop_products, lutin_shared, fast_mode, mod->selected_cells(), show_tempdir, sop_mode, + box_file, lut_file); continue; } @@ -1540,7 +1577,8 @@ struct Abc9Pass : public Pass { en_polarity = std::get<2>(it.first); en_sig = assign_map(std::get<3>(it.first)); abc9_module(design, mod, script_file, exe_file, liberty_file, constr_file, cleanup, lut_costs, !clk_sig.empty(), "$", - keepff, delay_target, sop_inputs, sop_products, lutin_shared, fast_mode, it.second, show_tempdir, sop_mode); + keepff, delay_target, sop_inputs, sop_products, lutin_shared, fast_mode, it.second, show_tempdir, sop_mode, + box_file, lut_file); assign_map.set(mod); } } -- 2.30.2