Merge pull request from chungshien/openfpga-overwrite-bits

Openfpga support setting bitstream bit manually
This commit is contained in:
tangxifan 2024-07-31 14:05:04 -07:00 committed by GitHub
commit 6ea1feb445
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
18 changed files with 553 additions and 19 deletions

View File

@ -16,6 +16,9 @@ This can define a hard-coded bitstream for a reconfigurable resource in FPGA fab
<non_fabric name="<string>" file="<string>"> <non_fabric name="<string>" file="<string>">
<pb name="<string>" type="<string>" content="<string>"/> <pb name="<string>" type="<string>" content="<string>"/>
</non_fabric> </non_fabric>
<overwrite_bitstream>
<bit value="<0 or 1>" path="<string>"/>
</overwrite_bitstream>
</openfpga_bitstream_setting> </openfpga_bitstream_setting>
pb_type-related Settings pb_type-related Settings
@ -75,7 +78,7 @@ The following syntax are applicable to the XML definition tagged by ``interconne
The default path can be either ``iopad.inpad`` or ``ff.Q`` which corresponds to the first input and the second input respectively. The default path can be either ``iopad.inpad`` or ``ff.Q`` which corresponds to the first input and the second input respectively.
non_fabric-related Settings non_fabric-related Settings
^^^^^^^^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^
This is special syntax to extract PB defined parameter or attribute and save the data into dedicated JSON file outside of fabric bitstream This is special syntax to extract PB defined parameter or attribute and save the data into dedicated JSON file outside of fabric bitstream
@ -97,7 +100,7 @@ The following syntax are applicable to the XML definition tagged by ``non_fabric
file="bram.json" file="bram.json"
.. option:: ``pb`` child element name="<string: pb_type child name>" .. option:: pb child element name="<string: pb_type child name>"
Together with ``pb_type`` top level name, that is the source of the ``pb_type`` bitstream Together with ``pb_type`` top level name, that is the source of the ``pb_type`` bitstream
@ -112,6 +115,33 @@ The following syntax are applicable to the XML definition tagged by ``non_fabric
The final ``pb_type`` name is "bram.bram_lr[mem_36K_tdp].mem_36K" The final ``pb_type`` name is "bram.bram_lr[mem_36K_tdp].mem_36K"
.. option:: ``pb`` child element content="<string>" .. option:: pb child element content="<string>"
The content of the ``pb_type`` data to be extracted. For example, ``content=".param INIT_i"`` means that the data will be extracted from the ``.param INIT_i`` line defined under the ``.blif model``. The content of the ``pb_type`` data to be extracted. For example, ``content=".param INIT_i"`` means that the data will be extracted from the ``.param INIT_i`` line defined under the ``.blif model``.
overwrite_bitstream-related Settings
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
This is to allow user to set value of a list of bits which is represented using full path in the hierarchy of FPGA fabric
This ``overwrite_bitstream`` settings has the highest priority than loading any external bitstream file
Each bit to overwrite is represented by one ``bit`` child node/tag
The following syntax are applicable to the XML definition tagged by ``bit`` node under ``overwrite_bitstream`` setting.
.. option:: value="<0 or 1>"
The boolean ``0`` or ``1`` that will be set. For example,
.. code-block:: xml
value="0"
.. option:: path="<string>"
``path`` represents the location of this block in FPGA fabric, i.e., the full path in the hierarchy of FPGA fabric.
.. code-block:: xml
path="fpga_top.grid_clb_1__2_.logical_tile_clb_mode_clb__0.mem_fle_9_in_5[0]"

View File

@ -24,6 +24,12 @@ BitstreamSetting::interconnect_settings() const {
interconnect_setting_ids_.end()); interconnect_setting_ids_.end());
} }
BitstreamSetting::overwrite_bitstream_range
BitstreamSetting::overwrite_bitstreams() const {
return vtr::make_range(overwrite_bitstream_ids_.begin(),
overwrite_bitstream_ids_.end());
}
/************************************************************************ /************************************************************************
* Constructors * Constructors
***********************************************************************/ ***********************************************************************/
@ -106,6 +112,18 @@ std::vector<NonFabricBitstreamSetting> BitstreamSetting::non_fabric() const {
return non_fabric_; return non_fabric_;
} }
std::string BitstreamSetting::overwrite_bitstream_path(
const OverwriteBitstreamId& id) const {
VTR_ASSERT(true == valid_overwrite_bitstream_id(id));
return overwrite_bitstream_paths_[id];
}
bool BitstreamSetting::overwrite_bitstream_value(
const OverwriteBitstreamId& id) const {
VTR_ASSERT(true == valid_overwrite_bitstream_id(id));
return overwrite_bitstream_values_[id];
}
/************************************************************************ /************************************************************************
* Public Mutators * Public Mutators
***********************************************************************/ ***********************************************************************/
@ -178,6 +196,21 @@ void BitstreamSetting::add_non_fabric_pb(const std::string& pb,
} }
} }
OverwriteBitstreamId BitstreamSetting::add_overwrite_bitstream(
const std::string& path, const bool& value) {
VTR_ASSERT(path.size());
VTR_ASSERT(overwrite_bitstream_ids_.size() ==
overwrite_bitstream_paths_.size());
VTR_ASSERT(overwrite_bitstream_paths_.size() ==
overwrite_bitstream_values_.size());
OverwriteBitstreamId id =
OverwriteBitstreamId(overwrite_bitstream_ids_.size());
overwrite_bitstream_ids_.push_back(id);
overwrite_bitstream_paths_.push_back(path);
overwrite_bitstream_values_.push_back(value);
return id;
}
/************************************************************************ /************************************************************************
* Public Validators * Public Validators
***********************************************************************/ ***********************************************************************/
@ -194,4 +227,14 @@ bool BitstreamSetting::valid_bitstream_interconnect_setting_id(
interconnect_setting_ids_[interconnect_setting_id]); interconnect_setting_ids_[interconnect_setting_id]);
} }
bool BitstreamSetting::valid_overwrite_bitstream_id(
const OverwriteBitstreamId& id) const {
VTR_ASSERT(overwrite_bitstream_ids_.size() ==
overwrite_bitstream_paths_.size());
VTR_ASSERT(overwrite_bitstream_paths_.size() ==
overwrite_bitstream_values_.size());
return (size_t(id) < overwrite_bitstream_ids_.size()) &&
(id == overwrite_bitstream_ids_[id]);
}
} // namespace openfpga } // namespace openfpga

View File

@ -61,11 +61,15 @@ class BitstreamSetting {
typedef vtr::vector<BitstreamInterconnectSettingId, typedef vtr::vector<BitstreamInterconnectSettingId,
BitstreamInterconnectSettingId>::const_iterator BitstreamInterconnectSettingId>::const_iterator
bitstream_interconnect_setting_iterator; bitstream_interconnect_setting_iterator;
typedef vtr::vector<OverwriteBitstreamId,
OverwriteBitstreamId>::const_iterator
overwrite_bitstream_iterator;
/* Create range */ /* Create range */
typedef vtr::Range<bitstream_pb_type_setting_iterator> typedef vtr::Range<bitstream_pb_type_setting_iterator>
bitstream_pb_type_setting_range; bitstream_pb_type_setting_range;
typedef vtr::Range<bitstream_interconnect_setting_iterator> typedef vtr::Range<bitstream_interconnect_setting_iterator>
bitstream_interconnect_setting_range; bitstream_interconnect_setting_range;
typedef vtr::Range<overwrite_bitstream_iterator> overwrite_bitstream_range;
public: /* Constructors */ public: /* Constructors */
BitstreamSetting(); BitstreamSetting();
@ -73,6 +77,7 @@ class BitstreamSetting {
public: /* Accessors: aggregates */ public: /* Accessors: aggregates */
bitstream_pb_type_setting_range pb_type_settings() const; bitstream_pb_type_setting_range pb_type_settings() const;
bitstream_interconnect_setting_range interconnect_settings() const; bitstream_interconnect_setting_range interconnect_settings() const;
overwrite_bitstream_range overwrite_bitstreams() const;
public: /* Public Accessors */ public: /* Public Accessors */
std::string pb_type_name( std::string pb_type_name(
@ -98,6 +103,8 @@ class BitstreamSetting {
std::string default_path( std::string default_path(
const BitstreamInterconnectSettingId& interconnect_setting_id) const; const BitstreamInterconnectSettingId& interconnect_setting_id) const;
std::vector<NonFabricBitstreamSetting> non_fabric() const; std::vector<NonFabricBitstreamSetting> non_fabric() const;
std::string overwrite_bitstream_path(const OverwriteBitstreamId& id) const;
bool overwrite_bitstream_value(const OverwriteBitstreamId& id) const;
public: /* Public Mutators */ public: /* Public Mutators */
BitstreamPbTypeSettingId add_bitstream_pb_type_setting( BitstreamPbTypeSettingId add_bitstream_pb_type_setting(
@ -120,11 +127,15 @@ class BitstreamSetting {
void add_non_fabric(const std::string& name, const std::string& file); void add_non_fabric(const std::string& name, const std::string& file);
void add_non_fabric_pb(const std::string& pb, const std::string& content); void add_non_fabric_pb(const std::string& pb, const std::string& content);
OverwriteBitstreamId add_overwrite_bitstream(const std::string& path,
const bool& value);
public: /* Public Validators */ public: /* Public Validators */
bool valid_bitstream_pb_type_setting_id( bool valid_bitstream_pb_type_setting_id(
const BitstreamPbTypeSettingId& pb_type_setting_id) const; const BitstreamPbTypeSettingId& pb_type_setting_id) const;
bool valid_bitstream_interconnect_setting_id( bool valid_bitstream_interconnect_setting_id(
const BitstreamInterconnectSettingId& interconnect_setting_id) const; const BitstreamInterconnectSettingId& interconnect_setting_id) const;
bool valid_overwrite_bitstream_id(const OverwriteBitstreamId& id) const;
private: /* Internal data */ private: /* Internal data */
/* Pb type -related settings /* Pb type -related settings
@ -162,6 +173,10 @@ class BitstreamSetting {
vtr::vector<BitstreamInterconnectSettingId, std::string> vtr::vector<BitstreamInterconnectSettingId, std::string>
interconnect_default_paths_; interconnect_default_paths_;
std::vector<NonFabricBitstreamSetting> non_fabric_; std::vector<NonFabricBitstreamSetting> non_fabric_;
vtr::vector<OverwriteBitstreamId, OverwriteBitstreamId>
overwrite_bitstream_ids_;
vtr::vector<OverwriteBitstreamId, std::string> overwrite_bitstream_paths_;
vtr::vector<OverwriteBitstreamId, bool> overwrite_bitstream_values_;
}; };
} // namespace openfpga } // namespace openfpga

View File

@ -15,11 +15,13 @@
struct bitstream_pb_type_setting_id_tag; struct bitstream_pb_type_setting_id_tag;
struct bitstream_interconnect_setting_id_tag; struct bitstream_interconnect_setting_id_tag;
struct overwrite_bitstream_id_tag;
typedef vtr::StrongId<bitstream_pb_type_setting_id_tag> typedef vtr::StrongId<bitstream_pb_type_setting_id_tag>
BitstreamPbTypeSettingId; BitstreamPbTypeSettingId;
typedef vtr::StrongId<bitstream_interconnect_setting_id_tag> typedef vtr::StrongId<bitstream_interconnect_setting_id_tag>
BitstreamInterconnectSettingId; BitstreamInterconnectSettingId;
typedef vtr::StrongId<overwrite_bitstream_id_tag> OverwriteBitstreamId;
/* Short declaration of class */ /* Short declaration of class */
class BitstreamSetting; class BitstreamSetting;

View File

@ -102,6 +102,30 @@ static void read_xml_non_fabric_bitstream_setting(
} }
} }
/********************************************************************
* Parse XML description for a bit setting under a <bit> XML node
*******************************************************************/
static void read_xml_overwrite_bitstream_setting(
pugi::xml_node& xml_overwrite_bitstream, const pugiutil::loc_data& loc_data,
openfpga::BitstreamSetting& bitstream_setting) {
// Loopthrough bit
for (pugi::xml_node xml_bit : xml_overwrite_bitstream.children()) {
if (xml_bit.name() != std::string("bit")) {
bad_tag(xml_bit, loc_data, xml_overwrite_bitstream, {"bit"});
}
const std::string& path_attr =
get_attribute(xml_bit, "path", loc_data).as_string();
const std::string& value_attr =
get_attribute(xml_bit, "value", loc_data).as_string();
if (value_attr != "0" && value_attr != "1") {
archfpga_throw(loc_data.filename_c_str(), loc_data.line(xml_bit),
"Invalid value of overwrite_bitstream bit. Expect [0|1]");
}
/* Add to bit */
bitstream_setting.add_overwrite_bitstream(path_attr, value_attr == "1");
}
}
/******************************************************************** /********************************************************************
* Parse XML codes about <openfpga_bitstream_setting> to an object * Parse XML codes about <openfpga_bitstream_setting> to an object
*******************************************************************/ *******************************************************************/
@ -116,9 +140,10 @@ openfpga::BitstreamSetting read_xml_bitstream_setting(
/* Error out if the XML child has an invalid name! */ /* Error out if the XML child has an invalid name! */
if ((xml_child.name() != std::string("pb_type")) && if ((xml_child.name() != std::string("pb_type")) &&
(xml_child.name() != std::string("interconnect")) && (xml_child.name() != std::string("interconnect")) &&
(xml_child.name() != std::string("non_fabric"))) { (xml_child.name() != std::string("non_fabric")) &&
(xml_child.name() != std::string("overwrite_bitstream"))) {
bad_tag(xml_child, loc_data, Node, bad_tag(xml_child, loc_data, Node,
{"pb_type | interconnect | non_fabric"}); {"pb_type | interconnect | non_fabric | overwrite_bitstream"});
} }
if (xml_child.name() == std::string("pb_type")) { if (xml_child.name() == std::string("pb_type")) {
@ -127,10 +152,13 @@ openfpga::BitstreamSetting read_xml_bitstream_setting(
} else if (xml_child.name() == std::string("interconnect")) { } else if (xml_child.name() == std::string("interconnect")) {
read_xml_bitstream_interconnect_setting(xml_child, loc_data, read_xml_bitstream_interconnect_setting(xml_child, loc_data,
bitstream_setting); bitstream_setting);
} else { } else if (xml_child.name() == std::string("non_fabric")) {
VTR_ASSERT_SAFE(xml_child.name() == std::string("non_fabric"));
read_xml_non_fabric_bitstream_setting(xml_child, loc_data, read_xml_non_fabric_bitstream_setting(xml_child, loc_data,
bitstream_setting); bitstream_setting);
} else {
VTR_ASSERT_SAFE(xml_child.name() == std::string("overwrite_bitstream"));
read_xml_overwrite_bitstream_setting(xml_child, loc_data,
bitstream_setting);
} }
} }

View File

@ -5,6 +5,10 @@
#include <algorithm> #include <algorithm>
#include "arch_error.h"
#include "bitstream_manager_utils.h"
#include "openfpga_port_parser.h"
#include "openfpga_tokenizer.h"
#include "vtr_assert.h" #include "vtr_assert.h"
#include "vtr_log.h" #include "vtr_log.h"
@ -296,6 +300,69 @@ void BitstreamManager::add_output_net_id_to_block(
block_output_net_ids_[block] = output_net_id; block_output_net_ids_[block] = output_net_id;
} }
void BitstreamManager::overwrite_bitstream(const std::string& path,
const bool& value) {
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 "
"<full path in the hierarchy of FPGA fabric>[bit index]",
path.c_str());
} else {
BasicPort port = port_parser.port();
size_t bit = port.get_lsb();
StringToken tokenizer(port.get_name());
std::vector<std::string> blocks = tokenizer.split(".");
std::vector<ConfigBlockId> block_ids;
ConfigBlockId block_id = ConfigBlockId::INVALID();
size_t found = 0;
for (size_t i = 0; i < blocks.size(); i++) {
if (i == 0) {
block_ids = find_bitstream_manager_top_blocks(*this);
} else {
block_ids = block_children(block_id);
}
// Reset
block_id = ConfigBlockId::INVALID();
// Find the one from the list that match the name
for (auto id : block_ids) {
if (block_name(id) == blocks[i]) {
block_id = id;
break;
}
}
if (block_id != ConfigBlockId::INVALID()) {
// Found one that match the name
found++;
if (found == blocks.size()) {
// Last one, no more child must end here
if (block_children(block_id).size() == 0) {
std::vector<ConfigBitId> ids = block_bits(block_id);
if (bit < ids.size()) {
VTR_ASSERT(valid_bit_id(ids[bit]));
bit_values_[ids[bit]] = value ? '1' : '0';
} else {
// No configuration bits at all or out of range, invalidate
found = 0;
}
} else {
// There are more child, hence the path still no end, invalidate
found = 0;
}
}
} else {
// Cannot match the name, just stop
break;
}
}
if (found != blocks.size()) {
archfpga_throw(__FILE__, __LINE__,
"Failed to find path '%s' to overwrite bitstream",
path.c_str());
}
}
}
/****************************************************************************** /******************************************************************************
* Public Validators * Public Validators
******************************************************************************/ ******************************************************************************/

View File

@ -213,6 +213,9 @@ class BitstreamManager {
void add_output_net_id_to_block(const ConfigBlockId& block, void add_output_net_id_to_block(const ConfigBlockId& block,
const std::string& output_net_id); const std::string& output_net_id);
/* Set bit to the bitstream at the given path */
void overwrite_bitstream(const std::string& path, const bool& value);
public: /* Public Validators */ public: /* Public Validators */
bool valid_bit_id(const ConfigBitId& bit_id) const; bool valid_bit_id(const ConfigBitId& bit_id) const;

View File

@ -5,6 +5,7 @@
#include <cstring> #include <cstring>
#include "arch_error.h"
#include "openfpga_tokenizer.h" #include "openfpga_tokenizer.h"
#include "vtr_assert.h" #include "vtr_assert.h"
#include "vtr_geometry.h" #include "vtr_geometry.h"
@ -19,9 +20,10 @@ namespace openfpga {
/************************************************************************ /************************************************************************
* Constructors * Constructors
***********************************************************************/ ***********************************************************************/
PortParser::PortParser(const std::string& data) { PortParser::PortParser(const std::string& data, const int support_format) {
set_default_bracket(); set_default_bracket();
set_default_delim(); set_default_delim();
set_support_format(support_format);
set_data(data); set_data(data);
} }
@ -33,9 +35,18 @@ std::string PortParser::data() const { return data_; }
BasicPort PortParser::port() const { return port_; } BasicPort PortParser::port() const { return port_; }
bool PortParser::valid() const { return valid_; }
/************************************************************************ /************************************************************************
* Public Mutators * 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) { void PortParser::set_data(const std::string& data) {
data_ = data; data_ = data;
parse(); parse();
@ -47,6 +58,8 @@ void PortParser::set_data(const std::string& data) {
***********************************************************************/ ***********************************************************************/
/* Parse the data */ /* Parse the data */
void PortParser::parse() { void PortParser::parse() {
valid_ = true;
/* Create a tokenizer */ /* Create a tokenizer */
StringToken tokenizer(data_); StringToken tokenizer(data_);
@ -54,11 +67,14 @@ void PortParser::parse() {
std::vector<std::string> port_tokens = tokenizer.split(bracket_.x()); std::vector<std::string> port_tokens = tokenizer.split(bracket_.x());
/* Make sure we have a port name! */ /* Make sure we have a port name! */
VTR_ASSERT_SAFE((1 == port_tokens.size()) || (2 == port_tokens.size())); VTR_ASSERT_SAFE((1 == port_tokens.size()) || (2 == port_tokens.size()));
/* Store the port name! */ /* Store the port name! */
port_.set_name(port_tokens[0]); port_.set_name(port_tokens[0]);
/* If we only have one token */ /* If we only have one token */
if (1 == port_tokens.size()) { if (1 == port_tokens.size()) {
// there is no [
valid_ = (support_format_ & PORT_PARSER_SUPPORT_NO_PORT_FORMAT) != 0;
port_.set_width(1); port_.set_width(1);
return; /* We can finish here */ return; /* We can finish here */
} }
@ -72,19 +88,25 @@ void PortParser::parse() {
/* Split the pin string now */ /* Split the pin string now */
tokenizer.set_data(pin_tokens[0]); tokenizer.set_data(pin_tokens[0]);
pin_tokens = tokenizer.split(delim_); 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 */ /* Check if we have LSB and MSB or just one */
if (1 == pin_tokens.size()) { if (1 == pin_tokens.size()) {
/* Single pin */ /* 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()) { } else if (2 == pin_tokens.size()) {
/* A number of pins. /* A number of pins.
* Note that we always use the LSB for token[0] and MSB for token[1] * 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])) { valid_ = (support_format_ & PORT_PARSER_SUPPORT_RANGE_FORMAT) != 0;
port_.set_width(std::stoi(pin_tokens[1]), std::stoi(pin_tokens[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 { } 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; 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 * Member functions for MultiPortParser class
***********************************************************************/ ***********************************************************************/

View File

@ -21,37 +21,51 @@
/* namespace openfpga begins */ /* namespace openfpga begins */
namespace openfpga { 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 * Class PortParser: single port parser
* Supported port definition: * Supported port definition:
* 1. <port_name>[<LSB>:<MSB>] * (1) <port_name>[<LSB>:<MSB>]
* 2. <port_name>[<MSB>:<LSB>] * (2) <port_name>[<MSB>:<LSB>]
* 3. <port_name>[<single_pin_index>] * (3) <port_name>[<single_pin_index>]
* 4. <port_name>[] * (4) <port_name>[] -- this is not currently supported. Two problems:
* 5. <port_name> * * tokenizer will error out and
* * stoi cannot support empty string, and give
* std::invalid_argument error
* (5) <port_name>
* In case 4 and 5, we will assign (-1,-1) for LSB and MSB * In case 4 and 5, we will assign (-1,-1) for LSB and MSB
***********************************************************************/ ***********************************************************************/
class PortParser { class PortParser {
public: /* Constructors*/ public: /* Constructors*/
PortParser(const std::string& data); PortParser(const std::string& data,
const int support_format = PORT_PARSER_SUPPORT_ALL_FORMAT);
public: /* Public Accessors */ public: /* Public Accessors */
std::string data() const; std::string data() const;
BasicPort port() const; BasicPort port() const;
bool valid() const;
public: /* Public Mutators */ public: /* Public Mutators */
void set_support_format(const int support_format);
void set_data(const std::string& data); void set_data(const std::string& data);
private: /* Private Mutators */ private: /* Private Mutators */
void parse(); void parse();
void set_default_bracket(); void set_default_bracket();
void set_default_delim(); void set_default_delim();
size_t string_to_number(const std::string& str);
private: /* Internal data */ private: /* Internal data */
std::string data_; /* Lines to be splited */ std::string data_; /* Lines to be splited */
int support_format_;
vtr::Point<char> bracket_; vtr::Point<char> bracket_;
char delim_; char delim_;
BasicPort port_; BasicPort port_;
bool valid_;
}; };
/************************************************************************ /************************************************************************

View File

@ -69,7 +69,19 @@ int call_external_command(const Command& cmd,
return CMD_EXEC_FATAL_ERROR; return CMD_EXEC_FATAL_ERROR;
} }
return system(cmd_ss.c_str()); // Refer https://pubs.opengroup.org/onlinepubs/009695399/functions/system.html
// Refer
// https://pubs.opengroup.org/onlinepubs/009695399/functions/waitpid.html
int status = system(cmd_ss.c_str());
if (WIFEXITED(status)) {
// This is normal program exit, WEXITSTATUS() will help you shift the status
// accordingly (status >> 8)
// Becareful if the final status is 2 or beyond, program will not error
// as it is treated as CMD_EXEC_MINOR_ERROR
return WEXITSTATUS(status);
}
// Program maybe terminated because of various killed or stopped signal
return CMD_EXEC_FATAL_ERROR;
} }
} /* end namespace openfpga */ } /* end namespace openfpga */

View File

@ -16,6 +16,7 @@
#include "openfpga_digest.h" #include "openfpga_digest.h"
#include "openfpga_naming.h" #include "openfpga_naming.h"
#include "openfpga_reserved_words.h" #include "openfpga_reserved_words.h"
#include "overwrite_bitstream.h"
#include "read_xml_arch_bitstream.h" #include "read_xml_arch_bitstream.h"
#include "report_bitstream_distribution.h" #include "report_bitstream_distribution.h"
#include "vtr_log.h" #include "vtr_log.h"
@ -47,6 +48,10 @@ int fpga_bitstream_template(T& openfpga_ctx, const Command& cmd,
g_vpr_ctx, openfpga_ctx, cmd_context.option_enable(cmd, opt_verbose)); g_vpr_ctx, openfpga_ctx, cmd_context.option_enable(cmd, opt_verbose));
} }
overwrite_bitstream(openfpga_ctx.mutable_bitstream_manager(),
openfpga_ctx.bitstream_setting(),
cmd_context.option_enable(cmd, opt_verbose));
if (true == cmd_context.option_enable(cmd, opt_write_file)) { if (true == cmd_context.option_enable(cmd, opt_write_file)) {
std::string src_dir_path = std::string src_dir_path =
find_path_dir_name(cmd_context.option_value(cmd, opt_write_file)); find_path_dir_name(cmd_context.option_value(cmd, opt_write_file));

View File

@ -230,6 +230,7 @@ BitstreamManager build_device_bitstream(const VprContext& vpr_ctx,
openfpga_ctx.vpr_device_annotation(), openfpga_ctx.vpr_routing_annotation(), openfpga_ctx.vpr_device_annotation(), openfpga_ctx.vpr_routing_annotation(),
vpr_ctx.device().rr_graph, openfpga_ctx.device_rr_gsb(), vpr_ctx.device().rr_graph, openfpga_ctx.device_rr_gsb(),
openfpga_ctx.flow_manager().compress_routing(), verbose); openfpga_ctx.flow_manager().compress_routing(), verbose);
VTR_LOGV(verbose, "Done\n"); VTR_LOGV(verbose, "Done\n");
VTR_LOGV(verbose, "Decoded %lu configuration bits into %lu blocks\n", VTR_LOGV(verbose, "Decoded %lu configuration bits into %lu blocks\n",

View File

@ -0,0 +1,38 @@
/********************************************************************
* This file includes functions to build bitstream from a mapped
* FPGA fabric.
* We decode the bitstream from configuration of routing multiplexers
* and Look-Up Tables (LUTs) which locate in CLBs and global routing
*architecture
*******************************************************************/
/* Headers from vtrutil library */
#include "overwrite_bitstream.h"
#include "vtr_assert.h"
#include "vtr_log.h"
#include "vtr_time.h"
/* begin namespace openfpga */
namespace openfpga {
/********************************************************************
* Overwrite bitstream retrieve from bitstream annotation XML which stored in
*BitstreamSetting
*******************************************************************/
void overwrite_bitstream(openfpga::BitstreamManager& bitstream_manager,
const openfpga::BitstreamSetting& bitstream_setting,
const bool& verbose) {
vtr::ScopedStartFinishTimer timer("\nOverwrite Bitstream\n");
/* Apply overwrite_bitstream bit's path and value */
for (auto& id : bitstream_setting.overwrite_bitstreams()) {
std::string path = bitstream_setting.overwrite_bitstream_path(id);
bool value = bitstream_setting.overwrite_bitstream_value(id);
VTR_LOGV(verbose, "Overwrite bitstream path='%s' to value='%d'\n",
path.c_str(), value);
bitstream_manager.overwrite_bitstream(path, value);
}
}
} /* end namespace openfpga */

View File

@ -0,0 +1,23 @@
#ifndef OVERWRITE_BITSTREAM_H
#define OVERWRITE_BITSTREAM_H
/********************************************************************
* Include header files that are required by function declaration
*******************************************************************/
#include "openfpga_context.h"
/********************************************************************
* Function declaration
*******************************************************************/
/* begin namespace openfpga */
namespace openfpga {
void overwrite_bitstream(openfpga::BitstreamManager& bitstream_manager,
const openfpga::BitstreamSetting& bitstream_setting,
const bool& verbose);
} /* end namespace openfpga */
#endif

View File

@ -15,6 +15,9 @@ echo -e "Testing bitstream generation for an 48x48 FPGA device";
run-task fpga_bitstream/generate_bitstream/configuration_chain/device_48x48 $@ run-task fpga_bitstream/generate_bitstream/configuration_chain/device_48x48 $@
run-task fpga_bitstream/generate_bitstream/ql_memory_bank_shift_register/device_48x48 $@ run-task fpga_bitstream/generate_bitstream/ql_memory_bank_shift_register/device_48x48 $@
echo -e "Testing bitstream generation for an 4x4 FPGA device (randomly overwrite fabric bits)";
run-task fpga_bitstream/overwrite_bitstream/device_4x4 $@
echo -e "Testing bitstream generation for an 96x96 FPGA device"; echo -e "Testing bitstream generation for an 96x96 FPGA device";
run-task fpga_bitstream/generate_bitstream/configuration_chain/device_96x96 $@ run-task fpga_bitstream/generate_bitstream/configuration_chain/device_96x96 $@
run-task fpga_bitstream/generate_bitstream/ql_memory_bank_shift_register/device_72x72 $@ run-task fpga_bitstream/generate_bitstream/ql_memory_bank_shift_register/device_72x72 $@

View File

@ -0,0 +1,37 @@
# = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
# Configuration file for running experiments
# = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
# timeout_each_job : FPGA Task script splits fpga flow into multiple jobs
# Each job execute fpga_flow script on combination of architecture & benchmark
# timeout_each_job is timeout for each job
# = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
[GENERAL]
run_engine=openfpga_shell
power_tech_file = ${PATH:OPENFPGA_PATH}/openfpga_flow/tech/PTM_45nm/45nm.xml
power_analysis = false
spice_output=false
verilog_output=true
timeout_each_job = 20*60
fpga_flow=vpr_blif
[OpenFPGA_SHELL]
openfpga_shell_template=${PATH:OPENFPGA_PATH}/openfpga_flow/tasks/fpga_bitstream/overwrite_bitstream/device_4x4/config/test.openfpga
openfpga_arch_file=${PATH:OPENFPGA_PATH}/openfpga_flow/openfpga_arch/k6_frac_N10_adder_chain_mem16K_40nm_openfpga.xml
openfpga_sim_setting_file=${PATH:OPENFPGA_PATH}/openfpga_flow/openfpga_simulation_settings/auto_sim_openfpga.xml
openfpga_bitstream_setting_file=bitstream_annotation.xml
openfpga_vpr_device_layout=4x4
openfpga_ext_exec_python_script=${PATH:TASK_DIR}/config/test.py
[ARCHITECTURES]
arch0=${PATH:OPENFPGA_PATH}/openfpga_flow/vpr_arch/k6_frac_N10_tileable_thru_channel_adder_chain_wide_mem16K_40nm.xml
[BENCHMARKS]
bench0=${PATH:OPENFPGA_PATH}/openfpga_flow/benchmarks/micro_benchmark/and2/and2.blif
[SYNTHESIS_PARAM]
bench0_top = and2
bench0_act = ${PATH:OPENFPGA_PATH}/openfpga_flow/benchmarks/micro_benchmark/and2/and2.act
bench0_verilog = ${PATH:OPENFPGA_PATH}/openfpga_flow/benchmarks/micro_benchmark/and2/and2.v
[SCRIPT_PARAM_MIN_ROUTE_CHAN_WIDTH]

View File

@ -0,0 +1,53 @@
# Majority of the content refer to fix_device_example_script.openfpga
ext_exec --command "python3 ${OPENFPGA_EXT_EXEC_PYTHON_SCRIPT} run_golden ${OPENFPGA_PATH}"
ext_exec --command "python3 ${OPENFPGA_EXT_EXEC_PYTHON_SCRIPT} generate_testcase"
# Run VPR for the 'and' design
#--write_rr_graph example_rr_graph.xml
vpr ${VPR_ARCH_FILE} ${VPR_TESTBENCH_BLIF} --clock_modeling route --device ${OPENFPGA_VPR_DEVICE_LAYOUT}
# Read OpenFPGA architecture definition
read_openfpga_arch -f ${OPENFPGA_ARCH_FILE}
# Read OpenFPGA simulation settings
read_openfpga_simulation_setting -f ${OPENFPGA_SIM_SETTING_FILE}
# Read OpenFPGA bitstream settings
read_openfpga_bitstream_setting -f ${OPENFPGA_BITSTREAM_SETTING_FILE}
# Annotate the OpenFPGA architecture to VPR data base
# to debug use --verbose options
link_openfpga_arch --activity_file ${ACTIVITY_FILE} --sort_gsb_chan_node_in_edges
# Check and correct any naming conflicts in the BLIF netlist
check_netlist_naming_conflict --fix --report ./netlist_renaming.xml
# Apply fix-up to Look-Up Table truth tables based on packing results
lut_truth_table_fixup
# Build the module graph
# - Enabled compression on routing architecture modules
# - Enable pin duplication on grid modules
build_fabric --compress_routing #--verbose
# Repack the netlist to physical pbs
# This must be done before bitstream generator and testbench generation
# Strongly recommend it is done after all the fix-up have been applied
repack #--verbose
# Build the bitstream
# - Output the fabric-independent bitstream to a file
build_architecture_bitstream --verbose
# Build fabric-dependent bitstream
build_fabric_bitstream --verbose
# Write fabric-dependent bitstream
write_fabric_bitstream --file fabric_bitstream.xml --format xml
ext_exec --command "python3 ${OPENFPGA_EXT_EXEC_PYTHON_SCRIPT} validate"
# Finish and exit OpenFPGA
exit

View File

@ -0,0 +1,120 @@
import xml.etree.ElementTree as ET
import sys
import shutil
import os
import random
random.seed()
assert len(sys.argv) >= 2
assert sys.argv[1] in ["run_golden", "generate_testcase", "validate"]
TEST_BIT_COUNT = 200
def read_fabric_bitstream_xml(file) :
bit_count = 0
tree = ET.parse(file)
root = tree.getroot()
assert root.tag == "fabric_bitstream", "Root tag is not 'fabric_bitstream', but '%s'" % root.tag
for region in root :
assert region.tag == "region", "fabric_bitstream child node tag is not 'region', but '%s'" % region.tag
for bit in region :
assert bit.tag == "bit", "region child node tag is not 'bit', but '%s'" % bit.tag
assert "path" in bit.attrib, "Attribute 'path' does not exist in bit node"
assert "value" in bit.attrib, "Attribute 'value' does not exist in bit node"
assert bit.attrib["value"] in ["0", "1"]
bit_count += 1
return [tree, bit_count]
def read_bitstream_annotation_xml(file) :
xml = {}
tree = ET.parse(file)
root = tree.getroot()
assert root.tag == "openfpga_bitstream_setting", "Root tag is not 'openfpga_bitstream_setting', but '%s'" % root.tag
for overwrite_bitstream in root :
assert overwrite_bitstream.tag == "overwrite_bitstream", "openfpga_bitstream_setting child node tag is not 'overwrite_bitstream', but '%s'" % overwrite_bitstream.tag
for bit in overwrite_bitstream :
assert bit.tag == "bit", "overwrite_bitstream child node tag is not 'bit', but '%s'" % bit.tag
assert "path" in bit.attrib, "Attribute 'path' does not exist in bit node"
assert "value" in bit.attrib, "Attribute 'value' does not exist in bit node"
path = bit.attrib["path"]
assert path not in xml
index = path.rfind("[")
assert index != -1
path = "%s.mem_out%s" % (path[:index], path[index:])
assert path not in xml
assert bit.attrib["value"] in ["0", "1"]
xml[path] = bit.attrib["value"]
return xml
if sys.argv[1] == "run_golden" :
assert len(sys.argv) >= 3
openfpga_exe = os.path.abspath("%s/build/openfpga/openfpga" % sys.argv[2])
assert os.path.exists(openfpga_exe)
shutil.rmtree("golden", ignore_errors=True)
os.mkdir("golden")
original_openfpga = open("and2_run.openfpga")
golden_openfpga = open("golden/and2_run.openfpga", "w")
for line in original_openfpga :
if line.find("ext_exec") == 0 :
pass
else :
golden_openfpga.write(line)
golden_openfpga.close()
original_openfpga.close()
bitstream_annotation = open("golden/bitstream_annotation.xml", "w")
bitstream_annotation.write("<openfpga_bitstream_setting/>\n")
bitstream_annotation.close()
shutil.copyfile("and2.blif", "golden/and2.blif")
shutil.copyfile("and2_ace_out.act", "golden/and2_ace_out.act")
cmd = "cd golden && %s -batch -f and2_run.openfpga > golden.log" % (openfpga_exe)
assert os.system(cmd) == 0
elif sys.argv[1] == "generate_testcase" :
(tree, bit_count) = read_fabric_bitstream_xml("golden/fabric_bitstream.xml")
random_bits = []
while len(random_bits) != TEST_BIT_COUNT :
bit = random.randint(0, bit_count - 1)
if bit not in random_bits :
random_bits.append(bit)
bitstream_annotation = open("bitstream_annotation.xml", "w")
bitstream_annotation.write("<openfpga_bitstream_setting>\n")
bitstream_annotation.write(" <overwrite_bitstream>\n")
index = 0
for region in tree.getroot() :
for bit in region :
if index in random_bits :
path = bit.attrib["path"]
value = bit.attrib["value"]
assert value in ["0", "1"]
path = path.replace(".mem_out[", "[")
bitstream_annotation.write(" <bit value=\"%s\" path=\"%s\"/>\n" % ("1" if value == "0" else "0", path))
index += 1
bitstream_annotation.write(" </overwrite_bitstream>\n")
bitstream_annotation.write("</openfpga_bitstream_setting>\n")
bitstream_annotation.close()
else :
gtree = ET.parse("golden/fabric_bitstream.xml")
tree = ET.parse("fabric_bitstream.xml")
bitstream_annotation = read_bitstream_annotation_xml("bitstream_annotation.xml")
checked_count = 0
for gregion, region in zip(gtree.getroot(), tree.getroot()) :
for gbit, bit in zip(gregion, region) :
assert bit.attrib["path"] == gbit.attrib["path"]
path = bit.attrib["path"]
if path in bitstream_annotation :
# This is something we want to overwrite, hence the value should
# Same in the annotation file
# Not same in golden fabric
assert bit.attrib["value"] != gbit.attrib["value"]
assert bit.attrib["value"] == bitstream_annotation[path]
else :
# This is not what we want to overwrite
# Hence the value should same in golden fabric
assert bit.attrib["value"] == gbit.attrib["value"]
exit(0)