| #include "read_circuit.h" |
| #include "read_blif.h" |
| #include "atom_netlist.h" |
| #include "atom_netlist_utils.h" |
| #include "echo_files.h" |
| |
| #include "vtr_assert.h" |
| #include "vtr_log.h" |
| #include "vtr_util.h" |
| #include "vtr_path.h" |
| #include "vtr_time.h" |
| |
| static void process_circuit(AtomNetlist& netlist, |
| e_const_gen_inference const_gen_inference_method, |
| bool should_absorb_buffers, |
| bool should_sweep_dangling_primary_ios, |
| bool should_sweep_dangling_nets, |
| bool should_sweep_dangling_blocks, |
| bool should_sweep_constant_primary_outputs, |
| int verbosity); |
| |
| static void show_circuit_stats(const AtomNetlist& netlist); |
| |
| AtomNetlist read_and_process_circuit(e_circuit_format circuit_format, |
| const char* circuit_file, |
| const t_model* user_models, |
| const t_model* library_models, |
| e_const_gen_inference const_gen_inference, |
| bool should_absorb_buffers, |
| bool should_sweep_dangling_primary_ios, |
| bool should_sweep_dangling_nets, |
| bool should_sweep_dangling_blocks, |
| bool should_sweep_constant_primary_outputs, |
| int verbosity) { |
| if (circuit_format == e_circuit_format::AUTO) { |
| auto name_ext = vtr::split_ext(circuit_file); |
| |
| if (name_ext[1] == ".blif") { |
| circuit_format = e_circuit_format::BLIF; |
| } else if (name_ext[1] == ".eblif") { |
| circuit_format = e_circuit_format::EBLIF; |
| } else { |
| VPR_FATAL_ERROR(VPR_ERROR_ATOM_NETLIST, "Failed to determine file format for '%s' expected .blif or .eblif extension", |
| circuit_file); |
| } |
| } |
| |
| AtomNetlist netlist; |
| { |
| vtr::ScopedStartFinishTimer t("Load circuit"); |
| |
| VTR_ASSERT(circuit_format == e_circuit_format::BLIF |
| || circuit_format == e_circuit_format::EBLIF); |
| |
| netlist = read_blif(circuit_format, circuit_file, user_models, library_models); |
| } |
| |
| if (isEchoFileEnabled(E_ECHO_ATOM_NETLIST_ORIG)) { |
| print_netlist_as_blif(getEchoFileName(E_ECHO_ATOM_NETLIST_ORIG), netlist); |
| } |
| |
| process_circuit(netlist, |
| const_gen_inference, |
| should_absorb_buffers, |
| should_sweep_dangling_primary_ios, |
| should_sweep_dangling_nets, |
| should_sweep_dangling_blocks, |
| should_sweep_constant_primary_outputs, |
| verbosity); |
| |
| if (isEchoFileEnabled(E_ECHO_ATOM_NETLIST_CLEANED)) { |
| print_netlist_as_blif(getEchoFileName(E_ECHO_ATOM_NETLIST_CLEANED), netlist); |
| } |
| |
| show_circuit_stats(netlist); |
| |
| return netlist; |
| } |
| |
| static void process_circuit(AtomNetlist& netlist, |
| e_const_gen_inference const_gen_inference_method, |
| bool should_absorb_buffers, |
| bool should_sweep_dangling_primary_ios, |
| bool should_sweep_dangling_nets, |
| bool should_sweep_dangling_blocks, |
| bool should_sweep_constant_primary_outputs, |
| int verbosity) { |
| { |
| vtr::ScopedStartFinishTimer t("Clean circuit"); |
| |
| //Clean-up lut buffers |
| if (should_absorb_buffers) { |
| absorb_buffer_luts(netlist, verbosity); |
| } |
| |
| //Remove the special 'unconn' net |
| AtomNetId unconn_net_id = netlist.find_net("unconn"); |
| if (unconn_net_id) { |
| VTR_LOGV_WARN(verbosity > 1, "Removing special net 'unconn' (assumed it represented explicitly unconnected pins)\n"); |
| netlist.remove_net(unconn_net_id); |
| } |
| |
| //Also remove the 'unconn' block driver, if it exists |
| AtomBlockId unconn_blk_id = netlist.find_block("unconn"); |
| if (unconn_blk_id) { |
| VTR_LOGV_WARN(verbosity > 1, "Removing special block 'unconn' (assumed it represented explicitly unconnected pins)\n"); |
| netlist.remove_block(unconn_blk_id); |
| } |
| |
| //Sweep unused logic/nets/inputs/outputs |
| sweep_iterative(netlist, |
| should_sweep_dangling_primary_ios, |
| should_sweep_dangling_nets, |
| should_sweep_dangling_blocks, |
| should_sweep_constant_primary_outputs, |
| const_gen_inference_method, |
| verbosity); |
| } |
| |
| { |
| vtr::ScopedStartFinishTimer t("Compress circuit"); |
| |
| //Compress the netlist to clean-out invalid entries |
| netlist.remove_and_compress(); |
| } |
| { |
| vtr::ScopedStartFinishTimer t("Verify circuit"); |
| |
| netlist.verify(); |
| } |
| } |
| |
| static void show_circuit_stats(const AtomNetlist& netlist) { |
| std::map<std::string, size_t> block_type_counts; |
| |
| //Count the block statistics |
| for (auto blk_id : netlist.blocks()) { |
| const t_model* blk_model = netlist.block_model(blk_id); |
| if (blk_model->name == std::string(MODEL_NAMES)) { |
| //LUT |
| size_t lut_size = 0; |
| auto in_ports = netlist.block_input_ports(blk_id); |
| |
| //May have zero (no input LUT) or one input port |
| if (in_ports.size() == 1) { |
| auto port_id = *in_ports.begin(); |
| |
| //Figure out the LUT size |
| lut_size = netlist.port_width(port_id); |
| |
| } else { |
| VTR_ASSERT(in_ports.size() == 0); |
| } |
| |
| ++block_type_counts[std::to_string(lut_size) + "-LUT"]; |
| } else { |
| //Other types |
| ++block_type_counts[blk_model->name]; |
| } |
| } |
| //Count the net statistics |
| std::map<std::string, double> net_stats; |
| for (auto net_id : netlist.nets()) { |
| double fanout = netlist.net_sinks(net_id).size(); |
| |
| net_stats["Max Fanout"] = std::max(net_stats["Max Fanout"], fanout); |
| |
| if (net_stats.count("Min Fanout")) { |
| net_stats["Min Fanout"] = std::min(net_stats["Min Fanout"], fanout); |
| } else { |
| net_stats["Min Fanout"] = fanout; |
| } |
| |
| net_stats["Avg Fanout"] += fanout; |
| } |
| net_stats["Avg Fanout"] /= netlist.nets().size(); |
| |
| //Determine the maximum length of a type name for nice formatting |
| size_t max_block_type_len = 0; |
| for (auto kv : block_type_counts) { |
| max_block_type_len = std::max(max_block_type_len, kv.first.size()); |
| } |
| size_t max_net_type_len = 0; |
| for (auto kv : net_stats) { |
| max_net_type_len = std::max(max_net_type_len, kv.first.size()); |
| } |
| |
| //Print the statistics |
| VTR_LOG("Circuit Statistics:\n"); |
| VTR_LOG(" Blocks: %zu\n", netlist.blocks().size()); |
| for (auto kv : block_type_counts) { |
| VTR_LOG(" %-*s: %7zu\n", max_block_type_len, kv.first.c_str(), kv.second); |
| } |
| VTR_LOG(" Nets : %zu\n", netlist.nets().size()); |
| for (auto kv : net_stats) { |
| VTR_LOG(" %-*s: %7.1f\n", max_net_type_len, kv.first.c_str(), kv.second); |
| } |
| VTR_LOG(" Netlist Clocks: %zu\n", find_netlist_logical_clock_drivers(netlist).size()); |
| |
| if (netlist.blocks().empty()) { |
| VTR_LOG_WARN("Netlist contains no blocks\n"); |
| } |
| } |