add fabric bitstream XML writer
This commit is contained in:
parent
a3d22c56e3
commit
92d2d2d849
|
@ -52,6 +52,13 @@ bool BitstreamManager::bit_value(const ConfigBitId& bit_id) const {
|
|||
return '1' == bit_values_[bit_id];
|
||||
}
|
||||
|
||||
ConfigBlockId BitstreamManager::bit_parent_block(const ConfigBitId& bit_id) const {
|
||||
/* Ensure a valid id */
|
||||
VTR_ASSERT(true == valid_bit_id(bit_id));
|
||||
|
||||
return bit_parent_blocks_[bit_id];
|
||||
}
|
||||
|
||||
std::string BitstreamManager::block_name(const ConfigBlockId& block_id) const {
|
||||
/* Ensure the input ids are valid */
|
||||
VTR_ASSERT(true == valid_block_id(block_id));
|
||||
|
@ -140,7 +147,7 @@ std::string BitstreamManager::block_output_net_ids(const ConfigBlockId& block_id
|
|||
/******************************************************************************
|
||||
* Public Mutators
|
||||
******************************************************************************/
|
||||
ConfigBitId BitstreamManager::add_bit(const bool& bit_value) {
|
||||
ConfigBitId BitstreamManager::add_bit(const ConfigBlockId& parent_block, const bool& bit_value) {
|
||||
ConfigBitId bit = ConfigBitId(num_bits_);
|
||||
/* Add a new bit, and allocate associated data structures */
|
||||
num_bits_++;
|
||||
|
@ -150,6 +157,8 @@ ConfigBitId BitstreamManager::add_bit(const bool& bit_value) {
|
|||
bit_values_.push_back('0');
|
||||
}
|
||||
|
||||
bit_parent_blocks_.push_back(parent_block);
|
||||
|
||||
return bit;
|
||||
}
|
||||
|
||||
|
@ -234,7 +243,7 @@ void BitstreamManager::add_block_bits(const ConfigBlockId& block,
|
|||
block_bit_id_lsbs_[block] = num_bits_;
|
||||
block_bit_lengths_[block] = block_bitstream.size();
|
||||
for (const bool& bit : block_bitstream) {
|
||||
add_bit(bit);
|
||||
add_bit(block, bit);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -119,6 +119,9 @@ class BitstreamManager {
|
|||
/* Find the value of bitstream */
|
||||
bool bit_value(const ConfigBitId& bit_id) const;
|
||||
|
||||
/* Find the parent block of a configuration bit */
|
||||
ConfigBlockId bit_parent_block(const ConfigBitId& bit_id) const;
|
||||
|
||||
/* Find a name of a block */
|
||||
std::string block_name(const ConfigBlockId& block_id) const;
|
||||
|
||||
|
@ -145,7 +148,7 @@ class BitstreamManager {
|
|||
|
||||
public: /* Public Mutators */
|
||||
/* Add a new configuration bit to the bitstream manager */
|
||||
ConfigBitId add_bit(const bool& bit_value);
|
||||
ConfigBitId add_bit(const ConfigBlockId& parent_block, const bool& bit_value);
|
||||
|
||||
/* Reserve memory for a number of clocks */
|
||||
void reserve_blocks(const size_t& num_blocks);
|
||||
|
@ -235,6 +238,7 @@ class BitstreamManager {
|
|||
std::unordered_set<ConfigBitId> invalid_bit_ids_;
|
||||
/* value of a bit in the Bitstream */
|
||||
vtr::vector<ConfigBitId, char> bit_values_;
|
||||
vtr::vector<ConfigBitId, ConfigBlockId> bit_parent_blocks_;
|
||||
};
|
||||
|
||||
} /* end namespace openfpga */
|
||||
|
|
|
@ -16,7 +16,8 @@
|
|||
#include "write_xml_arch_bitstream.h"
|
||||
|
||||
#include "build_device_bitstream.h"
|
||||
#include "fabric_bitstream_writer.h"
|
||||
#include "write_text_fabric_bitstream.h"
|
||||
#include "write_xml_fabric_bitstream.h"
|
||||
#include "build_fabric_bitstream.h"
|
||||
#include "openfpga_bitstream.h"
|
||||
|
||||
|
@ -66,6 +67,7 @@ int build_fabric_bitstream(OpenfpgaContext& openfpga_ctx,
|
|||
|
||||
CommandOptionId opt_verbose = cmd.option("verbose");
|
||||
CommandOptionId opt_file = cmd.option("file");
|
||||
CommandOptionId opt_file_format = cmd.option("file_format");
|
||||
|
||||
/* Build fabric bitstream here */
|
||||
openfpga_ctx.mutable_fabric_bitstream() = build_fabric_dependent_bitstream(openfpga_ctx.bitstream_manager(),
|
||||
|
@ -81,10 +83,24 @@ int build_fabric_bitstream(OpenfpgaContext& openfpga_ctx,
|
|||
/* Create directories */
|
||||
create_directory(src_dir_path);
|
||||
|
||||
status = write_fabric_bitstream_to_text_file(openfpga_ctx.bitstream_manager(),
|
||||
openfpga_ctx.fabric_bitstream(),
|
||||
openfpga_ctx.arch().config_protocol,
|
||||
cmd_context.option_value(cmd, opt_file));
|
||||
/* Check file format requirements */
|
||||
std::string file_format("plain_text");
|
||||
if (true == cmd_context.option_enable(cmd, opt_file_format)) {
|
||||
file_format = cmd_context.option_value(cmd, opt_file_format);
|
||||
}
|
||||
|
||||
if (std::string("xml") == file_format) {
|
||||
status = write_fabric_bitstream_to_xml_file(openfpga_ctx.bitstream_manager(),
|
||||
openfpga_ctx.fabric_bitstream(),
|
||||
openfpga_ctx.arch().config_protocol,
|
||||
cmd_context.option_value(cmd, opt_file));
|
||||
} else {
|
||||
/* By default, output in plain text format */
|
||||
status = write_fabric_bitstream_to_text_file(openfpga_ctx.bitstream_manager(),
|
||||
openfpga_ctx.fabric_bitstream(),
|
||||
openfpga_ctx.arch().config_protocol,
|
||||
cmd_context.option_value(cmd, opt_file));
|
||||
}
|
||||
}
|
||||
|
||||
/* TODO: should identify the error code from internal function execution */
|
||||
|
|
|
@ -85,6 +85,10 @@ ShellCommandId add_openfpga_fabric_bitstream_command(openfpga::Shell<OpenfpgaCon
|
|||
shell_cmd.set_option_short_name(opt_file, "f");
|
||||
shell_cmd.set_option_require_value(opt_file, openfpga::OPT_STRING);
|
||||
|
||||
/* Add an option '--file_format'*/
|
||||
CommandOptionId opt_file_format = shell_cmd.add_option("format", false, "file format of fabric bitstream [plain_text|xml]. Default: plain_text");
|
||||
shell_cmd.set_option_require_value(opt_file_format, openfpga::OPT_STRING);
|
||||
|
||||
/* Add an option '--verbose' */
|
||||
shell_cmd.add_option("verbose", false, "Enable verbose output");
|
||||
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
/********************************************************************
|
||||
* This file includes functions that output a fabric-dependent
|
||||
* bitstream database to files in different formats
|
||||
* bitstream database to files in plain text
|
||||
*******************************************************************/
|
||||
#include <chrono>
|
||||
#include <ctime>
|
||||
|
@ -17,7 +17,7 @@
|
|||
#include "openfpga_naming.h"
|
||||
|
||||
#include "bitstream_manager_utils.h"
|
||||
#include "fabric_bitstream_writer.h"
|
||||
#include "write_text_fabric_bitstream.h"
|
||||
|
||||
/* begin namespace openfpga */
|
||||
namespace openfpga {
|
|
@ -1,5 +1,5 @@
|
|||
#ifndef FABRIC_BITSTREAM_WRITER_H
|
||||
#define FABRIC_BITSTREAM_WRITER_H
|
||||
#ifndef WRITE_TEXT_FABRIC_BITSTREAM_H
|
||||
#define WRITE_TEXT_FABRIC_BITSTREAM_H
|
||||
|
||||
/********************************************************************
|
||||
* Include header files that are required by function declaration
|
|
@ -0,0 +1,194 @@
|
|||
/********************************************************************
|
||||
* This file includes functions that output a fabric-dependent
|
||||
* bitstream database to files in XML format
|
||||
*******************************************************************/
|
||||
#include <chrono>
|
||||
#include <ctime>
|
||||
#include <fstream>
|
||||
|
||||
/* Headers from vtrutil library */
|
||||
#include "vtr_assert.h"
|
||||
#include "vtr_log.h"
|
||||
#include "vtr_time.h"
|
||||
|
||||
/* Headers from openfpgautil library */
|
||||
#include "openfpga_digest.h"
|
||||
|
||||
/* Headers from archopenfpga library */
|
||||
|
||||
#include "openfpga_naming.h"
|
||||
|
||||
#include "bitstream_manager_utils.h"
|
||||
#include "write_xml_fabric_bitstream.h"
|
||||
|
||||
/* begin namespace openfpga */
|
||||
namespace openfpga {
|
||||
|
||||
/********************************************************************
|
||||
* This function write header information to a bitstream file
|
||||
*******************************************************************/
|
||||
static
|
||||
void write_fabric_bitstream_xml_file_head(std::fstream& fp) {
|
||||
valid_file_stream(fp);
|
||||
|
||||
auto end = std::chrono::system_clock::now();
|
||||
std::time_t end_time = std::chrono::system_clock::to_time_t(end);
|
||||
|
||||
fp << "<!--" << std::endl;
|
||||
fp << "\t- Fabric bitstream" << std::endl;
|
||||
fp << "\t- Author: Xifan TANG" << std::endl;
|
||||
fp << "\t- Organization: University of Utah" << std::endl;
|
||||
fp << "\t- Date: " << std::ctime(&end_time) ;
|
||||
fp << "-->" << std::endl;
|
||||
fp << std::endl;
|
||||
}
|
||||
|
||||
/********************************************************************
|
||||
* Write a configuration bit into a plain text file
|
||||
* General format
|
||||
* <bit id="<fabric_bit>" value="<config_bit_value>">
|
||||
* <hierarchy>
|
||||
* <!-- configurable memory hierarchy -->
|
||||
* </hierarchy>
|
||||
* <!-- address information -->
|
||||
* ...
|
||||
* </bit>
|
||||
* The format depends on the type of configuration protocol
|
||||
* - Vanilla (standalone): No more information to be included
|
||||
* - Configuration chain: No more information to be included
|
||||
* - Memory bank :
|
||||
* <bl address="<bl_address_value>"/>
|
||||
* <wl address="<wl_address_value>"/>
|
||||
* - Frame-based configuration protocol :
|
||||
* <frame address="<frame_address_value>"/>
|
||||
*
|
||||
* Return:
|
||||
* - 0 if succeed
|
||||
* - 1 if critical errors occured
|
||||
*******************************************************************/
|
||||
static
|
||||
int write_fabric_config_bit_to_xml_file(std::fstream& fp,
|
||||
const BitstreamManager& bitstream_manager,
|
||||
const FabricBitstream& fabric_bitstream,
|
||||
const FabricBitId& fabric_bit,
|
||||
const e_config_protocol_type& config_type) {
|
||||
if (false == valid_file_stream(fp)) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
fp << "<bit id=\"" << size_t(fabric_bit) << "\" ";
|
||||
fp << "value=\"";
|
||||
fp << bitstream_manager.bit_value(fabric_bitstream.config_bit(fabric_bit));
|
||||
fp << "\">\n";
|
||||
|
||||
/* Output hierarchy of this parent*/
|
||||
const ConfigBitId& config_bit = fabric_bitstream.config_bit(fabric_bit);
|
||||
const ConfigBlockId& config_block = bitstream_manager.bit_parent_block(config_bit);
|
||||
std::vector<ConfigBlockId> block_hierarchy = find_bitstream_manager_block_hierarchy(bitstream_manager, config_block);
|
||||
write_tab_to_file(fp, 1);
|
||||
fp << "<hierarchy>\n";
|
||||
size_t hierarchy_counter = 0;
|
||||
for (const ConfigBlockId& temp_block : block_hierarchy) {
|
||||
write_tab_to_file(fp, 2);
|
||||
fp << "<instance level=\"" << hierarchy_counter << "\"";
|
||||
fp << " name=\"" << bitstream_manager.block_name(temp_block) << "\"";
|
||||
fp << "/>\n";
|
||||
hierarchy_counter++;
|
||||
}
|
||||
fp << "</hierarchy>\n";
|
||||
|
||||
switch (config_type) {
|
||||
case CONFIG_MEM_STANDALONE:
|
||||
case CONFIG_MEM_SCAN_CHAIN:
|
||||
break;
|
||||
case CONFIG_MEM_MEMORY_BANK: {
|
||||
/* Bit line address */
|
||||
write_tab_to_file(fp, 1);
|
||||
fp << "<bl address=\"";
|
||||
for (const char& addr_bit : fabric_bitstream.bit_bl_address(fabric_bit)) {
|
||||
fp << addr_bit;
|
||||
}
|
||||
fp << "\"/>\n";
|
||||
|
||||
write_space_to_file(fp, 1);
|
||||
fp << "<wl address=\"";
|
||||
for (const char& addr_bit : fabric_bitstream.bit_wl_address(fabric_bit)) {
|
||||
fp << addr_bit;
|
||||
}
|
||||
fp << "\"/>\n";
|
||||
break;
|
||||
}
|
||||
case CONFIG_MEM_FRAME_BASED: {
|
||||
write_space_to_file(fp, 1);
|
||||
fp << "<frame address=\"";
|
||||
for (const char& addr_bit : fabric_bitstream.bit_address(fabric_bit)) {
|
||||
fp << addr_bit;
|
||||
}
|
||||
fp << "\"/>\n";
|
||||
fp << "\n";
|
||||
break;
|
||||
}
|
||||
default:
|
||||
VTR_LOGF_ERROR(__FILE__, __LINE__,
|
||||
"Invalid configuration protocol type!\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
fp << "</bit>\n";
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/********************************************************************
|
||||
* Write the fabric bitstream to an XML file
|
||||
* Notes:
|
||||
* - This file is designed to be reused by testbench generators, e.g., CocoTB
|
||||
* - It can NOT be directly loaded to the FPGA fabric
|
||||
* - It include configurable memory paths in full hierarchy
|
||||
*
|
||||
* Return:
|
||||
* - 0 if succeed
|
||||
* - 1 if critical errors occured
|
||||
*******************************************************************/
|
||||
int write_fabric_bitstream_to_xml_file(const BitstreamManager& bitstream_manager,
|
||||
const FabricBitstream& fabric_bitstream,
|
||||
const ConfigProtocol& config_protocol,
|
||||
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.num_bits()) + std::string(" fabric bitstream into xml file '") + fname + std::string("'");
|
||||
vtr::ScopedStartFinishTimer timer(timer_message);
|
||||
|
||||
/* Create the file stream */
|
||||
std::fstream fp;
|
||||
fp.open(fname, std::fstream::out | std::fstream::trunc);
|
||||
|
||||
check_file_stream(fname.c_str(), fp);
|
||||
|
||||
/* Write XML head */
|
||||
write_fabric_bitstream_xml_file_head(fp);
|
||||
|
||||
/* Output fabric bitstream to the file */
|
||||
int status = 0;
|
||||
for (const FabricBitId& fabric_bit : fabric_bitstream.bits()) {
|
||||
status = write_fabric_config_bit_to_xml_file(fp, bitstream_manager,
|
||||
fabric_bitstream,
|
||||
fabric_bit,
|
||||
config_protocol.type());
|
||||
if (1 == status) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
/* Print an end to the file here */
|
||||
fp << std::endl;
|
||||
|
||||
/* Close file handler */
|
||||
fp.close();
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
} /* end namespace openfpga */
|
|
@ -0,0 +1,27 @@
|
|||
#ifndef WRITE_XML_FABRIC_BITSTREAM_H
|
||||
#define WRITE_XML_FABRIC_BITSTREAM_H
|
||||
|
||||
/********************************************************************
|
||||
* Include header files that are required by function declaration
|
||||
*******************************************************************/
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include "bitstream_manager.h"
|
||||
#include "fabric_bitstream.h"
|
||||
#include "config_protocol.h"
|
||||
|
||||
/********************************************************************
|
||||
* Function declaration
|
||||
*******************************************************************/
|
||||
|
||||
/* begin namespace openfpga */
|
||||
namespace openfpga {
|
||||
|
||||
int write_fabric_bitstream_to_xml_file(const BitstreamManager& bitstream_manager,
|
||||
const FabricBitstream& fabric_bitstream,
|
||||
const ConfigProtocol& config_protocol,
|
||||
const std::string& fname);
|
||||
|
||||
} /* end namespace openfpga */
|
||||
|
||||
#endif
|
Loading…
Reference in New Issue