Merge pull request #59 from LNIS-Projects/dev
Runtime and memory improvement on bitstream database
This commit is contained in:
commit
83d6bf32d3
|
@ -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
|
||||||
|
|
||||||
|
|
|
@ -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 {
|
||||||
|
|
|
@ -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 */
|
||||||
|
|
|
@ -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 */
|
||||||
|
|
|
@ -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 */
|
||||||
|
|
|
@ -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());
|
||||||
|
|
||||||
|
|
|
@ -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 */
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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,
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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");
|
||||||
|
|
||||||
|
|
|
@ -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!
|
||||||
|
|
|
@ -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,
|
||||||
|
|
|
@ -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),
|
||||||
|
|
|
@ -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,
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
|
@ -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);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/********************************************************************
|
/********************************************************************
|
||||||
|
|
|
@ -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 {
|
||||||
|
|
|
@ -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 */
|
||||||
|
|
|
@ -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 */
|
||||||
|
|
|
@ -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 */
|
||||||
|
|
|
@ -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) {
|
||||||
|
|
|
@ -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());
|
||||||
|
|
|
@ -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 << ", ";
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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
|
|
@ -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]
|
Loading…
Reference in New Issue