diff --git a/libopenfpga/libbusgroup/src/bus_group.cpp b/libopenfpga/libbusgroup/src/bus_group.cpp index 403888c75..71a433793 100644 --- a/libopenfpga/libbusgroup/src/bus_group.cpp +++ b/libopenfpga/libbusgroup/src/bus_group.cpp @@ -48,6 +48,27 @@ std::string BusGroup::pin_name(const BusPinId& pin_id) const { return pin_names_[pin_id]; } +BusGroupId BusGroup::find_pin_bus(const std::string& pin_name) const { + std::map::const_iterator result = pin_name2id_map_.find(pin_name); + if (result == pin_name2id_map_.end()) { + /* Not found, return an invalid id */ + return BusGroupId::INVALID(); + } + /* Found, we should get the parent bus */ + BusPinId pin_id = result->second; + return pin_parent_bus_ids_[pin_id]; +} + +BusPinId BusGroup::find_pin(const std::string& pin_name) const { + std::map::const_iterator result = pin_name2id_map_.find(pin_name); + if (result == pin_name2id_map_.end()) { + /* Not found, return an invalid id */ + return BusPinId::INVALID(); + } + /* Found, we should get the parent bus */ + return result->second; +} + bool BusGroup::empty() const { return 0 == bus_ids_.size(); } @@ -65,6 +86,7 @@ void BusGroup::reserve_pins(const size_t& num_pins) { pin_ids_.reserve(num_pins); pin_indices_.reserve(num_pins); pin_names_.reserve(num_pins); + pin_parent_bus_ids_.reserve(num_pins); } BusGroupId BusGroup::create_bus(const openfpga::BasicPort& bus_port) { @@ -89,8 +111,9 @@ BusPinId BusGroup::create_pin(const BusGroupId& bus_id) { /* Register the pin to the bus */ VTR_ASSERT(valid_bus_id(bus_id)); + pin_parent_bus_ids_.push_back(bus_id); bus_pin_ids_[bus_id].push_back(pin_id); - + return pin_id; } @@ -102,6 +125,15 @@ void BusGroup::set_pin_index(const BusPinId& pin_id, const int& index) { void BusGroup::set_pin_name(const BusPinId& pin_id, const std::string& name) { VTR_ASSERT(valid_pin_id(pin_id)); pin_names_[pin_id] = name; + + /* Register to fast look-up */ + auto result = pin_name2id_map_.find(name); + if (result == pin_name2id_map_.end()) { + pin_name2id_map_[name] = pin_id; + } else { + VTR_LOG_ERROR("Duplicated pin name '%s' in bus group", name.c_str()); + exit(1); + } } /************************************************************************ diff --git a/libopenfpga/libbusgroup/src/bus_group.h b/libopenfpga/libbusgroup/src/bus_group.h index bb7187fb5..d849f5fd3 100644 --- a/libopenfpga/libbusgroup/src/bus_group.h +++ b/libopenfpga/libbusgroup/src/bus_group.h @@ -59,6 +59,12 @@ class BusGroup { /* Get the name of a pin */ std::string pin_name(const BusPinId& pin_id) const; + /* Find the bus that a pin belongs to */ + BusGroupId find_pin_bus(const std::string& pin_name) const; + + /* Find the pin id with a given name */ + BusPinId find_pin(const std::string& pin_name) const; + /* Check if there are any buses */ bool empty() const; @@ -106,6 +112,12 @@ class BusGroup { /* Name of each pin under each bus */ vtr::vector pin_names_; + + /* Parent bus of each pin */ + vtr::vector pin_parent_bus_ids_; + + /* Fast look-up */ + std::map pin_name2id_map_; }; } // End of namespace openfpga diff --git a/openfpga/src/base/openfpga_verilog.cpp b/openfpga/src/base/openfpga_verilog.cpp index 7569a14bf..91412be31 100644 --- a/openfpga/src/base/openfpga_verilog.cpp +++ b/openfpga/src/base/openfpga_verilog.cpp @@ -17,6 +17,9 @@ /* Headers from pcf library */ #include "read_xml_pin_constraints.h" +/* Headers from bgf library */ +#include "read_xml_bus_group.h" + /* Include global variables of VPR */ #include "globals.h" @@ -79,6 +82,7 @@ int write_full_testbench(const OpenfpgaContext& openfpga_ctx, CommandOptionId opt_bitstream = cmd.option("bitstream"); CommandOptionId opt_fabric_netlist = cmd.option("fabric_netlist_file_path"); CommandOptionId opt_pcf = cmd.option("pin_constraints_file"); + CommandOptionId opt_bgf = cmd.option("bus_group_file"); CommandOptionId opt_reference_benchmark = cmd.option("reference_benchmark_file_path"); CommandOptionId opt_fast_configuration = cmd.option("fast_configuration"); CommandOptionId opt_explicit_port_mapping = cmd.option("explicit_port_mapping"); @@ -111,6 +115,12 @@ int write_full_testbench(const OpenfpgaContext& openfpga_ctx, if (true == cmd_context.option_enable(cmd, opt_pcf)) { pin_constraints = read_xml_pin_constraints(cmd_context.option_value(cmd, opt_pcf).c_str()); } + + /* If bug group file are enabled by command options, read the file */ + BusGroup bus_group; + if (true == cmd_context.option_enable(cmd, opt_bgf)) { + bus_group = read_xml_bus_group(cmd_context.option_value(cmd, opt_bgf).c_str()); + } return fpga_verilog_full_testbench(openfpga_ctx.module_graph(), openfpga_ctx.bitstream_manager(), @@ -119,6 +129,7 @@ int write_full_testbench(const OpenfpgaContext& openfpga_ctx, g_vpr_ctx.atom(), g_vpr_ctx.placement(), pin_constraints, + bus_group, cmd_context.option_value(cmd, opt_bitstream), openfpga_ctx.io_location_map(), openfpga_ctx.fabric_global_port_info(), @@ -138,6 +149,7 @@ int write_preconfigured_fabric_wrapper(const OpenfpgaContext& openfpga_ctx, CommandOptionId opt_output_dir = cmd.option("file"); CommandOptionId opt_fabric_netlist = cmd.option("fabric_netlist_file_path"); CommandOptionId opt_pcf = cmd.option("pin_constraints_file"); + CommandOptionId opt_bgf = cmd.option("bus_group_file"); CommandOptionId opt_explicit_port_mapping = cmd.option("explicit_port_mapping"); CommandOptionId opt_default_net_type = cmd.option("default_net_type"); CommandOptionId opt_include_signal_init = cmd.option("include_signal_init"); @@ -170,12 +182,19 @@ int write_preconfigured_fabric_wrapper(const OpenfpgaContext& openfpga_ctx, if (true == cmd_context.option_enable(cmd, opt_pcf)) { pin_constraints = read_xml_pin_constraints(cmd_context.option_value(cmd, opt_pcf).c_str()); } + + /* If bug group file are enabled by command options, read the file */ + BusGroup bus_group; + if (true == cmd_context.option_enable(cmd, opt_bgf)) { + bus_group = read_xml_bus_group(cmd_context.option_value(cmd, opt_bgf).c_str()); + } return fpga_verilog_preconfigured_fabric_wrapper(openfpga_ctx.module_graph(), openfpga_ctx.bitstream_manager(), g_vpr_ctx.atom(), g_vpr_ctx.placement(), pin_constraints, + bus_group, openfpga_ctx.io_location_map(), openfpga_ctx.fabric_global_port_info(), openfpga_ctx.vpr_netlist_annotation(), diff --git a/openfpga/src/base/openfpga_verilog_command.cpp b/openfpga/src/base/openfpga_verilog_command.cpp index 9d0f58eef..fc648e095 100644 --- a/openfpga/src/base/openfpga_verilog_command.cpp +++ b/openfpga/src/base/openfpga_verilog_command.cpp @@ -89,6 +89,11 @@ ShellCommandId add_openfpga_write_full_testbench_command(openfpga::Shell port_type2type_map; port_type2type_map[AtomBlockType::INPAD] = VERILOG_PORT_INPUT; port_type2type_map[AtomBlockType::OUTPAD] = VERILOG_PORT_OUTPUT; + /* Ports to be added, this is to avoid any bus port */ + std::vector port_list; + std::vector port_types; + /* Print all the I/Os of the circuit implementation to be tested*/ for (const AtomBlockId &atom_blk : atom_ctx.nlist.blocks()) { /* We only care I/O logical blocks !*/ @@ -62,11 +64,28 @@ void print_verilog_preconfig_top_module_ports(std::fstream &fp, continue; } - /* The block may be renamed as it contains special characters which violate Verilog syntax */ std::string block_name = atom_ctx.nlist.block_name(atom_blk); + /* If the pin is part of a bus, + * - Check if the bus is already in the list + * - If not, add it to the port list + * - If yes, do nothing and move onto the next port + * If the pin does not belong to any bus + * - Add it to the bus port + */ + BusGroupId bus_id = bus_group.find_pin_bus(block_name); + if (bus_id) { + if (port_list.end() == std::find(port_list.begin(), port_list.end(), bus_group.bus_port(bus_id))) { + port_list.push_back(bus_group.bus_port(bus_id)); + port_types.push_back(atom_ctx.nlist.block_type(atom_blk)); + } + continue; + } + + /* The block may be renamed as it contains special characters which violate Verilog syntax */ if (true == netlist_annotation.is_block_renamed(atom_blk)) { block_name = netlist_annotation.block_name(atom_blk); } + /* For output block, remove the prefix which is added by VPR */ std::vector output_port_prefix_to_remove; output_port_prefix_to_remove.push_back(std::string(VPR_BENCHMARK_OUT_PORT_PREFIX)); @@ -82,12 +101,22 @@ void print_verilog_preconfig_top_module_ports(std::fstream &fp, } } + /* Both input and output ports have only size of 1 */ + BasicPort module_port(std::string(block_name), 1); + port_list.push_back(module_port); + port_types.push_back(atom_ctx.nlist.block_type(atom_blk)); + } + + /* After collecting all the ports, now print the port mapping */ + size_t port_counter = 0; + for (size_t iport = 0; iport < port_list.size(); ++iport) { + BasicPort module_port = port_list[iport]; + AtomBlockType port_type = port_types[iport]; if (0 < port_counter) { fp << "," << std::endl; } - /* Both input and output ports have only size of 1 */ - BasicPort module_port(std::string(block_name), 1); - fp << generate_verilog_port(port_type2type_map[atom_ctx.nlist.block_type(atom_blk)], module_port); + + fp << generate_verilog_port(port_type2type_map[port_type], module_port); /* Update port counter */ port_counter++; @@ -434,6 +463,7 @@ int print_verilog_preconfig_top_module(const ModuleManager &module_manager, const AtomContext &atom_ctx, const PlacementContext &place_ctx, const PinConstraints& pin_constraints, + const BusGroup& bus_group, const IoLocationMap &io_location_map, const VprNetlistAnnotation &netlist_annotation, const std::string &circuit_name, @@ -461,7 +491,7 @@ int print_verilog_preconfig_top_module(const ModuleManager &module_manager, options.default_net_type()); /* Print module declaration and ports */ - print_verilog_preconfig_top_module_ports(fp, circuit_name, atom_ctx, netlist_annotation); + print_verilog_preconfig_top_module_ports(fp, circuit_name, atom_ctx, netlist_annotation, bus_group); /* Find the top_module */ ModuleId top_module = module_manager.find_module(generate_fpga_top_module_name()); @@ -494,6 +524,7 @@ int print_verilog_preconfig_top_module(const ModuleManager &module_manager, print_verilog_testbench_connect_fpga_ios(fp, module_manager, top_module, atom_ctx, place_ctx, io_location_map, netlist_annotation, + bus_group, std::string(FORMAL_VERIFICATION_TOP_MODULE_PORT_POSTFIX), std::string(), std::string(), diff --git a/openfpga/src/fpga_verilog/verilog_preconfig_top_module.h b/openfpga/src/fpga_verilog/verilog_preconfig_top_module.h index 01bb12f08..39e1d9f28 100644 --- a/openfpga/src/fpga_verilog/verilog_preconfig_top_module.h +++ b/openfpga/src/fpga_verilog/verilog_preconfig_top_module.h @@ -14,6 +14,7 @@ #include "io_location_map.h" #include "fabric_global_port_info.h" #include "config_protocol.h" +#include "bus_group.h" #include "vpr_netlist_annotation.h" #include "verilog_testbench_options.h" @@ -32,6 +33,7 @@ int print_verilog_preconfig_top_module(const ModuleManager& module_manager, const AtomContext& atom_ctx, const PlacementContext& place_ctx, const PinConstraints& pin_constraints, + const BusGroup& bus_group, const IoLocationMap& io_location_map, const VprNetlistAnnotation& netlist_annotation, const std::string& circuit_name, diff --git a/openfpga/src/fpga_verilog/verilog_testbench_utils.cpp b/openfpga/src/fpga_verilog/verilog_testbench_utils.cpp index 899d6b014..537098a68 100644 --- a/openfpga/src/fpga_verilog/verilog_testbench_utils.cpp +++ b/openfpga/src/fpga_verilog/verilog_testbench_utils.cpp @@ -177,6 +177,7 @@ void print_verilog_testbench_connect_fpga_ios(std::fstream& fp, const PlacementContext& place_ctx, const IoLocationMap& io_location_map, const VprNetlistAnnotation& netlist_annotation, + const BusGroup& bus_group, const std::string& net_name_postfix, const std::string& io_input_port_name_postfix, const std::string& io_output_port_name_postfix, @@ -285,11 +286,24 @@ void print_verilog_testbench_connect_fpga_ios(std::fstream& fp, } } + /* Create the port for benchmark I/O, due to BLIF benchmark, each I/O always has a size of 1 * In addition, the input and output ports may have different postfix in naming * due to verification context! Here, we give full customization on naming */ BasicPort benchmark_io_port; + + /* If this benchmark pin belongs to any bus group, use the bus pin instead */ + BusGroupId bus_id = bus_group.find_pin_bus(block_name); + BusPinId bus_pin_id = bus_group.find_pin(block_name); + if (bus_id) { + block_name = bus_group.bus_port(bus_id).get_name(); + VTR_ASSERT_SAFE(bus_pin_id); + benchmark_io_port.set_width(bus_group.pin_index(bus_pin_id), bus_group.pin_index(bus_pin_id)); + } else { + benchmark_io_port.set_width(1); + } + if (AtomBlockType::INPAD == atom_ctx.nlist.block_type(atom_blk)) { /* If the port is a clock, do not add a postfix */ if (clock_port_names.end() != std::find(clock_port_names.begin(), clock_port_names.end(), block_name)) { @@ -297,13 +311,11 @@ void print_verilog_testbench_connect_fpga_ios(std::fstream& fp, } else { benchmark_io_port.set_name(std::string(block_name + io_input_port_name_postfix)); } - benchmark_io_port.set_width(1); print_verilog_comment(fp, std::string("----- Blif Benchmark input " + block_name + " is mapped to FPGA IOPAD " + module_mapped_io_port.get_name() + "[" + std::to_string(io_index) + "] -----")); print_verilog_wire_connection(fp, module_mapped_io_port, benchmark_io_port, false); } else { VTR_ASSERT(AtomBlockType::OUTPAD == atom_ctx.nlist.block_type(atom_blk)); benchmark_io_port.set_name(std::string(block_name + io_output_port_name_postfix)); - benchmark_io_port.set_width(1); print_verilog_comment(fp, std::string("----- Blif Benchmark output " + block_name + " is mapped to FPGA IOPAD " + module_mapped_io_port.get_name() + "[" + std::to_string(io_index) + "] -----")); print_verilog_wire_connection(fp, benchmark_io_port, module_mapped_io_port, false); } diff --git a/openfpga/src/fpga_verilog/verilog_testbench_utils.h b/openfpga/src/fpga_verilog/verilog_testbench_utils.h index 44816e85b..1a6c106c0 100644 --- a/openfpga/src/fpga_verilog/verilog_testbench_utils.h +++ b/openfpga/src/fpga_verilog/verilog_testbench_utils.h @@ -17,6 +17,7 @@ #include "simulation_setting.h" #include "fabric_global_port_info.h" #include "pin_constraints.h" +#include "bus_group.h" /******************************************************************** * Function declaration @@ -53,6 +54,7 @@ void print_verilog_testbench_connect_fpga_ios(std::fstream& fp, const PlacementContext& place_ctx, const IoLocationMap& io_location_map, const VprNetlistAnnotation& netlist_annotation, + const BusGroup& bus_group, const std::string& net_name_postfix, const std::string& io_input_port_name_postfix, const std::string& io_output_port_name_postfix, diff --git a/openfpga/src/fpga_verilog/verilog_top_testbench.cpp b/openfpga/src/fpga_verilog/verilog_top_testbench.cpp index d668cb997..ed59bd05f 100644 --- a/openfpga/src/fpga_verilog/verilog_top_testbench.cpp +++ b/openfpga/src/fpga_verilog/verilog_top_testbench.cpp @@ -1924,6 +1924,7 @@ int print_verilog_full_testbench(const ModuleManager& module_manager, const AtomContext& atom_ctx, const PlacementContext& place_ctx, const PinConstraints& pin_constraints, + const BusGroup& bus_group, const std::string& bitstream_file, const IoLocationMap& io_location_map, const VprNetlistAnnotation& netlist_annotation, @@ -2064,6 +2065,7 @@ int print_verilog_full_testbench(const ModuleManager& module_manager, print_verilog_testbench_connect_fpga_ios(fp, module_manager, top_module, atom_ctx, place_ctx, io_location_map, netlist_annotation, + bus_group, std::string(), std::string(TOP_TESTBENCH_SHARED_INPUT_POSTFIX), std::string(TOP_TESTBENCH_FPGA_OUTPUT_POSTFIX), diff --git a/openfpga/src/fpga_verilog/verilog_top_testbench.h b/openfpga/src/fpga_verilog/verilog_top_testbench.h index bbad08125..51f71fee7 100644 --- a/openfpga/src/fpga_verilog/verilog_top_testbench.h +++ b/openfpga/src/fpga_verilog/verilog_top_testbench.h @@ -19,6 +19,7 @@ #include "simulation_setting.h" #include "memory_bank_shift_register_banks.h" #include "verilog_testbench_options.h" +#include "bus_group.h" /******************************************************************** * Function declaration @@ -37,6 +38,7 @@ int print_verilog_full_testbench(const ModuleManager& module_manager, const AtomContext& atom_ctx, const PlacementContext& place_ctx, const PinConstraints& pin_constraints, + const BusGroup& bus_group, const std::string& bitstream_file, const IoLocationMap& io_location_map, const VprNetlistAnnotation& netlist_annotation,