Merge pull request #59 from LNIS-Projects/dev

Runtime and memory improvement on bitstream database
This commit is contained in:
tangxifan 2020-07-03 18:32:54 -06:00 committed by GitHub
commit 83d6bf32d3
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
28 changed files with 723 additions and 173 deletions

View File

@ -99,6 +99,9 @@ python3 openfpga_flow/scripts/run_fpga_task.py openfpga_shell/generate_fabric --
echo -e "Testing Verilog testbench generation only"; echo -e "Testing Verilog testbench generation only";
python3 openfpga_flow/scripts/run_fpga_task.py openfpga_shell/generate_testbench --debug --show_thread_logs python3 openfpga_flow/scripts/run_fpga_task.py openfpga_shell/generate_testbench --debug --show_thread_logs
echo -e "Testing bitstream generation only";
python3 openfpga_flow/scripts/run_fpga_task.py openfpga_shell/generate_bitstream --debug --show_thread_logs
echo -e "Testing SDC generation with time units"; echo -e "Testing SDC generation with time units";
python3 openfpga_flow/scripts/run_fpga_task.py openfpga_shell/sdc_time_unit --debug --show_thread_logs python3 openfpga_flow/scripts/run_fpga_task.py openfpga_shell/sdc_time_unit --debug --show_thread_logs

View File

@ -9,17 +9,37 @@
/* begin namespace openfpga */ /* begin namespace openfpga */
namespace openfpga { namespace openfpga {
/**************************************************
* Public Constructors
*************************************************/
BitstreamManager::BitstreamManager() {
num_blocks_ = 0;
num_bits_ = 0;
invalid_block_ids_.clear();
invalid_bit_ids_.clear();
}
/************************************************** /**************************************************
* Public Accessors : Aggregates * Public Accessors : Aggregates
*************************************************/ *************************************************/
/* Find all the configuration bits */ /* Find all the configuration bits */
size_t BitstreamManager::num_bits() const {
return num_bits_;
}
BitstreamManager::config_bit_range BitstreamManager::bits() const { BitstreamManager::config_bit_range BitstreamManager::bits() const {
return vtr::make_range(bit_ids_.begin(), bit_ids_.end()); return vtr::make_range(config_bit_iterator(ConfigBitId(0), invalid_bit_ids_),
config_bit_iterator(ConfigBitId(num_bits_), invalid_bit_ids_));
}
size_t BitstreamManager::num_blocks() const {
return num_blocks_;
} }
/* Find all the configuration blocks */ /* Find all the configuration blocks */
BitstreamManager::config_block_range BitstreamManager::blocks() const { BitstreamManager::config_block_range BitstreamManager::blocks() const {
return vtr::make_range(block_ids_.begin(), block_ids_.end()); return vtr::make_range(config_block_iterator(ConfigBlockId(0), invalid_block_ids_),
config_block_iterator(ConfigBlockId(num_blocks_), invalid_block_ids_));
} }
/****************************************************************************** /******************************************************************************
@ -29,7 +49,7 @@ bool BitstreamManager::bit_value(const ConfigBitId& bit_id) const {
/* Ensure a valid id */ /* Ensure a valid id */
VTR_ASSERT(true == valid_bit_id(bit_id)); VTR_ASSERT(true == valid_bit_id(bit_id));
return bit_values_[bit_id]; return '1' == bit_values_[bit_id];
} }
std::string BitstreamManager::block_name(const ConfigBlockId& block_id) const { std::string BitstreamManager::block_name(const ConfigBlockId& block_id) const {
@ -57,32 +77,20 @@ std::vector<ConfigBitId> BitstreamManager::block_bits(const ConfigBlockId& block
/* Ensure the input ids are valid */ /* Ensure the input ids are valid */
VTR_ASSERT(true == valid_block_id(block_id)); VTR_ASSERT(true == valid_block_id(block_id));
return block_bit_ids_[block_id]; size_t lsb = block_bit_id_lsbs_[block_id];
} size_t length = block_bit_lengths_[block_id];
ConfigBlockId BitstreamManager::bit_parent_block(const ConfigBitId& bit_id) const { std::vector<ConfigBitId> bits(length, ConfigBitId::INVALID());
/* Ensure the input ids are valid */
VTR_ASSERT(true == valid_bit_id(bit_id));
return bit_parent_block_ids_[bit_id]; if (0 == length) {
} return bits;
size_t BitstreamManager::bit_index_in_parent_block(const ConfigBitId& bit_id) const {
/* Ensure the input ids are valid */
VTR_ASSERT(true == valid_bit_id(bit_id));
ConfigBlockId bit_parent_block = bit_parent_block_ids_[bit_id];
VTR_ASSERT(true == valid_block_id(bit_parent_block));
for (size_t index = 0; index < block_bits(bit_parent_block).size(); ++index) {
if (bit_id == block_bits(bit_parent_block)[index]) {
return index;
}
} }
/* Not found, return in valid value */ for (size_t i = lsb; i < lsb + length; ++i) {
return size_t(-1); bits[i - lsb] = ConfigBitId(i);
}
return bits;
} }
/* Find the child block in a bitstream manager with a given name */ /* Find the child block in a bitstream manager with a given name */
@ -133,20 +141,22 @@ std::vector<std::string> BitstreamManager::block_output_net_ids(const ConfigBloc
* Public Mutators * Public Mutators
******************************************************************************/ ******************************************************************************/
ConfigBitId BitstreamManager::add_bit(const bool& bit_value) { ConfigBitId BitstreamManager::add_bit(const bool& bit_value) {
ConfigBitId bit = ConfigBitId(bit_ids_.size()); ConfigBitId bit = ConfigBitId(num_bits_);
/* Add a new bit, and allocate associated data structures */ /* Add a new bit, and allocate associated data structures */
bit_ids_.push_back(bit); num_bits_++;
bit_values_.push_back(bit_value); if (true == bit_value) {
shared_config_bit_values_.emplace_back(); bit_values_.push_back('1');
bit_parent_block_ids_.push_back(ConfigBlockId::INVALID()); } else {
bit_values_.push_back('0');
}
return bit; return bit;
} }
void BitstreamManager::reserve_blocks(const size_t& num_blocks) { void BitstreamManager::reserve_blocks(const size_t& num_blocks) {
block_ids_.reserve(num_blocks);
block_names_.reserve(num_blocks); block_names_.reserve(num_blocks);
block_bit_ids_.reserve(num_blocks); block_bit_id_lsbs_.reserve(num_blocks);
block_bit_lengths_.reserve(num_blocks);
block_path_ids_.reserve(num_blocks); block_path_ids_.reserve(num_blocks);
block_input_net_ids_.reserve(num_blocks); block_input_net_ids_.reserve(num_blocks);
block_output_net_ids_.reserve(num_blocks); block_output_net_ids_.reserve(num_blocks);
@ -154,12 +164,17 @@ void BitstreamManager::reserve_blocks(const size_t& num_blocks) {
child_block_ids_.reserve(num_blocks); child_block_ids_.reserve(num_blocks);
} }
void BitstreamManager::reserve_bits(const size_t& num_bits) {
bit_values_.reserve(num_bits);
}
ConfigBlockId BitstreamManager::create_block() { ConfigBlockId BitstreamManager::create_block() {
ConfigBlockId block = ConfigBlockId(block_ids_.size()); ConfigBlockId block = ConfigBlockId(num_blocks_);
/* Add a new bit, and allocate associated data structures */ /* Add a new bit, and allocate associated data structures */
block_ids_.push_back(block); num_blocks_++;
block_names_.emplace_back(); block_names_.emplace_back();
block_bit_ids_.emplace_back(); block_bit_id_lsbs_.emplace_back(-1);
block_bit_lengths_.emplace_back(0);
block_path_ids_.push_back(-2); block_path_ids_.push_back(-2);
block_input_net_ids_.emplace_back(); block_input_net_ids_.emplace_back();
block_output_net_ids_.emplace_back(); block_output_net_ids_.emplace_back();
@ -183,6 +198,15 @@ void BitstreamManager::set_block_name(const ConfigBlockId& block_id,
block_names_[block_id] = block_name; block_names_[block_id] = block_name;
} }
void BitstreamManager::reserve_child_blocks(const ConfigBlockId& parent_block,
const size_t& num_children) {
/* Ensure the input ids are valid */
VTR_ASSERT(true == valid_block_id(parent_block));
/* Add the child_block to the parent_block */
child_block_ids_[parent_block].reserve(num_children);
}
void BitstreamManager::add_child_block(const ConfigBlockId& parent_block, const ConfigBlockId& child_block) { void BitstreamManager::add_child_block(const ConfigBlockId& parent_block, const ConfigBlockId& child_block) {
/* Ensure the input ids are valid */ /* Ensure the input ids are valid */
VTR_ASSERT(true == valid_block_id(parent_block)); VTR_ASSERT(true == valid_block_id(parent_block));
@ -201,18 +225,17 @@ void BitstreamManager::add_child_block(const ConfigBlockId& parent_block, const
parent_block_ids_[child_block] = parent_block; parent_block_ids_[child_block] = parent_block;
} }
void BitstreamManager::add_bit_to_block(const ConfigBlockId& block, const ConfigBitId& bit) { void BitstreamManager::add_block_bits(const ConfigBlockId& block,
const std::vector<bool>& block_bitstream) {
/* Ensure the input ids are valid */ /* Ensure the input ids are valid */
VTR_ASSERT(true == valid_block_id(block)); VTR_ASSERT(true == valid_block_id(block));
VTR_ASSERT(true == valid_bit_id(bit));
/* We should have only a parent block for each bit! */ /* Add the bit to the block, record anchors in bit indexing for block-level searching */
VTR_ASSERT(ConfigBlockId::INVALID() == bit_parent_block_ids_[bit]); block_bit_id_lsbs_[block] = num_bits_;
block_bit_lengths_[block] = block_bitstream.size();
/* Add the bit to the block */ for (const bool& bit : block_bitstream) {
block_bit_ids_[block].push_back(bit); add_bit(bit);
/* Register the block in the parent of the bit */ }
bit_parent_block_ids_[bit] = block;
} }
void BitstreamManager::add_path_id_to_block(const ConfigBlockId& block, const int& path_id) { void BitstreamManager::add_path_id_to_block(const ConfigBlockId& block, const int& path_id) {
@ -223,6 +246,14 @@ void BitstreamManager::add_path_id_to_block(const ConfigBlockId& block, const in
block_path_ids_[block] = path_id; block_path_ids_[block] = path_id;
} }
void BitstreamManager::reserve_block_input_net_ids(const ConfigBlockId& block,
const size_t& num_input_net_ids) {
/* Ensure the input ids are valid */
VTR_ASSERT(true == valid_block_id(block));
block_input_net_ids_[block].reserve(num_input_net_ids);
}
void BitstreamManager::add_input_net_id_to_block(const ConfigBlockId& block, void BitstreamManager::add_input_net_id_to_block(const ConfigBlockId& block,
const std::string& input_net_id) { const std::string& input_net_id) {
/* Ensure the input ids are valid */ /* Ensure the input ids are valid */
@ -232,6 +263,14 @@ void BitstreamManager::add_input_net_id_to_block(const ConfigBlockId& block,
block_input_net_ids_[block].push_back(input_net_id); block_input_net_ids_[block].push_back(input_net_id);
} }
void BitstreamManager::reserve_block_output_net_ids(const ConfigBlockId& block,
const size_t& num_output_net_ids) {
/* Ensure the input ids are valid */
VTR_ASSERT(true == valid_block_id(block));
block_output_net_ids_[block].reserve(num_output_net_ids);
}
void BitstreamManager::add_output_net_id_to_block(const ConfigBlockId& block, void BitstreamManager::add_output_net_id_to_block(const ConfigBlockId& block,
const std::string& output_net_id) { const std::string& output_net_id) {
/* Ensure the input ids are valid */ /* Ensure the input ids are valid */
@ -241,22 +280,15 @@ void BitstreamManager::add_output_net_id_to_block(const ConfigBlockId& block,
block_output_net_ids_[block].push_back(output_net_id); block_output_net_ids_[block].push_back(output_net_id);
} }
void BitstreamManager::add_shared_config_bit_values(const ConfigBitId& bit, const std::vector<bool>& shared_config_bits) {
/* Ensure the input ids are valid */
VTR_ASSERT(true == valid_bit_id(bit));
shared_config_bit_values_[bit] = shared_config_bits;
}
/****************************************************************************** /******************************************************************************
* Public Validators * Public Validators
******************************************************************************/ ******************************************************************************/
bool BitstreamManager::valid_bit_id(const ConfigBitId& bit_id) const { bool BitstreamManager::valid_bit_id(const ConfigBitId& bit_id) const {
return (size_t(bit_id) < bit_ids_.size()) && (bit_id == bit_ids_[bit_id]); return (size_t(bit_id) < num_bits_);
} }
bool BitstreamManager::valid_block_id(const ConfigBlockId& block_id) const { bool BitstreamManager::valid_block_id(const ConfigBlockId& block_id) const {
return (size_t(block_id) < block_ids_.size()) && (block_id == block_ids_[block_id]); return (size_t(block_id) < num_blocks_);
} }
bool BitstreamManager::valid_block_path_id(const ConfigBlockId& block_id) const { bool BitstreamManager::valid_block_path_id(const ConfigBlockId& block_id) const {

View File

@ -36,6 +36,8 @@
#include <vector> #include <vector>
#include <map> #include <map>
#include <unordered_set>
#include <unordered_map>
#include "vtr_vector.h" #include "vtr_vector.h"
#include "bitstream_manager_fwd.h" #include "bitstream_manager_fwd.h"
@ -44,17 +46,73 @@
namespace openfpga { namespace openfpga {
class BitstreamManager { class BitstreamManager {
public: /* Type implementations */
/*
* This class (forward delcared above) is a template used to represent a lazily calculated
* iterator of the specified ID type. The key assumption made is that the ID space is
* contiguous and can be walked by incrementing the underlying ID value. To account for
* invalid IDs, it keeps a reference to the invalid ID set and returns ID::INVALID() for
* ID values in the set.
*
* It is used to lazily create an iteration range (e.g. as returned by RRGraph::edges() RRGraph::nodes())
* just based on the count of allocated elements (i.e. RRGraph::num_nodes_ or RRGraph::num_edges_),
* and the set of any invalid IDs (i.e. RRGraph::invalid_node_ids_, RRGraph::invalid_edge_ids_).
*/
template<class ID>
class lazy_id_iterator : public std::iterator<std::bidirectional_iterator_tag, ID> {
public:
//Since we pass ID as a template to std::iterator we need to use an explicit 'typename'
//to bring the value_type and iterator names into scope
typedef typename std::iterator<std::bidirectional_iterator_tag, ID>::value_type value_type;
typedef typename std::iterator<std::bidirectional_iterator_tag, ID>::iterator iterator;
lazy_id_iterator(value_type init, const std::unordered_set<ID>& invalid_ids)
: value_(init)
, invalid_ids_(invalid_ids) {}
//Advance to the next ID value
iterator operator++() {
value_ = ID(size_t(value_) + 1);
return *this;
}
//Advance to the previous ID value
iterator operator--() {
value_ = ID(size_t(value_) - 1);
return *this;
}
//Dereference the iterator
value_type operator*() const { return (invalid_ids_.count(value_)) ? ID::INVALID() : value_; }
friend bool operator==(const lazy_id_iterator<ID> lhs, const lazy_id_iterator<ID> rhs) { return lhs.value_ == rhs.value_; }
friend bool operator!=(const lazy_id_iterator<ID> lhs, const lazy_id_iterator<ID> rhs) { return !(lhs == rhs); }
private:
value_type value_;
const std::unordered_set<ID>& invalid_ids_;
};
public: /* Public constructor */
BitstreamManager();
public: /* Types and ranges */ public: /* Types and ranges */
typedef vtr::vector<ConfigBitId, ConfigBitId>::const_iterator config_bit_iterator; //Lazy iterator utility forward declaration
typedef vtr::vector<ConfigBlockId, ConfigBlockId>::const_iterator config_block_iterator; template<class ID>
class lazy_id_iterator;
typedef lazy_id_iterator<ConfigBitId> config_bit_iterator;
typedef lazy_id_iterator<ConfigBlockId> config_block_iterator;
typedef vtr::Range<config_bit_iterator> config_bit_range; typedef vtr::Range<config_bit_iterator> config_bit_range;
typedef vtr::Range<config_block_iterator> config_block_range; typedef vtr::Range<config_block_iterator> config_block_range;
public: /* Public aggregators */ public: /* Public aggregators */
/* Find all the configuration bits */ /* Find all the configuration bits */
size_t num_bits() const;
config_bit_range bits() const; config_bit_range bits() const;
size_t num_blocks() const;
config_block_range blocks() const; config_block_range blocks() const;
public: /* Public Accessors */ public: /* Public Accessors */
@ -73,12 +131,6 @@ class BitstreamManager {
/* Find all the bits that belong to a block */ /* Find all the bits that belong to a block */
std::vector<ConfigBitId> block_bits(const ConfigBlockId& block_id) const; std::vector<ConfigBitId> block_bits(const ConfigBlockId& block_id) const;
/* Find the parent block of a bit */
ConfigBlockId bit_parent_block(const ConfigBitId& bit_id) const;
/* Find the index of a configuration bit in its parent block */
size_t bit_index_in_parent_block(const ConfigBitId& bit_id) const;
/* Find the child block in a bitstream manager with a given name */ /* Find the child block in a bitstream manager with a given name */
ConfigBlockId find_child_block(const ConfigBlockId& block_id, const std::string& child_block_name) const; ConfigBlockId find_child_block(const ConfigBlockId& block_id, const std::string& child_block_name) const;
@ -98,6 +150,9 @@ class BitstreamManager {
/* Reserve memory for a number of clocks */ /* Reserve memory for a number of clocks */
void reserve_blocks(const size_t& num_blocks); void reserve_blocks(const size_t& num_blocks);
/* Reserve memory for a number of bits */
void reserve_bits(const size_t& num_bits);
/* Create a new block of configuration bits */ /* Create a new block of configuration bits */
ConfigBlockId create_block(); ConfigBlockId create_block();
@ -108,24 +163,32 @@ class BitstreamManager {
void set_block_name(const ConfigBlockId& block_id, void set_block_name(const ConfigBlockId& block_id,
const std::string& block_name); const std::string& block_name);
/* Reserve child blocks for a block to be memory efficient */
void reserve_child_blocks(const ConfigBlockId& parent_block,
const size_t& num_children);
/* Set a block as a child block of another */ /* Set a block as a child block of another */
void add_child_block(const ConfigBlockId& parent_block, const ConfigBlockId& child_block); void add_child_block(const ConfigBlockId& parent_block, const ConfigBlockId& child_block);
/* Add a configuration bit to a block */ /* Add a bitstream to a block */
void add_bit_to_block(const ConfigBlockId& block, const ConfigBitId& bit); void add_block_bits(const ConfigBlockId& block,
const std::vector<bool>& block_bitstream);
/* Add a path id to a block */ /* Add a path id to a block */
void add_path_id_to_block(const ConfigBlockId& block, const int& path_id); void add_path_id_to_block(const ConfigBlockId& block, const int& path_id);
/* Reserve input net ids for a block */
void reserve_block_input_net_ids(const ConfigBlockId& block, const size_t& num_input_net_ids);
/* Add an input net id to a block */ /* Add an input net id to a block */
void add_input_net_id_to_block(const ConfigBlockId& block, const std::string& input_net_id); void add_input_net_id_to_block(const ConfigBlockId& block, const std::string& input_net_id);
/* Reserve output net ids for a block */
void reserve_block_output_net_ids(const ConfigBlockId& block, const size_t& num_output_net_ids);
/* Add an output net id to a block */ /* Add an output net id to a block */
void add_output_net_id_to_block(const ConfigBlockId& block, const std::string& output_net_id); void add_output_net_id_to_block(const ConfigBlockId& block, const std::string& output_net_id);
/* Add share configuration bits to a configuration bit */
void add_shared_config_bit_values(const ConfigBitId& bit, const std::vector<bool>& shared_config_bits);
public: /* Public Validators */ public: /* Public Validators */
bool valid_bit_id(const ConfigBitId& bit_id) const; bool valid_bit_id(const ConfigBitId& bit_id) const;
@ -135,8 +198,10 @@ class BitstreamManager {
private: /* Internal data */ private: /* Internal data */
/* Unique id of a block of bits in the Bitstream */ /* Unique id of a block of bits in the Bitstream */
vtr::vector<ConfigBlockId, ConfigBlockId> block_ids_; size_t num_blocks_;
vtr::vector<ConfigBlockId, std::vector<ConfigBitId>> block_bit_ids_; std::unordered_set<ConfigBlockId> invalid_block_ids_;
vtr::vector<ConfigBlockId, size_t> block_bit_id_lsbs_;
vtr::vector<ConfigBlockId, short> block_bit_lengths_;
/* Back-annotation for the bits */ /* Back-annotation for the bits */
/* Parent block of a bit in the Bitstream /* Parent block of a bit in the Bitstream
@ -160,7 +225,7 @@ class BitstreamManager {
* -Bitstream manager will NOT check if the id is good for bitstream builders * -Bitstream manager will NOT check if the id is good for bitstream builders
* It just store the results * It just store the results
*/ */
vtr::vector<ConfigBlockId, int> block_path_ids_; vtr::vector<ConfigBlockId, short> block_path_ids_;
/* Net ids that are mapped to inputs and outputs of this block /* Net ids that are mapped to inputs and outputs of this block
* *
@ -172,12 +237,10 @@ class BitstreamManager {
vtr::vector<ConfigBlockId, std::vector<std::string>> block_output_net_ids_; vtr::vector<ConfigBlockId, std::vector<std::string>> block_output_net_ids_;
/* Unique id of a bit in the Bitstream */ /* Unique id of a bit in the Bitstream */
vtr::vector<ConfigBitId, ConfigBitId> bit_ids_; size_t num_bits_;
vtr::vector<ConfigBitId, ConfigBlockId> bit_parent_block_ids_; std::unordered_set<ConfigBitId> invalid_bit_ids_;
/* value of a bit in the Bitstream */ /* value of a bit in the Bitstream */
vtr::vector<ConfigBitId, bool> bit_values_; vtr::vector<ConfigBitId, char> bit_values_;
/* value of a shared configuration bits in the Bitstream */
vtr::vector<ConfigBitId, std::vector<bool>> shared_config_bit_values_;
}; };
} /* end namespace openfpga */ } /* end namespace openfpga */

View File

@ -101,16 +101,17 @@ void rec_read_xml_bitstream_block(pugi::xml_node& xml_bitstream_block,
} }
/* Find the child paths/nets */ /* Find the child paths/nets */
std::vector<bool> block_bits;
for (pugi::xml_node xml_bit : xml_bitstream.children()) { for (pugi::xml_node xml_bit : xml_bitstream.children()) {
/* We only care child bitstream blocks here */ /* We only care child bitstream blocks here */
if (xml_bit.name() != std::string("bit")) { if (xml_bit.name() != std::string("bit")) {
bad_tag(xml_bit, loc_data, xml_bitstream, {"bit"}); bad_tag(xml_bit, loc_data, xml_bitstream, {"bit"});
} }
const int& bit_value = get_attribute(xml_bit, "value", loc_data).as_int(); const int& bit_value = get_attribute(xml_bit, "value", loc_data).as_int();
ConfigBitId bit = bitstream_manager.add_bit(1 == bit_value); block_bits.push_back(1 == bit_value);
/* Link the bit to parent block */ }
bitstream_manager.add_bit_to_block(curr_block, bit); /* Link the bit to parent block */
} bitstream_manager.add_block_bits(curr_block, block_bits);
} }
/* Go recursively: find all the child blocks and parse */ /* Go recursively: find all the child blocks and parse */

View File

@ -5,6 +5,7 @@
#include <map> #include <map>
#include <vector> #include <vector>
#include <functional> #include <functional>
#include <ctime>
#include "vtr_vector.h" #include "vtr_vector.h"
#include "vtr_range.h" #include "vtr_range.h"
@ -211,6 +212,9 @@ class Shell {
std::map<std::string, ShellCommandId> command_name2ids_; std::map<std::string, ShellCommandId> command_name2ids_;
std::map<std::string, ShellCommandClassId> command_class2ids_; std::map<std::string, ShellCommandClassId> command_class2ids_;
vtr::vector<ShellCommandClassId, std::vector<ShellCommandId>> commands_by_classes_; vtr::vector<ShellCommandClassId, std::vector<ShellCommandId>> commands_by_classes_;
/* Timer */
std::clock_t time_start_;
}; };
} /* End namespace openfpga */ } /* End namespace openfpga */

View File

@ -28,6 +28,7 @@ namespace openfpga {
template<class T> template<class T>
Shell<T>::Shell(const char* name) { Shell<T>::Shell(const char* name) {
name_ = std::string(name); name_ = std::string(name);
time_start_ = 0;
} }
/************************************************************************ /************************************************************************
@ -241,6 +242,9 @@ ShellCommandClassId Shell<T>::add_command_class(const char* name) {
template <class T> template <class T>
void Shell<T>::run_interactive_mode(T& context, const bool& quiet_mode) { void Shell<T>::run_interactive_mode(T& context, const bool& quiet_mode) {
if (false == quiet_mode) { if (false == quiet_mode) {
/* Reset timer since it does not come from another mode */
time_start_ = std::clock();
VTR_LOG("Start interactive mode of %s...\n", VTR_LOG("Start interactive mode of %s...\n",
name().c_str()); name().c_str());
@ -270,6 +274,8 @@ void Shell<T>::run_interactive_mode(T& context, const bool& quiet_mode) {
template <class T> template <class T>
void Shell<T>::run_script_mode(const char* script_file_name, T& context) { void Shell<T>::run_script_mode(const char* script_file_name, T& context) {
time_start_ = std::clock();
VTR_LOG("Reading script file %s...\n", script_file_name); VTR_LOG("Reading script file %s...\n", script_file_name);
/* Print the title of the shell */ /* Print the title of the shell */
@ -419,6 +425,9 @@ void Shell<T>::exit() const {
VTR_LOG("\nFinish execution with %d errors\n", VTR_LOG("\nFinish execution with %d errors\n",
num_err); num_err);
VTR_LOG("\nThe entire OpenFPGA flow took %g seconds\n",
(double)(std::clock() - time_start_) / (double)CLOCKS_PER_SEC);
VTR_LOG("\nThank you for using %s!\n", VTR_LOG("\nThank you for using %s!\n",
name().c_str()); name().c_str());

View File

@ -73,4 +73,59 @@ std::vector<size_t> itobin_vec(const size_t& in_int,
return ret; return ret;
} }
/********************************************************************
* Converter an integer to a binary vector
* For example:
* Input integer: 4
* Binary length : 3
* Output:
* index | 0 | 1 | 2
* ret | 0 | 0 | 1
*
* This function is optimized to return a vector of char
* which has a smaller memory footprint than size_t
********************************************************************/
std::vector<char> itobin_charvec(const size_t& in_int,
const size_t& bin_len) {
std::vector<char> ret(bin_len, '0');
/* Make sure we do not have any overflow! */
VTR_ASSERT ( (in_int < pow(2., bin_len)) );
size_t temp = in_int;
for (size_t i = 0; i < bin_len; i++) {
if (1 == temp % 2) {
ret[i] = '1'; /* Keep a good sequence of bits */
}
temp = temp / 2;
}
return ret;
}
/********************************************************************
* Converter a binary vector to an integer
* For example:
* Binary length : 3
* Input:
* index | 0 | 1 | 2
* ret | 0 | 0 | 1
*
* Output integer: 4
*
* This function is optimized to return a vector of char
* which has a smaller memory footprint than size_t
********************************************************************/
size_t bintoi_charvec(const std::vector<char>& bin) {
size_t ret = 0;
for (size_t i = 0; i < bin.size(); ++i) {
if ('1' == bin[i]) {
ret += pow(2., i);
}
}
return ret;
}
} /* end namespace openfpga */ } /* end namespace openfpga */

View File

@ -18,6 +18,11 @@ std::vector<size_t> ito1hot_vec(const size_t& in_int,
std::vector<size_t> itobin_vec(const size_t& in_int, std::vector<size_t> itobin_vec(const size_t& in_int,
const size_t& bin_len); const size_t& bin_len);
std::vector<char> itobin_charvec(const size_t& in_int,
const size_t& bin_len);
size_t bintoi_charvec(const std::vector<char>& bin);
} /* namespace openfpga ends */ } /* namespace openfpga ends */
#endif #endif

View File

@ -67,6 +67,7 @@ void compress_routing_hierarchy(OpenfpgaContext& openfpga_ctx,
int build_fabric(OpenfpgaContext& openfpga_ctx, int build_fabric(OpenfpgaContext& openfpga_ctx,
const Command& cmd, const CommandContext& cmd_context) { const Command& cmd, const CommandContext& cmd_context) {
CommandOptionId opt_frame_view = cmd.option("frame_view");
CommandOptionId opt_compress_routing = cmd.option("compress_routing"); CommandOptionId opt_compress_routing = cmd.option("compress_routing");
CommandOptionId opt_duplicate_grid_pin = cmd.option("duplicate_grid_pin"); CommandOptionId opt_duplicate_grid_pin = cmd.option("duplicate_grid_pin");
CommandOptionId opt_gen_random_fabric_key = cmd.option("generate_random_fabric_key"); CommandOptionId opt_gen_random_fabric_key = cmd.option("generate_random_fabric_key");
@ -96,6 +97,7 @@ int build_fabric(OpenfpgaContext& openfpga_ctx,
openfpga_ctx.mutable_decoder_lib(), openfpga_ctx.mutable_decoder_lib(),
const_cast<const OpenfpgaContext&>(openfpga_ctx), const_cast<const OpenfpgaContext&>(openfpga_ctx),
g_vpr_ctx.device(), g_vpr_ctx.device(),
cmd_context.option_enable(cmd, opt_frame_view),
cmd_context.option_enable(cmd, opt_compress_routing), cmd_context.option_enable(cmd, opt_compress_routing),
cmd_context.option_enable(cmd, opt_duplicate_grid_pin), cmd_context.option_enable(cmd, opt_duplicate_grid_pin),
predefined_fabric_key, predefined_fabric_key,

View File

@ -134,7 +134,7 @@ std::string generate_mux_branch_subckt_name(const CircuitLibrary& circuit_lib,
***********************************************/ ***********************************************/
std::string generate_mux_local_decoder_subckt_name(const size_t& addr_size, std::string generate_mux_local_decoder_subckt_name(const size_t& addr_size,
const size_t& data_size) { const size_t& data_size) {
std::string subckt_name = "decoder"; std::string subckt_name = "local_encoder";
subckt_name += std::to_string(addr_size); subckt_name += std::to_string(addr_size);
subckt_name += "to"; subckt_name += "to";
subckt_name += std::to_string(data_size); subckt_name += std::to_string(data_size);

View File

@ -267,6 +267,9 @@ ShellCommandId add_openfpga_build_fabric_command(openfpga::Shell<OpenfpgaContext
Command shell_cmd("build_fabric"); Command shell_cmd("build_fabric");
/* Add an option '--frame_view' */
shell_cmd.add_option("frame_view", false, "Build only frame view of the fabric (nets are skipped)");
/* Add an option '--compress_routing' */ /* Add an option '--compress_routing' */
shell_cmd.add_option("compress_routing", false, "Compress the number of unique routing modules by identifying the unique GSBs"); shell_cmd.add_option("compress_routing", false, "Compress the number of unique routing modules by identifying the unique GSBs");

View File

@ -30,6 +30,7 @@ ModuleManager build_device_module_graph(IoLocationMap& io_location_map,
DecoderLibrary& decoder_lib, DecoderLibrary& decoder_lib,
const OpenfpgaContext& openfpga_ctx, const OpenfpgaContext& openfpga_ctx,
const DeviceContext& vpr_device_ctx, const DeviceContext& vpr_device_ctx,
const bool& frame_view,
const bool& compress_routing, const bool& compress_routing,
const bool& duplicate_grid_pin, const bool& duplicate_grid_pin,
const FabricKey& fabric_key, const FabricKey& fabric_key,
@ -118,7 +119,7 @@ ModuleManager build_device_module_graph(IoLocationMap& io_location_map,
openfpga_ctx.arch().arch_direct, openfpga_ctx.arch().arch_direct,
openfpga_ctx.arch().config_protocol.type(), openfpga_ctx.arch().config_protocol.type(),
sram_model, sram_model,
compress_routing, duplicate_grid_pin, frame_view, compress_routing, duplicate_grid_pin,
fabric_key, generate_random_fabric_key); fabric_key, generate_random_fabric_key);
/* Now a critical correction has to be done! /* Now a critical correction has to be done!

View File

@ -19,6 +19,7 @@ ModuleManager build_device_module_graph(IoLocationMap& io_location_map,
DecoderLibrary& decoder_lib, DecoderLibrary& decoder_lib,
const OpenfpgaContext& openfpga_ctx, const OpenfpgaContext& openfpga_ctx,
const DeviceContext& vpr_device_ctx, const DeviceContext& vpr_device_ctx,
const bool& frame_view,
const bool& compress_routing, const bool& compress_routing,
const bool& duplicate_grid_pin, const bool& duplicate_grid_pin,
const FabricKey& fabric_key, const FabricKey& fabric_key,

View File

@ -329,6 +329,7 @@ void build_top_module(ModuleManager& module_manager,
const ArchDirect& arch_direct, const ArchDirect& arch_direct,
const e_config_protocol_type& sram_orgz_type, const e_config_protocol_type& sram_orgz_type,
const CircuitModelId& sram_model, const CircuitModelId& sram_model,
const bool& frame_view,
const bool& compact_routing_hierarchy, const bool& compact_routing_hierarchy,
const bool& duplicate_grid_pin, const bool& duplicate_grid_pin,
const FabricKey& fabric_key, const FabricKey& fabric_key,
@ -351,18 +352,23 @@ void build_top_module(ModuleManager& module_manager,
cb_instance_ids[CHANX] = add_top_module_connection_block_instances(module_manager, top_module, device_rr_gsb, CHANX, compact_routing_hierarchy); cb_instance_ids[CHANX] = add_top_module_connection_block_instances(module_manager, top_module, device_rr_gsb, CHANX, compact_routing_hierarchy);
cb_instance_ids[CHANY] = add_top_module_connection_block_instances(module_manager, top_module, device_rr_gsb, CHANY, compact_routing_hierarchy); cb_instance_ids[CHANY] = add_top_module_connection_block_instances(module_manager, top_module, device_rr_gsb, CHANY, compact_routing_hierarchy);
/* Reserve nets to be memory efficient */ /* Add nets when we need a complete fabric modeling,
reserve_module_manager_module_nets(module_manager, top_module); * which is required by downstream functions
*/
if (false == frame_view) {
/* Reserve nets to be memory efficient */
reserve_module_manager_module_nets(module_manager, top_module);
/* Add module nets to connect the sub modules */ /* Add module nets to connect the sub modules */
add_top_module_nets_connect_grids_and_gsbs(module_manager, top_module, add_top_module_nets_connect_grids_and_gsbs(module_manager, top_module,
grids, grid_instance_ids, grids, grid_instance_ids,
rr_graph, device_rr_gsb, sb_instance_ids, cb_instance_ids, rr_graph, device_rr_gsb, sb_instance_ids, cb_instance_ids,
compact_routing_hierarchy, duplicate_grid_pin); compact_routing_hierarchy, duplicate_grid_pin);
/* Add inter-CLB direct connections */ /* Add inter-CLB direct connections */
add_top_module_nets_tile_direct_connections(module_manager, top_module, circuit_lib, add_top_module_nets_tile_direct_connections(module_manager, top_module, circuit_lib,
grids, grid_instance_ids, grids, grid_instance_ids,
tile_direct, arch_direct); tile_direct, arch_direct);
}
/* Add global ports to the pb_module: /* Add global ports to the pb_module:
* This is a much easier job after adding sub modules (instances), * This is a much easier job after adding sub modules (instances),

View File

@ -36,6 +36,7 @@ void build_top_module(ModuleManager& module_manager,
const ArchDirect& arch_direct, const ArchDirect& arch_direct,
const e_config_protocol_type& sram_orgz_type, const e_config_protocol_type& sram_orgz_type,
const CircuitModelId& sram_model, const CircuitModelId& sram_model,
const bool& frame_view,
const bool& compact_routing_hierarchy, const bool& compact_routing_hierarchy,
const bool& duplicate_grid_pin, const bool& duplicate_grid_pin,
const FabricKey& fabric_key, const FabricKey& fabric_key,

View File

@ -20,6 +20,82 @@
/* begin namespace openfpga */ /* begin namespace openfpga */
namespace openfpga { namespace openfpga {
/********************************************************************
* Estimate the number of blocks to be added to the whole device bitstream
* This function will recursively walk through the module graph
* from the specified top module and count the number of configurable children
* which are the blocks that will be added to the bitstream manager
*******************************************************************/
static
size_t rec_estimate_device_bitstream_num_blocks(const ModuleManager& module_manager,
const ModuleId& top_module) {
size_t num_blocks = 0;
/* Those child modules which have no children are
* actually configurable memory elements
* We skip them in couting
*/
if (0 == module_manager.configurable_children(top_module).size()) {
return 0;
}
size_t num_configurable_children = module_manager.configurable_children(top_module).size();
for (size_t ichild = 0; ichild < num_configurable_children; ++ichild) {
ModuleId child_module = module_manager.configurable_children(top_module)[ichild];
num_blocks += rec_estimate_device_bitstream_num_blocks(module_manager, child_module);
}
/* Add the number of blocks at current level */
num_blocks++;
return num_blocks;
}
/********************************************************************
* Estimate the number of configuration bits to be added to the whole device bitstream
* This function will recursively walk through the module graph
* from the specified top module and count the number of leaf configurable children
* which are the bits that will be added to the bitstream manager
*******************************************************************/
static
size_t rec_estimate_device_bitstream_num_bits(const ModuleManager& module_manager,
const ModuleId& top_module,
const e_config_protocol_type& config_protocol_type) {
size_t num_bits = 0;
/* If a child module has no configurable children, this is a leaf node
* We can count it in. Otherwise, we should go recursively.
*/
if (0 == module_manager.configurable_children(top_module).size()) {
return 1;
}
size_t num_configurable_children = module_manager.configurable_children(top_module).size();
/* Frame-based configuration protocol will have 1 decoder
* if there are more than 1 configurable children
*/
if ( (CONFIG_MEM_FRAME_BASED == config_protocol_type)
&& (2 <= num_configurable_children)) {
num_configurable_children--;
}
/* Memory configuration protocol will have 2 decoders
* at the top-level
*/
if (CONFIG_MEM_MEMORY_BANK == config_protocol_type) {
std::string top_block_name = generate_fpga_top_module_name();
if (top_module == module_manager.find_module(top_block_name)) {
num_configurable_children -= 2;
}
}
for (size_t ichild = 0; ichild < num_configurable_children; ++ichild) {
ModuleId child_module = module_manager.configurable_children(top_module)[ichild];
num_bits += rec_estimate_device_bitstream_num_bits(module_manager, child_module, config_protocol_type);
}
return num_bits;
}
/******************************************************************** /********************************************************************
* A top-level function to build a bistream from the FPGA device * A top-level function to build a bistream from the FPGA device
* 1. It will organize the bitstream w.r.t. the hierarchy of module graphs * 1. It will organize the bitstream w.r.t. the hierarchy of module graphs
@ -52,6 +128,25 @@ BitstreamManager build_device_bitstream(const VprContext& vpr_ctx,
*/ */
std::string top_block_name = generate_fpga_top_module_name(); std::string top_block_name = generate_fpga_top_module_name();
ConfigBlockId top_block = bitstream_manager.add_block(top_block_name); ConfigBlockId top_block = bitstream_manager.add_block(top_block_name);
const ModuleId& top_module = openfpga_ctx.module_graph().find_module(top_block_name);
VTR_ASSERT(true == openfpga_ctx.module_graph().valid_module_id(top_module));
/* Estimate the number of blocks to be added to the database */
size_t num_blocks_to_reserve = rec_estimate_device_bitstream_num_blocks(openfpga_ctx.module_graph(),
top_module);
bitstream_manager.reserve_blocks(num_blocks_to_reserve);
VTR_LOGV(verbose, "Reserved %lu configurable blocks\n", num_blocks_to_reserve);
/* Estimate the number of bits to be added to the database */
size_t num_bits_to_reserve = rec_estimate_device_bitstream_num_bits(openfpga_ctx.module_graph(),
top_module,
openfpga_ctx.arch().config_protocol.type());
bitstream_manager.reserve_bits(num_bits_to_reserve);
VTR_LOGV(verbose, "Reserved %lu configuration bits\n", num_bits_to_reserve);
/* Reserve child blocks for the top level block */
bitstream_manager.reserve_child_blocks(top_block,
openfpga_ctx.module_graph().configurable_children(top_module).size());
/* Create bitstream from grids */ /* Create bitstream from grids */
VTR_LOGV(verbose, "Building grid bitstream...\n"); VTR_LOGV(verbose, "Building grid bitstream...\n");
@ -80,7 +175,13 @@ BitstreamManager build_device_bitstream(const VprContext& vpr_ctx,
openfpga_ctx.device_rr_gsb()); openfpga_ctx.device_rr_gsb());
VTR_LOGV(verbose, "Done\n"); VTR_LOGV(verbose, "Done\n");
VTR_LOGV(verbose, "Decoded %lu configuration bits\n", bitstream_manager.bits().size()); VTR_LOGV(verbose,
"Decoded %lu configuration bits into %lu blocks\n",
bitstream_manager.num_bits(),
bitstream_manager.num_blocks());
//VTR_ASSERT(num_blocks_to_reserve == bitstream_manager.num_blocks());
//VTR_ASSERT(num_bits_to_reserve == bitstream_manager.num_bits());
return bitstream_manager; return bitstream_manager;
} }

View File

@ -158,11 +158,11 @@ void rec_build_module_fabric_dependent_memory_bank_bitstream(const BitstreamMana
/* Find BL address */ /* Find BL address */
size_t cur_bl_index = std::floor(cur_mem_index / num_bls); size_t cur_bl_index = std::floor(cur_mem_index / num_bls);
std::vector<size_t> bl_addr_bits_vec = itobin_vec(cur_bl_index, bl_addr_size); std::vector<char> bl_addr_bits_vec = itobin_charvec(cur_bl_index, bl_addr_size);
/* Find WL address */ /* Find WL address */
size_t cur_wl_index = cur_mem_index % num_wls; size_t cur_wl_index = cur_mem_index % num_wls;
std::vector<size_t> wl_addr_bits_vec = itobin_vec(cur_wl_index, wl_addr_size); std::vector<char> wl_addr_bits_vec = itobin_charvec(cur_wl_index, wl_addr_size);
/* Set BL address */ /* Set BL address */
fabric_bitstream.set_bit_bl_address(fabric_bit, bl_addr_bits_vec); fabric_bitstream.set_bit_bl_address(fabric_bit, bl_addr_bits_vec);
@ -206,7 +206,7 @@ void rec_build_module_fabric_dependent_frame_bitstream(const BitstreamManager& b
const std::vector<ConfigBlockId>& parent_blocks, const std::vector<ConfigBlockId>& parent_blocks,
const ModuleManager& module_manager, const ModuleManager& module_manager,
const std::vector<ModuleId>& parent_modules, const std::vector<ModuleId>& parent_modules,
const std::vector<size_t>& addr_code, const std::vector<char>& addr_code,
FabricBitstream& fabric_bitstream) { FabricBitstream& fabric_bitstream) {
/* Depth-first search: if we have any children in the parent_block, /* Depth-first search: if we have any children in the parent_block,
@ -272,13 +272,13 @@ void rec_build_module_fabric_dependent_frame_bitstream(const BitstreamManager& b
child_modules.push_back(child_module); child_modules.push_back(child_module);
/* Set address, apply binary conversion from the first to the last element in the address list */ /* Set address, apply binary conversion from the first to the last element in the address list */
std::vector<size_t> child_addr_code = addr_code; std::vector<char> child_addr_code = addr_code;
if (true == add_addr_code) { if (true == add_addr_code) {
/* Find the address port from the decoder module */ /* Find the address port from the decoder module */
const ModulePortId& decoder_addr_port_id = module_manager.find_module_port(decoder_module, std::string(DECODER_ADDRESS_PORT_NAME)); const ModulePortId& decoder_addr_port_id = module_manager.find_module_port(decoder_module, std::string(DECODER_ADDRESS_PORT_NAME));
const BasicPort& decoder_addr_port = module_manager.module_port(decoder_module, decoder_addr_port_id); const BasicPort& decoder_addr_port = module_manager.module_port(decoder_module, decoder_addr_port_id);
std::vector<size_t> addr_bits_vec = itobin_vec(child_id, decoder_addr_port.get_width()); std::vector<char> addr_bits_vec = itobin_charvec(child_id, decoder_addr_port.get_width());
child_addr_code.insert(child_addr_code.begin(), addr_bits_vec.begin(), addr_bits_vec.end()); child_addr_code.insert(child_addr_code.begin(), addr_bits_vec.begin(), addr_bits_vec.end());
@ -316,7 +316,7 @@ void rec_build_module_fabric_dependent_frame_bitstream(const BitstreamManager& b
const ModulePortId& child_addr_port_id = module_manager.find_module_port(child_module, std::string(DECODER_ADDRESS_PORT_NAME)); const ModulePortId& child_addr_port_id = module_manager.find_module_port(child_module, std::string(DECODER_ADDRESS_PORT_NAME));
const BasicPort& child_addr_port = module_manager.module_port(child_module, child_addr_port_id); const BasicPort& child_addr_port = module_manager.module_port(child_module, child_addr_port_id);
if (0 < max_child_addr_code_size - child_addr_port.get_width()) { if (0 < max_child_addr_code_size - child_addr_port.get_width()) {
std::vector<size_t> dummy_codes(max_child_addr_code_size - child_addr_port.get_width(), 0); std::vector<char> dummy_codes(max_child_addr_code_size - child_addr_port.get_width(), '0');
child_addr_code.insert(child_addr_code.begin(), dummy_codes.begin(), dummy_codes.end()); child_addr_code.insert(child_addr_code.begin(), dummy_codes.begin(), dummy_codes.end());
} }
} }
@ -349,9 +349,9 @@ void rec_build_module_fabric_dependent_frame_bitstream(const BitstreamManager& b
for (size_t ibit = 0; ibit < bitstream_manager.block_bits(parent_blocks.back()).size(); ++ibit) { for (size_t ibit = 0; ibit < bitstream_manager.block_bits(parent_blocks.back()).size(); ++ibit) {
ConfigBitId config_bit = bitstream_manager.block_bits(parent_blocks.back())[ibit]; ConfigBitId config_bit = bitstream_manager.block_bits(parent_blocks.back())[ibit];
std::vector<size_t> addr_bits_vec = itobin_vec(ibit, decoder_addr_port.get_width()); std::vector<char> addr_bits_vec = itobin_charvec(ibit, decoder_addr_port.get_width());
std::vector<size_t> child_addr_code = addr_code; std::vector<char> child_addr_code = addr_code;
child_addr_code.insert(child_addr_code.begin(), addr_bits_vec.begin(), addr_bits_vec.end()); child_addr_code.insert(child_addr_code.begin(), addr_bits_vec.begin(), addr_bits_vec.end());
@ -379,12 +379,18 @@ void build_module_fabric_dependent_bitstream(const ConfigProtocol& config_protoc
switch (config_protocol.type()) { switch (config_protocol.type()) {
case CONFIG_MEM_STANDALONE: { case CONFIG_MEM_STANDALONE: {
/* Reserve bits before build-up */
fabric_bitstream.reserve_bits(bitstream_manager.num_bits());
rec_build_module_fabric_dependent_chain_bitstream(bitstream_manager, top_block, rec_build_module_fabric_dependent_chain_bitstream(bitstream_manager, top_block,
module_manager, top_module, module_manager, top_module,
fabric_bitstream); fabric_bitstream);
break; break;
} }
case CONFIG_MEM_SCAN_CHAIN: { case CONFIG_MEM_SCAN_CHAIN: {
/* Reserve bits before build-up */
fabric_bitstream.reserve_bits(bitstream_manager.num_bits());
rec_build_module_fabric_dependent_chain_bitstream(bitstream_manager, top_block, rec_build_module_fabric_dependent_chain_bitstream(bitstream_manager, top_block,
module_manager, top_module, module_manager, top_module,
fabric_bitstream); fabric_bitstream);
@ -392,6 +398,7 @@ void build_module_fabric_dependent_bitstream(const ConfigProtocol& config_protoc
break; break;
} }
case CONFIG_MEM_MEMORY_BANK: { case CONFIG_MEM_MEMORY_BANK: {
size_t cur_mem_index = 0; size_t cur_mem_index = 0;
/* Find BL address port size */ /* Find BL address port size */
ModulePortId bl_addr_port = module_manager.find_module_port(top_module, std::string(DECODER_BL_ADDRESS_PORT_NAME)); ModulePortId bl_addr_port = module_manager.find_module_port(top_module, std::string(DECODER_BL_ADDRESS_PORT_NAME));
@ -415,6 +422,13 @@ void build_module_fabric_dependent_bitstream(const ConfigProtocol& config_protoc
ModulePortId wl_port = module_manager.find_module_port(wl_decoder_module, std::string(DECODER_DATA_OUT_PORT_NAME)); ModulePortId wl_port = module_manager.find_module_port(wl_decoder_module, std::string(DECODER_DATA_OUT_PORT_NAME));
BasicPort wl_port_info = module_manager.module_port(wl_decoder_module, wl_port); BasicPort wl_port_info = module_manager.module_port(wl_decoder_module, wl_port);
/* Reserve bits before build-up */
fabric_bitstream.set_use_address(true);
fabric_bitstream.set_use_wl_address(true);
fabric_bitstream.set_bl_address_length(bl_addr_port_info.get_width());
fabric_bitstream.set_wl_address_length(wl_addr_port_info.get_width());
fabric_bitstream.reserve_bits(bitstream_manager.num_bits());
rec_build_module_fabric_dependent_memory_bank_bitstream(bitstream_manager, top_block, rec_build_module_fabric_dependent_memory_bank_bitstream(bitstream_manager, top_block,
module_manager, top_module, top_module, module_manager, top_module, top_module,
bl_addr_port_info.get_width(), bl_addr_port_info.get_width(),
@ -425,11 +439,21 @@ void build_module_fabric_dependent_bitstream(const ConfigProtocol& config_protoc
break; break;
} }
case CONFIG_MEM_FRAME_BASED: { case CONFIG_MEM_FRAME_BASED: {
/* Find address port size */
ModulePortId addr_port = module_manager.find_module_port(top_module, std::string(DECODER_ADDRESS_PORT_NAME));
BasicPort addr_port_info = module_manager.module_port(top_module, addr_port);
/* Reserve bits before build-up */
fabric_bitstream.set_use_address(true);
fabric_bitstream.reserve_bits(bitstream_manager.num_bits());
fabric_bitstream.set_address_length(addr_port_info.get_width());
rec_build_module_fabric_dependent_frame_bitstream(bitstream_manager, rec_build_module_fabric_dependent_frame_bitstream(bitstream_manager,
std::vector<ConfigBlockId>(1, top_block), std::vector<ConfigBlockId>(1, top_block),
module_manager, module_manager,
std::vector<ModuleId>(1, top_module), std::vector<ModuleId>(1, top_module),
std::vector<size_t>(), std::vector<char>(),
fabric_bitstream); fabric_bitstream);
break; break;
} }
@ -459,7 +483,7 @@ void build_module_fabric_dependent_bitstream(const ConfigProtocol& config_protoc
*/ */
/* Ensure our fabric bitstream is in the same size as device bistream */ /* Ensure our fabric bitstream is in the same size as device bistream */
VTR_ASSERT(bitstream_manager.bits().size() == fabric_bitstream.bits().size()); VTR_ASSERT(bitstream_manager.num_bits() == fabric_bitstream.num_bits());
} }
/******************************************************************** /********************************************************************
@ -495,6 +519,7 @@ FabricBitstream build_fabric_dependent_bitstream(const BitstreamManager& bitstre
VTR_ASSERT(1 == top_block.size()); VTR_ASSERT(1 == top_block.size());
VTR_ASSERT(0 == top_module_name.compare(bitstream_manager.block_name(top_block[0]))); VTR_ASSERT(0 == top_module_name.compare(bitstream_manager.block_name(top_block[0])));
/* Start build-up formally */
build_module_fabric_dependent_bitstream(config_protocol, build_module_fabric_dependent_bitstream(config_protocol,
bitstream_manager, top_block[0], bitstream_manager, top_block[0],
module_manager, top_module, module_manager, top_module,
@ -502,7 +527,7 @@ FabricBitstream build_fabric_dependent_bitstream(const BitstreamManager& bitstre
VTR_LOGV(verbose, VTR_LOGV(verbose,
"Built %lu configuration bits for fabric\n", "Built %lu configuration bits for fabric\n",
fabric_bitstream.bits().size()); fabric_bitstream.num_bits());
return fabric_bitstream; return fabric_bitstream;
} }

View File

@ -106,11 +106,7 @@ void build_primitive_bitstream(BitstreamManager& bitstream_manager,
bitstream_manager.add_child_block(parent_configurable_block, mem_block); bitstream_manager.add_child_block(parent_configurable_block, mem_block);
/* Add the bitstream to the bitstream manager */ /* Add the bitstream to the bitstream manager */
for (const bool& bit : mode_select_bitstream) { bitstream_manager.add_block_bits(mem_block, mode_select_bitstream);
ConfigBitId config_bit = bitstream_manager.add_bit(bit);
/* Link the memory bits to the mux mem block */
bitstream_manager.add_bit_to_block(mem_block, config_bit);
}
} }
/******************************************************************** /********************************************************************
@ -214,13 +210,10 @@ void build_physical_block_pin_interc_bitstream(BitstreamManager& bitstream_manag
VTR_ASSERT(mux_bitstream.size() == module_manager.module_port(mux_mem_module, mux_mem_out_port_id).get_width()); VTR_ASSERT(mux_bitstream.size() == module_manager.module_port(mux_mem_module, mux_mem_out_port_id).get_width());
/* Add the bistream to the bitstream manager */ /* Add the bistream to the bitstream manager */
for (const bool& bit : mux_bitstream) { bitstream_manager.add_block_bits(mux_mem_block, mux_bitstream);
ConfigBitId config_bit = bitstream_manager.add_bit(bit);
/* Link the memory bits to the mux mem block */
bitstream_manager.add_bit_to_block(mux_mem_block, config_bit);
}
/* Record path ids, input and output nets */ /* Record path ids, input and output nets */
bitstream_manager.add_path_id_to_block(mux_mem_block, mux_input_pin_id); bitstream_manager.add_path_id_to_block(mux_mem_block, mux_input_pin_id);
bitstream_manager.reserve_block_input_net_ids(mux_mem_block, input_nets.size());
for (const AtomNetId& input_net : input_nets) { for (const AtomNetId& input_net : input_nets) {
if (true == atom_ctx.nlist.valid_net_id(input_net)) { if (true == atom_ctx.nlist.valid_net_id(input_net)) {
bitstream_manager.add_input_net_id_to_block(mux_mem_block, atom_ctx.nlist.net_name(input_net)); bitstream_manager.add_input_net_id_to_block(mux_mem_block, atom_ctx.nlist.net_name(input_net));
@ -229,6 +222,7 @@ void build_physical_block_pin_interc_bitstream(BitstreamManager& bitstream_manag
} }
} }
if (true == atom_ctx.nlist.valid_net_id(output_net)) { if (true == atom_ctx.nlist.valid_net_id(output_net)) {
bitstream_manager.reserve_block_output_net_ids(mux_mem_block, 1);
bitstream_manager.add_output_net_id_to_block(mux_mem_block, atom_ctx.nlist.net_name(output_net)); bitstream_manager.add_output_net_id_to_block(mux_mem_block, atom_ctx.nlist.net_name(output_net));
} else { } else {
bitstream_manager.add_output_net_id_to_block(mux_mem_block, std::string("unmapped")); bitstream_manager.add_output_net_id_to_block(mux_mem_block, std::string("unmapped"));
@ -465,11 +459,7 @@ void build_lut_bitstream(BitstreamManager& bitstream_manager,
bitstream_manager.add_child_block(parent_configurable_block, mem_block); bitstream_manager.add_child_block(parent_configurable_block, mem_block);
/* Add the bitstream to the bitstream manager */ /* Add the bitstream to the bitstream manager */
for (const bool& bit : lut_bitstream) { bitstream_manager.add_block_bits(mem_block, lut_bitstream);
ConfigBitId config_bit = bitstream_manager.add_bit(bit);
/* Link the memory bits to the mux mem block */
bitstream_manager.add_bit_to_block(mem_block, config_bit);
}
} }
/******************************************************************** /********************************************************************

View File

@ -98,13 +98,10 @@ void build_switch_block_mux_bitstream(BitstreamManager& bitstream_manager,
VTR_ASSERT(mux_bitstream.size() == module_manager.module_port(mux_mem_module, mux_mem_out_port_id).get_width()); VTR_ASSERT(mux_bitstream.size() == module_manager.module_port(mux_mem_module, mux_mem_out_port_id).get_width());
/* Add the bistream to the bitstream manager */ /* Add the bistream to the bitstream manager */
for (const bool& bit : mux_bitstream) { bitstream_manager.add_block_bits(mux_mem_block, mux_bitstream);
ConfigBitId config_bit = bitstream_manager.add_bit(bit);
/* Link the memory bits to the mux mem block */
bitstream_manager.add_bit_to_block(mux_mem_block, config_bit);
}
/* Record path ids, input and output nets */ /* Record path ids, input and output nets */
bitstream_manager.add_path_id_to_block(mux_mem_block, path_id); bitstream_manager.add_path_id_to_block(mux_mem_block, path_id);
bitstream_manager.reserve_block_input_net_ids(mux_mem_block, input_nets.size());
for (const ClusterNetId& input_net : input_nets) { for (const ClusterNetId& input_net : input_nets) {
AtomNetId input_atom_net = atom_ctx.lookup.atom_net(input_net); AtomNetId input_atom_net = atom_ctx.lookup.atom_net(input_net);
if (true == atom_ctx.nlist.valid_net_id(input_atom_net)) { if (true == atom_ctx.nlist.valid_net_id(input_atom_net)) {
@ -114,6 +111,7 @@ void build_switch_block_mux_bitstream(BitstreamManager& bitstream_manager,
} }
} }
AtomNetId output_atom_net = atom_ctx.lookup.atom_net(output_net); AtomNetId output_atom_net = atom_ctx.lookup.atom_net(output_net);
bitstream_manager.reserve_block_output_net_ids(mux_mem_block, 1);
if (true == atom_ctx.nlist.valid_net_id(output_atom_net)) { if (true == atom_ctx.nlist.valid_net_id(output_atom_net)) {
bitstream_manager.add_output_net_id_to_block(mux_mem_block, atom_ctx.nlist.net_name(output_atom_net)); bitstream_manager.add_output_net_id_to_block(mux_mem_block, atom_ctx.nlist.net_name(output_atom_net));
} else { } else {
@ -289,13 +287,10 @@ void build_connection_block_mux_bitstream(BitstreamManager& bitstream_manager,
VTR_ASSERT(mux_bitstream.size() == module_manager.module_port(mux_mem_module, mux_mem_out_port_id).get_width()); VTR_ASSERT(mux_bitstream.size() == module_manager.module_port(mux_mem_module, mux_mem_out_port_id).get_width());
/* Add the bistream to the bitstream manager */ /* Add the bistream to the bitstream manager */
for (const bool& bit : mux_bitstream) { bitstream_manager.add_block_bits(mux_mem_block, mux_bitstream);
ConfigBitId config_bit = bitstream_manager.add_bit(bit);
/* Link the memory bits to the mux mem block */
bitstream_manager.add_bit_to_block(mux_mem_block, config_bit);
}
/* Record path ids, input and output nets */ /* Record path ids, input and output nets */
bitstream_manager.add_path_id_to_block(mux_mem_block, path_id); bitstream_manager.add_path_id_to_block(mux_mem_block, path_id);
bitstream_manager.reserve_block_input_net_ids(mux_mem_block, input_nets.size());
for (const ClusterNetId& input_net : input_nets) { for (const ClusterNetId& input_net : input_nets) {
AtomNetId input_atom_net = atom_ctx.lookup.atom_net(input_net); AtomNetId input_atom_net = atom_ctx.lookup.atom_net(input_net);
if (true == atom_ctx.nlist.valid_net_id(input_atom_net)) { if (true == atom_ctx.nlist.valid_net_id(input_atom_net)) {
@ -305,6 +300,7 @@ void build_connection_block_mux_bitstream(BitstreamManager& bitstream_manager,
} }
} }
AtomNetId output_atom_net = atom_ctx.lookup.atom_net(output_net); AtomNetId output_atom_net = atom_ctx.lookup.atom_net(output_net);
bitstream_manager.reserve_block_output_net_ids(mux_mem_block, 1);
if (true == atom_ctx.nlist.valid_net_id(output_atom_net)) { if (true == atom_ctx.nlist.valid_net_id(output_atom_net)) {
bitstream_manager.add_output_net_id_to_block(mux_mem_block, atom_ctx.nlist.net_name(output_atom_net)); bitstream_manager.add_output_net_id_to_block(mux_mem_block, atom_ctx.nlist.net_name(output_atom_net));
} else { } else {

View File

@ -4,17 +4,33 @@
#include <algorithm> #include <algorithm>
#include "vtr_assert.h" #include "vtr_assert.h"
#include "openfpga_decode.h"
#include "fabric_bitstream.h" #include "fabric_bitstream.h"
/* begin namespace openfpga */ /* begin namespace openfpga */
namespace openfpga { namespace openfpga {
/**************************************************
* Public Constructor
*************************************************/
FabricBitstream::FabricBitstream() {
num_bits_ = 0;
invalid_bit_ids_.clear();
address_length_ = 0;
wl_address_length_ = 0;
}
/************************************************** /**************************************************
* Public Accessors : Aggregates * Public Accessors : Aggregates
*************************************************/ *************************************************/
size_t FabricBitstream::num_bits() const {
return num_bits_;
}
/* Find all the configuration bits */ /* Find all the configuration bits */
FabricBitstream::fabric_bit_range FabricBitstream::bits() const { FabricBitstream::fabric_bit_range FabricBitstream::bits() const {
return vtr::make_range(bit_ids_.begin(), bit_ids_.end()); return vtr::make_range(fabric_bit_iterator(FabricBitId(0), invalid_bit_ids_),
fabric_bit_iterator(FabricBitId(num_bits_), invalid_bit_ids_));
} }
/****************************************************************************** /******************************************************************************
@ -27,79 +43,145 @@ ConfigBitId FabricBitstream::config_bit(const FabricBitId& bit_id) const {
return config_bit_ids_[bit_id]; return config_bit_ids_[bit_id];
} }
std::vector<size_t> FabricBitstream::bit_address(const FabricBitId& bit_id) const { std::vector<char> FabricBitstream::bit_address(const FabricBitId& bit_id) const {
/* Ensure a valid id */ /* Ensure a valid id */
VTR_ASSERT(true == valid_bit_id(bit_id)); VTR_ASSERT(true == valid_bit_id(bit_id));
VTR_ASSERT(true == use_address_);
return bit_addresses_[bit_id][0]; return itobin_charvec(bit_addresses_[bit_id], address_length_);
} }
std::vector<size_t> FabricBitstream::bit_bl_address(const FabricBitId& bit_id) const { std::vector<char> FabricBitstream::bit_bl_address(const FabricBitId& bit_id) const {
return bit_address(bit_id); return bit_address(bit_id);
} }
std::vector<size_t> FabricBitstream::bit_wl_address(const FabricBitId& bit_id) const { std::vector<char> FabricBitstream::bit_wl_address(const FabricBitId& bit_id) const {
/* Ensure a valid id */ /* Ensure a valid id */
VTR_ASSERT(true == valid_bit_id(bit_id)); VTR_ASSERT(true == valid_bit_id(bit_id));
VTR_ASSERT(true == use_address_);
VTR_ASSERT(true == use_wl_address_);
return bit_addresses_[bit_id][1]; return itobin_charvec(bit_wl_addresses_[bit_id], wl_address_length_);
} }
bool FabricBitstream::bit_din(const FabricBitId& bit_id) const { char FabricBitstream::bit_din(const FabricBitId& bit_id) const {
/* Ensure a valid id */ /* Ensure a valid id */
VTR_ASSERT(true == valid_bit_id(bit_id)); VTR_ASSERT(true == valid_bit_id(bit_id));
VTR_ASSERT(true == use_address_);
return bit_dins_[bit_id]; return bit_dins_[bit_id];
} }
bool FabricBitstream::use_address() const {
return use_address_;
}
bool FabricBitstream::use_wl_address() const {
return use_wl_address_;
}
/****************************************************************************** /******************************************************************************
* Public Mutators * Public Mutators
******************************************************************************/ ******************************************************************************/
void FabricBitstream::reserve_bits(const size_t& num_bits) {
config_bit_ids_.reserve(num_bits);
if (true == use_address_) {
bit_addresses_.reserve(num_bits);
bit_dins_.reserve(num_bits);
if (true == use_wl_address_) {
bit_wl_addresses_.reserve(num_bits);
}
}
}
FabricBitId FabricBitstream::add_bit(const ConfigBitId& config_bit_id) { FabricBitId FabricBitstream::add_bit(const ConfigBitId& config_bit_id) {
FabricBitId bit = FabricBitId(bit_ids_.size()); FabricBitId bit = FabricBitId(num_bits_);
/* Add a new bit, and allocate associated data structures */ /* Add a new bit, and allocate associated data structures */
bit_ids_.push_back(bit); num_bits_++;
config_bit_ids_.push_back(config_bit_id); config_bit_ids_.push_back(config_bit_id);
bit_addresses_.emplace_back();
bit_dins_.push_back(false);
return bit; return bit;
} }
void FabricBitstream::set_bit_address(const FabricBitId& bit_id, void FabricBitstream::set_bit_address(const FabricBitId& bit_id,
const std::vector<size_t>& address) { const std::vector<char>& address) {
VTR_ASSERT(true == valid_bit_id(bit_id)); VTR_ASSERT(true == valid_bit_id(bit_id));
bit_addresses_[bit_id][0] = address; VTR_ASSERT(true == use_address_);
VTR_ASSERT(address_length_ == address.size());
bit_addresses_[bit_id] = bintoi_charvec(address);
} }
void FabricBitstream::set_bit_bl_address(const FabricBitId& bit_id, void FabricBitstream::set_bit_bl_address(const FabricBitId& bit_id,
const std::vector<size_t>& address) { const std::vector<char>& address) {
set_bit_address(bit_id, address); set_bit_address(bit_id, address);
} }
void FabricBitstream::set_bit_wl_address(const FabricBitId& bit_id, void FabricBitstream::set_bit_wl_address(const FabricBitId& bit_id,
const std::vector<size_t>& address) { const std::vector<char>& address) {
VTR_ASSERT(true == valid_bit_id(bit_id)); VTR_ASSERT(true == valid_bit_id(bit_id));
bit_addresses_[bit_id][1] = address; VTR_ASSERT(true == use_address_);
VTR_ASSERT(true == use_wl_address_);
VTR_ASSERT(wl_address_length_ == address.size());
bit_wl_addresses_[bit_id] = bintoi_charvec(address);
} }
void FabricBitstream::set_bit_din(const FabricBitId& bit_id, void FabricBitstream::set_bit_din(const FabricBitId& bit_id,
const bool& din) { const char& din) {
VTR_ASSERT(true == valid_bit_id(bit_id)); VTR_ASSERT(true == valid_bit_id(bit_id));
VTR_ASSERT(true == use_address_);
bit_dins_[bit_id] = din; bit_dins_[bit_id] = din;
} }
void FabricBitstream::reverse() { void FabricBitstream::reverse() {
std::reverse(config_bit_ids_.begin(), config_bit_ids_.end()); std::reverse(config_bit_ids_.begin(), config_bit_ids_.end());
std::reverse(bit_addresses_.begin(), bit_addresses_.end());
std::reverse(bit_dins_.begin(), bit_dins_.end()); if (true == use_address_) {
std::reverse(bit_addresses_.begin(), bit_addresses_.end());
std::reverse(bit_dins_.begin(), bit_dins_.end());
if (true == use_wl_address_) {
std::reverse(bit_wl_addresses_.begin(), bit_wl_addresses_.end());
}
}
}
void FabricBitstream::set_use_address(const bool& enable) {
/* Add a lock, only can be modified when num bits are zero*/
if (0 == num_bits_) {
use_address_ = enable;
}
}
void FabricBitstream::set_address_length(const size_t& length) {
if (true == use_address_) {
address_length_ = length;
}
}
void FabricBitstream::set_bl_address_length(const size_t& length) {
set_address_length(length);
}
void FabricBitstream::set_use_wl_address(const bool& enable) {
/* Add a lock, only can be modified when num bits are zero*/
if (0 == num_bits_) {
use_wl_address_ = enable;
}
}
void FabricBitstream::set_wl_address_length(const size_t& length) {
if (true == use_address_) {
wl_address_length_ = length;
}
} }
/****************************************************************************** /******************************************************************************
* Public Validators * Public Validators
******************************************************************************/ ******************************************************************************/
bool FabricBitstream::valid_bit_id(const FabricBitId& bit_id) const { char FabricBitstream::valid_bit_id(const FabricBitId& bit_id) const {
return (size_t(bit_id) < bit_ids_.size()) && (bit_id == bit_ids_[bit_id]); return (size_t(bit_id) < num_bits_);
} }
} /* end namespace openfpga */ } /* end namespace openfpga */

View File

@ -29,6 +29,8 @@
#define FABRIC_BITSTREAM_H #define FABRIC_BITSTREAM_H
#include <vector> #include <vector>
#include <unordered_set>
#include <unordered_map>
#include "vtr_vector.h" #include "vtr_vector.h"
#include "bitstream_manager_fwd.h" #include "bitstream_manager_fwd.h"
@ -38,13 +40,68 @@
namespace openfpga { namespace openfpga {
class FabricBitstream { class FabricBitstream {
public: /* Type implementations */
/*
* This class (forward delcared above) is a template used to represent a lazily calculated
* iterator of the specified ID type. The key assumption made is that the ID space is
* contiguous and can be walked by incrementing the underlying ID value. To account for
* invalid IDs, it keeps a reference to the invalid ID set and returns ID::INVALID() for
* ID values in the set.
*
* It is used to lazily create an iteration range (e.g. as returned by RRGraph::edges() RRGraph::nodes())
* just based on the count of allocated elements (i.e. RRGraph::num_nodes_ or RRGraph::num_edges_),
* and the set of any invalid IDs (i.e. RRGraph::invalid_node_ids_, RRGraph::invalid_edge_ids_).
*/
template<class ID>
class lazy_id_iterator : public std::iterator<std::bidirectional_iterator_tag, ID> {
public:
//Since we pass ID as a template to std::iterator we need to use an explicit 'typename'
//to bring the value_type and iterator names into scope
typedef typename std::iterator<std::bidirectional_iterator_tag, ID>::value_type value_type;
typedef typename std::iterator<std::bidirectional_iterator_tag, ID>::iterator iterator;
lazy_id_iterator(value_type init, const std::unordered_set<ID>& invalid_ids)
: value_(init)
, invalid_ids_(invalid_ids) {}
//Advance to the next ID value
iterator operator++() {
value_ = ID(size_t(value_) + 1);
return *this;
}
//Advance to the previous ID value
iterator operator--() {
value_ = ID(size_t(value_) - 1);
return *this;
}
//Dereference the iterator
value_type operator*() const { return (invalid_ids_.count(value_)) ? ID::INVALID() : value_; }
friend bool operator==(const lazy_id_iterator<ID> lhs, const lazy_id_iterator<ID> rhs) { return lhs.value_ == rhs.value_; }
friend bool operator!=(const lazy_id_iterator<ID> lhs, const lazy_id_iterator<ID> rhs) { return !(lhs == rhs); }
private:
value_type value_;
const std::unordered_set<ID>& invalid_ids_;
};
public: /* Types and ranges */ public: /* Types and ranges */
typedef vtr::vector<FabricBitId, FabricBitId>::const_iterator fabric_bit_iterator; //Lazy iterator utility forward declaration
template<class ID>
class lazy_id_iterator;
typedef lazy_id_iterator<FabricBitId> fabric_bit_iterator;
typedef vtr::Range<fabric_bit_iterator> fabric_bit_range; typedef vtr::Range<fabric_bit_iterator> fabric_bit_range;
public: /* Public constructor */
FabricBitstream();
public: /* Public aggregators */ public: /* Public aggregators */
/* Find all the configuration bits */ /* Find all the configuration bits */
size_t num_bits() const;
fabric_bit_range bits() const; fabric_bit_range bits() const;
public: /* Public Accessors */ public: /* Public Accessors */
@ -52,52 +109,85 @@ class FabricBitstream {
ConfigBitId config_bit(const FabricBitId& bit_id) const; ConfigBitId config_bit(const FabricBitId& bit_id) const;
/* Find the address of bitstream */ /* Find the address of bitstream */
std::vector<size_t> bit_address(const FabricBitId& bit_id) const; std::vector<char> bit_address(const FabricBitId& bit_id) const;
std::vector<size_t> bit_bl_address(const FabricBitId& bit_id) const; std::vector<char> bit_bl_address(const FabricBitId& bit_id) const;
std::vector<size_t> bit_wl_address(const FabricBitId& bit_id) const; std::vector<char> bit_wl_address(const FabricBitId& bit_id) const;
/* Find the data-in of bitstream */ /* Find the data-in of bitstream */
bool bit_din(const FabricBitId& bit_id) const; char bit_din(const FabricBitId& bit_id) const;
/* Check if address data is accessible or not*/
bool use_address() const;
bool use_wl_address() const;
public: /* Public Mutators */ public: /* Public Mutators */
/* Reserve config bits */
void reserve_bits(const size_t& num_bits);
/* Add a new configuration bit to the bitstream manager */ /* Add a new configuration bit to the bitstream manager */
FabricBitId add_bit(const ConfigBitId& config_bit_id); FabricBitId add_bit(const ConfigBitId& config_bit_id);
void set_bit_address(const FabricBitId& bit_id, void set_bit_address(const FabricBitId& bit_id,
const std::vector<size_t>& address); const std::vector<char>& address);
void set_bit_bl_address(const FabricBitId& bit_id, void set_bit_bl_address(const FabricBitId& bit_id,
const std::vector<size_t>& address); const std::vector<char>& address);
void set_bit_wl_address(const FabricBitId& bit_id, void set_bit_wl_address(const FabricBitId& bit_id,
const std::vector<size_t>& address); const std::vector<char>& address);
void set_bit_din(const FabricBitId& bit_id, void set_bit_din(const FabricBitId& bit_id,
const bool& din); const char& din);
/* Reverse bit sequence of the fabric bitstream /* Reverse bit sequence of the fabric bitstream
* This is required by configuration chain protocol * This is required by configuration chain protocol
*/ */
void reverse(); void reverse();
/* Enable the use of address-related data
* When this is enabled, data allocation will be applied to these data
* and users can access/modify the data
* Otherwise, it will NOT be allocated and accessible.
*
* This function is only applicable before any bits are added
*/
void set_use_address(const bool& enable);
void set_address_length(const size_t& length);
void set_bl_address_length(const size_t& length);
/* Enable the use of WL-address related data
* Same priniciple as the set_use_address()
*/
void set_use_wl_address(const bool& enable);
void set_wl_address_length(const size_t& length);
public: /* Public Validators */ public: /* Public Validators */
bool valid_bit_id(const FabricBitId& bit_id) const; char valid_bit_id(const FabricBitId& bit_id) const;
private: /* Internal data */ private: /* Internal data */
/* Unique id of a bit in the Bitstream */ /* Unique id of a bit in the Bitstream */
vtr::vector<FabricBitId, FabricBitId> bit_ids_; size_t num_bits_;
std::unordered_set<FabricBitId> invalid_bit_ids_;
vtr::vector<FabricBitId, ConfigBitId> config_bit_ids_; vtr::vector<FabricBitId, ConfigBitId> config_bit_ids_;
/* Flags to indicate if the addresses and din should be enabled */
bool use_address_;
bool use_wl_address_;
size_t address_length_;
size_t wl_address_length_;
/* Address bits: this is designed for memory decoders /* Address bits: this is designed for memory decoders
* Here we store the binary format of the address, which can be loaded * Here we store the binary format of the address, which can be loaded
* to the configuration protocol directly * to the configuration protocol directly
* *
* We use a 2-element array, as we may have a BL address and a WL address * We use a 2-element array, as we may have a BL address and a WL address
*/ */
vtr::vector<FabricBitId, std::array<std::vector<size_t>, 2>> bit_addresses_; vtr::vector<FabricBitId, size_t> bit_addresses_;
vtr::vector<FabricBitId, size_t> bit_wl_addresses_;
/* Data input (Din) bits: this is designed for memory decoders */ /* Data input (Din) bits: this is designed for memory decoders */
vtr::vector<FabricBitId, bool> bit_dins_; vtr::vector<FabricBitId, char> bit_dins_;
}; };
} /* end namespace openfpga */ } /* end namespace openfpga */

View File

@ -50,11 +50,11 @@ int write_fabric_config_bit_to_text_file(std::fstream& fp,
fp << bitstream_manager.bit_value(fabric_bitstream.config_bit(fabric_bit)); fp << bitstream_manager.bit_value(fabric_bitstream.config_bit(fabric_bit));
break; break;
case CONFIG_MEM_MEMORY_BANK: { case CONFIG_MEM_MEMORY_BANK: {
for (const size_t& addr_bit : fabric_bitstream.bit_bl_address(fabric_bit)) { for (const char& addr_bit : fabric_bitstream.bit_bl_address(fabric_bit)) {
fp << addr_bit; fp << addr_bit;
} }
write_space_to_file(fp, 1); write_space_to_file(fp, 1);
for (const size_t& addr_bit : fabric_bitstream.bit_wl_address(fabric_bit)) { for (const char& addr_bit : fabric_bitstream.bit_wl_address(fabric_bit)) {
fp << addr_bit; fp << addr_bit;
} }
write_space_to_file(fp, 1); write_space_to_file(fp, 1);
@ -63,7 +63,7 @@ int write_fabric_config_bit_to_text_file(std::fstream& fp,
break; break;
} }
case CONFIG_MEM_FRAME_BASED: { case CONFIG_MEM_FRAME_BASED: {
for (const size_t& addr_bit : fabric_bitstream.bit_address(fabric_bit)) { for (const char& addr_bit : fabric_bitstream.bit_address(fabric_bit)) {
fp << addr_bit; fp << addr_bit;
} }
write_space_to_file(fp, 1); write_space_to_file(fp, 1);
@ -101,7 +101,7 @@ int write_fabric_bitstream_to_text_file(const BitstreamManager& bitstream_manage
VTR_LOG_ERROR("Received empty file name to output bitstream!\n\tPlease specify a valid file name.\n"); VTR_LOG_ERROR("Received empty file name to output bitstream!\n\tPlease specify a valid file name.\n");
} }
std::string timer_message = std::string("Write ") + std::to_string(fabric_bitstream.bits().size()) + std::string(" fabric bitstream into plain text file '") + fname + std::string("'"); std::string timer_message = std::string("Write ") + std::to_string(fabric_bitstream.num_bits()) + std::string(" fabric bitstream into plain text file '") + fname + std::string("'");
vtr::ScopedStartFinishTimer timer(timer_message); vtr::ScopedStartFinishTimer timer(timer_message);
/* Create the file stream */ /* Create the file stream */

View File

@ -78,6 +78,7 @@ void print_verilog_simulation_info(const std::string& ini_fname,
ini["SIMULATION_DECK"]["VERILOG_PATH "] = std::string(src_dir); ini["SIMULATION_DECK"]["VERILOG_PATH "] = std::string(src_dir);
ini["SIMULATION_DECK"]["VERILOG_FILE1"] = std::string(DEFINES_VERILOG_FILE_NAME); ini["SIMULATION_DECK"]["VERILOG_FILE1"] = std::string(DEFINES_VERILOG_FILE_NAME);
ini["SIMULATION_DECK"]["VERILOG_FILE2"] = std::string(circuit_name + std::string(TOP_INCLUDE_NETLIST_FILE_NAME_POSTFIX)); ini["SIMULATION_DECK"]["VERILOG_FILE2"] = std::string(circuit_name + std::string(TOP_INCLUDE_NETLIST_FILE_NAME_POSTFIX));
ini["SIMULATION_DECK"]["CONFIG_PROTOCOL"] = std::string(CONFIG_PROTOCOL_TYPE_STRING[config_protocol_type]);
/* Information required by UVM */ /* Information required by UVM */
if (CONFIG_MEM_FRAME_BASED == config_protocol_type) { if (CONFIG_MEM_FRAME_BASED == config_protocol_type) {

View File

@ -234,7 +234,7 @@ namespace openfpga
atom_ctx, place_ctx, io_location_map, atom_ctx, place_ctx, io_location_map,
module_manager, module_manager,
config_protocol_type, config_protocol_type,
bitstream_manager.bits().size(), bitstream_manager.num_bits(),
simulation_setting.num_clock_cycles(), simulation_setting.num_clock_cycles(),
simulation_setting.programming_clock_frequency(), simulation_setting.programming_clock_frequency(),
simulation_setting.operating_clock_frequency()); simulation_setting.operating_clock_frequency());

View File

@ -562,7 +562,7 @@ static
size_t calculate_num_config_clock_cycles(const e_config_protocol_type& sram_orgz_type, size_t calculate_num_config_clock_cycles(const e_config_protocol_type& sram_orgz_type,
const bool& fast_configuration, const bool& fast_configuration,
const FabricBitstream& fabric_bitstream) { const FabricBitstream& fabric_bitstream) {
size_t num_config_clock_cycles = 1 + fabric_bitstream.bits().size(); size_t num_config_clock_cycles = 1 + fabric_bitstream.num_bits();
/* Branch on the type of configuration protocol */ /* Branch on the type of configuration protocol */
switch (sram_orgz_type) { switch (sram_orgz_type) {
@ -1223,14 +1223,14 @@ void print_verilog_top_testbench_memory_bank_bitstream(std::fstream& fp,
fp << "\t\t" << std::string(TOP_TESTBENCH_PROG_TASK_NAME); fp << "\t\t" << std::string(TOP_TESTBENCH_PROG_TASK_NAME);
fp << "(" << bl_addr_port.get_width() << "'b"; fp << "(" << bl_addr_port.get_width() << "'b";
VTR_ASSERT(bl_addr_port.get_width() == fabric_bitstream.bit_bl_address(bit_id).size()); VTR_ASSERT(bl_addr_port.get_width() == fabric_bitstream.bit_bl_address(bit_id).size());
for (const size_t& addr_bit : fabric_bitstream.bit_bl_address(bit_id)) { for (const char& addr_bit : fabric_bitstream.bit_bl_address(bit_id)) {
fp << addr_bit; fp << addr_bit;
} }
fp << ", "; fp << ", ";
fp << wl_addr_port.get_width() << "'b"; fp << wl_addr_port.get_width() << "'b";
VTR_ASSERT(wl_addr_port.get_width() == fabric_bitstream.bit_wl_address(bit_id).size()); VTR_ASSERT(wl_addr_port.get_width() == fabric_bitstream.bit_wl_address(bit_id).size());
for (const size_t& addr_bit : fabric_bitstream.bit_wl_address(bit_id)) { for (const char& addr_bit : fabric_bitstream.bit_wl_address(bit_id)) {
fp << addr_bit; fp << addr_bit;
} }
@ -1319,7 +1319,7 @@ void print_verilog_top_testbench_frame_decoder_bitstream(std::fstream& fp,
fp << "\t\t" << std::string(TOP_TESTBENCH_PROG_TASK_NAME); fp << "\t\t" << std::string(TOP_TESTBENCH_PROG_TASK_NAME);
fp << "(" << addr_port.get_width() << "'b"; fp << "(" << addr_port.get_width() << "'b";
VTR_ASSERT(addr_port.get_width() == fabric_bitstream.bit_address(bit_id).size()); VTR_ASSERT(addr_port.get_width() == fabric_bitstream.bit_address(bit_id).size());
for (const size_t& addr_bit : fabric_bitstream.bit_address(bit_id)) { for (const char& addr_bit : fabric_bitstream.bit_address(bit_id)) {
fp << addr_bit; fp << addr_bit;
} }
fp << ", "; fp << ", ";

View File

@ -25,6 +25,7 @@
* Main function to start OpenFPGA shell interface * Main function to start OpenFPGA shell interface
*******************************************************************/ *******************************************************************/
int main(int argc, char** argv) { int main(int argc, char** argv) {
/* Create the command to launch shell in different modes */ /* Create the command to launch shell in different modes */
openfpga::Command start_cmd("OpenFPGA"); openfpga::Command start_cmd("OpenFPGA");
/* Add two options: /* Add two options:
@ -89,13 +90,11 @@ int main(int argc, char** argv) {
/* Parse succeed. Start a shell */ /* Parse succeed. Start a shell */
if (true == start_cmd_context.option_enable(start_cmd, opt_interactive)) { if (true == start_cmd_context.option_enable(start_cmd, opt_interactive)) {
vtr::ScopedStartFinishTimer timer("OpenFPGA operating");
shell.run_interactive_mode(openfpga_context); shell.run_interactive_mode(openfpga_context);
return 0; return 0;
} }
if (true == start_cmd_context.option_enable(start_cmd, opt_script_mode)) { if (true == start_cmd_context.option_enable(start_cmd, opt_script_mode)) {
vtr::ScopedStartFinishTimer timer("OpenFPGA operating");
shell.run_script_mode(start_cmd_context.option_value(start_cmd, opt_script_mode).c_str(), shell.run_script_mode(start_cmd_context.option_value(start_cmd, opt_script_mode).c_str(),
openfpga_context); openfpga_context);
return 0; return 0;

View File

@ -0,0 +1,47 @@
# Run VPR for the 'and' design
#--write_rr_graph example_rr_graph.xml
vpr ${VPR_ARCH_FILE} ${VPR_TESTBENCH_BLIF} --clock_modeling route
# Read OpenFPGA architecture definition
read_openfpga_arch -f ${OPENFPGA_ARCH_FILE}
# Read OpenFPGA simulation settings
read_openfpga_simulation_setting -f ${OPENFPGA_SIM_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 clustering nets based on routing results
pb_pin_fixup --verbose
# 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
# - Enabled frame view creation to save runtime and memory
# Note that this is turned on when bitstream generation
# is the ONLY purpose of the flow!!!
build_fabric --compress_routing --frame_view #--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 --write_file fabric_indepenent_bitstream.xml
# Build fabric-dependent bitstream
build_fabric_bitstream --verbose
# Finish and exit OpenFPGA
exit
# Note :
# To run verification at the end of the flow maintain source in ./SRC directory

View File

@ -0,0 +1,33 @@
# = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
# 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
openfpga_shell_template=${PATH:OPENFPGA_PATH}/openfpga_flow/OpenFPGAShellScripts/generate_bitstream_example_script.openfpga
power_tech_file = ${PATH:OPENFPGA_PATH}/openfpga_flow/tech/PTM_45nm/45nm.xml
power_analysis = true
spice_output=false
verilog_output=true
timeout_each_job = 20*60
fpga_flow=vpr_blif
openfpga_arch_file=${PATH:OPENFPGA_PATH}/openfpga_flow/openfpga_arch/k6_frac_N10_40nm_openfpga.xml
openfpga_sim_setting_file=${PATH:OPENFPGA_PATH}/openfpga_flow/openfpga_simulation_settings/auto_sim_openfpga.xml
external_fabric_key_file=
[ARCHITECTURES]
arch0=${PATH:OPENFPGA_PATH}/openfpga_flow/arch/vpr_only_templates/k6_frac_N10_tileable_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]