From 4d265c396545531bb03a4e597dde3e099f25c89d Mon Sep 17 00:00:00 2001 From: tangxifan Date: Thu, 22 Jun 2023 17:44:07 -0700 Subject: [PATCH] [lib] reworked io name map data structure. Passed I/O test --- libs/libionamemap/src/base/io_name_map.cpp | 182 ++++++++++++++++++--- libs/libionamemap/src/base/io_name_map.h | 21 ++- libs/libopenfpgautil/src/openfpga_port.cpp | 19 +++ libs/libopenfpgautil/src/openfpga_port.h | 4 + 4 files changed, 194 insertions(+), 32 deletions(-) diff --git a/libs/libionamemap/src/base/io_name_map.cpp b/libs/libionamemap/src/base/io_name_map.cpp index bf093c98a..7227d5541 100644 --- a/libs/libionamemap/src/base/io_name_map.cpp +++ b/libs/libionamemap/src/base/io_name_map.cpp @@ -7,6 +7,7 @@ #include #include "command_exit_codes.h" +#include "openfpga_port_parser.h" #include "vtr_assert.h" #include "vtr_log.h" #include "vtr_time.h" @@ -22,7 +23,7 @@ std::vector IoNameMap::fpga_top_ports() const { for (auto it = top2core_io_name_map_.begin(); it != top2core_io_name_map_.end(); ++it) { - ports.push_back(it->first); + ports.push_back(str2port(it->first)); } return ports; @@ -30,18 +31,86 @@ std::vector IoNameMap::fpga_top_ports() const { BasicPort IoNameMap::fpga_core_port(const BasicPort& fpga_top_port) const { BasicPort core_port; - auto result = top2core_io_name_map_.find(fpga_top_port); - if (result != top2core_io_name_map_.end()) { - core_port = result->second; + /* First, find the pin name matching */ + auto result_key = top2core_io_name_keys_.find(fpga_top_port.get_name()); + if (result_key == top2core_io_name_keys_.end()) { + return core_port; /* Not found, return invalid port */ + } + /* Second, find the exact key */ + std::string top_port_key; + for (std::string cand : result_key->second) { + BasicPort cand_port = str2port(cand); + /* if the top port is part of the cand port, e.g., clk[1] vs. clk[0:2], the + * candidate is the key that we want! */ + if (cand_port.contained(fpga_top_port)) { + top_port_key = cand; + break; + } + } + if (top_port_key.empty()) { + return core_port; /* Not found, return invalid port */ + } + auto result = top2core_io_name_map_.find(top_port_key); + if (result != top2core_io_name_map_.end() && result->second.is_valid()) { + BasicPort top_port_pool = str2port(top_port_key); + BasicPort fpga_top_port_lsb(fpga_top_port.get_name(), + fpga_top_port.get_lsb(), + fpga_top_port.get_lsb()); + BasicPort fpga_top_port_msb(fpga_top_port.get_name(), + fpga_top_port.get_msb(), + fpga_top_port.get_msb()); + size_t ipin_anchor_lsb = top_port_pool.find_ipin(fpga_top_port_lsb); + size_t ipin_anchor_msb = top_port_pool.find_ipin(fpga_top_port_msb); + /* Now find the exact pin and spot the core port with pin index */ + if (ipin_anchor_lsb < top_port_pool.get_width() && + ipin_anchor_msb < top_port_pool.get_width()) { + core_port.set_name(result->second.get_name()); + core_port.set_lsb(result->second.pins()[ipin_anchor_lsb]); + core_port.set_msb(result->second.pins()[ipin_anchor_msb]); + } } return core_port; } BasicPort IoNameMap::fpga_top_port(const BasicPort& fpga_core_port) const { BasicPort top_port; - auto result = core2top_io_name_map_.find(fpga_core_port); - if (result != core2top_io_name_map_.end()) { - top_port = result->second; + /* First, find the pin name matching */ + auto result_key = core2top_io_name_keys_.find(fpga_core_port.get_name()); + if (result_key == core2top_io_name_keys_.end()) { + return top_port; /* Not found, return invalid port */ + } + /* Second, find the exact key */ + std::string core_port_key; + for (std::string cand : result_key->second) { + BasicPort cand_port = str2port(cand); + /* if the top port is part of the cand port, e.g., clk[1] vs. clk[0:2], the + * candidate is the key that we want! */ + if (cand_port.contained(fpga_core_port)) { + core_port_key = cand; + break; + } + } + if (core_port_key.empty()) { + return top_port; /* Not found, return invalid port */ + } + auto result = core2top_io_name_map_.find(core_port_key); + if (result != core2top_io_name_map_.end() && result->second.is_valid()) { + BasicPort core_port_pool = str2port(core_port_key); + BasicPort fpga_core_port_lsb(fpga_core_port.get_name(), + fpga_core_port.get_lsb(), + fpga_core_port.get_lsb()); + BasicPort fpga_core_port_msb(fpga_core_port.get_name(), + fpga_core_port.get_msb(), + fpga_core_port.get_msb()); + size_t ipin_anchor_lsb = core_port_pool.find_ipin(fpga_core_port); + size_t ipin_anchor_msb = core_port_pool.find_ipin(fpga_core_port); + /* Now find the exact pin and spot the core port with pin index */ + if (ipin_anchor_lsb < core_port_pool.get_width() && + ipin_anchor_msb < core_port_pool.get_width()) { + top_port.set_name(result->second.get_name()); + top_port.set_lsb(result->second.pins()[ipin_anchor_lsb]); + top_port.set_msb(result->second.pins()[ipin_anchor_msb]); + } } return top_port; } @@ -63,36 +132,95 @@ int IoNameMap::set_io_pair(const BasicPort& fpga_top_port, return CMD_EXEC_FATAL_ERROR; } VTR_ASSERT_SAFE(fpga_top_port.get_width() != fpga_core_port.get_width()); - for (size_t ipin = 0; ipin < fpga_top_port.pins().size(); ++ipin) { - BasicPort top_pin(fpga_top_port.get_name(), fpga_top_port.pins()[ipin], - fpga_top_port.pins()[ipin]); - BasicPort core_pin(fpga_core_port.get_name(), fpga_core_port.pins()[ipin], - fpga_core_port.pins()[ipin]); - top2core_io_name_map_[top_pin] = core_pin; - core2top_io_name_map_[core_pin] = top_pin; + /* Register in the key first, and then add to the exact name mapping */ + { + std::string top_port_str = port2str(fpga_top_port); + auto result_key = top2core_io_name_keys_.find(fpga_top_port.get_name()); + if (result_key == top2core_io_name_keys_.end()) { + /* Add to the key registery */ + top2core_io_name_keys_[fpga_top_port.get_name()].push_back(top_port_str); + top2core_io_name_map_[top_port_str] = fpga_core_port; + } else { + /* Ensure that the key is not duplicated */ + if (std::find(result_key->second.begin(), result_key->second.end(), + top_port_str) == result_key->second.end()) { + top2core_io_name_keys_[fpga_top_port.get_name()].push_back( + top_port_str); + top2core_io_name_map_[top_port_str] = fpga_core_port; + } else { + /* Throw a warning since we have to overwrite */ + VTR_LOG_WARN( + "Overwrite the top-to-core pin mapping: top pin '%s' to core pin " + "'%s' (previously was '%s')!\n", + top_port_str, port2str(fpga_core_port).c_str(), + port2str(top2core_io_name_map_[top_port_str]).c_str()); + top2core_io_name_map_[top_port_str] = fpga_core_port; + } + } + } + /* Now, do similar to the core port */ + { + std::string core_port_str = port2str(fpga_core_port); + auto result_key = core2top_io_name_keys_.find(fpga_core_port.get_name()); + if (result_key == core2top_io_name_keys_.end()) { + /* Add to the key registery */ + core2top_io_name_keys_[fpga_core_port.get_name()].push_back( + core_port_str); + core2top_io_name_map_[core_port_str] = fpga_top_port; + } else { + /* Ensure that the key is not duplicated */ + if (std::find(result_key->second.begin(), result_key->second.end(), + core_port_str) == result_key->second.end()) { + core2top_io_name_keys_[fpga_core_port.get_name()].push_back( + core_port_str); + core2top_io_name_map_[core_port_str] = fpga_top_port; + } else { + /* Throw a warning since we have to overwrite */ + VTR_LOG_WARN( + "Overwrite the core-to-top pin mapping: core pin '%s' to top pin " + "'%s' (previously was '%s')!\n", + core_port_str, port2str(fpga_top_port).c_str(), + port2str(core2top_io_name_map_[core_port_str]).c_str()); + core2top_io_name_map_[core_port_str] = fpga_top_port; + } + } } return CMD_EXEC_SUCCESS; } int IoNameMap::set_dummy_io(const BasicPort& fpga_top_port) { /* Must be a true dummy port, none of its pins have been paired! */ - for (size_t ipin = 0; ipin < fpga_top_port.pins().size(); ++ipin) { - BasicPort top_pin(fpga_top_port.get_name(), fpga_top_port.pins()[ipin], - fpga_top_port.pins()[ipin]); - auto result = top2core_io_name_map_.find(top_pin); - if (result != top2core_io_name_map_.end() && result->second.is_valid()) { + std::string top_port_str = port2str(fpga_top_port); + /* First, find the pin name matching */ + auto result_key = top2core_io_name_keys_.find(fpga_top_port.get_name()); + if (result_key == top2core_io_name_keys_.end()) { + /* Add to the key registery */ + top2core_io_name_keys_[fpga_top_port.get_name()].push_back(top_port_str); + top2core_io_name_map_[top_port_str] = BasicPort(); + } else { + /* Ensure that the key is not duplicated */ + if (std::find(result_key->second.begin(), result_key->second.end(), + top_port_str) == result_key->second.end()) { + top2core_io_name_keys_[fpga_top_port.get_name()].push_back(top_port_str); + top2core_io_name_map_[top_port_str] = BasicPort(); + } else { + /* Throw a error because the dummy pin should NOT be mapped before! */ VTR_LOG_ERROR( - "Pin '%lu' in a dummy port '%s[%lu:%lu]' of fpga_top is already mapped " - "to a valid pin '%s[%lu:%lu]' of fpga_core!\n", - top_pin.get_lsb(), fpga_top_port.get_name().c_str(), - fpga_top_port.get_lsb(), fpga_top_port.get_msb(), - result->second.get_name().c_str(), result->second.get_lsb(), - result->second.get_msb()); - return CMD_EXEC_FATAL_ERROR; + "Dummy port '%s' of fpga_top is already mapped " + "to a valid pin '%s' of fpga_core!\n", + port2str(fpga_top_port).c_str(), + port2str(top2core_io_name_map_[top_port_str]).c_str()); } - top2core_io_name_map_[top_pin] = BasicPort(); } return CMD_EXEC_SUCCESS; } +std::string IoNameMap::port2str(const BasicPort& port) const { + return port.to_verilog_string(); +} + +BasicPort IoNameMap::str2port(const std::string& port_str) const { + return PortParser(port_str).port(); +} + } /* end namespace openfpga */ diff --git a/libs/libionamemap/src/base/io_name_map.h b/libs/libionamemap/src/base/io_name_map.h index 6b2cc3078..af3709acc 100644 --- a/libs/libionamemap/src/base/io_name_map.h +++ b/libs/libionamemap/src/base/io_name_map.h @@ -40,12 +40,23 @@ class IoNameMap { * fpga_core */ int set_dummy_io(const BasicPort& fpga_top_port); + private: /* Internal utility */ + /* Convert a port info to string, which can be used to store keys */ + std::string port2str(const BasicPort& port) const; + /* Convert a string to port, which can be used to echo internal info */ + BasicPort str2port(const std::string& port_str) const; + private: /* Internal Data */ - /* fpga_top -> fpga_core io name mapping, each port is in the size of 1. This - * is designed to fast look-up but at the cost of potential large memory - * footprints. TODO: Optimize if we see such issue */ - std::map top2core_io_name_map_; - std::map core2top_io_name_map_; + /* fpga_top -> fpga_core io_name_keys. Use the port name to find all the port + * details. For instance: prog_clk -> ["prog_clk[0:1]", "prog_clk[2:3]"] The + * keys are then used to spot the fpga core ports in the io_name_map_. For + * instance: "prog_clk[0:1]" -> pclk[0:1] + */ + std::map> top2core_io_name_keys_; + std::map top2core_io_name_map_; + + std::map> core2top_io_name_keys_; + std::map core2top_io_name_map_; }; } /* End namespace openfpga*/ diff --git a/libs/libopenfpgautil/src/openfpga_port.cpp b/libs/libopenfpgautil/src/openfpga_port.cpp index 2ca18f27e..cb42393ca 100644 --- a/libs/libopenfpgautil/src/openfpga_port.cpp +++ b/libs/libopenfpgautil/src/openfpga_port.cpp @@ -111,6 +111,25 @@ std::string BasicPort::to_verilog_string() const { std::to_string(get_msb()) + "]"; } +size_t BasicPort::find_ipin(const BasicPort& ref_port) const { + /* Port name should match first */ + if (!this->mergeable(ref_port)) { + return get_width(); /* Name does not match, no need to find the pin index, + return an invalid range */ + } + /* it should be only a pin (width = 1) */ + if (!ref_port.is_valid() || ref_port.get_width() != 1) { + return get_width(); /* Return an invalid range */ + } + /* Must cache the pin list otherwise the begin() and end() are not constant */ + auto pin_list = pins(); + auto it = std::find(pin_list.begin(), pin_list.end(), ref_port.get_lsb()); + if (it == pin_list.end()) { + return get_width(); /* Out of range, return an invalid range */ + } + return it - pin_list.begin(); +} + /************************************************************************ * Overloaded operators ***********************************************************************/ diff --git a/libs/libopenfpgautil/src/openfpga_port.h b/libs/libopenfpgautil/src/openfpga_port.h index 013a74b7b..be86334b5 100644 --- a/libs/libopenfpgautil/src/openfpga_port.h +++ b/libs/libopenfpgautil/src/openfpga_port.h @@ -37,6 +37,10 @@ class BasicPort { size_t get_origin_port_width() const; std::string to_verilog_string() const; /* Generate verilog-style string, e.g., a[0:1] */ + /** @brief Find the index of the pin in the reference port w.r.t. to this + * port. For example, given a reference pin 'a[1]', this port is 'a[0:2]', the + * pin is the second pin in the port. As a result, the index will be 1. */ + size_t find_ipin(const BasicPort& ref_port) const; public: /* Mutators */ void set(const BasicPort& basic_port); /* copy */