/* -*- 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 #include "arithmetics.h" #include "../include/vci_cc_xcache_wrapper_v4.h" #if CC_XCACHE_WRAPPER_DEBUG # define PRINTF(msg...) do { if (m_cpt_total_cycles>=CC_XCACHE_WRAPPER_DEBUG_CYCLE_MIN) printf(msg); } while (0); #else # define PRINTF(msg...) #endif # define ASSERT(cond,msg) assert ((cond) and msg); #if CC_XCACHE_WRAPPER_FIFO_RSP # define CACHE_MISS_BUF_ALLOC # define CACHE_MISS_BUF_DEALLOC # define CACHE_MISS_BUF_RESET(c) while (r_##c##cache_miss_buf.size()>0) {r_##c##cache_miss_buf.pop();} # define CACHE_MISS_BUF_REQ_INIT(c) # define CACHE_MISS_BUF_RSP_VAL(c,n) (r_##c##cache_miss_buf.size()>0) # define CACHE_MISS_BUF_RSP_ACK(c) (r_##c##cache_miss_buf.size()<2) # define CACHE_MISS_BUF_RSP_DATA(c,n) r_##c##cache_miss_buf.front() # define CACHE_MISS_BUF_RSP_POP(c) do { r_##c##cache_miss_buf.pop();} while (0) # define CACHE_MISS_BUF_RSP_PUSH(c,n,d) do { r_##c##cache_miss_buf.push(d);} 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_icache_words]; \ r_icache_miss_buf = new data_t[m_icache_words]; \ r_dcache_miss_val = new bool [m_dcache_words]; \ r_dcache_miss_buf = new data_t[m_dcache_words]; \ } while (0) # define CACHE_MISS_BUF_DEALLOC do { \ delete [] r_icache_miss_val; \ delete [] r_icache_miss_buf; \ delete [] r_dcache_miss_val; \ delete [] r_dcache_miss_buf; \ } while (0) # define CACHE_MISS_BUF_RESET(c) # define CACHE_MISS_BUF_REQ_INIT(c) do {for (uint32_t i=0; i __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 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_iss(this->name(), proc_id), m_srcid_rw(mtp.indexForId(initiator_index_rw)), m_srcid_c(mtc.indexForId(initiator_index_c)), m_dcache_ways(dcache_ways), m_dcache_words(dcache_words), m_dcache_words_shift(uint32_log2(dcache_words)+2), m_dcache_yzmask((~0)< 2) and ((1<<(vci_param::T-1)) >= wbuf_nlines), "I need more TRDID bits"); CACHE_MISS_BUF_ALLOC; r_tgt_buf = new data_t[m_cache_words]; r_tgt_be = new be_t [m_cache_words]; SC_METHOD(transition); dont_initialize(); sensitive << p_clk.pos(); SC_METHOD(genMoore); dont_initialize(); sensitive << p_clk.neg(); typename iss_t::CacheInfo cache_info; cache_info.has_mmu = false; cache_info.icache_line_size = icache_words*sizeof(data_t); cache_info.icache_assoc = icache_ways; cache_info.icache_n_lines = icache_sets; cache_info.dcache_line_size = dcache_words*sizeof(data_t); cache_info.dcache_assoc = dcache_ways; cache_info.dcache_n_lines = dcache_sets; m_iss.setCacheInfo(cache_info); #if CC_XCACHE_WRAPPER_STOP_SIMULATION m_stop_simulation = false; m_stop_simulation_nb_frz_cycles = 0; #endif // CC_XCACHE_WRAPPER_STOP_SIMULATION #if CC_XCACHE_WRAPPER_DEBUG_DCACHE_TRANSACTION std::ostringstream filename(""); filename << "Instruction_flow_" << proc_id << ".log"; log_dcache_transaction_file.open(filename.str().c_str() ,std::ios::out | std::ios::trunc); #endif } // end constructor /////////////////////////////////// tmpl(/**/)::~VciCcXCacheWrapperV4() /////////////////////////////////// { #if CC_XCACHE_WRAPPER_DEBUG_DCACHE_TRANSACTION log_dcache_transaction_file.close(); #endif delete [] r_tgt_buf; delete [] r_tgt_be ; CACHE_MISS_BUF_DEALLOC; } //////////////////////// tmpl(void)::print_cpi() //////////////////////// { std::cout << "CPU " << m_srcid_rw << " : CPI = " << (float)m_cpt_total_cycles/(m_cpt_total_cycles - m_cpt_frz_cycles) << std::endl ; } //////////////////////// tmpl(void)::print_stats() //////////////////////// { float run_cycles = (float)(m_cpt_total_cycles - m_cpt_frz_cycles); uint32_t m_cpt_data_read_cached = m_cpt_data_read-m_cpt_data_read_uncached; uint32_t m_cpt_data_write_cached = m_cpt_data_write-m_cpt_data_write_uncached; std::cout << "------------------------------------" << std:: dec << std::endl; std::cout << "CPU " << m_srcid_rw << " / Time = " << m_cpt_total_cycles << std::endl; std::cout << "- CPI : " << (float)m_cpt_total_cycles/run_cycles << std::endl ; std::cout << "- IPC : " << (float)run_cycles/m_cpt_total_cycles << std::endl ; std::cout << "- DATA READ * : " << m_cpt_data_read << std::endl ; std::cout << " + Uncached : " << m_cpt_data_read_uncached << " (" << (float)m_cpt_data_read_uncached*100.0/(float)m_cpt_data_read << "%)" << std::endl ; std::cout << " + Cached and miss : " << m_cpt_data_read_miss << " (" << (float)m_cpt_data_read_miss*100.0/(float)m_cpt_data_read_cached << "%)" << std::endl; std::cout << "- DATA WRITE * : " << m_cpt_data_write << std::endl ; std::cout << " + Uncached : " << m_cpt_data_write_uncached << " (" << (float)m_cpt_data_write_uncached*100.0/(float)m_cpt_data_write << "%)" << std::endl ; std::cout << " + Cached and miss : " << m_cpt_data_write_miss << " (" << (float)m_cpt_data_write_miss*100.0/(float)m_cpt_data_write_cached << "%)" << std::endl; // std::cout << "- WRITE RATE : " << (float)m_cpt_data_write/run_cycles << std::endl; // std::cout << "- UNCACHED READ RATE : " << (float)m_cpt_data_read_uncached/m_cpt_data_read << std::endl ; // std::cout << "- CACHED WRITE RATE : " << (float)m_cpt_data_write_cached/m_cpt_data_write << std::endl ; // std::cout << "- IMISS_RATE : " << (float)m_cpt_ins_miss/run_cycles << std::endl; // std::cout << "- DMISS RATE : " << (float)m_cpt_data_miss/(m_cpt_data_read-m_cpt_data_read_uncached) << std::endl ; // std::cout << "- INS MISS COST : " << (float)m_cost_ins_miss_frz/m_cpt_ins_miss << std::endl; // std::cout << "- IMISS TRANSACTION : " << (float)m_cost_imiss_transaction/m_cpt_imiss_transaction << std::endl; // std::cout << "- DMISS COST : " << (float)m_cost_data_miss_frz/m_cpt_data_miss << std::endl; // std::cout << "- DMISS TRANSACTION : " << (float)m_cost_dmiss_transaction/m_cpt_dmiss_transaction << std::endl; // std::cout << "- UNC COST : " << (float)m_cost_unc_read_frz/m_cpt_data_read_uncached << std::endl; // std::cout << "- UNC TRANSACTION : " << (float)m_cost_unc_transaction/m_cpt_unc_transaction << std::endl; // std::cout << "- WRITE COST : " << (float)m_cost_write_frz/m_cpt_data_write << std::endl; // std::cout << "- WRITE TRANSACTION : " << (float)m_cost_write_transaction/m_cpt_data_write_transaction << std::endl; // std::cout << "- WRITE LENGTH : " << (float)m_length_write_transaction/m_cpt_data_write_transaction << std::endl; std::cout << "- CC_UPDATE_ICACHE : " << m_cpt_cc_update_icache << std::endl; std::cout << " + AVERAGE WORD USEFUL : " << (float)m_cpt_cc_update_icache_word_useful/(float)m_cpt_cc_update_icache << " on " << m_icache_words << " words" << std::endl; std::cout << "- CC_UPDATE_DCACHE : " << m_cpt_cc_update_dcache << std::endl; std::cout << " + AVERAGE WORD USEFUL : " << (float)m_cpt_cc_update_dcache_word_useful/(float)m_cpt_cc_update_dcache << " on " << m_dcache_words << " words" << std::endl; uint32_t m_cpt_cc_inval = m_cpt_cc_inval_broadcast+m_cpt_cc_inval_icache+m_cpt_cc_inval_dcache; std::cout << "- CC_INVALID : " << m_cpt_cc_inval << std::endl; std::cout << " + ICACHE Only : " << (float)m_cpt_cc_inval_icache *100.0/(float)m_cpt_cc_inval << "%" << std::endl; std::cout << " + DCACHE Only : " << (float)m_cpt_cc_inval_dcache *100.0/(float)m_cpt_cc_inval << "%" << std::endl; std::cout << " + BROADCAST : " << (float)m_cpt_cc_inval_broadcast*100.0/(float)m_cpt_cc_inval << "%" << std::endl; std::cout << "* : accepted or not by the cache" << std::endl ; r_wbuf.printStatistics(); } //////////////////////////////////// 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; m_iss.getRequests( ireq, dreq ); std::cout << std::dec << "Proc \"" << name() << "\"" << std::endl; std::cout << ireq << std::endl; std::cout << dreq << std::endl; std::cout << " " << dcache_fsm_state_str[r_dcache_fsm] << " " << icache_fsm_state_str[r_icache_fsm] << " " << cmd_fsm_state_str[r_vci_cmd_fsm] << " " << rsp_fsm_state_str[r_vci_rsp_fsm] << " " << tgt_fsm_state_str[r_vci_tgt_fsm] << " " << cleanup_fsm_state_str[r_cleanup_fsm] << std::endl; if(mode & 0x1) { r_wbuf.printTrace((mode>>1)&1); } if(mode & 0x4) { std::cout << " Data cache" << std::endl; r_dcache.printTrace(); } if(mode & 0x8) { std::cout << " Instruction cache" << std::endl; r_icache.printTrace(); } // if(mode & 0x10) // { // std::cout << " Icache miss buffer : "; // CACHE_MISS_BUF_RSP_PRINT(i); // std::cout << std::endl; // std::cout << " Dcache miss buffer : "; // CACHE_MISS_BUF_RSP_PRINT(d); // std::cout << std::endl; // } } ////////////////////////// tmpl(void)::transition() ////////////////////////// { if ( not p_resetn.read() ) { m_iss.reset(); // FSM states r_dcache_fsm = DCACHE_IDLE; r_icache_fsm = ICACHE_IDLE; r_vci_cmd_fsm = CMD_IDLE; r_vci_rsp_fsm = RSP_IDLE; r_vci_tgt_fsm = TGT_IDLE; r_cleanup_fsm = CLEANUP_IDLE; // write buffer & caches r_wbuf.reset(); r_icache.reset(); r_dcache.reset(); // synchronisation flip-flops from ICACHE & DCACHE FSMs to VCI FSMs r_icache_miss_req = false; r_icache_unc_req = false; r_icache_cleanup_req = false; r_dcache_miss_req = false; r_dcache_unc_req = false; r_dcache_sc_req = false; r_dcache_cleanup_req = false; r_dcache_previous_unc= false; // synchronisation flip-flops from TGT FSM to ICACHE & DCACHE FSMs r_tgt_icache_req = false; r_tgt_dcache_req = false; r_tgt_icache_rsp = false; r_tgt_dcache_rsp = false; #if CC_XCACHE_WRAPPER_CC_UPDATE_MULTI_CYCLE r_cache_word = 0; #endif // internal messages in DCACHE et ICACHE FSMs r_icache_inval_rsp = false; r_dcache_inval_rsp = false; // error signals from the VCI RSP FSM to the ICACHE or DCACHE FSMs r_dcache_ll_valid = false; r_icache_buf_unc_valid = false; r_vci_cmd_dcache_prior = false; r_vci_rsp_data_error = false; r_vci_rsp_ins_error = false; CACHE_MISS_BUF_RESET(i); CACHE_MISS_BUF_RESET(d); // activity counters m_cpt_dcache_data_read = 0; m_cpt_dcache_data_write = 0; m_cpt_dcache_dir_read = 0; m_cpt_dcache_dir_write = 0; m_cpt_icache_data_read = 0; m_cpt_icache_data_write = 0; m_cpt_icache_dir_read = 0; m_cpt_icache_dir_write = 0; m_cpt_cc_update_icache = 0; m_cpt_cc_update_dcache = 0; m_cpt_cc_inval_broadcast = 0; m_cpt_cc_inval_icache = 0; m_cpt_cc_inval_dcache = 0; m_cpt_cc_update_icache_word_useful = 0; m_cpt_cc_update_dcache_word_useful = 0; m_cpt_frz_cycles = 0; m_cpt_total_cycles = 0; m_cpt_data_read = 0; m_cpt_data_read_miss = 0; m_cpt_data_read_uncached = 0; m_cpt_data_write = 0; m_cpt_data_write_miss = 0; m_cpt_data_write_uncached = 0; m_cpt_ins_miss = 0; m_cost_write_frz = 0; m_cost_data_miss_frz = 0; m_cost_unc_read_frz = 0; m_cost_ins_miss_frz = 0; m_cpt_imiss_transaction = 0; m_cpt_dmiss_transaction = 0; m_cpt_unc_transaction = 0; m_cpt_data_write_transaction = 0; m_cost_imiss_transaction = 0; m_cost_dmiss_transaction = 0; m_cost_unc_transaction = 0; m_cost_write_transaction = 0; m_length_write_transaction = 0; return; } // printf("%d\n",(uint32_t)m_cpt_total_cycles); PRINTF("--------------------------------------------\n"); PRINTF(" * CC_XCACHE_WRAPPER \"%s\" - Time = %d\n",name().c_str(),(uint32_t)m_cpt_total_cycles); PRINTF(" * fsm dcache = %s\n",dcache_fsm_state_str[r_dcache_fsm]); PRINTF(" * fsm icache = %s\n",icache_fsm_state_str[r_icache_fsm]); PRINTF(" * fsm cmd = %s\n",cmd_fsm_state_str[r_vci_cmd_fsm]); PRINTF(" * fsm rsp = %s\n",rsp_fsm_state_str[r_vci_rsp_fsm]); PRINTF(" * fsm tgt = %s\n",tgt_fsm_state_str[r_vci_tgt_fsm]); PRINTF(" * fsm cleanup = %s\n",cleanup_fsm_state_str[r_cleanup_fsm]); PRINTF(" * ll info : %d %llx %llx\n",r_dcache_ll_valid.read(), (uint64_t)r_dcache_ll_addr.read(), (uint64_t)r_dcache_ll_data.read()); PRINTF(" * dcache_previous_unc : %d\n",r_dcache_previous_unc.read()); // CACHE_MISS_BUF_RSP_PRINT(i); // CACHE_MISS_BUF_RSP_PRINT(d); #if CC_XCACHE_WRAPPER_DEBUG if (m_cpt_total_cycles>=CC_XCACHE_WRAPPER_DEBUG_CYCLE_MIN) { r_wbuf.printTrace(1); } #endif m_cpt_total_cycles++; ///////////////////////////////////////////////////////////////////// // The TGT_FSM controls the following ressources: // - r_vci_tgt_fsm // - r_tgt_buf[nwords] // - r_tgt_be[nwords] // - r_tgt_update // - r_tgt_word // - r_tgt_addr // - r_tgt_srcid // - r_tgt_trdid // - r_tgt_pktid // All VCI commands must be CMD_WRITE. // If the VCI address offset is null, the command is an invalidate // request. It is an update request otherwise. // The VCI_TGT FSM stores the external request arguments in the // IDLE, UPDT_WORD & UPDT_DATA states. It sets the r_tgt_icache_req // & r_tgt_dcache_req flip-flops to signal the external request to // the ICACHE & DCACHE FSMs in the REQ state. It waits the completion // of the update or invalidate request in the RSP state. // - for an invalidate request the VCI packet length is 1 word. // The WDATA field contains the line index (i.e. the Z & Y fields). // - for an update request the VCI packet length is (n+2) words. // The WDATA field of the first VCI word contains the line number. // The WDATA field of the second VCI word contains the word index. // The WDATA field of the n following words contains the values. // - for both invalidate & update requests, the VCI response // is one single word. // In case of errors in the VCI command packet, the simulation // is stopped with an error message. ///////////////////////////////////////////////////////////////////// switch(r_vci_tgt_fsm) { case TGT_IDLE: if ( p_vci_tgt.cmdval.read() ) { PRINTF(" * 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 << "oddress = " << 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 << "oddress = " << std::hex << address << std::dec << std::endl; std::cout << "srcid = " << p_vci_tgt.srcid.read() << std::endl; exit(0); } r_tgt_addr = (((addr_40) ((p_vci_tgt.be.read() & 0x3) << 32)) | ((addr_40) (p_vci_tgt.wdata.read()))) * m_dcache_words * 4; 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(); PRINTF(" * address : %llx\n",(uint64_t)address); PRINTF(" * address : %llx\n",(uint64_t)((((addr_40) ((p_vci_tgt.be.read() & 0x3) << 32)) | ((addr_40) (p_vci_tgt.wdata.read()))) * m_dcache_words * 4)); 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; m_cpt_cc_inval_broadcast++ ; } 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; m_cpt_cc_inval_dcache++ ; } 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; m_cpt_cc_inval_icache++ ; } 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; } else { m_cpt_cc_update_icache++; r_tgt_update_data = false; } r_tgt_update = true; r_vci_tgt_fsm = TGT_UPDT_WORD; } } // end if address } // 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=CC_XCACHE_WRAPPER_DEBUG_CYCLE_MIN) std::cout << " * Instruction Request : " << ireq << std::endl; #endif switch(r_icache_fsm) { ///////////////// case ICACHE_IDLE: { if ( r_tgt_icache_req ) { // external request if ( ireq.valid ) m_cost_ins_miss_frz++; r_icache_fsm = ICACHE_CC_CHECK; r_icache_fsm_save = r_icache_fsm.read(); break; } if ( ireq.valid ) { data_t icache_ins = 0; bool icache_hit = false; bool icache_cached = m_cacheability_table[(vci_addr_t)ireq.addr]; bool icache_cleanup_hit = r_icache_cleanup_req and (((addr_40)ireq.addr >> (addr_40)m_icache_words_shift) == r_icache_cleanup_line.read()); // icache_hit & icache_ins evaluation if ( icache_cached ) { icache_hit = r_icache.read((vci_addr_t) ireq.addr, &icache_ins); } else { // if uncache, again in the icache_miss_buf icache_hit = ( r_icache_buf_unc_valid and ((addr_40) ireq.addr == (addr_40)r_icache_addr_save)); icache_ins = CACHE_MISS_BUF_RSP_DATA(i,0); CACHE_MISS_BUF_RSP_POP(i); } PRINTF(" * hit %d - cached %d - cleanup_hit %d\n",icache_hit, icache_cached, icache_cleanup_hit); ASSERT( not (icache_hit and icache_cleanup_hit), "Icache hit and icache_cleanup_hit"); if ( not icache_hit and not icache_cleanup_hit) { m_cpt_ins_miss++; m_cost_ins_miss_frz++; r_icache_addr_save = (addr_40) ireq.addr; CACHE_MISS_BUF_REQ_INIT(i); if ( icache_cached ) { #if CC_XCACHE_WRAPPER_SELECT_VICTIM r_icache_fsm = ICACHE_MISS_VICTIM; #else r_icache_fsm = ICACHE_MISS_WAIT; #endif r_icache_miss_req = true; } else { r_icache_fsm = ICACHE_UNC_WAIT; r_icache_unc_req = true; } } else { r_icache_buf_unc_valid = 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; } ////////////////////// #if CC_XCACHE_WRAPPER_SELECT_VICTIM case ICACHE_MISS_VICTIM: { if (not r_icache_cleanup_req) { size_t way; size_t set; vci_addr_t addr = (vci_addr_t) r_icache_addr_save.read(); vci_addr_t victim; r_icache_cleanup_req = r_icache.victim_select(addr, &victim, &way, &set ); r_icache_cleanup_line = (addr_40) victim; r_icache_miss_way = way; r_icache_miss_set = set; r_icache_fsm = ICACHE_MISS_WAIT; } break; } #endif ////////////////////// case ICACHE_MISS_WAIT: { m_cost_ins_miss_frz++; if ( r_tgt_icache_req ) { // external request r_icache_fsm = ICACHE_CC_CHECK; r_icache_fsm_save = r_icache_fsm.read(); break; } bool val = CACHE_MISS_BUF_RSP_VAL(i,0); PRINTF(" * val : %d\n",val); if (val) { PRINTF(" * r_icache_inval_rsp : %d\n",(int) r_icache_inval_rsp ); PRINTF(" * r_vci_rsp_ins_error : %d\n",(int) r_vci_rsp_ins_error ); PRINTF(" * r_icache_cleanup_req : %d\n",(int) r_icache_cleanup_req); // if (not r_icache_inval_rsp ) // { // Miss read response and no invalidation if ( r_vci_rsp_ins_error ) { r_icache_fsm = ICACHE_ERROR; } else { #if not CC_XCACHE_WRAPPER_SELECT_VICTIM if (not r_icache_cleanup_req.read()) #endif { r_icache_update_addr = 0; r_icache_fsm = ICACHE_MISS_UPDT; } } // } // else // { // r_icache_inval_rsp = false; // // Miss read response and invalidation // if ( r_vci_rsp_ins_error ) // r_icache_fsm = ICACHE_ERROR; // else // r_icache_fsm = ICACHE_CC_CLEANUP; // } } break; } ///////////////////// case ICACHE_UNC_WAIT: { m_cost_ins_miss_frz++; if ( r_tgt_icache_req ) { // external request r_icache_fsm = ICACHE_CC_CHECK; r_icache_fsm_save = r_icache_fsm.read(); break; } bool ok = CACHE_MISS_BUF_RSP_VAL(i,0); if (ok) { if ( r_vci_rsp_ins_error ) { r_icache_fsm = ICACHE_ERROR; } else { r_icache_fsm = ICACHE_IDLE; r_icache_buf_unc_valid = true; } } break; } ////////////////// case ICACHE_ERROR: { if ( (addr_40)ireq.addr == (addr_40)r_icache_addr_save ) { irsp.error = true; irsp.valid = true; } r_icache_fsm = ICACHE_IDLE; r_vci_rsp_ins_error = false; break; } ////////////////////// case ICACHE_MISS_UPDT: { size_t word = r_icache_update_addr.read(); vci_addr_t addr = (vci_addr_t) r_icache_addr_save.read(); size_t way = 0; size_t set = 0; // need invalid rsp, don't select a victim if (not r_icache_inval_rsp ) { #if CC_XCACHE_WRAPPER_SELECT_VICTIM way = r_icache_miss_way.read(); set = r_icache_miss_set.read(); #else // First word : select an victim ! if (word == 0) { vci_addr_t victim; // r_icache_cleanup_req is false because is the transition condition to go in ICACHE_MISS_UPDT state r_icache_cleanup_req = r_icache.victim_select(addr, &victim, &way, &set ); r_icache.victim_update_tag(addr, way, set); r_icache_cleanup_line = (addr_40) victim; r_icache_miss_way = way; r_icache_miss_set = set; } else { way = r_icache_miss_way.read(); set = r_icache_miss_set.read(); } #endif } bool val = CACHE_MISS_BUF_RSP_VAL(i,word); if (val) { PRINTF(" * rsp_val : %d/%d\n",(int)r_icache_update_addr,m_icache_words); PRINTF(" * r_icache_inval_rsp : %d\n",(int)r_icache_inval_rsp); PRINTF(" * ins : %x\n",(int)CACHE_MISS_BUF_RSP_DATA(i,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 ) r_icache.write(way, set, word, CACHE_MISS_BUF_RSP_DATA(i,word)); CACHE_MISS_BUF_RSP_POP(i); r_icache_update_addr = ++word; // if last word, finish the update if (word >= m_icache_words) { // Last word : if previous invalid_rsp, can cleanup, else update the TAG if (r_icache_inval_rsp) { r_icache_inval_rsp = false; r_icache_fsm = ICACHE_CC_CLEANUP; } else { #if CC_XCACHE_WRAPPER_SELECT_VICTIM r_icache.victim_update_tag(addr, way, set); #endif r_icache_fsm = ICACHE_IDLE; } } } break; } //////////////////// case ICACHE_CC_CLEANUP: { // external cache invalidate request if ( r_tgt_icache_req ) { r_icache_fsm = ICACHE_CC_CHECK; r_icache_fsm_save = r_icache_fsm.read(); break; } // cleanup if(not r_icache_cleanup_req){ r_icache_cleanup_req = true; r_icache_cleanup_line = r_icache_addr_save.read() >> m_icache_words_shift; r_icache_fsm = ICACHE_IDLE; } 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_addr; data_t icache_rdata = 0; if((r_icache_fsm_save == ICACHE_MISS_WAIT) and ( (r_icache_addr_save.read() & ~((m_icache_words<<2)-1)) == (ad & ~((m_icache_words<<2)-1)))) { r_icache_inval_rsp = true; r_tgt_icache_req = false; if(r_tgt_update){ // Also send a cleanup and answer r_tgt_icache_rsp = true; } else { // Also send a cleanup but don't answer r_tgt_icache_rsp = false; } r_icache_fsm = r_icache_fsm_save; } else { bool icache_hit = r_icache.read(ad, &icache_rdata); 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.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 (; word=CC_XCACHE_WRAPPER_DEBUG_CYCLE_MIN) std::cout << " * Instruction Response : " << irsp << std::endl; #endif //////////////////////////////////////////////////////////////////////:///////////// // 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. /////////////////////////////////////////////////////////////////////////////////// #if CC_XCACHE_WRAPPER_DEBUG if (m_cpt_total_cycles>=CC_XCACHE_WRAPPER_DEBUG_CYCLE_MIN) std::cout << " * Data Request : " << dreq << std::endl; #endif switch ( r_dcache_fsm ) { ///////////////// case DCACHE_IDLE: { if ( r_tgt_dcache_req ) { // external request r_dcache_fsm = DCACHE_CC_CHECK; r_dcache_fsm_save = r_dcache_fsm; break; } if ( dreq.valid ) { PRINTF(" * Have dreq\n"); 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 = m_cacheability_table[(vci_addr_t)dreq.addr]; bool dcache_hit = r_dcache.read((vci_addr_t) dreq.addr, &dcache_rdata); bool dcache_cleanup_hit = r_dcache_cleanup_req and (((addr_40)dreq.addr >> (addr_40)m_dcache_words_shift) == r_dcache_cleanup_line.read()); PRINTF(" * hit %d - cached %d - cleanup_hit %d\n",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 = 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"); r_dcache_ll_valid = true; r_dcache_ll_data = dcache_rdata; r_dcache_ll_addr = (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.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); // 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 = true; #if CC_XCACHE_WRAPPER_SELECT_VICTIM r_dcache_fsm = DCACHE_MISS_VICTIM; #else r_dcache_fsm = DCACHE_MISS_WAIT; #endif } else { if (not r_dcache_previous_unc.read()) // strongly order to the uncached access { r_dcache_previous_unc = true; m_cpt_data_read_uncached++; m_cost_unc_read_frz++; r_dcache_unc_req = true; r_dcache_fsm = DCACHE_UNC_WAIT; } } } } } break; case iss_t::DATA_SC: { PRINTF(" * DATA_SC - ll_valid = %d\n",r_dcache_ll_valid.read()); if (not r_dcache_previous_unc.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.read() and (r_dcache_ll_addr.read() == (vci_addr_t)dreq.addr)){ PRINTF(" * have previous load linked\n"); r_dcache_previous_unc = true; r_dcache_sc_req = true; CACHE_MISS_BUF_REQ_INIT(d); r_dcache_fsm = DCACHE_SC_WAIT; } else { PRINTF(" * don't have previous load linked\n"); drsp.valid = true; drsp.rdata = 1; // SC rsp NOK r_dcache_ll_valid = false; } } break; } case iss_t::XTN_READ: case iss_t::XTN_WRITE: { bool drsp_valid = false; // only DCACHE INVALIDATE and SYNC request are supported switch (dreq.addr>>2) { case iss_t::XTN_DCACHE_INVAL : { drsp_valid = true; r_dcache_fsm = 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 if (r_wbuf.empty()) { drsp_valid = true; r_dcache_fsm = DCACHE_IDLE; } else { drsp_valid = false; r_dcache_fsm = DCACHE_SYNC; } 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 = DCACHE_IDLE; } }//end switch (dreq.addr>>2) drsp.valid = drsp_valid; drsp.rdata = 0; break; } case iss_t::DATA_WRITE: if (dcache_cached or not r_dcache_previous_unc.read()) // strongly order to the uncached access { bool drsp_valid; drsp_valid = r_wbuf.write((addr_40) dreq.addr, dreq.be, dreq.wdata, dcache_cached); if (drsp_valid) { m_cpt_data_write++; if (not dcache_cached) { r_dcache_previous_unc = true; m_cpt_data_write_uncached++; } else if (not dcache_hit) m_cpt_data_write_miss++; if ( dcache_hit) { r_dcache_fsm = DCACHE_WRITE_UPDT; } else { r_dcache_fsm = DCACHE_IDLE; } } drsp.valid = drsp_valid; drsp.rdata = 0; } break; } // end switch dreq.type r_dcache_addr_save = (addr_40) dreq.addr; r_dcache_type_save = dreq.type; r_dcache_wdata_save = dreq.wdata; r_dcache_be_save = dreq.be; r_dcache_rdata_save = dcache_rdata; r_dcache_cached_save = dcache_cached; } else { // end if dreq.valid r_dcache_fsm = DCACHE_IDLE; } break; } /////////////////////// case DCACHE_WRITE_UPDT: { m_cpt_dcache_data_write++; data_t mask = vci_param::be2mask(r_dcache_be_save); data_t wdata = (mask & r_dcache_wdata_save) | (~mask & r_dcache_rdata_save); vci_addr_t ad = r_dcache_addr_save.read(); r_dcache.write(ad, wdata); r_dcache_fsm = DCACHE_IDLE; break; } ////////////////////// #if CC_XCACHE_WRAPPER_SELECT_VICTIM case DCACHE_MISS_VICTIM: { if (not r_dcache_cleanup_req.read()) { size_t way; size_t set; vci_addr_t addr = (vci_addr_t) r_dcache_addr_save.read(); vci_addr_t victim; r_dcache_cleanup_req = r_dcache.victim_select(addr, &victim, &way, &set ); r_dcache_cleanup_line = (addr_40) victim; r_dcache_miss_way = way; r_dcache_miss_set = set; r_dcache_fsm = DCACHE_MISS_WAIT; } break; } #endif ////////////////////// case DCACHE_MISS_WAIT: { if ( dreq.valid ) m_cost_data_miss_frz++; if ( r_tgt_dcache_req.read() ) { // external request r_dcache_fsm = DCACHE_CC_CHECK; r_dcache_fsm_save = r_dcache_fsm; break; } bool val = CACHE_MISS_BUF_RSP_VAL(d,0); if (val) { // if (not r_dcache_inval_rsp ) // { // Miss read response and no invalidation if ( r_vci_rsp_data_error ) { r_dcache_fsm = DCACHE_ERROR; } else { #if not CC_XCACHE_WRAPPER_SELECT_VICTIM if (not r_dcache_cleanup_req.read()) #endif { r_dcache_update_addr = 0; r_dcache_fsm = DCACHE_MISS_UPDT; } } // } // else // { // r_dcache_inval_rsp = false; // // Miss read response and invalidation // if ( r_vci_rsp_data_error ) { // r_dcache_fsm = DCACHE_ERROR; // } else { // r_dcache_fsm = DCACHE_CC_CLEANUP; // } // } } break; } ////////////////////// case DCACHE_MISS_UPDT: { size_t word = r_dcache_update_addr.read(); vci_addr_t addr = (vci_addr_t) r_dcache_addr_save.read(); size_t way = 0; size_t set = 0; // need invalid rsp, don't select a victim if (not r_dcache_inval_rsp ) { #if CC_XCACHE_WRAPPER_SELECT_VICTIM way = r_dcache_miss_way.read(); set = r_dcache_miss_set.read(); #else // First word : select an victim ! if (word == 0) { vci_addr_t victim; // r_dcache_cleanup_req is false (condition to enter in DCACHE_MISS_UPDT r_dcache_cleanup_req = r_dcache.victim_select(addr, &victim, &way, &set ); r_dcache.victim_update_tag(addr, way, set); r_dcache_cleanup_line = (addr_40) victim; r_dcache_miss_way = way; r_dcache_miss_set = set; } else { way = r_dcache_miss_way.read(); set = r_dcache_miss_set.read(); } #endif } bool val = CACHE_MISS_BUF_RSP_VAL(d,word); if (val) { // m_cpt_dcache_dir_write++; // if ( ireq.valid ) m_cost_data_miss_frz++; // if need invalid rsp, don't modify the cache, but pop the buf_rsp if (not r_dcache_inval_rsp ) { r_dcache.write(way, set, word, CACHE_MISS_BUF_RSP_DATA(d,word)); m_cpt_dcache_data_write++; } CACHE_MISS_BUF_RSP_POP(d); r_dcache_update_addr = ++word; // if last word, finish the update if (word >= m_dcache_words) { // Last word : if previous invalid_rsp, can cleanup, else update the TAG if (r_dcache_inval_rsp) { r_dcache_inval_rsp = false; r_dcache_fsm = DCACHE_CC_CLEANUP; } else { #if CC_XCACHE_WRAPPER_SELECT_VICTIM r_dcache.victim_update_tag(addr, way, set); #endif r_dcache_fsm = DCACHE_IDLE; } } } break; } //////////////////// case DCACHE_UNC_WAIT: { if ( dreq.valid ) m_cost_unc_read_frz++; if ( r_tgt_dcache_req ) { // external request r_dcache_fsm = DCACHE_CC_CHECK; r_dcache_fsm_save = r_dcache_fsm; break; } bool ok = CACHE_MISS_BUF_RSP_VAL(d,0); if (ok) { if ( r_vci_rsp_data_error ) { r_dcache_fsm = DCACHE_ERROR; } else { data_t rdata = CACHE_MISS_BUF_RSP_DATA(d,0); CACHE_MISS_BUF_RSP_POP(d); if(dreq.type == iss_t::DATA_LL){ PRINTF(" * ll_valid = true\n"); r_dcache_ll_valid = true; r_dcache_ll_data = rdata; r_dcache_ll_addr = (vci_addr_t) dreq.addr; } r_dcache_fsm = 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 ) { // external request r_dcache_fsm = DCACHE_CC_CHECK; r_dcache_fsm_save = r_dcache_fsm; break; } bool ok = CACHE_MISS_BUF_RSP_VAL(d,0); if (ok) { if ( r_vci_rsp_data_error ) { r_dcache_fsm = DCACHE_ERROR; } else { r_dcache_fsm = DCACHE_IDLE; drsp.valid = true; drsp.rdata = CACHE_MISS_BUF_RSP_DATA(d,0); CACHE_MISS_BUF_RSP_POP(d); r_dcache_ll_valid = false; } } break; } ////////////////// case DCACHE_ERROR: { r_dcache_fsm = DCACHE_IDLE; r_vci_rsp_data_error = false; drsp.error = true; drsp.valid = true; break; } ///////////////// case DCACHE_INVAL: { if ( r_tgt_dcache_req.read() ) { // external request r_dcache_fsm = DCACHE_CC_CHECK; r_dcache_fsm_save = r_dcache_fsm; break; } if( not r_dcache_cleanup_req.read() ){ m_cpt_dcache_dir_read += m_dcache_ways; vci_addr_t ad = r_dcache_addr_save.read(); r_dcache_cleanup_req = r_dcache.inval(ad); r_dcache_cleanup_line = r_dcache_addr_save.read() >> m_dcache_words_shift; r_dcache_fsm = DCACHE_IDLE; } break; } case DCACHE_SYNC : { if ( r_tgt_dcache_req ) { // external request r_dcache_fsm = DCACHE_CC_CHECK; r_dcache_fsm_save = r_dcache_fsm; break; } if (r_wbuf.empty()) { drsp.valid = true; // end, can accept the sync request r_dcache_fsm = DCACHE_IDLE; } break; } ///////////////////// case DCACHE_CC_CHECK: // read directory in case of invalidate or update request { addr_40 ad = r_tgt_addr; data_t dcache_rdata = 0; if((r_dcache_fsm_save == DCACHE_MISS_WAIT) and ( (r_dcache_addr_save.read() & ~((m_dcache_words<<2)-1)) == (ad & ~((m_dcache_words<<2)-1)))) { r_dcache_inval_rsp = true; r_tgt_dcache_req = false; if(r_tgt_update){ // Also send a cleanup and answer r_tgt_dcache_rsp = true; } else { // Also send a cleanup but don't answer r_tgt_dcache_rsp = false; } r_dcache_fsm = r_dcache_fsm_save; } else { bool dcache_hit = r_dcache.read(ad, &dcache_rdata); 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.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 (; word> m_dcache_words_shift; r_dcache_fsm = DCACHE_IDLE; } 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 wbuf_flush=(r_dcache_fsm == DCACHE_SYNC); #if (CC_XCACHE_WRAPPER_WBUF_UPDATE_SCHEME==1) r_wbuf.update_multi_scan (wbuf_flush); #elif (CC_XCACHE_WRAPPER_WBUF_UPDATE_SCHEME==2) r_wbuf.update_round_robin_scan(wbuf_flush); #elif (CC_XCACHE_WRAPPER_WBUF_UPDATE_SCHEME==3) r_wbuf.update_one_scan (wbuf_flush); #else r_wbuf.update (wbuf_flush); #endif #if CC_XCACHE_WRAPPER_DEBUG if (m_cpt_total_cycles>=CC_XCACHE_WRAPPER_DEBUG_CYCLE_MIN) std::cout << " * Data Response : " << drsp << std::endl; #endif /////////// execute one iss cycle ///////////////////////////////////////////// { uint32_t it = 0; for (size_t i=0; i<(size_t)iss_t::n_irq; i++) if(p_irq[i].read()) it |= (1<= m_stop_simulation_nb_frz_cycles_max)) { std::cout << std::dec << "CC_XCACHE_WRAPPER \"" << name() << "\" : cycle " << m_cpt_total_cycles << ", the cpu is frozen since " << m_stop_simulation_nb_frz_cycles << " cycles." << std::endl; ASSERT(false,"CPU : anormal activity"); // exit } } else { m_stop_simulation_nb_frz_cycles = 0; // reinit counter #endif //CC_XCACHE_WRAPPER_STOP_SIMULATION } #if CC_XCACHE_WRAPPER_DEBUG_DCACHE_TRANSACTION if (dreq.valid and drsp.valid) { log_dcache_transaction_file << "[" << m_cpt_total_cycles << "]" << std::hex << " @ " << std::setw(8) << (uint32_t)dreq.addr << " 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_dcache_transaction_file << xtn_str(dreq.addr>>2); switch (dreq.addr>>2) { case iss_t::XTN_DCACHE_INVAL : log_dcache_transaction_file << " INVAL"; break; case iss_t::XTN_SYNC : log_dcache_transaction_file << " SYNC"; break; default : log_dcache_transaction_file << " invalid"; break; } log_dcache_transaction_file << std::endl; // printf("[%d] @ %.8x be %.1x W %.8x R %.8x error %d - %s" // ,(uint32_t)m_cpt_total_cycles // ,(uint32_t)dreq.addr // ,(uint32_t)dreq.be // ,(uint32_t)dreq.wdata // ,(uint32_t)drsp.rdata // ,(uint32_t)drsp.error // ,type_str(dreq.type)); // if ((dreq.type == iss_t::XTN_READ) or // (dreq.type == iss_t::XTN_WRITE)) // // printf(" %s",xtn_str(dreq.addr>>2)); // switch (dreq.addr>>2) // { // case iss_t::XTN_DCACHE_INVAL : printf(" INVAL"); break; // case iss_t::XTN_SYNC : printf(" SYNC"); break; // default : printf(" invalid"); break; // } // printf("\n"); } #endif //CC_XCACHE_WRAPPER_DEBUG_DCACHE_TRANSACTION //////////////////////////////////////////////////////////////////////////// // 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: { if ( p_vci_ini_c.cmdack ) { if (r_dcache_cleanup_req) r_cleanup_fsm = CLEANUP_DCACHE; else if (r_icache_cleanup_req) r_cleanup_fsm = CLEANUP_ICACHE; } break; } case CLEANUP_DCACHE: { 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_DATA_CLEANUP), "illegal response packet received for a cleanup transaction"); ASSERT( (p_vci_ini_c.rerror.read()&0x1) == vci_param::ERR_NORMAL, "error signaled in a cleanup response" ); r_cleanup_fsm = CLEANUP_IDLE; r_dcache_cleanup_req = false; // m_cpt_cc_cleanup_data++; TODO } break; } case CLEANUP_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()&0x1) == vci_param::ERR_NORMAL, "error signaled in a cleanup response" ); r_cleanup_fsm = CLEANUP_IDLE; r_icache_cleanup_req = false; // m_cpt_cc_cleanup_ins++; TODO } 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 min; size_t max; r_vci_cmd_cpt = 0; // Requests : // multi_write_buffer access is conditionnal with dcache_miss_req and icache_miss_req #if (CC_XCACHE_WRAPPER_VCI_CMD_PRIORITY==1) // 1) two access authorized bool dcache_miss_req = r_dcache_miss_req; bool icache_miss_req = r_icache_miss_req; #elif (CC_XCACHE_WRAPPER_VCI_CMD_PRIORITY==2) // 2) one access with static priority (dcache prior) bool dcache_miss_req = r_dcache_miss_req; // dcache prior bool icache_miss_req = not dcache_miss_req and r_icache_miss_req; #elif (CC_XCACHE_WRAPPER_VCI_CMD_PRIORITY==3) // 3) one access with static priority (icache prior) bool icache_miss_req = r_icache_miss_req; bool dcache_miss_req = not icache_miss_req and r_dcache_miss_req; // dcache prior #elif (CC_XCACHE_WRAPPER_VCI_CMD_PRIORITY==4) // 4) one access with round robin priority bool dcache_miss_req = ((r_dcache_miss_req and not r_icache_miss_req) or // only dcache (r_dcache_miss_req and r_vci_cmd_dcache_prior)); // dcache prior bool icache_miss_req = not dcache_miss_req and r_icache_miss_req; #else #error "Invalid value to CC_XCACHE_WRAPPER_VCI_CMD_PRIORITY" #endif // 1 - Data Read if (dcache_miss_req and r_wbuf.miss(r_dcache_addr_save)) { r_vci_cmd_fsm = CMD_DATA_MISS; r_dcache_miss_req = false; m_cpt_dmiss_transaction++; } // 2 - Data Read Uncachable else if ( r_dcache_unc_req ) { r_vci_cmd_fsm = CMD_DATA_UNC; r_dcache_unc_req = false; // m_cpt_data_unc_transaction++; } // 3 - Instruction Miss else if (icache_miss_req and r_wbuf.miss(r_icache_addr_save)) { r_vci_cmd_fsm = CMD_INS_MISS; r_icache_miss_req = false; m_cpt_imiss_transaction++; } // 4 - Instruction Uncachable else if ( r_icache_unc_req ) { r_vci_cmd_fsm = CMD_INS_UNC; r_icache_unc_req = false; // m_cpt_ins_unc_transaction++; } // 5 - Data Write else if ( r_wbuf.rok(&min, &max) ) { r_vci_cmd_fsm = CMD_DATA_WRITE; r_vci_cmd_cpt = min; r_vci_cmd_min = min; r_vci_cmd_max = max; m_cpt_data_write_transaction++; m_length_write_transaction += (max-min+1); } // 6 - Data Store Conditionnal else if ( r_dcache_sc_req ) { r_vci_cmd_fsm = CMD_DATA_SC; r_vci_cmd_max = 1; m_cpt_unc_transaction++; r_dcache_sc_req = false; } 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.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\n",(uint32_t)p_vci_ini_rw.rtrdid.read()); r_vci_rsp_cpt = 0; if ((p_vci_ini_rw.rtrdid.read()>>(vci_param::T-1)) != 0 ) r_vci_rsp_fsm = RSP_DATA_WRITE; else { switch (p_vci_ini_rw.rtrdid.read()) { case TYPE_INS_MISS : r_vci_rsp_fsm = RSP_INS_MISS; break; case TYPE_INS_UNC : r_vci_rsp_fsm = RSP_INS_UNC; break; case TYPE_DATA_MISS : r_vci_rsp_fsm = RSP_DATA_MISS; break; case TYPE_DATA_UNC : r_vci_rsp_fsm = RSP_DATA_UNC; break; case TYPE_DATA_SC : r_vci_rsp_fsm = RSP_DATA_SC; break; default : { ASSERT(false, "Unexpected response"); } } } } 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)r_vci_rsp_ack); if (p_vci_ini_rw.rspval.read() and r_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_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.read() == m_icache_words - 1) or p_vci_ini_rw.rerror.read() or (r_vci_rsp_ins_error.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 = true; } break; case RSP_INS_UNC: m_cost_imiss_transaction++; if (p_vci_ini_rw.rspval.read() and r_vci_rsp_ack) { ASSERT(p_vci_ini_rw.reop.read(), "illegal VCI response packet for uncached instruction"); CACHE_MISS_BUF_RSP_PUSH(i,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 = true; } break; case RSP_DATA_MISS: m_cost_dmiss_transaction++; if (p_vci_ini_rw.rspval.read() and r_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_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.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 = 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; bool cached = r_wbuf.completed(p_vci_ini_rw.rtrdid.read() - (1<<(vci_param::T-1)) ); PRINTF(" * cached : %d\n",cached); if (not cached) r_dcache_previous_unc = false; if ((p_vci_ini_rw.rerror.read()&0x1) != vci_param::ERR_NORMAL) m_iss.setWriteBerr(); } break; case RSP_DATA_UNC: m_cost_unc_transaction++; if (p_vci_ini_rw.rspval.read() and r_vci_rsp_ack) { ASSERT(p_vci_ini_rw.reop.read(), "illegal VCI response packet for data read uncached"); CACHE_MISS_BUF_RSP_PUSH(d,0,(data_t)p_vci_ini_rw.rdata.read()); r_vci_rsp_fsm = RSP_IDLE; r_dcache_previous_unc = false; if ( (p_vci_ini_rw.rerror.read()&0x1) != vci_param::ERR_NORMAL ) r_vci_rsp_data_error = true; } break; case RSP_DATA_SC: m_cost_unc_transaction++; if (p_vci_ini_rw.rspval.read() and r_vci_rsp_ack) { ASSERT(p_vci_ini_rw.reop.read(), "illegal VCI response packet for data SC"); CACHE_MISS_BUF_RSP_PUSH(d,0,(data_t)p_vci_ini_rw.rdata.read()); r_vci_rsp_fsm = RSP_IDLE; r_dcache_previous_unc = false; if ( (p_vci_ini_rw.rerror.read()&0x1) != vci_param::ERR_NORMAL ) r_vci_rsp_data_error = true; } break; } // end switch r_vci_rsp_fsm } // end transition() ////////////////////////////////////////////////////////////////////////////////// tmpl(void)::genMoore() ////////////////////////////////////////////////////////////////////////////////// { // VCI initiator response switch ( r_cleanup_fsm.read() ) { case CLEANUP_IDLE: p_vci_ini_c.rspack = false; p_vci_ini_c.cmdval = r_icache_cleanup_req || r_dcache_cleanup_req; if ( r_dcache_cleanup_req ) { p_vci_ini_c.address = r_dcache_cleanup_line.read() * (m_dcache_words << 2); p_vci_ini_c.trdid = TYPE_DATA_CLEANUP; } else { p_vci_ini_c.address = r_icache_cleanup_line.read() * (m_icache_words << 2); p_vci_ini_c.trdid = TYPE_INS_CLEANUP; } 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.pktid = 0; 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_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_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; p_vci_ini_rw.address = (addr_40) r_dcache_addr_save.read() & ~0x3; switch( r_dcache_type_save ) { case iss_t::DATA_READ: p_vci_ini_rw.wdata = 0; p_vci_ini_rw.be = r_dcache_be_save.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 = 0; 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; p_vci_ini_rw.address = (addr_40) r_dcache_addr_save.read() & ~0x3; 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.read() & 0xFFFFFFFF); break; case 1: p_vci_ini_rw.wdata = r_dcache_wdata_save.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 = 0; 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; p_vci_ini_rw.address = r_wbuf.getAddress(r_vci_cmd_cpt)&~0x3; p_vci_ini_rw.wdata = r_wbuf.getData(r_vci_cmd_cpt); p_vci_ini_rw.be = r_wbuf.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.getIndex() + (1<<(vci_param::T-1)); p_vci_ini_rw.pktid = 0; 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; p_vci_ini_rw.address = r_dcache_addr_save.read() & (addr_40) m_dcache_yzmask; 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 = 0; 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; p_vci_ini_rw.address = r_icache_addr_save.read() & (addr_40) m_icache_yzmask; 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 = 0; 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; p_vci_ini_rw.address = r_icache_addr_save.read() & ~0x3; 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 = 0; 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_IDLE : ack = false; break; case RSP_DATA_WRITE : ack = true; break; case RSP_INS_MISS : case RSP_INS_UNC : ack = CACHE_MISS_BUF_RSP_ACK(i); break; case RSP_DATA_MISS : case RSP_DATA_UNC : case RSP_DATA_SC : ack = CACHE_MISS_BUF_RSP_ACK(d); break; } // end switch r_vci_cmd_fsm r_vci_rsp_ack = ack; p_vci_ini_rw.rspack = ack; // VCI_TGT 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: p_vci_tgt.cmdack = false; p_vci_tgt.rspval = not r_tgt_icache_req.read() and not r_tgt_dcache_req.read() and ( r_tgt_icache_rsp | r_tgt_dcache_rsp ); 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: p_vci_tgt.cmdack = false; p_vci_tgt.rspval = not r_tgt_icache_req.read() and r_tgt_icache_rsp.read(); 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: p_vci_tgt.cmdack = false; p_vci_tgt.rspval = not r_tgt_dcache_req.read() and r_tgt_dcache_rsp.read(); 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 } }} // end namespace // Local Variables: // tab-width: 4 // c-basic-offset: 4 // c-file-offsets:((innamespace . 0)(inline-open . 0)) // indent-tabs-mode: nil // End: // vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=4:softtabstop=4