/* -*- c++ -*- * * SOCLIB_LGPL_HEADER_BEGIN * * This file is part of SoCLib, GNU LGPLv2.1. * * SoCLib is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as published * by the Free Software Foundation; version 2.1 of the License. * * SoCLib is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with SoCLib; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301 USA * * SOCLIB_LGPL_HEADER_END * * Copyright (c) UPMC, Lip6, Asim * alain.greiner@lip6.fr april 2011 * * Maintainers: alain */ #include #include #include #include "vci_block_device_tsar.h" #include "block_device_tsar.h" #define DEBUG_BDEV 0 namespace soclib { namespace caba { #define tmpl(t) template t VciBlockDeviceTsar using namespace soclib::caba; using namespace soclib::common; //////////////////////// tmpl(void)::transition() { if(p_resetn.read() == false) { r_initiator_fsm = M_IDLE; r_target_fsm = T_IDLE; r_irq_enable = true; r_go = false; return; } ////////////////////////////////////////////////////////////////////////////// // The Target FSM controls the following registers: // r_target_fsm, r_irq_enable, r_nblocks, r_buf adress, r_lba, r_go, r_read ////////////////////////////////////////////////////////////////////////////// switch(r_target_fsm) { //////////// case T_IDLE: { if ( p_vci_target.cmdval.read() ) { r_srcid = p_vci_target.srcid.read(); r_trdid = p_vci_target.trdid.read(); r_pktid = p_vci_target.pktid.read(); sc_dt::sc_uint address = p_vci_target.address.read(); bool found = false; std::list::iterator seg; for ( seg = m_seglist.begin() ; seg != m_seglist.end() ; seg++ ) { if ( seg->contains(address) ) found = true; } bool read = (p_vci_target.cmd.read() == vci_param::CMD_READ); uint32_t cell = (uint32_t)((address & 0x3F)>>2); bool pending = (r_initiator_fsm.read() != M_IDLE); if ( !read && not found ) r_target_fsm = T_WRITE_ERROR; else if( read && not found ) r_target_fsm = T_READ_ERROR; else if( !read && not p_vci_target.eop.read() ) r_target_fsm = T_WRITE_ERROR; else if( read && not p_vci_target.eop.read() ) r_target_fsm = T_READ_ERROR; else if( !read && pending ) r_target_fsm = T_WRITE_ERROR; else if( !read && (cell == BLOCK_DEVICE_BUFFER) ) r_target_fsm = T_WRITE_BUFFER; else if( read && (cell == BLOCK_DEVICE_BUFFER) ) r_target_fsm = T_READ_BUFFER; else if( !read && (cell == BLOCK_DEVICE_BUFFER_EXT) ) r_target_fsm = T_WRITE_BUFFER_EXT; else if( read && (cell == BLOCK_DEVICE_BUFFER_EXT) ) r_target_fsm = T_READ_BUFFER_EXT; else if( !read && (cell == BLOCK_DEVICE_COUNT) ) r_target_fsm = T_WRITE_COUNT; else if( read && (cell == BLOCK_DEVICE_COUNT) ) r_target_fsm = T_READ_COUNT; else if( !read && (cell == BLOCK_DEVICE_LBA) ) r_target_fsm = T_WRITE_LBA; else if( read && (cell == BLOCK_DEVICE_LBA) ) r_target_fsm = T_READ_LBA; else if( !read && (cell == BLOCK_DEVICE_OP) ) r_target_fsm = T_WRITE_OP; else if( read && (cell == BLOCK_DEVICE_STATUS) ) r_target_fsm = T_READ_STATUS; else if( !read && (cell == BLOCK_DEVICE_IRQ_ENABLE) ) r_target_fsm = T_WRITE_IRQEN; else if( read && (cell == BLOCK_DEVICE_IRQ_ENABLE) ) r_target_fsm = T_READ_IRQEN; else if( read && (cell == BLOCK_DEVICE_SIZE) ) r_target_fsm = T_READ_SIZE; else if( read && (cell == BLOCK_DEVICE_BLOCK_SIZE) ) r_target_fsm = T_READ_BLOCK; // get write data value for both 32 bits and 64 bits data width if( (vci_param::B == 8) and (p_vci_target.be.read() == 0xF0) ) r_tdata = (uint32_t)(p_vci_target.wdata.read()>>32); else r_tdata = p_vci_target.wdata.read(); } break; } //////////////////// case T_WRITE_BUFFER: { if (p_vci_target.rspack.read() ) { #if DEBUG_BDEV std::cout << " value = " << r_tdata.read() << std::endl; #endif r_buf_address = (uint64_t)r_tdata.read(); r_target_fsm = T_IDLE; } break; } //////////////////////// case T_WRITE_BUFFER_EXT: { if (p_vci_target.rspack.read() ) { #if DEBUG_BDEV std::cout << " value = " << r_tdata.read() << std::endl; #endif r_buf_address = r_buf_address.read() + (((uint64_t)r_tdata.read())<<32); r_target_fsm = T_IDLE; } break; } /////////////////// case T_WRITE_COUNT: { if (p_vci_target.rspack.read() ) { #if DEBUG_BDEV std::cout << " value = " << r_tdata.read() << std::endl; #endif r_nblocks = (uint32_t)r_tdata.read(); r_target_fsm = T_IDLE; } break; } ///////////////// case T_WRITE_LBA: { if (p_vci_target.rspack.read() ) { #if DEBUG_BDEV std::cout << " value = " << r_tdata.read() << std::endl; #endif r_lba = (uint32_t)r_tdata.read(); r_target_fsm = T_IDLE; } break; } //////////////// case T_WRITE_OP: { if ( p_vci_target.rspack.read() ) { if ( ((uint32_t)r_tdata.read() == BLOCK_DEVICE_READ) and (r_initiator_fsm.read() == M_IDLE) ) { #if DEBUG_BDEV std::cout << " value = READ" << std::endl; #endif r_read = true; r_go = true; } else if ( ((uint32_t)r_tdata.read() == BLOCK_DEVICE_WRITE) and (r_initiator_fsm.read() == M_IDLE) ) { #if DEBUG_BDEV std::cout << " value = WRITE" << std::endl; #endif r_read = false; r_go = true; } else { #if DEBUG_BDEV std::cout << " value = SOFT RESET" << std::endl; #endif r_go = false; } r_target_fsm = T_IDLE; } break; } /////////////////// case T_WRITE_IRQEN: { if ( p_vci_target.rspack.read() ) { #if DEBUG_BDEV std::cout << " value = " << r_tdata.read() << std::endl; #endif r_target_fsm = T_IDLE; r_irq_enable = (r_tdata.read() != 0); } break; } /////////////////// case T_READ_BUFFER: case T_READ_BUFFER_EXT: case T_READ_COUNT: case T_READ_LBA: case T_READ_IRQEN: case T_READ_SIZE: case T_READ_BLOCK: case T_READ_ERROR: case T_WRITE_ERROR: { if ( p_vci_target.rspack.read() ) r_target_fsm = T_IDLE; break; } /////////////////// case T_READ_STATUS: { if ( p_vci_target.rspack.read() ) { r_target_fsm = T_IDLE; if( (r_initiator_fsm == M_READ_SUCCESS ) || (r_initiator_fsm == M_READ_ERROR ) || (r_initiator_fsm == M_WRITE_SUCCESS) || (r_initiator_fsm == M_WRITE_ERROR ) ) r_go = false; } break; } } // end switch target fsm ////////////////////////////////////////////////////////////////////////////// // The initiator FSM executes a loop, transfering one block per iteration. // Each block is split in bursts, and the number of bursts depends // on the memory buffer alignment on a burst boundary: // - If buffer aligned, all burst have the same length (m_words_per burst) // and the number of bursts is (m_bursts_per_block). // - If buffer not aligned, the number of bursts is (m_bursts_per_block + 1) // and first and last burst are shorter, because all words in a burst // must be contained in a single cache line. // first burst => nwords = m_words_per_burst - offset // last burst => nwords = offset // other burst => nwords = m_words_per_burst ////////////////////////////////////////////////////////////////////////////// switch( r_initiator_fsm.read() ) { //////////// case M_IDLE: // check buffer alignment to compute the number of bursts { if ( r_go.read() ) { r_index = 0; r_block_count = 0; r_burst_count = 0; r_words_count = 0; r_latency_count = m_latency; // compute r_burst_offset (zero when buffer aligned) r_burst_offset = (uint32_t)((r_buf_address.read()>>2) % m_words_per_burst); // start tranfer if ( r_read.read() ) r_initiator_fsm = M_READ_BLOCK; else r_initiator_fsm = M_WRITE_BURST; } break; } ////////////////// case M_READ_BLOCK: // read one block from disk after waiting m_latency cycles { if ( r_latency_count.read() == 0 ) { r_latency_count = m_latency; ::lseek(m_fd, (r_lba + r_block_count)*m_words_per_block*4, SEEK_SET); if( ::read(m_fd, r_local_buffer, m_words_per_block*4) < 0 ) { r_initiator_fsm = M_READ_ERROR; } else { r_burst_count = 0; r_words_count = 0; r_initiator_fsm = M_READ_BURST; } //////////////////////////////////////////////////////////////////////////////////////// //std::cout << "***** Block content after read for lba " // << std::hex << r_lba.read() << " **************" << std::endl; //for ( size_t line=0 ; line<16 ; line++ ) //{ // for ( size_t word=0 ; word<8 ; word++ ) // { // std::cout << std::hex << r_local_buffer[line*8 + word] << " "; // } // std::cout << std::endl; //} //std::cout << "**********************************************************" << std::endl; //////////////////////////////////////////////////////////////////////////////////////// } else { r_latency_count = r_latency_count.read() - 1; } break; } ////////////////// case M_READ_BURST: // Compute the number of words and the number of flits in the burst // The number of flits can be smaller than the number of words // in case of 8 bytes flits... { uint32_t nwords; uint32_t offset = r_burst_offset.read(); if ( offset ) // buffer not aligned { if ( r_burst_count.read() == 0 ) nwords = m_words_per_burst - offset; else if ( r_burst_count.read() == m_bursts_per_block ) nwords = offset; else nwords = m_words_per_burst; } else // buffer aligned { nwords = m_words_per_burst; } r_burst_nwords = nwords; r_initiator_fsm = M_READ_CMD; break; } //////////////// case M_READ_CMD: // Send a multi-flits VCI WRITE command { if ( p_vci_initiator.cmdack.read() ) { uint32_t nwords = r_burst_nwords.read() - r_words_count.read(); if ( vci_param::B == 4 ) // one word per flit { if ( nwords <= 1 ) // last flit { r_initiator_fsm = M_READ_RSP; r_words_count = 0; } else // not the last flit { r_words_count = r_words_count.read() + 1; } // compute next word address and next local buffer index r_buf_address = r_buf_address.read() + 4; r_index = r_index.read() + 1; } else // 2 words per flit { if ( nwords <= 2 ) // last flit { r_initiator_fsm = M_READ_RSP; r_words_count = 0; } else // not the last flit { r_words_count = r_words_count.read() + 2; } // compute next word address and next local buffer index if ( nwords == 1 ) { r_buf_address = r_buf_address.read() + 4; r_index = r_index.read() + 1; } else { r_buf_address = r_buf_address.read() + 8; r_index = r_index.read() + 2; } } } break; } //////////////// case M_READ_RSP: // Wait a single flit VCI WRITE response { if ( p_vci_initiator.rspval.read() ) { bool aligned = (r_burst_offset.read() == 0); if ( (p_vci_initiator.rerror.read()&0x1) != 0 ) { r_initiator_fsm = M_READ_ERROR; } else if ( (not aligned and (r_burst_count.read() == m_bursts_per_block)) or (aligned and (r_burst_count.read() == (m_bursts_per_block-1))) ) { if ( r_block_count.read() == (r_nblocks.read()-1) ) // last burst of last block { r_initiator_fsm = M_READ_SUCCESS; } else // last burst not last block { r_index = 0; r_burst_count = 0; r_block_count = r_block_count.read() + 1; r_initiator_fsm = M_READ_BLOCK; } } else // not the last burst { r_burst_count = r_burst_count.read() + 1; r_initiator_fsm = M_READ_BURST; } } break; } /////////////////// case M_READ_SUCCESS: case M_READ_ERROR: { if( !r_go ) r_initiator_fsm = M_IDLE; break; } /////////////////// case M_WRITE_BURST: // Compute the number of words in the burst { uint32_t nwords; uint32_t offset = r_burst_offset.read(); if ( offset ) // buffer not aligned { if ( r_burst_count.read() == 0 ) nwords = m_words_per_burst - offset; else if ( r_burst_count.read() == m_bursts_per_block ) nwords = offset; else nwords = m_words_per_burst; } else // buffer aligned { nwords = m_words_per_burst; } r_burst_nwords = nwords; r_initiator_fsm = M_WRITE_CMD; break; } ///////////////// case M_WRITE_CMD: // This is actually a single flit VCI READ command { if ( p_vci_initiator.cmdack.read() ) r_initiator_fsm = M_WRITE_RSP; break; } ///////////////// case M_WRITE_RSP: // This is actually a multi-words VCI READ response { if ( p_vci_initiator.rspval.read() ) { bool aligned = (r_burst_offset.read() == 0); if ( (vci_param::B == 8) and (r_burst_nwords.read() > 1) ) { r_local_buffer[r_index.read()] = (uint32_t)p_vci_initiator.rdata.read(); r_local_buffer[r_index.read()+1] = (uint32_t)(p_vci_initiator.rdata.read()>>32); r_index = r_index.read() + 2; } else { r_local_buffer[r_index.read()] = (uint32_t)p_vci_initiator.rdata.read(); r_index = r_index.read() + 1; } if ( p_vci_initiator.reop.read() ) // last flit of the burst { r_words_count = 0; r_buf_address = r_buf_address.read() + (r_burst_nwords.read()<<2); if( (p_vci_initiator.rerror.read()&0x1) != 0 ) { r_initiator_fsm = M_WRITE_ERROR; } else if ( (not aligned and (r_burst_count.read() == m_bursts_per_block)) or (aligned and (r_burst_count.read() == (m_bursts_per_block-1))) ) // last burst { r_initiator_fsm = M_WRITE_BLOCK; } else // not the last burst { r_burst_count = r_burst_count.read() + 1; r_initiator_fsm = M_WRITE_BURST; } } else { r_words_count = r_words_count.read() + 1; } } break; } /////////////////// case M_WRITE_BLOCK: // write a block to disk after waiting m_latency cycles { if ( r_latency_count == 0 ) { //////////////////////////////////////////////////////////////////////////////////////// //std::cout << "***** Block content before write for lba " // << std::hex << r_lba.read() << " ***********" << std::endl; //for ( size_t line=0 ; line<16 ; line++ ) //{ // for ( size_t word=0 ; word<8 ; word++ ) // { // std::cout << std::hex << r_local_buffer[line*8 + word] << " "; // } // std::cout << std::endl; //} //std::cout << "**********************************************************" << std::endl; //////////////////////////////////////////////////////////////////////////////////////// r_latency_count = m_latency; ::lseek(m_fd, (r_lba + r_block_count)*m_words_per_block*4, SEEK_SET); if( ::write(m_fd, r_local_buffer, m_words_per_block*4) < 0 ) { r_initiator_fsm = M_WRITE_ERROR; } else if ( r_block_count.read() == r_nblocks.read() - 1 ) { r_initiator_fsm = M_WRITE_SUCCESS; } else { r_burst_count = 0; r_index = 0; r_block_count = r_block_count.read() + 1; r_initiator_fsm = M_WRITE_BURST; } } else { r_latency_count = r_latency_count - 1; } break; } ///////////////////// case M_WRITE_SUCCESS: case M_WRITE_ERROR: { if( !r_go ) r_initiator_fsm = M_IDLE; break; } } // end switch r_initiator_fsm } // end transition ////////////////////// tmpl(void)::genMoore() { // p_vci_target port p_vci_target.rsrcid = (sc_dt::sc_uint)r_srcid.read(); p_vci_target.rtrdid = (sc_dt::sc_uint)r_trdid.read(); p_vci_target.rpktid = (sc_dt::sc_uint)r_pktid.read(); p_vci_target.reop = true; switch(r_target_fsm) { case T_IDLE: p_vci_target.cmdack = true; p_vci_target.rspval = false; p_vci_target.rdata = 0; break; case T_READ_STATUS: p_vci_target.cmdack = false; p_vci_target.rspval = true; if (r_initiator_fsm == M_IDLE) p_vci_target.rdata = BLOCK_DEVICE_IDLE; else if(r_initiator_fsm == M_READ_SUCCESS) p_vci_target.rdata = BLOCK_DEVICE_READ_SUCCESS; else if(r_initiator_fsm == M_WRITE_SUCCESS) p_vci_target.rdata = BLOCK_DEVICE_WRITE_SUCCESS; else if(r_initiator_fsm == M_READ_ERROR) p_vci_target.rdata = BLOCK_DEVICE_READ_ERROR; else if(r_initiator_fsm == M_WRITE_ERROR) p_vci_target.rdata = BLOCK_DEVICE_WRITE_ERROR; else p_vci_target.rdata = BLOCK_DEVICE_BUSY; p_vci_target.rerror = VCI_READ_OK; break; case T_READ_BUFFER: p_vci_target.cmdack = false; p_vci_target.rspval = true; p_vci_target.rdata = (uint32_t)r_buf_address.read(); p_vci_target.rerror = VCI_READ_OK; break; case T_READ_BUFFER_EXT: p_vci_target.cmdack = false; p_vci_target.rspval = true; p_vci_target.rdata = (uint32_t)(r_buf_address.read()>>32); p_vci_target.rerror = VCI_READ_OK; break; case T_READ_COUNT: p_vci_target.cmdack = false; p_vci_target.rspval = true; p_vci_target.rdata = r_nblocks.read(); p_vci_target.rerror = VCI_READ_OK; break; case T_READ_LBA: p_vci_target.cmdack = false; p_vci_target.rspval = true; p_vci_target.rdata = r_lba.read(); p_vci_target.rerror = VCI_READ_OK; break; case T_READ_IRQEN: p_vci_target.cmdack = false; p_vci_target.rspval = true; p_vci_target.rdata = r_irq_enable.read(); p_vci_target.rerror = VCI_READ_OK; break; case T_READ_SIZE: p_vci_target.cmdack = false; p_vci_target.rspval = true; p_vci_target.rdata = m_device_size; p_vci_target.rerror = VCI_READ_OK; break; case T_READ_BLOCK: p_vci_target.cmdack = false; p_vci_target.rspval = true; p_vci_target.rdata = m_words_per_block*4; p_vci_target.rerror = VCI_READ_OK; break; case T_READ_ERROR: p_vci_target.cmdack = false; p_vci_target.rspval = true; p_vci_target.rdata = 0; p_vci_target.rerror = VCI_READ_ERROR; break; case T_WRITE_ERROR: p_vci_target.cmdack = false; p_vci_target.rspval = true; p_vci_target.rdata = 0; p_vci_target.rerror = VCI_WRITE_ERROR; break; default: p_vci_target.cmdack = false; p_vci_target.rspval = true; p_vci_target.rdata = 0; p_vci_target.rerror = VCI_WRITE_OK; break; } // end switch target fsm // p_vci_initiator port p_vci_initiator.srcid = (sc_dt::sc_uint)m_srcid; p_vci_initiator.trdid = 0; p_vci_initiator.contig = true; p_vci_initiator.cons = false; p_vci_initiator.wrap = false; p_vci_initiator.cfixed = false; p_vci_initiator.clen = 0; switch (r_initiator_fsm) { case M_WRITE_CMD: // It is actually a single flit VCI read command p_vci_initiator.rspack = false; p_vci_initiator.cmdval = true; p_vci_initiator.address = (sc_dt::sc_uint)r_buf_address.read(); p_vci_initiator.cmd = vci_param::CMD_READ; p_vci_initiator.pktid = TYPE_READ_DATA_UNC; p_vci_initiator.wdata = 0; p_vci_initiator.be = 0; p_vci_initiator.plen = (sc_dt::sc_uint)(r_burst_nwords.read()<<2); p_vci_initiator.eop = true; break; case M_READ_CMD: // It is actually a multi-words VCI WRITE command p_vci_initiator.rspack = false; p_vci_initiator.cmdval = true; p_vci_initiator.address = (sc_dt::sc_uint)r_buf_address.read(); p_vci_initiator.cmd = vci_param::CMD_WRITE; p_vci_initiator.pktid = TYPE_WRITE; p_vci_initiator.plen = (sc_dt::sc_uint)(r_burst_nwords.read()<<2); if ( (vci_param::B == 8) and ((r_burst_nwords.read() - r_words_count.read()) > 1) ) { p_vci_initiator.wdata = ((uint64_t)r_local_buffer[r_index.read() ]) + (((uint64_t)r_local_buffer[r_index.read()+1]) << 32); p_vci_initiator.be = 0xFF; p_vci_initiator.eop = ( (r_burst_nwords.read() - r_words_count.read()) <= 2 ); } else { p_vci_initiator.wdata = r_local_buffer[r_index.read()]; p_vci_initiator.be = 0xF; p_vci_initiator.eop = ( r_words_count.read() == (r_burst_nwords.read() - 1) ); } break; case M_READ_RSP: case M_WRITE_RSP: p_vci_initiator.rspack = true; p_vci_initiator.cmdval = false; break; default: p_vci_initiator.rspack = false; p_vci_initiator.cmdval = false; break; } // IRQ signal if ( ((r_initiator_fsm == M_READ_SUCCESS) || (r_initiator_fsm == M_WRITE_SUCCESS) || (r_initiator_fsm == M_READ_ERROR) || (r_initiator_fsm == M_WRITE_ERROR) ) && r_irq_enable.read() ) { #if DEBUG_BDEV if (p_irq != true) std::cout << " " << std::endl; #endif p_irq = true; } else { p_irq = false; } } // end GenMoore() ////////////////////////////////////////////////////////////////////////////// tmpl(/**/)::VciBlockDeviceTsar( sc_core::sc_module_name name, const soclib::common::MappingTable &mt, const soclib::common::IntTab &srcid, const soclib::common::IntTab &tgtid, const std::string &filename, const uint32_t block_size, const uint32_t burst_size, const uint32_t latency) : caba::BaseModule(name), m_seglist(mt.getSegmentList(tgtid)), m_srcid(mt.indexForId(srcid)), m_words_per_block(block_size/4), m_words_per_burst(burst_size/4), m_bursts_per_block(block_size/burst_size), m_latency(latency), p_clk("p_clk"), p_resetn("p_resetn"), p_vci_initiator("p_vci_initiator"), p_vci_target("p_vci_target"), p_irq("p_irq") { std::cout << " - Building VciBlockDeviceTsar " << name << std::endl; SC_METHOD(transition); dont_initialize(); sensitive << p_clk.pos(); SC_METHOD(genMoore); dont_initialize(); sensitive << p_clk.neg(); size_t nbsegs = 0; std::list::iterator seg; for ( seg = m_seglist.begin() ; seg != m_seglist.end() ; seg++ ) { nbsegs++; if ( (seg->baseAddress() & 0x0000003F) != 0 ) { std::cout << "Error in component VciBlockDeviceTsar : " << name << "The base address of segment " << seg->name() << " must be multiple of 64 bytes" << std::endl; exit(1); } if ( seg->size() < 64 ) { std::cout << "Error in component VciBlockDeviceTsar : " << name << "The size of segment " << seg->name() << " cannot be smaller than 64 bytes" << std::endl; exit(1); } std::cout << " => segment " << seg->name() << " / base = " << std::hex << seg->baseAddress() << " / size = " << seg->size() << std::endl; } if( nbsegs == 0 ) { std::cout << "Error in component VciBlockDeviceTsar : " << name << " No segment allocated" << std::endl; exit(1); } if( (block_size != 128) && (block_size != 256) && (block_size != 512) && (block_size != 1024) && (block_size != 2048) && (block_size != 4096) ) { std::cout << "Error in component VciBlockDeviceTsar : " << name << " The block size must be 128, 256, 512, 1024, 2048 or 4096 bytes" << std::endl; exit(1); } if( (burst_size != 8 ) && (burst_size != 16) && (burst_size != 32) && (burst_size != 64) ) { std::cout << "Error in component VciBlockDeviceTsar : " << name << " The burst size must be 8, 16, 32 or 64 bytes" << std::endl; exit(1); } if ( (vci_param::B != 4) and (vci_param::B != 8) ) { std::cout << "Error in component VciBlockDeviceTsar : " << name << " The VCI data fields must have 32 bits or 64 bits" << std::endl; exit(1); } m_fd = ::open(filename.c_str(), O_RDWR); if ( m_fd < 0 ) { std::cout << "Error in component VciBlockDeviceTsar : " << name << " Unable to open file " << filename << std::endl; exit(1); } m_device_size = lseek(m_fd, 0, SEEK_END) / block_size; if ( m_device_size > ((uint64_t)1<