/* -*- c++ -*- * File : vci_cc_xcache_wrapper_v4.cpp * Date : 26/11/2011 * Copyright : UPMC / LIP6 * Authors : Alain Greiner * * 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 * Alain Greiner , 2011 * * Maintainers: alain */ #include "../include/vci_cc_xcache_wrapper_v4.h" #define DEBUG_GLOBAL 0 #define DEBUG_DCACHE 0 #define DEBUG_ICACHE 0 #define DEBUG_START_CYCLE 0 #define DEBUG_ID 0 namespace soclib { namespace caba { namespace { const char *dcache_fsm_state_str[] = { "DCACHE_IDLE", "DCACHE_WRITE_UPDT", "DCACHE_MISS_VICTIM", "DCACHE_MISS_WAIT", "DCACHE_MISS_UPDT", "DCACHE_UNC_WAIT", "DCACHE_INVAL", "DCACHE_INVAL_GO", "DCACHE_SYNC", "DCACHE_ERROR", "DCACHE_CC_CHECK", "DCACHE_CC_INVAL", "DCACHE_CC_UPDT", }; const char *icache_fsm_state_str[] = { "ICACHE_IDLE", "ICACHE_MISS_VICTIM", "ICACHE_MISS_WAIT", "ICACHE_MISS_UPDT", "ICACHE_UNC_WAIT", "ICACHE_ERROR", "ICACHE_CC_CHECK", "ICACHE_CC_INVAL", "ICACHE_CC_UPDT", }; const char *cmd_fsm_state_str[] = { "CMD_IDLE", "CMD_INS_MISS", "CMD_INS_UNC", "CMD_DATA_MISS", "CMD_DATA_UNC", "CMD_DATA_WRITE", "CMD_DATA_SC", }; const char *rsp_fsm_state_str[] = { "RSP_IDLE", "RSP_INS_MISS", "RSP_INS_UNC", "RSP_DATA_MISS", "RSP_DATA_UNC", "RSP_DATA_WRITE", "RSP_DATA_SC", }; const char *tgt_fsm_state_str[] = { "TGT_IDLE", "TGT_UPDT_WORD", "TGT_UPDT_DATA", "TGT_REQ_BROADCAST", "TGT_REQ_ICACHE", "TGT_REQ_DCACHE", "TGT_RSP_BROADCAST", "TGT_RSP_ICACHE", "TGT_RSP_DCACHE", }; const char *cleanup_fsm_state_str[] = { "CLEANUP_DATA_IDLE", "CLEANUP_DATA_GO", "CLEANUP_INS_IDLE", "CLEANUP_INS_GO", }; } #define tmpl(...) template __VA_ARGS__ VciCcXCacheWrapperV4 using soclib::common::uint32_log2; ///////////////////////////////// tmpl(/**/)::VciCcXCacheWrapperV4( sc_module_name name, int proc_id, const soclib::common::MappingTable &mtp, const soclib::common::MappingTable &mtc, const soclib::common::IntTab &initiator_index_d, const soclib::common::IntTab &initiator_index_c, const soclib::common::IntTab &target_index_c, 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, uint32_t max_frozen_cycles) : soclib::caba::BaseModule(name), p_clk ("clk"), p_resetn ("resetn"), p_vci_ini_d ("vci_ini_d"), p_vci_ini_c ("vci_ini_c"), p_vci_tgt_c ("vci_tgt_c"), m_cacheability_table(mtp.getCacheabilityTable()), m_segment(mtc.getSegment(target_index_c)), m_srcid_d(mtp.indexForId(initiator_index_d)), m_srcid_c(mtc.indexForId(initiator_index_c)), m_dcache_ways(dcache_ways), m_icache_ways(icache_ways), m_cache_words(icache_words), m_cache_words_shift(uint32_log2(icache_words)+uint32_log2(sizeof(data_t))), m_cache_yzmask((~0)< 2) and ((1<<(vci_param::T-1)) >= (wbuf_nlines)) and "Need more TRDID bits."); assert( (icache_words == dcache_words) and "icache_words must be equal at dcache_words."); p_irq = new sc_in [iss_t::n_irq]; r_iss = new iss_t (this->name() , proc_id); r_icache = new GenericCache("icache", icache_ways, icache_sets, icache_words); r_dcache = new GenericCache("dcache", dcache_ways, dcache_sets, dcache_words); r_wbuf = new MultiWriteBuffer("wbuf", wbuf_nwords, wbuf_nlines, dcache_words); r_tgt_buf = new sc_signal [m_cache_words]; r_tgt_be = new sc_signal [m_cache_words]; m_cpt_fsm_dcache = new uint32_t [32]; m_cpt_fsm_icache = new uint32_t [32]; m_cpt_fsm_cmd = new uint32_t [32]; m_cpt_fsm_rsp = new uint32_t [32]; m_cpt_fsm_tgt = new uint32_t [32]; m_cpt_fsm_cleanup = new uint32_t [32]; 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; r_iss->setCacheInfo(cache_info); } // end constructor /////////////////////////////////// tmpl(/**/)::~VciCcXCacheWrapperV4() { delete r_icache ; delete r_wbuf ; delete r_dcache ; delete r_iss; delete [] p_irq; delete [] r_tgt_buf; delete [] r_tgt_be; } //////////////////////// tmpl(void)::print_cpi() { std::cout << "CPU " << m_srcid_d << " : CPI = " << (float)m_cpt_total_cycles/(m_cpt_total_cycles - m_cpt_frz_cycles) << std::endl ; } /* //////////////////////////////////////////////////////// tmpl(void)::print_stats(bool print_wbuf, bool print_fsm) { std::cout << "------------------------------------" << std:: dec << std::endl; std::cout << "CPU " << m_srcid_d << " / Time = " << m_cpt_total_cycles << std::endl; float run_cycles = (float)(m_cpt_total_cycles - m_cpt_frz_cycles); std::cout << "- CPI : " << (float)m_cpt_total_cycles/run_cycles << std::endl ; std::cout << "- CACHABLE INSTRUCTIONS : " << m_cpt_ins_cacheable << std::endl ; std::cout << "- INSTRUCTION CACHE MISS RATE : " << (float)m_cpt_ins_miss*100.0/(float)m_cpt_ins_cacheable << " %" << std::endl ; std::cout << "- NON CACHABLE INSTRUCTIONS : " << m_cpt_ins_uncacheable << std::endl ; std::cout << "- CACHABLE DATA READ : " << m_cpt_data_read_cacheable << std::endl; std::cout << "- DATA CACHE MISS RATE : " << (float)m_cpt_data_read_miss*100.0/(float)m_cpt_data_read_cacheable << " %" << std::endl; std::cout << "- CACHABLE DATA WRITE : " << m_cpt_data_write_cacheable << std::endl ; std::cout << "- CACHED WRITE RATE : " << (float)m_cpt_data_write_hit*100.0/(float)m_cpt_data_write_cacheable << " %" << std::endl; std::cout << "- NON CACHABLE DATA READ : " << m_cpt_data_read_uncacheable << std::endl; std::cout << "- NON CACHABLE DATA WRITE : " << m_cpt_data_write_uncacheable << std::endl; std::cout << "- WRITE RATE : " << (float)m_cpt_data_write_cacheable*100.0/(float)m_cpt_ins_cacheable << " %" << std::endl; std::cout << "- READ RATE : " << (float)m_cpt_data_read_cacheable*100.0/(float)m_cpt_ins_cacheable << " %" << std::endl; std::cout << "- AVERAGE INSTRUCTION MISS COST : " << (float)m_cost_ins_miss_frz/(float)m_cpt_ins_miss << std::endl; std::cout << "- AVERAGE DATA MISS COST : " << (float)m_cost_data_miss_frz/m_cpt_data_read_miss << std::endl; std::cout << "- AVERAGE WRITE COST : " << (float)m_cost_write_frz/m_cpt_data_write_cacheable << std::endl; std::cout << "- CC_UPDATE_ICACHE : " << m_cpt_cc_update_icache << std::endl; std::cout << "- CC_UPDATE_DCACHE : " << m_cpt_cc_update_dcache << std::endl; std::cout << "- CC_INVAL_ICACHE : " << m_cpt_cc_inval_icache << std::endl; std::cout << "- CC_INVAL_ICACHE : " << m_cpt_cc_inval_icache << std::endl; std::cout << "-CC_BROADCAST : " << m_cpt_cc_inval_broadcast << std::endl; // this part is removed because soclib::common::size() not found ... if (print_fsm) { std::cout << "- DCACHE FSM" << std::endl; for (uint32_t i=0; iprintStatistics(); } */ //////////////////////////////////// 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::InstructionResponse irsp; typename iss_t::DataRequest dreq; typename iss_t::DataResponse drsp; ireq.valid = m_ireq_valid; ireq.addr = m_ireq_addr; ireq.mode = m_ireq_mode; irsp.valid = m_irsp_valid; irsp.instruction = m_irsp_instruction; irsp.error = m_irsp_error; dreq.valid = m_dreq_valid; dreq.addr = m_dreq_addr; dreq.mode = m_dreq_mode; dreq.type = m_dreq_type; dreq.wdata = m_dreq_wdata; dreq.be = m_dreq_be; drsp.valid = m_drsp_valid; drsp.rdata = m_drsp_rdata; drsp.error = m_drsp_error; std::cout << std::dec << "Proc " << name() << std::endl; std::cout << " " << ireq << std::endl; std::cout << " " << irsp << std::endl; std::cout << " " << dreq << std::endl; std::cout << " " << drsp << std::endl; std::cout << " " << icache_fsm_state_str[r_icache_fsm.read()] << " | " << dcache_fsm_state_str[r_dcache_fsm.read()] << " | " << cmd_fsm_state_str[r_vci_cmd_fsm.read()] << " | " << rsp_fsm_state_str[r_vci_rsp_fsm.read()] << " | " << tgt_fsm_state_str[r_tgt_fsm.read()] << " | " << cleanup_fsm_state_str[r_cleanup_fsm.read()] << std::endl; if(mode & 0x1) { std::cout << " Write Buffer" << std::endl; 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(); } } ////////////////////////// tmpl(void)::transition() ////////////////////////// { // Reset if ( not p_resetn.read() ) { // iss, write buffer & caches r_iss->reset(); r_wbuf->reset(); r_dcache->reset(); r_icache->reset(); r_cleanup_buffer.reset(); // FSM states r_icache_fsm = ICACHE_IDLE; r_dcache_fsm = DCACHE_IDLE; r_vci_cmd_fsm = CMD_IDLE; r_vci_rsp_fsm = RSP_IDLE; r_tgt_fsm = TGT_IDLE; r_cleanup_fsm = CLEANUP_DATA_IDLE; // synchronisation flip-flops between TGT FSM and ICACHE/DCACHE FSMs r_tgt_icache_req = false; r_tgt_dcache_req = false; // synchronisation flip-flops between ICACHE/DCACHE FSMs and CLEANUP FSM r_icache_cleanup_req = false; r_dcache_cleanup_req = false; // synchronisation flip-flops between ICACHE FSMs and VCI FSMs r_icache_miss_req = false; r_icache_unc_req = false; r_icache_miss_inval = false; r_vci_rsp_ins_error = false; // synchronisation flip-flops between DCACHE FSMs and VCI FSMs r_dcache_miss_req = false; r_dcache_unc_req = false; r_dcache_sc_req = false; r_dcache_miss_inval = false; r_vci_rsp_data_error = false; // pending non cacheable write r_dcache_pending_unc_write = false; // linked load reservation flip-flop r_dcache_ll_valid = false; // uncacheable read buffers r_icache_unc_valid = false; r_dcache_unc_valid = false; // response FIFOs r_vci_rsp_fifo_icache.init(); r_vci_rsp_fifo_dcache.init(); // activity counters (consommation) m_conso_dcache_data_read = 0; m_conso_dcache_data_write = 0; m_conso_dcache_dir_read = 0; m_conso_dcache_dir_write = 0; m_conso_icache_data_read = 0; m_conso_icache_data_write = 0; m_conso_icache_dir_read = 0; m_conso_icache_dir_write = 0; m_conso_wbuf_read = 0; m_conso_wbuf_write = 0; // coherence request counters m_cpt_cc_update_icache = 0; m_cpt_cc_update_dcache = 0; m_cpt_cc_inval_icache = 0; m_cpt_cc_inval_dcache = 0; m_cpt_cc_inval_broadcast = 0; // CPI computation m_cpt_frz_cycles = 0; m_cpt_total_cycles = 0; m_cpt_stop_simulation = 0; // number of executed instructions m_cpt_ins_cacheable = 0; m_cpt_ins_uncacheable = 0; m_cpt_ins_miss = 0; // number of data requests m_cpt_data_read_cacheable = 0; m_cpt_data_read_miss = 0; m_cpt_data_read_uncacheable = 0; m_cpt_data_write_cacheable = 0; m_cpt_data_write_uncacheable = 0; m_cpt_data_write_hit = 0; m_cpt_data_ll = 0; m_cpt_data_sc = 0; // number of external register requests m_cpt_xtn_dcache_inval = 0; m_cpt_xtn_sync = 0; // cumulated cost (frozen cycles) for write and miss m_cost_write_frz = 0; m_cost_data_miss_frz = 0; m_cost_ins_miss_frz = 0; m_cpt_imiss_transaction = 0; m_cpt_dmiss_transaction = 0; m_cpt_iunc_transaction = 0; m_cpt_dunc_transaction = 0; m_cpt_write_transaction = 0; m_cpt_sc_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; for (uint32_t i=0; i<32 ; ++i) m_cpt_fsm_icache [i] = 0; for (uint32_t i=0; i<32 ; ++i) m_cpt_fsm_dcache [i] = 0; for (uint32_t i=0; i<32 ; ++i) m_cpt_fsm_cmd [i] = 0; for (uint32_t i=0; i<32 ; ++i) m_cpt_fsm_rsp [i] = 0; for (uint32_t i=0; i<32 ; ++i) m_cpt_fsm_tgt [i] = 0; for (uint32_t i=0; i<32 ; ++i) m_cpt_fsm_cleanup [i] = 0; return; } // Response FIFOs default values bool vci_rsp_fifo_icache_get = false; bool vci_rsp_fifo_icache_put = false; data_t vci_rsp_fifo_icache_data = 0; bool vci_rsp_fifo_dcache_get = false; bool vci_rsp_fifo_dcache_put = false; data_t vci_rsp_fifo_dcache_data = 0; // FSMs activity m_cpt_fsm_dcache [r_dcache_fsm.read() ] ++; m_cpt_fsm_icache [r_icache_fsm.read() ] ++; m_cpt_fsm_cmd [r_vci_cmd_fsm.read()] ++; m_cpt_fsm_rsp [r_vci_rsp_fsm.read()] ++; m_cpt_fsm_tgt [r_tgt_fsm.read() ] ++; m_cpt_fsm_cleanup [r_cleanup_fsm.read()] ++; m_cpt_total_cycles++; ////////////////////////////////////////////////////////////////////////////// // The TGT_FSM receives the coherence requests. // It controls the following ressources: // - r_tgt_fsm // - r_tgt_buf[nwords] // - r_tgt_be[nwords] // - r_tgt_update // - r_tgt_word_min // - r_tgt_word_max // - r_tgt_word_count // - r_tgt_addr // - r_tgt_srcid // - r_tgt_trdid // - r_tgt_pktid // - r_tgt_icache_req (set) // - r_tgt_dcache_req (set) // // All VCI commands must be CMD_WRITE. // - If the 2 LSB bits of the VCI address are 11, it is a broadcast request. // It is a multicast request otherwise. // - For multicast requests, the ADDRESS[2] bit distinguishes DATA/INS // (0 for data / 1 for instruction), and the ADDRESS[3] bit distinguishes // INVAL/UPDATE (0 for invalidate / 1 for UPDATE). // // For all types of coherence resqests, the line index (i.e. the Z & Y fields) // is coded on 34 bits, and is contained in the WDATA and BE fields // of the first VCI flit. // - for a multicast invalidate or for a broadcast invalidate request // the VCI packet length is 1 word. // - for an update request the VCI packet length is (n+2) words. // The WDATA field of the second VCI word contains the word index. // The WDATA field of the n following words contains the values. // - for all transaction types, the VCI response is one single word. // In case of errors in the VCI command packet, the simulation // is stopped with an error message. // // This FSM is NOT pipelined : It consumes a new request on the VCI port // only when the previous request is completed. // // The VCI_TGT FSM stores the external request arguments in the // IDLE, UPDT_WORD & UPDT_DATA states. It sets the r_tgt_icache_req // and/or the r_tgt_dcache_req flip-flops to signal the coherence request // to the ICACHE & DCACHE FSMs in the REQ_ICACHE, REQ_DCACHE & REQ_BROADCAST // states. It waits the completion of the coherence request by polling the // r_tgt_*cache_req flip-flops in the RSP_ICACHE, RSP_DCACHE & RSP_BROADCAST // states. These flip-flops are reset by the ICACHE_FSM and/or DCACHE_FSM. // These two FSMs signal if a VCI answer must be send by setting // the r_tgt_icache_rsp and/or the r_tgt_dcache_rsp flip_flops. /////////////////////////////////////////////////////////////////////////////// switch( r_tgt_fsm.read() ) { ////////////// case TGT_IDLE: { vci_addr_t tgt_addr; if ( p_vci_tgt_c.cmdval.read() ) { vci_addr_t address = p_vci_tgt_c.address.read(); if ( p_vci_tgt_c.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; exit(0); } // address checking for multi-update or multi-invalidate 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; exit(0); } // address of the target cache line = nline * m_cache_words * 4 tgt_addr = (vci_addr_t)(((((uint64_t)p_vci_tgt_c.be.read() & 0x3) << 32) | (uint64_t)p_vci_tgt_c.wdata.read() ) << m_cache_words_shift); r_tgt_srcid = p_vci_tgt_c.srcid.read(); r_tgt_trdid = p_vci_tgt_c.trdid.read(); r_tgt_pktid = p_vci_tgt_c.pktid.read(); r_tgt_addr = tgt_addr; // target line (for *CACHE FSMs) if ( (address&0x3) == 0x3 ) // broadcast invalidate { if ( not p_vci_tgt_c.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_fsm = TGT_REQ_BROADCAST; m_cpt_cc_inval_broadcast++ ; } else // multi-update or multi-invalidate { uint32_t cell = address - m_segment.baseAddress(); if (cell == 0) // invalidate data { if ( not p_vci_tgt_c.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_tgt_fsm = TGT_REQ_DCACHE; m_cpt_cc_inval_dcache++ ; } else if (cell == 4) // invalidate instruction { if ( not p_vci_tgt_c.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_tgt_fsm = TGT_REQ_ICACHE; m_cpt_cc_inval_icache++ ; } else if (cell == 8) // update data { if ( p_vci_tgt_c.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); } r_tgt_update = true; r_tgt_update_data = true; r_tgt_fsm = TGT_UPDT_WORD; m_cpt_cc_update_dcache++; } else // update instruction { if ( p_vci_tgt_c.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); } r_tgt_update = true; r_tgt_update_data = false; r_tgt_fsm = TGT_UPDT_WORD; m_cpt_cc_update_icache++; } } // end if multi } // end if cmdval break; } ////////////////// case TGT_UPDT_WORD: // first word index acquisition fo update requests { if (p_vci_tgt_c.cmdval.read()) { if ( p_vci_tgt_c.eop.read() ) { std::cout << "error in component VCI_CC_XCACHE_WRAPPER " << name() << std::endl; std::cout << "the MULTI-UPDATE command length must be N+2 words" << std::endl; exit(0); } for ( size_t i=0 ; i= m_cache_words ) { std::cout << "error in component VCI_CC_XCACHE_WRAPPER " << name() << std::endl; std::cout << "the reveived MULTI-UPDATE command length is wrong" << std::endl; exit(0); } r_tgt_buf[word] = p_vci_tgt_c.wdata.read(); r_tgt_be [word] = p_vci_tgt_c.be.read(); r_tgt_word_count = word + 1; if (p_vci_tgt_c.eop.read()) // last word { r_tgt_word_max = word; // last modified word if(r_tgt_update_data.read()) r_tgt_fsm = TGT_REQ_DCACHE; else r_tgt_fsm = TGT_REQ_ICACHE; } } break; } /////////////////////// case TGT_REQ_BROADCAST: // set the requests (if no previous request pending) { if (not r_tgt_icache_req.read() and not r_tgt_dcache_req.read()) { r_tgt_fsm = TGT_RSP_BROADCAST; r_tgt_icache_req = true; r_tgt_dcache_req = true; } break; } //////////////////// case TGT_REQ_ICACHE: // set the request (if no previous request pending) { if ( not r_tgt_icache_req.read() ) { r_tgt_fsm = TGT_RSP_ICACHE; r_tgt_icache_req = true; } break; } //////////////////// case TGT_REQ_DCACHE: // set the request (if no previous request pending) { if ( not r_tgt_dcache_req.read() ) { r_tgt_fsm = TGT_RSP_DCACHE; r_tgt_dcache_req = true; } break; } /////////////////////// case TGT_RSP_BROADCAST: // waiting acknowlege from both dcache fsm and icache fsm // no VCI response when the r_tgt_*cache_rsp flip_flop is false { if ( not r_tgt_icache_req.read() and not r_tgt_dcache_req.read() ) { if ( r_tgt_icache_rsp.read() or r_tgt_dcache_rsp.read() ) // at least one response { if ( p_vci_tgt_c.rspack.read()) { // reset dcache first if activated if (r_tgt_dcache_rsp) r_tgt_dcache_rsp = false; else r_tgt_icache_rsp = false; } } else { r_tgt_fsm = TGT_IDLE; } } break; } //////////////////// case TGT_RSP_ICACHE: // waiting acknowledge from the icache fsm { // no VCI response when the r_tgt_icache_rsp flip_flop is false if ( not r_tgt_icache_req.read() and p_vci_tgt_c.rspack.read() ) { r_tgt_fsm = TGT_IDLE; r_tgt_icache_rsp = false; } break; } //////////////////// case TGT_RSP_DCACHE: // waiting acknowledge from the dcache fsm { // no VCI response when the r_tgt_dcache_rsp flip_flop is false if ( not r_tgt_dcache_req.read() and p_vci_tgt_c.rspack.read() ) { r_tgt_fsm = TGT_IDLE; r_tgt_dcache_rsp = false; } break; } } // end switch TGT_FSM ///////////////////////////////////////////////////////////////////// // Get data and instruction requests from processor /////////////////////////////////////////////////////////////////////// typename iss_t::InstructionRequest ireq = ISS_IREQ_INITIALIZER; typename iss_t::DataRequest dreq = ISS_DREQ_INITIALIZER; r_iss->getRequests(ireq, dreq); /////////////////////////////////////////////////////////////////////////////// // The ICACHE FSM controls the following ressources: // - r_icache_fsm // - r_icache_fsm_save // - r_icache_addr_save // - r_icache_miss_req (set) // - r_icache_unc_req (set) // - r_icache_cleanup_req (set) // - r_icache_cleanup_line // - r_icache_cleanup_set // - r_icache_cleanup_way // - r_icache_miss_inval // - r_icache (instruction cache access) // - r_vci_rsp_ins_error (reset) // - r_tgt_icache_req (reset) // - r_tgt_icache_rsp // - ireq & irsp structures for communication with the processor // // 1/ Coherence requests (update or invalidate) have highest priority. // They are taken into account in IDLE, UNC_WAIT, and MISS_WAIT states. // In case of coherence request the ICACHE FSM goes to the CC_CHECK // state to test the cache hit, and then to the CC_INVAL or // CC_UPDATE states to execute the request. It reset the r_tgt_icache_req // flip_flop to signal completion, writes in the r_tgt_icache_rsp // to allow the VCI response, and returns in the pre-empted state. // // 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. // // 3/ In case of uncacheable instruction, the VCI_RSP FSM writes the // requested instruction in the r_icache_unc_buf register, and // sets the r_icache_unc_valid flip_flop. This flip_flop is reset // by the ICACHE FSM. // // 4/ In case of bus error, the VCI_RSP FSM sets the r_vci_rsp_ins_error // flip-flop, and does not write any data in the response FIFO. // The r_vci_rsp_ins_error flip-flop is reset by the ICACHE FSM. //////////////////////////////////////////////////////////////////////////////// // The default value for irsp.valid is false typename iss_t::InstructionResponse irsp = ISS_IRSP_INITIALIZER; switch( r_icache_fsm.read() ) { ///////////////// case ICACHE_IDLE: { if ( r_tgt_icache_req.read() ) // coherence request { r_icache_fsm = ICACHE_CC_CHECK; r_icache_fsm_save = r_icache_fsm.read(); break; } if ( ireq.valid ) // processor request { bool cacheable = m_cacheability_table[ireq.addr]; vci_addr_t addr = (vci_addr_t)ireq.addr; if ( cacheable ) // cacheable { data_t inst; bool hit = r_icache->read(addr, &inst); m_conso_icache_dir_read++; m_conso_icache_data_read++; if ( !hit ) // cacheable miss { // in order to avoid a dead-lock with the mem_cache // (in case of simultaneous broadcast for example), // we check that the previous cleanup request is completed // and the ICACHE FSM is blocked in IDLE state until completion if ( not r_icache_cleanup_req.read() ) { r_icache_fsm = ICACHE_MISS_VICTIM; r_icache_miss_req = true; r_icache_addr_save = addr; m_cpt_ins_miss++; m_cost_ins_miss_frz++; } } else // cacheable hit { irsp.valid = true; irsp.instruction = inst; m_cpt_ins_cacheable++; } } else // non cacheable { if ( r_icache_unc_valid.read() and (addr == r_icache_addr_save.read()) ) { r_icache_unc_valid = false; irsp.valid = true; irsp.instruction = r_icache_unc_buf.read(); m_cpt_ins_uncacheable++; } else { r_icache_unc_valid = false; r_icache_fsm = ICACHE_UNC_WAIT; r_icache_unc_req = true; r_icache_addr_save = addr; } } } break; } //////////////////////// case ICACHE_MISS_VICTIM: // Selects (and invalidates) a victim line { // Set the r_icache_cleanup_req flip-flop // when the selected slot is not empty m_cost_ins_miss_frz++; size_t way; size_t set; vci_addr_t victim; r_icache_cleanup_req = r_icache->victim_select( r_icache_addr_save.read(), &victim, &way, &set ); r_icache_cleanup_line = victim; r_icache_cleanup_way = way; r_icache_cleanup_set = set; r_icache_fsm = ICACHE_MISS_WAIT; break; } ////////////////////// case ICACHE_MISS_WAIT: // waiting the response to a miss request { // to test a bus error m_cost_ins_miss_frz++; if ( r_tgt_icache_req.read() ) // coherence request { r_icache_fsm = ICACHE_CC_CHECK; r_icache_fsm_save = r_icache_fsm.read(); break; } if ( r_vci_rsp_ins_error.read() ) { r_icache_fsm = ICACHE_ERROR; } else if ( r_vci_rsp_fifo_icache.rok() ) { r_icache_update_word = 0; r_icache_fsm = ICACHE_MISS_UPDT; } break; } ////////////////////// case ICACHE_MISS_UPDT: // Update the cache (one word per cycle) { m_cost_ins_miss_frz++; if ( r_vci_rsp_fifo_icache.rok() ) { size_t word = r_icache_update_word.read(); vci_addr_t addr = r_icache_addr_save.read(); size_t way = r_icache_cleanup_way.read(); size_t set = r_icache_cleanup_set.read(); m_conso_icache_data_write++; // if the pending miss is cancelled by a matching coherence request // we pop the FIFO, but we don't update the cache if ( not r_icache_miss_inval.read() ) r_icache->write( way, set, word, r_vci_rsp_fifo_icache.read() ); vci_rsp_fifo_icache_get = true; r_icache_update_word = word+1; // if last word, finish the update if ( word == m_cache_words-1 ) { if ( not r_icache_miss_inval.read() ) { m_conso_icache_dir_write++; r_icache->victim_update_tag(addr, way, set); } r_icache_miss_inval = false; r_icache_fsm = ICACHE_IDLE; } } break; } ///////////////////// case ICACHE_UNC_WAIT: // waiting the response to an uncached request { if ( r_tgt_icache_req.read() ) // coherence request { r_icache_fsm = ICACHE_CC_CHECK; r_icache_fsm_save = r_icache_fsm.read(); break; } if ( r_vci_rsp_ins_error ) { r_icache_fsm = ICACHE_ERROR; } else if ( r_vci_rsp_fifo_icache.rok() ) { vci_rsp_fifo_icache_get = true; r_icache_unc_buf = r_vci_rsp_fifo_icache.read(); r_icache_unc_valid = true; r_icache_fsm = ICACHE_IDLE; } break; } ////////////////// case ICACHE_ERROR: { irsp.error = true; irsp.valid = true; r_icache_fsm = ICACHE_IDLE; r_vci_rsp_ins_error = false; break; } ///////////////////// case ICACHE_CC_CHECK: // check directory in case of coherence request { vci_addr_t addr = r_tgt_addr.read(); vci_addr_t mask = ~((m_cache_words<<2)-1); if( (r_icache_fsm_save.read() == ICACHE_MISS_WAIT) and ((r_icache_addr_save.read() & mask) == (addr & mask))) // The coherence request matches a pending miss { r_icache_miss_inval = true; r_tgt_icache_req = false; r_tgt_icache_rsp = r_tgt_update.read(); r_icache_fsm = r_icache_fsm_save.read(); } else // no match for a pending miss { size_t way; size_t set; size_t word; bool hit = r_icache->hit(addr, &way, &set, &word); r_icache_cc_way = way; r_icache_cc_set = set; m_conso_icache_dir_read++; if ( hit and r_tgt_update.read() ) // hit update { r_icache_fsm = ICACHE_CC_UPDT; r_icache_update_word = r_tgt_word_min.read(); } else if ( hit and not r_tgt_update.read() ) // hit inval { r_icache_fsm = ICACHE_CC_INVAL; } else // miss can happen { r_tgt_icache_req = false; r_tgt_icache_rsp = r_tgt_update.read(); r_icache_fsm = r_icache_fsm_save.read(); } } break; } ///////////////////// case ICACHE_CC_INVAL: { vci_addr_t nline; r_icache->inval( r_icache_cc_way.read(), r_icache_cc_way.read(), &nline ); r_tgt_icache_req = false; r_tgt_icache_rsp = true; r_icache_fsm = r_icache_fsm_save.read(); break; } ///////////////////// case ICACHE_CC_UPDT: { size_t word = r_icache_update_word.read(); r_icache->write( r_icache_cc_way.read(), r_icache_cc_set.read(), word, r_tgt_buf[word].read(), r_tgt_be[word].read() ); r_icache_update_word = word+1; if ( word == r_tgt_word_max.read() ) // last word { r_tgt_icache_req = false; r_tgt_icache_rsp = true; r_icache_fsm = r_icache_fsm_save.read(); } break; } } // end switch r_icache_fsm // save the IREQ and IRSP fields for the print_trace() function m_ireq_valid = ireq.valid; m_ireq_addr = ireq.addr; m_ireq_mode = ireq.mode; m_irsp_valid = irsp.valid; m_irsp_instruction = irsp.instruction; m_irsp_error = irsp.error; //////////////////////////////////////////////////////////////////////:///////////// // 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_be_save // - r_dcache_way_save // - r_dcache_set_save // - r_dcache_word_save // - r_dcache_miss_req (set) // - r_dcache_unc_req (set) // - r_dcache_sc_req (set) // - r_dcache_cleanup_req (set) // - r_vci_rsp_data_error (reset) // - r_tgt_dcache_req (reset) // - r_wbuf write // - drsp structure // // 1/ Coherence requests : // There is a coherence request when the tgt_dcache_req flip-flop is set, // requesting a line invalidation or a line update. // Coherence requests are taken into account in IDLE, UNC_WAIT, MISS_WAIT states, // 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 requests : // Processor READ requests are taken into account in IDLE state only. // In order to support WRITE bursts, write requests are taken into account // in the WRITE_UPDT state as well as in the IDLE state. // - The processor read requests cannot be satisfied if // there is a cached read miss, or an uncached read. // - The processor write requests cannot be satisfied when the write buffer is full. // // 3/ Atomic instructions LL/SC // The reservation registers (r_dcache_ll_valid, r_dcache_ll_addr and // r_dcache_ll_data are stored in the L1 cache controller, and not in the // memory controller. // - LL requests from the processor and are transmitted as standard // VCI read transactions (one word / one line, depending on the cacheability). // - SC requests from the processor are systematically transmitted to the // memory cache as compare&swap requests (both the data value stored in the // r_dcache_ll_data register and the new value). // The LL/SC address can be cacheable or not cacheable. // // 4/ Non cacheable access // This component implement a strong order between non cacheable access // (read or write) : A new non cacheable VCI transaction starts only when // the previous non cacheable transaction is completed. Both cacheable and // non cacheable transactions use the write buffer, but the DCACHE FSM registers // a non cacheable write transaction posted in the write buffer by setting the // r_dcache_pending_unc_write flip_flop. All other non cacheable requests // are stalled until this flip-flop is reset by the VCI_RSP_FSM (when the // pending non cacheable write transaction completes). // // 5/ 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, without writing any data in the // r_vci_rsp_fifo_dcache FIFO, 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. /////////////////////////////////////////////////////////////////////////////////// // The default value for drsp.valid is false typename iss_t::DataResponse drsp = ISS_DRSP_INITIALIZER; switch ( r_dcache_fsm.read() ) { ///////////////// case DCACHE_IDLE: // waiting requests from processor { if ( r_tgt_dcache_req.read() ) // coherence request { r_dcache_fsm = DCACHE_CC_CHECK; r_dcache_fsm_save = r_dcache_fsm.read(); break; } if ( dreq.valid ) // processor request { bool cacheable = m_cacheability_table[dreq.addr]; vci_addr_t addr = (vci_addr_t)dreq.addr; switch( dreq.type ) { case iss_t::DATA_LL: case iss_t::DATA_READ: { if ( cacheable ) // cacheable read { data_t rdata; bool hit = r_dcache->read(addr, &rdata); m_conso_dcache_dir_read++; m_conso_dcache_data_read++; if ( !hit ) // cacheable read miss { // in order to avoid a dead-lock with the mem_cache // (in case of simultaneous broadcast for example), // we check that the previous cleanup request is completed // if not the DCACHE_FSM is blocked in IDLE state until completion if ( not r_dcache_cleanup_req.read() ) { r_dcache_fsm = DCACHE_MISS_VICTIM; r_dcache_miss_req = true; r_dcache_addr_save = addr; m_cpt_data_read_miss++; m_cost_data_miss_frz++; } } else // cacheable read hit { m_cpt_data_read_cacheable++; drsp.valid = true; drsp.rdata = rdata; // makes reservation in case of LL if( dreq.type == iss_t::DATA_LL ) { m_cpt_data_ll++; r_dcache_ll_valid = true; r_dcache_ll_data = rdata; r_dcache_ll_addr = addr; } } } else // non cacheable read { // non cacheable accesses must be strongly ordered // A non cacheable read must be delayed if there is // a pending uncacheable write in the write buffer if ( not r_dcache_pending_unc_write.read() ) { if ( r_dcache_unc_valid.read() and // hit (addr == r_dcache_addr_save.read()) ) { r_dcache_unc_valid = false; drsp.valid = true; drsp.rdata = r_dcache_unc_buf.read(); m_cpt_data_read_uncacheable++; // makes reservation in case of uncacheable LL if( dreq.type == iss_t::DATA_LL ) { m_cpt_data_ll++; r_dcache_ll_valid = true; r_dcache_ll_data = r_dcache_unc_buf.read(); r_dcache_ll_addr = addr; } } else // miss { r_dcache_unc_valid = false; r_dcache_unc_req = true; r_dcache_fsm = DCACHE_UNC_WAIT; r_dcache_addr_save = addr; } } // end if pending_unc_write } break; } case iss_t::DATA_SC: { // - if a previous LL (with the same address) is registered, // we makes a SC transaction, that will store the response // in the r_dcache_unc_buf register (0 if success). // As for the non cacheable read, we must test the // r_dcache_unc_valid flip-flop to detect the SC completion, // return the value stored in r_dcache_unc_buf, and invalidate // the LL reservation. // - if there is no registerd LL, we just stay in IDLE state // and return 1 (atomic access failed) if( r_dcache_ll_valid.read() and (r_dcache_ll_addr.read() == addr)) { if ( r_dcache_unc_valid.read() and // SC done (addr == r_dcache_addr_save.read()) ) { r_dcache_ll_valid = false; r_dcache_unc_valid = false; drsp.valid = true; drsp.rdata = r_dcache_unc_buf.read(); m_cpt_data_sc++; } else // SC to be done { r_dcache_sc_req = true; r_dcache_fsm = DCACHE_UNC_WAIT; r_dcache_addr_save = addr; r_dcache_wdata_save = dreq.wdata; } } else // no registered LL { drsp.valid = true; drsp.rdata = 1; r_dcache_ll_valid = false; } break; } case iss_t::XTN_READ: case iss_t::XTN_WRITE: { // only DCACHE INVALIDATE and SYNC requests are supported if ( dreq.addr>>2 == iss_t::XTN_DCACHE_INVAL ) { m_cpt_xtn_dcache_inval++; r_dcache_fsm = DCACHE_INVAL; r_dcache_wdata_save = dreq.wdata; } else if ( dreq.addr>>2 == iss_t::XTN_SYNC ) { m_cpt_xtn_sync++; // Test if write buffer is already empty if ( r_wbuf->empty() ) { drsp.valid = true; r_dcache_fsm = DCACHE_IDLE; } else { r_dcache_fsm = DCACHE_SYNC; } } else { std::cout << "Warning in VCI_CC_XCACHE_WRAPPER " << name() << std::endl; std::cout << "Unsupported external access : " << (dreq.addr>>2) << std::endl; drsp.valid = true; r_dcache_fsm = DCACHE_IDLE; } break; } case iss_t::DATA_WRITE: { if ( cacheable ) // cacheable write { bool hit; size_t way = 0; size_t set = 0; size_t word = 0; m_conso_dcache_dir_read++; hit = r_dcache->hit(addr, &way, &set, &word); m_conso_wbuf_write++; bool wok = r_wbuf->write(addr, dreq.be, dreq.wdata, cacheable); if ( wok ) { m_cpt_data_write_cacheable++; drsp.valid = true; if (hit) // cached write { m_cpt_data_write_hit++; r_dcache_fsm = DCACHE_WRITE_UPDT; r_dcache_addr_save = addr; r_dcache_wdata_save = dreq.wdata; r_dcache_be_save = dreq.be; r_dcache_way_save = way; r_dcache_set_save = set; r_dcache_word_save = word; } else // non cached { r_dcache_fsm = DCACHE_IDLE; } } else // write miss into write buffer { r_dcache_fsm = DCACHE_IDLE; m_cost_write_frz++; } } else // non cacheable write { // non cacheable accesses must be strongly ordered // A non cacahble write must be delayed if there is // a pending uncacheable write in the write buffer if ( not r_dcache_pending_unc_write.read() ) { m_conso_wbuf_write++; bool wok = r_wbuf->write(addr, dreq.be, dreq.wdata, cacheable); if ( wok ) { m_cpt_data_write_uncacheable++; drsp.valid = true; } } r_dcache_fsm = DCACHE_IDLE; } break; } } // end switch dreq.type } // end if dreq.valid break; } /////////////////////// case DCACHE_WRITE_UPDT: { // cache update (address, data & be from the previous cycle) m_conso_dcache_data_write++; r_dcache->write( r_dcache_way_save.read(), r_dcache_set_save.read(), r_dcache_word_save.read(), r_dcache_wdata_save.read(), r_dcache_be_save.read() ); #if DEBUG_DCACHE if ( (m_cpt_total_cycles > DEBUG_START_CYCLE) and (m_srcid_d == DEBUG_ID) ) { std::cout << " Writing one word :" << std::hex << " data = " << r_dcache_wdata_save.read() << " / be = " << r_dcache_be_save.read() << " / way = " << r_dcache_way_save.read() << " / set = " << r_dcache_set_save.read() << " / word = " << r_dcache_word_save.read() << std::endl; } #endif // possible write after write if ( dreq.valid and (dreq.type == iss_t::DATA_WRITE) ) { bool cacheable = m_cacheability_table[dreq.addr]; vci_addr_t addr = (vci_addr_t)dreq.addr; if ( cacheable ) // cacheable write { bool hit; size_t way = 0; size_t set = 0; size_t word = 0; m_conso_dcache_dir_read++; hit = r_dcache->hit(addr, &way, &set, &word); m_conso_wbuf_write++; bool wok = r_wbuf->write(addr, dreq.be, dreq.wdata, cacheable); if (wok) { m_cpt_data_write_cacheable++; drsp.valid = true; if (hit) // cached write { m_cpt_data_write_hit++; r_dcache_fsm = DCACHE_WRITE_UPDT; r_dcache_addr_save = addr; r_dcache_wdata_save = dreq.wdata; r_dcache_be_save = dreq.be; r_dcache_way_save = way; r_dcache_set_save = set; r_dcache_word_save = word; } else // uncached write { r_dcache_fsm = DCACHE_IDLE; } } else // write miss into write buffer { m_cost_write_frz++; r_dcache_fsm = DCACHE_IDLE; } } else // non cacheable write { // non cacheable accesses must be strongly ordered // A non cacahble write must be delayed if there is // a pending uncacheable write in the write buffer if ( not r_dcache_pending_unc_write.read() ) { m_conso_wbuf_write++; bool wok = r_wbuf->write(addr, dreq.be, dreq.wdata, cacheable); if ( wok ) { m_cpt_data_write_uncacheable++; drsp.valid = true; } } r_dcache_fsm = DCACHE_IDLE; } } else // no valid write request { r_dcache_fsm = DCACHE_IDLE; } break; } //////////////////////// case DCACHE_MISS_VICTIM: // Selects (and invalidates) a victim line { // Set the r_dcache_cleanup_req flip-flop // when the selected slot is not empty m_cost_data_miss_frz++; size_t way; size_t set; vci_addr_t addr = r_dcache_addr_save.read(); vci_addr_t victim; bool cleanup_requested = r_dcache->victim_select( addr, &victim, &way, &set ); r_dcache_cleanup_line = victim; r_dcache_cleanup_way = way; r_dcache_cleanup_set = set; r_dcache_cleanup_req = cleanup_requested; r_dcache_fsm = DCACHE_MISS_WAIT; break; } ////////////////////// case DCACHE_MISS_WAIT: // Waiting the response to a miss request { // to test a bus error m_cost_data_miss_frz++; if ( r_tgt_dcache_req.read() ) // coherence request { r_dcache_fsm = DCACHE_CC_CHECK; r_dcache_fsm_save = r_dcache_fsm.read(); break; } if ( r_vci_rsp_data_error.read() ) { r_dcache_fsm = DCACHE_ERROR; } else if ( r_vci_rsp_fifo_dcache.rok() ) { r_dcache_update_word = 0; r_dcache_fsm = DCACHE_MISS_UPDT; } break; } ////////////////////// case DCACHE_MISS_UPDT: // Update the cache (one word per cycle) { m_cost_data_miss_frz++; size_t word = r_dcache_update_word.read(); vci_addr_t addr = r_dcache_addr_save.read(); size_t way = r_dcache_cleanup_way.read(); size_t set = r_dcache_cleanup_set.read(); if ( r_vci_rsp_fifo_dcache.rok() ) { if ( not r_dcache_miss_inval.read() ) // no matching coherence request { m_conso_dcache_data_write++; r_dcache->write( way, set, word, r_vci_rsp_fifo_dcache.read() ); if ( word == m_cache_words-1 ) // last word { m_conso_dcache_dir_write++; r_dcache->victim_update_tag(addr, way, set); r_dcache_fsm = DCACHE_IDLE; } vci_rsp_fifo_dcache_get = true; r_dcache_update_word = word+1; } else // if there is a matching coherence request : // we pop the response FIFO, but we don't update the cache // when we receive the last word, we send a cleanup for the // missing line and return to the IDLE state { if ( word < m_cache_words-1 ) { vci_rsp_fifo_dcache_get = true; r_dcache_update_word = word+1; } else // last word { if ( not r_dcache_cleanup_req ) { vci_rsp_fifo_dcache_get = true; r_dcache_cleanup_req = true; r_dcache_cleanup_line = r_dcache_addr_save.read() >> m_cache_words_shift; r_dcache_miss_inval = false; r_dcache_fsm = DCACHE_IDLE; } } } #if DEBUG_DCACHE if ( (m_cpt_total_cycles > DEBUG_START_CYCLE) and (m_srcid_d == DEBUG_ID) ) { if ( r_dcache_miss_inval.read() ) { if ( word < m_cache_words-1 ) { std::cout << " Matching coherence request:" << " pop the FIFO, don't update the cache" << std::endl; } else { std::cout << " Matching coherence request:" << " last word : send a cleanup request " << std::endl; } } else { std::cout << " Write one word:" << " address = " << addr << " / data = " << r_vci_rsp_fifo_dcache.read() << " / way = " << way << " / set = " << set << " / word = " << word << std::endl; } } #endif } break; } ///////////////////// case DCACHE_UNC_WAIT: // Waiting the response to an uncached request { if ( r_tgt_dcache_req ) // coherence request { r_dcache_fsm = DCACHE_CC_CHECK; r_dcache_fsm_save = r_dcache_fsm; break; } if ( r_vci_rsp_data_error ) { r_dcache_fsm = DCACHE_ERROR; } else if ( r_vci_rsp_fifo_dcache.rok() ) { vci_rsp_fifo_dcache_get = true; r_dcache_unc_valid = true; r_dcache_unc_buf = r_vci_rsp_fifo_dcache.read(); r_dcache_fsm = DCACHE_IDLE; } break; } ////////////////// case DCACHE_ERROR: // signal a read bus error to the processor { r_dcache_fsm = DCACHE_IDLE; r_vci_rsp_data_error = false; drsp.error = true; drsp.valid = true; break; } ////////////////// case DCACHE_INVAL: // XTN inval is done in two cycles // In this state we test the cache hit { uint32_t data; // unused size_t word; // unused size_t way; size_t set; bool hit = r_dcache->read( r_dcache_wdata_save.read(), &data, &way, &set, &word ); if ( hit ) // inval to be done { r_dcache_way_save = way; r_dcache_set_save = set; r_dcache_fsm = DCACHE_INVAL_GO; } else // nothing to do { drsp.valid = true; r_dcache_fsm = DCACHE_IDLE; } break; } ///////////////////// case DCACHE_INVAL_GO: // XTN inval is done in two cycles // In this state we wait to post a cleanup request // and make the inval when cleanup is possible { if ( r_tgt_dcache_req ) // coherence request { r_dcache_fsm = DCACHE_CC_CHECK; r_dcache_fsm_save = r_dcache_fsm; break; } if ( not r_dcache_cleanup_req .read() ) { vci_addr_t nline; r_dcache_cleanup_req = r_dcache->inval( r_dcache_way_save.read(), r_dcache_set_save.read(), &nline ); r_dcache_cleanup_line = r_dcache_wdata_save.read() >> m_cache_words_shift; r_dcache_fsm = DCACHE_IDLE; drsp.valid = true; } break; } ///////////////// case DCACHE_SYNC: // waiting until the write buffer is empty { if ( r_tgt_dcache_req ) // coherence request { r_dcache_fsm = DCACHE_CC_CHECK; r_dcache_fsm_save = r_dcache_fsm; break; } if ( r_wbuf->empty() ); { drsp.valid = true; r_dcache_fsm = DCACHE_IDLE; } break; } ///////////////////// case DCACHE_CC_CHECK: // read directory in case of coherence request { vci_addr_t addr = r_tgt_addr.read(); vci_addr_t mask = ~((m_cache_words<<2)-1); if( (r_dcache_fsm_save.read() == DCACHE_MISS_WAIT) and ((r_dcache_addr_save.read() & mask) == (addr & mask)) ) // The coherence request matches a pending miss { r_dcache_miss_inval = true; r_tgt_dcache_req = false; r_tgt_dcache_rsp = r_tgt_update.read(); r_dcache_fsm = r_dcache_fsm_save.read(); } else // no match for a pending miss { size_t way; size_t set; size_t word; bool hit = r_dcache->hit( addr, &way, &set, &word ); r_dcache_cc_way = way; r_dcache_cc_set = set; m_conso_dcache_dir_read++; if ( hit and r_tgt_update.read() ) // hit update { r_dcache_fsm = DCACHE_CC_UPDT; r_dcache_update_word = r_tgt_word_min.read(); } else if (hit and not r_tgt_update.read() ) // hit inval { r_dcache_fsm = DCACHE_CC_INVAL; } else // miss can happen { r_tgt_dcache_req = false; r_tgt_dcache_rsp = r_tgt_update.read(); r_dcache_fsm = r_dcache_fsm_save.read(); } } break; } ///////////////////// case DCACHE_CC_INVAL: { vci_addr_t nline; r_dcache->inval( r_dcache_cc_way.read(), r_dcache_cc_set.read(), &nline ); r_tgt_dcache_req = false; r_tgt_dcache_rsp = true; r_dcache_fsm = r_dcache_fsm_save.read(); break; } //////////////////// case DCACHE_CC_UPDT: { size_t word = r_dcache_update_word.read(); r_dcache->write( r_dcache_cc_way.read(), r_dcache_cc_set.read(), word, r_tgt_buf[ word].read(), r_tgt_be[word].read() ); r_dcache_update_word = word+1; if ( word == r_tgt_word_max.read() ) // last word { r_tgt_dcache_req = false; r_tgt_dcache_rsp = true; r_dcache_fsm = r_dcache_fsm_save.read(); } break; } } // end switch r_dcache_fsm // save the DREQ and DRSP fields for the print_trace() function m_dreq_valid = dreq.valid; m_dreq_addr = dreq.addr; m_dreq_mode = dreq.mode; m_dreq_type = dreq.type; m_dreq_wdata = dreq.wdata; m_dreq_be = dreq.be; m_drsp_valid = drsp.valid; m_drsp_rdata = drsp.rdata; m_drsp_error = drsp.error; ////////// write buffer state update //////////////////////////////////////////// // The update() method must be called at each cycle to update the internal state. r_wbuf->update (); /////////// test processor frozen ///////////////////////////////////////////// // The simulation exit if the number of consecutive frozen cycles // is larger than the m_max_frozen_cycles (constructor parameter) if ( (ireq.valid and not irsp.valid) or (dreq.valid and not drsp.valid) ) { m_cpt_frz_cycles++; // used for instrumentation m_cpt_stop_simulation++; // used for processor stop if frozen if ( m_cpt_stop_simulation > m_max_frozen_cycles ) { std::cout << std::dec << "ERROR in CC_XCACHE_WRAPPER " << name() << " frozen since cycle " << m_cpt_total_cycles - m_max_frozen_cycles << std::endl; exit(1); } } else { m_cpt_stop_simulation = 0; } /////////// 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<executeNCycles(1, irsp, drsp, it); //////////////////////////////////////////////////////////////////////////////// // The CLEANUP FSM send the cleanup commands on the coherence network, // and supports simultaneous cleanup transactions, but two simultaneous // transactions mut address different cache lines. // Therefore, the line number is registered in an associative // registration buffer (Content Adressable Memory) by the CLEANUP FSM, // and the corresponding slot (identified by the VCI TRDID field) is cleared // when the cleanup transaction response is received. // It handles cleanup requests from both the DCACHE FSM & ICACHE FSM // with a round robin priority, and can support up to 16 simultaneous // cleanup transactions (16 slots in the registration buffer). // The r_dcache_cleanup_req (or r_icache_cleanup_req) flip-flops are reset // when the command has been sent. // The VCI TRDID field is used to distinguish data/instruction cleanups: // - if data cleanup : TRDID = 2*index + 0 // - if instruction cleanup : TRDID = 2*index + 1 //////////////////////////////////////////////////////////////////////////// switch ( r_cleanup_fsm.read() ) { /////////////////////// case CLEANUP_DATA_IDLE: // dcache has highest priority { size_t index = 0; bool ok; if ( r_dcache_cleanup_req.read() ) // dcache request { ok = r_cleanup_buffer.register_value( r_dcache_cleanup_line.read(), &index ); if ( ok ) // successful registration { r_cleanup_fsm = CLEANUP_DATA_GO; r_cleanup_trdid = index<<1; } } else if ( r_icache_cleanup_req.read() ) // icache request { ok = r_cleanup_buffer.register_value( r_icache_cleanup_line.read(), &index ); if ( ok ) // successful registration { r_cleanup_fsm = CLEANUP_INS_GO; r_cleanup_trdid = index<<1 + 1; } } break; } ////////////////////// case CLEANUP_INS_IDLE: // icache has highest priority { size_t index = 0; bool ok; if ( r_icache_cleanup_req.read() ) // icache request { ok = r_cleanup_buffer.register_value( r_icache_cleanup_line.read(), &index ); if ( ok ) // successful registration { r_cleanup_fsm = CLEANUP_INS_GO; r_cleanup_trdid = index<<1 + 1; } } else if ( r_dcache_cleanup_req.read() ) // dcache request { ok = r_cleanup_buffer.register_value( r_dcache_cleanup_line.read(), &index ); if ( ok ) // successful registration { r_cleanup_fsm = CLEANUP_DATA_GO; r_cleanup_trdid = index<<1; } } break; } ///////////////////// case CLEANUP_DATA_GO: { if ( p_vci_ini_c.cmdack.read() ) { r_dcache_cleanup_req = false; r_cleanup_fsm = CLEANUP_INS_IDLE; } } //////////////////////// case CLEANUP_INS_GO: { if ( p_vci_ini_c.cmdack.read() ) { r_icache_cleanup_req = false; r_cleanup_fsm = CLEANUP_DATA_IDLE; } } } // end switch CLEANUP FSM //////////////// Handling cleanup responses ////////////////// if ( p_vci_ini_c.rspval.read() ) // valid response { r_cleanup_buffer.cancel_index( p_vci_ini_c.rtrdid.read() >> 1); } //////////////////////////////////////////////////////////////////////////// // The VCI_CMD FSM controls the following ressources: // - r_vci_cmd_fsm // - r_vci_cmd_min // - r_vci_cmd_max // - r_vci_cmd_cpt // - r_vci_cmd_imiss_prio // - wbuf (reset) // - r_icache_miss_req (reset) // - r_icache_unc_req (reset) // - r_dcache_miss_req (reset) // - r_dcache_unc_req (reset) // - r_dcache_sc_req (reset) // // This FSM handles requests from both the DCACHE FSM & the ICACHE FSM. // There is 6 request types, with the following priorities : // 1 - Data Read Miss : r_dcache_miss_req and miss in the write buffer // 2 - Data Read Uncacheable : r_dcache_unc_req // 3 - Instruction Miss : r_icache_miss_req and miss in the write buffer // 4 - Instruction Uncacheable : r_icache_unc_req // 5 - Data Write : r_wbuf.rok() // 6 - Data Store Conditionnal: r_dcache_sc_req // // As we want to support several simultaneous VCI transactions, the VCI_CMD_FSM // and the VCI_RSP_FSM are fully desynchronized. // // VCI formats: // According to the VCI advanced specification, all read requests packets // (data Uncached, Miss data, instruction Uncached, Miss instruction) // are one word packets. // For write burst packets, all words are in the same cache line, // and addresses must be contiguous (the BE field is 0 in case of "holes"). // The sc command packet implements actually a compare-and-swap mechanism // and the packet contains two flits. ////////////////////////////////////////////////////////////////////////////// switch ( r_vci_cmd_fsm.read() ) { ////////////// case CMD_IDLE: { // r_dcache_miss_req and r_icache_miss_req require both a write_buffer access // to check a possible pending write on the same cache line. // As there is only one possible access per cycle to write buffer, we implement // a round-robin priority for this access, using the r_vci_cmd_imiss_prio flip-flop. size_t wbuf_min; size_t wbuf_max; bool dcache_miss_req = r_dcache_miss_req.read() and ( not r_icache_miss_req.read() or not r_vci_cmd_imiss_prio.read() ); bool icache_miss_req = r_icache_miss_req.read() and ( not r_dcache_miss_req.read() or r_vci_cmd_imiss_prio.read() ); // 1 - Data Read Miss if ( dcache_miss_req and r_wbuf->miss(r_dcache_addr_save.read()) ) { r_vci_cmd_fsm = CMD_DATA_MISS; r_dcache_miss_req = false; r_vci_cmd_imiss_prio = true; m_cpt_dmiss_transaction++; } // 2 - Data Read Uncacheable else if ( r_dcache_unc_req.read() ) { r_vci_cmd_fsm = CMD_DATA_UNC; r_dcache_unc_req = false; m_cpt_dunc_transaction++; } // 3 - Instruction Miss else if ( icache_miss_req and r_wbuf->miss(r_icache_addr_save.read()) ) { r_vci_cmd_fsm = CMD_INS_MISS; r_icache_miss_req = false; r_vci_cmd_imiss_prio = false; m_cpt_imiss_transaction++; } // 4 - Instruction Uncacheable else if ( r_icache_unc_req.read() ) { r_vci_cmd_fsm = CMD_INS_UNC; r_icache_unc_req = false; m_cpt_iunc_transaction++; } // 5 - Data Write else if ( r_wbuf->rok(&wbuf_min, &wbuf_max) ) { 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_write_transaction++; m_length_write_transaction += (wbuf_max-wbuf_min+1); } // 6 - Data Store Conditionnal else if ( r_dcache_sc_req.read() ) { r_vci_cmd_fsm = CMD_DATA_SC; r_dcache_sc_req = false; r_vci_cmd_cpt = 0; m_cpt_sc_transaction++; } break; } //////////////////// case CMD_DATA_WRITE: { if ( p_vci_ini_d.cmdack.read() ) { m_conso_wbuf_read++; r_vci_cmd_cpt = r_vci_cmd_cpt + 1; if (r_vci_cmd_cpt == r_vci_cmd_max) // last flit sent { r_vci_cmd_fsm = CMD_IDLE ; r_wbuf->sent() ; } } break; } ///////////////// case CMD_DATA_SC: { // The SC VCI command contains two flits if ( p_vci_ini_d.cmdack.read() ) { r_vci_cmd_cpt = r_vci_cmd_cpt + 1; if (r_vci_cmd_cpt == 1) r_vci_cmd_fsm = CMD_IDLE ; } break; } ////////////////// case CMD_INS_MISS: case CMD_INS_UNC: case CMD_DATA_MISS: case CMD_DATA_UNC: { // all read VCI commands contain one single flit if ( p_vci_ini_d.cmdack.read() ) r_vci_cmd_fsm = CMD_IDLE; break; } } // end switch r_vci_cmd_fsm /////////////////////////////////////////////////////////////////////////////// // The VCI_RSP FSM controls the following ressources: // - r_vci_rsp_fsm: // - r_vci_rsp_fifo_icache (push) // - r_vci_rsp_fifo_dcache (push) // - r_vci_rsp_data_error (set) // - r_vci_rsp_ins_error (set) // - r_vci_rsp_cpt // // As we support several simultaneous transactions, this FSM uses // the VCI TRDID field to identify the transactions. // // VCI vormat: // This component Rcheks the response packet length and accepts only // single word 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.read() ) { ////////////// case RSP_IDLE: { if( p_vci_ini_d.rspval.read() ) { r_vci_rsp_cpt = 0; if ( (p_vci_ini_d.rtrdid.read()>>(vci_param::T-1)) != 0 ) { r_vci_rsp_fsm = RSP_DATA_WRITE; } else if ( p_vci_ini_d.rtrdid.read() == TYPE_INS_MISS ) { r_vci_rsp_fsm = RSP_INS_MISS; } else if ( p_vci_ini_d.rtrdid.read() == TYPE_INS_UNC ) { r_vci_rsp_fsm = RSP_INS_UNC; } else if ( p_vci_ini_d.rtrdid.read() == TYPE_DATA_MISS ) { r_vci_rsp_fsm = RSP_DATA_MISS; } else if ( p_vci_ini_d.rtrdid.read() == TYPE_DATA_UNC ) { r_vci_rsp_fsm = RSP_DATA_UNC; } else { assert(false and "Unexpected response"); } } break; } ////////////////// case RSP_INS_MISS: { if ( p_vci_ini_d.rspval.read() ) { if ( (p_vci_ini_d.rerror.read()&0x1) != 0 ) // error reported { r_vci_rsp_ins_error = true; if ( p_vci_ini_d.reop.read() ) r_vci_rsp_fsm = RSP_IDLE; } else // no error reported { if ( r_vci_rsp_fifo_icache.wok() ) { assert( (r_vci_rsp_cpt.read() < m_cache_words) and "The VCI response packet for instruction miss is too long" ); r_vci_rsp_cpt = r_vci_rsp_cpt.read() + 1; vci_rsp_fifo_icache_put = true, vci_rsp_fifo_icache_data = p_vci_ini_d.rdata.read(); if ( p_vci_ini_d.reop.read() ) { assert( (r_vci_rsp_cpt.read() == m_cache_words - 1) and "The VCI response packet for instruction miss is too short"); r_vci_rsp_fsm = RSP_IDLE; } } } } break; } ///////////////// case RSP_INS_UNC: { if (p_vci_ini_d.rspval.read() ) { assert( p_vci_ini_d.reop.read() and "illegal VCI response packet for uncacheable instruction"); if ( (p_vci_ini_d.rerror.read()&0x1) != 0 ) // error reported { r_vci_rsp_ins_error = true; r_vci_rsp_fsm = RSP_IDLE; } else // no error reported { if ( r_vci_rsp_fifo_icache.wok()) { vci_rsp_fifo_icache_put = true; vci_rsp_fifo_icache_data = p_vci_ini_d.rdata.read(); r_vci_rsp_fsm = RSP_IDLE; } } } break; } /////////////////// case RSP_DATA_MISS: { if ( p_vci_ini_d.rspval.read() ) { if ( (p_vci_ini_d.rerror.read()&0x1) != 0 ) // error reported { r_vci_rsp_data_error = true; if ( p_vci_ini_d.reop.read() ) r_vci_rsp_fsm = RSP_IDLE; } else // no error reported { if ( r_vci_rsp_fifo_dcache.wok() ) { assert( (r_vci_rsp_cpt.read() < m_cache_words) and "The VCI response packet for data miss is too long"); r_vci_rsp_cpt = r_vci_rsp_cpt.read() + 1; vci_rsp_fifo_dcache_put = true, vci_rsp_fifo_dcache_data = p_vci_ini_d.rdata.read(); if ( p_vci_ini_d.reop.read() ) { assert( (r_vci_rsp_cpt.read() == m_cache_words - 1) and "The VCI response packet for data miss is too short"); r_vci_rsp_fsm = RSP_IDLE; } } } } break; } ////////////////// case RSP_DATA_UNC: { if (p_vci_ini_d.rspval.read() ) { assert( p_vci_ini_d.reop.read() and "illegal VCI response packet for uncacheable read data"); if ( (p_vci_ini_d.rerror.read()&0x1) != 0 ) // error reported { r_vci_rsp_data_error = true; r_vci_rsp_fsm = RSP_IDLE; } else // no error reported { if ( r_vci_rsp_fifo_dcache.wok()) { vci_rsp_fifo_dcache_put = true; vci_rsp_fifo_dcache_data = p_vci_ini_d.rdata.read(); r_vci_rsp_fsm = RSP_IDLE; } } } break; } //////////////////// case RSP_DATA_WRITE: { if (p_vci_ini_d.rspval.read()) { assert( p_vci_ini_d.reop.read() and "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_d.rtrdid.read() - (1<<(vci_param::T-1)); bool cacheable = r_wbuf->completed(wbuf_index); if ( not cacheable ) r_dcache_pending_unc_write = false; if ( (p_vci_ini_d.rerror.read()&0x1) != 0 ) r_iss->setWriteBerr(); } break; } } // end switch r_vci_rsp_fsm // FIFO_RSP update r_vci_rsp_fifo_icache.update(vci_rsp_fifo_icache_get, vci_rsp_fifo_icache_put, vci_rsp_fifo_icache_data); r_vci_rsp_fifo_dcache.update(vci_rsp_fifo_dcache_get, vci_rsp_fifo_dcache_put, vci_rsp_fifo_dcache_data); } // end transition() ////////////////////////// tmpl(void)::genMoore() ////////////////////////// { //////////////////////////////////////////////////////////////// // VCI initiator command on the coherence network (cleanup) vci_addr_t address; if ( r_cleanup_fsm.read() == CLEANUP_DATA_GO ) address = (vci_addr_t)r_dcache_cleanup_line.read()<getAddress(r_vci_cmd_cpt.read())&~0x3; p_vci_ini_d.wdata = r_wbuf->getData(r_vci_cmd_cpt.read()); p_vci_ini_d.be = r_wbuf->getBe(r_vci_cmd_cpt.read()); p_vci_ini_d.plen = (r_vci_cmd_max - r_vci_cmd_min + 1)<<2; p_vci_ini_d.cmd = vci_param::CMD_WRITE; p_vci_ini_d.trdid = r_wbuf->getIndex() + (1<<(vci_param::T-1)); p_vci_ini_d.pktid = 0; p_vci_ini_d.srcid = m_srcid_d; p_vci_ini_d.cons = false; p_vci_ini_d.wrap = false; p_vci_ini_d.contig = true; p_vci_ini_d.clen = 0; p_vci_ini_d.cfixed = false; p_vci_ini_d.eop = (r_vci_cmd_cpt.read() == r_vci_cmd_max.read()); break; } case CMD_DATA_MISS: { p_vci_ini_d.cmdval = true; p_vci_ini_d.address = (vci_addr_t)r_dcache_addr_save.read() & (vci_addr_t)m_cache_yzmask; p_vci_ini_d.be = 0xF; p_vci_ini_d.plen = m_cache_words << 2; p_vci_ini_d.cmd = vci_param::CMD_READ; p_vci_ini_d.trdid = TYPE_DATA_MISS; p_vci_ini_d.pktid = 0; p_vci_ini_d.srcid = m_srcid_d; p_vci_ini_d.cons = false; p_vci_ini_d.wrap = false; p_vci_ini_d.contig = true; p_vci_ini_d.clen = 0; p_vci_ini_d.cfixed = false; p_vci_ini_d.eop = true; break; } case CMD_INS_MISS: { p_vci_ini_d.cmdval = true; p_vci_ini_d.address = (vci_addr_t)r_icache_addr_save.read() & (vci_addr_t)m_cache_yzmask; p_vci_ini_d.be = 0xF; p_vci_ini_d.plen = m_cache_words << 2; p_vci_ini_d.cmd = vci_param::CMD_READ; p_vci_ini_d.trdid = TYPE_INS_MISS; p_vci_ini_d.pktid = 0; p_vci_ini_d.srcid = m_srcid_d; p_vci_ini_d.cons = false; p_vci_ini_d.wrap = false; p_vci_ini_d.contig = true; p_vci_ini_d.clen = 0; p_vci_ini_d.cfixed = false; p_vci_ini_d.eop = true; break; } case CMD_INS_UNC: { p_vci_ini_d.cmdval = true; p_vci_ini_d.address = (vci_addr_t)r_icache_addr_save.read() & ~0x3; p_vci_ini_d.be = 0xF; p_vci_ini_d.plen = 4; p_vci_ini_d.cmd = vci_param::CMD_READ; p_vci_ini_d.trdid = TYPE_INS_UNC; p_vci_ini_d.pktid = 0; p_vci_ini_d.srcid = m_srcid_d; p_vci_ini_d.cons = false; p_vci_ini_d.wrap = false; p_vci_ini_d.contig = true; p_vci_ini_d.clen = 0; p_vci_ini_d.cfixed = false; p_vci_ini_d.eop = true; break; } } // end switch r_vci_cmd_fsm /////////////////////////////////////////////// // VCI initiator response on the direct network switch (r_vci_rsp_fsm.read() ) { case RSP_DATA_WRITE : p_vci_ini_d.rspack = true; break; case RSP_INS_MISS : case RSP_INS_UNC : p_vci_ini_d.rspack = r_vci_rsp_fifo_icache.wok(); break; case RSP_DATA_MISS : case RSP_DATA_UNC : case RSP_DATA_SC : p_vci_ini_d.rspack = r_vci_rsp_fifo_dcache.wok(); break; case RSP_IDLE : default : p_vci_ini_d.rspack = false; break; } // end switch r_vci_rsp_fsm //////////////////////////////////////////////////////////// // VCI target command and response on the coherence network switch ( r_tgt_fsm.read() ) { case TGT_IDLE: case TGT_UPDT_WORD: case TGT_UPDT_DATA: { p_vci_tgt_c.cmdack = true; p_vci_tgt_c.rspval = false; break; } case TGT_RSP_BROADCAST: { p_vci_tgt_c.cmdack = false; p_vci_tgt_c.rspval = (not r_tgt_icache_req.read() and not r_tgt_dcache_req.read()) and (r_tgt_icache_rsp.read() or r_tgt_dcache_rsp.read()); p_vci_tgt_c.rsrcid = r_tgt_srcid.read(); p_vci_tgt_c.rpktid = r_tgt_pktid.read(); p_vci_tgt_c.rtrdid = r_tgt_trdid.read(); p_vci_tgt_c.rdata = 0; p_vci_tgt_c.rerror = 0; p_vci_tgt_c.reop = true; break; } case TGT_RSP_ICACHE: { p_vci_tgt_c.cmdack = false; p_vci_tgt_c.rspval = not r_tgt_icache_req.read() and r_tgt_icache_rsp.read(); p_vci_tgt_c.rsrcid = r_tgt_srcid.read(); p_vci_tgt_c.rpktid = r_tgt_pktid.read(); p_vci_tgt_c.rtrdid = r_tgt_trdid.read(); p_vci_tgt_c.rdata = 0; p_vci_tgt_c.rerror = 0; p_vci_tgt_c.reop = true; break; } case TGT_RSP_DCACHE: { p_vci_tgt_c.cmdack = false; p_vci_tgt_c.rspval = not r_tgt_dcache_req.read() and r_tgt_dcache_rsp.read(); p_vci_tgt_c.rsrcid = r_tgt_srcid.read(); p_vci_tgt_c.rpktid = r_tgt_pktid.read(); p_vci_tgt_c.rtrdid = r_tgt_trdid.read(); p_vci_tgt_c.rdata = 0; p_vci_tgt_c.rerror = 0; p_vci_tgt_c.reop = true; break; } case TGT_REQ_BROADCAST: case TGT_REQ_ICACHE: case TGT_REQ_DCACHE: { p_vci_tgt_c.cmdack = false; p_vci_tgt_c.rspval = false; break; } } // end switch TGT_FSM } // end genMoore() }} // 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