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";
|
||||
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";
|
||||
python3 openfpga_flow/scripts/run_fpga_task.py openfpga_shell/sdc_time_unit --debug --show_thread_logs
|
||||
|
||||
|
|
|
@ -9,17 +9,37 @@
|
|||
/* begin 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
|
||||
*************************************************/
|
||||
/* Find all the configuration bits */
|
||||
size_t BitstreamManager::num_bits() const {
|
||||
return num_bits_;
|
||||
}
|
||||
|
||||
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 */
|
||||
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 */
|
||||
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 {
|
||||
|
@ -57,32 +77,20 @@ std::vector<ConfigBitId> BitstreamManager::block_bits(const ConfigBlockId& block
|
|||
/* Ensure the input ids are valid */
|
||||
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 {
|
||||
/* Ensure the input ids are valid */
|
||||
VTR_ASSERT(true == valid_bit_id(bit_id));
|
||||
std::vector<ConfigBitId> bits(length, ConfigBitId::INVALID());
|
||||
|
||||
return bit_parent_block_ids_[bit_id];
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
if (0 == length) {
|
||||
return bits;
|
||||
}
|
||||
|
||||
/* Not found, return in valid value */
|
||||
return size_t(-1);
|
||||
for (size_t i = lsb; i < lsb + length; ++i) {
|
||||
bits[i - lsb] = ConfigBitId(i);
|
||||
}
|
||||
|
||||
return bits;
|
||||
}
|
||||
|
||||
/* 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
|
||||
******************************************************************************/
|
||||
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 */
|
||||
bit_ids_.push_back(bit);
|
||||
bit_values_.push_back(bit_value);
|
||||
shared_config_bit_values_.emplace_back();
|
||||
bit_parent_block_ids_.push_back(ConfigBlockId::INVALID());
|
||||
num_bits_++;
|
||||
if (true == bit_value) {
|
||||
bit_values_.push_back('1');
|
||||
} else {
|
||||
bit_values_.push_back('0');
|
||||
}
|
||||
|
||||
return bit;
|
||||
}
|
||||
|
||||
void BitstreamManager::reserve_blocks(const size_t& num_blocks) {
|
||||
block_ids_.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_input_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);
|
||||
}
|
||||
|
||||
void BitstreamManager::reserve_bits(const size_t& num_bits) {
|
||||
bit_values_.reserve(num_bits);
|
||||
}
|
||||
|
||||
ConfigBlockId BitstreamManager::create_block() {
|
||||
ConfigBlockId block = ConfigBlockId(block_ids_.size());
|
||||
ConfigBlockId block = ConfigBlockId(num_blocks_);
|
||||
/* Add a new bit, and allocate associated data structures */
|
||||
block_ids_.push_back(block);
|
||||
num_blocks_++;
|
||||
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_input_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;
|
||||
}
|
||||
|
||||
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) {
|
||||
/* Ensure the input ids are valid */
|
||||
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;
|
||||
}
|
||||
|
||||
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 */
|
||||
VTR_ASSERT(true == valid_block_id(block));
|
||||
VTR_ASSERT(true == valid_bit_id(bit));
|
||||
|
||||
/* We should have only a parent block for each bit! */
|
||||
VTR_ASSERT(ConfigBlockId::INVALID() == bit_parent_block_ids_[bit]);
|
||||
|
||||
/* Add the bit to the block */
|
||||
block_bit_ids_[block].push_back(bit);
|
||||
/* Register the block in the parent of the bit */
|
||||
bit_parent_block_ids_[bit] = block;
|
||||
/* Add the bit to the block, record anchors in bit indexing for block-level searching */
|
||||
block_bit_id_lsbs_[block] = num_bits_;
|
||||
block_bit_lengths_[block] = block_bitstream.size();
|
||||
for (const bool& bit : block_bitstream) {
|
||||
add_bit(bit);
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
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,
|
||||
const std::string& input_net_id) {
|
||||
/* 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);
|
||||
}
|
||||
|
||||
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,
|
||||
const std::string& output_net_id) {
|
||||
/* 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);
|
||||
}
|
||||
|
||||
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
|
||||
******************************************************************************/
|
||||
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 {
|
||||
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 {
|
||||
|
|
|
@ -36,6 +36,8 @@
|
|||
|
||||
#include <vector>
|
||||
#include <map>
|
||||
#include <unordered_set>
|
||||
#include <unordered_map>
|
||||
#include "vtr_vector.h"
|
||||
|
||||
#include "bitstream_manager_fwd.h"
|
||||
|
@ -44,17 +46,73 @@
|
|||
namespace openfpga {
|
||||
|
||||
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 */
|
||||
typedef vtr::vector<ConfigBitId, ConfigBitId>::const_iterator config_bit_iterator;
|
||||
typedef vtr::vector<ConfigBlockId, ConfigBlockId>::const_iterator config_block_iterator;
|
||||
//Lazy iterator utility forward declaration
|
||||
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_block_iterator> config_block_range;
|
||||
|
||||
public: /* Public aggregators */
|
||||
/* Find all the configuration bits */
|
||||
size_t num_bits() const;
|
||||
config_bit_range bits() const;
|
||||
|
||||
size_t num_blocks() const;
|
||||
config_block_range blocks() const;
|
||||
|
||||
public: /* Public Accessors */
|
||||
|
@ -73,12 +131,6 @@ class BitstreamManager {
|
|||
/* Find all the bits that belong to a block */
|
||||
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 */
|
||||
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 */
|
||||
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 */
|
||||
ConfigBlockId create_block();
|
||||
|
||||
|
@ -108,24 +163,32 @@ class BitstreamManager {
|
|||
void set_block_name(const ConfigBlockId& block_id,
|
||||
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 */
|
||||
void add_child_block(const ConfigBlockId& parent_block, const ConfigBlockId& child_block);
|
||||
|
||||
/* Add a configuration bit to a block */
|
||||
void add_bit_to_block(const ConfigBlockId& block, const ConfigBitId& bit);
|
||||
/* Add a bitstream to a block */
|
||||
void add_block_bits(const ConfigBlockId& block,
|
||||
const std::vector<bool>& block_bitstream);
|
||||
|
||||
/* Add a path id to a block */
|
||||
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 */
|
||||
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 */
|
||||
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 */
|
||||
bool valid_bit_id(const ConfigBitId& bit_id) const;
|
||||
|
||||
|
@ -135,8 +198,10 @@ class BitstreamManager {
|
|||
|
||||
private: /* Internal data */
|
||||
/* Unique id of a block of bits in the Bitstream */
|
||||
vtr::vector<ConfigBlockId, ConfigBlockId> block_ids_;
|
||||
vtr::vector<ConfigBlockId, std::vector<ConfigBitId>> block_bit_ids_;
|
||||
size_t num_blocks_;
|
||||
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 */
|
||||
/* 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
|
||||
* 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
|
||||
*
|
||||
|
@ -172,12 +237,10 @@ class BitstreamManager {
|
|||
vtr::vector<ConfigBlockId, std::vector<std::string>> block_output_net_ids_;
|
||||
|
||||
/* Unique id of a bit in the Bitstream */
|
||||
vtr::vector<ConfigBitId, ConfigBitId> bit_ids_;
|
||||
vtr::vector<ConfigBitId, ConfigBlockId> bit_parent_block_ids_;
|
||||
size_t num_bits_;
|
||||
std::unordered_set<ConfigBitId> invalid_bit_ids_;
|
||||
/* value of a bit in the Bitstream */
|
||||
vtr::vector<ConfigBitId, bool> bit_values_;
|
||||
/* value of a shared configuration bits in the Bitstream */
|
||||
vtr::vector<ConfigBitId, std::vector<bool>> shared_config_bit_values_;
|
||||
vtr::vector<ConfigBitId, char> bit_values_;
|
||||
};
|
||||
|
||||
} /* end namespace openfpga */
|
||||
|
|
|
@ -101,16 +101,17 @@ void rec_read_xml_bitstream_block(pugi::xml_node& xml_bitstream_block,
|
|||
}
|
||||
|
||||
/* Find the child paths/nets */
|
||||
std::vector<bool> block_bits;
|
||||
for (pugi::xml_node xml_bit : xml_bitstream.children()) {
|
||||
/* We only care child bitstream blocks here */
|
||||
if (xml_bit.name() != std::string("bit")) {
|
||||
bad_tag(xml_bit, loc_data, xml_bitstream, {"bit"});
|
||||
}
|
||||
const int& bit_value = get_attribute(xml_bit, "value", loc_data).as_int();
|
||||
ConfigBitId bit = bitstream_manager.add_bit(1 == bit_value);
|
||||
/* Link the bit to parent block */
|
||||
bitstream_manager.add_bit_to_block(curr_block, bit);
|
||||
}
|
||||
block_bits.push_back(1 == bit_value);
|
||||
}
|
||||
/* Link the bit to parent block */
|
||||
bitstream_manager.add_block_bits(curr_block, block_bits);
|
||||
}
|
||||
|
||||
/* Go recursively: find all the child blocks and parse */
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
#include <map>
|
||||
#include <vector>
|
||||
#include <functional>
|
||||
#include <ctime>
|
||||
|
||||
#include "vtr_vector.h"
|
||||
#include "vtr_range.h"
|
||||
|
@ -211,6 +212,9 @@ class Shell {
|
|||
std::map<std::string, ShellCommandId> command_name2ids_;
|
||||
std::map<std::string, ShellCommandClassId> command_class2ids_;
|
||||
vtr::vector<ShellCommandClassId, std::vector<ShellCommandId>> commands_by_classes_;
|
||||
|
||||
/* Timer */
|
||||
std::clock_t time_start_;
|
||||
};
|
||||
|
||||
} /* End namespace openfpga */
|
||||
|
|
|
@ -28,6 +28,7 @@ namespace openfpga {
|
|||
template<class T>
|
||||
Shell<T>::Shell(const char* name) {
|
||||
name_ = std::string(name);
|
||||
time_start_ = 0;
|
||||
}
|
||||
|
||||
/************************************************************************
|
||||
|
@ -241,6 +242,9 @@ ShellCommandClassId Shell<T>::add_command_class(const char* name) {
|
|||
template <class T>
|
||||
void Shell<T>::run_interactive_mode(T& context, const bool& 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",
|
||||
name().c_str());
|
||||
|
||||
|
@ -270,6 +274,8 @@ void Shell<T>::run_interactive_mode(T& context, const bool& quiet_mode) {
|
|||
template <class T>
|
||||
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);
|
||||
|
||||
/* Print the title of the shell */
|
||||
|
@ -419,6 +425,9 @@ void Shell<T>::exit() const {
|
|||
VTR_LOG("\nFinish execution with %d errors\n",
|
||||
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",
|
||||
name().c_str());
|
||||
|
||||
|
|
|
@ -73,4 +73,59 @@ std::vector<size_t> itobin_vec(const size_t& in_int,
|
|||
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 */
|
||||
|
|
|
@ -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,
|
||||
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 */
|
||||
|
||||
#endif
|
||||
|
|
|
@ -67,6 +67,7 @@ void compress_routing_hierarchy(OpenfpgaContext& openfpga_ctx,
|
|||
int build_fabric(OpenfpgaContext& openfpga_ctx,
|
||||
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_duplicate_grid_pin = cmd.option("duplicate_grid_pin");
|
||||
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(),
|
||||
const_cast<const OpenfpgaContext&>(openfpga_ctx),
|
||||
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_duplicate_grid_pin),
|
||||
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,
|
||||
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 += "to";
|
||||
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");
|
||||
|
||||
/* 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' */
|
||||
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,
|
||||
const OpenfpgaContext& openfpga_ctx,
|
||||
const DeviceContext& vpr_device_ctx,
|
||||
const bool& frame_view,
|
||||
const bool& compress_routing,
|
||||
const bool& duplicate_grid_pin,
|
||||
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().config_protocol.type(),
|
||||
sram_model,
|
||||
compress_routing, duplicate_grid_pin,
|
||||
frame_view, compress_routing, duplicate_grid_pin,
|
||||
fabric_key, generate_random_fabric_key);
|
||||
|
||||
/* Now a critical correction has to be done!
|
||||
|
|
|
@ -19,6 +19,7 @@ ModuleManager build_device_module_graph(IoLocationMap& io_location_map,
|
|||
DecoderLibrary& decoder_lib,
|
||||
const OpenfpgaContext& openfpga_ctx,
|
||||
const DeviceContext& vpr_device_ctx,
|
||||
const bool& frame_view,
|
||||
const bool& compress_routing,
|
||||
const bool& duplicate_grid_pin,
|
||||
const FabricKey& fabric_key,
|
||||
|
|
|
@ -329,6 +329,7 @@ void build_top_module(ModuleManager& module_manager,
|
|||
const ArchDirect& arch_direct,
|
||||
const e_config_protocol_type& sram_orgz_type,
|
||||
const CircuitModelId& sram_model,
|
||||
const bool& frame_view,
|
||||
const bool& compact_routing_hierarchy,
|
||||
const bool& duplicate_grid_pin,
|
||||
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[CHANY] = add_top_module_connection_block_instances(module_manager, top_module, device_rr_gsb, CHANY, compact_routing_hierarchy);
|
||||
|
||||
/* Reserve nets to be memory efficient */
|
||||
reserve_module_manager_module_nets(module_manager, top_module);
|
||||
/* Add nets when we need a complete fabric modeling,
|
||||
* 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_top_module_nets_connect_grids_and_gsbs(module_manager, top_module,
|
||||
grids, grid_instance_ids,
|
||||
rr_graph, device_rr_gsb, sb_instance_ids, cb_instance_ids,
|
||||
compact_routing_hierarchy, duplicate_grid_pin);
|
||||
/* Add inter-CLB direct connections */
|
||||
add_top_module_nets_tile_direct_connections(module_manager, top_module, circuit_lib,
|
||||
grids, grid_instance_ids,
|
||||
tile_direct, arch_direct);
|
||||
/* Add module nets to connect the sub modules */
|
||||
add_top_module_nets_connect_grids_and_gsbs(module_manager, top_module,
|
||||
grids, grid_instance_ids,
|
||||
rr_graph, device_rr_gsb, sb_instance_ids, cb_instance_ids,
|
||||
compact_routing_hierarchy, duplicate_grid_pin);
|
||||
/* Add inter-CLB direct connections */
|
||||
add_top_module_nets_tile_direct_connections(module_manager, top_module, circuit_lib,
|
||||
grids, grid_instance_ids,
|
||||
tile_direct, arch_direct);
|
||||
}
|
||||
|
||||
/* Add global ports to the pb_module:
|
||||
* 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 e_config_protocol_type& sram_orgz_type,
|
||||
const CircuitModelId& sram_model,
|
||||
const bool& frame_view,
|
||||
const bool& compact_routing_hierarchy,
|
||||
const bool& duplicate_grid_pin,
|
||||
const FabricKey& fabric_key,
|
||||
|
|
|
@ -20,6 +20,82 @@
|
|||
/* begin 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
|
||||
* 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();
|
||||
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 */
|
||||
VTR_LOGV(verbose, "Building grid bitstream...\n");
|
||||
|
@ -80,7 +175,13 @@ BitstreamManager build_device_bitstream(const VprContext& vpr_ctx,
|
|||
openfpga_ctx.device_rr_gsb());
|
||||
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;
|
||||
}
|
||||
|
|
|
@ -158,11 +158,11 @@ void rec_build_module_fabric_dependent_memory_bank_bitstream(const BitstreamMana
|
|||
|
||||
/* Find BL address */
|
||||
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 */
|
||||
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 */
|
||||
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 ModuleManager& module_manager,
|
||||
const std::vector<ModuleId>& parent_modules,
|
||||
const std::vector<size_t>& addr_code,
|
||||
const std::vector<char>& addr_code,
|
||||
FabricBitstream& fabric_bitstream) {
|
||||
|
||||
/* 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);
|
||||
|
||||
/* 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) {
|
||||
/* 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 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());
|
||||
|
||||
|
@ -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 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()) {
|
||||
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());
|
||||
}
|
||||
}
|
||||
|
@ -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) {
|
||||
|
||||
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());
|
||||
|
||||
|
@ -379,12 +379,18 @@ void build_module_fabric_dependent_bitstream(const ConfigProtocol& config_protoc
|
|||
|
||||
switch (config_protocol.type()) {
|
||||
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,
|
||||
module_manager, top_module,
|
||||
fabric_bitstream);
|
||||
break;
|
||||
}
|
||||
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,
|
||||
module_manager, top_module,
|
||||
fabric_bitstream);
|
||||
|
@ -392,6 +398,7 @@ void build_module_fabric_dependent_bitstream(const ConfigProtocol& config_protoc
|
|||
break;
|
||||
}
|
||||
case CONFIG_MEM_MEMORY_BANK: {
|
||||
|
||||
size_t cur_mem_index = 0;
|
||||
/* Find BL address port size */
|
||||
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));
|
||||
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,
|
||||
module_manager, top_module, top_module,
|
||||
bl_addr_port_info.get_width(),
|
||||
|
@ -425,11 +439,21 @@ void build_module_fabric_dependent_bitstream(const ConfigProtocol& config_protoc
|
|||
break;
|
||||
}
|
||||
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,
|
||||
std::vector<ConfigBlockId>(1, top_block),
|
||||
module_manager,
|
||||
std::vector<ModuleId>(1, top_module),
|
||||
std::vector<size_t>(),
|
||||
std::vector<char>(),
|
||||
fabric_bitstream);
|
||||
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 */
|
||||
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(0 == top_module_name.compare(bitstream_manager.block_name(top_block[0])));
|
||||
|
||||
/* Start build-up formally */
|
||||
build_module_fabric_dependent_bitstream(config_protocol,
|
||||
bitstream_manager, top_block[0],
|
||||
module_manager, top_module,
|
||||
|
@ -502,7 +527,7 @@ FabricBitstream build_fabric_dependent_bitstream(const BitstreamManager& bitstre
|
|||
|
||||
VTR_LOGV(verbose,
|
||||
"Built %lu configuration bits for fabric\n",
|
||||
fabric_bitstream.bits().size());
|
||||
fabric_bitstream.num_bits());
|
||||
|
||||
return fabric_bitstream;
|
||||
}
|
||||
|
|
|
@ -106,11 +106,7 @@ void build_primitive_bitstream(BitstreamManager& bitstream_manager,
|
|||
bitstream_manager.add_child_block(parent_configurable_block, mem_block);
|
||||
|
||||
/* Add the bitstream to the bitstream manager */
|
||||
for (const bool& bit : 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);
|
||||
}
|
||||
bitstream_manager.add_block_bits(mem_block, mode_select_bitstream);
|
||||
}
|
||||
|
||||
/********************************************************************
|
||||
|
@ -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());
|
||||
|
||||
/* Add the bistream to the bitstream manager */
|
||||
for (const bool& bit : 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);
|
||||
}
|
||||
bitstream_manager.add_block_bits(mux_mem_block, mux_bitstream);
|
||||
/* Record path ids, input and output nets */
|
||||
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) {
|
||||
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));
|
||||
|
@ -229,6 +222,7 @@ void build_physical_block_pin_interc_bitstream(BitstreamManager& bitstream_manag
|
|||
}
|
||||
}
|
||||
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));
|
||||
} else {
|
||||
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);
|
||||
|
||||
/* Add the bitstream to the bitstream manager */
|
||||
for (const bool& bit : 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);
|
||||
}
|
||||
bitstream_manager.add_block_bits(mem_block, lut_bitstream);
|
||||
}
|
||||
|
||||
/********************************************************************
|
||||
|
|
|
@ -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());
|
||||
|
||||
/* Add the bistream to the bitstream manager */
|
||||
for (const bool& bit : 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);
|
||||
}
|
||||
bitstream_manager.add_block_bits(mux_mem_block, mux_bitstream);
|
||||
/* Record path ids, input and output nets */
|
||||
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) {
|
||||
AtomNetId input_atom_net = atom_ctx.lookup.atom_net(input_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);
|
||||
bitstream_manager.reserve_block_output_net_ids(mux_mem_block, 1);
|
||||
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));
|
||||
} 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());
|
||||
|
||||
/* Add the bistream to the bitstream manager */
|
||||
for (const bool& bit : 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);
|
||||
}
|
||||
bitstream_manager.add_block_bits(mux_mem_block, mux_bitstream);
|
||||
/* Record path ids, input and output nets */
|
||||
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) {
|
||||
AtomNetId input_atom_net = atom_ctx.lookup.atom_net(input_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);
|
||||
bitstream_manager.reserve_block_output_net_ids(mux_mem_block, 1);
|
||||
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));
|
||||
} else {
|
||||
|
|
|
@ -4,17 +4,33 @@
|
|||
#include <algorithm>
|
||||
|
||||
#include "vtr_assert.h"
|
||||
#include "openfpga_decode.h"
|
||||
#include "fabric_bitstream.h"
|
||||
|
||||
/* begin 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
|
||||
*************************************************/
|
||||
size_t FabricBitstream::num_bits() const {
|
||||
return num_bits_;
|
||||
}
|
||||
|
||||
/* Find all the configuration bits */
|
||||
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];
|
||||
}
|
||||
|
||||
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 */
|
||||
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);
|
||||
}
|
||||
|
||||
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 */
|
||||
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 */
|
||||
VTR_ASSERT(true == valid_bit_id(bit_id));
|
||||
VTR_ASSERT(true == use_address_);
|
||||
|
||||
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
|
||||
******************************************************************************/
|
||||
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 bit = FabricBitId(bit_ids_.size());
|
||||
FabricBitId bit = FabricBitId(num_bits_);
|
||||
/* Add a new bit, and allocate associated data structures */
|
||||
bit_ids_.push_back(bit);
|
||||
num_bits_++;
|
||||
config_bit_ids_.push_back(config_bit_id);
|
||||
bit_addresses_.emplace_back();
|
||||
bit_dins_.push_back(false);
|
||||
|
||||
return bit;
|
||||
}
|
||||
|
||||
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));
|
||||
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,
|
||||
const std::vector<size_t>& address) {
|
||||
const std::vector<char>& address) {
|
||||
set_bit_address(bit_id, address);
|
||||
}
|
||||
|
||||
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));
|
||||
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,
|
||||
const bool& din) {
|
||||
const char& din) {
|
||||
VTR_ASSERT(true == valid_bit_id(bit_id));
|
||||
VTR_ASSERT(true == use_address_);
|
||||
bit_dins_[bit_id] = din;
|
||||
}
|
||||
|
||||
void FabricBitstream::reverse() {
|
||||
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
|
||||
******************************************************************************/
|
||||
bool FabricBitstream::valid_bit_id(const FabricBitId& bit_id) const {
|
||||
return (size_t(bit_id) < bit_ids_.size()) && (bit_id == bit_ids_[bit_id]);
|
||||
char FabricBitstream::valid_bit_id(const FabricBitId& bit_id) const {
|
||||
return (size_t(bit_id) < num_bits_);
|
||||
}
|
||||
|
||||
} /* end namespace openfpga */
|
||||
|
|
|
@ -29,6 +29,8 @@
|
|||
#define FABRIC_BITSTREAM_H
|
||||
|
||||
#include <vector>
|
||||
#include <unordered_set>
|
||||
#include <unordered_map>
|
||||
#include "vtr_vector.h"
|
||||
|
||||
#include "bitstream_manager_fwd.h"
|
||||
|
@ -38,13 +40,68 @@
|
|||
namespace openfpga {
|
||||
|
||||
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 */
|
||||
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;
|
||||
|
||||
public: /* Public constructor */
|
||||
FabricBitstream();
|
||||
|
||||
public: /* Public aggregators */
|
||||
/* Find all the configuration bits */
|
||||
size_t num_bits() const;
|
||||
fabric_bit_range bits() const;
|
||||
|
||||
public: /* Public Accessors */
|
||||
|
@ -52,52 +109,85 @@ class FabricBitstream {
|
|||
ConfigBitId config_bit(const FabricBitId& bit_id) const;
|
||||
|
||||
/* Find the address of bitstream */
|
||||
std::vector<size_t> bit_address(const FabricBitId& bit_id) const;
|
||||
std::vector<size_t> bit_bl_address(const FabricBitId& bit_id) const;
|
||||
std::vector<size_t> bit_wl_address(const FabricBitId& bit_id) const;
|
||||
std::vector<char> bit_address(const FabricBitId& bit_id) const;
|
||||
std::vector<char> bit_bl_address(const FabricBitId& bit_id) const;
|
||||
std::vector<char> bit_wl_address(const FabricBitId& bit_id) const;
|
||||
|
||||
/* 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 */
|
||||
/* Reserve config bits */
|
||||
void reserve_bits(const size_t& num_bits);
|
||||
|
||||
/* Add a new configuration bit to the bitstream manager */
|
||||
FabricBitId add_bit(const ConfigBitId& config_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,
|
||||
const std::vector<size_t>& address);
|
||||
const std::vector<char>& address);
|
||||
|
||||
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,
|
||||
const bool& din);
|
||||
const char& din);
|
||||
|
||||
/* Reverse bit sequence of the fabric bitstream
|
||||
* This is required by configuration chain protocol
|
||||
*/
|
||||
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 */
|
||||
bool valid_bit_id(const FabricBitId& bit_id) const;
|
||||
char valid_bit_id(const FabricBitId& bit_id) const;
|
||||
|
||||
private: /* Internal data */
|
||||
/* 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_;
|
||||
|
||||
/* 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
|
||||
* Here we store the binary format of the address, which can be loaded
|
||||
* to the configuration protocol directly
|
||||
*
|
||||
* 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 */
|
||||
vtr::vector<FabricBitId, bool> bit_dins_;
|
||||
vtr::vector<FabricBitId, char> bit_dins_;
|
||||
};
|
||||
|
||||
} /* 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));
|
||||
break;
|
||||
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;
|
||||
}
|
||||
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;
|
||||
}
|
||||
write_space_to_file(fp, 1);
|
||||
|
@ -63,7 +63,7 @@ int write_fabric_config_bit_to_text_file(std::fstream& fp,
|
|||
break;
|
||||
}
|
||||
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;
|
||||
}
|
||||
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");
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
/* 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_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"]["CONFIG_PROTOCOL"] = std::string(CONFIG_PROTOCOL_TYPE_STRING[config_protocol_type]);
|
||||
|
||||
/* Information required by UVM */
|
||||
if (CONFIG_MEM_FRAME_BASED == config_protocol_type) {
|
||||
|
|
|
@ -234,7 +234,7 @@ namespace openfpga
|
|||
atom_ctx, place_ctx, io_location_map,
|
||||
module_manager,
|
||||
config_protocol_type,
|
||||
bitstream_manager.bits().size(),
|
||||
bitstream_manager.num_bits(),
|
||||
simulation_setting.num_clock_cycles(),
|
||||
simulation_setting.programming_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,
|
||||
const bool& fast_configuration,
|
||||
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 */
|
||||
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 << "(" << bl_addr_port.get_width() << "'b";
|
||||
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 << ", ";
|
||||
fp << wl_addr_port.get_width() << "'b";
|
||||
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;
|
||||
}
|
||||
|
||||
|
@ -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 << "(" << addr_port.get_width() << "'b";
|
||||
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 << ", ";
|
||||
|
|
|
@ -25,6 +25,7 @@
|
|||
* Main function to start OpenFPGA shell interface
|
||||
*******************************************************************/
|
||||
int main(int argc, char** argv) {
|
||||
|
||||
/* Create the command to launch shell in different modes */
|
||||
openfpga::Command start_cmd("OpenFPGA");
|
||||
/* Add two options:
|
||||
|
@ -89,13 +90,11 @@ int main(int argc, char** argv) {
|
|||
/* Parse succeed. Start a shell */
|
||||
if (true == start_cmd_context.option_enable(start_cmd, opt_interactive)) {
|
||||
|
||||
vtr::ScopedStartFinishTimer timer("OpenFPGA operating");
|
||||
shell.run_interactive_mode(openfpga_context);
|
||||
return 0;
|
||||
}
|
||||
|
||||
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(),
|
||||
openfpga_context);
|
||||
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