add fabric bitstream data structure and deploy it to Verilog testbench generation
This commit is contained in:
parent
8c14cced84
commit
4a0e1cd908
|
@ -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 */
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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,
|
||||
const ConfigBlockId& parent_block,
|
||||
const ModuleManager& module_manager,
|
||||
const ModuleId& parent_module,
|
||||
std::vector<ConfigBitId>& fabric_bitstream) {
|
||||
void rec_build_module_fabric_dependent_chain_bitstream(const BitstreamManager& bitstream_manager,
|
||||
const ConfigBlockId& parent_block,
|
||||
const ModuleManager& module_manager,
|
||||
const ModuleId& parent_module,
|
||||
FabricBitstream& fabric_bitstream) {
|
||||
|
||||
/* Depth-first search: if we have any children in the parent_block,
|
||||
* we dive to the next level first!
|
||||
|
@ -51,9 +51,9 @@ 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,
|
||||
module_manager, child_module,
|
||||
fabric_bitstream);
|
||||
rec_build_module_fabric_dependent_chain_bitstream(bitstream_manager, child_block,
|
||||
module_manager, child_module,
|
||||
fabric_bitstream);
|
||||
}
|
||||
/* Ensure that there should be no configuration bits in the parent block */
|
||||
VTR_ASSERT(0 == bitstream_manager.block_bits(parent_block).size());
|
||||
|
@ -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,
|
||||
const ModuleManager& module_manager,
|
||||
const bool& verbose) {
|
||||
std::vector<ConfigBitId> fabric_bitstream;
|
||||
static
|
||||
void build_module_fabric_dependent_bitstream(const ConfigProtocol& config_protocol,
|
||||
const BitstreamManager& bitstream_manager,
|
||||
const ConfigBlockId& top_block,
|
||||
const ModuleManager& module_manager,
|
||||
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],
|
||||
module_manager, top_module,
|
||||
fabric_bitstream);
|
||||
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;
|
||||
}
|
||||
|
|
|
@ -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,9 +17,10 @@
|
|||
/* begin namespace openfpga */
|
||||
namespace openfpga {
|
||||
|
||||
std::vector<ConfigBitId> build_fabric_dependent_bitstream(const BitstreamManager& bitstream_manager,
|
||||
const ModuleManager& module_manager,
|
||||
const bool& verbose);
|
||||
FabricBitstream build_fabric_dependent_bitstream(const BitstreamManager& bitstream_manager,
|
||||
const ModuleManager& module_manager,
|
||||
const ConfigProtocol& config_protocol,
|
||||
const bool& verbose);
|
||||
|
||||
} /* end namespace openfpga */
|
||||
|
||||
|
|
|
@ -56,17 +56,23 @@ FabricBitId FabricBitstream::add_bit(const ConfigBitId& config_bit_id) {
|
|||
}
|
||||
|
||||
void FabricBitstream::set_bit_address(const FabricBitId& bit_id,
|
||||
const std::vector<bool>& address) {
|
||||
const std::vector<bool>& address) {
|
||||
VTR_ASSERT(true == valid_bit_id(bit_id));
|
||||
bit_addresses_[bit_id] = address;
|
||||
}
|
||||
|
||||
void FabricBitstream::set_bit_din(const FabricBitId& bit_id,
|
||||
const bool& din) {
|
||||
const bool& din) {
|
||||
VTR_ASSERT(true == valid_bit_id(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
|
||||
******************************************************************************/
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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,
|
||||
|
|
Loading…
Reference in New Issue