/* -*- 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" // =====[ 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 // =====[ FIFO_RSP ]================================= #if (CC_XCACHE_WRAPPER_FIFO_RSP==1) # define CACHE_MISS_BUF_ALLOC do { \ r_icache_miss_buf = new std::queue [m_nb_icache]; \ r_dcache_miss_buf = new std::queue [m_nb_dcache]; \ } while (0) # define CACHE_MISS_BUF_DEALLOC do { \ delete [] r_icache_miss_buf; \ delete [] r_dcache_miss_buf; \ } while (0) # define CACHE_MISS_BUF_RESET(c) do { \ for (uint32_t x=0; x0) { \ r_##c##cache_miss_buf[x].pop(); \ } \ } \ } while (0) # define CACHE_MISS_BUF_REQ_INIT(c,x) # define CACHE_MISS_BUF_RSP_VAL(c,x,n) (r_##c##cache_miss_buf[x].size()>0) # define CACHE_MISS_BUF_RSP_ACK(c,x) (r_##c##cache_miss_buf[x].size()<2) # define CACHE_MISS_BUF_RSP_DATA(c,x,n) r_##c##cache_miss_buf[x].front() # define CACHE_MISS_BUF_RSP_POP(c,x) do { \ r_##c##cache_miss_buf[x].pop(); \ } while (0) # define CACHE_MISS_BUF_RSP_PUSH(c,x,n,d) do { \ r_##c##cache_miss_buf[x].push(d); \ } while (0) # define CACHE_MISS_BUF_RSP_PRINT(c) do { \ for (uint32_t x=0; x0) { \ r_##c##cache_miss_buf.pop(); \ } \ } while (0) # define CACHE_MISS_BUF_REQ_INIT(c,x) # define CACHE_MISS_BUF_RSP_VAL(c,x,n) ((r_##c##cache_miss_buf.size()>0) and (r_##c##cache_miss_buf.front().num_cache==x)) # define CACHE_MISS_BUF_RSP_ACK(c,x) (r_##c##cache_miss_buf.size()<2) # define CACHE_MISS_BUF_RSP_DATA(c,x,n) r_##c##cache_miss_buf.front().data # define CACHE_MISS_BUF_RSP_POP(c,x) do { \ r_##c##cache_miss_buf.pop(); \ } while (0) # define CACHE_MISS_BUF_RSP_PUSH(c,x,n,d) do { \ miss_buf_t miss_buf; \ miss_buf.data = d; \ miss_buf.num_cache = x; \ r_##c##cache_miss_buf.push(miss_buf); \ } while (0) # define CACHE_MISS_BUF_RSP_PRINT(c) do { \ PRINTF(" * cache_miss_buf - size : %d\n",r_##c##cache_miss_buf.size()); \ } while (0) #else # define CACHE_MISS_BUF_ALLOC do { \ r_icache_miss_val = new bool * [m_nb_icache]; \ r_icache_miss_buf = new data_t * [m_nb_icache]; \ for (uint32_t x=0; x __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, size_t wbuf_timeout ) : 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 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); } CACHE_MISS_BUF_ALLOC; 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_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_num_cpu_save = 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_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 Parameters :" << std::endl; std::cout << " * nb_cpu : " << nb_cpu << std::endl; std::cout << " * nb_cache : " << m_nb_icache << " icache(s), " << m_nb_dcache << " dcache(s)" << std::endl; std::cout << " * icache (total) : " << icache_ways << " way(s), " << icache_sets << " set(s), " << icache_words << " word(s)" << std::endl; std::cout << " * icache (per cache) : " << _icache_ways << " way(s), " << _icache_sets << " set(s), " << _icache_words << " word(s)" << std::endl; std::cout << " * dcache (total) : " << dcache_ways << " way(s), " << dcache_sets << " set(s), " << dcache_words << " word(s)" << std::endl; std::cout << " * dcache (per cache) : " << _dcache_ways << " way(s), " << _dcache_sets << " set(s), " << _dcache_words << " word(s)" << std::endl; std::cout << " * wbuf (total) : " << wbuf_nlines << " line(s), " << wbuf_nwords << " word(s), timeout : " << wbuf_timeout << std::endl; std::cout << " * wbuf (per cache) : " << _wbuf_nlines << " line(s), " << _wbuf_nwords << " word(s), timeout : " << _wbuf_timeout << std::endl; #endif r_icache = new GenericCache * [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, _wbuf_timeout, _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() ////////////////////////// { 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 } // CACHE_MISS_BUF_RSP_PRINT(i); // CACHE_MISS_BUF_RSP_PRINT(d); 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 { 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 { 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 { 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 { 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 { 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); } #ifdef COHERENCE_DEBUG std::cout << "PROC " << m_srcid_rw << " update, data : " << p_vci_tgt.wdata.read() << " be : " << std::hex << p_vci_tgt.be.read() << std::dec << std::endl; #endif 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()){ #if CC_XCACHE_WRAPPER_CC_UPDATE_MULTI_CYCLE_OPT 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); // test if already used if (not ireq[num_cache].valid and (r_icache_lock [num_cache] == m_nb_cpu) or (r_icache_lock [num_cache] == num_cpu)) { 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); // test if already used if (not dreq[num_cache].valid and not have_sync and (r_dcache_lock [num_cache] == m_nb_cpu) or (r_dcache_lock [num_cache] == num_cpu)) { 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; 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 icache_miss_buf icache_hit = (r_icache_buf_unc_valid[num_cache] and ((addr_40) _ireq.addr == (addr_40)r_icache_addr_save[num_cache])); icache_ins = CACHE_MISS_BUF_RSP_DATA(i,num_cache,0); if (icache_hit) CACHE_MISS_BUF_RSP_POP(i,num_cache); } PRINTF(" * hit %d - cached %d - cleanup_hit %d\n",num_cache, icache_hit, icache_cached, icache_cleanup_hit); // ASSERT( not (icache_hit and icache_cleanup_hit), // "Icache hit and 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; CACHE_MISS_BUF_REQ_INIT(i,num_cache); if ( icache_cached ) { r_icache_fsm [num_cache] = ICACHE_MISS_VICTIM; r_icache_miss_req[num_cache] = true; } else { r_icache_fsm [num_cache] = ICACHE_UNC_WAIT; r_icache_unc_req[num_cache] = true; } } else { 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 = CACHE_MISS_BUF_RSP_VAL(i,num_cache,0); 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 = CACHE_MISS_BUF_RSP_VAL(i,num_cache,0); 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 = CACHE_MISS_BUF_RSP_VAL(i,num_cache,word); 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)CACHE_MISS_BUF_RSP_DATA(i,num_cache,word)); // 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, CACHE_MISS_BUF_RSP_DATA(i,num_cache,word)); CACHE_MISS_BUF_RSP_POP(i,num_cache); 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; data_t icache_rdata = 0; 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 { bool icache_hit = r_icache[num_cache]->read(ad, &icache_rdata); PRINTF(" * have no request, hit cache : %d\n",num_cache,icache_hit); if ( icache_hit and r_tgt_update) { #if CC_XCACHE_WRAPPER_CC_UPDATE_MULTI_CYCLE uint32_t word = r_cache_word; data_t mask = vci_param::be2mask(r_tgt_be[word]); data_t rdata = 0; r_icache[num_cache]->read(ad+word*4,&rdata); r_tgt_buf[word] = (mask & r_tgt_buf[word]) | (~mask & rdata); word ++; #if CC_XCACHE_WRAPPER_CC_UPDATE_MULTI_CYCLE_OPT for (; wordread(ad + i*4,&rdata); data_t mask = vci_param::be2mask(r_tgt_be[i]); r_tgt_buf[i] = (mask & r_tgt_buf[i]) | (~mask & rdata); } #endif //CC_XCACHE_WRAPPER_CC_UPDATE_MULTI_CYCLE } else if ( icache_hit and not r_tgt_update) { r_icache_fsm[num_cache] = ICACHE_CC_INVAL; } else { // instruction not found (can happen) r_tgt_icache_req[num_cache] = false; if(r_tgt_update){ r_tgt_icache_rsp[num_cache] = true; } else { r_tgt_icache_rsp[num_cache] = false; } r_icache_fsm[num_cache] = r_icache_fsm_save[num_cache]; } } break; } ///////////////////// case ICACHE_CC_INVAL: { addr_40 ad = r_tgt_iaddr; // if ( _ireq.valid ) m_cost_ins_miss_frz++; m_cpt_icache_dir_read += m_icache_ways; r_tgt_icache_rsp[num_cache] = true; r_icache[num_cache]->inval(ad); r_tgt_icache_req[num_cache] = false; r_icache_fsm [num_cache] = r_icache_fsm_save[num_cache]; break; } ///////////////////// case ICACHE_CC_UPDT: { addr_40 ad = r_tgt_iaddr.read(); m_cpt_icache_dir_write++; m_cpt_icache_data_write++; #if CC_XCACHE_WRAPPER_CC_UPDATE_MULTI_CYCLE uint32_t word = r_cache_word; if(r_tgt_be[word]) r_icache[num_cache]->write(ad+word*4, r_tgt_buf[word]); word ++; #if CC_XCACHE_WRAPPER_CC_UPDATE_MULTI_CYCLE_OPT for (; wordwrite( ad + i*4, buf[i]); } r_tgt_icache_req [num_cache] = false; r_tgt_icache_rsp [num_cache] = true; r_icache_fsm [num_cache] = r_icache_fsm_save[num_cache].read(); #endif //CC_XCACHE_WRAPPER_CC_UPDATE_MULTI_CYCLE 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; #ifdef COHERENCE_DEBUG std::cout << "Value returned for LL at address : " << std::hex << _dreq.addr << " data : " << std::dec << dcache_rdata<< std::endl; r_dcache[num_cache]->read((vci_addr_t) _dreq.addr, &dcache_rdata); std::cout << "Value stored at this address : " << std::hex << _dreq.addr << " data : " << std::dec << dcache_rdata<< std::endl; #endif } } else { if (not dcache_cleanup_hit) { CACHE_MISS_BUF_REQ_INIT(d,num_cache); // Miss : send signal at the CMD_FSM (via r_dcache_miss_req or r_dcache_unc_req) if ( dcache_cached ) { 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 { 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; CACHE_MISS_BUF_REQ_INIT(d,num_cache); 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); PRINTF(" * r_wbuf valid : %d\n",num_cache,valid); if (valid) { 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 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); r_dcache_fsm [num_cache] = DCACHE_IDLE; 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: { // 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 = CACHE_MISS_BUF_RSP_VAL(d,num_cache,0); 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); if (CACHE_MISS_BUF_RSP_VAL(d,num_cache,word)) { // 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, CACHE_MISS_BUF_RSP_DATA(d,num_cache,word)); m_cpt_dcache_data_write++; } CACHE_MISS_BUF_RSP_POP(d,num_cache); 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 = CACHE_MISS_BUF_RSP_VAL(d,num_cache,0); if (ok) { if (r_vci_rsp_data_error[num_cache]) { r_dcache_fsm[num_cache] = DCACHE_ERROR; } else { data_t rdata = CACHE_MISS_BUF_RSP_DATA(d,num_cache,0); CACHE_MISS_BUF_RSP_POP(d,num_cache); 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 = CACHE_MISS_BUF_RSP_VAL(d,num_cache,0); 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 = CACHE_MISS_BUF_RSP_DATA(d,num_cache,0); CACHE_MISS_BUF_RSP_POP(d,num_cache); 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; data_t dcache_rdata = 0; 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 { bool dcache_hit = r_dcache[num_cache]->read(ad, &dcache_rdata); PRINTF(" * have no request, hit cache : %d, update : %d\n",num_cache,dcache_hit,(uint32_t)r_tgt_update); m_cpt_dcache_data_read += m_dcache_ways; m_cpt_dcache_dir_read += m_dcache_ways; #ifdef COHERENCE_DEBUG std::cout << "PROC " << m_srcid_rw << " DCACHE_CC_CHECK, hit ? : " << dcache_hit << std::endl; #endif if ( dcache_hit and r_tgt_update ) { #if CC_XCACHE_WRAPPER_CC_UPDATE_MULTI_CYCLE uint32_t word = r_cache_word; data_t mask = vci_param::be2mask(r_tgt_be[word]); data_t rdata = 0; r_dcache[num_cache]->read(ad+word*4,&rdata); r_tgt_buf[word] = (mask & r_tgt_buf[word]) | (~mask & rdata); word ++; #if CC_XCACHE_WRAPPER_CC_UPDATE_MULTI_CYCLE_OPT for (; wordread(ad + i*4,&rdata); data_t mask = vci_param::be2mask(r_tgt_be[i]); r_tgt_buf[i] = (mask & r_tgt_buf[i]) | (~mask & rdata); } r_dcache_fsm[num_cache] = DCACHE_CC_UPDT; #endif //CC_XCACHE_WRAPPER_CC_UPDATE_MULTI_CYCLE } else if ( dcache_hit and not r_tgt_update ) { r_dcache_fsm[num_cache] = DCACHE_CC_INVAL; } else { if(r_tgt_update){ r_tgt_dcache_rsp[num_cache] = true; } else { r_tgt_dcache_rsp[num_cache] = false; } r_tgt_dcache_req[num_cache] = false; r_dcache_fsm [num_cache] = r_dcache_fsm_save[num_cache]; } } break; } /////////////////// case DCACHE_CC_UPDT: // update directory and data cache { addr_40 ad = r_tgt_daddr; m_cpt_dcache_dir_write++; m_cpt_dcache_data_write++; # ifdef COHERENCE_DEBUG std::cout << "PROC " << m_srcid_rw << " DCACHE_CC_UPDT, update : " << std::endl; # endif #if CC_XCACHE_WRAPPER_CC_UPDATE_MULTI_CYCLE uint32_t word = r_cache_word; if(r_tgt_be[word]) r_dcache[num_cache]->write(ad+word*4, r_tgt_buf[word]); # ifdef COHERENCE_DEBUG std::cout << " address " << std::hex << ad+word*4 << " data " << std::dec << r_tgt_buf[word] << std::endl; data_t rdata = 0xAAAAAAAA; r_dcache[num_cache]->read(ad+word*4,&rdata); std::cout << "data written " << rdata << std::endl; # endif word ++; #if CC_XCACHE_WRAPPER_CC_UPDATE_MULTI_CYCLE_OPT for (; wordwrite( ad + i*4, buf[i]); # ifdef COHERENCE_DEBUG std::cout << " address " << std::hex << ad+i*4 << " data " << std::dec << buf[i] << std::endl; data_t rdata = 0xAAAAAAAA; r_dcache[num_cache]->read(ad + i*4,&rdata); std::cout << "data written " << rdata << std::endl; # endif //CC_XCACHE_WRAPPER_CC_UPDATE_MULTI_CYCLE } } r_tgt_dcache_req[num_cache] = false; r_tgt_dcache_rsp[num_cache] = true; r_dcache_fsm [num_cache] = r_dcache_fsm_save[num_cache]; #endif break; } ///////////////////// case DCACHE_CC_INVAL: // invalidate a cache line { addr_40 ad = r_tgt_daddr; r_tgt_dcache_rsp[num_cache] = true; r_dcache [num_cache]->inval(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 // bool have_sync=(r_dcache_fsm[num_cache] == DCACHE_SYNC); #if (CC_XCACHE_WRAPPER_WBUF_UPDATE_SCHEME==1) r_wbuf[num_cache]->update_multi_scan (have_sync); #elif (CC_XCACHE_WRAPPER_WBUF_UPDATE_SCHEME==2) r_wbuf[num_cache]->update_round_robin_scan(have_sync); #elif (CC_XCACHE_WRAPPER_WBUF_UPDATE_SCHEME==3) r_wbuf[num_cache]->update_one_scan (have_sync); #else r_wbuf[num_cache]->update (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 (_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 (_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() == 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() == 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"). ////////////////////////////////////////////////////////////////////////////// r_vci_cmd_dcache_prior = not r_vci_cmd_dcache_prior; switch (r_vci_cmd_fsm) { case CMD_IDLE: { // if (r_vci_rsp_fsm != RSP_IDLE) break; 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 r_vci_cmd_cpt = 0; // 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 = 0; uint32_t icache_miss_num_cache = 0; addr_40 addr = 0; { for (; dcache_miss_num_cache icache_miss_req (before) : %d\n",icache_miss_req); PRINTF(" * dcache_miss_req (before) : %d\n",dcache_miss_req); #if (CC_XCACHE_WRAPPER_VCI_CMD_PRIORITY==1) // 1) one access with static priority (dcache prior) icache_miss_req &= not dcache_miss_req; #elif (CC_XCACHE_WRAPPER_VCI_CMD_PRIORITY==2) // 2) one access with static priority (icache prior) dcache_miss_req &= not icache_miss_req; #elif (CC_XCACHE_WRAPPER_VCI_CMD_PRIORITY==3) // 3) 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; // #elif (CC_XCACHE_WRAPPER_VCI_CMD_PRIORITY==4) // // 4) two access authorized // dcache_miss_req = r_dcache_miss_req[cache_miss_num_cache]; // icache_miss_req = r_icache_miss_req[cache_miss_num_cache]; #else #error "Invalid value to CC_XCACHE_WRAPPER_VCI_CMD_PRIORITY" #endif 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 dcache_unc_num_cache = 0; for (; dcache_unc_num_cachedebug_rok(&wbuf_min, &wbuf_max, &wbuf_addr, &wbuf_index)) break; #else if ( r_wbuf[dcache_write_num_cache]->rok(&wbuf_min, &wbuf_max)) break; #endif } // 1 - Data Read if (dcache_miss_req and r_wbuf[dcache_miss_num_cache]->miss(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 { 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 { 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 (icache_miss_req and r_wbuf[icache_miss_num_cache]->miss(addr)) //else if (icache_miss_req and r_wbuf[dcache_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 { 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 { 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 { 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_max = 1; m_cpt_unc_transaction++; r_dcache_sc_req[dcache_sc_num_cache] = false; #if CC_XCACHE_WRAPPER_DEBUG_FILE_TRANSACTION { 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() ) { 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() ; } } 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_icache_miss_buf[m_icache_words] // - r_dcache_miss_buf[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 { 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 { 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 { 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 { 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 { 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 { 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/ack : %d - %d\n",(uint32_t)p_vci_ini_rw.rspval.read(), (uint32_t)s_vci_rsp_ack); if (p_vci_ini_rw.rspval.read() and s_vci_rsp_ack) { 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 < m_icache_words), "The VCI response packet for instruction miss is too long" ); r_vci_rsp_cpt = r_vci_rsp_cpt + 1; CACHE_MISS_BUF_RSP_PUSH(i,r_vci_rsp_num_cache,r_vci_rsp_cpt,(data_t)p_vci_ini_rw.rdata.read()); if ( p_vci_ini_rw.reop.read() ) { PRINTF(" * have reop\n"); ASSERT( ((r_vci_rsp_cpt == m_icache_words - 1) or p_vci_ini_rw.rerror.read() 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 s_vci_rsp_ack) { ASSERT(p_vci_ini_rw.reop.read(), "illegal VCI response packet for uncached instruction"); CACHE_MISS_BUF_RSP_PUSH(i,r_vci_rsp_num_cache,0,(data_t)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++; if (p_vci_ini_rw.rspval.read() and s_vci_rsp_ack) { PRINTF(" * have rspval - error : %d\n",(int)p_vci_ini_rw.rerror.read()); ASSERT(r_vci_rsp_cpt < m_dcache_words, "illegal VCI response packet for data read miss"); r_vci_rsp_cpt = r_vci_rsp_cpt + 1; CACHE_MISS_BUF_RSP_PUSH(d,r_vci_rsp_num_cache,r_vci_rsp_cpt,(data_t)p_vci_ini_rw.rdata.read()); if ( p_vci_ini_rw.reop.read() ) { ASSERT( ((r_vci_rsp_cpt == 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)); 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[r_wbuf[r_vci_rsp_num_cache]->getCpuId(wbuf_index)]->setWriteBerr(); } break; case RSP_DATA_UNC: m_cost_unc_transaction++; if (p_vci_ini_rw.rspval.read() and s_vci_rsp_ack) { ASSERT(p_vci_ini_rw.reop.read(), "illegal VCI response packet for data read uncached"); CACHE_MISS_BUF_RSP_PUSH(d,r_vci_rsp_num_cache,0,(data_t)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 s_vci_rsp_ack) { ASSERT(p_vci_ini_rw.reop.read(), "illegal VCI response packet for data SC"); CACHE_MISS_BUF_RSP_PUSH(d,r_vci_rsp_num_cache,0,(data_t)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 } // 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 { bool ack; switch (r_vci_rsp_fsm.read() ) { case RSP_DATA_WRITE : ack = true; break; case RSP_INS_MISS : case RSP_INS_UNC : ack = CACHE_MISS_BUF_RSP_ACK(i,r_vci_rsp_num_cache); break; case RSP_DATA_MISS : case RSP_DATA_UNC : case RSP_DATA_SC : ack = CACHE_MISS_BUF_RSP_ACK(d,r_vci_rsp_num_cache); break; case RSP_IDLE : default : ack = false; break; } // end switch r_vci_cmd_fsm s_vci_rsp_ack = ack; p_vci_ini_rw.rspack = ack; PRINTF(" * rspack : %d\n", ack); } // 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(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)<