/* -*- 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 * malek */ ///////////////////////////////////////////////////////////////////////////// // 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. // Three types of packets can be send by the L2 cache to the L1 cache // * MULTICAST INVALIDATE packets : length = 1 // * MULTICAST UPDATE packets : length = n + 2 // * BROADCAST INVALIDATE packets : length = 1 // 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 uncachable write // requests, each request is transmited as a single VCI transaction. // Both the data & instruction caches can be flushed in one single cycle. // - 08/12/2009 // The update instruction coherence request (code 0XC) are supported. // - 26/12/2009 // The VCI_CC_XCACHE_WRAPPER_MULTI is derived from the VCI_CC_XCACHE_WRAPPER_V1 // to support several concurrent VCI transactions, in order to improve the CPI. // A new write buffer supporting simultaneous write transactions has been // introduced. The VCI command & response FSMs are not synchronized anymore: // The read requests can be transmitted before previous write requests // (if the missing address does not match a pending write in the write buffer) // and several read & write requests can be simultaneously transmitted. // The transactions can complete in any order, depending on the network. // Two new flip-flops have been introduced to signal completion of the // read transactions from the RSP FSM to the DCACHE & ICACHE FSMs: // r_rsp_data_ok, r_rsp_ins_ok // As simultaneous VCI transactions are supported, the TRDID & RTRDID fields // are used to transport the transaction index. // The transaction index has an odd value for a write transaction, depending // on the line index in the write buffer: PKTID = 2*wbuf_index + 1 // The transaction index has an even value for a read transaction, with only // only four possible values, depending on cachable/uncachable & data/instruction. // A new CLEANUP FSM has been introduced to transmit the cleanups // request from the DCACHE & ICACHE FSM on the coherence network. // The LL/SC requests are still uncachable. // - 07/06/2010 // The DCACHE FSM has been modified to enforce a well defined consistency model: // 1) All uncachable acces (both read and write) are now blocking // the processor until the VCI response is received. // Uncachable access are considered as I/O access and must respect // a strict sequencial policy. // 2) For cachable access, the write buffer supports the "read after write" // rule, and the "write after write" rule : registered write requests // are tested before handling a read miss, and before locking a buffer line. // The MultiWriteBuffer component has been modified, to support // these rules, and to have an associative behavior: it can exist several // open lines, with a private time-out for each open line. // A printTrace() method has been defined. /////////////////////////////////////////////////////////////////////////////// #include #include "arithmetics.h" #include "../include/vci_cc_xcache_wrapper_multi.h" namespace soclib { namespace caba { namespace { const char *dcache_fsm_state_str[] = { "DCACHE_IDLE ", "DCACHE_WRITE_UPDT ", "DCACHE_WRITE_REQ ", "DCACHE_MISS_SELECT ", "DCACHE_MISS_CLEANUP", "DCACHE_MISS_WAIT ", "DCACHE_MISS_UPDT ", "DCACHE_UNC_WAIT ", "DCACHE_UNC_GO ", "DCACHE_INVAL ", "DCACHE_SYNC ", "DCACHE_ERROR ", "DCACHE_CC_CHECK ", "DCACHE_CC_INVAL ", "DCACHE_CC_UPDT ", }; const char *icache_fsm_state_str[] = { "ICACHE_IDLE ", "ICACHE_MISS_SELECT ", "ICACHE_MISS_CLEANUP", "ICACHE_MISS_WAIT ", "ICACHE_MISS_UPDT ", "ICACHE_UNC_WAIT ", "ICACHE_UNC_GO ", "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", }; const char *rsp_fsm_state_str[] = { "RSP_IDLE ", "RSP_INS_MISS ", "RSP_INS_UNC ", "RSP_DATA_MISS ", "RSP_DATA_UNC ", "RSP_DATA_WRITE", }; const char *tgt_fsm_state_str[] = { "TGT_IDLE ", "TGT_UPDT_WORD ", "TGT_UPDT_DATA ", "TGT_REQ_BROADCAST", "TGT_REQ_ICACHE ", "TGT_REQ_DCACHE ", "TGT_RSP_BROADCAST", "TGT_RSP_ICACHE ", "TGT_RSP_DCACHE ", }; const char *cleanup_fsm_state_str[] = { "CLEANUP_IDLE", "CLEANUP_DCACHE", "CLEANUP_ICACHE", }; } #define tmpl(...) template __VA_ARGS__ VciCcXCacheWrapperMulti using soclib::common::uint32_log2; ///////////////////////////////////// tmpl(/**/)::VciCcXCacheWrapperMulti( sc_module_name name, int proc_id, const soclib::common::MappingTable &mtp, const soclib::common::MappingTable &mtc, const soclib::common::IntTab &initiator_index_p, 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, size_t wbuf_timeout) : soclib::caba::BaseModule(name), p_clk("clk"), p_resetn("resetn"), p_vci_ini_d("vci_ini_p"), 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_iss(this->name(), proc_id), m_srcid_d(mtp.indexForId(initiator_index_p)), m_srcid_c(mtc.indexForId(initiator_index_c)), m_dcache_ways(dcache_ways), m_dcache_words(dcache_words), m_dcache_yzmask((~0)<<(uint32_log2(dcache_words) + 2)), m_icache_ways(icache_ways), m_icache_words(icache_words), m_icache_yzmask((~0)<<(uint32_log2(icache_words) + 2)), r_dcache_fsm("r_dcache_fsm"), r_dcache_fsm_save("r_dcache_fsm_save"), r_dcache_addr_save("r_dcache_addr_save"), r_dcache_wdata_save("r_dcache_wdata_save"), r_dcache_rdata_save("r_dcache_rdata_save"), r_dcache_type_save("r_dcache_type_save"), r_dcache_be_save("r_dcache_be_save"), r_dcache_cleanup_save("r_dcache_cleanup_save"), r_dcache_way_save("r_dcache_way_save"), r_dcache_cleanup_req("r_dcache_cleanup_req"), r_dcache_cleanup_line("r_dcache_cleanup_line"), r_dcache_miss_req("r_dcache_miss_req"), r_dcache_unc_req("r_dcache_unc_req"), r_dcache_inval_pending("r_dcache_inval_pending"), r_icache_fsm("r_icache_fsm"), r_icache_fsm_save("r_icache_fsm_save"), r_icache_addr_save("r_icache_addr_save"), r_icache_cleanup_save("r_icache_cleanup_save"), r_icache_way_save("r_icache_way_save"), r_icache_miss_req("r_icache_miss_req"), r_icache_cleanup_req("r_icache_cleanup_req"), r_icache_cleanup_line("r_icache_cleanup_line"), r_icache_inval_pending("r_icache_inval_pending"), r_cmd_fsm("r_cmd_fsm"), r_cmd_min("r_cmd_min"), r_cmd_max("r_cmd_max"), r_cmd_cpt("r_cmd_cpt"), r_rsp_fsm("r_rsp_fsm"), r_rsp_ins_error("r_rsp_ins_error"), r_rsp_data_error("r_rsp_data_error"), r_rsp_cpt("r_rsp_cpt"), r_rsp_ins_ok("r_rsp_ins_ok"), r_rsp_data_ok("r_rsp_data_ok"), r_tgt_fsm("r_tgt_fsm"), r_tgt_addr("r_tgt_addr"), r_tgt_word("r_tgt_word"), r_tgt_update("r_tgt_update"), r_tgt_data("r_tgt_data"), r_tgt_srcid("r_tgt_srcid"), r_tgt_pktid("r_tgt_pktid"), r_tgt_trdid("r_tgt_trdid"), r_tgt_icache_req("r_tgt_icache_req"), r_tgt_dcache_req("r_tgt_dcache_req"), r_tgt_icache_rsp("r_tgt_icache_rsp"), r_tgt_dcache_rsp("r_tgt_dcache_rsp"), r_cleanup_fsm("r_cleanup_fsm"), r_wbuf("r_wbuf", wbuf_nwords, wbuf_nlines, wbuf_timeout, dcache_words), r_icache("icache", icache_ways, icache_sets, icache_words), r_dcache("dcache", dcache_ways, dcache_sets, dcache_words) { assert( (icache_words*vci_param::B) < (1< 2) && ((1<<(vci_param::T-1)) >= wbuf_nlines) && "I need more TRDID bits"); r_icache_miss_buf = new data_t[icache_words]; r_dcache_miss_buf = new data_t[dcache_words]; r_tgt_buf = new data_t[dcache_words]; r_tgt_val = new bool[dcache_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); } // end constructor ////////////////////////////////////// tmpl(/**/)::~VciCcXCacheWrapperMulti() { delete [] r_icache_miss_buf; delete [] r_dcache_miss_buf; delete [] r_tgt_val; delete [] r_tgt_buf; } /////////////////////////////////// tmpl(void)::printTrace(size_t mode) { typename iss_t::InstructionRequest ireq; typename iss_t::DataRequest dreq; m_iss.getRequests( ireq, dreq ); std::cout << std::dec << "Proc " << m_srcid_d << 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_cmd_fsm] << " " << rsp_fsm_state_str[r_rsp_fsm] << " " << tgt_fsm_state_str[r_tgt_fsm] << " " << cleanup_fsm_state_str[r_cleanup_fsm] << std::endl; if(mode & 0x1) { r_wbuf.printTrace(); } if(mode & 0x2) { std::cout << " Data cache" << std::endl; r_dcache.printTrace(); } if(mode & 0x4) { std::cout << " Instruction cache" << std::endl; r_icache.printTrace(); } } ///////////////////////////// tmpl(void)::printStatistics() { float run_cycles = (float)(m_cpt_total_cycles - m_cpt_frz_cycles); std::cout << "------------------------------------" << std:: dec << std::endl << "CPU " << m_srcid_d << " / cycles = " << m_cpt_total_cycles << std::endl << "- CPI = " << (float)m_cpt_total_cycles/run_cycles << std::endl << "- READ RATE = " << (float)m_cpt_read/run_cycles << std::endl << "- WRITE RATE = " << (float)m_cpt_write/run_cycles << std::endl << "- CACHED WRITE RATE = " << (float)m_cpt_write_cached/m_cpt_write << std::endl << "- UNC RATE = " << (float)m_cpt_data_unc/run_cycles << std::endl << "- LL RATE = " << (float)m_cpt_ll/run_cycles << std::endl << "- SC RATE = " << (float)m_cpt_sc/run_cycles << std::endl << "- IMISS_RATE = " << (float)m_cpt_ins_miss/run_cycles << std::endl << "- IMISS COST = " << (float)m_cost_ins_miss_frz/m_cpt_ins_miss << std::endl << "- DMISS RATE = " << (float)m_cpt_data_miss/m_cpt_read << std::endl << "- DMISS COST = " << (float)m_cost_data_miss_frz/m_cpt_data_miss << std::endl << "- UNC COST = " << (float)m_cost_unc_frz/m_cpt_data_unc << std::endl << "- WRITE COST = " << (float)m_cost_write_frz/m_cpt_write << std::endl << "- WRITE LENGTH = " << (float)m_length_write_transaction/m_cpt_write_transaction << std::endl << "- CC_BROADCAST = " << m_cpt_cc_broadcast << std::endl << "- CC_UPDATE_DATA = " << m_cpt_cc_update_data << std::endl << "- CC_UPDATE_INS = " << m_cpt_cc_update_ins << std::endl << "- CC_INVAL_DATA = " << m_cpt_cc_inval_data << std::endl << "- CC_INVAL_INS = " << m_cpt_cc_inval_ins << std::endl << "- CC_CLEANUP_DATA = " << m_cpt_cc_cleanup_data << std::endl << "- CC_CLEANUP_INS = " << m_cpt_cc_cleanup_ins << std::endl; } ////////////////////////// tmpl(void)::transition() { if ( ! p_resetn.read() ) { m_iss.reset(); // FSM states r_dcache_fsm = DCACHE_IDLE; r_icache_fsm = ICACHE_IDLE; r_cmd_fsm = CMD_IDLE; r_rsp_fsm = RSP_IDLE; r_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 CMD FSM r_icache_miss_req = false; r_icache_unc_req = false; r_dcache_miss_req = false; r_dcache_unc_req = false; // synchronisation flip-flops from ICACHE & DCACHE FSMs to CLEANUP FSM r_icache_cleanup_req = false; r_dcache_cleanup_req = 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; // internal messages in DCACHE et ICACHE FSMs r_icache_inval_pending = false; r_dcache_inval_pending = false; // synchronisation flip-flops from the RSP FSM to the ICACHE or DCACHE FSMs r_rsp_data_ok = false; r_rsp_ins_ok = false; r_rsp_data_error = false; r_rsp_ins_error = false; // 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_broadcast = 0; m_cpt_cc_update_data = 0; m_cpt_cc_inval_data = 0; m_cpt_cc_cleanup_data = 0; m_cpt_cc_update_ins = 0; m_cpt_cc_inval_ins = 0; m_cpt_cc_cleanup_ins = 0; m_cpt_frz_cycles = 0; m_cpt_total_cycles = 0; m_cpt_read = 0; m_cpt_write = 0; m_cpt_write_cached = 0; m_cpt_data_unc = 0; m_cpt_ins_unc = 0; m_cpt_ll = 0; m_cpt_sc = 0; m_cpt_data_miss = 0; m_cpt_ins_miss = 0; m_cost_write_frz = 0; m_cost_data_miss_frz = 0; m_cost_unc_frz = 0; m_cost_ins_miss_frz = 0; m_cpt_imiss_transaction = 0; m_cpt_dmiss_transaction = 0; m_cpt_data_unc_transaction = 0; m_cpt_ins_unc_transaction = 0; m_cpt_write_transaction = 0; return; } #if SOCLIB_MODULE_DEBUG if ( m_srcid_d == 0 ) { std::cout << std::dec << "CcXcache " << m_srcid_d << " / Time = " << m_cpt_total_cycles << std::endl << " " << dcache_fsm_state_str[r_dcache_fsm] << " " << icache_fsm_state_str[r_icache_fsm] << " " << cmd_fsm_state_str[r_cmd_fsm] << " " << rsp_fsm_state_str[r_rsp_fsm] << " " << cleanup_fsm_state_str[r_cleanup_fsm] << " " << tgt_fsm_state_str[r_tgt_fsm] << std::endl; } #endif m_cpt_total_cycles++; ///////////////////////////////////////////////////////////////////// // The TGT_FSM controls the following ressources: // - r_tgt_fsm // - r_tgt_buf[nwords] // - r_tgt_val[nwords] // - r_tgt_update // - r_tgt_data // - 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 states. It waits the completion // of the update or invalidate request in the RSP states. // - 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 index. // 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_tgt_fsm ) { case TGT_IDLE: { if ( p_vci_tgt_c.cmdval.read() ) { addr_t address = p_vci_tgt_c.address.read(); if ( p_vci_tgt_c.cmd.read() != vci_param::CMD_WRITE) { std::cout << "error in VCI_CC_XCACHE_WRAPPER " << name() << std::endl; std::cout << "the received coherence request from " << p_vci_tgt_c.srcid.read() << " is not a write" << std::endl; exit(0); } if ( (address != 0x3) && (! m_segment.contains(address)) ) { std::cout << "error in VCI_CC_XCACHE_WRAPPER " << name() << std::endl; std::cout << "out of segment coherence request" << std::endl; exit(0); } r_tgt_addr = (((addr_t) ((p_vci_tgt_c.be.read() & 0x3) << 32)) | ((addr_t) (p_vci_tgt_c.wdata.read()))) * m_dcache_words * 4; 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_plen = p_vci_tgt_c.plen.read(); if ( address == 0x3 ) // broadcast invalidate { if ( ! p_vci_tgt_c.eop.read() ) { std::cout << "error in VCI_CC_XCACHE_WRAPPER " << name() << std::endl; std::cout << "a broascast request must be one word" << std::endl; exit(0); } r_tgt_update = false; r_tgt_brdcast= true; r_tgt_fsm = TGT_REQ_BROADCAST; m_cpt_cc_broadcast++; } else // multicast-update or multicast-invalidate { uint32_t cell = address - m_segment.baseAddress(); if (cell == 0) // invalidate data { if ( ! p_vci_tgt_c.eop.read() ) { std::cout << "error in VCI_CC_XCACHE_WRAPPER " << name() << std::endl; std::cout << "an invalidate requestn must be one word" << std::endl; exit(0); } r_tgt_brdcast = false; r_tgt_update = false; r_tgt_data = true; r_tgt_fsm = TGT_REQ_DCACHE; m_cpt_cc_inval_data++; } else if (cell == 4) // update data { if ( p_vci_tgt_c.eop.read() ) { std::cout << "error in VCI_CC_VCACHE_WRAPPER " << name() << std::endl; std::cout << "an update request must be N+2 words" << std::endl; exit(0); } r_tgt_brdcast = false; r_tgt_update = true; r_tgt_data = true; r_tgt_fsm = TGT_UPDT_WORD; m_cpt_cc_update_data++; } else if (cell == 8) // invalidate instruction { if ( ! p_vci_tgt_c.eop.read() ) { std::cout << "error in VCI_CC_VCACHE_WRAPPER " << name() << std::endl; std::cout << "an invalidate request must be one word" << std::endl; exit(0); } r_tgt_brdcast = false; r_tgt_data = false; r_tgt_update = false; r_tgt_fsm = TGT_REQ_ICACHE; m_cpt_cc_inval_ins++; } else if (cell == 12) // update ins { if ( p_vci_tgt_c.eop.read() ) { std::cout << "error in VCI_CC_VCACHE_WRAPPER " << name() << std::endl; std::cout << "an update request must be N+2 words" << std::endl; exit(0); } r_tgt_brdcast = false; r_tgt_update = true; r_tgt_data = false; r_tgt_fsm = TGT_UPDT_WORD; m_cpt_cc_update_ins++; } } // end if address } // end if cmdval break; } case TGT_UPDT_WORD: { if (p_vci_tgt_c.cmdval.read()) { if ( p_vci_tgt_c.eop.read() ) { std::cout << "error in VCI_CC_XCACHE_WRAPPER " << name() << std::endl; std::cout << "an update command length must be N+2 words" << std::endl; exit(0); } for ( size_t i=0 ; i= m_dcache_words ) { std::cout << "error in VCI_CC_XCACHE_WRAPPER " << name() << std::endl; std::cout << "the word index in an update request is wrong" << std::endl; exit(0); } r_tgt_buf[word] = p_vci_tgt_c.wdata.read(); if(p_vci_tgt_c.be.read()) r_tgt_val[word] = true; r_tgt_word = word + 1; if (p_vci_tgt_c.eop.read()) { if (r_tgt_data.read()) r_tgt_fsm = TGT_REQ_DCACHE; else r_tgt_fsm = TGT_REQ_ICACHE; } } break; } case TGT_REQ_ICACHE: { if ( !r_tgt_icache_req.read() ) { r_tgt_fsm = TGT_RSP_ICACHE; r_tgt_icache_req = true; } break; } case TGT_REQ_DCACHE: { if ( !r_tgt_dcache_req.read() ) { r_tgt_fsm = TGT_RSP_DCACHE; r_tgt_dcache_req = true; } break; } case TGT_REQ_BROADCAST: { if ( !r_tgt_icache_req.read() && !r_tgt_dcache_req.read() ) { r_tgt_fsm = TGT_RSP_BROADCAST; r_tgt_icache_req = true; r_tgt_dcache_req = true; } break; } case TGT_RSP_BROADCAST: { if ( !r_tgt_icache_req.read() && !r_tgt_dcache_req.read() ) { // one response if ( !r_tgt_icache_rsp || !r_tgt_dcache_rsp ) { if ( p_vci_tgt_c.rspack.read() ) { r_tgt_fsm = TGT_IDLE; r_tgt_icache_rsp = false; r_tgt_dcache_rsp = false; } } // two responses if ( r_tgt_icache_rsp && r_tgt_dcache_rsp ) { if ( p_vci_tgt_c.rspack.read() ) { r_tgt_icache_rsp = false; // reset one to prepare the second response } } // no need for a response if ( !r_tgt_icache_rsp && !r_tgt_dcache_rsp ) { r_tgt_fsm = TGT_IDLE; } } break; } case TGT_RSP_ICACHE: { if ( (p_vci_tgt_c.rspack.read() || !r_tgt_icache_rsp.read()) && !r_tgt_icache_req.read() ) { r_tgt_fsm = TGT_IDLE; r_tgt_icache_rsp = false; } break; } case TGT_RSP_DCACHE: { if ( (p_vci_tgt_c.rspack.read() || !r_tgt_dcache_rsp.read()) && !r_tgt_dcache_req.read() ) { r_tgt_fsm = TGT_IDLE; r_tgt_dcache_rsp = false; } break; } } // end switch TGT_FSM typename iss_t::InstructionRequest ireq; typename iss_t::InstructionResponse irsp; typename iss_t::DataRequest dreq; typename iss_t::DataResponse drsp; ireq.valid = false; dreq.valid = false; irsp.valid = false; irsp.error = false; drsp.valid = false; drsp.error = false; m_iss.getRequests( ireq, dreq ); ////////////////////////////////////////////////////////////////////////////// // The ICACHE FSM controls the following ressources: // - r_icache_fsm // - r_icache_fsm_save // - r_icache (read & write) // - r_icache_addr_save // - r_icache_miss_req (set) // - r_icache_unc_req (set) // - r_rsp_ins_ok (reset) // - r_rsp_ins_error (reset) // - r_tgt_icache_req (reset) // - r_tgt_icache_rsp // - r_icache_cleanup_req (set) // - r_icache_cleanup_line // - ireq & irsp structures (communication with the processor) // // 1/ External coherence requests (update or invalidate) // There is an external request when the r_tgt_icache_req flip-flop is set, // These requests are taken into account in the IDLE and WAIT states. // In case of external request the ICACHE FSM goes to the CC_CHECK // state to test the external hit, and returns in the // pre-empted state after this external request is completed. // // 2/ Processor requests are taken into account only in the IDLE state. // The cache access takes into account the cacheability_table. // In case of MISS, or in case of uncachable 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 CMD FSM. // The r_rsp_ins_ok flip-flop is set by the RSP FSM when the // transaction is completed. In case of bus error, the RSP FSM sets // the r_rsp_ins_error flip-flop. They must be reset by the ICACHE FSM. // - CACHED READ MISS => to the MISS_WAIT state, waiting the r_rsp_ins_ok signal. // It can be delayed in the MISS_DELAY state in case of matching pending // cleanup request. Then it goes to the MISS_UPDT state, then to the CLEANUP_REQ // state (if necessary), and finally to the IDLE state. // - UNCACHED READ => to the UNC_WAIT state (waiting the r_rsp_ins_ok signal), // and back to the IDLE state. //////////////////////////////////////////////////////////////////////////////////// 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; break; } if ( ireq.valid ) { data_t icache_ins; bool icache_cachable = m_cacheability_table[(addr_t)ireq.addr]; m_cpt_icache_dir_read += m_icache_ways; m_cpt_icache_data_read += m_icache_ways; if ( icache_cachable ) { if ( r_icache.read((addr_t)ireq.addr, &icache_ins) ) // hit { r_icache_fsm = ICACHE_IDLE; irsp.valid = true; irsp.instruction = icache_ins; } else // miss { m_cpt_ins_miss++; m_cost_ins_miss_frz++; // if the missing line corresponds to a pending cleanup // the miss request to the CMD FSM must be delayed if ( r_icache_cleanup_req && ((addr_t)r_icache_cleanup_line == (addr_t)(ireq.addr/(m_icache_words*4))) ) { break; } else { r_icache_fsm = ICACHE_MISS_SELECT; r_icache_addr_save = ireq.addr; r_icache_miss_req = true; r_rsp_ins_ok = false; } } } else // uncachable instruction { m_cpt_ins_unc++; m_cost_ins_miss_frz++; r_icache_addr_save = ireq.addr; r_icache_fsm = ICACHE_UNC_WAIT; r_icache_unc_req = true; r_rsp_ins_ok = false; } } break; } case ICACHE_MISS_SELECT: // select a victim { m_cost_ins_miss_frz++; size_t way; addr_t index; addr_t ad = r_icache_addr_save; if ( r_icache.select_before_update( ad, &way, &index) ) { r_icache_fsm = ICACHE_MISS_CLEANUP; r_icache_cleanup_save = index; r_icache_way_save = way; } else { r_icache_way_save = way; r_icache_fsm = ICACHE_MISS_WAIT; } break; } case ICACHE_MISS_CLEANUP: // try to post a cleanup request to the CLEANUP FSM { m_cost_ins_miss_frz++; if ( r_tgt_icache_req ) // coherence request { r_icache_fsm = ICACHE_CC_CHECK; r_icache_fsm_save = r_icache_fsm; break; } if ( !r_icache_cleanup_req ) // no pending cleanup { r_icache_cleanup_req = true; r_icache_cleanup_line = r_icache_cleanup_save; r_icache_fsm = ICACHE_MISS_WAIT; } break; } case ICACHE_MISS_WAIT: // waiting the response from the RSP FSM { m_cost_ins_miss_frz++; if ( r_tgt_icache_req ) // coherence request { r_icache_fsm = ICACHE_CC_CHECK; r_icache_fsm_save = r_icache_fsm; break; } if ( r_rsp_ins_ok ) // there is a response { if ( r_rsp_ins_error ) r_icache_fsm = ICACHE_ERROR; else if ( !r_icache_inval_pending ) r_icache_fsm = ICACHE_MISS_UPDT; else { if ( r_icache_cleanup_req ) { break; } else { // the cache is not updated in case of pending inval r_icache_cleanup_req = true; r_icache_cleanup_line = r_icache_addr_save.read() >> (uint32_log2(m_icache_words) + 2); r_icache_fsm = ICACHE_IDLE; r_icache_inval_pending = false; } } } break; } case ICACHE_MISS_UPDT: // update the cache { m_cost_ins_miss_frz++; m_cpt_icache_dir_write++; m_cpt_icache_data_write++; addr_t ad = (addr_t) r_icache_addr_save; data_t* buf = (data_t*) r_icache_miss_buf; size_t way = (size_t) r_icache_way_save; r_icache.update_after_select( buf, way, ad ); r_icache_fsm = ICACHE_IDLE; 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; break; } if ( r_rsp_ins_ok ) { if ( r_rsp_ins_error ) r_icache_fsm = ICACHE_ERROR; else r_icache_fsm = ICACHE_UNC_GO; } break; } case ICACHE_UNC_GO: { r_icache_fsm = ICACHE_IDLE; if( ireq.addr == r_icache_addr_save ) { irsp.valid = true; irsp.instruction = r_icache_miss_buf[0]; } } case ICACHE_ERROR: { r_icache_fsm = ICACHE_IDLE; r_rsp_ins_error = false; irsp.error = true; irsp.valid = true; break; } case ICACHE_CC_CHECK: // read directory in case of external request { m_cpt_icache_dir_read += m_icache_ways; m_cpt_icache_data_read += m_icache_ways; if ( ( (r_icache_fsm_save == ICACHE_MISS_WAIT) || (r_icache_fsm_save == ICACHE_MISS_CLEANUP) ) && ((r_icache_addr_save & ~((m_icache_words<<2)-1))==(r_tgt_addr & ~((m_icache_words<<2)-1)))) // the external request matches a miss { r_icache_inval_pending = true; r_tgt_icache_req = false; r_tgt_icache_rsp = r_tgt_update; // always a response in case of update r_icache_fsm = r_icache_fsm_save; } else // the external request is not matching a pending miss { data_t data; bool icache_hit = r_icache.read(r_tgt_addr, &data); if ( icache_hit && r_tgt_update ) // hit update { r_icache_fsm = ICACHE_CC_UPDT; } else if ( icache_hit && !r_tgt_update ) // hit inval { r_icache_fsm = ICACHE_CC_INVAL; } else // miss { r_tgt_icache_req = false; r_tgt_icache_rsp = r_tgt_update; // alaways a response in case of update r_icache_fsm = r_icache_fsm_save; } } break; } case ICACHE_CC_UPDT: // update the cache line { m_cpt_icache_dir_write++; m_cpt_icache_data_write++; for(size_t i=0; i to the MISS_WAIT state (waiting r_rsp_data_ok), // then to the MISS_UPDT state, and finally to the IDLE state. // - UNCACHED READ or WRITE => to the UNC_WAIT state (waiting r_rsp_data_ok), // then to the UNC_GO state, and finally to the IDLE state. // - XTN_INVAL => to the INVAL state for one cycle, then to IDLE state. // - XTN_SYNC => to the SYNC state until write buffer empty, 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. // // All LL or SC requests are handled as uncachable. // // 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_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. /////////////////////////////////////////////////////////////////////////////////// switch ( r_dcache_fsm ) { case DCACHE_WRITE_REQ: { if ( r_tgt_dcache_req ) // coherence request { r_dcache_fsm = DCACHE_CC_CHECK; r_dcache_fsm_save = r_dcache_fsm; break; } if( !r_wbuf.write(r_dcache_addr_save, r_dcache_be_save, r_dcache_wdata_save) ) { // stay in DCACHE_WRITEREQ state if the write request is not accepted m_cost_write_frz++; break; } // If the write request is accepted by the write buffer // the next state and the response to processor request are evaluated // as in the DCACHE_IDLE state below ... } case DCACHE_IDLE: { if ( r_tgt_dcache_req ) // coherence request { r_dcache_fsm = DCACHE_CC_CHECK; r_dcache_fsm_save = r_dcache_fsm; break; } if ( dreq.valid ) { bool dcache_hit; data_t dcache_rdata; bool dcache_cachable; // dcache_cachable, dcache_hit & dcache_rdata evaluation m_cpt_dcache_data_read += m_dcache_ways; m_cpt_dcache_dir_read += m_dcache_ways; dcache_cachable = m_cacheability_table[dreq.addr]; dcache_hit = r_dcache.read(dreq.addr, &dcache_rdata); // Save data request r_dcache_addr_save = 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; // reset r_rsp_data_ok r_rsp_data_ok = false; // next FSM state, request to VCI, and processor response if(dreq.type == iss_t::DATA_READ) { if(!dcache_cachable) // uncachable read { m_cpt_data_unc++; m_cost_unc_frz++; r_dcache_unc_req = true; r_dcache_fsm = DCACHE_UNC_WAIT; } else { m_cpt_read++; if(dcache_hit) // cachable read hit { drsp.valid = true; drsp.rdata = dcache_rdata; r_dcache_fsm = DCACHE_IDLE; } else // cachable read miss { m_cost_data_miss_frz++; // if the missing line corresponds to a pending cleanup // the miss request to the CMD FSM must be delayed if ( r_dcache_cleanup_req && ((addr_t)r_dcache_cleanup_line == (addr_t)(dreq.addr/(m_dcache_words*4))) ) { break; } else { m_cpt_data_miss++; r_dcache_miss_req = true; r_dcache_fsm = DCACHE_MISS_SELECT; } } } } else if(dreq.type == iss_t::DATA_WRITE) { if(!dcache_cachable) // uncachable write { m_cpt_data_unc++; m_cost_unc_frz++; r_dcache_unc_req = true; r_dcache_fsm = DCACHE_UNC_WAIT; } else { m_cpt_write++; if(!dcache_hit) // cachable write miss { drsp.rdata = 0; drsp.valid = true; r_dcache_fsm = DCACHE_WRITE_REQ; } else // cachable write hit { m_cpt_write_cached++; drsp.rdata = 0; drsp.valid = true; r_dcache_fsm = DCACHE_WRITE_UPDT; } } } else if(dreq.type == iss_t::DATA_LL) // linked read // all LL requests are handled as uncachable { m_cpt_ll++; m_cost_unc_frz++; r_dcache_unc_req = true; r_dcache_fsm = DCACHE_UNC_WAIT; } else if(dreq.type == iss_t::DATA_SC) // conditional write // all SC requests are handled as uncachable { m_cpt_sc++; m_cost_unc_frz++; r_dcache_unc_req = true; r_dcache_fsm = DCACHE_UNC_WAIT; } else if((dreq.type == iss_t::XTN_WRITE) || (dreq.type == iss_t::XTN_READ)) // XTN access // only INVAL & SYNC requests are supported { drsp.valid = true; drsp.rdata = 0; if ( dreq.addr/4 == iss_t::XTN_DCACHE_INVAL ) { r_dcache_fsm = DCACHE_INVAL; } else if ( dreq.addr/4 == iss_t::XTN_SYNC ) { r_dcache_fsm = DCACHE_SYNC; } else if ( dreq.addr/4 == iss_t::XTN_TLB_MODE ) { r_dcache_fsm = DCACHE_IDLE; } else { std::cout << "warning in VCI_CC_XCACHE_WRAPPER " << name() << std::endl; std::cout << "unsupported external access : " << dreq.addr/4 << std::endl; std::cout << "only TLB_MODE, DCACHE_INVAL & SYNC are supported" << std::endl; } } } else // no dreq.valid { r_dcache_fsm = DCACHE_IDLE; drsp.valid = true; drsp.rdata = 0; } 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); r_dcache.write( r_dcache_addr_save, wdata ); r_dcache_fsm = DCACHE_WRITE_REQ; break; } case DCACHE_MISS_SELECT: // select a victim { m_cost_data_miss_frz++; size_t way; addr_t index; addr_t addr = r_dcache_addr_save; if ( r_dcache.select_before_update( addr, &way, &index) ) { r_dcache_fsm = DCACHE_MISS_CLEANUP; r_dcache_cleanup_save = index; r_dcache_way_save = way; } else { r_dcache_way_save = way; r_dcache_fsm = DCACHE_MISS_WAIT; } break; } case DCACHE_MISS_CLEANUP: // try to post a cleanup request to the CLEANUP FSM { m_cost_data_miss_frz++; if ( r_tgt_dcache_req ) // coherence request { r_dcache_fsm = DCACHE_CC_CHECK; r_dcache_fsm_save = r_dcache_fsm; break; } if ( !r_dcache_cleanup_req ) // no pending cleanup { r_dcache_cleanup_req = true; r_dcache_cleanup_line = r_dcache_cleanup_save; r_dcache_fsm = DCACHE_MISS_WAIT; } break; } case DCACHE_MISS_WAIT: // waiting the response from the RSP FSM { m_cost_data_miss_frz++; if ( r_tgt_dcache_req ) // coherence request { r_dcache_fsm = DCACHE_CC_CHECK; r_dcache_fsm_save = r_dcache_fsm; break; } if ( r_rsp_data_ok ) // there is a response { if ( r_rsp_data_error ) r_dcache_fsm = DCACHE_ERROR; else if ( !r_dcache_inval_pending ) r_dcache_fsm = DCACHE_MISS_UPDT; else { if ( r_dcache_cleanup_req ) { break; } else { // the cache is not updated in case of pending inval r_dcache_cleanup_req = true; r_dcache_cleanup_line = r_dcache_addr_save >> (uint32_log2(m_icache_words) + 2); r_dcache_fsm = DCACHE_IDLE; r_dcache_inval_pending = false; } } } break; } case DCACHE_MISS_UPDT: // update the cache { m_cost_data_miss_frz++; m_cpt_dcache_dir_write++; m_cpt_dcache_data_write++; addr_t ad = (addr_t) r_dcache_addr_save; data_t* buf = (data_t*) r_dcache_miss_buf; size_t way = (size_t) r_dcache_way_save; r_dcache.update_after_select( buf, way, ad ); r_dcache_fsm = DCACHE_IDLE; break; } case DCACHE_UNC_WAIT: { if ( dreq.valid ) m_cost_unc_frz++; if ( r_tgt_dcache_req ) // external request { r_dcache_fsm = DCACHE_CC_CHECK; r_dcache_fsm_save = r_dcache_fsm; break; } if ( r_rsp_data_ok ) { if ( r_rsp_data_error ) r_dcache_fsm = DCACHE_ERROR; else r_dcache_fsm = DCACHE_UNC_GO; } break; } case DCACHE_UNC_GO: { r_dcache_fsm = DCACHE_IDLE; drsp.valid = true; drsp.rdata = r_dcache_miss_buf[0]; break; } case DCACHE_ERROR: { r_dcache_fsm = DCACHE_IDLE; r_rsp_data_error = false; drsp.error = true; drsp.valid = true; break; } case DCACHE_INVAL: // local inval requiring a cleanup in case of hit { if( !r_dcache_cleanup_req ) { m_cpt_dcache_dir_read += m_dcache_ways; r_dcache_cleanup_req = r_dcache.inval( r_dcache_addr_save ); r_dcache_cleanup_line = r_dcache_addr_save.read() >> (uint32_log2(m_dcache_words)+2); r_dcache_fsm = DCACHE_IDLE; } break; } case DCACHE_SYNC: { if ( r_wbuf.empty() ) r_dcache_fsm = DCACHE_IDLE; break; } case DCACHE_CC_CHECK: // read directory in case of external request { m_cpt_dcache_dir_read += m_dcache_ways; m_cpt_dcache_data_read += m_dcache_ways; if ( ( (r_dcache_fsm_save == DCACHE_MISS_WAIT) || (r_dcache_fsm_save == DCACHE_MISS_CLEANUP) ) && ((r_dcache_addr_save & ~((m_dcache_words<<2)-1))==(r_tgt_addr & ~((m_dcache_words<<2)-1)))) // external request matches a miss { r_dcache_inval_pending = true; r_tgt_dcache_req = false; r_tgt_dcache_rsp = r_tgt_update; // always a response to an update r_dcache_fsm = r_dcache_fsm_save; } else // the external request is not matching a pending miss { data_t data; bool dcache_hit = r_dcache.read(r_tgt_addr, &data); if ( dcache_hit && r_tgt_update ) // hit update { r_dcache_fsm = DCACHE_CC_UPDT; } else if ( dcache_hit && !r_tgt_update ) // hit inval { r_dcache_fsm = DCACHE_CC_INVAL; } else // miss { r_tgt_dcache_req = false; r_tgt_dcache_rsp = r_tgt_update; // always a respons in case of update r_dcache_fsm = r_dcache_fsm_save; } } break; } case DCACHE_CC_UPDT: // update the cache line { m_cpt_dcache_dir_write++; m_cpt_dcache_data_write++; for(size_t i=0; i>(vci_param::T-1)) != 0 ) r_rsp_fsm = RSP_DATA_WRITE; else if ( p_vci_ini_d.rtrdid.read() == TYPE_DATA_MISS ) r_rsp_fsm = RSP_DATA_MISS; else if ( p_vci_ini_d.rtrdid.read() == TYPE_DATA_UNC ) r_rsp_fsm = RSP_DATA_UNC; else if ( p_vci_ini_d.rtrdid.read() == TYPE_INS_MISS ) r_rsp_fsm = RSP_INS_MISS; else if ( p_vci_ini_d.rtrdid.read() == TYPE_INS_UNC ) r_rsp_fsm = RSP_INS_UNC; } break; } case RSP_DATA_WRITE: { if ( p_vci_ini_d.rspval.read() ) { assert(p_vci_ini_d.reop.read() && "A VCI response packet must contain one flit for a write transaction"); r_rsp_fsm = RSP_IDLE; r_wbuf.completed( p_vci_ini_d.rtrdid.read() - (1<<(vci_param::T-1)) ); if ( p_vci_ini_d.rerror.read() != vci_param::ERR_NORMAL ) m_iss.setWriteBerr(); } break; } case RSP_INS_MISS: { if ( p_vci_ini_d.rspval.read() ) { assert( (r_rsp_cpt < m_icache_words) && "The VCI response packet for instruction miss is too long" ); r_rsp_cpt = r_rsp_cpt + 1; r_icache_miss_buf[r_rsp_cpt] = (data_t)p_vci_ini_d.rdata.read(); if ( p_vci_ini_d.reop.read() ) { assert( (r_rsp_cpt == m_icache_words - 1) && "The VCI response packet for instruction miss is too short"); r_rsp_ins_ok = true; r_rsp_fsm = RSP_IDLE; } if ( p_vci_ini_d.rerror.read() != vci_param::ERR_NORMAL ) r_rsp_ins_error = true; } break; } case RSP_INS_UNC: { if ( p_vci_ini_d.rspval.read() ) { assert(p_vci_ini_d.reop.read() && "illegal VCI response packet for uncachable instruction"); r_icache_miss_buf[0] = (data_t)p_vci_ini_d.rdata.read(); r_rsp_ins_ok = true; r_rsp_fsm = RSP_IDLE; if ( p_vci_ini_d.rerror.read() != vci_param::ERR_NORMAL ) r_rsp_ins_error = true; } break; } case RSP_DATA_MISS: { if ( p_vci_ini_d.rspval.read() ) { assert( (r_rsp_cpt < m_dcache_words) && "The VCI response packet for data miss is too long" ); r_rsp_cpt = r_rsp_cpt + 1; r_dcache_miss_buf[r_rsp_cpt] = (data_t)p_vci_ini_d.rdata.read(); if ( p_vci_ini_d.reop.read() ) { assert(r_rsp_cpt == m_dcache_words - 1 && "The VCI response packet for data miss is too short" ); r_rsp_data_ok = true; r_rsp_fsm = RSP_IDLE; } if ( p_vci_ini_d.rerror.read() != vci_param::ERR_NORMAL ) r_rsp_data_error = true; } break; } case RSP_DATA_UNC: { if ( p_vci_ini_d.rspval.read() ) { assert(p_vci_ini_d.reop.read() && "illegal VCI response packet for uncachable data"); r_dcache_miss_buf[0] = (data_t)p_vci_ini_d.rdata.read(); r_rsp_data_ok = true; r_rsp_fsm = RSP_IDLE; if ( p_vci_ini_d.rerror.read() != vci_param::ERR_NORMAL ) r_rsp_data_error = true; } break; } } // end switch r_rsp_fsm } // end transition() ////////////////////// tmpl(void)::genMoore() { // Coherence network (initiator port) 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 = 0; } else { p_vci_ini_c.address = r_icache_cleanup_line.read() * (m_icache_words << 2); p_vci_ini_c.trdid = 1; } 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 // Direct network initiator response p_vci_ini_d.rspack = ( r_rsp_fsm != RSP_IDLE ); // Direct network initiator command switch ( r_cmd_fsm ) { case CMD_IDLE: p_vci_ini_d.cmdval = false; p_vci_ini_d.address = 0; p_vci_ini_d.wdata = 0; p_vci_ini_d.be = 0; p_vci_ini_d.plen = 0; p_vci_ini_d.cmd = vci_param::CMD_WRITE; p_vci_ini_d.trdid = 0; p_vci_ini_d.pktid = 0; p_vci_ini_d.srcid = 0; p_vci_ini_d.cons = false; p_vci_ini_d.wrap = false; p_vci_ini_d.contig = false; p_vci_ini_d.clen = 0; p_vci_ini_d.cfixed = false; p_vci_ini_d.eop = false; break; case CMD_DATA_WRITE: p_vci_ini_d.cmdval = true; p_vci_ini_d.address = r_wbuf.getAddress(r_cmd_cpt); p_vci_ini_d.wdata = r_wbuf.getData(r_cmd_cpt); p_vci_ini_d.be = r_wbuf.getBe(r_cmd_cpt); p_vci_ini_d.plen = (r_cmd_max - r_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_cmd_cpt == r_cmd_max); break; case CMD_DATA_MISS: p_vci_ini_d.cmdval = true; p_vci_ini_d.address = r_dcache_addr_save & (addr_t)m_dcache_yzmask; p_vci_ini_d.be = 0xF; p_vci_ini_d.plen = m_dcache_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_DATA_UNC: p_vci_ini_d.cmdval = true; p_vci_ini_d.address = r_dcache_addr_save & ~0x3; switch( r_dcache_type_save ) { case iss_t::DATA_WRITE: p_vci_ini_d.wdata = r_dcache_wdata_save.read(); p_vci_ini_d.be = r_dcache_be_save.read(); p_vci_ini_d.cmd = vci_param::CMD_WRITE; break; case iss_t::DATA_READ: p_vci_ini_d.wdata = 0; p_vci_ini_d.be = r_dcache_be_save.read(); p_vci_ini_d.cmd = vci_param::CMD_READ; break; case iss_t::DATA_LL: p_vci_ini_d.wdata = 0; p_vci_ini_d.be = 0xF; p_vci_ini_d.cmd = vci_param::CMD_LOCKED_READ; break; case iss_t::DATA_SC: p_vci_ini_d.wdata = r_dcache_wdata_save.read(); p_vci_ini_d.be = 0xF; p_vci_ini_d.cmd = vci_param::CMD_STORE_COND; break; default: assert("this should not happen"); } p_vci_ini_d.plen = 4; p_vci_ini_d.trdid = TYPE_DATA_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; case CMD_INS_MISS: p_vci_ini_d.cmdval = true; p_vci_ini_d.address = r_icache_addr_save & (addr_t)m_icache_yzmask; p_vci_ini_d.be = 0xF; p_vci_ini_d.plen = m_icache_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 = 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_cmd_fsm // coherence network : target port 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 = !r_tgt_icache_req.read() && !r_tgt_dcache_req.read() && ( r_tgt_icache_rsp | r_tgt_dcache_rsp ); 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 = !r_tgt_icache_req.read() && 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 = !r_tgt_dcache_req.read() && 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