2020-02-23 21:40:18 -06:00
/********************************************************************
* This file includes functions that output bitstream database
* to files in different formats
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
# 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"
2020-07-08 17:28:20 -05:00
# include "openfpga_tokenizer.h"
2020-02-23 21:40:18 -06:00
2020-06-20 19:25:17 -05:00
# include "openfpga_reserved_words.h"
2020-02-23 21:40:18 -06:00
# include "bitstream_manager_utils.h"
2020-06-21 14:06:39 -05:00
# include "write_xml_arch_bitstream.h"
2020-02-23 21:40:18 -06:00
/* begin namespace openfpga */
namespace openfpga {
/********************************************************************
* This function write header information to a bitstream file
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
static
void write_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 - Architecture independent 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 ;
}
/********************************************************************
* Recursively write the bitstream of a block to a xml file
* This function will use a Depth - First Search in outputting bitstream
* for each block
* 1. For block with bits as children , we will output the XML lines
* 2. For block without bits / child blocks , we can return
* 3. For block with child blocks , we visit each child recursively
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
static
void rec_write_block_bitstream_to_xml_file ( std : : fstream & fp ,
const BitstreamManager & bitstream_manager ,
2020-06-20 19:25:17 -05:00
const ConfigBlockId & block ,
const size_t & hierarchy_level ) {
2020-02-23 21:40:18 -06:00
valid_file_stream ( fp ) ;
2020-06-20 19:25:17 -05:00
/* Write the bits of this block */
write_tab_to_file ( fp , hierarchy_level ) ;
fp < < " <bitstream_block " ;
fp < < " name= \" " < < bitstream_manager . block_name ( block ) < < " \" " ;
fp < < " hierarchy_level= \" " < < hierarchy_level < < " \" " ;
fp < < " > " < < std : : endl ;
2020-02-23 21:40:18 -06:00
/* Dive to child blocks if this block has any */
for ( const ConfigBlockId & child_block : bitstream_manager . block_children ( block ) ) {
2020-06-20 19:25:17 -05:00
rec_write_block_bitstream_to_xml_file ( fp , bitstream_manager , child_block , hierarchy_level + 1 ) ;
2020-02-23 21:40:18 -06:00
}
if ( 0 = = bitstream_manager . block_bits ( block ) . size ( ) ) {
2020-06-20 19:25:17 -05:00
write_tab_to_file ( fp , hierarchy_level ) ;
fp < < " </bitstream_block> " < < std : : endl ;
2020-02-23 21:40:18 -06:00
return ;
}
std : : vector < ConfigBlockId > block_hierarchy = find_bitstream_manager_block_hierarchy ( bitstream_manager , block ) ;
/* Output hierarchy of this parent*/
2020-06-20 19:25:17 -05:00
write_tab_to_file ( fp , hierarchy_level + 1 ) ;
fp < < " <hierarchy> " < < std : : endl ;
2020-02-23 21:40:18 -06:00
size_t hierarchy_counter = 0 ;
for ( const ConfigBlockId & temp_block : block_hierarchy ) {
2020-06-20 19:25:17 -05:00
write_tab_to_file ( fp , hierarchy_level + 2 ) ;
fp < < " <instance level= \" " < < hierarchy_counter < < " \" " ;
2020-02-23 21:40:18 -06:00
fp < < " name= \" " < < bitstream_manager . block_name ( temp_block ) < < " \" " ;
fp < < " /> " < < std : : endl ;
hierarchy_counter + + ;
}
2020-06-20 19:25:17 -05:00
write_tab_to_file ( fp , hierarchy_level + 1 ) ;
fp < < " </hierarchy> " < < std : : endl ;
2020-02-23 21:40:18 -06:00
2020-06-17 01:04:55 -05:00
/* Output input/output nets if there are any */
if ( false = = bitstream_manager . block_input_net_ids ( block ) . empty ( ) ) {
2020-06-20 19:25:17 -05:00
write_tab_to_file ( fp , hierarchy_level + 1 ) ;
fp < < " <input_nets> \n " ;
size_t path_counter = 0 ;
2020-07-08 17:28:20 -05:00
/* Split with space */
StringToken input_net_tokenizer ( bitstream_manager . block_input_net_ids ( block ) ) ;
for ( const std : : string & net : input_net_tokenizer . split ( std : : string ( " " ) ) ) {
2020-06-20 19:25:17 -05:00
write_tab_to_file ( fp , hierarchy_level + 2 ) ;
fp < < " <path id= \" " < < path_counter < < " \" " ;
2020-06-20 19:39:21 -05:00
fp < < " net_name= \" " ;
2020-06-20 19:25:17 -05:00
fp < < net ;
fp < < " \" /> " ;
2020-06-20 20:01:33 -05:00
fp < < " \n " ;
2020-06-20 19:25:17 -05:00
path_counter + + ;
2020-06-17 01:04:55 -05:00
}
2020-06-20 19:25:17 -05:00
write_tab_to_file ( fp , hierarchy_level + 1 ) ;
fp < < " </input_nets> \n " ;
2020-06-17 01:04:55 -05:00
}
if ( false = = bitstream_manager . block_output_net_ids ( block ) . empty ( ) ) {
2020-06-20 19:25:17 -05:00
write_tab_to_file ( fp , hierarchy_level + 1 ) ;
fp < < " <output_nets> \n " ;
size_t path_counter = 0 ;
2020-07-08 17:28:20 -05:00
/* Split with space */
StringToken output_net_tokenizer ( bitstream_manager . block_output_net_ids ( block ) ) ;
for ( const std : : string & net : output_net_tokenizer . split ( std : : string ( " " ) ) ) {
2020-06-20 19:25:17 -05:00
write_tab_to_file ( fp , hierarchy_level + 2 ) ;
fp < < " <path id= \" " < < path_counter < < " \" " ;
2020-06-20 19:39:21 -05:00
fp < < " net_name= \" " ;
2020-06-20 19:25:17 -05:00
fp < < net ;
fp < < " \" /> " ;
2020-06-20 20:01:33 -05:00
fp < < " \n " ;
2020-06-20 19:25:17 -05:00
path_counter + + ;
2020-06-17 01:04:55 -05:00
}
2020-06-20 19:25:17 -05:00
write_tab_to_file ( fp , hierarchy_level + 1 ) ;
fp < < " </output_nets> \n " ;
2020-06-17 01:04:55 -05:00
}
2020-02-23 21:40:18 -06:00
/* Output child bits under this block */
size_t bit_counter = 0 ;
2020-06-20 19:25:17 -05:00
write_tab_to_file ( fp , hierarchy_level + 1 ) ;
fp < < " <bitstream " ;
2020-06-16 22:29:45 -05:00
/* Output path id only when it is valid */
if ( true = = bitstream_manager . valid_block_path_id ( block ) ) {
fp < < " path_id= \" " < < bitstream_manager . block_path_id ( block ) < < " \" " ;
}
fp < < " > " < < std : : endl ;
2020-06-17 01:04:55 -05:00
2020-02-23 21:40:18 -06:00
for ( const ConfigBitId & child_bit : bitstream_manager . block_bits ( block ) ) {
2020-06-20 19:25:17 -05:00
write_tab_to_file ( fp , hierarchy_level + 2 ) ;
fp < < " <bit " ;
fp < < " memory_port= \" " < < CONFIGURABLE_MEMORY_DATA_OUT_NAME < < " [ " < < bit_counter < < " ] " < < " \" " ;
2020-02-23 21:40:18 -06:00
fp < < " value= \" " < < bitstream_manager . bit_value ( child_bit ) < < " \" " ;
fp < < " /> " < < std : : endl ;
bit_counter + + ;
}
2020-06-20 19:25:17 -05:00
write_tab_to_file ( fp , hierarchy_level + 1 ) ;
fp < < " </bitstream> " < < std : : endl ;
2020-02-23 21:40:18 -06:00
2020-06-20 19:25:17 -05:00
write_tab_to_file ( fp , hierarchy_level ) ;
2020-02-23 21:40:18 -06:00
fp < < " </bitstream_block> " < < std : : endl ;
}
/********************************************************************
* Write the bitstream to a file without binding to the configuration
* procotols of a given FPGA fabric in XML format
*
* Notes :
* This is a very generic representation for bitstream that are implemented
* by VPR engine . It shows the bitstream for each blocks in the FPGA
* architecture that users are modeling .
* This function can be used to :
* 1. Debug the bitstream decoding to see if there is any bug
* 2. Create an intermediate file to reorganize a bitstream for
* specific FPGAs
* 3. TODO : support FASM format
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2020-06-21 14:06:39 -05:00
void write_xml_architecture_bitstream ( const BitstreamManager & bitstream_manager ,
const std : : string & fname ) {
2020-02-26 12:09:23 -06:00
/* Ensure that we have a valid file name */
if ( true = = fname . empty ( ) ) {
VTR_LOG_ERROR ( " Received empty file name to output bitstream! \n \t Please specify a valid file name. \n " ) ;
}
std : : string timer_message = std : : string ( " Write " ) + std : : to_string ( bitstream_manager . bits ( ) . size ( ) ) + std : : string ( " architecture independent bitstream into XML file ' " ) + fname + std : : string ( " ' " ) ;
2020-02-23 21:40:18 -06:00
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 ) ;
/* Put down a brief introduction */
write_bitstream_xml_file_head ( fp ) ;
/* Find the top block, which has not parents */
std : : vector < ConfigBlockId > top_block = find_bitstream_manager_top_blocks ( bitstream_manager ) ;
2020-06-21 14:06:39 -05:00
/* Make sure we have only 1 top block */
2020-02-23 21:40:18 -06:00
VTR_ASSERT ( 1 = = top_block . size ( ) ) ;
/* Write bitstream, block by block, in a recursive way */
2020-06-20 19:25:17 -05:00
rec_write_block_bitstream_to_xml_file ( fp , bitstream_manager , top_block [ 0 ] , 0 ) ;
2020-02-23 21:40:18 -06:00
/* Close file handler */
fp . close ( ) ;
}
} /* end namespace openfpga */