diff --git a/.travis/openfpga_vpr8_reg_test.sh b/.travis/openfpga_vpr8_reg_test.sh index 8c07480cd..c48959e58 100755 --- a/.travis/openfpga_vpr8_reg_test.sh +++ b/.travis/openfpga_vpr8_reg_test.sh @@ -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 diff --git a/libopenfpga/libfpgabitstream/src/bitstream_manager.cpp b/libopenfpga/libfpgabitstream/src/bitstream_manager.cpp index 66b4d1f23..990423802 100644 --- a/libopenfpga/libfpgabitstream/src/bitstream_manager.cpp +++ b/libopenfpga/libfpgabitstream/src/bitstream_manager.cpp @@ -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 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 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 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& 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& 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 { diff --git a/libopenfpga/libfpgabitstream/src/bitstream_manager.h b/libopenfpga/libfpgabitstream/src/bitstream_manager.h index 71bd63b43..6f2e56c38 100644 --- a/libopenfpga/libfpgabitstream/src/bitstream_manager.h +++ b/libopenfpga/libfpgabitstream/src/bitstream_manager.h @@ -36,6 +36,8 @@ #include #include +#include +#include #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 lazy_id_iterator : public std::iterator { + 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::value_type value_type; + typedef typename std::iterator::iterator iterator; + + lazy_id_iterator(value_type init, const std::unordered_set& 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 lhs, const lazy_id_iterator rhs) { return lhs.value_ == rhs.value_; } + friend bool operator!=(const lazy_id_iterator lhs, const lazy_id_iterator rhs) { return !(lhs == rhs); } + + private: + value_type value_; + const std::unordered_set& invalid_ids_; + }; + + public: /* Public constructor */ + BitstreamManager(); + public: /* Types and ranges */ - typedef vtr::vector::const_iterator config_bit_iterator; - typedef vtr::vector::const_iterator config_block_iterator; + //Lazy iterator utility forward declaration + template + class lazy_id_iterator; + + typedef lazy_id_iterator config_bit_iterator; + typedef lazy_id_iterator config_block_iterator; typedef vtr::Range config_bit_range; typedef vtr::Range 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 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& 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& 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 block_ids_; - vtr::vector> block_bit_ids_; + size_t num_blocks_; + std::unordered_set invalid_block_ids_; + vtr::vector block_bit_id_lsbs_; + vtr::vector 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 block_path_ids_; + vtr::vector block_path_ids_; /* Net ids that are mapped to inputs and outputs of this block * @@ -172,12 +237,10 @@ class BitstreamManager { vtr::vector> block_output_net_ids_; /* Unique id of a bit in the Bitstream */ - vtr::vector bit_ids_; - vtr::vector bit_parent_block_ids_; + size_t num_bits_; + std::unordered_set invalid_bit_ids_; /* value of a bit in the Bitstream */ - vtr::vector bit_values_; - /* value of a shared configuration bits in the Bitstream */ - vtr::vector> shared_config_bit_values_; + vtr::vector bit_values_; }; } /* end namespace openfpga */ diff --git a/libopenfpga/libfpgabitstream/src/read_xml_arch_bitstream.cpp b/libopenfpga/libfpgabitstream/src/read_xml_arch_bitstream.cpp index 3895b85b6..04e0918f1 100644 --- a/libopenfpga/libfpgabitstream/src/read_xml_arch_bitstream.cpp +++ b/libopenfpga/libfpgabitstream/src/read_xml_arch_bitstream.cpp @@ -101,16 +101,17 @@ void rec_read_xml_bitstream_block(pugi::xml_node& xml_bitstream_block, } /* Find the child paths/nets */ + std::vector 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 */ diff --git a/libopenfpga/libopenfpgashell/src/shell.h b/libopenfpga/libopenfpgashell/src/shell.h index 1a49b313c..67dd4356d 100644 --- a/libopenfpga/libopenfpgashell/src/shell.h +++ b/libopenfpga/libopenfpgashell/src/shell.h @@ -5,6 +5,7 @@ #include #include #include +#include #include "vtr_vector.h" #include "vtr_range.h" @@ -211,6 +212,9 @@ class Shell { std::map command_name2ids_; std::map command_class2ids_; vtr::vector> commands_by_classes_; + + /* Timer */ + std::clock_t time_start_; }; } /* End namespace openfpga */ diff --git a/libopenfpga/libopenfpgashell/src/shell.tpp b/libopenfpga/libopenfpgashell/src/shell.tpp index 219287ee1..7c0ff7ce6 100644 --- a/libopenfpga/libopenfpgashell/src/shell.tpp +++ b/libopenfpga/libopenfpgashell/src/shell.tpp @@ -28,6 +28,7 @@ namespace openfpga { template Shell::Shell(const char* name) { name_ = std::string(name); + time_start_ = 0; } /************************************************************************ @@ -241,6 +242,9 @@ ShellCommandClassId Shell::add_command_class(const char* name) { template void Shell::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::run_interactive_mode(T& context, const bool& quiet_mode) { template void Shell::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::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()); diff --git a/libopenfpga/libopenfpgautil/src/openfpga_decode.cpp b/libopenfpga/libopenfpgautil/src/openfpga_decode.cpp index 06b3487b0..168f98e42 100644 --- a/libopenfpga/libopenfpgautil/src/openfpga_decode.cpp +++ b/libopenfpga/libopenfpgautil/src/openfpga_decode.cpp @@ -73,4 +73,59 @@ std::vector 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 itobin_charvec(const size_t& in_int, + const size_t& bin_len) { + std::vector 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& 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 */ diff --git a/libopenfpga/libopenfpgautil/src/openfpga_decode.h b/libopenfpga/libopenfpgautil/src/openfpga_decode.h index c79254f63..ab6778c86 100644 --- a/libopenfpga/libopenfpgautil/src/openfpga_decode.h +++ b/libopenfpga/libopenfpgautil/src/openfpga_decode.h @@ -18,6 +18,11 @@ std::vector ito1hot_vec(const size_t& in_int, std::vector itobin_vec(const size_t& in_int, const size_t& bin_len); +std::vector itobin_charvec(const size_t& in_int, + const size_t& bin_len); + +size_t bintoi_charvec(const std::vector& bin); + } /* namespace openfpga ends */ #endif diff --git a/openfpga/src/base/openfpga_build_fabric.cpp b/openfpga/src/base/openfpga_build_fabric.cpp index adbe8fce6..df407e949 100644 --- a/openfpga/src/base/openfpga_build_fabric.cpp +++ b/openfpga/src/base/openfpga_build_fabric.cpp @@ -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(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, diff --git a/openfpga/src/base/openfpga_naming.cpp b/openfpga/src/base/openfpga_naming.cpp index 84366b1ab..f4a72ff61 100644 --- a/openfpga/src/base/openfpga_naming.cpp +++ b/openfpga/src/base/openfpga_naming.cpp @@ -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); diff --git a/openfpga/src/base/openfpga_setup_command.cpp b/openfpga/src/base/openfpga_setup_command.cpp index ca5864b2e..eb0e0430d 100644 --- a/openfpga/src/base/openfpga_setup_command.cpp +++ b/openfpga/src/base/openfpga_setup_command.cpp @@ -267,6 +267,9 @@ ShellCommandId add_openfpga_build_fabric_command(openfpga::Shell bl_addr_bits_vec = itobin_vec(cur_bl_index, bl_addr_size); + std::vector 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 wl_addr_bits_vec = itobin_vec(cur_wl_index, wl_addr_size); + std::vector 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& parent_blocks, const ModuleManager& module_manager, const std::vector& parent_modules, - const std::vector& addr_code, + const std::vector& 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 child_addr_code = addr_code; + std::vector 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 addr_bits_vec = itobin_vec(child_id, decoder_addr_port.get_width()); + std::vector 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 dummy_codes(max_child_addr_code_size - child_addr_port.get_width(), 0); + std::vector 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 addr_bits_vec = itobin_vec(ibit, decoder_addr_port.get_width()); + std::vector addr_bits_vec = itobin_charvec(ibit, decoder_addr_port.get_width()); - std::vector child_addr_code = addr_code; + std::vector 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(1, top_block), module_manager, std::vector(1, top_module), - std::vector(), + std::vector(), 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; } diff --git a/openfpga/src/fpga_bitstream/build_grid_bitstream.cpp b/openfpga/src/fpga_bitstream/build_grid_bitstream.cpp index c3de6cbfe..436c04697 100644 --- a/openfpga/src/fpga_bitstream/build_grid_bitstream.cpp +++ b/openfpga/src/fpga_bitstream/build_grid_bitstream.cpp @@ -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); } /******************************************************************** diff --git a/openfpga/src/fpga_bitstream/build_routing_bitstream.cpp b/openfpga/src/fpga_bitstream/build_routing_bitstream.cpp index 457b1d004..1e6b8d3c6 100644 --- a/openfpga/src/fpga_bitstream/build_routing_bitstream.cpp +++ b/openfpga/src/fpga_bitstream/build_routing_bitstream.cpp @@ -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 { diff --git a/openfpga/src/fpga_bitstream/fabric_bitstream.cpp b/openfpga/src/fpga_bitstream/fabric_bitstream.cpp index 1e318a530..750cc0296 100644 --- a/openfpga/src/fpga_bitstream/fabric_bitstream.cpp +++ b/openfpga/src/fpga_bitstream/fabric_bitstream.cpp @@ -4,17 +4,33 @@ #include #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 FabricBitstream::bit_address(const FabricBitId& bit_id) const { +std::vector 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 FabricBitstream::bit_bl_address(const FabricBitId& bit_id) const { +std::vector FabricBitstream::bit_bl_address(const FabricBitId& bit_id) const { return bit_address(bit_id); } -std::vector FabricBitstream::bit_wl_address(const FabricBitId& bit_id) const { +std::vector 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& address) { + const std::vector& 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& address) { + const std::vector& address) { set_bit_address(bit_id, address); } void FabricBitstream::set_bit_wl_address(const FabricBitId& bit_id, - const std::vector& address) { + const std::vector& 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 */ diff --git a/openfpga/src/fpga_bitstream/fabric_bitstream.h b/openfpga/src/fpga_bitstream/fabric_bitstream.h index 519330dae..9869fffed 100644 --- a/openfpga/src/fpga_bitstream/fabric_bitstream.h +++ b/openfpga/src/fpga_bitstream/fabric_bitstream.h @@ -29,6 +29,8 @@ #define FABRIC_BITSTREAM_H #include +#include +#include #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 lazy_id_iterator : public std::iterator { + 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::value_type value_type; + typedef typename std::iterator::iterator iterator; + + lazy_id_iterator(value_type init, const std::unordered_set& 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 lhs, const lazy_id_iterator rhs) { return lhs.value_ == rhs.value_; } + friend bool operator!=(const lazy_id_iterator lhs, const lazy_id_iterator rhs) { return !(lhs == rhs); } + + private: + value_type value_; + const std::unordered_set& invalid_ids_; + }; + public: /* Types and ranges */ - typedef vtr::vector::const_iterator fabric_bit_iterator; + //Lazy iterator utility forward declaration + template + class lazy_id_iterator; + + typedef lazy_id_iterator fabric_bit_iterator; typedef vtr::Range 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 bit_address(const FabricBitId& bit_id) const; - std::vector bit_bl_address(const FabricBitId& bit_id) const; - std::vector bit_wl_address(const FabricBitId& bit_id) const; + std::vector bit_address(const FabricBitId& bit_id) const; + std::vector bit_bl_address(const FabricBitId& bit_id) const; + std::vector 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& address); + const std::vector& address); void set_bit_bl_address(const FabricBitId& bit_id, - const std::vector& address); + const std::vector& address); void set_bit_wl_address(const FabricBitId& bit_id, - const std::vector& address); + const std::vector& 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 bit_ids_; + size_t num_bits_; + std::unordered_set invalid_bit_ids_; vtr::vector 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, 2>> bit_addresses_; + vtr::vector bit_addresses_; + vtr::vector bit_wl_addresses_; /* Data input (Din) bits: this is designed for memory decoders */ - vtr::vector bit_dins_; + vtr::vector bit_dins_; }; } /* end namespace openfpga */ diff --git a/openfpga/src/fpga_bitstream/fabric_bitstream_writer.cpp b/openfpga/src/fpga_bitstream/fabric_bitstream_writer.cpp index 6317fd47d..2991dd6a0 100644 --- a/openfpga/src/fpga_bitstream/fabric_bitstream_writer.cpp +++ b/openfpga/src/fpga_bitstream/fabric_bitstream_writer.cpp @@ -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 */ diff --git a/openfpga/src/fpga_verilog/simulation_info_writer.cpp b/openfpga/src/fpga_verilog/simulation_info_writer.cpp index de9f5f6af..134b34f0a 100644 --- a/openfpga/src/fpga_verilog/simulation_info_writer.cpp +++ b/openfpga/src/fpga_verilog/simulation_info_writer.cpp @@ -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) { diff --git a/openfpga/src/fpga_verilog/verilog_api.cpp b/openfpga/src/fpga_verilog/verilog_api.cpp index ff7872999..0e2f84124 100644 --- a/openfpga/src/fpga_verilog/verilog_api.cpp +++ b/openfpga/src/fpga_verilog/verilog_api.cpp @@ -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()); diff --git a/openfpga/src/fpga_verilog/verilog_top_testbench.cpp b/openfpga/src/fpga_verilog/verilog_top_testbench.cpp index c985c48f0..9e7bde572 100644 --- a/openfpga/src/fpga_verilog/verilog_top_testbench.cpp +++ b/openfpga/src/fpga_verilog/verilog_top_testbench.cpp @@ -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 << ", "; diff --git a/openfpga/src/main.cpp b/openfpga/src/main.cpp index e1f813e9b..9f332263c 100644 --- a/openfpga/src/main.cpp +++ b/openfpga/src/main.cpp @@ -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; diff --git a/openfpga_flow/OpenFPGAShellScripts/generate_bitstream_example_script.openfpga b/openfpga_flow/OpenFPGAShellScripts/generate_bitstream_example_script.openfpga new file mode 100644 index 000000000..e7c934513 --- /dev/null +++ b/openfpga_flow/OpenFPGAShellScripts/generate_bitstream_example_script.openfpga @@ -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 diff --git a/openfpga_flow/tasks/openfpga_shell/generate_bitstream/config/task.conf b/openfpga_flow/tasks/openfpga_shell/generate_bitstream/config/task.conf new file mode 100644 index 000000000..4c12ab08b --- /dev/null +++ b/openfpga_flow/tasks/openfpga_shell/generate_bitstream/config/task.conf @@ -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]