add fabric bitstream data structure and deploy it to Verilog testbench generation

This commit is contained in:
tangxifan 2020-05-27 15:53:40 -06:00
parent 8c14cced84
commit 4a0e1cd908
12 changed files with 125 additions and 67 deletions

View File

@ -62,6 +62,7 @@ int build_fabric_bitstream(OpenfpgaContext& openfpga_ctx,
/* Build fabric bitstream here */ /* Build fabric bitstream here */
openfpga_ctx.mutable_fabric_bitstream() = build_fabric_dependent_bitstream(openfpga_ctx.bitstream_manager(), openfpga_ctx.mutable_fabric_bitstream() = build_fabric_dependent_bitstream(openfpga_ctx.bitstream_manager(),
openfpga_ctx.module_graph(), openfpga_ctx.module_graph(),
openfpga_ctx.arch().config_protocol,
cmd_context.option_enable(cmd, opt_verbose)); cmd_context.option_enable(cmd, opt_verbose));
/* Write fabric bitstream if required */ /* Write fabric bitstream if required */

View File

@ -16,6 +16,7 @@
#include "netlist_manager.h" #include "netlist_manager.h"
#include "openfpga_flow_manager.h" #include "openfpga_flow_manager.h"
#include "bitstream_manager.h" #include "bitstream_manager.h"
#include "fabric_bitstream.h"
#include "device_rr_gsb.h" #include "device_rr_gsb.h"
#include "io_location_map.h" #include "io_location_map.h"
@ -61,7 +62,7 @@ class OpenfpgaContext : public Context {
const openfpga::ModuleManager& module_graph() const { return module_graph_; } const openfpga::ModuleManager& module_graph() const { return module_graph_; }
const openfpga::FlowManager& flow_manager() const { return flow_manager_; } const openfpga::FlowManager& flow_manager() const { return flow_manager_; }
const openfpga::BitstreamManager& bitstream_manager() const { return bitstream_manager_; } const openfpga::BitstreamManager& bitstream_manager() const { return bitstream_manager_; }
const std::vector<openfpga::ConfigBitId>& fabric_bitstream() const { return fabric_bitstream_; } const openfpga::FabricBitstream& fabric_bitstream() const { return fabric_bitstream_; }
const openfpga::IoLocationMap& io_location_map() const { return io_location_map_; } const openfpga::IoLocationMap& io_location_map() const { return io_location_map_; }
const std::unordered_map<AtomNetId, t_net_power>& net_activity() const { return net_activity_; } const std::unordered_map<AtomNetId, t_net_power>& net_activity() const { return net_activity_; }
const openfpga::NetlistManager& verilog_netlists() const { return verilog_netlists_; } const openfpga::NetlistManager& verilog_netlists() const { return verilog_netlists_; }
@ -79,7 +80,7 @@ class OpenfpgaContext : public Context {
openfpga::ModuleManager& mutable_module_graph() { return module_graph_; } openfpga::ModuleManager& mutable_module_graph() { return module_graph_; }
openfpga::FlowManager& mutable_flow_manager() { return flow_manager_; } openfpga::FlowManager& mutable_flow_manager() { return flow_manager_; }
openfpga::BitstreamManager& mutable_bitstream_manager() { return bitstream_manager_; } openfpga::BitstreamManager& mutable_bitstream_manager() { return bitstream_manager_; }
std::vector<openfpga::ConfigBitId>& mutable_fabric_bitstream() { return fabric_bitstream_; } openfpga::FabricBitstream& mutable_fabric_bitstream() { return fabric_bitstream_; }
openfpga::IoLocationMap& mutable_io_location_map() { return io_location_map_; } openfpga::IoLocationMap& mutable_io_location_map() { return io_location_map_; }
std::unordered_map<AtomNetId, t_net_power>& mutable_net_activity() { return net_activity_; } std::unordered_map<AtomNetId, t_net_power>& mutable_net_activity() { return net_activity_; }
openfpga::NetlistManager& mutable_verilog_netlists() { return verilog_netlists_; } openfpga::NetlistManager& mutable_verilog_netlists() { return verilog_netlists_; }
@ -120,7 +121,7 @@ class OpenfpgaContext : public Context {
/* Bitstream database */ /* Bitstream database */
openfpga::BitstreamManager bitstream_manager_; openfpga::BitstreamManager bitstream_manager_;
std::vector<openfpga::ConfigBitId> fabric_bitstream_; openfpga::FabricBitstream fabric_bitstream_;
/* Netlist database /* Netlist database
* TODO: Each format should have an independent entry * TODO: Each format should have an independent entry

View File

@ -28,11 +28,11 @@ namespace openfpga {
* in the configurable_children) and configurable_child_instances() of each module of module manager * in the configurable_children) and configurable_child_instances() of each module of module manager
*******************************************************************/ *******************************************************************/
static static
void rec_build_module_fabric_dependent_bitstream(const BitstreamManager& bitstream_manager, void rec_build_module_fabric_dependent_chain_bitstream(const BitstreamManager& bitstream_manager,
const ConfigBlockId& parent_block, const ConfigBlockId& parent_block,
const ModuleManager& module_manager, const ModuleManager& module_manager,
const ModuleId& parent_module, const ModuleId& parent_module,
std::vector<ConfigBitId>& fabric_bitstream) { FabricBitstream& fabric_bitstream) {
/* Depth-first search: if we have any children in the parent_block, /* Depth-first search: if we have any children in the parent_block,
* we dive to the next level first! * we dive to the next level first!
@ -51,7 +51,7 @@ void rec_build_module_fabric_dependent_bitstream(const BitstreamManager& bitstre
VTR_ASSERT(true == bitstream_manager.valid_block_id(child_block)); VTR_ASSERT(true == bitstream_manager.valid_block_id(child_block));
/* Go recursively */ /* Go recursively */
rec_build_module_fabric_dependent_bitstream(bitstream_manager, child_block, rec_build_module_fabric_dependent_chain_bitstream(bitstream_manager, child_block,
module_manager, child_module, module_manager, child_module,
fabric_bitstream); fabric_bitstream);
} }
@ -64,45 +64,47 @@ void rec_build_module_fabric_dependent_bitstream(const BitstreamManager& bitstre
* And then, we can return * And then, we can return
*/ */
for (const ConfigBitId& config_bit : bitstream_manager.block_bits(parent_block)) { for (const ConfigBitId& config_bit : bitstream_manager.block_bits(parent_block)) {
fabric_bitstream.push_back(config_bit); fabric_bitstream.add_bit(config_bit);
} }
} }
/******************************************************************** /********************************************************************
* A top-level function re-organizes the bitstream for a specific * Main function to build a fabric-dependent bitstream
* FPGA fabric, where configuration bits are organized in the sequence * by considering the configuration protocol types
* that can be directly loaded to the FPGA configuration protocol.
* Support:
* 1. Configuration chain
* 2. Memory decoders
* This function does NOT modify the bitstream database
* Instead, it builds a vector of ids for configuration bits in bitstream manager
*
* This function can be called ONLY after the function build_device_bitstream()
* Note that this function does NOT decode bitstreams from circuit implementation
* It was done in the function build_device_bitstream()
*******************************************************************/ *******************************************************************/
std::vector<ConfigBitId> build_fabric_dependent_bitstream(const BitstreamManager& bitstream_manager, static
void build_module_fabric_dependent_bitstream(const ConfigProtocol& config_protocol,
const BitstreamManager& bitstream_manager,
const ConfigBlockId& top_block,
const ModuleManager& module_manager, const ModuleManager& module_manager,
const bool& verbose) { const ModuleId& top_module,
std::vector<ConfigBitId> fabric_bitstream; FabricBitstream& fabric_bitstream) {
vtr::ScopedStartFinishTimer timer("\nBuild fabric dependent bitstream\n"); switch (config_protocol.type()) {
case CONFIG_MEM_STANDALONE: {
/* Get the top module name in module manager, which is our starting point */ rec_build_module_fabric_dependent_chain_bitstream(bitstream_manager, top_block,
std::string top_module_name = generate_fpga_top_module_name();
ModuleId top_module = module_manager.find_module(top_module_name);
VTR_ASSERT(true == module_manager.valid_module_id(top_module));
/* Find the top block in bitstream manager, which has not parents */
std::vector<ConfigBlockId> top_block = find_bitstream_manager_top_blocks(bitstream_manager);
/* Make sure we have only 1 top block and its name matches the top module */
VTR_ASSERT(1 == top_block.size());
VTR_ASSERT(0 == top_module_name.compare(bitstream_manager.block_name(top_block[0])));
rec_build_module_fabric_dependent_bitstream(bitstream_manager, top_block[0],
module_manager, top_module, module_manager, top_module,
fabric_bitstream); fabric_bitstream);
break;
}
case CONFIG_MEM_SCAN_CHAIN: {
rec_build_module_fabric_dependent_chain_bitstream(bitstream_manager, top_block,
module_manager, top_module,
fabric_bitstream);
fabric_bitstream.reverse();
break;
}
case CONFIG_MEM_MEMORY_BANK: {
break;
}
case CONFIG_MEM_FRAME_BASED: {
break;
}
default:
VTR_LOGF_ERROR(__FILE__, __LINE__,
"Invalid SRAM organization.\n");
exit(1);
}
/* Time-consuming sanity check: Uncomment these codes only for debugging!!! /* Time-consuming sanity check: Uncomment these codes only for debugging!!!
* Check which configuration bits are not touched * Check which configuration bits are not touched
@ -124,11 +126,50 @@ std::vector<ConfigBitId> build_fabric_dependent_bitstream(const BitstreamManager
*/ */
/* Ensure our fabric bitstream is in the same size as device bistream */ /* Ensure our fabric bitstream is in the same size as device bistream */
VTR_ASSERT(bitstream_manager.bits().size() == fabric_bitstream.size()); VTR_ASSERT(bitstream_manager.bits().size() == fabric_bitstream.bits().size());
}
/********************************************************************
* A top-level function re-organizes the bitstream for a specific
* FPGA fabric, where configuration bits are organized in the sequence
* that can be directly loaded to the FPGA configuration protocol.
* Support:
* 1. Configuration chain
* 2. Memory decoders
* This function does NOT modify the bitstream database
* Instead, it builds a vector of ids for configuration bits in bitstream manager
*
* This function can be called ONLY after the function build_device_bitstream()
* Note that this function does NOT decode bitstreams from circuit implementation
* It was done in the function build_device_bitstream()
*******************************************************************/
FabricBitstream build_fabric_dependent_bitstream(const BitstreamManager& bitstream_manager,
const ModuleManager& module_manager,
const ConfigProtocol& config_protocol,
const bool& verbose) {
FabricBitstream fabric_bitstream;
vtr::ScopedStartFinishTimer timer("\nBuild fabric dependent bitstream\n");
/* Get the top module name in module manager, which is our starting point */
std::string top_module_name = generate_fpga_top_module_name();
ModuleId top_module = module_manager.find_module(top_module_name);
VTR_ASSERT(true == module_manager.valid_module_id(top_module));
/* Find the top block in bitstream manager, which has not parents */
std::vector<ConfigBlockId> top_block = find_bitstream_manager_top_blocks(bitstream_manager);
/* Make sure we have only 1 top block and its name matches the top module */
VTR_ASSERT(1 == top_block.size());
VTR_ASSERT(0 == top_module_name.compare(bitstream_manager.block_name(top_block[0])));
build_module_fabric_dependent_bitstream(config_protocol,
bitstream_manager, top_block[0],
module_manager, top_module,
fabric_bitstream);
VTR_LOGV(verbose, VTR_LOGV(verbose,
"Built %lu configuration bits for fabric\n", "Built %lu configuration bits for fabric\n",
fabric_bitstream.size()); fabric_bitstream.bits().size());
return fabric_bitstream; return fabric_bitstream;
} }

View File

@ -5,7 +5,9 @@
* Include header files that are required by function declaration * Include header files that are required by function declaration
*******************************************************************/ *******************************************************************/
#include <vector> #include <vector>
#include "config_protocol.h"
#include "bitstream_manager.h" #include "bitstream_manager.h"
#include "fabric_bitstream.h"
#include "module_manager.h" #include "module_manager.h"
/******************************************************************** /********************************************************************
@ -15,8 +17,9 @@
/* begin namespace openfpga */ /* begin namespace openfpga */
namespace openfpga { namespace openfpga {
std::vector<ConfigBitId> build_fabric_dependent_bitstream(const BitstreamManager& bitstream_manager, FabricBitstream build_fabric_dependent_bitstream(const BitstreamManager& bitstream_manager,
const ModuleManager& module_manager, const ModuleManager& module_manager,
const ConfigProtocol& config_protocol,
const bool& verbose); const bool& verbose);
} /* end namespace openfpga */ } /* end namespace openfpga */

View File

@ -67,6 +67,12 @@ void FabricBitstream::set_bit_din(const FabricBitId& bit_id,
bit_dins_[bit_id] = din; 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());
}
/****************************************************************************** /******************************************************************************
* Public Validators * Public Validators
******************************************************************************/ ******************************************************************************/

View File

@ -67,6 +67,11 @@ class FabricBitstream {
void set_bit_din(const FabricBitId& bit_id, void set_bit_din(const FabricBitId& bit_id,
const bool& din); const bool& din);
/* Reverse bit sequence of the fabric bitstream
* This is required by configuration chain protocol
*/
void reverse();
public: /* Public Validators */ public: /* Public Validators */
bool valid_bit_id(const FabricBitId& bit_id) const; bool valid_bit_id(const FabricBitId& bit_id) const;

View File

@ -31,14 +31,14 @@ namespace openfpga {
* in this file * in this file
*******************************************************************/ *******************************************************************/
void write_fabric_bitstream_to_text_file(const BitstreamManager& bitstream_manager, void write_fabric_bitstream_to_text_file(const BitstreamManager& bitstream_manager,
const std::vector<ConfigBitId>& fabric_bitstream, const FabricBitstream& fabric_bitstream,
const std::string& fname) { const std::string& fname) {
/* Ensure that we have a valid file name */ /* Ensure that we have a valid file name */
if (true == fname.empty()) { if (true == fname.empty()) {
VTR_LOG_ERROR("Received empty file name to output bitstream!\n\tPlease specify a valid file name.\n"); VTR_LOG_ERROR("Received empty file name to output bitstream!\n\tPlease specify a valid file name.\n");
} }
std::string timer_message = std::string("Write ") + std::to_string(fabric_bitstream.size()) + std::string(" fabric bitstream into plain text file '") + fname + std::string("'"); 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("'");
vtr::ScopedStartFinishTimer timer(timer_message); vtr::ScopedStartFinishTimer timer(timer_message);
/* Create the file stream */ /* Create the file stream */
@ -48,8 +48,8 @@ void write_fabric_bitstream_to_text_file(const BitstreamManager& bitstream_manag
check_file_stream(fname.c_str(), fp); check_file_stream(fname.c_str(), fp);
/* Put down pure 0|1 bitstream here */ /* Put down pure 0|1 bitstream here */
for (const ConfigBitId& fabric_bit : fabric_bitstream) { for (const FabricBitId& fabric_bit : fabric_bitstream.bits()) {
fp << bitstream_manager.bit_value(fabric_bit); fp << bitstream_manager.bit_value(fabric_bitstream.config_bit(fabric_bit));
} }
/* Print an end to the file here */ /* Print an end to the file here */
fp << std::endl; fp << std::endl;

View File

@ -7,6 +7,7 @@
#include <string> #include <string>
#include <vector> #include <vector>
#include "bitstream_manager.h" #include "bitstream_manager.h"
#include "fabric_bitstream.h"
/******************************************************************** /********************************************************************
* Function declaration * Function declaration
@ -16,7 +17,7 @@
namespace openfpga { namespace openfpga {
void write_fabric_bitstream_to_text_file(const BitstreamManager& bitstream_manager, void write_fabric_bitstream_to_text_file(const BitstreamManager& bitstream_manager,
const std::vector<ConfigBitId>& fabric_bitstream, const FabricBitstream& fabric_bitstream,
const std::string& fname); const std::string& fname);
} /* end namespace openfpga */ } /* end namespace openfpga */

View File

@ -147,7 +147,7 @@ void fpga_fabric_verilog(ModuleManager& module_manager,
********************************************************************/ ********************************************************************/
void fpga_verilog_testbench(const ModuleManager& module_manager, void fpga_verilog_testbench(const ModuleManager& module_manager,
const BitstreamManager& bitstream_manager, const BitstreamManager& bitstream_manager,
const std::vector<ConfigBitId>& fabric_bitstream, const FabricBitstream& fabric_bitstream,
const AtomContext& atom_ctx, const AtomContext& atom_ctx,
const PlacementContext& place_ctx, const PlacementContext& place_ctx,
const IoLocationMap& io_location_map, const IoLocationMap& io_location_map,

View File

@ -16,6 +16,7 @@
#include "netlist_manager.h" #include "netlist_manager.h"
#include "module_manager.h" #include "module_manager.h"
#include "bitstream_manager.h" #include "bitstream_manager.h"
#include "fabric_bitstream.h"
#include "simulation_setting.h" #include "simulation_setting.h"
#include "io_location_map.h" #include "io_location_map.h"
#include "vpr_netlist_annotation.h" #include "vpr_netlist_annotation.h"
@ -41,7 +42,7 @@ void fpga_fabric_verilog(ModuleManager& module_manager,
void fpga_verilog_testbench(const ModuleManager& module_manager, void fpga_verilog_testbench(const ModuleManager& module_manager,
const BitstreamManager& bitstream_manager, const BitstreamManager& bitstream_manager,
const std::vector<ConfigBitId>& fabric_bitstream, const FabricBitstream& fabric_bitstream,
const AtomContext& atom_ctx, const AtomContext& atom_ctx,
const PlacementContext& place_ctx, const PlacementContext& place_ctx,
const IoLocationMap& io_location_map, const IoLocationMap& io_location_map,

View File

@ -694,7 +694,7 @@ void print_verilog_top_testbench_generic_stimulus(std::fstream& fp,
static static
void print_verilog_top_testbench_configuration_chain_bitstream(std::fstream& fp, void print_verilog_top_testbench_configuration_chain_bitstream(std::fstream& fp,
const BitstreamManager& bitstream_manager, const BitstreamManager& bitstream_manager,
const std::vector<ConfigBitId>& fabric_bitstream) { const FabricBitstream& fabric_bitstream) {
/* Validate the file stream */ /* Validate the file stream */
valid_file_stream(fp); valid_file_stream(fp);
@ -720,11 +720,9 @@ void print_verilog_top_testbench_configuration_chain_bitstream(std::fstream& fp,
/* Attention: the configuration chain protcol requires the last configuration bit is fed first /* Attention: the configuration chain protcol requires the last configuration bit is fed first
* We will visit the fabric bitstream in a reverse way * We will visit the fabric bitstream in a reverse way
*/ */
std::vector<ConfigBitId> cc_bitstream = fabric_bitstream; for (const FabricBitId& bit_id : fabric_bitstream.bits()) {
std::reverse(cc_bitstream.begin(), cc_bitstream.end());
for (const ConfigBitId& bit_id : cc_bitstream) {
fp << "\t\t" << std::string(TOP_TESTBENCH_CC_PROG_TASK_NAME); fp << "\t\t" << std::string(TOP_TESTBENCH_CC_PROG_TASK_NAME);
fp << "(1'b" << (size_t)bitstream_manager.bit_value(bit_id) << ");" << std::endl; fp << "(1'b" << (size_t)bitstream_manager.bit_value(fabric_bitstream.config_bit(bit_id)) << ");" << std::endl;
} }
/* Raise the flag of configuration done when bitstream loading is complete */ /* Raise the flag of configuration done when bitstream loading is complete */
@ -753,7 +751,7 @@ static
void print_verilog_top_testbench_bitstream(std::fstream& fp, void print_verilog_top_testbench_bitstream(std::fstream& fp,
const e_config_protocol_type& sram_orgz_type, const e_config_protocol_type& sram_orgz_type,
const BitstreamManager& bitstream_manager, const BitstreamManager& bitstream_manager,
const std::vector<ConfigBitId>& fabric_bitstream) { const FabricBitstream& fabric_bitstream) {
/* Branch on the type of configuration protocol */ /* Branch on the type of configuration protocol */
switch (sram_orgz_type) { switch (sram_orgz_type) {
case CONFIG_MEM_STANDALONE: case CONFIG_MEM_STANDALONE:
@ -794,7 +792,7 @@ void print_verilog_top_testbench_bitstream(std::fstream& fp,
*******************************************************************/ *******************************************************************/
void print_verilog_top_testbench(const ModuleManager& module_manager, void print_verilog_top_testbench(const ModuleManager& module_manager,
const BitstreamManager& bitstream_manager, const BitstreamManager& bitstream_manager,
const std::vector<ConfigBitId>& fabric_bitstream, const FabricBitstream& fabric_bitstream,
const e_config_protocol_type& sram_orgz_type, const e_config_protocol_type& sram_orgz_type,
const CircuitLibrary& circuit_lib, const CircuitLibrary& circuit_lib,
const std::vector<CircuitPortId>& global_ports, const std::vector<CircuitPortId>& global_ports,
@ -842,7 +840,7 @@ void print_verilog_top_testbench(const ModuleManager& module_manager,
* by traversing the linked-list and count the number of SRAM=1 or BL=1&WL=1 in it. * by traversing the linked-list and count the number of SRAM=1 or BL=1&WL=1 in it.
* We plus 1 additional config clock cycle here because we need to reset everything during the first clock cycle * We plus 1 additional config clock cycle here because we need to reset everything during the first clock cycle
*/ */
size_t num_config_clock_cycles = 1 + fabric_bitstream.size(); size_t num_config_clock_cycles = 1 + fabric_bitstream.bits().size();
/* Generate stimuli for general control signals */ /* Generate stimuli for general control signals */
print_verilog_top_testbench_generic_stimulus(fp, print_verilog_top_testbench_generic_stimulus(fp,

View File

@ -8,6 +8,7 @@
#include <vector> #include <vector>
#include "module_manager.h" #include "module_manager.h"
#include "bitstream_manager.h" #include "bitstream_manager.h"
#include "fabric_bitstream.h"
#include "circuit_library.h" #include "circuit_library.h"
#include "vpr_context.h" #include "vpr_context.h"
#include "io_location_map.h" #include "io_location_map.h"
@ -23,7 +24,7 @@ namespace openfpga {
void print_verilog_top_testbench(const ModuleManager& module_manager, void print_verilog_top_testbench(const ModuleManager& module_manager,
const BitstreamManager& bitstream_manager, const BitstreamManager& bitstream_manager,
const std::vector<ConfigBitId>& fabric_bitstream, const FabricBitstream& fabric_bitstream,
const e_config_protocol_type& sram_orgz_type, const e_config_protocol_type& sram_orgz_type,
const CircuitLibrary& circuit_lib, const CircuitLibrary& circuit_lib,
const std::vector<CircuitPortId>& global_ports, const std::vector<CircuitPortId>& global_ports,