From 766df0a1b5bae0af7342c55850be9b62fe7d051a Mon Sep 17 00:00:00 2001 From: chungshien-chai Date: Wed, 31 Jul 2024 12:19:30 -0700 Subject: [PATCH] Improve Port Parser --- .../src/bitstream_manager.cpp | 21 +++----- .../src/openfpga_port_parser.cpp | 50 +++++++++++++++++-- .../src/openfpga_port_parser.h | 26 +++++++--- 3 files changed, 71 insertions(+), 26 deletions(-) diff --git a/libs/libfpgabitstream/src/bitstream_manager.cpp b/libs/libfpgabitstream/src/bitstream_manager.cpp index 39c3515b3..291befb60 100644 --- a/libs/libfpgabitstream/src/bitstream_manager.cpp +++ b/libs/libfpgabitstream/src/bitstream_manager.cpp @@ -7,6 +7,7 @@ #include "arch_error.h" #include "bitstream_manager_utils.h" +#include "openfpga_port_parser.h" #include "openfpga_tokenizer.h" #include "vtr_assert.h" #include "vtr_log.h" @@ -301,26 +302,16 @@ void BitstreamManager::add_output_net_id_to_block( void BitstreamManager::overwrite_bitstream(const std::string& path, const bool& value) { - bool bad_format = true; - size_t index = path.rfind("["); - std::string bit_string = ""; - if (index != std::string::npos && path[path.size() - 1] == ']') { - bit_string = path.substr(index + 1, path.size() - index - 2); - bad_format = bit_string.size() == 0; - auto iter = bit_string.begin(); - while (!bad_format && iter != bit_string.end()) { - bad_format = !std::isdigit(*iter); - iter++; - } - } - if (bad_format) { + PortParser port_parser(path, PORT_PARSER_SUPPORT_SINGLE_INDEX_FORMAT); + if (!port_parser.valid()) { archfpga_throw(__FILE__, __LINE__, "overwrite_bitstream bit path '%s' does not match format " "[bit index]", path.c_str()); } else { - size_t bit = (size_t)(std::stoi(bit_string)); - StringToken tokenizer(path.substr(0, index)); + BasicPort port = port_parser.port(); + size_t bit = port.get_lsb(); + StringToken tokenizer(port.get_name()); std::vector blocks = tokenizer.split("."); std::vector block_ids; ConfigBlockId block_id = ConfigBlockId::INVALID(); diff --git a/libs/libopenfpgautil/src/openfpga_port_parser.cpp b/libs/libopenfpgautil/src/openfpga_port_parser.cpp index 93b7e0899..da0a27368 100644 --- a/libs/libopenfpgautil/src/openfpga_port_parser.cpp +++ b/libs/libopenfpgautil/src/openfpga_port_parser.cpp @@ -5,6 +5,7 @@ #include +#include "arch_error.h" #include "openfpga_tokenizer.h" #include "vtr_assert.h" #include "vtr_geometry.h" @@ -19,9 +20,10 @@ namespace openfpga { /************************************************************************ * Constructors ***********************************************************************/ -PortParser::PortParser(const std::string& data) { +PortParser::PortParser(const std::string& data, const int support_format) { set_default_bracket(); set_default_delim(); + set_support_format(support_format); set_data(data); } @@ -33,9 +35,18 @@ std::string PortParser::data() const { return data_; } BasicPort PortParser::port() const { return port_; } +bool PortParser::valid() const { return valid_; } + /************************************************************************ * Public Mutators ***********************************************************************/ +void PortParser::set_support_format(const int support_format) { + VTR_ASSERT((support_format & PORT_PARSER_SUPPORT_ALL_FORMAT) != 0); + VTR_ASSERT((support_format & ~PORT_PARSER_SUPPORT_ALL_FORMAT) == 0); + support_format_ = support_format; + return; +} + void PortParser::set_data(const std::string& data) { data_ = data; parse(); @@ -47,6 +58,8 @@ void PortParser::set_data(const std::string& data) { ***********************************************************************/ /* Parse the data */ void PortParser::parse() { + valid_ = true; + /* Create a tokenizer */ StringToken tokenizer(data_); @@ -54,11 +67,14 @@ void PortParser::parse() { std::vector port_tokens = tokenizer.split(bracket_.x()); /* Make sure we have a port name! */ VTR_ASSERT_SAFE((1 == port_tokens.size()) || (2 == port_tokens.size())); + /* Store the port name! */ port_.set_name(port_tokens[0]); /* If we only have one token */ if (1 == port_tokens.size()) { + // there is no [ + valid_ = (support_format_ & PORT_PARSER_SUPPORT_NO_PORT_FORMAT) != 0; port_.set_width(1); return; /* We can finish here */ } @@ -72,19 +88,25 @@ void PortParser::parse() { /* Split the pin string now */ tokenizer.set_data(pin_tokens[0]); pin_tokens = tokenizer.split(delim_); + VTR_ASSERT_SAFE((1 == pin_tokens.size()) || (2 == pin_tokens.size())); /* Check if we have LSB and MSB or just one */ if (1 == pin_tokens.size()) { /* Single pin */ - port_.set_width(std::stoi(pin_tokens[0]), std::stoi(pin_tokens[0])); + valid_ = (support_format_ & PORT_PARSER_SUPPORT_SINGLE_INDEX_FORMAT) != 0; + size_t temp = string_to_number(pin_tokens[0]); + port_.set_width(temp, temp); } else if (2 == pin_tokens.size()) { /* A number of pins. * Note that we always use the LSB for token[0] and MSB for token[1] */ - if (std::stoi(pin_tokens[1]) < std::stoi(pin_tokens[0])) { - port_.set_width(std::stoi(pin_tokens[1]), std::stoi(pin_tokens[0])); + valid_ = (support_format_ & PORT_PARSER_SUPPORT_RANGE_FORMAT) != 0; + size_t temp0 = string_to_number(pin_tokens[0]); + size_t temp1 = string_to_number(pin_tokens[1]); + if (temp1 < temp0) { + port_.set_width(temp1, temp0); } else { - port_.set_width(std::stoi(pin_tokens[0]), std::stoi(pin_tokens[1])); + port_.set_width(temp0, temp1); } } @@ -102,6 +124,24 @@ void PortParser::set_default_delim() { return; } +/* + Make sure string is not empty and is all digit before stoi +*/ +size_t PortParser::string_to_number(const std::string& str) { + bool bad_format = str.empty(); + for (auto& chr : str) { + if (!std::isdigit(chr)) { + bad_format = true; + break; + } + } + if (bad_format) { + archfpga_throw(__FILE__, __LINE__, + "Invalid string '%s' to call std::stoi()", str.c_str()); + } + return (size_t)(std::stoi(str)); +} + /************************************************************************ * Member functions for MultiPortParser class ***********************************************************************/ diff --git a/libs/libopenfpgautil/src/openfpga_port_parser.h b/libs/libopenfpgautil/src/openfpga_port_parser.h index f596fd309..ab61603e0 100644 --- a/libs/libopenfpgautil/src/openfpga_port_parser.h +++ b/libs/libopenfpgautil/src/openfpga_port_parser.h @@ -21,37 +21,51 @@ /* namespace openfpga begins */ namespace openfpga { +constexpr int PORT_PARSER_SUPPORT_NO_PORT_FORMAT = (1 << 0); // (5) below +constexpr int PORT_PARSER_SUPPORT_SINGLE_INDEX_FORMAT = (1 << 1); // (3) below +constexpr int PORT_PARSER_SUPPORT_RANGE_FORMAT = (1 << 2); // (1) and (2) below +constexpr int PORT_PARSER_SUPPORT_ALL_FORMAT = ((1 << 3) - 1); + /************************************************************************ * Class PortParser: single port parser * Supported port definition: - * 1. [:] - * 2. [:] - * 3. [] - * 4. [] - * 5. + * (1) [:] + * (2) [:] + * (3) [] + * (4) [] -- this is not currently supported. Two problems: + * * tokenizer will error out and + * * stoi cannot support empty string, and give + * std::invalid_argument error + * (5) * In case 4 and 5, we will assign (-1,-1) for LSB and MSB ***********************************************************************/ class PortParser { public: /* Constructors*/ - PortParser(const std::string& data); + PortParser(const std::string& data, + const int support_format = PORT_PARSER_SUPPORT_ALL_FORMAT); public: /* Public Accessors */ std::string data() const; BasicPort port() const; + bool valid() const; public: /* Public Mutators */ + void set_support_format(const int support_format); void set_data(const std::string& data); private: /* Private Mutators */ void parse(); void set_default_bracket(); void set_default_delim(); + size_t string_to_number(const std::string& str); private: /* Internal data */ std::string data_; /* Lines to be splited */ + int support_format_; vtr::Point bracket_; char delim_; BasicPort port_; + bool valid_; }; /************************************************************************