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 */
openfpga_ctx.mutable_fabric_bitstream() = build_fabric_dependent_bitstream(openfpga_ctx.bitstream_manager(),
openfpga_ctx.module_graph(),
openfpga_ctx.arch().config_protocol,
cmd_context.option_enable(cmd, opt_verbose));
/* Write fabric bitstream if required */

View File

@ -16,6 +16,7 @@
#include "netlist_manager.h"
#include "openfpga_flow_manager.h"
#include "bitstream_manager.h"
#include "fabric_bitstream.h"
#include "device_rr_gsb.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::FlowManager& flow_manager() const { return flow_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 std::unordered_map<AtomNetId, t_net_power>& net_activity() const { return net_activity_; }
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::FlowManager& mutable_flow_manager() { return flow_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_; }
std::unordered_map<AtomNetId, t_net_power>& mutable_net_activity() { return net_activity_; }
openfpga::NetlistManager& mutable_verilog_netlists() { return verilog_netlists_; }
@ -120,7 +121,7 @@ class OpenfpgaContext : public Context {
/* Bitstream database */
openfpga::BitstreamManager bitstream_manager_;
std::vector<openfpga::ConfigBitId> fabric_bitstream_;
openfpga::FabricBitstream fabric_bitstream_;
/* Netlist database
* 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
*******************************************************************/
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 ModuleManager& module_manager,
const ModuleId& parent_module,
std::vector<ConfigBitId>& fabric_bitstream) {
FabricBitstream& fabric_bitstream) {
/* Depth-first search: if we have any children in the parent_block,
* 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));
/* 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,
fabric_bitstream);
}
@ -64,45 +64,47 @@ void rec_build_module_fabric_dependent_bitstream(const BitstreamManager& bitstre
* And then, we can return
*/
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
* 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()
* Main function to build a fabric-dependent bitstream
* by considering the configuration protocol types
*******************************************************************/
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 bool& verbose) {
std::vector<ConfigBitId> fabric_bitstream;
const ModuleId& top_module,
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])));
rec_build_module_fabric_dependent_bitstream(bitstream_manager, top_block[0],
switch (config_protocol.type()) {
case CONFIG_MEM_STANDALONE: {
rec_build_module_fabric_dependent_chain_bitstream(bitstream_manager, top_block,
module_manager, top_module,
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!!!
* 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 */
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,
"Built %lu configuration bits for fabric\n",
fabric_bitstream.size());
fabric_bitstream.bits().size());
return fabric_bitstream;
}

View File

@ -5,7 +5,9 @@
* Include header files that are required by function declaration
*******************************************************************/
#include <vector>
#include "config_protocol.h"
#include "bitstream_manager.h"
#include "fabric_bitstream.h"
#include "module_manager.h"
/********************************************************************
@ -15,8 +17,9 @@
/* begin 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 ConfigProtocol& config_protocol,
const bool& verbose);
} /* end namespace openfpga */

View File

@ -67,6 +67,12 @@ void FabricBitstream::set_bit_din(const FabricBitId& bit_id,
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
******************************************************************************/

View File

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

View File

@ -31,14 +31,14 @@ namespace openfpga {
* in this file
*******************************************************************/
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) {
/* Ensure that we have a valid file name */
if (true == fname.empty()) {
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);
/* 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);
/* Put down pure 0|1 bitstream here */
for (const ConfigBitId& fabric_bit : fabric_bitstream) {
fp << bitstream_manager.bit_value(fabric_bit);
for (const FabricBitId& fabric_bit : fabric_bitstream.bits()) {
fp << bitstream_manager.bit_value(fabric_bitstream.config_bit(fabric_bit));
}
/* Print an end to the file here */
fp << std::endl;

View File

@ -7,6 +7,7 @@
#include <string>
#include <vector>
#include "bitstream_manager.h"
#include "fabric_bitstream.h"
/********************************************************************
* Function declaration
@ -16,7 +17,7 @@
namespace openfpga {
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);
} /* end namespace openfpga */

View File

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

View File

@ -16,6 +16,7 @@
#include "netlist_manager.h"
#include "module_manager.h"
#include "bitstream_manager.h"
#include "fabric_bitstream.h"
#include "simulation_setting.h"
#include "io_location_map.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,
const BitstreamManager& bitstream_manager,
const std::vector<ConfigBitId>& fabric_bitstream,
const FabricBitstream& fabric_bitstream,
const AtomContext& atom_ctx,
const PlacementContext& place_ctx,
const IoLocationMap& io_location_map,

View File

@ -694,7 +694,7 @@ void print_verilog_top_testbench_generic_stimulus(std::fstream& fp,
static
void print_verilog_top_testbench_configuration_chain_bitstream(std::fstream& fp,
const BitstreamManager& bitstream_manager,
const std::vector<ConfigBitId>& fabric_bitstream) {
const FabricBitstream& fabric_bitstream) {
/* Validate the file stream */
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
* We will visit the fabric bitstream in a reverse way
*/
std::vector<ConfigBitId> cc_bitstream = fabric_bitstream;
std::reverse(cc_bitstream.begin(), cc_bitstream.end());
for (const ConfigBitId& bit_id : cc_bitstream) {
for (const FabricBitId& bit_id : fabric_bitstream.bits()) {
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 */
@ -753,7 +751,7 @@ static
void print_verilog_top_testbench_bitstream(std::fstream& fp,
const e_config_protocol_type& sram_orgz_type,
const BitstreamManager& bitstream_manager,
const std::vector<ConfigBitId>& fabric_bitstream) {
const FabricBitstream& fabric_bitstream) {
/* Branch on the type of configuration protocol */
switch (sram_orgz_type) {
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,
const BitstreamManager& bitstream_manager,
const std::vector<ConfigBitId>& fabric_bitstream,
const FabricBitstream& fabric_bitstream,
const e_config_protocol_type& sram_orgz_type,
const CircuitLibrary& circuit_lib,
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.
* 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 */
print_verilog_top_testbench_generic_stimulus(fp,

View File

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