/* -*- 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, SoC * Alain Greiner , 2008 * * Maintainers: alain eric.guthmuller@polytechnique.edu nipo */ ///////////////////////////////////////////////////////////////////////////// // History // - 25/04/2008 // The existing vci_xcache component has been extended to include // a VCI target port to support a directory based coherence protocol. // Two types of packets can be send by the L2 cache to the L1 cache // * INVALIDATE packets : length = 1 // * UPDATE packets : length = n + 2 // The CLEANUP packets are sent by the L1 cache to the L2 cache, // to signal a replaced cache line. // - 12/08/2008 // The vci_cc_xcache_wrapper component instanciates directly the processsor // iss, in order to supress the processor/cache interface. // According to the VCI advanced specification, this component uses one // word VCI CMD packets for MISS transactions, and accept one word VCI RSP // packets for Write burst transactions. // The write buffer has been modified to use the WriteBuffer object. // A VCI write burst is constructed when two conditions are satisfied : // The processor make strictly successive write requests, and they are // in the same cache line. The write buffer performs re-ordering, to // respect the contiguous addresses VCI constraint. In case of several // WRITE_WORD requests in the same word, only the last request is conserved. // In case of several WRITE_HALF or WRITE_WORD requests in the same word, // the requests are merged in the same word. In case of uncached write // requests, each request is transmited as a single VCI transaction. // Both the data & instruction caches can be flushed in one single cycle. /////////////////////////////////////////////////////////////////////////////// #include #include "arithmetics.h" #include "size.h" #include "../include/vci_cc_xcache_wrapper_v4.h" namespace soclib { namespace caba { namespace { // =====[ DEBUG ]==================================== #define ASSERT_VERBOSE #define ASSERT_NCYCLES m_cpt_total_cycles #include "debug.h" #if CC_XCACHE_WRAPPER_DEBUG # define PRINTF(msg...) PRINTF_COND(m_cpt_total_cycles>=CC_XCACHE_WRAPPER_DEBUG_CYCLE_MIN,msg) #else # define PRINTF(msg...) #endif ///////////////////////////////////////////////////////////////////// // Management of address stocked in icache/dcache/mwbuf in case // of multiple bank implementation ///////////////////////////////////////////////////////////////////// // =====[ MULTI_CACHE ]============================== #if (CC_XCACHE_WRAPPER_MULTI_CACHE==1) # define get_num_icache( addr,num_cpu) get_num_cache (addr) # define get_num_icache_only(addr,num_cpu) get_num_cache_only(addr) # define set_num_icache( addr,num_cache) set_num_cache (addr,num_cache) # define set_num_icache_only(addr,num_cache) set_num_cache_only(addr,num_cache) #elif (CC_XCACHE_WRAPPER_MULTI_CACHE==2) # define get_num_icache( addr,num_cpu) num_cpu # define get_num_icache_only(addr,num_cpu) num_cpu # define set_num_icache( addr,num_cache) do {} while (0) # define set_num_icache_only(addr,num_cache) addr #else #error "Invalid value to CC_XCACHE_WRAPPER_MULTI_CACHE" #endif # define get_num_dcache( addr) get_num_cache (addr) # define get_num_dcache_only(addr) get_num_cache_only(addr) # define set_num_dcache( addr,num_cache) set_num_cache (addr,num_cache) # define set_num_dcache_only(addr,num_cache) set_num_cache_only(addr,num_cache) const char *dcache_fsm_state_str[] = { "DCACHE_IDLE", "DCACHE_WRITE_UPDT", "DCACHE_MISS_VICTIM", "DCACHE_MISS_WAIT", "DCACHE_MISS_UPDT", "DCACHE_UNC_WAIT", "DCACHE_SC_WAIT", "DCACHE_INVAL", "DCACHE_SYNC", "DCACHE_ERROR", "DCACHE_CC_CHECK", "DCACHE_CC_INVAL", "DCACHE_CC_CLEANUP", }; const char *icache_fsm_state_str[] = { "ICACHE_IDLE", "ICACHE_MISS_VICTIM", "ICACHE_MISS_WAIT", "ICACHE_MISS_UPDT", "ICACHE_UNC_WAIT", "ICACHE_ERROR", "ICACHE_CC_CLEANUP", "ICACHE_CC_CHECK", "ICACHE_CC_INVAL", }; const char *cmd_fsm_state_str[] = { "CMD_IDLE", "CMD_INS_MISS", "CMD_INS_UNC", "CMD_DATA_MISS", "CMD_DATA_UNC", "CMD_DATA_WRITE", "CMD_DATA_SC", }; const char *rsp_fsm_state_str[] = { "RSP_IDLE", "RSP_INS_MISS", "RSP_INS_UNC", "RSP_DATA_MISS", "RSP_DATA_UNC", "RSP_DATA_WRITE", "RSP_DATA_SC", }; const char *tgt_fsm_state_str[] = { "TGT_IDLE", "TGT_UPDT_WORD", "TGT_UPDT_DATA", "TGT_REQ_BROADCAST", "TGT_REQ_ICACHE", "TGT_REQ_DCACHE", "TGT_RSP_BROADCAST", "TGT_RSP_ICACHE", "TGT_RSP_DCACHE", }; const char *cleanup_fsm_state_str[] = { "CLEANUP_IDLE", "CLEANUP_REQ", "CLEANUP_RSP_DCACHE", "CLEANUP_RSP_ICACHE", }; } typedef long long unsigned int blob_t; #define tmpl(...) template __VA_ARGS__ VciCcXCacheWrapperV4 using soclib::common::uint32_log2; ///////////////////////////////// tmpl(/**/)::VciCcXCacheWrapperV4( ///////////////////////////////// sc_module_name name, int proc_id, const soclib::common::MappingTable &mtp, const soclib::common::MappingTable &mtc, const soclib::common::IntTab &initiator_index_rw, const soclib::common::IntTab &initiator_index_c, const soclib::common::IntTab &target_index, size_t nb_cpu, size_t nb_dcache, size_t icache_ways, size_t icache_sets, size_t icache_words, size_t dcache_ways, size_t dcache_sets, size_t dcache_words, size_t wbuf_nwords, size_t wbuf_nlines ) : soclib::caba::BaseModule(name), p_clk ("clk"), p_resetn ("resetn"), p_vci_ini_rw("vci_ini_rw"), p_vci_ini_c ("vci_ini_c"), p_vci_tgt ("vci_tgt"), m_cacheability_table(mtp.getCacheabilityTable()), m_segment(mtc.getSegment(target_index)), m_srcid_rw(mtp.indexForId(initiator_index_rw)), m_srcid_c(mtc.indexForId(initiator_index_c)), m_nb_cpu(nb_cpu), #if (CC_XCACHE_WRAPPER_MULTI_CACHE==1) m_nb_icache(nb_dcache), #elif (CC_XCACHE_WRAPPER_MULTI_CACHE==2) m_nb_icache(m_nb_cpu), #endif m_nb_dcache(nb_dcache), m_nb_cache((m_nb_dcache>m_nb_icache)?m_nb_dcache:m_nb_icache), m_dcache_ways(dcache_ways), m_dcache_words(dcache_words), m_dcache_words_shift(uint32_log2(dcache_words)+uint32_log2(sizeof(data_t))), m_dcache_yzmask((~0)< 2) and ((1<<(vci_param::T-1)) >= (wbuf_nlines/m_nb_dcache)), "Need more TRDID bits."); ASSERT(uint32_log2(nb_dcache) <= (1< 0), "nb cpu must be a multiple of nb cache."); ASSERT(IS_POW_OF_2(m_icache_ways) and (m_nb_icache <= m_icache_ways), "nb icache ways must be a multiple of nb cache."); ASSERT(IS_POW_OF_2(m_dcache_ways) and (m_nb_dcache <= m_dcache_ways), "nb dcache ways must be a multiple of nb cache."); ASSERT(icache_words == dcache_words, "icache_words must be equal at dcache_words."); ASSERT(IS_POW_OF_2(wbuf_nlines) and (m_nb_dcache <= wbuf_nlines), "wbuf_nlines must be a multiple of nb cache."); // FIXME : s'adapter à la taille des requêtes XTN_READ/XTN_WRITE, car le type est fournit dans le champs l'adresse ASSERT((m_nb_dcache == 1) or (dcache_words >= 16), "When multi cache is activated, need 4 bits (16 word) to the cache set ."); if (m_nb_cpu > 1) ASSERT(CC_XCACHE_MULTI_CPU!=0, "Macro CC_XCACHE_MULTI_CPU in wbuf must be set at 1."); p_irq = new sc_in * [m_nb_cpu]; for (uint32_t num_cpu=0; num_cpu [iss_t::n_irq]; m_iss = new iss_t * [m_nb_cpu]; for (uint32_t num_cpu=0; num_cpuname() << "_" << num_cpu; m_iss[num_cpu] = new iss_t (iss_name.str().c_str(), proc_id+num_cpu); } r_icache_lock = new sc_signal[m_nb_icache]; r_dcache_lock = new sc_signal[m_nb_dcache]; r_dcache_sync = new sc_signal [m_nb_dcache]; r_icache_fsm = new sc_signal [m_nb_icache]; r_icache_fsm_save = new sc_signal [m_nb_icache]; r_icache_addr_save = new sc_signal [m_nb_icache]; r_icache_miss_req = new sc_signal [m_nb_icache]; r_icache_miss_way = new sc_signal [m_nb_icache]; r_icache_miss_set = new sc_signal [m_nb_icache]; r_icache_unc_req = new sc_signal [m_nb_icache]; r_icache_cleanup_req = new sc_signal [m_nb_icache]; r_icache_cleanup_line = new sc_signal [m_nb_icache]; r_icache_inval_rsp = new sc_signal [m_nb_icache]; r_icache_update_addr = new sc_signal [m_nb_icache]; r_icache_buf_unc_valid = new sc_signal [m_nb_icache]; r_dcache_fsm = new sc_signal [m_nb_dcache]; r_dcache_fsm_save = new sc_signal [m_nb_dcache]; r_dcache_addr_save = new sc_signal [m_nb_dcache]; r_dcache_wdata_save = new sc_signal [m_nb_dcache]; r_dcache_rdata_save = new sc_signal [m_nb_dcache]; r_dcache_type_save = new sc_signal [m_nb_dcache]; r_dcache_be_save = new sc_signal [m_nb_dcache]; r_dcache_cached_save = new sc_signal [m_nb_dcache]; r_dcache_num_cpu_save = new sc_signal[m_nb_dcache]; r_dcache_cleanup_req = new sc_signal [m_nb_dcache]; r_dcache_cleanup_line = new sc_signal [m_nb_dcache]; r_dcache_miss_req = new sc_signal [m_nb_dcache]; r_dcache_miss_way = new sc_signal [m_nb_dcache]; r_dcache_miss_set = new sc_signal [m_nb_dcache]; r_dcache_unc_req = new sc_signal [m_nb_dcache]; r_dcache_sc_req = new sc_signal [m_nb_dcache]; r_dcache_inval_rsp = new sc_signal [m_nb_dcache]; r_dcache_update_addr = new sc_signal [m_nb_dcache]; r_dcache_previous_unc = new sc_signal [m_nb_dcache]; r_dcache_ll_data = new sc_signal * [m_nb_dcache]; r_dcache_ll_addr = new sc_signal * [m_nb_dcache]; r_dcache_ll_valid = new sc_signal * [m_nb_dcache]; for (uint32_t num_cache=0; num_cache [m_nb_cpu]; r_dcache_ll_addr [num_cache] = new sc_signal [m_nb_cpu]; r_dcache_ll_valid [num_cache] = new sc_signal [m_nb_cpu]; } r_tgt_icache_req = new sc_signal [m_nb_icache]; r_tgt_icache_rsp = new sc_signal [m_nb_icache]; r_tgt_dcache_req = new sc_signal [m_nb_dcache]; r_tgt_dcache_rsp = new sc_signal [m_nb_dcache]; r_tgt_buf = new data_t [m_cache_words]; r_tgt_be = new be_t [m_cache_words]; r_vci_rsp_ins_error = new sc_signal [m_nb_icache]; r_vci_rsp_data_error = new sc_signal [m_nb_dcache]; ireq = new typename iss_t::InstructionRequest [m_nb_icache]; irsp = new typename iss_t::InstructionResponse [m_nb_icache]; ireq_cached = new bool [m_nb_icache]; ireq_num_cpu = new uint32_t [m_nb_dcache]; dreq = new typename iss_t::DataRequest [m_nb_dcache]; drsp = new typename iss_t::DataResponse [m_nb_dcache]; dreq_cached = new bool [m_nb_dcache]; dreq_num_cpu = new uint32_t [m_nb_dcache]; m_cpt_icache_access = new uint32_t [m_nb_icache]; m_cpt_dcache_access = new uint32_t [m_nb_dcache]; m_cpt_icache_miss_victim_wait = new uint32_t [m_nb_icache]; m_cpt_dcache_miss_victim_wait = new uint32_t [m_nb_dcache]; m_cpt_dcache_store_after_store = new uint32_t [m_nb_dcache]; m_cpt_dcache_hit_after_miss_read = new uint32_t [m_nb_dcache]; m_cpt_dcache_hit_after_miss_write = new uint32_t [m_nb_dcache]; m_cpt_fsm_dcache = new uint32_t * [m_nb_dcache]; m_cpt_fsm_icache = new uint32_t * [m_nb_icache]; for (uint32_t num_cache=0; num_cache * [m_nb_icache]; r_dcache = new GenericCache * [m_nb_dcache]; r_wbuf = new MultiWriteBuffer * [m_nb_dcache]; for (uint32_t num_cache=0; num_cache ("icache", _icache_ways, _icache_sets, _icache_words); } for (uint32_t num_cache=0; num_cache ("dcache", _dcache_ways, _dcache_sets, _dcache_words); r_wbuf [num_cache] = new MultiWriteBuffer ("r_wbuf", _wbuf_nwords, _wbuf_nlines, _dcache_words); } m_num_cache_LSB_mask = 0; for (uint32_t i=0; isetCacheInfo(cache_info); #if CC_XCACHE_WRAPPER_STOP_SIMULATION m_stop_simulation = false; m_stop_simulation_nb_frz_cycles = new uint32_t [m_nb_cpu]; for (uint32_t num_cpu=0; num_cpuprintStatistics(); } //////////////////////////////////// tmpl(void)::print_trace(size_t mode) //////////////////////////////////// { // b0 : write buffer print trace // b1 : write buffer verbose // b2 : dcache print trace // b3 : icache print trace typename iss_t::InstructionRequest ireq; typename iss_t::DataRequest dreq; std::cout << std::dec << "Proc \"" << name() << "\"" << std::endl; for (uint32_t num_cpu=0; num_cpugetRequests( ireq, dreq ); std::cout << ireq << std::endl; std::cout << dreq << std::endl; } for (uint32_t num_cache=0; num_cacheprintTrace((mode>>1)&1); } if(mode & 0x4) { std::cout << " Data cache" << std::endl; for (uint32_t num_cache=0; num_cacheprintTrace(); } if(mode & 0x8) { std::cout << " Instruction cache" << std::endl; for (uint32_t num_cache=0; num_cacheprintTrace(); } } ////////////////////////// tmpl(void)::transition() ////////////////////////// { ///////////////////////////////////////////////////////////////////// // Reset ///////////////////////////////////////////////////////////////////// if ( not p_resetn.read() ) { r_cpu_prior = 0; for (uint32_t num_cpu=0; num_cpureset(); // FSM states for (uint32_t num_cache=0; num_cachereset(); // synchronisation flip-flops from ICACHE & DCACHE FSMs to VCI FSMs r_icache_miss_req [num_cache] = false; r_icache_unc_req [num_cache] = false; r_icache_cleanup_req [num_cache] = false; // internal messages in DCACHE et ICACHE FSMs r_icache_inval_rsp [num_cache] = false; // error signals from the VCI RSP FSM to the ICACHE or DCACHE FSMs r_icache_buf_unc_valid [num_cache] = false; // synchronisation flip-flops from TGT FSM to ICACHE & DCACHE FSMs r_tgt_icache_req [num_cache] = false; r_tgt_icache_rsp [num_cache] = false; r_vci_rsp_ins_error [num_cache] = false; }// end for num_cache for (uint32_t num_cache=0; num_cachereset(); r_dcache[num_cache]->reset(); // synchronisation flip-flops from ICACHE & DCACHE FSMs to VCI FSMs r_dcache_miss_req [num_cache] = false; r_dcache_unc_req [num_cache] = false; r_dcache_sc_req [num_cache] = false; r_dcache_cleanup_req [num_cache] = false; r_dcache_previous_unc[num_cache] = false; // internal messages in DCACHE et ICACHE FSMs r_dcache_inval_rsp [num_cache] = false; // error signals from the VCI RSP FSM to the ICACHE or DCACHE FSMs for (uint32_t num_cpu=0; num_cpu=CC_XCACHE_WRAPPER_DEBUG_CYCLE_MIN) r_wbuf[num_cache]->printTrace(1); #endif // VHDL debug // #if MWBUF_VHDL_TESTBENCH // printf("\nMWBUF[%d] - Time = %d\n\n",num_cache,(uint32_t)m_cpt_total_cycles); // r_wbuf[num_cache]->printTrace(1); // #endif } #if CC_XCACHE_WRAPPER_DEBUG if (m_cpt_total_cycles>=CC_XCACHE_WRAPPER_DEBUG_CYCLE_MIN) { PRINTF(" * rsp_fifo_icache %s\n",name().c_str()); r_vci_rsp_fifo_icache_data .print(); r_vci_rsp_fifo_icache_num_cache.print(); PRINTF(" * rsp_fifo_dcache %s\n",name().c_str()); r_vci_rsp_fifo_dcache_data .print(); r_vci_rsp_fifo_dcache_num_cache.print(); } #endif ///////////////////////////////////////////////////////////////////// // Statistics // Count state fsm activity ///////////////////////////////////////////////////////////////////// for (uint32_t num_cache=0; num_cache Request\n"); addr_40 address = p_vci_tgt.address.read(); if ( p_vci_tgt.cmd.read() != vci_param::CMD_WRITE) { std::cout << "error in component VCI_CC_XCACHE_WRAPPER " << name() << std::endl; std::cout << "coherence request is not a write" << std::endl; std::cout << "address = " << std::hex << address << std::dec << std::endl; std::cout << "srcid = " << p_vci_tgt.srcid.read() << std::endl; exit(0); } // multi-update or multi-invalidate for data type if ( ((address&0x3) != 0x3) and (not m_segment.contains(address)) ) { std::cout << "error in component VCI_CC_XCACHE_WRAPPER " << name() << std::endl; std::cout << "out of segment coherence request" << std::endl; std::cout << "address = " << std::hex << address << std::dec << std::endl; std::cout << "srcid = " << p_vci_tgt.srcid.read() << std::endl; exit(0); } addr_40 tgt_addr = ((((addr_40)p_vci_tgt.be.read() & 0x3) << 32) | ((addr_40) p_vci_tgt.wdata.read())) << (addr_40)m_dcache_words_shift; // * m_dcache_words * 4; addr_40 tgt_iaddr = tgt_addr; addr_40 tgt_daddr = tgt_addr; PRINTF(" * srcid : %d\n",(uint32_t)p_vci_tgt.srcid.read()); PRINTF(" * trdid : %d\n",(uint32_t)p_vci_tgt.trdid.read()); PRINTF(" * pktid : %d\n",(uint32_t)p_vci_tgt.pktid.read()); PRINTF(" * address (before) : %llx\n",(blob_t)tgt_iaddr); r_tgt_srcid = p_vci_tgt.srcid.read(); r_tgt_trdid = p_vci_tgt.trdid.read(); r_tgt_pktid = p_vci_tgt.pktid.read(); // r_tgt_plen = p_vci_tgt.plen.read(); // BROADCAST if ( (address&0x3) == 0x3 ) // broadcast invalidate for data or instruction type { if ( not p_vci_tgt.eop.read() ) { std::cout << "error in component VCI_CC_XCACHE_WRAPPER " << name() << std::endl; std::cout << "the BROADCAST INVALIDATE command length must be one word" << std::endl; exit(0); } r_tgt_update = false; // r_tgt_brdcast= true; r_vci_tgt_fsm = TGT_REQ_BROADCAST; uint32_t tgt_num_cache; tgt_num_cache = get_num_icache(tgt_iaddr,0); // none effect (else CC_XCACHE_WRAPPER_MULTI_CACHE==1) tgt_num_cache = get_num_dcache(tgt_daddr); r_tgt_num_cache = tgt_num_cache; PRINTF(" * REQ_BROADCAST\n"); PRINTF(" * num_cache (data) : %d\n",tgt_num_cache); m_cpt_cc_inval_broadcast++ ; #if CC_XCACHE_WRAPPER_DEBUG_FILE_TRANSACTION if (generate_log_transaction_file_tgt) { log_transaction_file_tgt << "[" << m_cpt_total_cycles << "] " << "BROADCAST " << std::hex << " L " << std::setw(10) << (blob_t)tgt_addr << std::dec << " - " << tgt_num_cache << std::endl; } #endif //CC_XCACHE_WRAPPER_DEBUG_FILE_TRANSACTION } else // multi-update or multi-invalidate for data type { uint32_t cell = address - m_segment.baseAddress(); // addr_40 // r_tgt_brdcast = false; if (cell == 0) { // invalidate data if ( not p_vci_tgt.eop.read() ) { std::cout << "error in component VCI_CC_XCACHE_WRAPPER " << name() << std::endl; std::cout << "the MULTI-INVALIDATE command length must be one word" << std::endl; exit(0); } r_tgt_update = false; r_vci_tgt_fsm = TGT_REQ_DCACHE; uint32_t tgt_num_cache = get_num_dcache(tgt_daddr); // static partionnement r_tgt_num_cache = tgt_num_cache; PRINTF(" * REQ_DCACHE\n"); PRINTF(" * num_cache : %d\n",tgt_num_cache); m_cpt_cc_inval_dcache++ ; #if CC_XCACHE_WRAPPER_DEBUG_FILE_TRANSACTION if (generate_log_transaction_file_tgt) { log_transaction_file_tgt << "[" << m_cpt_total_cycles << "] " << "INVAL DATA " << std::hex << " L " << std::setw(10) << (blob_t)tgt_addr << std::dec << " - " << tgt_num_cache << std::endl; } #endif //CC_XCACHE_WRAPPER_DEBUG_FILE_TRANSACTION } else if (cell == 4) // invalidate instruction { if ( not p_vci_tgt.eop.read() ) { std::cout << "error in component VCI_CC_VCACHE_WRAPPER " << name() << std::endl; std::cout << "the MULTI-INVALIDATE command length must be one word" << std::endl; exit(0); } r_tgt_update = false; r_vci_tgt_fsm = TGT_REQ_ICACHE; uint32_t tgt_num_cpu = p_vci_tgt.pktid.read(); uint32_t tgt_num_cache = get_num_icache(tgt_iaddr,tgt_num_cpu); r_tgt_num_cache = tgt_num_cache; PRINTF(" * REQ_ICACHE\n"); PRINTF(" * num_cache : %d\n",tgt_num_cache); m_cpt_cc_inval_icache++ ; #if CC_XCACHE_WRAPPER_DEBUG_FILE_TRANSACTION if (generate_log_transaction_file_tgt) { log_transaction_file_tgt << "[" << m_cpt_total_cycles << "] " << "INVAL INS " << std::hex << " L " << std::setw(10) << (blob_t)tgt_addr << std::dec << " - " << tgt_num_cache << std::endl; } #endif //CC_XCACHE_WRAPPER_DEBUG_FILE_TRANSACTION } else if ( (cell == 8) or (cell==12) ) // update data or instruction { if ( p_vci_tgt.eop.read() ) { std::cout << "error in component VCI_CC_VCACHE_WRAPPER " << name() << std::endl; std::cout << "the MULTI-UPDATE command length must be N+2 words" << std::endl; exit(0); } if(cell == 8) { m_cpt_cc_update_dcache++; r_tgt_update_data = true; uint32_t tgt_num_cache = get_num_dcache(tgt_daddr); r_tgt_num_cache = tgt_num_cache; PRINTF(" * UPDT_WORD DATA\n"); PRINTF(" * num_cache : %d\n",tgt_num_cache); #if CC_XCACHE_WRAPPER_DEBUG_FILE_TRANSACTION if (generate_log_transaction_file_tgt) { log_transaction_file_tgt << "[" << m_cpt_total_cycles << "] " << "UPT DATA " << std::hex << " L " << std::setw(10) << (blob_t)tgt_addr << std::dec << " - " << tgt_num_cache << std::endl; } #endif //CC_XCACHE_WRAPPER_DEBUG_FILE_TRANSACTION } else { m_cpt_cc_update_icache++; r_tgt_update_data = false; uint32_t tgt_num_cpu = p_vci_tgt.pktid.read(); uint32_t tgt_num_cache = get_num_icache(tgt_iaddr,tgt_num_cpu); r_tgt_num_cache = tgt_num_cache; PRINTF(" * UPDT_WORD INSTRUCTION\n"); PRINTF(" * num_cache : %d\n",tgt_num_cache); #if CC_XCACHE_WRAPPER_DEBUG_FILE_TRANSACTION if (generate_log_transaction_file_tgt) { log_transaction_file_tgt << "[" << m_cpt_total_cycles << "] " << "UPT INS " << std::hex << " L " << std::setw(10) << (blob_t)tgt_addr << std::dec << " - " << tgt_num_cache << std::endl; } #endif //CC_XCACHE_WRAPPER_DEBUG_FILE_TRANSACTION } r_tgt_update = true; r_vci_tgt_fsm = TGT_UPDT_WORD; } } // end if address r_tgt_iaddr = tgt_iaddr; r_tgt_daddr = tgt_daddr; PRINTF(" * address (after) : i %llx, d %llx\n",(blob_t)tgt_iaddr,(blob_t)tgt_daddr); } // end if cmdval break; case TGT_UPDT_WORD: if (p_vci_tgt.cmdval.read()) { if ( p_vci_tgt.eop.read() ) { std::cout << "error in component VCI_CC_XCACHE_WRAPPER " << name() << std::endl; std::cout << "the MULTI-UPDATE command length must be N+2 words" << std::endl; exit(0); } for ( size_t i=0 ; i= m_cache_words ) { std::cout << "error in component VCI_CC_XCACHE_WRAPPER " << name() << std::endl; std::cout << "the reveived MULTI-UPDATE command length is wrong" << std::endl; exit(0); } r_tgt_buf[word] = p_vci_tgt.wdata.read(); r_tgt_be [word] = p_vci_tgt.be.read(); if (p_vci_tgt.be.read()) { if(r_tgt_update_data.read()) m_cpt_cc_update_dcache_word_useful++ ; else m_cpt_cc_update_icache_word_useful++ ; } r_tgt_word = word + 1; if (p_vci_tgt.eop.read()){ uint32_t word=0; for (; word dcache[%d] : %d - %d\n",(uint32_t)r_tgt_num_cache, (uint32_t)r_tgt_dcache_req[r_tgt_num_cache].read(),(uint32_t)r_tgt_dcache_rsp[r_tgt_num_cache].read()); for (uint32_t num_cache=0; num_cache icache[%d] : %d - %d\n",(uint32_t)num_cache, (uint32_t)r_tgt_icache_req[num_cache].read(),(uint32_t)r_tgt_icache_rsp[num_cache].read()); bool tgt_icache_req; #if (CC_XCACHE_WRAPPER_MULTI_CACHE==1) tgt_icache_req = r_tgt_icache_req[r_tgt_num_cache].read(); #elif (CC_XCACHE_WRAPPER_MULTI_CACHE==2) tgt_icache_req = false; for (uint32_t num_cache=0; num_cache icache[%d] : %d\n",(uint32_t)tgt_icache_rsp_num_cache, (uint32_t)r_tgt_icache_rsp[tgt_icache_rsp_num_cache].read()); if (r_tgt_icache_rsp[tgt_icache_rsp_num_cache].read()) break; } tgt_icache_rsp = (tgt_icache_rsp_num_cache icache_rsp [%d] : %d\n",tgt_icache_rsp_num_cache,(uint32_t) tgt_icache_rsp); PRINTF(" * dcache_rsp [%d] : %d\n",(uint32_t)r_tgt_num_cache,(uint32_t) r_tgt_dcache_rsp[r_tgt_num_cache]); if (tgt_icache_rsp or r_tgt_dcache_rsp[r_tgt_num_cache]) { // Have send one response if ( p_vci_tgt.rspack.read()) { // reset dcache if activated if (r_tgt_dcache_rsp[r_tgt_num_cache]) r_tgt_dcache_rsp[r_tgt_num_cache] = false; else // reset one icache r_tgt_icache_rsp[tgt_icache_rsp_num_cache] = false; } } // // one response // if ( not r_tgt_icache_rsp[r_tgt_num_cache] or not r_tgt_dcache_rsp[r_tgt_num_cache] ) // { // if ( p_vci_tgt.rspack.read() ) // { // r_vci_tgt_fsm = TGT_IDLE; // r_tgt_icache_rsp[r_tgt_num_cache] = false; // r_tgt_dcache_rsp[r_tgt_num_cache] = false; // } // } // // if data and instruction have the inval line, need two responses // if ( r_tgt_icache_rsp[r_tgt_num_cache] and r_tgt_dcache_rsp[r_tgt_num_cache] ) // { // if ( p_vci_tgt.rspack.read() ) // { // r_tgt_icache_rsp[r_tgt_num_cache] = false; // only reset one for respond the second time // } // } PRINTF(" * icache_rsp : %d\n",(uint32_t) r_tgt_icache_rsp[r_tgt_num_cache]); PRINTF(" * dcache_rsp[%d] : %d\n",(uint32_t)r_tgt_num_cache,(uint32_t)r_tgt_dcache_rsp[r_tgt_num_cache].read()); // if there is no need for a response if (not tgt_icache_rsp and not r_tgt_dcache_rsp[r_tgt_num_cache] ) { r_vci_tgt_fsm = TGT_IDLE; } } break; } //////////////////// case TGT_RSP_ICACHE: { bool transaction_rsp = (p_vci_tgt.rspack.read() or not r_tgt_icache_rsp[r_tgt_num_cache].read()) and not r_tgt_icache_req[r_tgt_num_cache].read(); PRINTF(" * RSP_ICACHE : transaction : %d ((%d or not %d) and not %d)\n",transaction_rsp ,(int)p_vci_tgt.rspack.read() ,(int)r_tgt_icache_rsp[r_tgt_num_cache].read() ,(int)r_tgt_icache_req[r_tgt_num_cache].read() ); if (transaction_rsp) { r_vci_tgt_fsm = TGT_IDLE; r_tgt_icache_rsp[r_tgt_num_cache] = false; } break; } case TGT_RSP_DCACHE: { bool transaction_rsp = (p_vci_tgt.rspack.read() or not r_tgt_dcache_rsp[r_tgt_num_cache].read()) and not r_tgt_dcache_req[r_tgt_num_cache].read(); PRINTF(" * RSP_DCACHE : transaction : %d\n",transaction_rsp); if (transaction_rsp) { r_vci_tgt_fsm = TGT_IDLE; r_tgt_dcache_rsp[r_tgt_num_cache] = false; } break; } } // end switch TGT_FSM ///////////////////////////////////////////////////////////////////// // Interface between CPU and CACHE FSM /////////////////////////////////////////////////////////////////////// uint32_t ireq_num_cache [m_nb_cpu]; uint32_t dreq_num_cache [m_nb_cpu]; bool have_sync = false; { typename iss_t::InstructionRequest _ireq = ISS_IREQ_INITIALIZER; typename iss_t::DataRequest _dreq = ISS_DREQ_INITIALIZER; for (uint32_t num_cache=0; num_cachegetRequests(_ireq, _dreq); addr_40 addr; uint32_t num_cache; addr = (addr_40)_ireq.addr; num_cache = get_num_icache(addr,num_cpu); bool icache_req_valid = ((not ireq[num_cache].valid and // no previous request in this cycle (r_icache_lock [num_cache] == m_nb_cpu)) or // no previous request in previous cycle (r_icache_lock [num_cache] == num_cpu)); // previous request in previous cycle by this cpu if (icache_req_valid) { bool valid = _ireq.valid; if (valid) { PRINTF(" * ICACHE : Transaction between cpu %d and cache %d (lock)\n",num_cpu,num_cache); ireq_num_cache [num_cpu ] = num_cache; r_icache_lock [num_cache] = num_cpu; } else { PRINTF(" * ICACHE : No Transaction between cpu %d and cache %d : invalid\n",num_cpu,num_cache); ireq_num_cache [num_cpu] = m_nb_icache; } ireq_cached [num_cache] = m_cacheability_table[(vci_addr_t)_ireq.addr]; ireq_num_cpu [num_cache] = num_cpu; ireq [num_cache] = _ireq; ireq [num_cache].addr = addr; } else { PRINTF(" * ICACHE : No transaction (cpu %d)\n",num_cpu); ireq_num_cache [num_cpu] = m_nb_icache; } addr = (addr_40)_dreq.addr; num_cache = get_num_dcache(addr); bool dcache_no_lock = (r_dcache_lock [num_cache] == m_nb_cpu); bool dcache_lock_owner = (r_dcache_lock [num_cache] == num_cpu); bool dcache_lock_no_owner= not dcache_no_lock and not dcache_lock_owner; bool dcache_req_valid; // multi cache : hit after miss) if (m_nb_dcache > 0) { bool dcache_wait = ((r_dcache_fsm[num_cache] == DCACHE_MISS_WAIT)// or // (r_dcache_fsm[num_cache] == DCACHE_UNC_WAIT) or // (r_dcache_fsm[num_cache] == DCACHE_SC_WAIT) ); dcache_req_valid = ((not dreq[num_cache].valid and // no previous request in this cycle not have_sync and // no sync instruction (dcache_no_lock or (dcache_lock_no_owner and dcache_wait))) or // no previous request in previous cycle (dcache_lock_owner and not dcache_wait)); // previous request in previous cycle by this cpu } else { dcache_req_valid = ((not dreq[num_cache].valid and // no previous request in this cycle not have_sync and // no sync instruction dcache_no_lock) or // no previous request in previous cycle dcache_lock_owner); // previous request in previous cycle by this cpu } // test if already used if (dcache_req_valid) { bool valid = _dreq.valid; if (valid) { PRINTF(" * DCACHE : Transaction between cpu %d and cache %d (lock)\n",num_cpu,num_cache); dreq_num_cache [num_cpu ] = num_cache; // always lock if no multi cache if ((m_nb_dcache == 1) or (not dcache_lock_no_owner)) r_dcache_lock [num_cache] = num_cpu; } else { PRINTF(" * DCACHE : No Transaction between cpu %d and cache %d : invalid\n",num_cpu,num_cache); dreq_num_cache [num_cpu] = m_nb_dcache; } dreq_cached [num_cache] = m_cacheability_table[(vci_addr_t)_dreq.addr]; dreq_num_cpu [num_cache] = num_cpu; dreq [num_cache] = _dreq; dreq [num_cache].addr = addr; } else { PRINTF(" * DCACHE : No transaction (cpu %d)\n",num_cpu); dreq_num_cache [num_cpu] = m_nb_dcache; } #if CC_XCACHE_WRAPPER_DEBUG if (m_cpt_total_cycles>=CC_XCACHE_WRAPPER_DEBUG_CYCLE_MIN) { std::cout << " * Instruction Request : " << ireq_num_cache[num_cpu] << " - " << _ireq << std::endl << " * Data Request : " << dreq_num_cache[num_cpu] << " - " << _dreq << std::endl; } #endif } // round robin priority r_cpu_prior = (r_cpu_prior+1)%m_nb_cpu; ///////////////////////////////////////////////////////////////////// // The ICACHE FSM controls the following ressources: // - r_icache_fsm // - r_icache_fsm_save // - r_icache instruction cache access // - r_icache_addr_save // - r_icache_miss_req set // - r_icache_unc_req set // - r_icache_buf_unc_valid set // - r_vci_rsp_icache_miss_ok reset // - r_vci_rsp_ins_error reset // - r_tgt_icache_req reset // - ireq & irsp structures for communication with the processor // // 1/ External requests (update or invalidate) have highest priority. // They are taken into account in the IDLE and WAIT states. // As external hit should be extremly rare on the ICACHE, // all external requests are handled as invalidate... // In case of external request the ICACHE FSM goes to the CC_CHECK // state to test the external hit, and returns in the // pre-empted state after completion. // 2/ Processor requests are taken into account only in the IDLE state. // In case of MISS, or in case of uncached instruction, the FSM // writes the missing address line in the r_icache_addr_save register // and sets the r_icache_miss_req or the r_icache_unc_req flip-flops. // These request flip-flops are reset by the VCI_RSP FSM // when the VCI transaction is completed and the r_icache_buf_unc_valid // is set in case of uncached access. // In case of bus error, the VCI_RSP FSM sets the r_vci_rsp_ins_error // flip-flop. It is reset by the ICACHE FSM. /////////////////////////////////////////////////////////////////////// for (uint32_t num_cache=0; num_cache> (addr_40)m_icache_words_shift) == r_icache_cleanup_line[num_cache].read()); // icache_hit & icache_ins evaluation if ( icache_cached ) { icache_hit = r_icache[num_cache]->read((vci_addr_t) _ireq.addr, &icache_ins); } else { // if uncache, again in the vci_rsp_fifo_icache icache_hit = (r_icache_buf_unc_valid[num_cache] and ((addr_40) _ireq.addr == (addr_40)r_icache_addr_save[num_cache])); // Test if top of fifo_rsp is for this cache is in ICACHE_UNC_WAIT icache_ins = r_vci_rsp_fifo_icache_data.read(); if (icache_hit) vci_rsp_fifo_icache_get = true; } PRINTF(" * hit %d - cached %d - cleanup_hit %d\n",num_cache, icache_hit, icache_cached, icache_cleanup_hit); if (icache_hit and icache_cleanup_hit) { PRINTF(" * Warning : icache hit and icache_cleanup_hit\n",num_cache); icache_hit = false; } else { if ( not icache_hit and not icache_cleanup_hit) { m_cpt_ins_miss++; m_cost_ins_miss_frz++; r_icache_addr_save[num_cache] = (addr_40) _ireq.addr; if ( icache_cached ) { // to prevent deadlock, miss victim don't be block if (not r_icache_cleanup_req[num_cache]) { r_icache_fsm [num_cache] = ICACHE_MISS_VICTIM; r_icache_miss_req[num_cache] = true; } else m_cpt_icache_miss_victim_wait [num_cache] ++; } else { r_icache_addr_save[num_cache] = (addr_40) _ireq.addr; r_icache_fsm [num_cache] = ICACHE_UNC_WAIT; r_icache_unc_req[num_cache] = true; } } else { // icache_hit and not icache_cleanup_hit // not icache_hit and icache_cleanup_hit // request accepted, inval the buf unc r_icache_buf_unc_valid[num_cache] = false; } m_cpt_icache_dir_read += m_icache_ways; m_cpt_icache_data_read += m_icache_ways; } _irsp.valid = icache_hit; _irsp.instruction = icache_ins; } break; } ////////////////////// case ICACHE_MISS_VICTIM: { // if (not r_icache_cleanup_req[num_cache]) { size_t way; size_t set; vci_addr_t addr = (vci_addr_t) r_icache_addr_save[num_cache].read(); vci_addr_t victim; r_icache_cleanup_req [num_cache] = r_icache[num_cache]->victim_select(addr, &victim, &way, &set ); r_icache_cleanup_line[num_cache] = (addr_40) victim; r_icache_miss_way [num_cache] = way; r_icache_miss_set [num_cache] = set; r_icache_fsm [num_cache] = ICACHE_MISS_WAIT; } break; } ////////////////////// case ICACHE_MISS_WAIT: { m_cost_ins_miss_frz++; if ( r_tgt_icache_req[num_cache] ) { // external request r_icache_fsm [num_cache] = ICACHE_CC_CHECK; r_icache_fsm_save [num_cache] = r_icache_fsm[num_cache].read(); break; } bool val = (r_vci_rsp_fifo_icache_data.rok() and (r_vci_rsp_fifo_icache_num_cache.read() == num_cache)); PRINTF(" * val : %d\n",num_cache,val); if (val) { PRINTF(" * r_icache_inval_rsp : %d\n",num_cache,(int) r_icache_inval_rsp [num_cache]); PRINTF(" * r_vci_rsp_ins_error : %d\n",num_cache,(int) r_vci_rsp_ins_error [num_cache]); PRINTF(" * r_icache_cleanup_req : %d\n",num_cache,(int) r_icache_cleanup_req[num_cache]); // Miss read response and no invalidation if ( r_vci_rsp_ins_error [num_cache]) { r_icache_fsm[num_cache] = ICACHE_ERROR; } else { r_icache_update_addr[num_cache] = 0; r_icache_fsm [num_cache] = ICACHE_MISS_UPDT; } } break; } ///////////////////// case ICACHE_UNC_WAIT: { m_cost_ins_miss_frz++; if ( r_tgt_icache_req[num_cache] ) { // external request r_icache_fsm [num_cache] = ICACHE_CC_CHECK; r_icache_fsm_save[num_cache] = r_icache_fsm[num_cache].read(); break; } bool ok = (r_vci_rsp_fifo_icache_data.rok() and (r_vci_rsp_fifo_icache_num_cache.read() == num_cache)); PRINTF(" * ok : %d\n",num_cache,ok); PRINTF(" * error : %d\n",num_cache,(uint32_t)r_vci_rsp_ins_error [num_cache]); if (ok) { if ( r_vci_rsp_ins_error [num_cache]) { r_icache_fsm[num_cache] = ICACHE_ERROR; } else { r_icache_fsm [num_cache] = ICACHE_IDLE; r_icache_buf_unc_valid[num_cache] = true; } } break; } ////////////////// case ICACHE_ERROR: { if ( (addr_40)_ireq.addr == (addr_40)r_icache_addr_save[num_cache] ) { _irsp.error = true; _irsp.valid = true; } r_icache_fsm [num_cache] = ICACHE_IDLE; r_vci_rsp_ins_error [num_cache] = false; break; } ////////////////////// case ICACHE_MISS_UPDT: { size_t word = r_icache_update_addr[num_cache].read(); vci_addr_t addr = (vci_addr_t) r_icache_addr_save [num_cache].read(); size_t way = r_icache_miss_way[num_cache].read(); size_t set = r_icache_miss_set[num_cache].read(); bool val = (r_vci_rsp_fifo_icache_data.rok() and (r_vci_rsp_fifo_icache_num_cache.read() == num_cache)); if (val) { PRINTF(" * rsp_val : %d/%d\n",num_cache,(int)r_icache_update_addr[num_cache],(int)m_icache_words); PRINTF(" * r_icache_inval_rsp : %d\n" ,num_cache,(int)r_icache_inval_rsp[num_cache]); PRINTF(" * ins : %x\n" ,num_cache,(int)r_vci_rsp_fifo_icache_data.read()); // m_cpt_icache_dir_write++; // m_cpt_icache_data_write++; // if ( _ireq.valid ) m_cost_ins_miss_frz++; // if need invalid rsp, don't modify the cache, but pop the buf_rsp if (not r_icache_inval_rsp[num_cache]) r_icache[num_cache]->write(way, set, word, r_vci_rsp_fifo_icache_data.read()); vci_rsp_fifo_icache_get = true; r_icache_update_addr[num_cache] = ++word; // if last word, finish the update if (word >= m_icache_words) { // in all case (inval_rsp or not), update the victim tag r_icache[num_cache]->victim_update_tag(addr, way, set); // Last word : if previous invalid_rsp, can cleanup, else update the TAG if (r_icache_inval_rsp[num_cache]) { r_icache_inval_rsp[num_cache] = false; r_icache_fsm [num_cache] = ICACHE_CC_CLEANUP; } else { r_icache_fsm [num_cache] = ICACHE_IDLE; } } } break; } //////////////////// case ICACHE_CC_CLEANUP: { // cleanup if(not r_icache_cleanup_req[num_cache]){ r_icache_cleanup_req [num_cache] = true; r_icache_cleanup_line[num_cache] = r_icache_addr_save[num_cache].read() >> m_icache_words_shift; r_icache_fsm [num_cache] = ICACHE_IDLE; m_cpt_icache_dir_read += m_icache_ways; r_icache[num_cache]->inval((addr_40)r_icache_addr_save[num_cache]); } break; } ///////////////////// case ICACHE_CC_CHECK: // read directory in case of invalidate or update request { m_cpt_icache_dir_read += m_icache_ways; m_cpt_icache_data_read += m_icache_ways; addr_40 ad = r_tgt_iaddr; PRINTF(" * CC_CHECK\n",num_cache); if((r_icache_fsm_save[num_cache] == ICACHE_MISS_WAIT) and ((r_icache_addr_save[num_cache].read() & ~((m_icache_words<<2)-1)) == (ad & ~((m_icache_words<<2)-1)))) { PRINTF(" * have request, need inval rsp\n",num_cache); r_icache_inval_rsp[num_cache] = true; r_tgt_icache_req [num_cache] = false; if(r_tgt_update){ // Also send a cleanup and answer PRINTF(" * send a cleanup and answer\n",num_cache); r_tgt_icache_rsp[num_cache] = true; } else { // Also send a cleanup but don't answer PRINTF(" * send a cleanup and but don't answer\n",num_cache); r_tgt_icache_rsp[num_cache] = false; } r_icache_fsm[num_cache] = r_icache_fsm_save[num_cache]; } else { uint32_t word = r_cache_word; data_t mask = vci_param::be2mask(r_tgt_be[word]); data_t rdata = 0; bool icache_hit = r_icache[num_cache]->read(ad+word*4,&rdata); PRINTF(" * have no request, hit cache : %d\n",num_cache,icache_hit); if ( icache_hit and r_tgt_update) { // Assumption : We have RAM for icache with write enable on byte. // Consequence : icache_read is only consultation of directory //if(r_tgt_be[word]) r_icache[num_cache]->write(ad+word*4, (mask & r_tgt_buf[word]) | (~mask & rdata)); word ++; // Find next valid word for (; wordinval(ad); r_tgt_icache_req[num_cache] = false; r_icache_fsm [num_cache] = r_icache_fsm_save[num_cache]; break; } }// end switch r_icache_fsm irsp [num_cache] = _irsp; if (_ireq.valid and _irsp.valid) { PRINTF(" * Transaction between cpu %d and Icache %d (unlock)\n",r_icache_lock [num_cache].read(),num_cache); r_icache_lock [num_cache] = m_nb_cpu; m_cpt_icache_access [num_cache] ++; } }// end for num_cache //////////////////////////////////////////////////////////////////////:///////////// // The DCACHE FSM controls the following ressources: // - r_dcache_fsm // - r_dcache_fsm_save // - r_dcache (data cache access) // - r_dcache_addr_save // - r_dcache_wdata_save // - r_dcache_rdata_save // - r_dcache_type_save // - r_dcache_be_save // - r_dcache_cached_save // - r_dcache_miss_req set // - r_dcache_unc_req set // - r_dcache_cleanup_req set // - r_vci_rsp_data_error reset // - r_tgt_dcache_req reset // - r_wbuf write // - dreq & drsp structures for communication with the processor // // 1/ EXTERNAL REQUEST : // There is an external request when the tgt_dcache req flip-flop is set, // requesting a line invalidation or a line update. // External requests are taken into account in the states IDLE, WRITE_REQ, // UNC_WAIT, MISS_WAIT, and have the highest priority : // The actions associated to the pre-empted state are not executed, the DCACHE FSM // goes to the CC_CHECK state to execute the requested action, and returns to the // pre-empted state. // 2/ PROCESSOR REQUEST : // In order to support VCI write burst, the processor requests are taken into account // in the WRITE_REQ state as well as in the IDLE state. // - In the IDLE state, the processor request cannot be satisfied if // there is a cached read miss, or an uncached read. // - In the WRITE_REQ state, the request cannot be satisfied if // there is a cached read miss, or an uncached read, // or when the write buffer is full. // - In all other states, the processor request is not satisfied. // // The cache access takes into account the cacheability_table. // In case of processor request, there is five conditions to exit the IDLE state: // - CACHED READ MISS => to the MISS_WAIT state (waiting the r_miss_ok signal), // then to the MISS_UPDT state, and finally to the IDLE state. // - UNCACHED READ => to the UNC_WAIT state (waiting the r_miss_ok signal), // and to the IDLE state. // - CACHE INVALIDATE HIT => to the INVAL state for one cycle, then to IDLE state. // - WRITE MISS => directly to the WRITE_REQ state to access the write buffer. // - WRITE HIT => to the WRITE_UPDT state, then to the WRITE_REQ state. // // Error handling : Read Bus Errors are synchronous events, but // Write Bus Errors are asynchronous events (processor is not frozen). // - If a Read Bus Error is detected, the VCI_RSP FSM sets the // r_vci_rsp_data_error flip-flop, and the synchronous error is signaled // by the DCACHE FSM. // - If a Write Bus Error is detected, the VCI_RSP FSM signals // the asynchronous error using the setWriteBerr() method. /////////////////////////////////////////////////////////////////////////////////// for (uint32_t num_cache=0; num_cache Have dreq\n",num_cache); data_t dcache_rdata = 0; // dcache_cached and dcache_hit don't used with _dreq.type == {DATA_SC, XTN_READ, XTN_WRITE} bool dcache_cached = dreq_cached [num_cache]; uint32_t dcache_num_cpu = dreq_num_cpu [num_cache]; bool dcache_hit = r_dcache[num_cache]->read((vci_addr_t) _dreq.addr, &dcache_rdata); bool dcache_cleanup_hit = r_dcache_cleanup_req[num_cache] and (((addr_40)_dreq.addr >> (addr_40)m_dcache_words_shift) == r_dcache_cleanup_line[num_cache].read()); PRINTF(" * hit %d - cached %d - cleanup_hit %d\n",num_cache,dcache_hit, dcache_cached, dcache_cleanup_hit); m_cpt_dcache_data_read += m_dcache_ways; m_cpt_dcache_dir_read += m_dcache_ways; switch( _dreq.type ) { case iss_t::DATA_READ: case iss_t::DATA_LL: { m_cpt_data_read++; // new dcache read if (dcache_hit) // no special test for uncached read, because it's always miss { // address is in the cache : return the word r_dcache_fsm [num_cache] = DCACHE_IDLE; _drsp.valid = true; _drsp.rdata = dcache_rdata; // return read data (cf dcache_hit) // if the request is a Load Linked instruction, save request information if(_dreq.type == iss_t::DATA_LL) { PRINTF(" * ll_valid = true\n",num_cache); r_dcache_ll_valid [num_cache][dcache_num_cpu] = true; r_dcache_ll_data [num_cache][dcache_num_cpu] = dcache_rdata; r_dcache_ll_addr [num_cache][dcache_num_cpu] = (vci_addr_t) _dreq.addr; } } else { if (not dcache_cleanup_hit) { // Miss : send signal at the CMD_FSM (via r_dcache_miss_req or r_dcache_unc_req) if ( dcache_cached ) { // to prevent deadlock, miss victim don't be block if (not r_dcache_cleanup_req[num_cache].read()) { m_cpt_data_read_miss++; m_cost_data_miss_frz++; r_dcache_miss_req [num_cache] = true; r_dcache_fsm [num_cache] = DCACHE_MISS_VICTIM; } else m_cpt_icache_miss_victim_wait [num_cache] ++; } else { if (not r_dcache_previous_unc[num_cache].read()) // strongly order to the uncached access { r_dcache_previous_unc[num_cache] = true; m_cpt_data_read_uncached++; m_cost_unc_read_frz++; r_dcache_unc_req[num_cache] = true; r_dcache_fsm [num_cache] = DCACHE_UNC_WAIT; } } } } } break; case iss_t::DATA_SC: { PRINTF(" * DATA_SC - ll_valid = %d, num_cpu = %d\n",num_cache,r_dcache_ll_valid[num_cache][dcache_num_cpu].read(),dcache_num_cpu); if (not r_dcache_previous_unc[num_cache].read() and not dcache_cleanup_hit) // strongly order to the uncached access { //m_cpt_data_read_unc++; // instruction must read the memory in uncached mode m_cost_unc_read_frz++; // if previous load linked (with the same address), make a transaction // else, keep in IDLE state and return 1 (no OK) if( r_dcache_ll_valid[num_cache][dcache_num_cpu].read() and (r_dcache_ll_addr [num_cache][dcache_num_cpu].read() == (vci_addr_t)_dreq.addr)){ PRINTF(" * have previous load linked\n",num_cache); r_dcache_previous_unc[num_cache] = true; r_dcache_sc_req [num_cache] = true; r_dcache_fsm [num_cache] = DCACHE_SC_WAIT; } else { PRINTF(" * don't have previous load linked\n",num_cache); _drsp.valid = true; _drsp.rdata = 1; // SC rsp NOK r_dcache_ll_valid[num_cache][dcache_num_cpu] = false; } } break; } case iss_t::XTN_READ: case iss_t::XTN_WRITE: { bool valid = false; // only DCACHE INVALIDATE and SYNC request are supported switch (_dreq.addr>>2) { case iss_t::XTN_DCACHE_INVAL : { valid = true; r_dcache_fsm[num_cache] = DCACHE_INVAL; break; } case iss_t::XTN_SYNC : { // Test if write buffer is already empty // * gain : 1 cycle // * cost : can be on the critical path bool empty=true; for (uint32_t i=0; iempty(); if (empty) { valid = true; r_dcache_fsm [num_cache] = DCACHE_IDLE; } else { valid = false; r_dcache_fsm [num_cache] = DCACHE_SYNC; r_dcache_sync[num_cache] = true; } break; } default : { // std::cout << "Warning in VCI_CC_XCACHE_WRAPPER " << name() << std::endl; // std::cout << "Unsupported external access : " << (_dreq.addr>>2) << std::endl; r_dcache_fsm [num_cache] = DCACHE_IDLE; } }//end switch (_dreq.addr>>2) _drsp.valid = valid; _drsp.rdata = 0; break; } case iss_t::DATA_WRITE: PRINTF(" * r_dcache_previous_unc : %d\n",num_cache,r_dcache_previous_unc[num_cache].read()); if (dcache_cached or not r_dcache_previous_unc[num_cache].read()) // strongly order to the uncached access { bool valid; addr_40 addr = _dreq.addr; set_num_dcache(addr,num_cache); // FIXME : // * dans le wbuf, ne pas mettre l'adresse au complet (economie de surface) // * pour cela, virer le set_num_dcache ! valid = r_wbuf[num_cache]->write(addr, _dreq.be, _dreq.wdata, dcache_cached, dcache_num_cpu); #if MWBUF_VHDL_TESTBENCH vhdl_mwbuf_port_write_val [num_cache] = (vhdl_tb_t)1; vhdl_mwbuf_test_write_ack [num_cache] = (vhdl_tb_t)1; vhdl_mwbuf_port_write_ack [num_cache] = (vhdl_tb_t)valid; vhdl_mwbuf_port_write_addr [num_cache] = (vhdl_tb_t)addr; vhdl_mwbuf_port_write_data [num_cache] = (vhdl_tb_t)_dreq.wdata; vhdl_mwbuf_port_write_be [num_cache] = (vhdl_tb_t)_dreq.be; vhdl_mwbuf_port_write_cached [num_cache] = (vhdl_tb_t)dcache_cached; vhdl_mwbuf_port_write_cpu_id [num_cache] = (vhdl_tb_t)dcache_num_cpu; #endif PRINTF(" * r_wbuf valid : %d\n",num_cache,valid); if (valid) { m_cpt_data_write++; if (not dcache_cached) { ASSERT(not dcache_hit, "Request is uncached, but hit in dcache!"); r_dcache_previous_unc[num_cache] = true; m_cpt_data_write_uncached++; } else if (not dcache_hit) m_cpt_data_write_miss++; if (dcache_hit) { // update data cache r_dcache_fsm[num_cache] = DCACHE_WRITE_UPDT; } else { // write accepted r_dcache_fsm [num_cache] = DCACHE_IDLE; } } _drsp.valid = valid; _drsp.rdata = 0; } break; } // end switch _dreq.type r_dcache_addr_save [num_cache] = (addr_40) _dreq.addr; r_dcache_type_save [num_cache] = _dreq.type; r_dcache_wdata_save [num_cache] = _dreq.wdata; r_dcache_be_save [num_cache] = _dreq.be; r_dcache_rdata_save [num_cache] = dcache_rdata; r_dcache_cached_save [num_cache] = dcache_cached; r_dcache_num_cpu_save[num_cache] = dcache_num_cpu; } else { // end if _dreq.valid r_dcache_fsm [num_cache] = DCACHE_IDLE; } break; } /////////////////////// case DCACHE_WRITE_UPDT: { m_cpt_dcache_data_write++; data_t mask = vci_param::be2mask(r_dcache_be_save[num_cache]); data_t wdata = (mask & r_dcache_wdata_save[num_cache]) | (~mask & r_dcache_rdata_save[num_cache]); vci_addr_t ad = r_dcache_addr_save[num_cache].read(); r_dcache[num_cache]->write(ad, wdata); int dcache_fsm_next = DCACHE_IDLE; // default // Test if write after write if (_dreq.valid and (_dreq.type == iss_t::DATA_WRITE)) { PRINTF(" * Have dreq (Write after Write)\n",num_cache); data_t dcache_rdata = 0; // dcache_cached and dcache_hit don't used with _dreq.type == {DATA_SC, XTN_READ, XTN_WRITE} bool dcache_cached = dreq_cached [num_cache]; uint32_t dcache_num_cpu = dreq_num_cpu [num_cache]; bool dcache_hit = r_dcache[num_cache]->read((vci_addr_t) _dreq.addr, &dcache_rdata); m_cpt_dcache_data_read += m_dcache_ways; m_cpt_dcache_dir_read += m_dcache_ways; PRINTF(" * r_dcache_previous_unc : %d\n",num_cache,r_dcache_previous_unc[num_cache].read()); if (dcache_cached or not r_dcache_previous_unc[num_cache].read()) // strongly order to the uncached access { bool valid; addr_40 addr = _dreq.addr; set_num_dcache(addr,num_cache); // FIXME : // * dans le wbuf, ne pas mettre l'adresse au complet (economie de surface) // * pour cela, virer le set_num_dcache ! valid = r_wbuf[num_cache]->write(addr, _dreq.be, _dreq.wdata, dcache_cached, dcache_num_cpu); #if MWBUF_VHDL_TESTBENCH vhdl_mwbuf_port_write_val [num_cache] = (vhdl_tb_t)1; vhdl_mwbuf_test_write_ack [num_cache] = (vhdl_tb_t)1; vhdl_mwbuf_port_write_ack [num_cache] = (vhdl_tb_t)valid; vhdl_mwbuf_port_write_addr [num_cache] = (vhdl_tb_t)addr; vhdl_mwbuf_port_write_data [num_cache] = (vhdl_tb_t)_dreq.wdata; vhdl_mwbuf_port_write_be [num_cache] = (vhdl_tb_t)_dreq.be; vhdl_mwbuf_port_write_cached [num_cache] = (vhdl_tb_t)dcache_cached; vhdl_mwbuf_port_write_cpu_id [num_cache] = (vhdl_tb_t)dcache_num_cpu; #endif PRINTF(" * r_wbuf valid : %d\n",num_cache,valid); if (valid) { m_cpt_dcache_store_after_store [num_cache] ++; m_cpt_data_write++; if (not dcache_cached) { r_dcache_previous_unc[num_cache] = true; m_cpt_data_write_uncached++; } else if (not dcache_hit) m_cpt_data_write_miss++; if (dcache_hit) { // update data cache dcache_fsm_next = DCACHE_WRITE_UPDT; } else { // write accepted dcache_fsm_next = DCACHE_IDLE; } } _drsp.valid = valid; _drsp.rdata = 0; } r_dcache_addr_save [num_cache] = (addr_40) _dreq.addr; // r_dcache_type_save [num_cache] = _dreq.type; r_dcache_wdata_save [num_cache] = _dreq.wdata; r_dcache_be_save [num_cache] = _dreq.be; r_dcache_rdata_save [num_cache] = dcache_rdata; // r_dcache_cached_save [num_cache] = dcache_cached; // r_dcache_num_cpu_save[num_cache] = dcache_num_cpu; } r_dcache_fsm [num_cache] = dcache_fsm_next; // default break; } ////////////////////// case DCACHE_MISS_VICTIM: { // if (not r_dcache_cleanup_req[num_cache].read()) { size_t way; size_t set; vci_addr_t addr = (vci_addr_t) r_dcache_addr_save[num_cache].read(); vci_addr_t victim; bool victim_val = r_dcache[num_cache]->victim_select(addr, &victim, &way, &set ); r_dcache_cleanup_req [num_cache] = victim_val; r_dcache_cleanup_line [num_cache] = (addr_40) victim; r_dcache_miss_way [num_cache] = way; r_dcache_miss_set [num_cache] = set; PRINTF(" * MISS_VICTIM : Victim %d - %llx (way %d, set %d)\n",num_cache,victim_val, (blob_t)victim, (int)way, (int)set); r_dcache_fsm [num_cache] = DCACHE_MISS_WAIT; } break; } ////////////////////// case DCACHE_MISS_WAIT: { // Multi_cache ; Hit after Miss if (m_nb_dcache>0) { data_t dcache_rdata = 0; bool dcache_hit = r_dcache[num_cache]->read((vci_addr_t) _dreq.addr, &dcache_rdata); // bool dcache_cached = dreq_cached [num_cache]; // uint32_t dcache_num_cpu = dreq_num_cpu [num_cache]; m_cpt_dcache_data_read += m_dcache_ways; m_cpt_dcache_dir_read += m_dcache_ways; if (_dreq.valid) switch (_dreq.type) { case iss_t::DATA_READ : // accept only hit dcache load { m_cpt_data_read++; // new dcache read if (dcache_hit) // no special test for uncached read, because it's always miss { m_cpt_dcache_hit_after_miss_read [num_cache] ++; // address is in the cache : return the word _drsp.valid = true; _drsp.rdata = dcache_rdata; // return read data (cf dcache_hit) } break; } // case iss_t::DATA_WRITE : // accept only cached write and miss in dcache (else need update dcache) // { // if (dcache_cached and not dcache_hit) // { // bool valid; // addr_40 addr = _dreq.addr; // set_num_dcache(addr,num_cache); // // FIXME : // // * dans le wbuf, ne pas mettre l'adresse au complet (economie de surface) // // * pour cela, virer le set_num_dcache ! // valid = r_wbuf[num_cache]->write(addr, _dreq.be, _dreq.wdata, dcache_cached, dcache_num_cpu); // PRINTF(" * r_wbuf valid : %d\n",num_cache,valid); // if (valid) // { // m_cpt_dcache_hit_after_miss_write [num_cache] ++; // m_cpt_data_write++; // m_cpt_data_write_miss++; // } // _drsp.valid = valid; // _drsp.rdata = 0; // } // break; // } default : { break; } } } // end multi cache hit after miss // if ( _dreq.valid ) m_cost_data_miss_frz++; if ( r_tgt_dcache_req[num_cache].read() ) { // external request r_dcache_fsm [num_cache] = DCACHE_CC_CHECK; r_dcache_fsm_save [num_cache] = r_dcache_fsm[num_cache]; break; } bool val = (r_vci_rsp_fifo_dcache_data.rok() and (r_vci_rsp_fifo_dcache_num_cache.read() == num_cache)); if (val) { // Miss read response and no invalidation if (r_vci_rsp_data_error[num_cache]) { r_dcache_fsm [num_cache] = DCACHE_ERROR; } else { r_dcache_update_addr[num_cache] = 0; r_dcache_fsm [num_cache] = DCACHE_MISS_UPDT; } } break; } ////////////////////// case DCACHE_MISS_UPDT: { size_t word = r_dcache_update_addr[num_cache].read(); vci_addr_t addr = (vci_addr_t) r_dcache_addr_save[num_cache].read(); size_t way = r_dcache_miss_way[num_cache].read(); size_t set = r_dcache_miss_set[num_cache].read(); PRINTF(" * MISS_UPDT : Victim way %d, set %d\n",num_cache, (int)way, (int)set); bool val = (r_vci_rsp_fifo_dcache_data.rok() and (r_vci_rsp_fifo_dcache_num_cache.read() == num_cache)); if (val) { // m_cpt_dcache_dir_write++; // if ( _dreq.valid ) m_cost_data_miss_frz++; // if need invalid rsp, don't modify the cache, but pop the buf_rsp // (power save) if (not r_dcache_inval_rsp[num_cache]) { r_dcache[num_cache]->write(way, set, word, r_vci_rsp_fifo_dcache_data.read()); m_cpt_dcache_data_write++; } vci_rsp_fifo_dcache_get = true; r_dcache_update_addr[num_cache] = ++word; // if last word, finish the update if (word >= m_dcache_words) { // in all case (inval_rsp or not), update the victim tag // because victim is already cleanup r_dcache[num_cache]->victim_update_tag(addr, way, set); // Last word : if previous invalid_rsp, can cleanup, else update the TAG if (r_dcache_inval_rsp[num_cache]) { r_dcache_inval_rsp[num_cache] = false; r_dcache_fsm [num_cache] = DCACHE_CC_CLEANUP; } else { r_dcache_fsm [num_cache] = DCACHE_IDLE; } } } break; } //////////////////// case DCACHE_UNC_WAIT: { // if ( _dreq.valid ) m_cost_unc_read_frz++; if ( r_tgt_dcache_req[num_cache] ) { // external request r_dcache_fsm [num_cache] = DCACHE_CC_CHECK; r_dcache_fsm_save[num_cache] = r_dcache_fsm[num_cache]; break; } bool ok = (r_vci_rsp_fifo_dcache_data.rok() and (r_vci_rsp_fifo_dcache_num_cache.read() == num_cache)); if (ok) { if (r_vci_rsp_data_error[num_cache]) { r_dcache_fsm[num_cache] = DCACHE_ERROR; } else { data_t rdata = r_vci_rsp_fifo_dcache_data.read(); vci_rsp_fifo_dcache_get = true; if(_dreq.type == iss_t::DATA_LL){ PRINTF(" * ll_valid = true\n",num_cache); r_dcache_ll_valid [num_cache][r_dcache_num_cpu_save[num_cache]] = true; r_dcache_ll_data [num_cache][r_dcache_num_cpu_save[num_cache]] = rdata; r_dcache_ll_addr [num_cache][r_dcache_num_cpu_save[num_cache]] = (vci_addr_t) _dreq.addr; } r_dcache_fsm [num_cache] = DCACHE_IDLE; _drsp.valid = true; _drsp.rdata = rdata; } } break; } //////////////////// case DCACHE_SC_WAIT: { // if ( _dreq.valid ) m_cost_unc_read_frz++; if ( r_tgt_dcache_req[num_cache] ) { // external request r_dcache_fsm [num_cache] = DCACHE_CC_CHECK; r_dcache_fsm_save [num_cache] = r_dcache_fsm [num_cache]; break; } bool ok = (r_vci_rsp_fifo_dcache_data.rok() and (r_vci_rsp_fifo_dcache_num_cache.read() == num_cache)); if (ok) { if (r_vci_rsp_data_error[num_cache]) { r_dcache_fsm [num_cache] = DCACHE_ERROR; } else { r_dcache_fsm [num_cache] = DCACHE_IDLE; _drsp.valid = true; _drsp.rdata = r_vci_rsp_fifo_dcache_data.read(); vci_rsp_fifo_dcache_get = true; r_dcache_ll_valid [num_cache][r_dcache_num_cpu_save[num_cache]] = false; } } break; } ////////////////// case DCACHE_ERROR: { r_dcache_fsm [num_cache] = DCACHE_IDLE; r_vci_rsp_data_error[num_cache] = false; _drsp.error = true; _drsp.valid = true; break; } ///////////////// case DCACHE_INVAL: { if ( r_tgt_dcache_req[num_cache].read() ) { // external request r_dcache_fsm [num_cache] = DCACHE_CC_CHECK; r_dcache_fsm_save [num_cache] = r_dcache_fsm [num_cache]; break; } if( not r_dcache_cleanup_req [num_cache].read() ){ m_cpt_dcache_dir_read += m_dcache_ways; vci_addr_t ad = r_dcache_addr_save [num_cache].read(); r_dcache_cleanup_req [num_cache] = r_dcache[num_cache]->inval(ad); r_dcache_cleanup_line [num_cache] = r_dcache_addr_save [num_cache].read() >> m_dcache_words_shift; r_dcache_fsm [num_cache] = DCACHE_IDLE; } break; } case DCACHE_SYNC : { if ( r_tgt_dcache_req[num_cache] ) { // external request r_dcache_fsm [num_cache] = DCACHE_CC_CHECK; r_dcache_fsm_save[num_cache] = r_dcache_fsm[num_cache]; break; } bool empty=true; for (uint32_t i=0; iempty(); if (empty) { _drsp.valid = true; // end, can accept the sync request r_dcache_fsm [num_cache] = DCACHE_IDLE; r_dcache_sync[num_cache] = false; } break; } ///////////////////// case DCACHE_CC_CHECK: // read directory in case of invalidate or update request { addr_40 ad = r_tgt_daddr; PRINTF(" * CC_CHECK\n",num_cache); // if((r_dcache_fsm_save[num_cache] == DCACHE_MISS_WAIT) and ((r_dcache_addr_save[num_cache].read() & ~((m_dcache_words<<2)-1)) == (ad & ~((m_dcache_words<<2)-1)))) { PRINTF(" * have request, need inval rsp\n",num_cache); r_dcache_inval_rsp[num_cache] = true; r_tgt_dcache_req [num_cache] = false; if(r_tgt_update){ // Also send a cleanup and answer PRINTF(" * send a cleanup and answer\n",num_cache); r_tgt_dcache_rsp[num_cache] = true; } else { // Also send a cleanup but don't answer PRINTF(" * send a cleanup and but don't answer\n",num_cache); r_tgt_dcache_rsp[num_cache] = false; } r_dcache_fsm[num_cache] = r_dcache_fsm_save[num_cache]; } else { uint32_t word = r_cache_word; data_t mask = vci_param::be2mask(r_tgt_be[word]); data_t rdata = 0; bool dcache_hit = r_dcache[num_cache]->read(ad+word*4,&rdata); PRINTF(" * have no request, hit cache : %d, update : %d\n",num_cache,dcache_hit,(uint32_t)r_tgt_update); m_cpt_dcache_data_write+= m_dcache_ways; m_cpt_dcache_dir_read += m_dcache_ways; if ( dcache_hit and r_tgt_update ) { // Assumption : We have RAM for dcache with write enable on byte. // Consequence : dcache_read is only consultation of directory //if(r_tgt_be[word]) r_dcache[num_cache]->write(ad+word*4, (mask & r_tgt_buf[word]) | (~mask & rdata)); word ++; // find next valid word for (; wordinval(ad); r_tgt_dcache_req[num_cache] = false; r_dcache_fsm [num_cache] = r_dcache_fsm_save[num_cache]; break; } /////////////////// case DCACHE_CC_CLEANUP: { // cleanup if(not r_dcache_cleanup_req[num_cache]){ r_dcache_cleanup_req [num_cache] = true; r_dcache_cleanup_line [num_cache] = r_dcache_addr_save[num_cache].read() >> m_dcache_words_shift; r_dcache_fsm [num_cache] = DCACHE_IDLE; m_cpt_dcache_dir_read += m_dcache_ways; r_dcache[num_cache]->inval((addr_40)r_dcache_addr_save[num_cache]); } break; } } // end switch r_dcache_fsm ////////// write buffer state update ///////////// // The update() method must be called at each cycle to update the internal state. // All pending write requests must be locked in case of SYNC r_wbuf[num_cache]->update (have_sync); #if MWBUF_VHDL_TESTBENCH vhdl_mwbuf_port_flush [num_cache] = (vhdl_tb_t)have_sync; #endif drsp [num_cache] = _drsp; if (_dreq.valid and _drsp.valid) { PRINTF(" * Transaction between cpu %d and Dcache %d (unlock)\n",r_dcache_lock [num_cache].read(),num_cache); r_dcache_lock [num_cache] = m_nb_cpu; m_cpt_dcache_access [num_cache] ++; } }// end for num_cache /////////// execute one iss cycle ///////////////////////////////////////////// for (uint32_t num_cpu=0; num_cpu=CC_XCACHE_WRAPPER_DEBUG_CYCLE_MIN) { std::cout << " * CPU : " << num_cpu << std::endl << " * Instruction Cache : " << ireq_num_cache[num_cpu] << ", valid : " << (ireq_num_cache[num_cpu]= m_stop_simulation_nb_frz_cycles_max)) { std::cout << std::dec << "CC_XCACHE_WRAPPER \"" << name() << "\" (" << num_cpu << ") : cycle " << m_cpt_total_cycles << ", the cpu is frozen since " << m_stop_simulation_nb_frz_cycles [num_cpu]<< " cycles." << std::endl; ASSERT(false,"CPU : anormal activity"); // exit } } else { m_stop_simulation_nb_frz_cycles [num_cpu] = 0; // reinit counter #endif //CC_XCACHE_WRAPPER_STOP_SIMULATION } #if CC_XCACHE_WRAPPER_DEBUG_FILE_TRANSACTION if (generate_log_transaction_file_icache and _ireq.valid and _irsp.valid) { log_transaction_file_icache [num_cpu] << "[" << m_cpt_total_cycles << "]" << std::hex << " @ " << std::setw(8) << (uint32_t)_ireq.addr << " (" << std::setw(8) << (uint32_t)set_num_icache_only(_ireq.addr,ireq_num_cache[num_cpu]) << " - L " << std::setw(8) <<((uint32_t)set_num_icache_only(_ireq.addr,ireq_num_cache[num_cpu])&m_icache_yzmask) << ")" << " I " << std::setw(8) << (uint32_t)_irsp.instruction << " error " << (uint32_t)_irsp.error << std::dec << std::endl; } if (generate_log_transaction_file_dcache and _dreq.valid and _drsp.valid) { log_transaction_file_dcache [num_cpu] << "[" << m_cpt_total_cycles << "]" << std::hex << " @ " << std::setw(8) << (uint32_t)_dreq.addr << " (" << std::setw(8) << (uint32_t)set_num_dcache_only(_dreq.addr,dreq_num_cache[num_cpu]) << " - L " << std::setw(8) <<((uint32_t)set_num_dcache_only(_dreq.addr,dreq_num_cache[num_cpu])&m_dcache_yzmask) << ")" << " be " << std::setw(1) << (uint32_t)_dreq.be << " W " << std::setw(8) << (uint32_t)_dreq.wdata << " R " << std::setw(8) << (uint32_t)_drsp.rdata << " error " << (uint32_t)_drsp.error << std::dec << " " << type_str(_dreq.type); if ((_dreq.type == iss_t::XTN_READ) or (_dreq.type == iss_t::XTN_WRITE)) //log_transaction_file_dcache [num_cpu] << xtn_str(_dreq.addr>>2); switch (_dreq.addr>>2) { case iss_t::XTN_DCACHE_INVAL : log_transaction_file_dcache [num_cpu]<< " INVAL"; break; case iss_t::XTN_SYNC : log_transaction_file_dcache [num_cpu]<< " SYNC"; break; default : log_transaction_file_dcache [num_cpu]<< " invalid"; break; } log_transaction_file_dcache [num_cpu]<< std::endl; } #endif //CC_XCACHE_WRAPPER_DEBUG_FILE_TRANSACTION { uint32_t it = 0; for (size_t i=0; i<(size_t)iss_t::n_irq; i++) if(p_irq[num_cpu][i].read()) it |= (1<executeNCycles(1, _irsp, _drsp, it); } }//end num_cpu //////////////////////////////////////////////////////////////////////////// // This CLEANUP FSM controls the transmission of the cleanup transactions // on the coherence network. It controls the following ressources: // - r_cleanup_fsm // - r_dcache_cleanup_req (reset) // - r_icache_cleanup_req (reset) // // This FSM handles cleanup requests from both the DCACHE FSM & ICACHE FSM // - Instruction Cleanup : r_icache_cleanup_req // - Data Cleanup : r_dcache_cleanup_req // In case of simultaneous requests, the data request have highest priority. // There is only one cleanup transaction at a given time (sequencial behavior) // because the same FSM controls both command & response. // The the r_icache_cleanup_req & r_dcache_cleanup_req are reset only // when the response packet is received. // Error handling : // As the coherence trafic is controled by hardware, errors are not reported // to software : In case of errors, the simulation stops. //////////////////////////////////////////////////////////////////////////// switch (r_cleanup_fsm) { case CLEANUP_IDLE: { uint32_t num_cache = 0; bool cleanup_dcache_req = false; bool cleanup_icache_req = false; // dcache is prior for (uint32_t i=0; i dcache_cleanup_req : [%d] %d\n",i,(int)r_dcache_cleanup_req[i]); cleanup_dcache_req |= r_dcache_cleanup_req[i]; if (cleanup_dcache_req) { PRINTF(" * ... find\n"); num_cache=i; break; } } if (not cleanup_dcache_req) for (uint32_t i=0; i icache_cleanup_req : [%d] %d\n",i,(int)r_icache_cleanup_req[i]); cleanup_icache_req |= r_icache_cleanup_req[i]; if (cleanup_icache_req) { PRINTF(" * ... find\n"); num_cache=i; break; } } PRINTF(" * cleanup_icache_req : %d\n",cleanup_icache_req); PRINTF(" * cleanup_dcache_req : %d\n",cleanup_dcache_req); PRINTF(" * num_cache : %d\n",num_cache); if (cleanup_icache_req or cleanup_dcache_req) { r_cleanup_fsm = CLEANUP_REQ; r_cleanup_icache = cleanup_icache_req; r_cleanup_num_cache = num_cache; PRINTF(" * address : %llx\n",((cleanup_icache_req)?((blob_t)set_num_icache_only(r_icache_cleanup_line[num_cache].read()< rerror : %d (%d)\n",(uint32_t)p_vci_ini_c.rerror.read(),0x2 & ( (1 << vci_param::E) - 1)); PRINTF(" * rpktid : %d, r_cleanup_num_cache : %d\n",(uint32_t)p_vci_ini_c.rpktid.read(), (uint32_t)r_cleanup_num_cache); ASSERT(p_vci_ini_c.reop and (p_vci_ini_c.rtrdid.read() == TYPE_DATA_CLEANUP), "illegal response packet received for a cleanup transaction"); ASSERT((p_vci_ini_c.rerror.read()&1) == vci_param::ERR_NORMAL, "error signaled in a cleanup response" ); ASSERT(p_vci_ini_c.rpktid.read() == (sc_dt::sc_uint)r_cleanup_num_cache, "invalid pktid in a cleanup response"); r_cleanup_fsm = CLEANUP_IDLE; r_dcache_cleanup_req[r_cleanup_num_cache] = false; // m_cpt_cc_cleanup_data++; } break; } case CLEANUP_RSP_ICACHE: { if ( p_vci_ini_c.rspval ) { PRINTF(" * rerror : %d (%d)\n",(uint32_t)p_vci_ini_c.rerror.read(),0x2 & ( (1 << vci_param::E) - 1)); ASSERT(p_vci_ini_c.reop and (p_vci_ini_c.rtrdid.read() == TYPE_INS_CLEANUP), "illegal response packet received for a cleanup transaction"); ASSERT((p_vci_ini_c.rerror.read()&1) == vci_param::ERR_NORMAL, "error signaled in a cleanup response" ); r_cleanup_fsm = CLEANUP_IDLE; r_icache_cleanup_req[r_cleanup_num_cache] = false; // m_cpt_cc_cleanup_ins++; } break; } } // end switch r_cleanup_fsm //////////////////////////////////////////////////////////////////////////// // The VCI_CMD FSM controls the following ressources: // - r_vci_cmd_fsm // - r_vci_cmd_min // - r_vci_cmd_max // - r_vci_cmd_cpt // - wbuf (reset) // - r_icache_miss_req (reset) // - r_icache_unc_req (reset) // - r_dcache_miss_req (reset) // - r_dcache_sc_req (reset) // // This FSM handles requests from both the DCACHE FSM & the ICACHE FSM. // There is 7 request types, with the following priorities : // 1 - Data Read Miss : r_dcache_miss_req and miss in the write buffer // 2 - Data Read Uncachable : r_dcache_unc_req and miss in the write buffer // 3 - Instruction Miss : r_icache_miss_req and miss in the write buffer // 4 - Instruction Uncachable : r_icache_unc_req and miss in the write buffer // 5 - Data Write : r_wbuf.rok() // 6 - Data Store Conditionnal: r_dcache_sc_req // There is at most one (CMD/RSP) VCI transaction, as both CMD_FSM // and RSP_FSM exit simultaneously the IDLE state. // // VCI formats: // According to the VCI advanced specification, all read requests packets // (read Uncached, Miss data, Miss instruction) are one word packets. // For write burst packets, all words must be in the same cache line, // and addresses must be contiguous (the BE field is 0 in case of "holes"). ////////////////////////////////////////////////////////////////////////////// // reverse priority r_vci_cmd_dcache_prior = not r_vci_cmd_dcache_prior; r_vci_cmd_num_icache_prior = (r_vci_cmd_num_icache_prior+1)%m_nb_icache; r_vci_cmd_num_dcache_prior = (r_vci_cmd_num_dcache_prior+1)%m_nb_dcache; size_t wbuf_min = 0; size_t wbuf_max = 0; #if CC_XCACHE_WRAPPER_DEBUG_FILE_TRANSACTION addr_40 wbuf_addr = 0; size_t wbuf_index = 0; #endif uint32_t dcache_write_num_cache = m_nb_dcache; for (uint32_t i=0; irok_info(&_wbuf_min, &_wbuf_max, &_wbuf_addr, &_wbuf_index)) and #else (r_wbuf[num_cache]->rok (&_wbuf_min, &_wbuf_max)) and #endif (dcache_write_num_cache == m_nb_dcache)) { find = true; dcache_write_num_cache = num_cache; PRINTF(" * wbuf min, max : %d, %d\n",(int)_wbuf_min,(int)_wbuf_max); wbuf_min = _wbuf_min ; wbuf_max = _wbuf_max ; #if CC_XCACHE_WRAPPER_DEBUG_FILE_TRANSACTION wbuf_addr = _wbuf_addr ; wbuf_index = _wbuf_index; PRINTF(" * wbuf index : %d\n",(int)_wbuf_index); PRINTF(" * wbuf address : %llx\n",(blob_t)_wbuf_addr); #endif } PRINTF(" * Test read after miss : cache : %d, find : %d\n",dcache_write_num_cache, find); #if MWBUF_VHDL_TESTBENCH vhdl_mwbuf_test_sent_val [dcache_write_num_cache] = (vhdl_tb_t)1; vhdl_mwbuf_port_sent_val [dcache_write_num_cache] = (vhdl_tb_t)find; vhdl_mwbuf_test_sent_word_min [dcache_write_num_cache] = (vhdl_tb_t)find; vhdl_mwbuf_port_sent_word_min [dcache_write_num_cache] = (vhdl_tb_t)wbuf_min; vhdl_mwbuf_test_sent_word_max [dcache_write_num_cache] = (vhdl_tb_t)find; vhdl_mwbuf_port_sent_word_max [dcache_write_num_cache] = (vhdl_tb_t)wbuf_max; #endif } switch (r_vci_cmd_fsm) { case CMD_IDLE: { // if (r_vci_rsp_fsm != RSP_IDLE) break; // Requests : // multi_write_buffer access is conditionnal with dcache_miss_req and icache_miss_req bool dcache_miss_req = false; bool icache_miss_req = false; uint32_t dcache_miss_num_cache = m_nb_dcache; uint32_t icache_miss_num_cache = m_nb_icache; addr_40 addr = 0; bool wbuf_imiss = false; bool wbuf_dmiss = false; { for (uint32_t i=0; i icache_miss_req (before) : %d\n",icache_miss_req); PRINTF(" * dcache_miss_req (before) : %d\n",dcache_miss_req); // one access with round robin priority dcache_miss_req = ((dcache_miss_req and not icache_miss_req) or // only dcache (dcache_miss_req and r_vci_cmd_dcache_prior)); // dcache prior icache_miss_req &= not dcache_miss_req; PRINTF(" * icache_miss_req (after ) : %d\n",icache_miss_req); PRINTF(" * dcache_miss_req (after ) : %d\n",dcache_miss_req); PRINTF(" * icache_miss_num_cache : %d\n",icache_miss_num_cache); PRINTF(" * dcache_miss_num_cache : %d\n",dcache_miss_num_cache); if (icache_miss_req or dcache_miss_req) { addr = (icache_miss_req)?r_icache_addr_save[icache_miss_num_cache].read():r_dcache_addr_save[dcache_miss_num_cache].read(); PRINTF(" * addr : %llx\n",(blob_t)addr); if (icache_miss_req) { // FIXME : // si wbuf contient des addresses partionné, set_num_icache puis get_num_dcache // dcache_miss_num_cache = icache_miss_num_cache; set_num_icache(addr,icache_miss_num_cache); // get_num_dcache(addr,dcache_miss_num_cache); } else set_num_dcache(addr,dcache_miss_num_cache); PRINTF(" * addr : %llx\n",(blob_t)addr); uint32_t num_cache = get_num_dcache_only(addr); wbuf_imiss = (icache_miss_req)?r_wbuf[num_cache]->miss(addr):false; wbuf_dmiss = (dcache_miss_req)?r_wbuf[num_cache]->miss(addr):false; #if MWBUF_VHDL_TESTBENCH vhdl_mwbuf_port_raw_test [num_cache] = (vhdl_tb_t)1; vhdl_mwbuf_port_raw_addr [num_cache] = (vhdl_tb_t)addr; vhdl_mwbuf_test_raw_miss [num_cache] = (vhdl_tb_t)1; vhdl_mwbuf_port_raw_miss [num_cache] = (dcache_miss_req)?(vhdl_tb_t)wbuf_dmiss:(vhdl_tb_t)wbuf_imiss; #endif } } uint32_t dcache_unc_num_cache = m_nb_dcache; for (uint32_t i=0; imiss(addr)) { r_vci_cmd_fsm = CMD_DATA_MISS; r_vci_cmd_num_cache = dcache_miss_num_cache; r_dcache_miss_req[dcache_miss_num_cache] = false; m_cpt_dmiss_transaction++; #if CC_XCACHE_WRAPPER_DEBUG_FILE_TRANSACTION if (generate_log_transaction_file_cmd) { log_transaction_file_cmd << "[" << m_cpt_total_cycles << "] " << "CMD DATA MISS " << "(" << dcache_miss_num_cache << ") " << std::hex << " @ " << std::setw(10) << (blob_t)addr << " (L " << std::setw(10) << ((blob_t)addr&(blob_t)m_dcache_yzmask) << ")" << std::dec << std::endl; } #endif //CC_XCACHE_WRAPPER_DEBUG_FILE_TRANSACTION } // 2 - Data Read Uncachable else if (dcache_unc_num_cache < m_nb_dcache) // have r_dcache_unc_req { r_vci_cmd_fsm = CMD_DATA_UNC; r_vci_cmd_num_cache = dcache_unc_num_cache; r_dcache_unc_req[dcache_unc_num_cache] = false; // m_cpt_data_unc_transaction++; #if CC_XCACHE_WRAPPER_DEBUG_FILE_TRANSACTION if (generate_log_transaction_file_cmd) { addr_40 addr = (addr_40) r_dcache_addr_save[dcache_unc_num_cache].read() & ~0x3; set_num_dcache(addr,dcache_unc_num_cache); log_transaction_file_cmd << "[" << m_cpt_total_cycles << "] " << "CMD DATA UNC " << "(" << dcache_unc_num_cache << ") " << std::hex << " @ " << std::setw(10) << (blob_t)addr << " (L " << std::setw(10) << ((blob_t)addr&(blob_t)m_dcache_yzmask) << ")" << std::dec << std::endl; } #endif //CC_XCACHE_WRAPPER_DEBUG_FILE_TRANSACTION } // 3 - Instruction Miss else if (wbuf_imiss) //else if (icache_miss_req and r_wbuf[icache_miss_num_cache]->miss(addr)) { r_vci_cmd_fsm = CMD_INS_MISS; r_vci_cmd_num_cache = icache_miss_num_cache; r_icache_miss_req[icache_miss_num_cache] = false; m_cpt_imiss_transaction++; #if CC_XCACHE_WRAPPER_DEBUG_FILE_TRANSACTION if (generate_log_transaction_file_cmd) { log_transaction_file_cmd << "[" << m_cpt_total_cycles << "] " << "CMD INS MISS " << "(" << icache_miss_num_cache << ") " << std::hex << " @ " << std::setw(10) << (blob_t)addr << " (L " << std::setw(10) << ((blob_t)addr&(blob_t)m_icache_yzmask) << ")" << std::dec << std::endl; } #endif //CC_XCACHE_WRAPPER_DEBUG_FILE_TRANSACTION } // 4 - Instruction Uncachable else if (icache_unc_num_cache < m_nb_icache) // have r_icache_unc_req { r_vci_cmd_fsm = CMD_INS_UNC; r_vci_cmd_num_cache = icache_unc_num_cache; r_icache_unc_req[icache_unc_num_cache] = false; // m_cpt_ins_unc_transaction++; #if CC_XCACHE_WRAPPER_DEBUG_FILE_TRANSACTION if (generate_log_transaction_file_cmd) { addr_40 addr = (addr_40) r_icache_addr_save[icache_unc_num_cache].read() & ~0x3; set_num_dcache(addr,icache_unc_num_cache); log_transaction_file_cmd << "[" << m_cpt_total_cycles << "] " << "CMD INS UNC " << "(" << icache_unc_num_cache << ") " << std::hex << " @ " << std::setw(10) << (blob_t)addr << " (L " << std::setw(10) << ((blob_t)addr&(blob_t)m_icache_yzmask) << ")" << std::dec << std::endl; } #endif //CC_XCACHE_WRAPPER_DEBUG_FILE_TRANSACTION } // 5 - Data Write else if (dcache_write_num_cache < m_nb_dcache) // have r_wbuf.rok(&wbuf_min, &wbuf_max) { r_vci_cmd_num_cache = dcache_write_num_cache; r_vci_cmd_fsm = CMD_DATA_WRITE; r_vci_cmd_cpt = wbuf_min; r_vci_cmd_min = wbuf_min; r_vci_cmd_max = wbuf_max; m_cpt_data_write_transaction++; m_length_write_transaction += (wbuf_max-wbuf_min+1); #if CC_XCACHE_WRAPPER_DEBUG_FILE_TRANSACTION if (generate_log_transaction_file_cmd) { addr_40 addr = (addr_40) wbuf_addr&~0x3; log_transaction_file_cmd << "[" << m_cpt_total_cycles << "] " << "CMD DATA WRITE " << "(" << dcache_write_num_cache << ") " << std::hex << " @ " << std::setw(10) << (blob_t)addr << " (L " << std::setw(10) << ((blob_t)addr&(blob_t)m_dcache_yzmask) << ")" << " [" << wbuf_min << ":" << wbuf_max << "]" << " {" << wbuf_index << "}" << std::dec << std::endl; } #endif //CC_XCACHE_WRAPPER_DEBUG_FILE_TRANSACTION } // 6 - Data Store Conditionnal else if (dcache_sc_num_cache < m_nb_dcache) // have r_dcache_sc_req { r_vci_cmd_fsm = CMD_DATA_SC; r_vci_cmd_num_cache = dcache_sc_num_cache; r_vci_cmd_cpt = 0; r_vci_cmd_min = 0; r_vci_cmd_max = 1; m_cpt_unc_transaction++; r_dcache_sc_req[dcache_sc_num_cache] = false; #if CC_XCACHE_WRAPPER_DEBUG_FILE_TRANSACTION if (generate_log_transaction_file_cmd) { addr_40 addr = (addr_40) r_dcache_addr_save[dcache_sc_num_cache].read() & ~0x3; set_num_dcache(addr,dcache_sc_num_cache); log_transaction_file_cmd << "[" << m_cpt_total_cycles << "] " << "CMD DATA SC " << "(" << dcache_sc_num_cache << ") " << std::hex << " @ " << std::setw(10) << (blob_t)addr << " (L " << std::setw(10) << ((blob_t)addr&(blob_t)m_dcache_yzmask) << ")" << std::dec << std::endl; } #endif //CC_XCACHE_WRAPPER_DEBUG_FILE_TRANSACTION } break; } case CMD_DATA_WRITE: if ( p_vci_ini_rw.cmdack.read() ) { #if MWBUF_VHDL_TESTBENCH vhdl_mwbuf_port_sent_word [r_vci_cmd_num_cache] = (vhdl_tb_t)r_vci_cmd_cpt; vhdl_mwbuf_test_sent_addr [r_vci_cmd_num_cache] = (vhdl_tb_t)1; vhdl_mwbuf_port_sent_addr [r_vci_cmd_num_cache] = (vhdl_tb_t)r_wbuf[r_vci_cmd_num_cache]->getAddress(r_vci_cmd_cpt); vhdl_mwbuf_test_sent_data [r_vci_cmd_num_cache] = (vhdl_tb_t)1; vhdl_mwbuf_port_sent_data [r_vci_cmd_num_cache] = (vhdl_tb_t)r_wbuf[r_vci_cmd_num_cache]->getData(r_vci_cmd_cpt); vhdl_mwbuf_test_sent_be [r_vci_cmd_num_cache] = (vhdl_tb_t)1; vhdl_mwbuf_port_sent_be [r_vci_cmd_num_cache] = (vhdl_tb_t)r_wbuf[r_vci_cmd_num_cache]->getBe(r_vci_cmd_cpt); vhdl_mwbuf_test_sent_index [r_vci_cmd_num_cache] = (vhdl_tb_t)1; vhdl_mwbuf_port_sent_index [r_vci_cmd_num_cache] = (vhdl_tb_t)r_wbuf[r_vci_cmd_num_cache]->getIndex(); #endif r_vci_cmd_cpt = r_vci_cmd_cpt + 1; if (r_vci_cmd_cpt == r_vci_cmd_max) { r_vci_cmd_fsm = CMD_IDLE ; r_wbuf[r_vci_cmd_num_cache]->sent() ; #if MWBUF_VHDL_TESTBENCH vhdl_mwbuf_port_sent_ack [r_vci_cmd_num_cache] = (vhdl_tb_t)1; #endif } } break; case CMD_DATA_SC: if ( p_vci_ini_rw.cmdack.read() ) { r_vci_cmd_cpt = r_vci_cmd_cpt + 1; if (r_vci_cmd_cpt == r_vci_cmd_max) { r_vci_cmd_fsm = CMD_IDLE ; } } break; case CMD_INS_MISS: case CMD_INS_UNC: case CMD_DATA_MISS: case CMD_DATA_UNC: if ( p_vci_ini_rw.cmdack.read() ) { r_vci_cmd_fsm = CMD_IDLE; } break; } // end switch r_vci_cmd_fsm ////////////////////////////////////////////////////////////////////////// // The VCI_RSP FSM controls the following ressources: // - r_vci_rsp_fsm: // - r_vci_rsp_fifo_icache[m_icache_words] // - r_vci_rsp_fifo_dcache[m_dcache_words] // - r_vci_rsp_data_error set // - r_vci_rsp_ins_error set // - r_vci_rsp_cpt // In order to have only one active VCI transaction, this VCI_RSP_FSM // is synchronized with the VCI_CMD FSM, and both FSMs exit the // IDLE state simultaneously. // // VCI formats: // This component accepts single word or multi-word response packets for // write response packets. // // Error handling: // This FSM analyzes the VCI error code and signals directly the // Write Bus Error. // In case of Read Data Error, the VCI_RSP FSM sets the r_vci_rsp_data_error // flip_flop and the error is signaled by the DCACHE FSM. // In case of Instruction Error, the VCI_RSP FSM sets the r_vci_rsp_ins_error // flip_flop and the error is signaled by the DCACHE FSM. // In case of Cleanup Error, the simulation stops with an error message... ////////////////////////////////////////////////////////////////////////// switch (r_vci_rsp_fsm) { case RSP_IDLE: if( p_vci_ini_rw.rspval.read() ) { PRINTF(" * have rsp - trdid : %x - num_cache : %d\n",(uint32_t)p_vci_ini_rw.rtrdid.read(),(uint32_t)p_vci_ini_rw.rpktid.read()); ASSERT(p_vci_ini_rw.rpktid.read() <= (1<>(vci_param::T-1)) != 0 ) { r_vci_rsp_fsm = RSP_DATA_WRITE; #if CC_XCACHE_WRAPPER_DEBUG_FILE_TRANSACTION if (generate_log_transaction_file_cmd) { log_transaction_file_cmd << "[" << m_cpt_total_cycles << "] " << "RSP DATA WRITE " << "(" << p_vci_ini_rw.rpktid.read() << ") " << "{" << (p_vci_ini_rw.rtrdid.read() - (1<<(vci_param::T-1))) << "}" << std::endl; } #endif //CC_XCACHE_WRAPPER_DEBUG_FILE_TRANSACTION } else { switch (p_vci_ini_rw.rtrdid.read()) { case TYPE_INS_MISS : { r_vci_rsp_fsm = RSP_INS_MISS; #if CC_XCACHE_WRAPPER_DEBUG_FILE_TRANSACTION if (generate_log_transaction_file_cmd) { log_transaction_file_cmd << "[" << m_cpt_total_cycles << "] " << "RSP INS MISS " << "(" << p_vci_ini_rw.rpktid.read() << ") " << std::endl; } #endif //CC_XCACHE_WRAPPER_DEBUG_FILE_TRANSACTION break; } case TYPE_INS_UNC : { r_vci_rsp_fsm = RSP_INS_UNC; #if CC_XCACHE_WRAPPER_DEBUG_FILE_TRANSACTION if (generate_log_transaction_file_cmd) { log_transaction_file_cmd << "[" << m_cpt_total_cycles << "] " << "RSP INS UNC " << "(" << p_vci_ini_rw.rpktid.read() << ") " << std::endl; } #endif //CC_XCACHE_WRAPPER_DEBUG_FILE_TRANSACTION break; } case TYPE_DATA_MISS : { r_vci_rsp_fsm = RSP_DATA_MISS; #if CC_XCACHE_WRAPPER_DEBUG_FILE_TRANSACTION if (generate_log_transaction_file_cmd) { log_transaction_file_cmd << "[" << m_cpt_total_cycles << "] " << "RSP DATA MISS " << "(" << p_vci_ini_rw.rpktid.read() << ") " << std::endl; } #endif //CC_XCACHE_WRAPPER_DEBUG_FILE_TRANSACTION break; } case TYPE_DATA_UNC : { r_vci_rsp_fsm = RSP_DATA_UNC; #if CC_XCACHE_WRAPPER_DEBUG_FILE_TRANSACTION if (generate_log_transaction_file_cmd) { log_transaction_file_cmd << "[" << m_cpt_total_cycles << "] " << "RSP DATA UNC " << "(" << p_vci_ini_rw.rpktid.read() << ") " << std::endl; } #endif //CC_XCACHE_WRAPPER_DEBUG_FILE_TRANSACTION break; } case TYPE_DATA_SC : { r_vci_rsp_fsm = RSP_DATA_SC; #if CC_XCACHE_WRAPPER_DEBUG_FILE_TRANSACTION if (generate_log_transaction_file_cmd) { log_transaction_file_cmd << "[" << m_cpt_total_cycles << "] " << "RSP DATA SC " << "(" << p_vci_ini_rw.rpktid.read() << ") " << std::endl; } #endif //CC_XCACHE_WRAPPER_DEBUG_FILE_TRANSACTION break; } default : { ASSERT(false, "Unexpected response"); } } } r_vci_rsp_num_cache = p_vci_ini_rw.rpktid.read(); } break; case RSP_INS_MISS: m_cost_imiss_transaction++; PRINTF(" * rspval : %d / r_vci_rsp_fifo_icache_data.wok %d\n",(uint32_t)p_vci_ini_rw.rspval.read(),(uint32_t)r_vci_rsp_fifo_icache_data.wok()); if (p_vci_ini_rw.rspval.read() and r_vci_rsp_fifo_icache_data.wok()) { PRINTF(" * have rsp - r_vci_rsp_cpt : %d/%d\n",(uint32_t)r_vci_rsp_cpt.read(),(uint32_t)m_icache_words); PRINTF(" * ins : %x\n",(int)p_vci_ini_rw.rdata.read()); ASSERT( (r_vci_rsp_cpt.read() < m_icache_words), "The VCI response packet for instruction miss is too long" ); r_vci_rsp_cpt = r_vci_rsp_cpt.read() + 1; vci_rsp_fifo_icache_put = true, vci_rsp_fifo_icache_num_cache = r_vci_rsp_num_cache; vci_rsp_fifo_icache_data = p_vci_ini_rw.rdata.read(); if ( p_vci_ini_rw.reop.read() ) { PRINTF(" * have reop\n"); ASSERT( ((r_vci_rsp_cpt.read() == m_icache_words - 1) or (p_vci_ini_rw.rerror.read()&1) or (r_vci_rsp_ins_error[r_vci_rsp_num_cache].read()&0x1)), "The VCI response packet for instruction miss is too short"); r_vci_rsp_cpt = 0; r_vci_rsp_fsm = RSP_IDLE; } if ( (p_vci_ini_rw.rerror.read()&0x1) != vci_param::ERR_NORMAL ) r_vci_rsp_ins_error[r_vci_rsp_num_cache] = true; } break; case RSP_INS_UNC: m_cost_imiss_transaction++; if (p_vci_ini_rw.rspval.read() and r_vci_rsp_fifo_icache_data.wok()) { ASSERT(p_vci_ini_rw.reop.read(), "illegal VCI response packet for uncached instruction"); vci_rsp_fifo_icache_put = true, vci_rsp_fifo_icache_num_cache = r_vci_rsp_num_cache; vci_rsp_fifo_icache_data = p_vci_ini_rw.rdata.read(); r_vci_rsp_fsm = RSP_IDLE; if ( (p_vci_ini_rw.rerror.read()&0x1) != vci_param::ERR_NORMAL ) r_vci_rsp_ins_error[r_vci_rsp_num_cache] = true; } break; case RSP_DATA_MISS: m_cost_dmiss_transaction++; PRINTF(" * rspval : %d / r_vci_rsp_fifo_icache_data.wok %d\n",(uint32_t)p_vci_ini_rw.rspval.read(),(uint32_t)r_vci_rsp_fifo_dcache_data.wok()); if (p_vci_ini_rw.rspval.read() and r_vci_rsp_fifo_dcache_data.wok()) { PRINTF(" * have rsp - r_vci_rsp_cpt : %d/%d\n",(uint32_t)r_vci_rsp_cpt.read(),(uint32_t)m_icache_words); ASSERT(r_vci_rsp_cpt.read() < m_dcache_words, "illegal VCI response packet for data read miss"); r_vci_rsp_cpt = r_vci_rsp_cpt.read() + 1; vci_rsp_fifo_dcache_put = true, vci_rsp_fifo_dcache_num_cache = r_vci_rsp_num_cache; vci_rsp_fifo_dcache_data = p_vci_ini_rw.rdata.read(); if ( p_vci_ini_rw.reop.read() ) { ASSERT( ((r_vci_rsp_cpt.read() == m_dcache_words - 1) or (p_vci_ini_rw.rerror.read()&0x1) or r_vci_rsp_data_error[r_vci_rsp_num_cache].read()), "illegal VCI response packet for data read miss"); r_vci_rsp_cpt = 0; r_vci_rsp_fsm = RSP_IDLE; } if ( (p_vci_ini_rw.rerror.read()&0x1) != vci_param::ERR_NORMAL ) r_vci_rsp_data_error[r_vci_rsp_num_cache] = true; } break; case RSP_DATA_WRITE: m_cost_write_transaction++; if (p_vci_ini_rw.rspval.read()) { PRINTF(" * have rspval - error : %d\n",(int)p_vci_ini_rw.rerror.read()); ASSERT(p_vci_ini_rw.reop.read(), "A VCI response packet must contain one flit for a write transaction"); r_vci_rsp_fsm = RSP_IDLE; uint32_t wbuf_index = p_vci_ini_rw.rtrdid.read() - (1<<(vci_param::T-1)); size_t cpu_id = r_wbuf[r_vci_rsp_num_cache]->getCpuId (wbuf_index); bool cached = r_wbuf[r_vci_rsp_num_cache]->completed(wbuf_index); PRINTF(" * cached : %d\n",cached); if (not cached) r_dcache_previous_unc[r_vci_rsp_num_cache] = false; if ((p_vci_ini_rw.rerror.read()&0x1) != vci_param::ERR_NORMAL) m_iss[cpu_id]->setWriteBerr(); #if MWBUF_VHDL_TESTBENCH vhdl_mwbuf_port_completed_val [r_vci_rsp_num_cache] = (vhdl_tb_t)1; vhdl_mwbuf_port_completed_index [r_vci_rsp_num_cache] = (vhdl_tb_t)wbuf_index; vhdl_mwbuf_test_completed_cached [r_vci_rsp_num_cache] = (vhdl_tb_t)1; vhdl_mwbuf_port_completed_cached [r_vci_rsp_num_cache] = (vhdl_tb_t)cached; vhdl_mwbuf_test_completed_cpu_id [r_vci_rsp_num_cache] = (vhdl_tb_t)1; vhdl_mwbuf_port_completed_cpu_id [r_vci_rsp_num_cache] = (vhdl_tb_t)cpu_id; #endif } break; case RSP_DATA_UNC: m_cost_unc_transaction++; if (p_vci_ini_rw.rspval.read() and r_vci_rsp_fifo_dcache_data.wok()) { ASSERT(p_vci_ini_rw.reop.read(), "illegal VCI response packet for data read uncached"); vci_rsp_fifo_dcache_put = true, vci_rsp_fifo_dcache_num_cache = r_vci_rsp_num_cache; vci_rsp_fifo_dcache_data = p_vci_ini_rw.rdata.read(); r_vci_rsp_fsm = RSP_IDLE; r_dcache_previous_unc[r_vci_rsp_num_cache] = false; if ( (p_vci_ini_rw.rerror.read()&0x1) != vci_param::ERR_NORMAL ) r_vci_rsp_data_error[r_vci_rsp_num_cache] = true; } break; case RSP_DATA_SC: m_cost_unc_transaction++; if (p_vci_ini_rw.rspval.read() and r_vci_rsp_fifo_dcache_data.wok()) { ASSERT(p_vci_ini_rw.reop.read(), "illegal VCI response packet for data SC"); vci_rsp_fifo_dcache_put = true, vci_rsp_fifo_dcache_num_cache = r_vci_rsp_num_cache; vci_rsp_fifo_dcache_data = p_vci_ini_rw.rdata.read(); r_vci_rsp_fsm = RSP_IDLE; r_dcache_previous_unc[r_vci_rsp_num_cache] = false; if ( (p_vci_ini_rw.rerror.read()&0x1) != vci_param::ERR_NORMAL ) r_vci_rsp_data_error[r_vci_rsp_num_cache] = true; } break; } // end switch r_vci_rsp_fsm ////////////////////////////////////////////////////////////////////////// // FIFO_RSP ////////////////////////////////////////////////////////////////////////// r_vci_rsp_fifo_icache_data .update(vci_rsp_fifo_icache_get, vci_rsp_fifo_icache_put, vci_rsp_fifo_icache_data); r_vci_rsp_fifo_icache_num_cache.update(vci_rsp_fifo_icache_get, vci_rsp_fifo_icache_put, vci_rsp_fifo_icache_num_cache); r_vci_rsp_fifo_dcache_data .update(vci_rsp_fifo_dcache_get, vci_rsp_fifo_dcache_put, vci_rsp_fifo_dcache_data); r_vci_rsp_fifo_dcache_num_cache.update(vci_rsp_fifo_dcache_get, vci_rsp_fifo_dcache_put, vci_rsp_fifo_dcache_num_cache); #if MWBUF_VHDL_TESTBENCH for (uint32_t num_dcache=0; num_dcacheempty(); vhdl_testbench_mwbuf [num_dcache] << std::hex << vhdl_mwbuf_test_empty [num_dcache] << " " << vhdl_mwbuf_port_empty [num_dcache] << " " << vhdl_mwbuf_port_flush [num_dcache] << " " << vhdl_mwbuf_port_write_val [num_dcache] << " " << vhdl_mwbuf_test_write_ack [num_dcache] << " " << vhdl_mwbuf_port_write_ack [num_dcache] << " " << vhdl_mwbuf_port_write_addr [num_dcache] << " " << vhdl_mwbuf_port_write_data [num_dcache] << " " << vhdl_mwbuf_port_write_be [num_dcache] << " " << vhdl_mwbuf_port_write_cached [num_dcache] << " " << vhdl_mwbuf_port_write_cpu_id [num_dcache] << " " << vhdl_mwbuf_test_sent_val [num_dcache] << " " << vhdl_mwbuf_port_sent_val [num_dcache] << " " << vhdl_mwbuf_port_sent_ack [num_dcache] << " " << vhdl_mwbuf_test_sent_word_min [num_dcache] << " " << vhdl_mwbuf_port_sent_word_min [num_dcache] << " " << vhdl_mwbuf_test_sent_word_max [num_dcache] << " " << vhdl_mwbuf_port_sent_word_max [num_dcache] << " " << vhdl_mwbuf_port_sent_word [num_dcache] << " " << vhdl_mwbuf_test_sent_addr [num_dcache] << " " << vhdl_mwbuf_port_sent_addr [num_dcache] << " " << vhdl_mwbuf_test_sent_data [num_dcache] << " " << vhdl_mwbuf_port_sent_data [num_dcache] << " " << vhdl_mwbuf_test_sent_be [num_dcache] << " " << vhdl_mwbuf_port_sent_be [num_dcache] << " " << vhdl_mwbuf_test_sent_index [num_dcache] << " " << vhdl_mwbuf_port_sent_index [num_dcache] << " " << vhdl_mwbuf_port_raw_test [num_dcache] << " " << vhdl_mwbuf_port_raw_addr [num_dcache] << " " << vhdl_mwbuf_test_raw_miss [num_dcache] << " " << vhdl_mwbuf_port_raw_miss [num_dcache] << " " << vhdl_mwbuf_port_completed_val [num_dcache] << " " << vhdl_mwbuf_port_completed_index [num_dcache] << " " << vhdl_mwbuf_test_completed_cached [num_dcache] << " " << vhdl_mwbuf_port_completed_cached [num_dcache] << " " << vhdl_mwbuf_test_completed_cpu_id [num_dcache] << " " << vhdl_mwbuf_port_completed_cpu_id [num_dcache] << std::dec << std::endl; } #endif } // end transition() ////////////////////////////////////////////////////////////////////////////////// tmpl(void)::genMoore() ////////////////////////////////////////////////////////////////////////////////// { PRINTF("--------------------------------------------\n"); PRINTF(" * CC_XCACHE_WRAPPER \"%s\" genMoore - Time = %d\n",name().c_str(),(uint32_t)m_cpt_total_cycles); // VCI initiator response switch ( r_cleanup_fsm.read() ) { case CLEANUP_IDLE: p_vci_ini_c.rspack = false; p_vci_ini_c.cmdval = false; p_vci_ini_c.address = 0; p_vci_ini_c.wdata = 0; p_vci_ini_c.be = 0; p_vci_ini_c.plen = 0; p_vci_ini_c.cmd = vci_param::CMD_WRITE; p_vci_ini_c.trdid = 0; p_vci_ini_c.pktid = 0; p_vci_ini_c.srcid = 0; p_vci_ini_c.cons = false; p_vci_ini_c.wrap = false; p_vci_ini_c.contig = false; p_vci_ini_c.clen = 0; p_vci_ini_c.cfixed = false; p_vci_ini_c.eop = false; break; case CLEANUP_REQ: { addr_40 addr; if (r_cleanup_icache) { addr = r_icache_cleanup_line[r_cleanup_num_cache].read()< icache : %llx\n",(blob_t)addr); } else { addr = r_dcache_cleanup_line[r_cleanup_num_cache].read()< dcache : %llx\n",(blob_t)addr); } p_vci_ini_c.rspack = false; p_vci_ini_c.cmdval = true; p_vci_ini_c.address = addr; p_vci_ini_c.wdata = 0; p_vci_ini_c.be = 0xF; p_vci_ini_c.plen = 4; p_vci_ini_c.cmd = vci_param::CMD_WRITE; p_vci_ini_c.trdid = (r_cleanup_icache)?TYPE_INS_CLEANUP:TYPE_DATA_CLEANUP; p_vci_ini_c.pktid = (sc_dt::sc_uint)r_cleanup_num_cache; p_vci_ini_c.srcid = m_srcid_c; p_vci_ini_c.cons = false; p_vci_ini_c.wrap = false; p_vci_ini_c.contig = false; p_vci_ini_c.clen = 0; p_vci_ini_c.cfixed = false; p_vci_ini_c.eop = true; break; } case CLEANUP_RSP_DCACHE: p_vci_ini_c.rspack = true; p_vci_ini_c.cmdval = false; p_vci_ini_c.address = 0; p_vci_ini_c.wdata = 0; p_vci_ini_c.be = 0; p_vci_ini_c.plen = 0; p_vci_ini_c.cmd = vci_param::CMD_WRITE; p_vci_ini_c.trdid = 0; p_vci_ini_c.pktid = 0; p_vci_ini_c.srcid = 0; p_vci_ini_c.cons = false; p_vci_ini_c.wrap = false; p_vci_ini_c.contig = false; p_vci_ini_c.clen = 0; p_vci_ini_c.cfixed = false; p_vci_ini_c.eop = false; break; case CLEANUP_RSP_ICACHE: p_vci_ini_c.rspack = true; p_vci_ini_c.cmdval = false; p_vci_ini_c.address = 0; p_vci_ini_c.wdata = 0; p_vci_ini_c.be = 0; p_vci_ini_c.plen = 0; p_vci_ini_c.cmd = vci_param::CMD_WRITE; p_vci_ini_c.trdid = 0; p_vci_ini_c.pktid = 0; p_vci_ini_c.srcid = 0; p_vci_ini_c.cons = false; p_vci_ini_c.wrap = false; p_vci_ini_c.contig = false; p_vci_ini_c.clen = 0; p_vci_ini_c.cfixed = false; p_vci_ini_c.eop = false; break; } // end switch r_cleanup_fsm // VCI initiator command switch (r_vci_cmd_fsm.read() ) { case CMD_IDLE: { p_vci_ini_rw.cmdval = false; p_vci_ini_rw.address = 0; p_vci_ini_rw.wdata = 0; p_vci_ini_rw.be = 0; p_vci_ini_rw.plen = 0; p_vci_ini_rw.cmd = vci_param::CMD_NOP; p_vci_ini_rw.trdid = 0; p_vci_ini_rw.pktid = 0; p_vci_ini_rw.srcid = 0; p_vci_ini_rw.cons = false; p_vci_ini_rw.wrap = false; p_vci_ini_rw.contig = false; p_vci_ini_rw.clen = 0; p_vci_ini_rw.cfixed = false; p_vci_ini_rw.eop = false; break; } case CMD_DATA_UNC: { p_vci_ini_rw.cmdval = true; addr_40 addr = (addr_40) r_dcache_addr_save[r_vci_cmd_num_cache].read() & ~0x3; set_num_dcache(addr,r_vci_cmd_num_cache); PRINTF(" * DATA_UNC : %d - %llx\n",(uint32_t)r_vci_cmd_num_cache,(blob_t)(addr)); p_vci_ini_rw.address = addr; switch( r_dcache_type_save[r_vci_cmd_num_cache] ) { case iss_t::DATA_READ: p_vci_ini_rw.wdata = 0; p_vci_ini_rw.be = r_dcache_be_save[r_vci_cmd_num_cache].read(); p_vci_ini_rw.cmd = vci_param::CMD_READ; break; case iss_t::DATA_LL: p_vci_ini_rw.wdata = 0; p_vci_ini_rw.be = 0xF; p_vci_ini_rw.cmd = vci_param::CMD_LOCKED_READ; break; default: ASSERT(false,"this should not happen"); } p_vci_ini_rw.plen = 4; p_vci_ini_rw.trdid = TYPE_DATA_UNC; // data cache uncached read p_vci_ini_rw.pktid = (sc_dt::sc_uint)r_vci_cmd_num_cache; p_vci_ini_rw.srcid = m_srcid_rw; p_vci_ini_rw.cons = false; p_vci_ini_rw.wrap = false; p_vci_ini_rw.contig = true; p_vci_ini_rw.clen = 0; p_vci_ini_rw.cfixed = false; p_vci_ini_rw.eop = true; break; } case CMD_DATA_SC: { p_vci_ini_rw.cmdval = true; addr_40 addr = (addr_40) r_dcache_addr_save[r_vci_cmd_num_cache].read() & ~0x3; set_num_dcache(addr,r_vci_cmd_num_cache); PRINTF(" * DATA_SC : %d - %llx\n",(uint32_t)r_vci_cmd_num_cache,(blob_t)(addr)); p_vci_ini_rw.address = addr; if(r_vci_cmd_max.read() == 3){ ASSERT(false, "Not handled yet"); } else { // r_vci_cmd_cpt == 1 switch(r_vci_cmd_cpt.read()){ case 0: p_vci_ini_rw.wdata = (uint32_t)(r_dcache_ll_data[r_vci_cmd_num_cache][r_dcache_num_cpu_save[r_vci_cmd_num_cache]].read() & 0xFFFFFFFF); break; case 1: p_vci_ini_rw.wdata = r_dcache_wdata_save[r_vci_cmd_num_cache].read(); break; } } p_vci_ini_rw.be = 0xF; p_vci_ini_rw.cmd = vci_param::CMD_STORE_COND; p_vci_ini_rw.plen = 4*(r_vci_cmd_max.read()+1); p_vci_ini_rw.trdid = TYPE_DATA_SC; // data cache uncached read p_vci_ini_rw.pktid = (sc_dt::sc_uint)r_vci_cmd_num_cache; p_vci_ini_rw.srcid = m_srcid_rw; p_vci_ini_rw.cons = true; p_vci_ini_rw.wrap = false; p_vci_ini_rw.contig = false; p_vci_ini_rw.clen = 0; p_vci_ini_rw.cfixed = false; p_vci_ini_rw.eop = (r_vci_cmd_cpt.read() == r_vci_cmd_max.read()); break; } case CMD_DATA_WRITE: { p_vci_ini_rw.cmdval = true; addr_40 addr = (addr_40) r_wbuf[r_vci_cmd_num_cache]->getAddress(r_vci_cmd_cpt)&~0x3; PRINTF(" * DATA_WRITE : %d - %llx\n",(uint32_t)r_vci_cmd_num_cache,(blob_t)(addr)); p_vci_ini_rw.address = addr; p_vci_ini_rw.wdata = r_wbuf[r_vci_cmd_num_cache]->getData(r_vci_cmd_cpt); p_vci_ini_rw.be = r_wbuf[r_vci_cmd_num_cache]->getBe(r_vci_cmd_cpt); p_vci_ini_rw.plen = (r_vci_cmd_max - r_vci_cmd_min + 1)<<2; p_vci_ini_rw.cmd = vci_param::CMD_WRITE; p_vci_ini_rw.trdid = r_wbuf[r_vci_cmd_num_cache]->getIndex() + (1<<(vci_param::T-1)); p_vci_ini_rw.pktid = (sc_dt::sc_uint)r_vci_cmd_num_cache; p_vci_ini_rw.srcid = m_srcid_rw; p_vci_ini_rw.cons = false; p_vci_ini_rw.wrap = false; p_vci_ini_rw.contig = true; p_vci_ini_rw.clen = 0; p_vci_ini_rw.cfixed = false; p_vci_ini_rw.eop = (r_vci_cmd_cpt == r_vci_cmd_max); break; } case CMD_DATA_MISS: { p_vci_ini_rw.cmdval = true; addr_40 addr = r_dcache_addr_save[r_vci_cmd_num_cache].read() & (addr_40) m_dcache_yzmask; set_num_dcache(addr,r_vci_cmd_num_cache); PRINTF(" * DATA_MISS : %d - %llx\n",(uint32_t)r_vci_cmd_num_cache,(blob_t)(addr)); p_vci_ini_rw.address = addr; p_vci_ini_rw.be = 0xF; p_vci_ini_rw.plen = m_dcache_words << 2; p_vci_ini_rw.cmd = vci_param::CMD_READ; p_vci_ini_rw.trdid = TYPE_DATA_MISS; // data cache cached read p_vci_ini_rw.pktid = (sc_dt::sc_uint)r_vci_cmd_num_cache; p_vci_ini_rw.srcid = m_srcid_rw; p_vci_ini_rw.cons = false; p_vci_ini_rw.wrap = false; p_vci_ini_rw.contig = true; p_vci_ini_rw.clen = 0; p_vci_ini_rw.cfixed = false; p_vci_ini_rw.eop = true; break; } case CMD_INS_MISS: { p_vci_ini_rw.cmdval = true; addr_40 addr = r_icache_addr_save[r_vci_cmd_num_cache].read() & (addr_40) m_icache_yzmask; set_num_icache(addr,r_vci_cmd_num_cache); PRINTF(" * INS_MISS : %d - %llx\n",(uint32_t)r_vci_cmd_num_cache,(blob_t)(addr)); p_vci_ini_rw.address = addr; p_vci_ini_rw.be = 0xF; p_vci_ini_rw.plen = m_icache_words << 2; p_vci_ini_rw.cmd = vci_param::CMD_READ; p_vci_ini_rw.trdid = TYPE_INS_MISS; // ins cache cached read p_vci_ini_rw.pktid = (sc_dt::sc_uint)r_vci_cmd_num_cache; p_vci_ini_rw.srcid = m_srcid_rw; p_vci_ini_rw.cons = false; p_vci_ini_rw.wrap = false; p_vci_ini_rw.contig = true; p_vci_ini_rw.clen = 0; p_vci_ini_rw.cfixed = false; p_vci_ini_rw.eop = true; break; } case CMD_INS_UNC: { p_vci_ini_rw.cmdval = true; addr_40 addr = r_icache_addr_save[r_vci_cmd_num_cache].read() & ~0x3; set_num_icache(addr,r_vci_cmd_num_cache); PRINTF(" * INS_UNC : %d - %llx\n",(uint32_t)r_vci_cmd_num_cache,(blob_t)(addr)); p_vci_ini_rw.address = addr; p_vci_ini_rw.be = 0xF; p_vci_ini_rw.plen = 4; p_vci_ini_rw.cmd = vci_param::CMD_READ; p_vci_ini_rw.trdid = TYPE_INS_UNC; // ins cache uncached read p_vci_ini_rw.pktid = (sc_dt::sc_uint)r_vci_cmd_num_cache; p_vci_ini_rw.srcid = m_srcid_rw; p_vci_ini_rw.cons = false; p_vci_ini_rw.wrap = false; p_vci_ini_rw.contig = true; p_vci_ini_rw.clen = 0; p_vci_ini_rw.cfixed = false; p_vci_ini_rw.eop = true; break; } } // end switch r_vci_cmd_fsm switch (r_vci_rsp_fsm.read() ) { case RSP_DATA_WRITE : p_vci_ini_rw.rspack = true; break; case RSP_INS_MISS : case RSP_INS_UNC : p_vci_ini_rw.rspack = r_vci_rsp_fifo_icache_data.wok(); break; case RSP_DATA_MISS : case RSP_DATA_UNC : case RSP_DATA_SC : p_vci_ini_rw.rspack = r_vci_rsp_fifo_dcache_data.wok(); break; case RSP_IDLE : default : p_vci_ini_rw.rspack = false; break; } // end switch r_vci_rsp_fsm // VCI_TGT // PRINTF(" * srcid : %d\n", r_tgt_srcid.read()); switch ( r_vci_tgt_fsm.read() ) { case TGT_IDLE: case TGT_UPDT_WORD: case TGT_UPDT_DATA: p_vci_tgt.cmdack = true; p_vci_tgt.rspval = false; break; case TGT_RSP_BROADCAST: { bool tgt_icache_req; bool tgt_icache_rsp; #if (CC_XCACHE_WRAPPER_MULTI_CACHE==1) tgt_icache_req = r_tgt_icache_req[r_tgt_num_cache].read(); tgt_icache_rsp = r_tgt_icache_rsp[r_tgt_num_cache].read(); #elif (CC_XCACHE_WRAPPER_MULTI_CACHE==2) tgt_icache_req = false; tgt_icache_rsp = false; for (uint32_t num_cache=0; num_cache RSP_BROADCAST : rspval : %d (i %d %d, d %d %d)\n",rspval,tgt_icache_req,tgt_icache_rsp, r_tgt_dcache_req[r_tgt_num_cache].read(), r_tgt_dcache_rsp[r_tgt_num_cache].read()); p_vci_tgt.cmdack = false; p_vci_tgt.rspval = rspval; p_vci_tgt.rsrcid = r_tgt_srcid.read(); p_vci_tgt.rpktid = r_tgt_pktid.read(); p_vci_tgt.rtrdid = r_tgt_trdid.read(); p_vci_tgt.rdata = 0; p_vci_tgt.rerror = 0x2 & ( (1 << vci_param::E) - 1); // Write OK p_vci_tgt.reop = true; break; } case TGT_RSP_ICACHE: { bool rspval = not r_tgt_icache_req[r_tgt_num_cache].read() and r_tgt_icache_rsp[r_tgt_num_cache].read(); PRINTF(" * RSP_ICACHE : rspval : %d\n",rspval); p_vci_tgt.cmdack = false; p_vci_tgt.rspval = rspval; p_vci_tgt.rsrcid = r_tgt_srcid.read(); p_vci_tgt.rpktid = r_tgt_pktid.read(); p_vci_tgt.rtrdid = r_tgt_trdid.read(); p_vci_tgt.rdata = 0; p_vci_tgt.rerror = 0x2 & ( (1 << vci_param::E) - 1); // Write OK p_vci_tgt.reop = true; break; } case TGT_RSP_DCACHE: { bool rspval = not r_tgt_dcache_req[r_tgt_num_cache].read() and r_tgt_dcache_rsp[r_tgt_num_cache].read(); PRINTF(" * RSP_DCACHE : rspval : %d\n",rspval); p_vci_tgt.cmdack = false; p_vci_tgt.rspval = rspval; p_vci_tgt.rsrcid = r_tgt_srcid.read(); p_vci_tgt.rpktid = r_tgt_pktid.read(); p_vci_tgt.rtrdid = r_tgt_trdid.read(); p_vci_tgt.rdata = 0; p_vci_tgt.rerror = 0x2 & ( (1 << vci_param::E) - 1); // Write OK p_vci_tgt.reop = true; break; } case TGT_REQ_BROADCAST: case TGT_REQ_ICACHE: case TGT_REQ_DCACHE: p_vci_tgt.cmdack = false; p_vci_tgt.rspval = false; break; } // end switch TGT_FSM } // end genMoore() ////////////////////////////////////////////////////////////////////////////////// tmpl(void)::stop_simulation (uint32_t nb_frz_cycles) ////////////////////////////////////////////////////////////////////////////////// { #if CC_XCACHE_WRAPPER_STOP_SIMULATION if (nb_frz_cycles == 0) { PRINTF("CC_XCACHE_WRAPPER \"%s\" : don't stop the simulation.\n",name().c_str()); m_stop_simulation = false; } else { PRINTF("CC_XCACHE_WRAPPER \"%s\" : stop the simulation after %d cycles.\n",name().c_str(),nb_frz_cycles); m_stop_simulation = true; m_stop_simulation_nb_frz_cycles_max = nb_frz_cycles; } #else std::cout << "CC_XCACHE_WRAPPER \"" << name() << "\" : flag CC_XCACHE_WRAPPER_STOP_SIMULATION is unset, you can't use stop_simulation." << std::endl; #endif // CC_XCACHE_WRAPPER_STOP_SIMULATION } ////////////////////////////////////////////////////////////////////////////////// tmpl(void)::log_transaction ( bool generate_file_icache ,bool generate_file_dcache ,bool generate_file_cmd ,bool generate_file_tgt ,bool generate_file_cleanup) ////////////////////////////////////////////////////////////////////////////////// { #if CC_XCACHE_WRAPPER_DEBUG_FILE_TRANSACTION generate_log_transaction_file_icache = generate_file_icache ; generate_log_transaction_file_dcache = generate_file_dcache ; generate_log_transaction_file_cmd = generate_file_cmd ; generate_log_transaction_file_tgt = generate_file_tgt ; generate_log_transaction_file_cleanup = generate_file_cleanup; #else std::cout << "CC_XCACHE_WRAPPER \"" << name() << "\" : flag CC_XCACHE_WRAPPER_DEBUG_FILE_TRANSACTION is unset, you can't use log_transaction." << std::endl; #endif // CC_XCACHE_WRAPPER_STOP_SIMULATION } ////////////////////////////////////////////////////////////////////////////////// tmpl(void)::vhdl_testbench (bool generate_file_mwbuf) ////////////////////////////////////////////////////////////////////////////////// { #if MWBUF_VHDL_TESTBENCH if (simulation_started) std::cout << "CC_XCACHE_WRAPPER \"" << name() << "\" : Simulation is starting, you can't use vhdl_testbench." << std::endl; else generate_vhdl_testbench_mwbuf = generate_file_mwbuf; #else std::cout << "CC_XCACHE_WRAPPER \"" << name() << "\" : flag MWBUF_VHDL_TESTBENCH is unset, you can't use vhdl_testbench." << std::endl; #endif // CC_XCACHE_WRAPPER_STOP_SIMULATION } ////////////////////////////////////////////////////////////////////////////////// tmpl(uint32_t)::get_num_cache(addr_40 & addr) ////////////////////////////////////////////////////////////////////////////////// { uint32_t num_cache = get_num_cache_only(addr); addr = ((addr&m_num_cache_LSB_mask) | // keep LSB ((addr>>m_num_cache_MSB)<>m_num_cache_LSB)&m_num_cache_mask; } ////////////////////////////////////////////////////////////////////////////////// tmpl(void)::set_num_cache(addr_40 & addr, uint32_t num_cache) ////////////////////////////////////////////////////////////////////////////////// { addr = ((addr&m_num_cache_LSB_mask) | // keep LSB ((addr_40)num_cache << m_num_cache_LSB) | ((addr>>m_num_cache_LSB)<)::set_num_cache_only(addr_40 addr, uint32_t num_cache) ////////////////////////////////////////////////////////////////////////////////// { return ((addr&m_num_cache_LSB_mask) | // keep LSB ((addr_40)num_cache << m_num_cache_LSB) | ((addr>>m_num_cache_LSB)<