/* -*- c++ -*- * File : vci_mem_cache.cpp * Date : 30/10/2008 * Copyright : UPMC / LIP6 * Authors : Alain Greiner / Eric Guthmuller * * 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 * * Maintainers: alain eric.guthmuller@polytechnique.edu * cesar.fuguet-tortolero@lip6.fr * alexandre.joannou@lip6.fr */ #include "../include/vci_mem_cache_dspin_coherence.h" ////// debug services /////////////////////////////////////////////////////// // All debug messages are conditionned by two variables: // - compile time : DEBUG_MEMC_*** : defined below // - execution time : m_debug_*** : defined by constructor arguments // m_debug_* = (m_debug_ok) and (m_cpt_cycle > m_debug_start_cycle) ///////////////////////////////////////////////////////////////////////////////// #define DEBUG_MEMC_GLOBAL 0 // synthetic trace of all FSMs #define DEBUG_MEMC_READ 1 // detailed trace of READ FSM #define DEBUG_MEMC_WRITE 1 // detailed trace of WRITE FSM #define DEBUG_MEMC_CAS 1 // detailed trace of CAS FSM #define DEBUG_MEMC_IXR_CMD 1 // detailed trace of IXR_RSP FSM #define DEBUG_MEMC_IXR_RSP 1 // detailed trace of IXR_RSP FSM #define DEBUG_MEMC_XRAM_RSP 1 // detailed trace of XRAM_RSP FSM #define DEBUG_MEMC_CC_SEND 1 // detailed trace of CC_SEND FSM #define DEBUG_MEMC_MULTI_ACK 1 // detailed trace of MULTI_ACK FSM #define DEBUG_MEMC_TGT_CMD 1 // detailed trace of TGT_CMD FSM #define DEBUG_MEMC_TGT_RSP 1 // detailed trace of TGT_RSP FSM #define DEBUG_MEMC_CLEANUP 1 // detailed trace of CLEANUP FSM #define RANDOMIZE_CAS 1 namespace soclib { namespace caba { const char *tgt_cmd_fsm_str[] = { "TGT_CMD_IDLE", "TGT_CMD_READ", "TGT_CMD_WRITE", "TGT_CMD_CAS" }; const char *tgt_rsp_fsm_str[] = { "TGT_RSP_READ_IDLE", "TGT_RSP_WRITE_IDLE", "TGT_RSP_CAS_IDLE", "TGT_RSP_XRAM_IDLE", "TGT_RSP_INIT_IDLE", "TGT_RSP_CLEANUP_IDLE", "TGT_RSP_READ", "TGT_RSP_WRITE", "TGT_RSP_CAS", "TGT_RSP_XRAM", "TGT_RSP_INIT", "TGT_RSP_CLEANUP" }; const char *cc_receive_fsm_str[] = { "CC_RECEIVE_IDLE", "CC_RECEIVE_CLEANUP", "CC_RECEIVE_MULTI_ACK" }; const char *cc_send_fsm_str[] = { "CC_SEND_XRAM_RSP_IDLE", "CC_SEND_WRITE_IDLE", "CC_SEND_CAS_IDLE", "CC_SEND_CLEANUP_IDLE", "CC_SEND_CLEANUP_ACK", "CC_SEND_XRAM_RSP_BRDCAST_HEADER", "CC_SEND_XRAM_RSP_BRDCAST_NLINE", "CC_SEND_XRAM_RSP_INVAL_HEADER", "CC_SEND_XRAM_RSP_INVAL_NLINE", "CC_SEND_WRITE_BRDCAST_HEADER", "CC_SEND_WRITE_BRDCAST_NLINE", "CC_SEND_WRITE_UPDT_HEADER", "CC_SEND_WRITE_UPDT_NLINE", "CC_SEND_WRITE_UPDT_DATA", "CC_SEND_CAS_BRDCAST_HEADER", "CC_SEND_CAS_BRDCAST_NLINE", "CC_SEND_CAS_UPDT_HEADER", "CC_SEND_CAS_UPDT_NLINE", "CC_SEND_CAS_UPDT_DATA", "CC_SEND_CAS_UPDT_DATA_HIGH" }; const char *multi_ack_fsm_str[] = { "MULTI_ACK_IDLE", "MULTI_ACK_UPT_LOCK", "MULTI_ACK_UPT_CLEAR", "MULTI_ACK_WRITE_RSP" }; const char *read_fsm_str[] = { "READ_IDLE", "READ_DIR_REQ", "READ_DIR_LOCK", "READ_DIR_HIT", "READ_HEAP_REQ", "READ_HEAP_LOCK", "READ_HEAP_WRITE", "READ_HEAP_ERASE", "READ_HEAP_LAST", "READ_RSP", "READ_TRT_LOCK", "READ_TRT_SET", "READ_TRT_REQ" }; const char *write_fsm_str[] = { "WRITE_IDLE", "WRITE_NEXT", "WRITE_DIR_REQ", "WRITE_DIR_LOCK", "WRITE_DIR_READ", "WRITE_DIR_HIT", "WRITE_UPT_LOCK", "WRITE_UPT_HEAP_LOCK", "WRITE_UPT_REQ", "WRITE_UPT_NEXT", "WRITE_UPT_DEC", "WRITE_RSP", "WRITE_MISS_TRT_LOCK", "WRITE_MISS_TRT_DATA", "WRITE_MISS_TRT_SET", "WRITE_MISS_XRAM_REQ", "WRITE_BC_TRT_LOCK", "WRITE_BC_UPT_LOCK", "WRITE_BC_DIR_INVAL", "WRITE_BC_CC_SEND", "WRITE_BC_XRAM_REQ", "WRITE_WAIT" }; const char *ixr_rsp_fsm_str[] = { "IXR_RSP_IDLE", "IXR_RSP_ACK", "IXR_RSP_TRT_ERASE", "IXR_RSP_TRT_READ" }; const char *xram_rsp_fsm_str[] = { "XRAM_RSP_IDLE", "XRAM_RSP_TRT_COPY", "XRAM_RSP_TRT_DIRTY", "XRAM_RSP_DIR_LOCK", "XRAM_RSP_DIR_UPDT", "XRAM_RSP_DIR_RSP", "XRAM_RSP_INVAL_LOCK", "XRAM_RSP_INVAL_WAIT", "XRAM_RSP_INVAL", "XRAM_RSP_WRITE_DIRTY", "XRAM_RSP_HEAP_REQ", "XRAM_RSP_HEAP_ERASE", "XRAM_RSP_HEAP_LAST", "XRAM_RSP_ERROR_ERASE", "XRAM_RSP_ERROR_RSP" }; const char *ixr_cmd_fsm_str[] = { "IXR_CMD_READ_IDLE", "IXR_CMD_WRITE_IDLE", "IXR_CMD_CAS_IDLE", "IXR_CMD_XRAM_IDLE", "IXR_CMD_READ_NLINE", "IXR_CMD_WRITE_NLINE", "IXR_CMD_CAS_NLINE", "IXR_CMD_XRAM_DATA" }; const char *cas_fsm_str[] = { "CAS_IDLE", "CAS_DIR_REQ", "CAS_DIR_LOCK", "CAS_DIR_HIT_READ", "CAS_DIR_HIT_COMPARE", "CAS_DIR_HIT_WRITE", "CAS_UPT_LOCK", "CAS_UPT_HEAP_LOCK", "CAS_UPT_REQ", "CAS_UPT_NEXT", "CAS_BC_TRT_LOCK", "CAS_BC_UPT_LOCK", "CAS_BC_DIR_INVAL", "CAS_BC_CC_SEND", "CAS_BC_XRAM_REQ", "CAS_RSP_FAIL", "CAS_RSP_SUCCESS", "CAS_MISS_TRT_LOCK", "CAS_MISS_TRT_SET", "CAS_MISS_XRAM_REQ", "CAS_WAIT" }; const char *cleanup_fsm_str[] = { "CLEANUP_IDLE", "CLEANUP_GET_NLINE", "CLEANUP_DIR_REQ", "CLEANUP_DIR_LOCK", "CLEANUP_DIR_WRITE", "CLEANUP_HEAP_REQ", "CLEANUP_HEAP_LOCK", "CLEANUP_HEAP_SEARCH", "CLEANUP_HEAP_CLEAN", "CLEANUP_HEAP_FREE", "CLEANUP_UPT_LOCK", "CLEANUP_UPT_DECREMENT", "CLEANUP_UPT_CLEAR", "CLEANUP_WRITE_RSP", "CLEANUP_SEND_ACK" }; const char *alloc_dir_fsm_str[] = { "ALLOC_DIR_RESET", "ALLOC_DIR_READ", "ALLOC_DIR_WRITE", "ALLOC_DIR_CAS", "ALLOC_DIR_CLEANUP", "ALLOC_DIR_XRAM_RSP" }; const char *alloc_trt_fsm_str[] = { "ALLOC_TRT_READ", "ALLOC_TRT_WRITE", "ALLOC_TRT_CAS", "ALLOC_TRT_XRAM_RSP", "ALLOC_TRT_IXR_RSP" }; const char *alloc_upt_fsm_str[] = { "ALLOC_UPT_WRITE", "ALLOC_UPT_XRAM_RSP", "ALLOC_UPT_MULTI_ACK", "ALLOC_UPT_CLEANUP", "ALLOC_UPT_CAS" }; const char *alloc_heap_fsm_str[] = { "ALLOC_HEAP_RESET", "ALLOC_HEAP_READ", "ALLOC_HEAP_WRITE", "ALLOC_HEAP_CAS", "ALLOC_HEAP_CLEANUP", "ALLOC_HEAP_XRAM_RSP" }; #define tmpl(x) \ template x \ VciMemCache using soclib::common::uint32_log2; //////////////////////////////// // Constructor //////////////////////////////// tmpl(/**/) ::VciMemCache( sc_module_name name, const soclib::common::MappingTable &mtp, const soclib::common::MappingTable &mtc, const soclib::common::MappingTable &mtx, const soclib::common::IntTab &vci_ixr_index, const soclib::common::IntTab &vci_ini_index, const soclib::common::IntTab &vci_tgt_index, const soclib::common::IntTab &vci_tgt_index_cleanup, size_t nways, // number of ways per set size_t nsets, // number of cache sets size_t nwords, // number of words in cache line size_t heap_size, // number of heap entries size_t transaction_tab_lines, // number of TRT entries size_t update_tab_lines, // number of UPT entries size_t debug_start_cycle, bool debug_ok) : soclib::caba::BaseModule(name), m_debug_start_cycle(debug_start_cycle), m_debug_ok(debug_ok), p_clk("clk"), p_resetn("resetn"), p_vci_tgt("vci_tgt"), p_vci_ixr("vci_ixr"), p_dspin_in("dspin_tgt"), p_dspin_out("cc_send"), m_seglist(mtp.getSegmentList(vci_tgt_index)), m_cseglist(mtc.getSegmentList(vci_tgt_index_cleanup)), m_initiators(1 << vci_param::S), m_heap_size(heap_size), m_ways(nways), m_sets(nsets), m_words(nwords), m_srcid_ixr(mtx.indexForId(vci_ixr_index)), m_srcid_ini(mtc.indexForId(vci_ini_index)), m_transaction_tab_lines(transaction_tab_lines), m_transaction_tab(transaction_tab_lines, nwords), m_update_tab_lines(update_tab_lines), m_update_tab(update_tab_lines), m_cache_directory(nways, nsets, nwords, vci_param::N), m_cache_data(nways, nsets, nwords), m_heap(m_heap_size), m_llsc_table(), #define L2 soclib::common::uint32_log2 m_x(L2(m_words), 2), m_y(L2(m_sets), L2(m_words) + 2), m_z(vci_param::N - L2(m_sets) - L2(m_words) - 2, L2(m_sets) + L2(m_words) + 2), m_nline(vci_param::N - L2(m_words) - 2, L2(m_words) + 2), #undef L2 // XMIN(5 bits) / XMAX(5 bits) / YMIN(5 bits) / YMAX(5 bits) // 0b00000 / 0b11111 / 0b00000 / 0b11111 m_broadcast_address(0x7C1F), // FIFOs m_cmd_read_addr_fifo("m_cmd_read_addr_fifo", 4), m_cmd_read_length_fifo("m_cmd_read_length_fifo", 4), m_cmd_read_srcid_fifo("m_cmd_read_srcid_fifo", 4), m_cmd_read_trdid_fifo("m_cmd_read_trdid_fifo", 4), m_cmd_read_pktid_fifo("m_cmd_read_pktid_fifo", 4), m_cmd_write_addr_fifo("m_cmd_write_addr_fifo",8), m_cmd_write_eop_fifo("m_cmd_write_eop_fifo",8), m_cmd_write_srcid_fifo("m_cmd_write_srcid_fifo",8), m_cmd_write_trdid_fifo("m_cmd_write_trdid_fifo",8), m_cmd_write_pktid_fifo("m_cmd_write_pktid_fifo",8), m_cmd_write_data_fifo("m_cmd_write_data_fifo",8), m_cmd_write_be_fifo("m_cmd_write_be_fifo",8), m_cmd_cas_addr_fifo("m_cmd_cas_addr_fifo",4), m_cmd_cas_eop_fifo("m_cmd_cas_eop_fifo",4), m_cmd_cas_srcid_fifo("m_cmd_cas_srcid_fifo",4), m_cmd_cas_trdid_fifo("m_cmd_cas_trdid_fifo",4), m_cmd_cas_pktid_fifo("m_cmd_cas_pktid_fifo",4), m_cmd_cas_wdata_fifo("m_cmd_cas_wdata_fifo",4), m_cc_receive_to_cleanup_fifo("m_cc_receive_to_cleanup_fifo", 4), m_cc_receive_to_multi_ack_fifo("m_cc_receive_to_multi_ack_fifo", 4), r_tgt_cmd_fsm("r_tgt_cmd_fsm"), m_nseg(0), m_ncseg(0), r_read_fsm("r_read_fsm"), r_write_fsm("r_write_fsm"), m_write_to_cc_send_inst_fifo("m_write_to_cc_send_inst_fifo",8), m_write_to_cc_send_srcid_fifo("m_write_to_cc_send_srcid_fifo",8), #if L1_MULTI_CACHE m_write_to_cc_send_cache_id_fifo("m_write_to_cc_send_cache_id_fifo",8), #endif r_multi_ack_fsm("r_multi_ack_fsm"), r_cleanup_fsm("r_cleanup_fsm"), r_cas_fsm("r_cas_fsm"), m_cas_to_cc_send_inst_fifo("m_cas_to_cc_send_inst_fifo",8), m_cas_to_cc_send_srcid_fifo("m_cas_to_cc_send_srcid_fifo",8), #if L1_MULTI_CACHE m_cas_to_cc_send_cache_id_fifo("m_cas_to_cc_send_cache_id_fifo",8), #endif r_ixr_rsp_fsm("r_ixr_rsp_fsm"), r_xram_rsp_fsm("r_xram_rsp_fsm"), m_xram_rsp_to_cc_send_inst_fifo("m_xram_rsp_to_cc_send_inst_fifo",8), m_xram_rsp_to_cc_send_srcid_fifo("m_xram_rsp_to_cc_send_srcid_fifo",8), #if L1_MULTI_CACHE m_xram_rsp_to_cc_send_cache_id_fifo("m_xram_rsp_to_cc_send_cache_id_fifo",8), #endif r_ixr_cmd_fsm("r_ixr_cmd_fsm"), r_tgt_rsp_fsm("r_tgt_rsp_fsm"), r_cc_send_fsm("r_cc_send_fsm"), r_cc_receive_fsm("r_cc_receive_fsm"), r_alloc_dir_fsm("r_alloc_dir_fsm"), r_alloc_dir_reset_cpt("r_alloc_dir_reset_cpt"), r_alloc_trt_fsm("r_alloc_trt_fsm"), r_alloc_upt_fsm("r_alloc_upt_fsm"), r_alloc_heap_fsm("r_alloc_heap_fsm"), r_alloc_heap_reset_cpt("r_alloc_heap_reset_cpt") { assert(IS_POW_OF_2(nsets)); assert(IS_POW_OF_2(nwords)); assert(IS_POW_OF_2(nways)); assert(nsets); assert(nwords); assert(nways); // check Transaction table size assert((uint32_log2(transaction_tab_lines) <= vci_param::T) and "Need more bits for VCI TRDID field"); // Get the segments associated to the MemCache std::list::iterator seg; size_t i; for(seg = m_seglist.begin(); seg != m_seglist.end() ; seg++) { m_nseg++; } for(seg = m_cseglist.begin(); seg != m_cseglist.end() ; seg++) { m_ncseg++; } m_seg = new soclib::common::Segment*[m_nseg]; i = 0; for(seg = m_seglist.begin() ; seg != m_seglist.end() ; seg++) { m_seg[i] = & (*seg); i++; } m_cseg = new soclib::common::Segment*[m_ncseg]; i = 0; for(seg = m_cseglist.begin() ; seg != m_cseglist.end() ; seg++) { m_cseg[i] = & (*seg); i++; } // Allocation for IXR_RSP FSM r_ixr_rsp_to_xram_rsp_rok = new sc_signal[m_transaction_tab_lines]; // Allocation for XRAM_RSP FSM r_xram_rsp_victim_data = new sc_signal[nwords]; r_xram_rsp_to_tgt_rsp_data = new sc_signal[nwords]; r_xram_rsp_to_ixr_cmd_data = new sc_signal[nwords]; // Allocation for READ FSM r_read_data = new sc_signal[nwords]; r_read_to_tgt_rsp_data = new sc_signal[nwords]; // Allocation for WRITE FSM r_write_data = new sc_signal[nwords]; r_write_be = new sc_signal[nwords]; r_write_to_cc_send_data = new sc_signal[nwords]; r_write_to_cc_send_be = new sc_signal[nwords]; r_write_to_ixr_cmd_data = new sc_signal[nwords]; // Allocation for CAS FSM r_cas_to_ixr_cmd_data = new sc_signal[nwords]; r_cas_data = new sc_signal[nwords]; r_cas_rdata = new sc_signal[2]; // Simulation SC_METHOD(transition); dont_initialize(); sensitive << p_clk.pos(); SC_METHOD(genMoore); dont_initialize(); sensitive << p_clk.neg(); } // end constructor /////////////////////////////////////////////////////////////////////// tmpl(void) ::start_monitor(vci_addr_t addr, vci_addr_t length) /////////////////////////////////////////////////////////////////////// { m_monitor_ok = true; m_monitor_base = addr; m_monitor_length = length; } /////////////////////////////////////////////////////////////////////// tmpl(void) ::stop_monitor() /////////////////////////////////////////////////////////////////////// { m_monitor_ok = false; } /////////////////////////////////////////////////////////////////////// tmpl(void) ::check_monitor(const char *buf, vci_addr_t addr, data_t data) /////////////////////////////////////////////////////////////////////// { if((addr >= m_monitor_base) and (addr < m_monitor_base + m_monitor_length)) { std::cout << " MEMC Write Monitor : " << buf << " Address = " << std::hex << addr << " / Data = " << data << " at cycle " << std::dec << m_cpt_cycles << std::endl; } } /////////////////////////////////////////////////////////////////////// tmpl(void) ::check_monitor_read(const char *buf, vci_addr_t addr) /////////////////////////////////////////////////////////////////////// { if((addr >= m_monitor_base) and (addr < m_monitor_base + m_monitor_length)) { std::cout << " MEMC Read Monitor : " << buf << " Address = " << std::hex << addr << std::endl; } } ///////////////////////////////////////////////////// tmpl(void) ::copies_monitor(vci_addr_t addr) ///////////////////////////////////////////////////// { DirectoryEntry entry = m_cache_directory.read_neutral(addr); if((entry.count != m_debug_previous_count) or (entry.valid != m_debug_previous_hit)) { std::cout << " MEMC " << name() << " cache change at cycle " << std::dec << m_cpt_cycles << " for address " << std::hex << addr << " / HIT = " << entry.valid << " / COUNT = " << std::dec << entry.count << std::endl; } m_debug_previous_count = entry.count; m_debug_previous_hit = entry.valid; } ////////////////////////////////////////////////// tmpl(void) ::print_trace() ////////////////////////////////////////////////// { std::cout << "MEMC " << name() << std::endl; std::cout << " " << tgt_cmd_fsm_str[r_tgt_cmd_fsm] << " | " << tgt_rsp_fsm_str[r_tgt_rsp_fsm] << " | " << read_fsm_str[r_read_fsm] << " | " << write_fsm_str[r_write_fsm] << " | " << cas_fsm_str[r_cas_fsm] << " | " << cleanup_fsm_str[r_cleanup_fsm] << std::endl; std::cout << " " << cc_send_fsm_str[r_cc_send_fsm] << " | " << cc_receive_fsm_str[r_cc_receive_fsm] << " | " << multi_ack_fsm_str[r_multi_ack_fsm] << " | " << ixr_cmd_fsm_str[r_ixr_cmd_fsm] << " | " << ixr_rsp_fsm_str[r_ixr_rsp_fsm] << " | " << xram_rsp_fsm_str[r_xram_rsp_fsm] << std::endl; //m_llsc_table.print_trace(); } ///////////////////////////////////////// tmpl(void) ::print_stats() ///////////////////////////////////////// { std::cout << "----------------------------------" << std::dec << std::endl; std::cout << "MEM_CACHE " << m_srcid_ini << " / Time = " << m_cpt_cycles << std::endl << "- READ RATE = " << (double) m_cpt_read/m_cpt_cycles << std::endl << "- READ TOTAL = " << m_cpt_read << std::endl << "- READ MISS RATE = " << (double) m_cpt_read_miss/m_cpt_read << std::endl << "- WRITE RATE = " << (double) m_cpt_write/m_cpt_cycles << std::endl << "- WRITE TOTAL = " << m_cpt_write << std::endl << "- WRITE MISS RATE = " << (double) m_cpt_write_miss/m_cpt_write << std::endl << "- WRITE BURST LENGTH = " << (double) m_cpt_write_cells/m_cpt_write << std::endl << "- WRITE BURST TOTAL = " << m_cpt_write_cells << std::endl << "- REQUESTS TRT FULL = " << m_cpt_trt_full << std::endl << "- READ TRT BLOKED HIT = " << m_cpt_trt_rb << std::endl << "- UPDATE RATE = " << (double) m_cpt_update/m_cpt_cycles << std::endl << "- UPDATE ARITY = " << (double) m_cpt_update_mult/m_cpt_update << std::endl << "- INVAL MULTICAST RATE = " << (double)(m_cpt_inval-m_cpt_inval_brdcast) /m_cpt_cycles << std::endl << "- INVAL MULTICAST ARITY= " << (double) m_cpt_inval_mult/ (m_cpt_inval-m_cpt_inval_brdcast) << std::endl << "- INVAL BROADCAST RATE = " << (double) m_cpt_inval_brdcast/m_cpt_cycles << std::endl << "- SAVE DIRTY RATE = " << (double) m_cpt_write_dirty/m_cpt_cycles << std::endl << "- CLEANUP RATE = " << (double) m_cpt_cleanup/m_cpt_cycles << std::endl << "- LL RATE = " << (double) m_cpt_ll/m_cpt_cycles << std::endl << "- SC RATE = " << (double) m_cpt_sc/m_cpt_cycles << std::endl << "- CAS RATE = " << (double) m_cpt_cas/m_cpt_cycles << std::endl; } ///////////////////////////////// tmpl(/**/) ::~VciMemCache() ///////////////////////////////// { delete [] r_ixr_rsp_to_xram_rsp_rok; delete [] r_xram_rsp_victim_data; delete [] r_xram_rsp_to_tgt_rsp_data; delete [] r_xram_rsp_to_ixr_cmd_data; delete [] r_read_data; delete [] r_read_to_tgt_rsp_data; delete [] r_write_data; delete [] r_write_be; delete [] r_write_to_cc_send_data; } ////////////////////////////////// tmpl(void) ::transition() ////////////////////////////////// { using soclib::common::uint32_log2; // RESET if(! p_resetn.read()) { // Initializing FSMs r_tgt_cmd_fsm = TGT_CMD_IDLE; r_tgt_rsp_fsm = TGT_RSP_READ_IDLE; r_cc_send_fsm = CC_SEND_XRAM_RSP_IDLE; r_cc_receive_fsm = CC_RECEIVE_IDLE; r_multi_ack_fsm = MULTI_ACK_IDLE; r_read_fsm = READ_IDLE; r_write_fsm = WRITE_IDLE; r_cas_fsm = CAS_IDLE; r_cleanup_fsm = CLEANUP_IDLE; r_alloc_dir_fsm = ALLOC_DIR_RESET; r_alloc_heap_fsm = ALLOC_HEAP_RESET; r_alloc_trt_fsm = ALLOC_TRT_READ; r_alloc_upt_fsm = ALLOC_UPT_WRITE; r_ixr_rsp_fsm = IXR_RSP_IDLE; r_xram_rsp_fsm = XRAM_RSP_IDLE; r_ixr_cmd_fsm = IXR_CMD_READ_IDLE; m_debug_global = false; m_debug_tgt_cmd_fsm = false; m_debug_tgt_rsp_fsm = false; m_debug_cc_send_fsm = false; m_debug_cc_receive_fsm = false; m_debug_multi_ack_fsm = false; m_debug_read_fsm = false; m_debug_write_fsm = false; m_debug_cas_fsm = false; m_debug_cleanup_fsm = false; m_debug_ixr_cmd_fsm = false; m_debug_ixr_rsp_fsm = false; m_debug_xram_rsp_fsm = false; m_debug_previous_hit = false; m_debug_previous_count = 0; // Initializing Tables m_transaction_tab.init(); m_update_tab.init(); m_llsc_table.init(); // initializing FIFOs and communication Buffers m_cmd_read_addr_fifo.init(); m_cmd_read_length_fifo.init(); m_cmd_read_srcid_fifo.init(); m_cmd_read_trdid_fifo.init(); m_cmd_read_pktid_fifo.init(); m_cmd_write_addr_fifo.init(); m_cmd_write_eop_fifo.init(); m_cmd_write_srcid_fifo.init(); m_cmd_write_trdid_fifo.init(); m_cmd_write_pktid_fifo.init(); m_cmd_write_data_fifo.init(); m_cmd_cas_addr_fifo.init() ; m_cmd_cas_srcid_fifo.init() ; m_cmd_cas_trdid_fifo.init() ; m_cmd_cas_pktid_fifo.init() ; m_cmd_cas_wdata_fifo.init() ; m_cmd_cas_eop_fifo.init() ; r_read_to_tgt_rsp_req = false; r_read_to_ixr_cmd_req = false; r_write_to_tgt_rsp_req = false; r_write_to_ixr_cmd_req = false; r_write_to_cc_send_multi_req = false; r_write_to_cc_send_brdcast_req = false; r_write_to_multi_ack_req = false; m_write_to_cc_send_inst_fifo.init(); m_write_to_cc_send_srcid_fifo.init(); #if L1_MULTI_CACHE m_write_to_cc_send_cache_id_fifo.init(); #endif r_cleanup_to_tgt_rsp_req = false; m_cc_receive_to_cleanup_fifo.init(); r_multi_ack_to_tgt_rsp_req = false; m_cc_receive_to_multi_ack_fifo.init(); r_cas_to_tgt_rsp_req = false; r_cas_cpt = 0 ; r_cas_lfsr = -1 ; r_cas_to_ixr_cmd_req = false; r_cas_to_cc_send_multi_req = false; r_cas_to_cc_send_brdcast_req = false; m_cas_to_cc_send_inst_fifo.init(); m_cas_to_cc_send_srcid_fifo.init(); #if L1_MULTI_CACHE m_cas_to_cc_send_cache_id_fifo.init(); #endif for(size_t i=0; i m_debug_start_cycle) and m_debug_ok; m_debug_tgt_cmd_fsm = (m_cpt_cycles > m_debug_start_cycle) and m_debug_ok; m_debug_tgt_rsp_fsm = (m_cpt_cycles > m_debug_start_cycle) and m_debug_ok; m_debug_cc_send_fsm = (m_cpt_cycles > m_debug_start_cycle) and m_debug_ok; m_debug_cc_receive_fsm = (m_cpt_cycles > m_debug_start_cycle) and m_debug_ok; m_debug_multi_ack_fsm = (m_cpt_cycles > m_debug_start_cycle) and m_debug_ok; m_debug_read_fsm = (m_cpt_cycles > m_debug_start_cycle) and m_debug_ok; m_debug_write_fsm = (m_cpt_cycles > m_debug_start_cycle) and m_debug_ok; m_debug_cas_fsm = (m_cpt_cycles > m_debug_start_cycle) and m_debug_ok; m_debug_cleanup_fsm = (m_cpt_cycles > m_debug_start_cycle) and m_debug_ok; m_debug_ixr_cmd_fsm = (m_cpt_cycles > m_debug_start_cycle) and m_debug_ok; m_debug_ixr_rsp_fsm = (m_cpt_cycles > m_debug_start_cycle) and m_debug_ok; m_debug_xram_rsp_fsm = (m_cpt_cycles > m_debug_start_cycle) and m_debug_ok; #if DEBUG_MEMC_GLOBAL if(m_debug_global) { std::cout << "---------------------------------------------" << std::dec << std::endl << "MEM_CACHE " << m_srcid_ini << " ; Time = " << m_cpt_cycles << std::endl << " - TGT_CMD FSM = " << tgt_cmd_fsm_str[r_tgt_cmd_fsm.read()] << std::endl << " - TGT_RSP FSM = " << tgt_rsp_fsm_str[r_tgt_rsp_fsm.read()] << std::endl << " - CC_SEND FSM = " << cc_send_fsm_str[r_cc_send_fsm.read()] << std::endl << " - CC_RECEIVE FSM = " << cc_receive_fsm_str[r_cc_receive_fsm.read()] << std::endl << " - MULTI_ACK FSM = " << multi_ack_fsm_str[r_multi_ack_fsm.read()] << std::endl << " - READ FSM = " << read_fsm_str[r_read_fsm.read()] << std::endl << " - WRITE FSM = " << write_fsm_str[r_write_fsm.read()] << std::endl << " - CAS FSM = " << cas_fsm_str[r_cas_fsm.read()] << std::endl << " - CLEANUP FSM = " << cleanup_fsm_str[r_cleanup_fsm.read()] << std::endl << " - IXR_CMD FSM = " << ixr_cmd_fsm_str[r_ixr_cmd_fsm.read()] << std::endl << " - IXR_RSP FSM = " << ixr_rsp_fsm_str[r_ixr_rsp_fsm.read()] << std::endl << " - XRAM_RSP FSM = " << xram_rsp_fsm_str[r_xram_rsp_fsm.read()] << std::endl << " - ALLOC_DIR FSM = " << alloc_dir_fsm_str[r_alloc_dir_fsm.read()] << std::endl << " - ALLOC_TRT FSM = " << alloc_trt_fsm_str[r_alloc_trt_fsm.read()] << std::endl << " - ALLOC_UPT FSM = " << alloc_upt_fsm_str[r_alloc_upt_fsm.read()] << std::endl << " - ALLOC_HEAP FSM = " << alloc_heap_fsm_str[r_alloc_heap_fsm.read()] << std::endl; } #endif //////////////////////////////////////////////////////////////////////////////////// // TGT_CMD FSM //////////////////////////////////////////////////////////////////////////////////// // The TGT_CMD_FSM controls the incoming VCI command pakets from the processors // // There are 5 types of accepted commands : // - READ : A READ request has a length of 1 VCI cell. It can be a single word // or an entire cache line, depending on the PLEN value. // - WRITE : A WRITE request has a maximum length of 16 cells, and can only // concern words in a same line. // - CAS : A CAS request has a length of 2 cells or 4 cells. // - LL : An LL request has a length of 1 cell. // - SC : An SC request has a length of 2 cells. First cell contains the // acces key, second cell the data to write in case of success. //////////////////////////////////////////////////////////////////////////////////// switch(r_tgt_cmd_fsm.read()) { ////////////////// case TGT_CMD_IDLE: if(p_vci_tgt.cmdval) { #if DEBUG_MEMC_TGT_CMD if(m_debug_tgt_cmd_fsm) { std::cout << " Receive command from srcid " << std::dec << p_vci_tgt.srcid.read() << " / for address " << std::hex << p_vci_tgt.address.read() << std::endl; } #endif // checking segmentation violation vci_addr_t address = p_vci_tgt.address.read(); uint32_t plen = p_vci_tgt.plen.read(); bool found = false; for(size_t seg_id = 0 ; seg_id < m_nseg ; seg_id++) { if(m_seg[seg_id]->contains(address) && m_seg[seg_id]->contains(address + plen - vci_param::B)) { found = true; } } if(not found) { std::cout << "VCI_MEM_CACHE ERROR " << name() << std::endl; std::cout << "Out of segment VCI address in TGT_CMD_IDLE state (address = " << std::hex << address << ", srcid = " << p_vci_tgt.srcid.read() << std::dec << ", cycle = " << m_cpt_cycles << ")" << std::endl; exit(0); } if(p_vci_tgt.cmd.read() == vci_param::CMD_READ) { // check that the pktid is either : // TYPE_READ_DATA_UNC // TYPE_READ_DATA_MISS // TYPE_READ_INS_UNC // TYPE_READ_INS_MISS // ==> bit2 must be zero with the TSAR encoding // ==> mask = 0b0100 = 0x4 assert(((p_vci_tgt.pktid.read() & 0x4) == 0x0) && "The type specified in the pktid field is incompatible with the READ CMD"); r_tgt_cmd_fsm = TGT_CMD_READ; } else if(p_vci_tgt.cmd.read() == vci_param::CMD_WRITE) { // check that the pktid is TYPE_WRITE // ==> TYPE_WRITE = X100 with the TSAR encoding // ==> mask = 0b0111 = 0x7 assert(((p_vci_tgt.pktid.read() & 0x7) == 0x4) && "The type specified in the pktid field is incompatible with the WRITE CMD"); r_tgt_cmd_fsm = TGT_CMD_WRITE; } else if(p_vci_tgt.cmd.read() == vci_param::CMD_LOCKED_READ) { // check that the pktid is TYPE_LL // ==> TYPE_LL = X110 with the TSAR encoding // ==> mask = 0b0111 = 0x7 assert(((p_vci_tgt.pktid.read() & 0x7) == 0x6) && "The type specified in the pktid field is incompatible with the LL CMD"); r_tgt_cmd_fsm = TGT_CMD_READ; } else if(p_vci_tgt.cmd.read() == vci_param::CMD_NOP) { // check that the pktid is either : // TYPE_CAS // TYPE_SC // ==> TYPE_CAS = X101 with the TSAR encoding // ==> TYPE_SC = X111 with the TSAR encoding // ==> mask = 0b0101 = 0x5 assert(((p_vci_tgt.pktid.read() & 0x5) == 0x5) && "The type specified in the pktid field is incompatible with the NOP CMD"); if((p_vci_tgt.pktid.read() & 0x7) == TYPE_CAS) r_tgt_cmd_fsm = TGT_CMD_CAS; else // TYPE_SC r_tgt_cmd_fsm = TGT_CMD_WRITE; } else { std::cout << "VCI_MEM_CACHE ERROR " << name() << " TGT_CMD_IDLE state" << std::endl; std::cout << " illegal VCI command type" << std::endl; exit(0); } } break; ////////////////// case TGT_CMD_READ: // This test checks that the read does not cross a cache line limit. // It must not be taken into account when dealing with an LL CMD. if(((m_x[(vci_addr_t) p_vci_tgt.address.read()]+ (p_vci_tgt.plen.read() >>2)) > 16) && (p_vci_tgt.cmd.read() != vci_param::CMD_LOCKED_READ)) { std::cout << "VCI_MEM_CACHE ERROR " << name() << " TGT_CMD_READ state" << std::endl; std::cout << " illegal address/plen combination for VCI read command" << std::endl; exit(0); } if(!p_vci_tgt.eop.read()) { std::cout << "VCI_MEM_CACHE ERROR " << name() << " TGT_CMD_READ state" << std::endl; std::cout << " read or ll command packets must contain one single flit" << std::endl; exit(0); } if((p_vci_tgt.cmd.read() == vci_param::CMD_LOCKED_READ) && (p_vci_tgt.plen.read() != 8)) { std::cout << "VCI_MEM_CACHE ERROR " << name() << " TGT_CMD_READ state" << std::endl; std::cout << " ll command packets must have a plen of 8" << std::endl; exit(0); } if(p_vci_tgt.cmdval && m_cmd_read_addr_fifo.wok()) { #if DEBUG_MEMC_TGT_CMD if(m_debug_tgt_cmd_fsm) { std::cout << " Push into read_fifo:" << " address = " << std::hex << p_vci_tgt.address.read() << " srcid = " << std::dec << p_vci_tgt.srcid.read() << " trdid = " << p_vci_tgt.trdid.read() << " pktid = " << p_vci_tgt.pktid.read() << " plen = " << std::dec << p_vci_tgt.plen.read() << std::endl; } #endif cmd_read_fifo_put = true; if(p_vci_tgt.cmd.read() == vci_param::CMD_LOCKED_READ) m_cpt_ll++; else m_cpt_read++; r_tgt_cmd_fsm = TGT_CMD_IDLE; } break; /////////////////// case TGT_CMD_WRITE: if(p_vci_tgt.cmdval && m_cmd_write_addr_fifo.wok()) { #if DEBUG_MEMC_TGT_CMD if(m_debug_tgt_cmd_fsm) { std::cout << " Push into write_fifo:" << " address = " << std::hex << p_vci_tgt.address.read() << " srcid = " << std::dec << p_vci_tgt.srcid.read() << " trdid = " << p_vci_tgt.trdid.read() << " pktid = " << p_vci_tgt.pktid.read() << " wdata = " << std::hex << p_vci_tgt.wdata.read() << " be = " << p_vci_tgt.be.read() << " plen = " << std::dec << p_vci_tgt.plen.read() << std::endl; } #endif cmd_write_fifo_put = true; if(p_vci_tgt.eop) r_tgt_cmd_fsm = TGT_CMD_IDLE; } break; //////////////////// case TGT_CMD_CAS: if((p_vci_tgt.plen.read() != 8) && (p_vci_tgt.plen.read() != 16)) { std::cout << "VCI_MEM_CACHE ERROR " << name() << " TGT_CMD_CAS state" << std::endl << "illegal format for CAS command " << std::endl; exit(0); } if(p_vci_tgt.cmdval && m_cmd_cas_addr_fifo.wok()) { #if DEBUG_MEMC_TGT_CMD if(m_debug_tgt_cmd_fsm) { std::cout << " Pushing command into cmd_cas_fifo:" << " address = " << std::hex << p_vci_tgt.address.read() << " srcid = " << std::dec << p_vci_tgt.srcid.read() << " trdid = " << p_vci_tgt.trdid.read() << " pktid = " << p_vci_tgt.pktid.read() << " wdata = " << std::hex << p_vci_tgt.wdata.read() << " be = " << p_vci_tgt.be.read() << " plen = " << std::dec << p_vci_tgt.plen.read() << std::endl; } #endif cmd_cas_fifo_put = true; if(p_vci_tgt.eop) r_tgt_cmd_fsm = TGT_CMD_IDLE; } break; } // end switch tgt_cmd_fsm ///////////////////////////////////////////////////////////////////////// // MULTI_ACK FSM ///////////////////////////////////////////////////////////////////////// // This FSM controls the response to the multicast update or multicast // inval coherence requests sent by the memory cache to the L1 caches and // update the UPT. // // It can be update or inval requests initiated by the WRITE or CAS FSM, // or inval requests initiated by the XRAM_RSP FSM. // It can also be a direct request from the WRITE FSM. // // The FSM decrements the proper entry in UPT. // It sends a request to the TGT_RSP FSM to complete the pending // write transaction (acknowledge response to the writer processor), // and clear the UPT entry when all responses have been received. // // All those response packets are one flit packet. // The index in the Table is defined in the UPDT_TABLE INDEX field, and // the transaction type is defined in the UPT entry. //////////////////////////////////////////////////////////////////////// switch(r_multi_ack_fsm.read()) { case MULTI_ACK_IDLE: { bool multi_ack_fifo_rok = m_cc_receive_to_multi_ack_fifo.rok(); // None Multicast Acknowledgement received and // none WRITE FSM UPT decrement request if( not multi_ack_fifo_rok and not r_write_to_multi_ack_req.read()) { break; } // WRITE FSM request to decrement update table response counter // Priority to Multicast Acknowledgement priority if(not multi_ack_fifo_rok) { r_write_to_multi_ack_req = false; r_multi_ack_upt_index = r_write_to_multi_ack_upt_index.read(); r_multi_ack_fsm = MULTI_ACK_UPT_LOCK; break; } // Multicast Acknowledgement received uint64_t flit = m_cc_receive_to_multi_ack_fifo.read(); uint8_t updt_index = DspinDhccpParam::dspin_get(flit, DspinDhccpParam::MULTI_ACK_UPDT_INDEX); bool eop = (DspinDhccpParam::dspin_get(flit, DspinDhccpParam::FROM_L1_EOP) == 0x1); if(updt_index >= m_update_tab.size()) { std::cout << "VCI_MEM_CACHE ERROR " << name() << " MULTI_ACK_IDLE state" << std::endl << "index too large for UPT: " << std::dec << " / UPT index = " << updt_index << " / UPT size = " << m_update_tab.size() << std::endl; exit(0); } if(not eop) { std::cout << "VCI_MEM_CACHE ERROR " << name() << " MULTI_ACK_IDLE state" << std::endl << "A Multicast Acknowledgement must be an one flit packet" << std::endl; exit(0); } cc_receive_to_multi_ack_fifo_get = true; r_multi_ack_upt_index = updt_index; r_multi_ack_fsm = MULTI_ACK_UPT_LOCK; #if DEBUG_MEMC_MULTI_ACK if(m_debug_multi_ack_fsm) { std::cout << " Response for UPT entry " << updt_index << std::endl; } #endif break; } case MULTI_ACK_UPT_LOCK: { // get lock to the UPDATE table if(r_alloc_upt_fsm.read() != ALLOC_UPT_MULTI_ACK) break; // decrement the number of expected responses size_t count = 0; bool valid = m_update_tab.decrement(r_multi_ack_upt_index.read(), count); if(not valid) { std::cout << "VCI_MEM_CACHE ERROR " << name() << " MULTI_ACK_UPT_LOCK state" << std::endl << "unsuccessful access to decrement the UPT" << std::endl; exit(0); } if(count == 0) { r_multi_ack_fsm = MULTI_ACK_UPT_CLEAR; } else { r_multi_ack_fsm = MULTI_ACK_IDLE; } #if DEBUG_MEMC_MULTI_ACK if(m_debug_multi_ack_fsm) { std::cout << " Decrement the responses counter for UPT:" << " entry = " << r_multi_ack_upt_index.read() << " / rsp_count = " << std::dec << count << std::endl; } #endif break; } case MULTI_ACK_UPT_CLEAR: { if(r_alloc_upt_fsm.read() != ALLOC_UPT_MULTI_ACK) { std::cout << "VCI_MEM_CACHE ERROR " << name() << " MULTI_ACK_UPT_LOCK state" << " bad UPT allocation" << std::endl; exit(0); } r_multi_ack_srcid = m_update_tab.srcid(r_multi_ack_upt_index.read()); r_multi_ack_trdid = m_update_tab.trdid(r_multi_ack_upt_index.read()); r_multi_ack_pktid = m_update_tab.pktid(r_multi_ack_upt_index.read()); r_multi_ack_nline = m_update_tab.nline(r_multi_ack_upt_index.read()); bool need_rsp = m_update_tab.need_rsp(r_multi_ack_upt_index.read()); // clear the UPT entry m_update_tab.clear(r_multi_ack_upt_index.read()); if(need_rsp) { r_multi_ack_fsm = MULTI_ACK_WRITE_RSP; } else { r_multi_ack_fsm = MULTI_ACK_IDLE; } #if DEBUG_MEMC_MULTI_ACK if(m_debug_multi_ack_fsm) { std::cout << " Clear UPT entry " << r_multi_ack_upt_index.read() << std::endl; } #endif break; } case MULTI_ACK_WRITE_RSP: { // Post a request to TGT_RSP FSM // Wait if pending request to the TGT_RSP FSM if(r_multi_ack_to_tgt_rsp_req.read()) break; r_multi_ack_to_tgt_rsp_req = true; r_multi_ack_to_tgt_rsp_srcid = r_multi_ack_srcid.read(); r_multi_ack_to_tgt_rsp_trdid = r_multi_ack_trdid.read(); r_multi_ack_to_tgt_rsp_pktid = r_multi_ack_pktid.read(); r_multi_ack_fsm = MULTI_ACK_IDLE; #if DEBUG_MEMC_MULTI_ACK if(m_debug_multi_ack_fsm) { std::cout << " Request TGT_RSP FSM to send a response to srcid " << r_multi_ack_srcid.read() << std::endl; } #endif break; } } // end switch r_multi_ack_fsm //////////////////////////////////////////////////////////////////////////////////// // READ FSM //////////////////////////////////////////////////////////////////////////////////// // The READ FSM controls the VCI read and ll requests. // It takes the lock protecting the cache directory to check the cache line status: // - In case of HIT // The fsm copies the data (one line, or one single word) // in the r_read_to_tgt_rsp buffer. It waits if this buffer is not empty. // The requesting initiator is registered in the cache directory. // If the number of copy is larger than 1, the new copy is registered // in the HEAP. // If the number of copy is larger than the threshold, the HEAP is cleared, // and the corresponding line switches to the counter mode. // - In case of MISS // The READ fsm takes the lock protecting the transaction tab. // If a read transaction to the XRAM for this line already exists, // or if the transaction tab is full, the fsm is stalled. // If a TRT entry is free, the READ request is registered in TRT, // it is consumed in the request FIFO, and transmited to the IXR_CMD FSM. // The READ FSM returns in the IDLE state as the read transaction will be // completed when the missing line will be received. //////////////////////////////////////////////////////////////////////////////////// switch(r_read_fsm.read()) { /////////////// case READ_IDLE: // waiting a read request { if(m_cmd_read_addr_fifo.rok()) { #if DEBUG_MEMC_READ if(m_debug_read_fsm) { std::cout << " Read request:" << " srcid = " << std::dec << m_cmd_read_srcid_fifo.read() << " / address = " << std::hex << m_cmd_read_addr_fifo.read() << " / pktid = " << std::hex << m_cmd_read_pktid_fifo.read() << " / nwords = " << std::dec << m_cmd_read_length_fifo.read() << std::endl; } #endif r_read_fsm = READ_DIR_REQ; } break; } /////////////////// case READ_DIR_REQ: // Get the lock to the directory { if(r_alloc_dir_fsm.read() == ALLOC_DIR_READ) { r_read_fsm = READ_DIR_LOCK; } #if DEBUG_MEMC_READ if(m_debug_read_fsm) { std::cout << " Requesting DIR lock " << std::endl; } #endif break; } /////////////////// case READ_DIR_LOCK: // check directory for hit / miss { if(r_alloc_dir_fsm.read() == ALLOC_DIR_READ) { size_t way = 0; DirectoryEntry entry = m_cache_directory.read(m_cmd_read_addr_fifo.read(), way); if((m_cmd_read_pktid_fifo.read() & 0x7) == TYPE_LL) // access the global table ONLY when we have an LL cmd { r_read_ll_key = m_llsc_table.ll(m_cmd_read_addr_fifo.read()); } r_read_is_cnt = entry.is_cnt; r_read_dirty = entry.dirty; r_read_lock = entry.lock; r_read_tag = entry.tag; r_read_way = way; r_read_count = entry.count; r_read_copy = entry.owner.srcid; #if L1_MULTI_CACHE r_read_copy_cache = entry.owner.cache_id; #endif r_read_copy_inst = entry.owner.inst; r_read_ptr = entry.ptr; // pointer to the heap // check if this is a cached read, this means pktid is either // TYPE_READ_DATA_MISS 0bX001 with TSAR encoding // TYPE_READ_INS_MISS 0bX011 with TSAR encoding bool cached_read = (m_cmd_read_pktid_fifo.read() & 0x1); if(entry.valid) // hit { // test if we need to register a new copy in the heap if(entry.is_cnt || (entry.count == 0) || !cached_read) { r_read_fsm = READ_DIR_HIT; } else { r_read_fsm = READ_HEAP_REQ; } } else // miss { r_read_fsm = READ_TRT_LOCK; } #if DEBUG_MEMC_READ if(m_debug_read_fsm) { std::cout << " Accessing directory: " << " address = " << std::hex << m_cmd_read_addr_fifo.read() << " / hit = " << std::dec << entry.valid << " / count = " < global_llsc_table LL access" << std::endl; } } #endif } else { std::cout << "VCI_MEM_CACHE ERROR " << name() << " READ_DIR_LOCK state" << std::endl << "Bad DIR allocation" << std::endl; exit(0); } break; } ////////////////// case READ_DIR_HIT: { // read data in cache & update the directory // we enter this state in 3 cases: // - the read request is uncachable // - the cache line is in counter mode // - the cache line is valid but not replcated if(r_alloc_dir_fsm.read() == ALLOC_DIR_READ) { // signals generation // check if this is an instruction read, this means pktid is either // TYPE_READ_INS_UNC 0bX010 with TSAR encoding // TYPE_READ_INS_MISS 0bX011 with TSAR encoding bool inst_read = ((m_cmd_read_pktid_fifo.read() & 0x2) != 0); // check if this is a cached read, this means pktid is either // TYPE_READ_DATA_MISS 0bX001 with TSAR encoding // TYPE_READ_INS_MISS 0bX011 with TSAR encoding bool cached_read = (m_cmd_read_pktid_fifo.read() & 0x1); bool is_cnt = r_read_is_cnt.read(); // read data in the cache size_t set = m_y[(vci_addr_t)(m_cmd_read_addr_fifo.read())]; size_t way = r_read_way.read(); m_cache_data.read_line(way, set, r_read_data); // update the cache directory DirectoryEntry entry; entry.valid = true; entry.is_cnt = is_cnt; entry.dirty = r_read_dirty.read(); entry.tag = r_read_tag.read(); entry.lock = r_read_lock.read(); entry.ptr = r_read_ptr.read(); if(cached_read) // Cached read => we must update the copies { if(!is_cnt) // Not counter mode { entry.owner.srcid = m_cmd_read_srcid_fifo.read(); #if L1_MULTI_CACHE entry.owner.cache_id = m_cmd_read_pktid_fifo.read(); #endif entry.owner.inst = inst_read; entry.count = r_read_count.read() + 1; } else // Counter mode { entry.owner.srcid = 0; #if L1_MULTI_CACHE entry.owner.cache_id = 0; #endif entry.owner.inst = false; entry.count = r_read_count.read() + 1; } } else // Uncached read { entry.owner.srcid = r_read_copy.read(); #if L1_MULTI_CACHE entry.owner.cache_id = r_read_copy_cache.read(); #endif entry.owner.inst = r_read_copy_inst.read(); entry.count = r_read_count.read(); } #if DEBUG_MEMC_READ if(m_debug_read_fsm) { std::cout << " Update directory entry:" << " addr = " << std::hex << m_cmd_read_addr_fifo.read() << " / set = " << std::dec << set << " / way = " << way << " / owner_id = " << entry.owner.srcid << " / owner_ins = " << entry.owner.inst << " / count = " << entry.count << " / is_cnt = " << entry.is_cnt << std::endl; } #endif /**/ if(m_monitor_ok) { char buf[80]; snprintf(buf, 80, "READ_DIR_HIT srcid %d, ins %d", m_cmd_read_srcid_fifo.read(), ((m_cmd_read_pktid_fifo.read()&0x2)!=0)); check_monitor_read(buf, m_cmd_read_addr_fifo.read()); } /**/ m_cache_directory.write(set, way, entry); r_read_fsm = READ_RSP; } break; } //////////////////// case READ_HEAP_REQ: // Get the lock to the HEAP directory { /**/ if(m_monitor_ok) { char buf[80]; snprintf(buf, 80, "READ_HEAP_REQ srcid %d, ins %d", m_cmd_read_srcid_fifo.read(), ((m_cmd_read_pktid_fifo.read()&0x2)!=0)); check_monitor_read(buf, m_cmd_read_addr_fifo.read()); } /**/ if(r_alloc_heap_fsm.read() == ALLOC_HEAP_READ) { r_read_fsm = READ_HEAP_LOCK; } #if DEBUG_MEMC_READ if(m_debug_read_fsm) { std::cout << " Requesting HEAP lock " << std::endl; } #endif break; } //////////////////// case READ_HEAP_LOCK: // read data in cache, update the directory // and prepare the HEAP update { if(r_alloc_heap_fsm.read() == ALLOC_HEAP_READ) { // enter counter mode when we reach the limit of copies or the heap is full bool go_cnt = (r_read_count.read() >= r_copies_limit.read()) || m_heap.is_full(); // read data in the cache size_t set = m_y[(vci_addr_t)(m_cmd_read_addr_fifo.read())]; size_t way = r_read_way.read(); m_cache_data.read_line(way, set, r_read_data); // update the cache directory DirectoryEntry entry; entry.valid = true; entry.is_cnt = go_cnt; entry.dirty = r_read_dirty.read(); entry.tag = r_read_tag.read(); entry.lock = r_read_lock.read(); entry.count = r_read_count.read() + 1; if(not go_cnt) // Not entering counter mode { entry.owner.srcid = r_read_copy.read(); #if L1_MULTI_CACHE entry.owner.cache_id = r_read_copy_cache.read(); #endif entry.owner.inst = r_read_copy_inst.read(); entry.ptr = m_heap.next_free_ptr(); // set pointer on the heap } else // Entering Counter mode { entry.owner.srcid = 0; #if L1_MULTI_CACHE entry.owner.cache_id = 0; #endif entry.owner.inst = false; entry.ptr = 0; } m_cache_directory.write(set, way, entry); // prepare the heap update (add an entry, or clear the linked list) if(not go_cnt) // not switching to counter mode { // We test if the next free entry in the heap is the last HeapEntry heap_entry = m_heap.next_free_entry(); r_read_next_ptr = heap_entry.next; r_read_last_free = (heap_entry.next == m_heap.next_free_ptr()); r_read_fsm = READ_HEAP_WRITE; // add an entry in the HEAP } else // switching to counter mode { if(r_read_count.read() >1) // heap must be cleared { HeapEntry next_entry = m_heap.read(r_read_ptr.read()); r_read_next_ptr = m_heap.next_free_ptr(); m_heap.write_free_ptr(r_read_ptr.read()); if(next_entry.next == r_read_ptr.read()) // last entry { r_read_fsm = READ_HEAP_LAST; // erase the entry } else // not the last entry { r_read_ptr = next_entry.next; r_read_fsm = READ_HEAP_ERASE; // erase the list } } else // the heap is not used / nothing to do { r_read_fsm = READ_RSP; } } #if DEBUG_MEMC_READ if(m_debug_read_fsm) { std::cout << " Update directory:" << " tag = " << std::hex << entry.tag << " set = " << std::dec << set << " way = " << way << " count = " << entry.count << " is_cnt = " << entry.is_cnt << std::endl; } #endif } else { std::cout << "VCI_MEM_CACHE ERROR " << name() << " READ_HEAP_LOCK state" << std::endl << "Bad HEAP allocation" << std::endl; exit(0); } break; } ///////////////////// case READ_HEAP_WRITE: // add a entry in the heap { if(r_alloc_heap_fsm.read() == ALLOC_HEAP_READ) { HeapEntry heap_entry; heap_entry.owner.srcid = m_cmd_read_srcid_fifo.read(); #if L1_MULTI_CACHE heap_entry.owner.cache_id = m_cmd_read_pktid_fifo.read(); #endif heap_entry.owner.inst = ((m_cmd_read_pktid_fifo.read() & 0x2) != 0); if(r_read_count.read() == 1) // creation of a new linked list { heap_entry.next = m_heap.next_free_ptr(); } else // head insertion in existing list { heap_entry.next = r_read_ptr.read(); } m_heap.write_free_entry(heap_entry); m_heap.write_free_ptr(r_read_next_ptr.read()); if(r_read_last_free.read()) m_heap.set_full(); r_read_fsm = READ_RSP; #if DEBUG_MEMC_READ if(m_debug_read_fsm) { std::cout << " Add an entry in the heap:" << " owner_id = " << heap_entry.owner.srcid << " owner_ins = " << heap_entry.owner.inst << std::endl; } #endif } else { std::cout << "VCI_MEM_CACHE ERROR " << name() << " READ_HEAP_WRITE state" << std::endl << "Bad HEAP allocation" << std::endl; exit(0); } break; } ///////////////////// case READ_HEAP_ERASE: { if(r_alloc_heap_fsm.read() == ALLOC_HEAP_READ) { HeapEntry next_entry = m_heap.read(r_read_ptr.read()); if(next_entry.next == r_read_ptr.read()) { r_read_fsm = READ_HEAP_LAST; } else { r_read_ptr = next_entry.next; r_read_fsm = READ_HEAP_ERASE; } } else { std::cout << "VCI_MEM_CACHE ERROR " << name() << " READ_HEAP_ERASE state" << std::endl << "Bad HEAP allocation" << std::endl; exit(0); } break; } //////////////////// case READ_HEAP_LAST: { if(r_alloc_heap_fsm.read() == ALLOC_HEAP_READ) { HeapEntry last_entry; last_entry.owner.srcid = 0; #if L1_MULTI_CACHE last_entry.owner.cache_id = 0; #endif last_entry.owner.inst = false; if(m_heap.is_full()) { last_entry.next = r_read_ptr.read(); m_heap.unset_full(); } else { last_entry.next = r_read_next_ptr.read(); } m_heap.write(r_read_ptr.read(),last_entry); r_read_fsm = READ_RSP; } else { std::cout << "VCI_MEM_CACHE ERROR " << name() << " READ_HEAP_LAST state" << std::endl; std::cout << "Bad HEAP allocation" << std::endl; exit(0); } break; } ////////////// case READ_RSP: // request the TGT_RSP FSM to return data { if(!r_read_to_tgt_rsp_req) { for(size_t i=0 ; i Request the TGT_RSP FSM to return data:" << " rsrcid = " << std::dec << m_cmd_read_srcid_fifo.read() << " / address = " << std::hex << m_cmd_read_addr_fifo.read() << " / nwords = " << std::dec << m_cmd_read_length_fifo.read() << std::endl; } #endif } break; } /////////////////// case READ_TRT_LOCK: // read miss : check the Transaction Table { if(r_alloc_trt_fsm.read() == ALLOC_TRT_READ) { size_t index = 0; vci_addr_t addr = (vci_addr_t) m_cmd_read_addr_fifo.read(); bool hit_read = m_transaction_tab.hit_read(m_nline[addr], index); bool hit_write = m_transaction_tab.hit_write(m_nline[addr]); bool wok = !m_transaction_tab.full(index); if(hit_read || !wok || hit_write) // missing line already requested or no space { if(!wok) m_cpt_trt_full++; if(hit_read || hit_write) m_cpt_trt_rb++; r_read_fsm = READ_IDLE; } else // missing line is requested to the XRAM { m_cpt_read_miss++; r_read_trt_index = index; r_read_fsm = READ_TRT_SET; } #if DEBUG_MEMC_READ if(m_debug_read_fsm) { std::cout << " Check TRT:" << " hit_read = " << hit_read << " / hit_write = " << hit_write << " / full = " << !wok << std::endl; } #endif } break; } ////////////////// case READ_TRT_SET: // register get transaction in TRT { if(r_alloc_trt_fsm.read() == ALLOC_TRT_READ) { m_transaction_tab.set(r_read_trt_index.read(), true, m_nline[(vci_addr_t)(m_cmd_read_addr_fifo.read())], m_cmd_read_srcid_fifo.read(), m_cmd_read_trdid_fifo.read(), m_cmd_read_pktid_fifo.read(), true, m_cmd_read_length_fifo.read(), m_x[(vci_addr_t)(m_cmd_read_addr_fifo.read())], std::vector (m_words,0), std::vector (m_words,0), r_read_ll_key.read()); #if DEBUG_MEMC_READ if(m_debug_read_fsm) { std::cout << " Write in Transaction Table: " << std::hex << " address = " << std::hex << m_cmd_read_addr_fifo.read() << " / srcid = " << std::dec << m_cmd_read_srcid_fifo.read() << std::endl; } #endif r_read_fsm = READ_TRT_REQ; } break; } ////////////////// case READ_TRT_REQ: { // consume the read request in the FIFO, // and send it to the ixr_cmd_fsm if(not r_read_to_ixr_cmd_req) { cmd_read_fifo_get = true; r_read_to_ixr_cmd_req = true; r_read_to_ixr_cmd_nline = m_nline[(vci_addr_t)(m_cmd_read_addr_fifo.read())]; r_read_to_ixr_cmd_trdid = r_read_trt_index.read(); r_read_fsm = READ_IDLE; #if DEBUG_MEMC_READ if(m_debug_read_fsm) { std::cout << " Request GET transaction for address " << std::hex << m_cmd_read_addr_fifo.read() << std::endl; } #endif } break; } } // end switch read_fsm /////////////////////////////////////////////////////////////////////////////////// // WRITE FSM /////////////////////////////////////////////////////////////////////////////////// // The WRITE FSM handles the write bursts and sc requests sent by the processors. // All addresses in a burst must be in the same cache line. // A complete write burst is consumed in the FIFO & copied to a local buffer. // Then the FSM takes the lock protecting the cache directory, to check // if the line is in the cache. // // - In case of HIT, the cache is updated. // If there is no other copy, an acknowledge response is immediately // returned to the writing processor. // If the data is cached by other processors, a coherence transaction must // be launched (sc requests always require a coherence transaction): // It is a multicast update if the line is not in counter mode, and the processor // takes the lock protecting the Update Table (UPT) to register this transaction. // It is a broadcast invalidate if the line is in counter mode. // If the UPT is full, it releases the lock(s) and retry. Then, it sends // a multi-update request to all owners of the line (but the writer), // through the CC_SEND FSM. In case of coherence transaction, the WRITE FSM // does not respond to the writing processor, as this response will be sent by // the MULTI_ACK FSM when all update responses have been received. // // - In case of MISS, the WRITE FSM takes the lock protecting the transaction // table (TRT). If a read transaction to the XRAM for this line already exists, // it writes in the TRT (write buffer). Otherwise, if a TRT entry is free, // the WRITE FSM register a new transaction in TRT, and sends a read line request // to the XRAM. If the TRT is full, it releases the lock, and waits. // Finally, the WRITE FSM returns an aknowledge response to the writing processor. ///////////////////////////////////////////////////////////////////////////////////// switch(r_write_fsm.read()) { //////////////// case WRITE_IDLE: // copy first word of a write burst in local buffer { if(m_cmd_write_addr_fifo.rok()) { if((m_cmd_write_pktid_fifo.read() & 0x7) == TYPE_SC) m_cpt_sc++; else { m_cpt_write++; m_cpt_write_cells++; } // consume a word in the FIFO & write it in the local buffer cmd_write_fifo_get = true; size_t index = m_x[(vci_addr_t)(m_cmd_write_addr_fifo.read())]; r_write_address = (addr_t)(m_cmd_write_addr_fifo.read()); r_write_word_index = index; r_write_word_count = 1; r_write_data[index] = m_cmd_write_data_fifo.read(); r_write_srcid = m_cmd_write_srcid_fifo.read(); r_write_trdid = m_cmd_write_trdid_fifo.read(); r_write_pktid = m_cmd_write_pktid_fifo.read(); r_write_pending_sc = false; // initialize the be field for all words for(size_t word=0 ; word Write request " << " srcid = " << std::dec << m_cmd_write_srcid_fifo.read() << " / address = " << std::hex << m_cmd_write_addr_fifo.read() << " / data = " << m_cmd_write_data_fifo.read() << std::endl; } #endif } break; } //////////////// case WRITE_NEXT: // copy next word of a write burst in local buffer { if(m_cmd_write_addr_fifo.rok()) { #if DEBUG_MEMC_WRITE if(m_debug_write_fsm) { std::cout << " Write another word in local buffer" << std::endl; } #endif m_cpt_write_cells++; // check that the next word is in the same cache line if((m_nline[(vci_addr_t)(r_write_address.read())] != m_nline[(vci_addr_t)(m_cmd_write_addr_fifo.read())])) { std::cout << "VCI_MEM_CACHE ERROR " << name() << " WRITE_NEXT state" << std::endl << "all words in a write burst must be in same cache line" << std::endl; exit(0); } // consume a word in the FIFO & write it in the local buffer cmd_write_fifo_get = true; size_t index = r_write_word_index.read() + r_write_word_count.read(); r_write_be[index] = m_cmd_write_be_fifo.read(); r_write_data[index] = m_cmd_write_data_fifo.read(); r_write_word_count = r_write_word_count.read() + 1; if(m_cmd_write_eop_fifo.read()) { r_write_fsm = WRITE_DIR_REQ; } } break; } //////////////////// case WRITE_DIR_REQ: { // Get the lock to the directory // and access the llsc_global_table if(r_alloc_dir_fsm.read() == ALLOC_DIR_WRITE) { /////////////////////////////////////////////////////////////////////// // SC command treatment // We test the r_write_pending_sc register to know if we are returning // from the WAIT state. // In this case, the SC has already succeed and we cannot consume // another time from the FIFO. Also, we don't have to test another // time if the SC has succeed if(((r_write_pktid.read() & 0x7) == TYPE_SC) and not r_write_pending_sc.read()) { if(not m_cmd_write_addr_fifo.rok()) break; assert(m_cmd_write_eop_fifo.read() && "Error in VCI_MEM_CACHE : " "invalid packet format for SC command"); size_t index = r_write_word_index.read(); bool sc_success = m_llsc_table.sc(r_write_address.read() , r_write_data[index].read()); // consume a word in the FIFO & write it in the local buffer cmd_write_fifo_get = true; r_write_data[index] = m_cmd_write_data_fifo.read(); r_write_sc_fail = not sc_success; r_write_pending_sc = true; if(not sc_success) r_write_fsm = WRITE_RSP; else r_write_fsm = WRITE_DIR_LOCK; break; } /////////////////////////////////////////////////////////////////////// // WRITE command treatment or SC command returning from the WAIT state // In the second case, we must access the LL/SC global table to // erase any possible new reservation when we release the lock on the // directory m_llsc_table.sw(r_write_address.read()); r_write_fsm = WRITE_DIR_LOCK; } #if DEBUG_MEMC_WRITE if(m_debug_write_fsm) { std::cout << " Requesting DIR lock " << std::endl; } #endif break; } //////////////////// case WRITE_DIR_LOCK: // access directory to check hit/miss { if(r_alloc_dir_fsm.read() == ALLOC_DIR_WRITE) { size_t way = 0; DirectoryEntry entry(m_cache_directory.read(r_write_address.read(), way)); if(entry.valid) // hit { // copy directory entry in local buffer in case of hit r_write_is_cnt = entry.is_cnt; r_write_lock = entry.lock; r_write_tag = entry.tag; r_write_copy = entry.owner.srcid; #if L1_MULTI_CACHE r_write_copy_cache = entry.owner.cache_id; #endif r_write_copy_inst = entry.owner.inst; r_write_count = entry.count; r_write_ptr = entry.ptr; r_write_way = way; if(entry.is_cnt && entry.count) { r_write_fsm = WRITE_DIR_READ; } else { r_write_fsm = WRITE_DIR_HIT; } } else // miss { r_write_fsm = WRITE_MISS_TRT_LOCK; } #if DEBUG_MEMC_WRITE if(m_debug_write_fsm) { std::cout << " Check the directory: " << " address = " << std::hex << r_write_address.read() << " hit = " << std::dec << entry.valid << " count = " << entry.count << " is_cnt = " << entry.is_cnt << std::endl; if((r_write_pktid.read() & 0x7) == TYPE_SC) std::cout << " global_llsc_table SC access" << std::endl; else std::cout << " global_llsc_table SW access" << std::endl; } #endif } else { std::cout << "VCI_MEM_CACHE ERROR " << name() << " WRITE_DIR_LOCK state" << std::endl << "bad DIR allocation" << std::endl; exit(0); } break; } //////////////////// case WRITE_DIR_READ: // read the cache and complete the buffer when be!=0xF { // update local buffer size_t set = m_y[(vci_addr_t)(r_write_address.read())]; size_t way = r_write_way.read(); for(size_t word=0 ; word Read the cache to complete local buffer" << std::endl; } #endif break; } /////////////////// case WRITE_DIR_HIT: { // update the cache directory // update directory with Dirty bit DirectoryEntry entry; entry.valid = true; entry.dirty = true; entry.tag = r_write_tag.read(); entry.is_cnt = r_write_is_cnt.read(); entry.lock = r_write_lock.read(); entry.owner.srcid = r_write_copy.read(); #if L1_MULTI_CACHE entry.owner.cache_id = r_write_copy_cache.read(); #endif entry.owner.inst = r_write_copy_inst.read(); entry.count = r_write_count.read(); entry.ptr = r_write_ptr.read(); size_t set = m_y[(vci_addr_t)(r_write_address.read())]; size_t way = r_write_way.read(); // update directory m_cache_directory.write(set, way, entry); // owner is true when the the first registered copy is the writer itself bool owner = (((r_write_copy.read() == r_write_srcid.read()) #if L1_MULTI_CACHE and(r_write_copy_cache.read() ==r_write_pktid.read()) #endif ) and not r_write_copy_inst.read()); // no_update is true when there is no need for coherence transaction // (tests for sc requests) bool no_update = ((r_write_count.read() ==0) || (owner && (r_write_count.read() ==1) && (r_write_pktid.read() != TYPE_SC))); // write data in the cache if no coherence transaction if(no_update) { for(size_t word=0 ; word Write into cache / No coherence transaction" << std::endl; } else { std::cout << " Coherence update required:" << " is_cnt = " << r_write_is_cnt.read() << " nb_copies = " << std::dec << r_write_count.read() << std::endl; if(owner) std::cout << " ... but the first copy is the writer" << std::endl; } } #endif break; } //////////////////// case WRITE_UPT_LOCK: // Try to register the update request in UPT { if(r_alloc_upt_fsm.read() == ALLOC_UPT_WRITE) { bool wok = false; size_t index = 0; size_t srcid = r_write_srcid.read(); size_t trdid = r_write_trdid.read(); size_t pktid = r_write_pktid.read(); addr_t nline = m_nline[(vci_addr_t)(r_write_address.read())]; size_t nb_copies = r_write_count.read(); size_t set = m_y[(vci_addr_t)(r_write_address.read())]; size_t way = r_write_way.read(); wok = m_update_tab.set(true, // it's an update transaction false, // it's not a broadcast true, // it needs a response srcid, trdid, pktid, nline, nb_copies, index); if(wok) // write data in cache { for(size_t word=0 ; word Register the multicast update in UPT / " << " nb_copies = " << r_write_count.read() << std::endl; } } #endif r_write_upt_index = index; // releases the lock protecting UPT and the DIR if no entry... if(wok) r_write_fsm = WRITE_UPT_HEAP_LOCK; else r_write_fsm = WRITE_WAIT; } break; } ///////////////////////// case WRITE_UPT_HEAP_LOCK: // get access to heap { if(r_alloc_heap_fsm.read() == ALLOC_HEAP_WRITE) { #if DEBUG_MEMC_WRITE if(m_debug_write_fsm) { std::cout << " Get acces to the HEAP" << std::endl; } #endif r_write_fsm = WRITE_UPT_REQ; } break; } ////////////////// case WRITE_UPT_REQ: { // prepare the coherence transaction for the CC_SEND FSM // and write the first copy in the FIFO // send the request if only one copy if(!r_write_to_cc_send_multi_req.read() && !r_write_to_cc_send_brdcast_req.read()) // no pending coherence request { r_write_to_cc_send_brdcast_req = false; r_write_to_cc_send_trdid = r_write_upt_index.read(); r_write_to_cc_send_nline = m_nline[(vci_addr_t)(r_write_address.read())]; r_write_to_cc_send_index = r_write_word_index.read(); r_write_to_cc_send_count = r_write_word_count.read(); for(size_t i=0; i Post first request to CC_SEND FSM" << " / srcid = " << std::dec << r_write_copy.read() << " / inst = " << std::dec << r_write_copy_inst.read() << std::endl; if(r_write_count.read() == 1) std::cout << " ... and this is the last" << std::endl; } #endif } break; } /////////////////// case WRITE_UPT_NEXT: { // continue the multi-update request to CC_SEND fsm // when there is copies in the heap. // if one copy in the heap is the writer itself // the corresponding SRCID should not be written in the fifo, // but the UPT counter must be decremented. // As this decrement is done in the WRITE_UPT_DEC state, // after the last copy has been found, the decrement request // must be registered in the r_write_to_dec flip-flop. HeapEntry entry = m_heap.read(r_write_ptr.read()); bool dec_upt_counter; if(((entry.owner.srcid != r_write_srcid.read()) || (r_write_pktid.read() == TYPE_SC)) or #if L1_MULTI_CACHE (entry.owner.cache_id != r_write_pktid.read()) or #endif entry.owner.inst) // put the next srcid in the fifo { dec_upt_counter = false; write_to_cc_send_fifo_put = true; write_to_cc_send_fifo_inst = entry.owner.inst; write_to_cc_send_fifo_srcid = entry.owner.srcid; #if L1_MULTI_CACHE write_to_cc_send_fifo_cache_id = entry.owner.cache_id; #endif #if DEBUG_MEMC_WRITE if(m_debug_write_fsm) { std::cout << " Post another request to CC_SEND FSM" << " / heap_index = " << std::dec << r_write_ptr.read() << " / srcid = " << std::dec << r_write_copy.read() << " / inst = " << std::dec << r_write_copy_inst.read() << std::endl; if(entry.next == r_write_ptr.read()) std::cout << " ... and this is the last" << std::endl; } #endif } else // the UPT counter must be decremented { dec_upt_counter = true; #if DEBUG_MEMC_WRITE if(m_debug_write_fsm) { std::cout << " Skip one entry in heap matching the writer" << " / heap_index = " << std::dec << r_write_ptr.read() << " / srcid = " << std::dec << r_write_copy.read() << " / inst = " << std::dec << r_write_copy_inst.read() << std::endl; if(entry.next == r_write_ptr.read()) std::cout << " ... and this is the last" << std::endl; } #endif } // register the possible UPT decrement request r_write_to_dec = dec_upt_counter or r_write_to_dec.read(); if(not m_write_to_cc_send_inst_fifo.wok()) { std::cout << "VCI_MEM_CACHE ERROR " << name() << " WRITE_UPT_NEXT state" << std::endl << "The write_to_cc_send_fifo should not be full" << std::endl << "as the depth should be larger than the max number of copies" << std::endl; exit(0); } r_write_ptr = entry.next; if(entry.next == r_write_ptr.read()) // last copy { r_write_to_cc_send_multi_req = true; if(r_write_to_dec.read() or dec_upt_counter) r_write_fsm = WRITE_UPT_DEC; else r_write_fsm = WRITE_IDLE; } break; } ////////////////// case WRITE_UPT_DEC: { // If the initial writer has a copy, it should not // receive an update request, but the counter in the // update table must be decremented by the MULTI_ACK FSM. if(!r_write_to_multi_ack_req.read()) { r_write_to_multi_ack_req = true; r_write_to_multi_ack_upt_index = r_write_upt_index.read(); r_write_fsm = WRITE_IDLE; } break; } /////////////// case WRITE_RSP: { // Post a request to TGT_RSP FSM to acknowledge the write // In order to increase the Write requests throughput, // we don't wait to return in the IDLE state to consume // a new request in the write FIFO if(!r_write_to_tgt_rsp_req.read()) { // post the request to TGT_RSP_FSM r_write_to_tgt_rsp_req = true; r_write_to_tgt_rsp_srcid = r_write_srcid.read(); r_write_to_tgt_rsp_trdid = r_write_trdid.read(); r_write_to_tgt_rsp_pktid = r_write_pktid.read(); r_write_to_tgt_rsp_sc_fail = r_write_sc_fail.read(); // try to get a new write request from the FIFO if(m_cmd_write_addr_fifo.rok()) { if((m_cmd_write_pktid_fifo.read() & 0x7) == TYPE_SC) m_cpt_sc++; else { m_cpt_write++; m_cpt_write_cells++; } // consume a word in the FIFO & write it in the local buffer cmd_write_fifo_get = true; size_t index = m_x[(vci_addr_t)(m_cmd_write_addr_fifo.read())]; r_write_address = (addr_t)(m_cmd_write_addr_fifo.read()); r_write_word_index = index; r_write_word_count = 1; r_write_data[index] = m_cmd_write_data_fifo.read(); r_write_srcid = m_cmd_write_srcid_fifo.read(); r_write_trdid = m_cmd_write_trdid_fifo.read(); r_write_pktid = m_cmd_write_pktid_fifo.read(); r_write_pending_sc = false; // initialize the be field for all words for(size_t word=0 ; word Post a request to TGT_RSP FSM: rsrcid = " << std::dec << r_write_srcid.read() << std::endl; if(m_cmd_write_addr_fifo.rok()) { std::cout << " New Write request: " << " srcid = " << std::dec << m_cmd_write_srcid_fifo.read() << " / address = " << std::hex << m_cmd_write_addr_fifo.read() << " / data = " << m_cmd_write_data_fifo.read() << std::endl; } } #endif } break; } ///////////////////////// case WRITE_MISS_TRT_LOCK: // Miss : check Transaction Table { if(r_alloc_trt_fsm.read() == ALLOC_TRT_WRITE) { #if DEBUG_MEMC_WRITE if(m_debug_write_fsm) { std::cout << " Check the TRT" << std::endl; } #endif size_t hit_index = 0; size_t wok_index = 0; vci_addr_t addr = (vci_addr_t) r_write_address.read(); bool hit_read = m_transaction_tab.hit_read(m_nline[addr], hit_index); bool hit_write = m_transaction_tab.hit_write(m_nline[addr]); bool wok = !m_transaction_tab.full(wok_index); if(hit_read) // register the modified data in TRT { r_write_trt_index = hit_index; r_write_fsm = WRITE_MISS_TRT_DATA; m_cpt_write_miss++; } else if(wok && !hit_write) // set a new entry in TRT { r_write_trt_index = wok_index; r_write_fsm = WRITE_MISS_TRT_SET; m_cpt_write_miss++; } else // wait an empty entry in TRT { r_write_fsm = WRITE_WAIT; m_cpt_trt_full++; } } break; } //////////////// case WRITE_WAIT: // release the locks protecting the shared ressources { #if DEBUG_MEMC_WRITE if(m_debug_write_fsm) { std::cout << " Releases the locks before retry" << std::endl; } #endif r_write_fsm = WRITE_DIR_REQ; break; } //////////////////////// case WRITE_MISS_TRT_SET: // register a new transaction in TRT (Write Buffer) { if(r_alloc_trt_fsm.read() == ALLOC_TRT_WRITE) { std::vector be_vector; std::vector data_vector; be_vector.clear(); data_vector.clear(); for(size_t i=0; i Set a new entry in TRT" << std::endl; } #endif } break; } ///////////////////////// case WRITE_MISS_TRT_DATA: // update an entry in TRT (used as a Write Buffer) { if(r_alloc_trt_fsm.read() == ALLOC_TRT_WRITE) { std::vector be_vector; std::vector data_vector; be_vector.clear(); data_vector.clear(); for(size_t i=0; i Modify an existing entry in TRT" << std::endl; m_transaction_tab.print(r_write_trt_index.read()); } #endif } break; } ///////////////////////// case WRITE_MISS_XRAM_REQ: // send a GET request to IXR_CMD FSM { if(!r_write_to_ixr_cmd_req) { r_write_to_ixr_cmd_req = true; r_write_to_ixr_cmd_write = false; r_write_to_ixr_cmd_nline = m_nline[(vci_addr_t)(r_write_address.read())]; r_write_to_ixr_cmd_trdid = r_write_trt_index.read(); r_write_fsm = WRITE_RSP; #if DEBUG_MEMC_WRITE if(m_debug_write_fsm) { std::cout << " Post a GET request to the IXR_CMD FSM" << std::endl; } #endif } break; } /////////////////////// case WRITE_BC_TRT_LOCK: // Check TRT not full { if(r_alloc_trt_fsm.read() == ALLOC_TRT_WRITE) { size_t wok_index = 0; bool wok = !m_transaction_tab.full(wok_index); if(wok) // set a new entry in TRT { r_write_trt_index = wok_index; r_write_fsm = WRITE_BC_UPT_LOCK; } else // wait an empty entry in TRT { r_write_fsm = WRITE_WAIT; } #if DEBUG_MEMC_WRITE if(m_debug_write_fsm) { std::cout << " Check TRT : wok = " << wok << " / index = " << wok_index << std::endl; } #endif } break; } ////////////////////// case WRITE_BC_UPT_LOCK: // register BC transaction in UPT { if(r_alloc_upt_fsm.read() == ALLOC_UPT_WRITE) { bool wok = false; size_t index = 0; size_t srcid = r_write_srcid.read(); size_t trdid = r_write_trdid.read(); size_t pktid = r_write_pktid.read(); addr_t nline = m_nline[(vci_addr_t)(r_write_address.read())]; size_t nb_copies = r_write_count.read(); wok =m_update_tab.set(false, // it's an inval transaction true, // it's a broadcast true, // it needs a response srcid, trdid, pktid, nline, nb_copies, index); #if DEBUG_MEMC_WRITE if(m_debug_write_fsm) { if(wok) { std::cout << " Register the broadcast inval in UPT / " << " nb_copies = " << r_write_count.read() << std::endl; } } #endif r_write_upt_index = index; if(wok) r_write_fsm = WRITE_BC_DIR_INVAL; else r_write_fsm = WRITE_WAIT; } break; } //////////////////////// case WRITE_BC_DIR_INVAL: { // Register a put transaction to XRAM in TRT // and invalidate the line in directory if((r_alloc_trt_fsm.read() != ALLOC_TRT_WRITE) || (r_alloc_upt_fsm.read() != ALLOC_UPT_WRITE) || (r_alloc_dir_fsm.read() != ALLOC_DIR_WRITE)) { std::cout << "VCI_MEM_CACHE ERROR " << name() << " WRITE_BC_DIR_INVAL state" << std::endl; std::cout << "bad TRT, DIR, or UPT allocation" << std::endl; exit(0); } // register a write request to XRAM in TRT m_transaction_tab.set(r_write_trt_index.read(), false, // write request to XRAM m_nline[(vci_addr_t)(r_write_address.read())], 0, 0, 0, false, // not a processor read 0, // not a single word 0, // word index std::vector (m_words,0), std::vector (m_words,0)); // invalidate directory entry DirectoryEntry entry; entry.valid = false; entry.dirty = false; entry.tag = 0; entry.is_cnt = false; entry.lock = false; entry.owner.srcid = 0; #if L1_MULTI_CACHE entry.owner.cache_id= 0; #endif entry.owner.inst = false; entry.ptr = 0; entry.count = 0; size_t set = m_y[(vci_addr_t)(r_write_address.read())]; size_t way = r_write_way.read(); m_cache_directory.write(set, way, entry); #if DEBUG_MEMC_WRITE if(m_debug_write_fsm) { std::cout << " Invalidate the directory entry: @ = " << r_write_address.read() << " / register the put transaction in TRT:" << std::endl; } #endif r_write_fsm = WRITE_BC_CC_SEND; break; } ////////////////////// case WRITE_BC_CC_SEND: // Post a coherence broadcast request to CC_SEND FSM { if(!r_write_to_cc_send_multi_req.read() && !r_write_to_cc_send_brdcast_req.read()) { r_write_to_cc_send_multi_req = false; r_write_to_cc_send_brdcast_req = true; r_write_to_cc_send_trdid = r_write_upt_index.read(); r_write_to_cc_send_nline = m_nline[(vci_addr_t)(r_write_address.read())]; r_write_to_cc_send_index = 0; r_write_to_cc_send_count = 0; for(size_t i=0; i Post a broadcast request to CC_SEND FSM" << std::endl; } #endif } break; } /////////////////////// case WRITE_BC_XRAM_REQ: // Post a put request to IXR_CMD FSM { if(!r_write_to_ixr_cmd_req) { r_write_to_ixr_cmd_req = true; r_write_to_ixr_cmd_write = true; r_write_to_ixr_cmd_nline = m_nline[(vci_addr_t)(r_write_address.read())]; r_write_to_ixr_cmd_trdid = r_write_trt_index.read(); for(size_t i=0; i Post a put request to IXR_CMD FSM" << std::endl; } #endif } break; } } // end switch r_write_fsm /////////////////////////////////////////////////////////////////////// // IXR_CMD FSM /////////////////////////////////////////////////////////////////////// // The IXR_CMD fsm controls the command packets to the XRAM : // - It sends a single cell VCI read request to the XRAM in case of MISS // posted by the READ, WRITE or CAS FSMs : the TRDID field contains // the Transaction Tab index. // The VCI response is a multi-cell packet : the N cells contain // the N data words. // - It sends a multi-cell VCI write when the XRAM_RSP FSM, WRITE FSM // or CAS FSM request to save a dirty line to the XRAM. // The VCI response is a single cell packet. // This FSM handles requests from the READ, WRITE, CAS & XRAM_RSP FSMs // with a round-robin priority. //////////////////////////////////////////////////////////////////////// switch(r_ixr_cmd_fsm.read()) { //////////////////////// case IXR_CMD_READ_IDLE: if(r_write_to_ixr_cmd_req) r_ixr_cmd_fsm = IXR_CMD_WRITE_NLINE; else if(r_cas_to_ixr_cmd_req) r_ixr_cmd_fsm = IXR_CMD_CAS_NLINE; else if(r_xram_rsp_to_ixr_cmd_req) r_ixr_cmd_fsm = IXR_CMD_XRAM_DATA; else if(r_read_to_ixr_cmd_req) r_ixr_cmd_fsm = IXR_CMD_READ_NLINE; break; //////////////////////// case IXR_CMD_WRITE_IDLE: if(r_cas_to_ixr_cmd_req) r_ixr_cmd_fsm = IXR_CMD_CAS_NLINE; else if(r_xram_rsp_to_ixr_cmd_req) r_ixr_cmd_fsm = IXR_CMD_XRAM_DATA; else if(r_read_to_ixr_cmd_req) r_ixr_cmd_fsm = IXR_CMD_READ_NLINE; else if(r_write_to_ixr_cmd_req) r_ixr_cmd_fsm = IXR_CMD_WRITE_NLINE; break; //////////////////////// case IXR_CMD_CAS_IDLE: if(r_xram_rsp_to_ixr_cmd_req) r_ixr_cmd_fsm = IXR_CMD_XRAM_DATA; else if(r_read_to_ixr_cmd_req) r_ixr_cmd_fsm = IXR_CMD_READ_NLINE; else if(r_write_to_ixr_cmd_req) r_ixr_cmd_fsm = IXR_CMD_WRITE_NLINE; else if(r_cas_to_ixr_cmd_req) r_ixr_cmd_fsm = IXR_CMD_CAS_NLINE; break; //////////////////////// case IXR_CMD_XRAM_IDLE: if(r_read_to_ixr_cmd_req) r_ixr_cmd_fsm = IXR_CMD_READ_NLINE; else if(r_write_to_ixr_cmd_req) r_ixr_cmd_fsm = IXR_CMD_WRITE_NLINE; else if(r_cas_to_ixr_cmd_req) r_ixr_cmd_fsm = IXR_CMD_CAS_NLINE; else if(r_xram_rsp_to_ixr_cmd_req) r_ixr_cmd_fsm = IXR_CMD_XRAM_DATA; break; ///////////////////////// // send a get request to XRAM case IXR_CMD_READ_NLINE: if(p_vci_ixr.cmdack) { r_ixr_cmd_fsm = IXR_CMD_READ_IDLE; r_read_to_ixr_cmd_req = false; #if DEBUG_MEMC_IXR_CMD if(m_debug_ixr_cmd_fsm) { std::cout << " Send a get request to xram" << std::endl; } #endif } break; ////////////////////////// case IXR_CMD_WRITE_NLINE: // send a put or get command to XRAM if(p_vci_ixr.cmdack) { if(r_write_to_ixr_cmd_write.read()) { if(r_ixr_cmd_cpt.read() == (m_words - 1)) { r_ixr_cmd_cpt = 0; r_ixr_cmd_fsm = IXR_CMD_WRITE_IDLE; r_write_to_ixr_cmd_req = false; } else { r_ixr_cmd_cpt = r_ixr_cmd_cpt + 1; } #if DEBUG_MEMC_IXR_CMD if(m_debug_ixr_cmd_fsm) { std::cout << " Send a put request to xram" << std::endl; } #endif } else { r_ixr_cmd_fsm = IXR_CMD_WRITE_IDLE; r_write_to_ixr_cmd_req = false; #if DEBUG_MEMC_IXR_CMD if(m_debug_ixr_cmd_fsm) { std::cout << " Send a get request to xram" << std::endl; } #endif } } break; ////////////////////// case IXR_CMD_CAS_NLINE: // send a put or get command to XRAM if(p_vci_ixr.cmdack) { if(r_cas_to_ixr_cmd_write.read()) { if(r_ixr_cmd_cpt.read() == (m_words - 1)) { r_ixr_cmd_cpt = 0; r_ixr_cmd_fsm = IXR_CMD_CAS_IDLE; r_cas_to_ixr_cmd_req = false; } else { r_ixr_cmd_cpt = r_ixr_cmd_cpt + 1; } #if DEBUG_MEMC_IXR_CMD if(m_debug_ixr_cmd_fsm) { std::cout << " Send a put request to xram" << std::endl; } #endif } else { r_ixr_cmd_fsm = IXR_CMD_CAS_IDLE; r_cas_to_ixr_cmd_req = false; #if DEBUG_MEMC_IXR_CMD if(m_debug_ixr_cmd_fsm) { std::cout << " Send a get request to xram" << std::endl; } #endif } } break; //////////////////////// case IXR_CMD_XRAM_DATA: // send a put command to XRAM if(p_vci_ixr.cmdack) { if(r_ixr_cmd_cpt.read() == (m_words - 1)) { r_ixr_cmd_cpt = 0; r_ixr_cmd_fsm = IXR_CMD_XRAM_IDLE; r_xram_rsp_to_ixr_cmd_req = false; } else { r_ixr_cmd_cpt = r_ixr_cmd_cpt + 1; } #if DEBUG_MEMC_IXR_CMD if(m_debug_ixr_cmd_fsm) { std::cout << " Send a put request to xram" << std::endl; } #endif } break; } // end switch r_ixr_cmd_fsm //////////////////////////////////////////////////////////////////////////// // IXR_RSP FSM //////////////////////////////////////////////////////////////////////////// // The IXR_RSP FSM receives the response packets from the XRAM, // for both put transaction, and get transaction. // // - A response to a put request is a single-cell VCI packet. // The Transaction Tab index is contained in the RTRDID field. // The FSM takes the lock protecting the TRT, and the corresponding // entry is erased. // // - A response to a get request is a multi-cell VCI packet. // The Transaction Tab index is contained in the RTRDID field. // The N cells contain the N words of the cache line in the RDATA field. // The FSM takes the lock protecting the TRT to store the line in the TRT // (taking into account the write requests already stored in the TRT). // When the line is completely written, the corresponding rok signal is set. /////////////////////////////////////////////////////////////////////////////// switch(r_ixr_rsp_fsm.read()) { ////////////////// case IXR_RSP_IDLE: // test if it's a get or a put transaction { if(p_vci_ixr.rspval.read()) { r_ixr_rsp_cpt = 0; r_ixr_rsp_trt_index = p_vci_ixr.rtrdid.read(); if(p_vci_ixr.reop.read() && !(p_vci_ixr.rerror.read() &0x1)) // put transaction { r_ixr_rsp_fsm = IXR_RSP_ACK; #if DEBUG_MEMC_IXR_RSP if(m_debug_ixr_rsp_fsm) { std::cout << " Response from XRAM to a put transaction" << std::endl; } #endif } else // get transaction { r_ixr_rsp_fsm = IXR_RSP_TRT_READ; #if DEBUG_MEMC_IXR_RSP if(m_debug_ixr_rsp_fsm) { std::cout << " Response from XRAM to a get transaction" << std::endl; } #endif } } break; } //////////////////////// case IXR_RSP_ACK: // Aknowledge the VCI response { if(p_vci_ixr.rspval.read()) r_ixr_rsp_fsm = IXR_RSP_TRT_ERASE; #if DEBUG_MEMC_IXR_RSP if(m_debug_ixr_rsp_fsm) { std::cout << " " << std::endl; } #endif break; } //////////////////////// case IXR_RSP_TRT_ERASE: // erase the entry in the TRT { if(r_alloc_trt_fsm.read() == ALLOC_TRT_IXR_RSP) { m_transaction_tab.erase(r_ixr_rsp_trt_index.read()); r_ixr_rsp_fsm = IXR_RSP_IDLE; #if DEBUG_MEMC_IXR_RSP if(m_debug_ixr_rsp_fsm) { std::cout << " Erase TRT entry " << r_ixr_rsp_trt_index.read() << std::endl; } #endif } break; } /////////////////////// case IXR_RSP_TRT_READ: // write data in the TRT { if((r_alloc_trt_fsm.read() == ALLOC_TRT_IXR_RSP) && p_vci_ixr.rspval) { size_t index = r_ixr_rsp_trt_index.read(); bool eop = p_vci_ixr.reop.read(); data_t data = p_vci_ixr.rdata.read(); bool error = ((p_vci_ixr.rerror.read() & 0x1) == 1); assert(((eop == (r_ixr_rsp_cpt.read() == (m_words-1))) || p_vci_ixr.rerror.read()) and "Error in VCI_MEM_CACHE : invalid length for a response from XRAM"); m_transaction_tab.write_rsp(index, r_ixr_rsp_cpt.read(), data, error); r_ixr_rsp_cpt = r_ixr_rsp_cpt.read() + 1; if(eop) { r_ixr_rsp_to_xram_rsp_rok[r_ixr_rsp_trt_index.read()]=true; r_ixr_rsp_fsm = IXR_RSP_IDLE; } #if DEBUG_MEMC_IXR_RSP if(m_debug_ixr_rsp_fsm) { std::cout << " Writing a word in TRT : " << " index = " << std::dec << index << " / word = " << r_ixr_rsp_cpt.read() << " / data = " << std::hex << data << std::endl; } #endif } break; } } // end swich r_ixr_rsp_fsm //////////////////////////////////////////////////////////////////////////// // XRAM_RSP FSM //////////////////////////////////////////////////////////////////////////// // The XRAM_RSP FSM handles the incoming cache lines from the XRAM. // The cache line has been written in the TRT by the IXR_CMD_FSM. // As the IXR_RSP FSM and the XRAM_RSP FSM are running in parallel, // there is as many flip-flops r_ixr_rsp_to_xram_rsp_rok[i] // as the number of entries in the TRT, that are handled with // a round-robin priority... // // When a response is available, the corresponding TRT entry // must be copied in a local buffer to be written in the cache. // The FSM takes the lock protecting the TRT, and the lock protecting the DIR. // It selects a cache slot and writes the line in the cache. // If it was a read MISS, the XRAM_RSP FSM send a request to the TGT_RSP // FSM to return the cache line to the registered processor. // If there is no empty slot, a victim line is evicted, and // invalidate requests are sent to the L1 caches containing copies. // If this line is dirty, the XRAM_RSP FSM send a request to the IXR_CMD // FSM to save the victim line to the XRAM, and register the write transaction // in the TRT (using the entry previously used by the read transaction). /////////////////////////////////////////////////////////////////////////////// switch(r_xram_rsp_fsm.read()) { /////////////////// case XRAM_RSP_IDLE: // scan the XRAM responses to get the TRT index (round robin) { size_t ptr = r_xram_rsp_trt_index.read(); size_t lines = m_transaction_tab_lines; for(size_t i=0 ; i Available cache line in TRT:" << " index = " << std::dec << index << std::endl; } #endif break; } } break; } /////////////////////// case XRAM_RSP_DIR_LOCK: // Takes the lock on the directory // Takes the lock on TRT // Copy the TRT entry in a local buffer { if((r_alloc_dir_fsm.read() == ALLOC_DIR_XRAM_RSP) && (r_alloc_trt_fsm.read() == ALLOC_TRT_XRAM_RSP)) { // copy the TRT entry in the r_xram_rsp_trt_buf local buffer size_t index = r_xram_rsp_trt_index.read(); TransactionTabEntry trt_entry(m_transaction_tab.read(index)); r_xram_rsp_trt_buf.copy(trt_entry); // TRT entry local buffer r_xram_rsp_fsm = XRAM_RSP_TRT_COPY; #if DEBUG_MEMC_XRAM_RSP if(m_debug_xram_rsp_fsm) { std::cout << " Get access to directory" << std::endl; } #endif } break; } /////////////////////// case XRAM_RSP_TRT_COPY: // Select a victim cache line { if((r_alloc_trt_fsm.read() == ALLOC_TRT_XRAM_RSP)) { // selects & extracts a victim line from cache size_t way = 0; size_t set = m_y[(vci_addr_t)(r_xram_rsp_trt_buf.nline * m_words * 4)]; DirectoryEntry victim(m_cache_directory.select(set, way)); bool inval = (victim.count && victim.valid) ; // copy the victim line in a local buffer m_cache_data.read_line(way, set, r_xram_rsp_victim_data); r_xram_rsp_victim_copy = victim.owner.srcid; #if L1_MULTI_CACHE r_xram_rsp_victim_copy_cache= victim.owner.cache_id; #endif r_xram_rsp_victim_copy_inst = victim.owner.inst; r_xram_rsp_victim_count = victim.count; r_xram_rsp_victim_ptr = victim.ptr; r_xram_rsp_victim_way = way; r_xram_rsp_victim_set = set; r_xram_rsp_victim_nline = victim.tag*m_sets + set; r_xram_rsp_victim_is_cnt = victim.is_cnt; r_xram_rsp_victim_inval = inval ; r_xram_rsp_victim_dirty = victim.dirty; if(!r_xram_rsp_trt_buf.rerror) { r_xram_rsp_fsm = XRAM_RSP_INVAL_LOCK; } else { r_xram_rsp_fsm = XRAM_RSP_ERROR_ERASE; } #if DEBUG_MEMC_XRAM_RSP if(m_debug_xram_rsp_fsm) { std::cout << " Select a slot: " << " way = " << std::dec << way << " / set = " << set << " / inval_required = " << inval << std::endl; } #endif } else { std::cout << "VCI_MEM_CACHE ERROR " << name() << " XRAM_RSP_TRT_COPY state" << std::endl << "bad TRT allocation" << std::endl; exit(0); } break; } ///////////////////////// case XRAM_RSP_INVAL_LOCK: // check a possible pending inval { if(r_alloc_upt_fsm == ALLOC_UPT_XRAM_RSP) { size_t index; if(m_update_tab.search_inval(r_xram_rsp_trt_buf.nline, index)) { r_xram_rsp_fsm = XRAM_RSP_INVAL_WAIT; #if DEBUG_MEMC_XRAM_RSP if(m_debug_xram_rsp_fsm) { std::cout << " Get acces to UPT," << " but an invalidation is already registered at this address" << std::endl; m_update_tab.print(); } #endif } else if(m_update_tab.is_full() && r_xram_rsp_victim_inval.read()) { r_xram_rsp_fsm = XRAM_RSP_INVAL_WAIT; #if DEBUG_MEMC_XRAM_RSP if(m_debug_xram_rsp_fsm) { std::cout << " Get acces to UPT," << " but the table is full" << std::endl; m_update_tab.print(); } #endif } else { r_xram_rsp_fsm = XRAM_RSP_DIR_UPDT; #if DEBUG_MEMC_XRAM_RSP if(m_debug_xram_rsp_fsm) { std::cout << " Get acces to UPT" << std::endl; } #endif } } break; } ///////////////////////// case XRAM_RSP_INVAL_WAIT: // returns to DIR_LOCK to retry { r_xram_rsp_fsm = XRAM_RSP_DIR_LOCK; break; } /////////////////////// case XRAM_RSP_DIR_UPDT: // updates the cache (both data & directory) // and possibly set an inval request in UPT { // signals generation // check if this is an instruction read, this means pktid is either // TYPE_READ_INS_UNC 0bX010 with TSAR encoding // TYPE_READ_INS_MISS 0bX011 with TSAR encoding bool inst_read = (r_xram_rsp_trt_buf.pktid & 0x2) && r_xram_rsp_trt_buf.proc_read; // check if this is a cached read, this means pktid is either // TYPE_READ_DATA_MISS 0bX001 with TSAR encoding // TYPE_READ_INS_MISS 0bX011 with TSAR encoding bool cached_read = (r_xram_rsp_trt_buf.pktid & 0x1) && r_xram_rsp_trt_buf.proc_read; // update data size_t set = r_xram_rsp_victim_set.read(); size_t way = r_xram_rsp_victim_way.read(); for(size_t word=0; word Directory update: " << " way = " << std::dec << way << " / set = " << set << " / owner_id = " << entry.owner.srcid << " / owner_ins = " << entry.owner.inst << " / count = " << entry.count << " / is_cnt = " << entry.is_cnt << std::endl; if(r_xram_rsp_victim_inval.read()) std::cout << " Invalidation request for victim line " << std::hex << r_xram_rsp_victim_nline.read() << " / broadcast = " << r_xram_rsp_victim_is_cnt.read() << std::endl; } #endif // If the victim is not dirty, we don't need another XRAM put transaction, // and we canwe erase the TRT entry if(!r_xram_rsp_victim_dirty.read()) m_transaction_tab.erase(r_xram_rsp_trt_index.read()); // Next state if(r_xram_rsp_victim_dirty.read()) r_xram_rsp_fsm = XRAM_RSP_TRT_DIRTY; else if(r_xram_rsp_trt_buf.proc_read) r_xram_rsp_fsm = XRAM_RSP_DIR_RSP; else if(r_xram_rsp_victim_inval.read()) r_xram_rsp_fsm = XRAM_RSP_INVAL; else r_xram_rsp_fsm = XRAM_RSP_IDLE; break; } //////////////////////// case XRAM_RSP_TRT_DIRTY: // set the TRT entry (write to XRAM) if the victim is dirty { if(r_alloc_trt_fsm.read() == ALLOC_TRT_XRAM_RSP) { m_transaction_tab.set(r_xram_rsp_trt_index.read(), false, // write to XRAM r_xram_rsp_victim_nline.read(), // line index 0, 0, 0, false, 0, 0, std::vector (m_words,0), std::vector (m_words,0)); #if DEBUG_MEMC_XRAM_RSP if(m_debug_xram_rsp_fsm) { std::cout << " Set TRT entry for the put transaction:" << " dirty victim line = " << r_xram_rsp_victim_nline.read() << std::endl; } #endif if(r_xram_rsp_trt_buf.proc_read) r_xram_rsp_fsm = XRAM_RSP_DIR_RSP; else if(r_xram_rsp_victim_inval.read()) r_xram_rsp_fsm = XRAM_RSP_INVAL; else r_xram_rsp_fsm = XRAM_RSP_WRITE_DIRTY; } break; } ////////////////////// case XRAM_RSP_DIR_RSP: // Request a response to TGT_RSP FSM { if(!r_xram_rsp_to_tgt_rsp_req.read()) { r_xram_rsp_to_tgt_rsp_srcid = r_xram_rsp_trt_buf.srcid; r_xram_rsp_to_tgt_rsp_trdid = r_xram_rsp_trt_buf.trdid; r_xram_rsp_to_tgt_rsp_pktid = r_xram_rsp_trt_buf.pktid; for(size_t i=0; i < m_words; i++) r_xram_rsp_to_tgt_rsp_data[i] = r_xram_rsp_trt_buf.wdata[i]; r_xram_rsp_to_tgt_rsp_word = r_xram_rsp_trt_buf.word_index; r_xram_rsp_to_tgt_rsp_length = r_xram_rsp_trt_buf.read_length; r_xram_rsp_to_tgt_rsp_ll_key = r_xram_rsp_trt_buf.ll_key; r_xram_rsp_to_tgt_rsp_rerror = false; r_xram_rsp_to_tgt_rsp_req = true; if(r_xram_rsp_victim_inval) r_xram_rsp_fsm = XRAM_RSP_INVAL; else if(r_xram_rsp_victim_dirty) r_xram_rsp_fsm = XRAM_RSP_WRITE_DIRTY; else r_xram_rsp_fsm = XRAM_RSP_IDLE; #if DEBUG_MEMC_XRAM_RSP if(m_debug_xram_rsp_fsm) { std::cout << " Request the TGT_RSP FSM to return data:" << " rsrcid = " << std::dec << r_xram_rsp_trt_buf.srcid << " / address = " << std::hex << r_xram_rsp_trt_buf.nline*m_words*4 << " / nwords = " << std::dec << r_xram_rsp_trt_buf.read_length << std::endl; } #endif } break; } //////////////////// case XRAM_RSP_INVAL: // send invalidate request to CC_SEND FSM { if(!r_xram_rsp_to_cc_send_multi_req.read() && !r_xram_rsp_to_cc_send_brdcast_req.read()) { bool multi_req = !r_xram_rsp_victim_is_cnt.read(); bool last_multi_req = multi_req && (r_xram_rsp_victim_count.read() == 1); bool not_last_multi_req = multi_req && (r_xram_rsp_victim_count.read() != 1); r_xram_rsp_to_cc_send_multi_req = last_multi_req; r_xram_rsp_to_cc_send_brdcast_req = r_xram_rsp_victim_is_cnt.read(); r_xram_rsp_to_cc_send_nline = r_xram_rsp_victim_nline.read(); r_xram_rsp_to_cc_send_trdid = r_xram_rsp_upt_index; xram_rsp_to_cc_send_fifo_srcid = r_xram_rsp_victim_copy.read(); xram_rsp_to_cc_send_fifo_inst = r_xram_rsp_victim_copy_inst.read(); #if L1_MULTI_CACHE xram_rsp_to_cc_send_fifo_cache_id = r_xram_rsp_victim_copy_cache.read(); #endif xram_rsp_to_cc_send_fifo_put = multi_req; r_xram_rsp_next_ptr = r_xram_rsp_victim_ptr.read(); if(r_xram_rsp_victim_dirty) r_xram_rsp_fsm = XRAM_RSP_WRITE_DIRTY; else if(not_last_multi_req) r_xram_rsp_fsm = XRAM_RSP_HEAP_REQ; else r_xram_rsp_fsm = XRAM_RSP_IDLE; #if DEBUG_MEMC_XRAM_RSP if(m_debug_xram_rsp_fsm) { std::cout << " Send an inval request to CC_SEND FSM:" << " victim line = " << r_xram_rsp_victim_nline.read() << std::endl; } #endif } break; } ////////////////////////// case XRAM_RSP_WRITE_DIRTY: // send a write request to IXR_CMD FSM { if(!r_xram_rsp_to_ixr_cmd_req.read()) { r_xram_rsp_to_ixr_cmd_req = true; r_xram_rsp_to_ixr_cmd_nline = r_xram_rsp_victim_nline.read(); r_xram_rsp_to_ixr_cmd_trdid = r_xram_rsp_trt_index.read(); for(size_t i=0; i Send the put request to IXR_CMD FSM:" << " victim line = " << r_xram_rsp_victim_nline.read() << std::endl; } #endif } break; } ///////////////////////// case XRAM_RSP_HEAP_REQ: // Get the lock to the HEAP directory { if(r_alloc_heap_fsm.read() == ALLOC_HEAP_XRAM_RSP) { r_xram_rsp_fsm = XRAM_RSP_HEAP_ERASE; } #if DEBUG_MEMC_XRAM_RSP if(m_debug_xram_rsp_fsm) { std::cout << " Requesting HEAP lock " << std::endl; } #endif break; } ///////////////////////// case XRAM_RSP_HEAP_ERASE: // erase the list of copies and sent invalidations { if(r_alloc_heap_fsm.read() == ALLOC_HEAP_XRAM_RSP) { HeapEntry entry = m_heap.read(r_xram_rsp_next_ptr.read()); xram_rsp_to_cc_send_fifo_srcid = entry.owner.srcid; #if L1_MULTI_CACHE xram_rsp_to_cc_send_fifo_cache_id = entry.owner.cache_id; #endif xram_rsp_to_cc_send_fifo_inst = entry.owner.inst; xram_rsp_to_cc_send_fifo_put = true; if(m_xram_rsp_to_cc_send_inst_fifo.wok()) { r_xram_rsp_next_ptr = entry.next; if(entry.next == r_xram_rsp_next_ptr.read()) // last copy { r_xram_rsp_to_cc_send_multi_req = true; r_xram_rsp_fsm = XRAM_RSP_HEAP_LAST; } else { r_xram_rsp_fsm = XRAM_RSP_HEAP_ERASE; } } else { r_xram_rsp_fsm = XRAM_RSP_HEAP_ERASE; } #if DEBUG_MEMC_XRAM_RSP if(m_debug_xram_rsp_fsm) { std::cout << " Erase the list of copies:" << " srcid = " << std::dec << entry.owner.srcid << " / inst = " << std::dec << entry.owner.inst << std::endl; } #endif } break; } ///////////////////////// case XRAM_RSP_HEAP_LAST: // last member of the list { if(r_alloc_heap_fsm.read() != ALLOC_HEAP_XRAM_RSP) { std::cout << "VCI_MEM_CACHE ERROR " << name() << " XRAM_RSP_HEAP_LAST state" << std::endl; std::cout << "bad HEAP allocation" << std::endl; exit(0); } size_t free_pointer = m_heap.next_free_ptr(); HeapEntry last_entry; last_entry.owner.srcid = 0; #if L1_MULTI_CACHE last_entry.owner.cache_id = 0; #endif last_entry.owner.inst = false; if(m_heap.is_full()) { last_entry.next = r_xram_rsp_next_ptr.read(); m_heap.unset_full(); } else { last_entry.next = free_pointer; } m_heap.write_free_ptr(r_xram_rsp_victim_ptr.read()); m_heap.write(r_xram_rsp_next_ptr.read(),last_entry); r_xram_rsp_fsm = XRAM_RSP_IDLE; #if DEBUG_MEMC_XRAM_RSP if(m_debug_xram_rsp_fsm) { std::cout << " Heap housekeeping" << std::endl; } #endif break; } // /////////////////////// case XRAM_RSP_ERROR_ERASE: // erase TRT entry in case of error { m_transaction_tab.erase(r_xram_rsp_trt_index.read()); // Next state if(r_xram_rsp_trt_buf.proc_read) r_xram_rsp_fsm = XRAM_RSP_ERROR_RSP; else r_xram_rsp_fsm = XRAM_RSP_IDLE; #if DEBUG_MEMC_XRAM_RSP if(m_debug_xram_rsp_fsm) { std::cout << " Error reported by XRAM / erase the TRT entry" << std::endl; } #endif break; } //////////////////////// case XRAM_RSP_ERROR_RSP: // Request an error response to TGT_RSP FSM { if(!r_xram_rsp_to_tgt_rsp_req.read()) { r_xram_rsp_to_tgt_rsp_srcid = r_xram_rsp_trt_buf.srcid; r_xram_rsp_to_tgt_rsp_trdid = r_xram_rsp_trt_buf.trdid; r_xram_rsp_to_tgt_rsp_pktid = r_xram_rsp_trt_buf.pktid; for(size_t i=0; i < m_words; i++) r_xram_rsp_to_tgt_rsp_data[i] = r_xram_rsp_trt_buf.wdata[i]; r_xram_rsp_to_tgt_rsp_word = r_xram_rsp_trt_buf.word_index; r_xram_rsp_to_tgt_rsp_length = r_xram_rsp_trt_buf.read_length; r_xram_rsp_to_tgt_rsp_rerror = true; r_xram_rsp_to_tgt_rsp_req = true; r_xram_rsp_fsm = XRAM_RSP_IDLE; #if DEBUG_MEMC_XRAM_RSP if(m_debug_xram_rsp_fsm) { std::cout << " Request a response error to TGT_RSP FSM:" << " srcid = " << std::dec << r_xram_rsp_trt_buf.srcid << std::endl; } #endif } break; } } // end swich r_xram_rsp_fsm //////////////////////////////////////////////////////////////////////////////////// // CLEANUP FSM //////////////////////////////////////////////////////////////////////////////////// // The CLEANUP FSM handles the cleanup request from L1 caches. // It accesses the cache directory and the heap to update the list of copies. //////////////////////////////////////////////////////////////////////////////////// switch(r_cleanup_fsm.read()) { case CLEANUP_IDLE: { // Get first DSPIN flit of the CLEANUP command if(not m_cc_receive_to_cleanup_fifo.rok()) break; uint64_t flit = m_cc_receive_to_cleanup_fifo.read(); uint32_t srcid = DspinDhccpParam::dspin_get( flit, DspinDhccpParam::CLEANUP_SRCID); uint8_t type = DspinDhccpParam::dspin_get( flit, DspinDhccpParam::FROM_L1_TYPE); r_cleanup_way_index = DspinDhccpParam::dspin_get( flit, DspinDhccpParam::CLEANUP_WAY_INDEX); r_cleanup_nline = DspinDhccpParam::dspin_get( flit, DspinDhccpParam::CLEANUP_NLINE_MSB) << 32; r_cleanup_inst = (type == DspinDhccpParam::TYPE_CLEANUP_INST); r_cleanup_srcid = srcid; if(srcid >= m_initiators) { std::cout << "VCI_MEM_CACHE ERROR " << name() << " CLEANUP_IDLE state" << std::endl << "illegal srcid for cleanup request" << std::endl; exit(0); } m_cpt_cleanup++; cc_receive_to_cleanup_fifo_get = true; r_cleanup_fsm = CLEANUP_GET_NLINE; #if DEBUG_MEMC_CLEANUP if(m_debug_cleanup_fsm) { std::cout << " Cleanup request:" << std::hex << " / owner_id = " << srcid << " / owner_ins = " << (type == DspinDhccpParam::TYPE_CLEANUP_INST) << std::endl; } #endif break; } case CLEANUP_GET_NLINE: { // Get second flit of cleanup command if(not m_cc_receive_to_cleanup_fifo.rok()) break; uint64_t flit = m_cc_receive_to_cleanup_fifo.read(); addr_t nline = r_cleanup_nline.read() | DspinDhccpParam::dspin_get(flit, DspinDhccpParam::CLEANUP_NLINE_LSB); bool eop = DspinDhccpParam::dspin_get(flit, DspinDhccpParam::FROM_L1_EOP) == 0x1; assert( eop && "VCI_MEM_CACHE ERROR: " "CLEANUP command must have exactly two flits"); cc_receive_to_cleanup_fifo_get = true; r_cleanup_nline = nline; r_cleanup_fsm = CLEANUP_DIR_REQ; #if DEBUG_MEMC_CLEANUP if(m_debug_cleanup_fsm) { std::cout << " Cleanup request:" << std::hex << " / address = " << nline * m_words * 4 << std::endl; } #endif break; } case CLEANUP_DIR_REQ: { // Get the lock to the directory if(r_alloc_dir_fsm.read() != ALLOC_DIR_CLEANUP) break; r_cleanup_fsm = CLEANUP_DIR_LOCK; #if DEBUG_MEMC_CLEANUP if(m_debug_cleanup_fsm) { std::cout << " Requesting DIR lock " << std::endl; } #endif break; } case CLEANUP_DIR_LOCK: { // test directory status if(r_alloc_dir_fsm.read() != ALLOC_DIR_CLEANUP) { std::cout << "VCI_MEM_CACHE ERROR " << name() << " CLEANUP_DIR_LOCK state" << " bad DIR allocation" << std::endl; exit(0); } // Read the directory size_t way = 0; addr_t cleanup_address = r_cleanup_nline.read() * m_words * 4; DirectoryEntry entry = m_cache_directory.read(cleanup_address , way); r_cleanup_is_cnt = entry.is_cnt; r_cleanup_dirty = entry.dirty; r_cleanup_tag = entry.tag; r_cleanup_lock = entry.lock; r_cleanup_way = way; r_cleanup_count = entry.count; r_cleanup_ptr = entry.ptr; r_cleanup_copy = entry.owner.srcid; r_cleanup_copy_inst = entry.owner.inst; #if L1_MULTI_CACHE r_cleanup_copy_cache = entry.owner.cache_id; #endif // hit : // the copy must be cleared if(entry.valid) { assert( (entry.count > 0) && "VCI MEM CACHE ERROR: " "In CLEANUP_DIR_LOCK, CLEANUP command on a valid entry " "with no copies"); // no access to the heap if((entry.count == 1) || (entry.is_cnt)) { r_cleanup_fsm = CLEANUP_DIR_WRITE; } // access to the heap else { r_cleanup_fsm = CLEANUP_HEAP_REQ; } } // miss : // we must check the update table for a pending // invalidation transaction else { r_cleanup_fsm = CLEANUP_UPT_LOCK; } #if DEBUG_MEMC_CLEANUP if(m_debug_cleanup_fsm) { std::cout << " Test directory status: " << std::hex << " line = " << cleanup_address << " / hit = " << entry.valid << " / dir_id = " << entry.owner.srcid << " / dir_ins = " << entry.owner.inst << " / search_id = " << r_cleanup_srcid.read() << " / search_ins = " << r_cleanup_inst.read() << " / count = " << entry.count << " / is_cnt = " << entry.is_cnt << std::endl; } #endif break; } case CLEANUP_DIR_WRITE: { // Update the directory entry without heap access if(r_alloc_dir_fsm.read() != ALLOC_DIR_CLEANUP) { std::cout << "VCI_MEM_CACHE ERROR " << name() << " CLEANUP_DIR_WRITE state" << " bad DIR allocation" << std::endl; exit(0); } size_t way = r_cleanup_way.read(); size_t set = m_y[(vci_addr_t)(r_cleanup_nline.read()*m_words*4)]; bool match_srcid = (r_cleanup_copy.read() == r_cleanup_srcid.read()); #if L1_MULTI_CACHE match_srcid &= (r_cleanup_copy_cache.read() == r_cleanup_pktid.read()); #endif bool match_inst = (r_cleanup_copy_inst.read() == r_cleanup_inst.read()); bool match = match_srcid && match_inst; if(not r_cleanup_is_cnt.read() and not match) { std::cout << "VCI_MEM_CACHE ERROR : Cleanup request on a valid" << "entry using linked list mode with no corresponding" << "directory or heap entry" << std::endl; exit(1); } // update the cache directory (for the copies) DirectoryEntry entry; entry.valid = true; entry.is_cnt = r_cleanup_is_cnt.read(); entry.dirty = r_cleanup_dirty.read(); entry.tag = r_cleanup_tag.read(); entry.lock = r_cleanup_lock.read(); entry.ptr = r_cleanup_ptr.read(); entry.count = r_cleanup_count.read() - 1; entry.owner.srcid = 0; entry.owner.inst = 0; #if L1_MULTI_CACHE entry.owner.cache_id = 0; #endif m_cache_directory.write(set, way, entry); r_cleanup_fsm = CLEANUP_SEND_ACK; #if DEBUG_MEMC_CLEANUP if(m_debug_cleanup_fsm) { std::cout << " Update directory:" << std::hex << " address = " << r_cleanup_nline.read() * m_words * 4 << " / dir_id = " << entry.owner.srcid << " / dir_ins = " << entry.owner.inst << " / count = " << entry.count << " / is_cnt = " << entry.is_cnt << std::endl; } #endif break; } case CLEANUP_HEAP_REQ: { // get the lock to the HEAP directory if(r_alloc_heap_fsm.read() != ALLOC_HEAP_CLEANUP) break; r_cleanup_fsm = CLEANUP_HEAP_LOCK; #if DEBUG_MEMC_CLEANUP if(m_debug_cleanup_fsm) { std::cout << " HEAP lock acquired " << std::endl; } #endif break; } case CLEANUP_HEAP_LOCK: { // two cases are handled in this state : // 1. the matching copy is directly in the directory // 2. the matching copy is the first copy in the heap if(r_alloc_heap_fsm.read() != ALLOC_HEAP_CLEANUP) { std::cout << "VCI_MEM_CACHE ERROR " << name() << " CLEANUP_HEAP_LOCK state" << " bad HEAP allocation" << std::endl; exit(0); } size_t way = r_cleanup_way.read(); size_t set = m_y[(vci_addr_t)(r_cleanup_nline.read() *m_words*4)]; HeapEntry heap_entry = m_heap.read(r_cleanup_ptr.read()); bool last = (heap_entry.next == r_cleanup_ptr.read()); // match_dir computation bool match_dir_srcid = (r_cleanup_copy.read() == r_cleanup_srcid.read()); bool match_dir_inst = (r_cleanup_copy_inst.read() == r_cleanup_inst.read()); bool match_dir = match_dir_srcid and match_dir_inst; // match_heap computation bool match_heap_srcid = (heap_entry.owner.srcid == r_cleanup_srcid.read()); bool match_heap_inst = (heap_entry.owner.inst == r_cleanup_inst.read()); bool match_heap = match_heap_srcid and match_heap_inst; r_cleanup_prev_ptr = r_cleanup_ptr.read(); r_cleanup_prev_srcid = heap_entry.owner.srcid; r_cleanup_prev_inst = heap_entry.owner.inst; #if L1_MULTI_CACHE match_dir = match_dir and(r_cleanup_copy_cache.read() == r_cleanup_pktid.read()); match_heap = match_heap and(heap_entry.owner.cache_id == r_cleanup_pktid.read()); r_cleanup_prev_cache_id = heap_entry.owner.cache_id; #endif if(not match_dir and not match_heap and last) { std::cout << "VCI_MEM_CACHE ERROR " << name() << " CLEANUP_HEAP_LOCK state" << " hit but copy not found" << std::endl; /**/ std::cout << "r_cleanup_srcid = " << r_cleanup_srcid.read() << " / r_cleanup_inst = " << r_cleanup_inst.read() << std::endl << "r_cleanup_copy = " << r_cleanup_copy.read() << " / r_cleanup_copy_inst = " << r_cleanup_copy_inst.read() << std::endl << "heap_entry.owner.srcid = " << heap_entry.owner.srcid << " / heap_entry.owner.inst = " << heap_entry.owner.inst << std::endl; /**/ exit(0); } if(match_dir and match_heap) { std::cout << "VCI_MEM_CACHE ERROR " << name() << " CLEANUP_HEAP_LOCK state" << " two copies matching the cleanup owner id" << std::endl; /**/ std::cout << "r_cleanup_srcid = " << r_cleanup_srcid.read() << " / r_cleanup_inst = " << r_cleanup_inst.read() << std::endl << "r_cleanup_copy = " << r_cleanup_copy.read() << " / r_cleanup_copy_inst = " << r_cleanup_copy_inst.read() << std::endl << "heap_entry.owner.srcid = " << heap_entry.owner.srcid << " / heap_entry.owner.inst = " << heap_entry.owner.inst << std::endl; /**/ exit(0); } DirectoryEntry dir_entry; dir_entry.valid = true; dir_entry.is_cnt = r_cleanup_is_cnt.read(); dir_entry.dirty = r_cleanup_dirty.read(); dir_entry.tag = r_cleanup_tag.read(); dir_entry.lock = r_cleanup_lock.read(); dir_entry.count = r_cleanup_count.read()-1; // the matching copy is registered in the directory and // it must be replaced by the first copy registered in // the heap. The corresponding entry must be freed if(match_dir) { dir_entry.ptr = heap_entry.next; dir_entry.owner.srcid = heap_entry.owner.srcid; dir_entry.owner.inst = heap_entry.owner.inst; #if L1_MULTI_CACHE dir_entry.owner.cache_id = heap_entry.owner.cache_id; #endif r_cleanup_next_ptr = r_cleanup_ptr.read(); r_cleanup_fsm = CLEANUP_HEAP_FREE; } // the matching copy is the first copy in the heap // It must be freed and the copy registered in directory // must point to the next copy in heap else if(match_heap) { dir_entry.ptr = heap_entry.next; dir_entry.owner.srcid = r_cleanup_copy.read(); dir_entry.owner.inst = r_cleanup_copy_inst.read(); #if L1_MULTI_CACHE dir_entry.owner.cache_id = r_cleanup_copy_cache.read(); #endif r_cleanup_next_ptr = r_cleanup_ptr.read(); r_cleanup_fsm = CLEANUP_HEAP_FREE; } // The matching copy is in the heap, but is not the first copy // The directory entry must be modified to decrement count else { dir_entry.ptr = r_cleanup_ptr.read(); dir_entry.owner.srcid = r_cleanup_copy.read(); dir_entry.owner.inst = r_cleanup_copy_inst.read(); #if L1_MULTI_CACHE dir_entry.owner.cache_id = r_cleanup_copy_cache.read(); #endif r_cleanup_next_ptr = heap_entry.next; r_cleanup_fsm = CLEANUP_HEAP_SEARCH; } m_cache_directory.write(set,way,dir_entry); #if DEBUG_MEMC_CLEANUP if(m_debug_cleanup_fsm) { std::cout << " Checks matching:" << " address = " << r_cleanup_nline.read() * m_words * 4 << " / dir_id = " << r_cleanup_copy.read() << " / dir_ins = " << r_cleanup_copy_inst.read() << " / heap_id = " << heap_entry.owner.srcid << " / heap_ins = " << heap_entry.owner.inst << " / search_id = " << r_cleanup_srcid.read() << " / search_ins = " << r_cleanup_inst.read() << std::endl; } #endif break; } case CLEANUP_HEAP_SEARCH: { // This state is handling the case where the copy // is in the heap, but is not the first in the linked list if(r_alloc_heap_fsm.read() != ALLOC_HEAP_CLEANUP) { std::cout << "VCI_MEM_CACHE ERROR " << name() << " CLEANUP_HEAP_SEARCH state" << " bad HEAP allocation" << std::endl; exit(0); } HeapEntry heap_entry = m_heap.read(r_cleanup_next_ptr.read()); bool last = (heap_entry.next == r_cleanup_next_ptr.read()); bool match_heap_srcid = (heap_entry.owner.srcid == r_cleanup_srcid.read()); bool match_heap_inst = (heap_entry.owner.inst == r_cleanup_inst.read()); bool match_heap = match_heap_srcid && match_heap_inst; #if L1_MULTI_CACHE match_heap = match_heap and(heap_entry.owner.cache_id == r_cleanup_pktid.read()); #endif if(not match_heap and last) { std::cout << "VCI_MEM_CACHE_ERROR " << name() << " CLEANUP_HEAP_SEARCH state" << " cleanup on valid line but copy not found" << std::endl; exit(0); } // the matching copy must be removed if(match_heap) { // re-use ressources r_cleanup_ptr = heap_entry.next; r_cleanup_fsm = CLEANUP_HEAP_CLEAN; } // test the next in the linked list else { r_cleanup_prev_ptr = r_cleanup_next_ptr.read(); r_cleanup_prev_srcid = heap_entry.owner.srcid; r_cleanup_prev_inst = heap_entry.owner.inst; r_cleanup_next_ptr = heap_entry.next; r_cleanup_fsm = CLEANUP_HEAP_SEARCH; #if L1_MULTI_CACHE r_cleanup_prev_cache_id = heap_entry.owner.cache_id; #endif } #if DEBUG_MEMC_CLEANUP if(m_debug_cleanup_fsm) { if(not match_heap) { std::cout << " Matching copy not found, search next:" << std::endl; } else { std::cout << " Matching copy found:" << std::endl; } std::cout << " address = " << r_cleanup_nline.read() * m_words * 4 << " / heap_id = " << heap_entry.owner.srcid << " / heap_ins = " << heap_entry.owner.inst << " / search_id = " << r_cleanup_srcid.read() << " / search_ins = " << r_cleanup_inst.read() << " / last = " << last << std::endl; } #endif break; } case CLEANUP_HEAP_CLEAN: { // remove a copy in the linked list if(r_alloc_heap_fsm.read() != ALLOC_HEAP_CLEANUP) { std::cout << "VCI_MEM_CACHE ERROR " << name() << " CLEANUP_HEAP_CLEAN state" << "Bad HEAP allocation" << std::endl; exit(0); } HeapEntry heap_entry; heap_entry.owner.srcid = r_cleanup_prev_srcid.read(); heap_entry.owner.inst = r_cleanup_prev_inst.read(); #if L1_MULTI_CACHE heap_entry.owner.cache_id = r_cleanup_prev_cache_id.read(); #endif bool last = (r_cleanup_next_ptr.read() == r_cleanup_ptr.read()); // this is the last entry of the list of copies if(last) { heap_entry.next = r_cleanup_prev_ptr.read(); } // this is not the last entry else { heap_entry.next = r_cleanup_ptr.read(); } m_heap.write(r_cleanup_prev_ptr.read(), heap_entry); r_cleanup_fsm = CLEANUP_HEAP_FREE; #if DEBUG_MEMC_CLEANUP if(m_debug_cleanup_fsm) { std::cout << " Remove the copy in the linked list" << std::endl; } #endif break; } case CLEANUP_HEAP_FREE: { // The heap entry pointed by r_cleanup_next_ptr is freed // and becomes the head of the list of free entries if(r_alloc_heap_fsm.read() != ALLOC_HEAP_CLEANUP) { std::cout << "VCI_MEM_CACHE ERROR " << name() << " CLEANUP_HEAP_CLEAN state" << std::endl << "Bad HEAP allocation" << std::endl; exit(0); } HeapEntry heap_entry; heap_entry.owner.srcid = 0; heap_entry.owner.inst = false; #if L1_MULTI_CACHE heap_entry.owner.cache_id = 0; #endif if(m_heap.is_full()) { heap_entry.next = r_cleanup_next_ptr.read(); } else { heap_entry.next = m_heap.next_free_ptr(); } m_heap.write(r_cleanup_next_ptr.read(),heap_entry); m_heap.write_free_ptr(r_cleanup_next_ptr.read()); m_heap.unset_full(); r_cleanup_fsm = CLEANUP_SEND_ACK; #if DEBUG_MEMC_CLEANUP if(m_debug_cleanup_fsm) { std::cout << " Update the list of free entries" << std::endl; } #endif break; } case CLEANUP_UPT_LOCK: { // search pending invalidate transaction matching the Cleanup NLINE in the UPDATE TABLE // get the lock in the UPDATE_TABLE if(r_alloc_upt_fsm.read() != ALLOC_UPT_CLEANUP) break; size_t index = 0; bool match_inval; match_inval = m_update_tab.search_inval(r_cleanup_nline.read(), index); // no pending inval if(not match_inval) { r_cleanup_fsm = CLEANUP_SEND_ACK; #if DEBUG_MEMC_CLEANUP if(m_debug_cleanup_fsm) { std::cout << " Unexpected cleanup" << " with no corresponding UPT entry:" << " address = " << std::hex << (r_cleanup_nline.read() *4*m_words) << std::endl; } #endif break; } // pending inval r_cleanup_write_srcid = m_update_tab.srcid(index); r_cleanup_write_trdid = m_update_tab.trdid(index); r_cleanup_write_pktid = m_update_tab.pktid(index); r_cleanup_write_need_rsp = m_update_tab.need_rsp(index); r_cleanup_index = index; r_cleanup_fsm = CLEANUP_UPT_DECREMENT; #if DEBUG_MEMC_CLEANUP if(m_debug_cleanup_fsm) { std::cout << " Cleanup matching pending" << " invalidate transaction on UPT:" << std::hex << " address = " << r_cleanup_nline.read() * m_words * 4 << " upt_entry = " << index << std::endl; } #endif break; } case CLEANUP_UPT_DECREMENT: { // decrement response counter in UPT matching entry if(r_alloc_upt_fsm.read() != ALLOC_UPT_CLEANUP) { std::cout << "VCI_MEM_CACHE ERROR " << name() << " CLEANUP_UPT_DECREMENT state" << std::endl << "Bad UPT allocation" << std::endl; exit(0); } size_t count = 0; m_update_tab.decrement(r_cleanup_index.read(), count); // invalidation transaction finished // (all acknowledgements received) if(count == 0) { r_cleanup_fsm = CLEANUP_UPT_CLEAR; } // invalidation transaction not finished else { r_cleanup_fsm = CLEANUP_SEND_ACK ; } #if DEBUG_MEMC_CLEANUP if(m_debug_cleanup_fsm) { std::cout << " Decrement response counter in UPT:" << " UPT_index = " << r_cleanup_index.read() << " rsp_count = " << count << std::endl; } #endif break; } case CLEANUP_UPT_CLEAR: { // Clear UPT entry of finished invalidation transaction if(r_alloc_upt_fsm.read() != ALLOC_UPT_CLEANUP) { std::cout << "VCI_MEM_CACHE ERROR " << name() << " CLEANUP_UPT_CLEAR state" << std::endl << "Bad UPT allocation" << std::endl; exit(0); } m_update_tab.clear(r_cleanup_index.read()); if(r_cleanup_write_need_rsp.read()) { r_cleanup_fsm = CLEANUP_WRITE_RSP; } else { r_cleanup_fsm = CLEANUP_SEND_ACK; } #if DEBUG_MEMC_CLEANUP if(m_debug_cleanup_fsm) { std::cout << " Clear entry in UPT:" << " UPT_index = " << r_cleanup_index.read() << std::endl; } #endif break; } case CLEANUP_WRITE_RSP: { // response to a previous write on the direct network // wait if pending request to the TGT_RSP FSM if(r_cleanup_to_tgt_rsp_req.read()) break; // no pending request r_cleanup_to_tgt_rsp_req = true; r_cleanup_to_tgt_rsp_srcid = r_cleanup_write_srcid.read(); r_cleanup_to_tgt_rsp_trdid = r_cleanup_write_trdid.read(); r_cleanup_to_tgt_rsp_pktid = r_cleanup_write_pktid.read(); r_cleanup_fsm = CLEANUP_SEND_ACK; #if DEBUG_MEMC_CLEANUP if(m_debug_cleanup_fsm) { std::cout << " Send a response to a previous" << " write request waiting for coherence transaction completion: " << " rsrcid = " << std::dec << r_cleanup_write_srcid.read() << " / rtrdid = " << std::dec << r_cleanup_write_trdid.read() << std::endl; } #endif break; } case CLEANUP_SEND_ACK: { // acknowledgement to a cleanup command // on the coherence network (request to the CC_SEND FSM). // wait if pending request to the CC_SEND FSM if(r_cleanup_to_cc_send_req.read()) break; r_cleanup_to_cc_send_req = true; r_cleanup_to_cc_send_set_index = r_cleanup_nline.read() & 0xFFFF; r_cleanup_to_cc_send_way_index = r_cleanup_way_index.read(); r_cleanup_to_cc_send_srcid = r_cleanup_srcid.read(); r_cleanup_to_cc_send_inst = r_cleanup_inst.read(); r_cleanup_fsm = CLEANUP_IDLE; #if DEBUG_MEMC_CLEANUP if(m_debug_cleanup_fsm) { std::cout << " Send the response to a cleanup request:" << " srcid = " << std::dec << r_cleanup_srcid.read() << std::endl; } #endif break; } } // end switch cleanup fsm //////////////////////////////////////////////////////////////////////////////////// // CAS FSM //////////////////////////////////////////////////////////////////////////////////// // The CAS FSM handles the CAS (Store Conditionnal) atomic commands, // that are handled as "compare-and-swap instructions. // // This command contains two or four flits: // - In case of 32 bits atomic access, the first flit contains the value read // by a previous LL instruction, the second flit contains the value to be writen. // - In case of 64 bits atomic access, the 2 first flits contains the value read // by a previous LL instruction, the 2 next flits contains the value to be writen. // // The target address is cachable. If it is replicated in other L1 caches // than the writer, a coherence operation is done. // // It access the directory to check hit / miss. // - In case of miss, the CAS FSM must register a GET transaction in TRT. // If a read transaction to the XRAM for this line already exists, // or if the transaction table is full, it goes to the WAIT state // to release the locks and try again. When the GET transaction has been // launched, it goes to the WAIT state and try again. // The CAS request is not consumed in the FIFO until a HIT is obtained. // - In case of hit... /////////////////////////////////////////////////////////////////////////////////// switch(r_cas_fsm.read()) { ///////////// case CAS_IDLE: // fill the local rdata buffers { if(m_cmd_cas_addr_fifo.rok()) { #if DEBUG_MEMC_CAS if(m_debug_cas_fsm) { std::cout << " CAS command: " << std::hex << " srcid = " << std::dec << m_cmd_cas_srcid_fifo.read() << " addr = " << std::hex << m_cmd_cas_addr_fifo.read() << " wdata = " << m_cmd_cas_wdata_fifo.read() << " eop = " << std::dec << m_cmd_cas_eop_fifo.read() << " cpt = " << std::dec << r_cas_cpt.read() << std::endl; } #endif if(m_cmd_cas_eop_fifo.read()) { m_cpt_cas++; r_cas_fsm = CAS_DIR_REQ; } else // we keep the last word in the FIFO { cmd_cas_fifo_get = true; } // We fill the two buffers if(r_cas_cpt.read() < 2) // 32 bits access r_cas_rdata[r_cas_cpt.read()] = m_cmd_cas_wdata_fifo.read(); if((r_cas_cpt.read() == 1) && m_cmd_cas_eop_fifo.read()) r_cas_wdata = m_cmd_cas_wdata_fifo.read(); if(r_cas_cpt.read() >3) // more than 4 flits... { std::cout << "VCI_MEM_CACHE ERROR in CAS_IDLE state : illegal CAS command" << std::endl; exit(0); } if(r_cas_cpt.read() ==2) r_cas_wdata = m_cmd_cas_wdata_fifo.read(); r_cas_cpt = r_cas_cpt.read() +1; } break; } ///////////////// case CAS_DIR_REQ: { if(r_alloc_dir_fsm.read() == ALLOC_DIR_CAS) { r_cas_fsm = CAS_DIR_LOCK; } #if DEBUG_MEMC_CAS if(m_debug_cas_fsm) { std::cout << " Requesting DIR lock " << std::endl; } #endif break; } ///////////////// case CAS_DIR_LOCK: // Read the directory { if(r_alloc_dir_fsm.read() == ALLOC_DIR_CAS) { size_t way = 0; DirectoryEntry entry(m_cache_directory.read(m_cmd_cas_addr_fifo.read(), way)); r_cas_is_cnt = entry.is_cnt; r_cas_dirty = entry.dirty; r_cas_tag = entry.tag; r_cas_way = way; r_cas_copy = entry.owner.srcid; #if L1_MULTI_CACHE r_cas_copy_cache = entry.owner.cache_id; #endif r_cas_copy_inst = entry.owner.inst; r_cas_ptr = entry.ptr; r_cas_count = entry.count; if(entry.valid) r_cas_fsm = CAS_DIR_HIT_READ; else r_cas_fsm = CAS_MISS_TRT_LOCK; #if DEBUG_MEMC_CAS if(m_debug_cas_fsm) { std::cout << " Directory acces" << " / address = " << std::hex << m_cmd_cas_addr_fifo.read() << " / hit = " << std::dec << entry.valid << " / count = " << entry.count << " / is_cnt = " << entry.is_cnt << std::endl; } #endif } else { std::cout << "VCI_MEM_CACHE ERROR " << name() << " CAS_DIR_LOCK state" << std::endl << "Bad DIR allocation" << std::endl; exit(0); } break; } ///////////////////// case CAS_DIR_HIT_READ: // update directory for lock and dirty bit // and check data change in cache { size_t way = r_cas_way.read(); size_t set = m_y[(vci_addr_t)(m_cmd_cas_addr_fifo.read())]; // update directory (lock & dirty bits) DirectoryEntry entry; entry.valid = true; entry.is_cnt = r_cas_is_cnt.read(); entry.dirty = true; entry.lock = true; entry.tag = r_cas_tag.read(); entry.owner.srcid = r_cas_copy.read(); #if L1_MULTI_CACHE entry.owner.cache_id = r_cas_copy_cache.read(); #endif entry.owner.inst = r_cas_copy_inst.read(); entry.count = r_cas_count.read(); entry.ptr = r_cas_ptr.read(); m_cache_directory.write(set, way, entry); // Stored data from cache in buffer to do the comparison in next state m_cache_data.read_line(way, set, r_cas_data); r_cas_fsm = CAS_DIR_HIT_COMPARE; #if DEBUG_MEMC_CAS if(m_debug_cas_fsm) { std::cout << " Read data from " << " cache and store it in buffer" << std::endl; } #endif break; } case CAS_DIR_HIT_COMPARE: { size_t word = m_x[(vci_addr_t)(m_cmd_cas_addr_fifo.read())]; // Read data in buffer & check data change bool ok = (r_cas_rdata[0].read() == r_cas_data[word].read()); if(r_cas_cpt.read() == 4) // 64 bits CAS ok &= (r_cas_rdata[1] == r_cas_data[word+1]); // to avoid livelock, force the atomic access to fail pseudo-randomly bool forced_fail = ((r_cas_lfsr % (64) == 0) && RANDOMIZE_CAS); r_cas_lfsr = (r_cas_lfsr >> 1) ^ ((- (r_cas_lfsr & 1)) & 0xd0000001); // cas success if(ok and not forced_fail) { r_cas_fsm = CAS_DIR_HIT_WRITE; } // cas failure else { r_cas_fsm = CAS_RSP_FAIL; } #if DEBUG_MEMC_CAS if(m_debug_cas_fsm) { std::cout << " Compare the old" << " and the new data" << " / expected value = " << r_cas_rdata[0].read() << " / actual value = " << r_cas_data[word].read() << " / forced_fail = " << forced_fail << std::endl; } #endif break; } ////////////////////// case CAS_DIR_HIT_WRITE: // test if a CC transaction is required // write data in cache if no CC request { // The CAS is a success => sw access to the llsc_global_table m_llsc_table.sw(m_cmd_cas_addr_fifo.read()); // test coherence request if(r_cas_count.read()) // replicated line { if(r_cas_is_cnt.read()) { r_cas_fsm = CAS_BC_TRT_LOCK; // broadcast invalidate required } else if(!r_cas_to_cc_send_multi_req.read() && !r_cas_to_cc_send_brdcast_req.read()) { r_cas_fsm = CAS_UPT_LOCK; // multi update required } else { r_cas_fsm = CAS_WAIT; } } else // no copies { size_t way = r_cas_way.read(); size_t set = m_y[(vci_addr_t)(m_cmd_cas_addr_fifo.read())]; size_t word = m_x[(vci_addr_t)(m_cmd_cas_addr_fifo.read())]; // cache update m_cache_data.write(way, set, word, r_cas_wdata.read()); if(r_cas_cpt.read() == 4) m_cache_data.write(way, set, word+1, m_cmd_cas_wdata_fifo.read()); r_cas_fsm = CAS_RSP_SUCCESS; // monitor if(m_monitor_ok) { vci_addr_t address = m_cmd_cas_addr_fifo.read(); char buf[80]; snprintf(buf, 80, "CAS_DIR_HIT_WRITE srcid %d", m_cmd_cas_srcid_fifo.read()); check_monitor(buf, address, r_cas_wdata.read()); if(r_cas_cpt.read() == 4) check_monitor(buf, address+4, m_cmd_cas_wdata_fifo.read()); } #if DEBUG_MEMC_CAS if(m_debug_cas_fsm) { std::cout << " Update cache:" << " way = " << std::dec << way << " / set = " << set << " / word = " << word << " / value = " << r_cas_wdata.read() << " / count = " << r_cas_count.read() << std::endl; std::cout << " global_llsc_table SW access" << std::endl; } #endif } break; } ///////////////// case CAS_UPT_LOCK: // try to register the transaction in UPT // and write data in cache if successful registration // releases locks to retry later if UPT full { if(r_alloc_upt_fsm.read() == ALLOC_UPT_CAS) { bool wok = false; size_t index = 0; size_t srcid = m_cmd_cas_srcid_fifo.read(); size_t trdid = m_cmd_cas_trdid_fifo.read(); size_t pktid = m_cmd_cas_pktid_fifo.read(); addr_t nline = m_nline[(vci_addr_t)(m_cmd_cas_addr_fifo.read())]; size_t nb_copies = r_cas_count.read(); wok = m_update_tab.set(true, // it's an update transaction false, // it's not a broadcast true, // it needs a response srcid, trdid, pktid, nline, nb_copies, index); if(wok) // coherence transaction registered in UPT { // cache update size_t way = r_cas_way.read(); size_t set = m_y[(vci_addr_t)(m_cmd_cas_addr_fifo.read())]; size_t word = m_x[(vci_addr_t)(m_cmd_cas_addr_fifo.read())]; m_cache_data.write(way, set, word, r_cas_wdata.read()); if(r_cas_cpt.read() ==4) m_cache_data.write(way, set, word+1, m_cmd_cas_wdata_fifo.read()); r_cas_upt_index = index; r_cas_fsm = CAS_UPT_HEAP_LOCK; // monitor if(m_monitor_ok) { vci_addr_t address = m_cmd_cas_addr_fifo.read(); char buf[80]; snprintf(buf, 80, "CAS_DIR_HIT_WRITE srcid %d", m_cmd_cas_srcid_fifo.read()); check_monitor(buf, address, r_cas_wdata.read()); if(r_cas_cpt.read() ==4) check_monitor(buf, address+4, m_cmd_cas_wdata_fifo.read()); } } else // releases the locks protecting UPT and DIR UPT full { r_cas_fsm = CAS_WAIT; } #if DEBUG_MEMC_CAS if(m_debug_cas_fsm) { std::cout << " Register multi-update transaction in UPT" << " / wok = " << wok << " / nline = " << std::hex << nline << " / count = " << nb_copies << std::endl; } #endif } break; } ///////////// case CAS_WAIT: // release all locks and retry from beginning { #if DEBUG_MEMC_CAS if(m_debug_cas_fsm) { std::cout << " Release all locks" << std::endl; } #endif r_cas_fsm = CAS_DIR_REQ; break; } ////////////////// case CAS_UPT_HEAP_LOCK: // lock the heap { if(r_alloc_heap_fsm.read() == ALLOC_HEAP_CAS) { #if DEBUG_MEMC_CAS if(m_debug_cas_fsm) { std::cout << " Get access to the heap" << std::endl; } #endif r_cas_fsm = CAS_UPT_REQ; } break; } //////////////// case CAS_UPT_REQ: // send a first update request to CC_SEND FSM { assert((r_alloc_heap_fsm.read() == ALLOC_HEAP_CAS) and "VCI_MEM_CACHE ERROR : bad HEAP allocation"); if(!r_cas_to_cc_send_multi_req.read() && !r_cas_to_cc_send_brdcast_req.read()) { r_cas_to_cc_send_brdcast_req = false; r_cas_to_cc_send_trdid = r_cas_upt_index.read(); r_cas_to_cc_send_nline = m_nline[(vci_addr_t)(m_cmd_cas_addr_fifo.read())]; r_cas_to_cc_send_index = m_x[(vci_addr_t)(m_cmd_cas_addr_fifo.read())]; r_cas_to_cc_send_wdata = r_cas_wdata.read(); if(r_cas_cpt.read() == 4) { r_cas_to_cc_send_is_long = true; r_cas_to_cc_send_wdata_high = m_cmd_cas_wdata_fifo.read(); } else { r_cas_to_cc_send_is_long = false; r_cas_to_cc_send_wdata_high = 0; } // We put the first copy in the fifo cas_to_cc_send_fifo_put = true; cas_to_cc_send_fifo_inst = r_cas_copy_inst.read(); cas_to_cc_send_fifo_srcid = r_cas_copy.read(); #if L1_MULTI_CACHE cas_to_cc_send_fifo_cache_id= r_cas_copy_cache.read(); #endif if(r_cas_count.read() == 1) // one single copy { r_cas_fsm = CAS_IDLE; // Response will be sent after receiving // update responses cmd_cas_fifo_get = true; r_cas_to_cc_send_multi_req = true; r_cas_cpt = 0; } else // several copies { r_cas_fsm = CAS_UPT_NEXT; } #if DEBUG_MEMC_CAS if(m_debug_cas_fsm) { std::cout << " Send the first update request to CC_SEND FSM " << " / address = " << std::hex << m_cmd_cas_addr_fifo.read() << " / wdata = " << std::hex << r_cas_wdata.read() << " / srcid = " << std::dec << r_cas_copy.read() << " / inst = " << std::dec << r_cas_copy_inst.read() << std::endl; } #endif } break; } ///////////////// case CAS_UPT_NEXT: // send a multi-update request to CC_SEND FSM { assert((r_alloc_heap_fsm.read() == ALLOC_HEAP_CAS) and "VCI_MEM_CACHE ERROR : bad HEAP allocation"); HeapEntry entry = m_heap.read(r_cas_ptr.read()); cas_to_cc_send_fifo_srcid = entry.owner.srcid; #if L1_MULTI_CACHE cas_to_cc_send_fifo_cache_id = entry.owner.cache_id; #endif cas_to_cc_send_fifo_inst = entry.owner.inst; cas_to_cc_send_fifo_put = true; if(m_cas_to_cc_send_inst_fifo.wok()) // request accepted by CC_SEND FSM { r_cas_ptr = entry.next; if(entry.next == r_cas_ptr.read()) // last copy { r_cas_to_cc_send_multi_req = true; r_cas_fsm = CAS_IDLE; // Response will be sent after receiving // all update responses cmd_cas_fifo_get = true; r_cas_cpt = 0; } } #if DEBUG_MEMC_CAS if(m_debug_cas_fsm) { std::cout << " Send the next update request to CC_SEND FSM " << " / address = " << std::hex << m_cmd_cas_addr_fifo.read() << " / wdata = " << std::hex << r_cas_wdata.read() << " / srcid = " << std::dec << entry.owner.srcid << " / inst = " << std::dec << entry.owner.inst << std::endl; } #endif break; } ///////////////////// case CAS_BC_TRT_LOCK: // check the TRT to register a PUT transaction { if(r_alloc_trt_fsm.read() == ALLOC_TRT_CAS) { if(!r_cas_to_ixr_cmd_req) // we can transfer the request to IXR_CMD FSM { // fill the data buffer size_t word = m_x[(vci_addr_t)(m_cmd_cas_addr_fifo.read())]; for(size_t i = 0; i Register a broadcast inval transaction in UPT" << " / nline = " << nline << " / count = " << nb_copies << " / upt_index = " << index << std::endl; } #endif } else // releases the lock protecting UPT { r_cas_fsm = CAS_WAIT; } } break; } ////////////////// case CAS_BC_DIR_INVAL: // Register the PUT transaction in TRT, and inval the DIR entry { if((r_alloc_trt_fsm.read() == ALLOC_TRT_CAS) && (r_alloc_upt_fsm.read() == ALLOC_UPT_CAS) && (r_alloc_dir_fsm.read() == ALLOC_DIR_CAS)) { // set TRT m_transaction_tab.set(r_cas_trt_index.read(), false, // PUT request to XRAM m_nline[(vci_addr_t)(m_cmd_cas_addr_fifo.read())], 0, 0, 0, false, // not a processor read 0, 0, std::vector (m_words,0), std::vector (m_words,0)); // invalidate directory entry DirectoryEntry entry; entry.valid = false; entry.dirty = false; entry.tag = 0; entry.is_cnt = false; entry.lock = false; entry.count = 0; entry.owner.srcid = 0; #if L1_MULTI_CACHE entry.owner.cache_id= 0; #endif entry.owner.inst = false; entry.ptr = 0; size_t set = m_y[(vci_addr_t)(m_cmd_cas_addr_fifo.read())]; size_t way = r_cas_way.read(); m_cache_directory.write(set, way, entry); r_cas_fsm = CAS_BC_CC_SEND; #if DEBUG_MEMC_CAS if(m_debug_cas_fsm) { std::cout << " Register the PUT in TRT and invalidate DIR entry" << " / nline = " << std::hex << m_nline[(vci_addr_t)(m_cmd_cas_addr_fifo.read())] << " / set = " << std::dec << set << " / way = " << way << std::endl; } #endif } else { assert(false and "LOCK ERROR in CAS_FSM, STATE = CAS_BC_DIR_INVAL"); } break; } /////////////////// case CAS_BC_CC_SEND: // Request the broadcast inval to CC_SEND FSM { if(!r_cas_to_cc_send_multi_req.read() && !r_cas_to_cc_send_brdcast_req.read()) { r_cas_to_cc_send_multi_req = false; r_cas_to_cc_send_brdcast_req = true; r_cas_to_cc_send_trdid = r_cas_upt_index.read(); r_cas_to_cc_send_nline = m_nline[(vci_addr_t)(m_cmd_cas_addr_fifo.read())]; r_cas_to_cc_send_index = 0; r_cas_to_cc_send_wdata = 0; r_cas_fsm = CAS_BC_XRAM_REQ; } break; } //////////////////// case CAS_BC_XRAM_REQ: // request the IXR FSM to start a put transaction { if(!r_cas_to_ixr_cmd_req) { r_cas_to_ixr_cmd_req = true; r_cas_to_ixr_cmd_write = true; r_cas_to_ixr_cmd_nline = m_nline[(vci_addr_t)(m_cmd_cas_addr_fifo.read())]; r_cas_to_ixr_cmd_trdid = r_cas_trt_index.read(); r_cas_fsm = CAS_IDLE; cmd_cas_fifo_get = true; r_cas_cpt = 0; #if DEBUG_MEMC_CAS if(m_debug_cas_fsm) { std::cout << " Request a PUT transaction to IXR_CMD FSM" << std::hex << " / nline = " << m_nline[(vci_addr_t) m_cmd_cas_addr_fifo.read()] << " / trt_index = " << r_cas_trt_index.read() << std::endl; } #endif } else { std::cout << "MEM_CACHE, CAS_BC_XRAM_REQ state : request should not have been previously set" << std::endl; } break; } ///////////////// case CAS_RSP_FAIL: // request TGT_RSP FSM to send a failure response { if(!r_cas_to_tgt_rsp_req) { cmd_cas_fifo_get = true; r_cas_cpt = 0; r_cas_to_tgt_rsp_req = true; r_cas_to_tgt_rsp_data = 1; r_cas_to_tgt_rsp_srcid = m_cmd_cas_srcid_fifo.read(); r_cas_to_tgt_rsp_trdid = m_cmd_cas_trdid_fifo.read(); r_cas_to_tgt_rsp_pktid = m_cmd_cas_pktid_fifo.read(); r_cas_fsm = CAS_IDLE; #if DEBUG_MEMC_CAS if(m_debug_cas_fsm) { std::cout << " Request TGT_RSP to send a failure response" << std::endl; } #endif } break; } //////////////////// case CAS_RSP_SUCCESS: // request TGT_RSP FSM to send a success response { if(!r_cas_to_tgt_rsp_req) { cmd_cas_fifo_get = true; r_cas_cpt = 0; r_cas_to_tgt_rsp_req = true; r_cas_to_tgt_rsp_data = 0; r_cas_to_tgt_rsp_srcid = m_cmd_cas_srcid_fifo.read(); r_cas_to_tgt_rsp_trdid = m_cmd_cas_trdid_fifo.read(); r_cas_to_tgt_rsp_pktid = m_cmd_cas_pktid_fifo.read(); r_cas_fsm = CAS_IDLE; #if DEBUG_MEMC_CAS if(m_debug_cas_fsm) { std::cout << " Request TGT_RSP to send a success response" << std::endl; } #endif } break; } ///////////////////// case CAS_MISS_TRT_LOCK: // cache miss : request access to transaction Table { if(r_alloc_trt_fsm.read() == ALLOC_TRT_CAS) { size_t index = 0; bool hit_read = m_transaction_tab.hit_read( m_nline[(vci_addr_t) m_cmd_cas_addr_fifo.read()],index); bool hit_write = m_transaction_tab.hit_write( m_nline[(vci_addr_t) m_cmd_cas_addr_fifo.read()]); bool wok = !m_transaction_tab.full(index); #if DEBUG_MEMC_CAS if(m_debug_cas_fsm) { std::cout << " Check TRT state" << " / hit_read = " << hit_read << " / hit_write = " << hit_write << " / wok = " << wok << " / index = " << index << std::endl; } #endif if(hit_read || !wok || hit_write) // missing line already requested or no space in TRT { r_cas_fsm = CAS_WAIT; } else { r_cas_trt_index = index; r_cas_fsm = CAS_MISS_TRT_SET; } } break; } //////////////////// case CAS_MISS_TRT_SET: // register the GET transaction in TRT { if(r_alloc_trt_fsm.read() == ALLOC_TRT_CAS) { std::vector be_vector; std::vector data_vector; be_vector.clear(); data_vector.clear(); for(size_t i=0; i Register a GET transaction in TRT" << std::hex << " / nline = " << m_nline[(vci_addr_t) m_cmd_cas_addr_fifo.read()] << " / trt_index = " << r_cas_trt_index.read() << std::endl; } #endif } break; } ////////////////////// case CAS_MISS_XRAM_REQ: // request the IXR_CMD FSM to fetch the missing line { if(!r_cas_to_ixr_cmd_req) { r_cas_to_ixr_cmd_req = true; r_cas_to_ixr_cmd_write = false; r_cas_to_ixr_cmd_trdid = r_cas_trt_index.read(); r_cas_to_ixr_cmd_nline = m_nline[(vci_addr_t) m_cmd_cas_addr_fifo.read()]; r_cas_fsm = CAS_WAIT; #if DEBUG_MEMC_CAS if(m_debug_cas_fsm) { std::cout << " Request a GET transaction to IXR_CMD FSM" << std::hex << " / nline = " << m_nline[(vci_addr_t) m_cmd_cas_addr_fifo.read()] << " / trt_index = " << r_cas_trt_index.read() << std::endl; } #endif } break; } } // end switch r_cas_fsm ////////////////////////////////////////////////////////////////////////////// // CC_SEND FSM ////////////////////////////////////////////////////////////////////////////// // The CC_SEND fsm controls the DSPIN initiator port on the coherence // network, used to update or invalidate cache lines in L1 caches. // // This fsm is used also to acknowledge CLEANUP a command after request from // the CLEANUP fsm. // // It implements a round-robin priority between the four possible client FSMs // XRAM_RSP, WRITE, CAS and CLEANUP. Each FSM can request the next services: // - r_xram_rsp_to_cc_send_multi_req : multi-inval // r_xram_rsp_to_cc_send_brdcast_req : broadcast-inval // - r_write_to_cc_send_multi_req : multi-update // r_write_to_cc_send_brdcast_req : broadcast-inval // - r_cas_to_cc_send_multi_req : multi-update // r_cas_to_cc_send_brdcast_req : broadcast-inval // - r_cleanup_to_cc_send_req : cleanup acknowledgement // // An inval request is a double DSPIN flit command containing: // 1. the index of the line to be invalidated. // // An update request is a multi-flit DSPIN command containing: // 1. the index of the cache line to be updated. // 2. the index of the first modified word in the line. // 3. the data to update /////////////////////////////////////////////////////////////////////////////// switch(r_cc_send_fsm.read()) { case CC_SEND_WRITE_IDLE: { // XRAM_RSP FSM has highest priority if(m_xram_rsp_to_cc_send_inst_fifo.rok() || r_xram_rsp_to_cc_send_multi_req.read()) { r_cc_send_fsm = CC_SEND_XRAM_RSP_INVAL_HEADER; m_cpt_inval++; break; } if(r_xram_rsp_to_cc_send_brdcast_req.read()) { r_cc_send_fsm = CC_SEND_XRAM_RSP_BRDCAST_HEADER; m_cpt_inval++; break; } if(m_cas_to_cc_send_inst_fifo.rok() || r_cas_to_cc_send_multi_req.read()) { r_cc_send_fsm = CC_SEND_CAS_UPDT_HEADER; m_cpt_update++; break; } if(r_cas_to_cc_send_brdcast_req.read()) { r_cc_send_fsm = CC_SEND_CAS_BRDCAST_HEADER; m_cpt_inval++; break; } if (r_cleanup_to_cc_send_req.read()) { r_cc_send_fsm = CC_SEND_CLEANUP_ACK; break; } if(m_write_to_cc_send_inst_fifo.rok() || r_write_to_cc_send_multi_req.read()) { r_cc_send_fsm = CC_SEND_WRITE_UPDT_HEADER; m_cpt_update++; break; } if(r_write_to_cc_send_brdcast_req.read()) { r_cc_send_fsm = CC_SEND_WRITE_BRDCAST_HEADER; m_cpt_inval++; } break; } case CC_SEND_XRAM_RSP_IDLE: { // CAS FSM has highest priority if(m_cas_to_cc_send_inst_fifo.rok() || r_cas_to_cc_send_multi_req.read()) { r_cc_send_fsm = CC_SEND_CAS_UPDT_HEADER; m_cpt_update++; break; } if(r_cas_to_cc_send_brdcast_req.read()) { r_cc_send_fsm = CC_SEND_CAS_BRDCAST_HEADER; m_cpt_inval++; break; } if(r_cleanup_to_cc_send_req.read()) { r_cc_send_fsm = CC_SEND_CLEANUP_ACK; break; } if(m_write_to_cc_send_inst_fifo.rok() || r_write_to_cc_send_multi_req.read()) { r_cc_send_fsm = CC_SEND_WRITE_UPDT_HEADER; m_cpt_update++; break; } if(r_write_to_cc_send_brdcast_req.read()) { r_cc_send_fsm = CC_SEND_WRITE_BRDCAST_HEADER; m_cpt_inval++; break; } if(m_xram_rsp_to_cc_send_inst_fifo.rok() || r_xram_rsp_to_cc_send_multi_req.read()) { r_cc_send_fsm = CC_SEND_XRAM_RSP_INVAL_HEADER; m_cpt_inval++; break; } if(r_xram_rsp_to_cc_send_brdcast_req.read()) { r_cc_send_fsm = CC_SEND_XRAM_RSP_BRDCAST_HEADER; m_cpt_inval++; } break; } case CC_SEND_CAS_IDLE: { // CLEANUP FSM has highest priority if(r_cleanup_to_cc_send_req.read()) { r_cc_send_fsm = CC_SEND_CLEANUP_ACK; break; } if(m_write_to_cc_send_inst_fifo.rok() || r_write_to_cc_send_multi_req.read()) { r_cc_send_fsm = CC_SEND_WRITE_UPDT_HEADER; m_cpt_update++; break; } if(r_write_to_cc_send_brdcast_req.read()) { r_cc_send_fsm = CC_SEND_WRITE_BRDCAST_HEADER; m_cpt_inval++; break; } if(m_xram_rsp_to_cc_send_inst_fifo.rok() || r_xram_rsp_to_cc_send_multi_req.read()) { r_cc_send_fsm = CC_SEND_XRAM_RSP_INVAL_HEADER; m_cpt_inval++; break; } if(r_xram_rsp_to_cc_send_brdcast_req.read()) { r_cc_send_fsm = CC_SEND_XRAM_RSP_BRDCAST_HEADER; m_cpt_inval++; break; } if(m_cas_to_cc_send_inst_fifo.rok() || r_cas_to_cc_send_multi_req.read()) { r_cc_send_fsm = CC_SEND_CAS_UPDT_HEADER; m_cpt_update++; break; } if(r_cas_to_cc_send_brdcast_req.read()) { r_cc_send_fsm = CC_SEND_CAS_BRDCAST_HEADER; m_cpt_inval++; } break; } case CC_SEND_CLEANUP_IDLE: { // WRITE FSM has highest priority if(m_write_to_cc_send_inst_fifo.rok() || r_write_to_cc_send_multi_req.read()) { r_cc_send_fsm = CC_SEND_WRITE_UPDT_HEADER; m_cpt_update++; break; } if(r_write_to_cc_send_brdcast_req.read()) { r_cc_send_fsm = CC_SEND_WRITE_BRDCAST_HEADER; m_cpt_inval++; break; } if(m_xram_rsp_to_cc_send_inst_fifo.rok() || r_xram_rsp_to_cc_send_multi_req.read()) { r_cc_send_fsm = CC_SEND_XRAM_RSP_INVAL_HEADER; m_cpt_inval++; break; } if(r_xram_rsp_to_cc_send_brdcast_req.read()) { r_cc_send_fsm = CC_SEND_XRAM_RSP_BRDCAST_HEADER; m_cpt_inval++; break; } if(m_cas_to_cc_send_inst_fifo.rok() || r_cas_to_cc_send_multi_req.read()) { r_cc_send_fsm = CC_SEND_CAS_UPDT_HEADER; m_cpt_update++; break; } if(r_cas_to_cc_send_brdcast_req.read()) { r_cc_send_fsm = CC_SEND_CAS_BRDCAST_HEADER; m_cpt_inval++; break; } if(r_cleanup_to_cc_send_req.read()) { r_cc_send_fsm = CC_SEND_CLEANUP_ACK; } break; } case CC_SEND_CLEANUP_ACK: { // send only flit for a cleanup acknowledgement (from CLEANUP FSM) if(not p_dspin_out.read) break; r_cleanup_to_cc_send_req = false; r_cc_send_fsm = CC_SEND_CLEANUP_IDLE; #if DEBUG_MEMC_CC_SEND if(m_debug_cc_send_fsm) { std::cout << " Cleanup Acknowledgement for srcid " << r_cleanup_to_cc_send_srcid.read() << std::endl; } #endif break; } case CC_SEND_XRAM_RSP_INVAL_HEADER: { // send first flit multi-inval (from XRAM_RSP FSM) if(m_xram_rsp_to_cc_send_inst_fifo.rok()) { if(not p_dspin_out.read) break; r_cc_send_fsm = CC_SEND_XRAM_RSP_INVAL_NLINE; break; } if(r_xram_rsp_to_cc_send_multi_req.read()) { r_xram_rsp_to_cc_send_multi_req = false; } r_cc_send_fsm = CC_SEND_XRAM_RSP_IDLE; break; } case CC_SEND_XRAM_RSP_INVAL_NLINE: { // send second flit multi-inval (from XRAM_RSP FSM) if(not p_dspin_out.read) break; m_cpt_inval_mult++; r_cc_send_fsm = CC_SEND_XRAM_RSP_INVAL_HEADER; #if DEBUG_MEMC_CC_SEND if(m_debug_cc_send_fsm) { std::cout << " Broadcast-Inval for line " << r_xram_rsp_to_cc_send_nline.read() << std::endl; } #endif break; } case CC_SEND_XRAM_RSP_BRDCAST_HEADER: { // send first flit broadcast-inval (from XRAM_RSP FSM) if(not p_dspin_out.read) break; r_cc_send_fsm = CC_SEND_XRAM_RSP_BRDCAST_NLINE; break; } case CC_SEND_XRAM_RSP_BRDCAST_NLINE: { // send second flit broadcast-inval (from XRAM_RSP FSM) if(not p_dspin_out.read) break; m_cpt_inval_brdcast++; r_xram_rsp_to_cc_send_brdcast_req = false; r_cc_send_fsm = CC_SEND_XRAM_RSP_IDLE; #if DEBUG_MEMC_CC_SEND if(m_debug_cc_send_fsm) { std::cout << " Broadcast-Inval for line " << r_xram_rsp_to_cc_send_nline.read() << std::endl; } #endif break; } case CC_SEND_WRITE_BRDCAST_HEADER: { // send first flit broadcast-inval (from WRITE FSM) if(not p_dspin_out.read) break; r_cc_send_fsm = CC_SEND_WRITE_BRDCAST_NLINE; break; } case CC_SEND_WRITE_BRDCAST_NLINE: { // send second flit broadcast-inval (from WRITE FSM) if(not p_dspin_out.read) break; m_cpt_inval_brdcast++; r_write_to_cc_send_brdcast_req = false; r_cc_send_fsm = CC_SEND_WRITE_IDLE; #if DEBUG_MEMC_CC_SEND if(m_debug_cc_send_fsm) { std::cout << " Broadcast-Inval for line " << r_write_to_cc_send_nline.read() << std::endl; } #endif break; } case CC_SEND_WRITE_UPDT_HEADER: { // send first flit for a multi-update (from WRITE FSM) if(m_write_to_cc_send_inst_fifo.rok()) { if(not p_dspin_out.read) break; r_cc_send_fsm = CC_SEND_WRITE_UPDT_NLINE; break; } if(r_write_to_cc_send_multi_req.read()) { r_write_to_cc_send_multi_req = false; } r_cc_send_fsm = CC_SEND_WRITE_IDLE; break; } case CC_SEND_WRITE_UPDT_NLINE: { // send second flit for a multi-update (from WRITE FSM) if(not p_dspin_out.read) break; m_cpt_update_mult++; r_cc_send_cpt = 0; r_cc_send_fsm = CC_SEND_WRITE_UPDT_DATA; #if DEBUG_MEMC_CC_SEND if(m_debug_cc_send_fsm) { std::cout << " Multicast-Update for line " << r_write_to_cc_send_nline.read() << std::endl; } #endif break; } case CC_SEND_WRITE_UPDT_DATA: { // send N data flits for a multi-update (from WRITE FSM) if(not p_dspin_out.read) break; if(r_cc_send_cpt.read() == (r_write_to_cc_send_count.read()-1)) { write_to_cc_send_fifo_get = true; r_cc_send_fsm = CC_SEND_WRITE_UPDT_HEADER; break; } r_cc_send_cpt = r_cc_send_cpt.read() + 1; break; } case CC_SEND_CAS_BRDCAST_HEADER: { // send first flit for a broadcast-inval (from CAS FSM) if(not p_dspin_out.read) break; r_cc_send_fsm = CC_SEND_CAS_BRDCAST_NLINE; break; } case CC_SEND_CAS_BRDCAST_NLINE: { // send second flit broadcast-inval (from CAS FSM) if(not p_dspin_out.read) break; m_cpt_inval_brdcast++; r_cas_to_cc_send_brdcast_req = false; r_cc_send_fsm = CC_SEND_CAS_IDLE; #if DEBUG_MEMC_CC_SEND if(m_debug_cc_send_fsm) { std::cout << " Broadcast-Inval for line " << r_cas_to_cc_send_nline.read() << std::endl; } #endif break; } case CC_SEND_CAS_UPDT_HEADER: { // send first flit for a multi-update (from CAS FSM) if(m_cas_to_cc_send_inst_fifo.rok()) { if(not p_dspin_out.read) break; r_cc_send_fsm = CC_SEND_CAS_UPDT_NLINE; break; } // no more packets to send for the multi-update if(r_cas_to_cc_send_multi_req.read()) { r_cas_to_cc_send_multi_req = false; } r_cc_send_fsm = CC_SEND_CAS_IDLE; break; } case CC_SEND_CAS_UPDT_NLINE: { // send second flit for a multi-update (from CAS FSM) if(not p_dspin_out.read) break; m_cpt_update_mult++; r_cc_send_cpt = 0; r_cc_send_fsm = CC_SEND_CAS_UPDT_DATA; #if DEBUG_MEMC_CC_SEND if(m_debug_cc_send_fsm) { std::cout << " Multicast-Update for line " << r_cas_to_cc_send_nline.read() << std::endl; } #endif break; } case CC_SEND_CAS_UPDT_DATA: { // send first data for a multi-update (from CAS FSM) if(not p_dspin_out.read) break; if(r_cas_to_cc_send_is_long.read()) { r_cc_send_fsm = CC_SEND_CAS_UPDT_DATA_HIGH; break; } cas_to_cc_send_fifo_get = true; r_cc_send_fsm = CC_SEND_CAS_UPDT_HEADER; break; } case CC_SEND_CAS_UPDT_DATA_HIGH: { // send second data for a multi-update (from CAS FSM) if(not p_dspin_out.read) break; cas_to_cc_send_fifo_get = true; r_cc_send_fsm = CC_SEND_CAS_UPDT_HEADER; break; } } // end switch r_cc_send_fsm ////////////////////////////////////////////////////////////////////////////// // CC_RECEIVE FSM ////////////////////////////////////////////////////////////////////////////// // The CC_RECEIVE fsm controls the DSPIN target port on the coherence // network. /////////////////////////////////////////////////////////////////////////////// switch(r_cc_receive_fsm.read()) { case CC_RECEIVE_IDLE: { if(not p_dspin_in.write) break; uint8_t type = DspinDhccpParam::dspin_get( p_dspin_in.data.read(), DspinDhccpParam::FROM_L1_TYPE); if((type == DspinDhccpParam::TYPE_CLEANUP_DATA) || (type == DspinDhccpParam::TYPE_CLEANUP_INST) ) { r_cc_receive_fsm = CC_RECEIVE_CLEANUP; break; } if(type == DspinDhccpParam::TYPE_MULTI_ACK) { r_cc_receive_fsm = CC_RECEIVE_MULTI_ACK; break; } assert( false && "VCI_MEM_CACHE ERROR: Incorrect type in coherence request from " "L1 Cache"); break; } case CC_RECEIVE_CLEANUP: { // wait for a valid cleanup flit // wait for a WOK in the CC_RECEIVE to CLEANUP fifo if(not p_dspin_in.write or not m_cc_receive_to_cleanup_fifo.wok()) break; bool eop = ( DspinDhccpParam::dspin_get( p_dspin_in.data.read(), DspinDhccpParam::FROM_L1_EOP) == 0x1); cc_receive_to_cleanup_fifo_put = true; if(eop) { r_cc_receive_fsm = CC_RECEIVE_IDLE; } break; } case CC_RECEIVE_MULTI_ACK: { // wait for a valid multicast acknowledgement flit // wait for a WOK in the CC_RECEIVE to MULTI_ACK fifo if(not p_dspin_in.write or not m_cc_receive_to_multi_ack_fifo.wok()) break; bool eop = ( DspinDhccpParam::dspin_get( p_dspin_in.data.read(), DspinDhccpParam::FROM_L1_EOP) == 0x1); cc_receive_to_multi_ack_fifo_put = true; if(eop) { r_cc_receive_fsm = CC_RECEIVE_IDLE; } break; } default: { assert( false && "VCI_MEM_CACHE ERROR: Invalid state in CC_RECEIVE FSM"); } } ///////////////////////////////////////////////////////////////////// // TGT_RSP FSM ///////////////////////////////////////////////////////////////////// // The TGT_RSP fsm sends the responses on the VCI target port // with a round robin priority between six requests : // - r_read_to_tgt_rsp_req // - r_write_to_tgt_rsp_req // - r_cas_to_tgt_rsp_req // - r_cleanup_to_tgt_rsp_req // - r_xram_rsp_to_tgt_rsp_req // - r_multi_ack_to_tgt_rsp_req // The ordering is : read > write > cas > xram > init > cleanup ///////////////////////////////////////////////////////////////////// switch(r_tgt_rsp_fsm.read()) { case TGT_RSP_READ_IDLE: { // write requests have the highest priority if(r_write_to_tgt_rsp_req) r_tgt_rsp_fsm = TGT_RSP_WRITE; else if(r_cas_to_tgt_rsp_req) r_tgt_rsp_fsm = TGT_RSP_CAS ; else if(r_xram_rsp_to_tgt_rsp_req) { r_tgt_rsp_fsm = TGT_RSP_XRAM; r_tgt_rsp_cpt = r_xram_rsp_to_tgt_rsp_word.read(); } else if(r_multi_ack_to_tgt_rsp_req) r_tgt_rsp_fsm = TGT_RSP_INIT ; else if(r_cleanup_to_tgt_rsp_req) r_tgt_rsp_fsm = TGT_RSP_CLEANUP; else if(r_read_to_tgt_rsp_req) { r_tgt_rsp_fsm = TGT_RSP_READ; r_tgt_rsp_cpt = r_read_to_tgt_rsp_word.read(); } break; } //////////////////////// case TGT_RSP_WRITE_IDLE: // cas requests have the highest priority { if(r_cas_to_tgt_rsp_req) r_tgt_rsp_fsm = TGT_RSP_CAS; else if(r_xram_rsp_to_tgt_rsp_req) { r_tgt_rsp_fsm = TGT_RSP_XRAM; r_tgt_rsp_cpt = r_xram_rsp_to_tgt_rsp_word.read(); } else if(r_multi_ack_to_tgt_rsp_req) r_tgt_rsp_fsm = TGT_RSP_INIT ; else if(r_cleanup_to_tgt_rsp_req) r_tgt_rsp_fsm = TGT_RSP_CLEANUP; else if(r_read_to_tgt_rsp_req) { r_tgt_rsp_fsm = TGT_RSP_READ; r_tgt_rsp_cpt = r_read_to_tgt_rsp_word.read(); } else if(r_write_to_tgt_rsp_req) r_tgt_rsp_fsm = TGT_RSP_WRITE; break; } /////////////////////// case TGT_RSP_CAS_IDLE: // xram_rsp requests have the highest priority { if(r_xram_rsp_to_tgt_rsp_req) { r_tgt_rsp_fsm = TGT_RSP_XRAM; r_tgt_rsp_cpt = r_xram_rsp_to_tgt_rsp_word.read(); } else if(r_multi_ack_to_tgt_rsp_req) r_tgt_rsp_fsm = TGT_RSP_INIT ; else if(r_cleanup_to_tgt_rsp_req) r_tgt_rsp_fsm = TGT_RSP_CLEANUP; else if(r_read_to_tgt_rsp_req) { r_tgt_rsp_fsm = TGT_RSP_READ; r_tgt_rsp_cpt = r_read_to_tgt_rsp_word.read(); } else if(r_write_to_tgt_rsp_req) r_tgt_rsp_fsm = TGT_RSP_WRITE; else if(r_cas_to_tgt_rsp_req) r_tgt_rsp_fsm = TGT_RSP_CAS ; break; } /////////////////////// case TGT_RSP_XRAM_IDLE: // init requests have the highest priority { if(r_multi_ack_to_tgt_rsp_req) r_tgt_rsp_fsm = TGT_RSP_INIT ; else if(r_cleanup_to_tgt_rsp_req) r_tgt_rsp_fsm = TGT_RSP_CLEANUP; else if(r_read_to_tgt_rsp_req) { r_tgt_rsp_fsm = TGT_RSP_READ; r_tgt_rsp_cpt = r_read_to_tgt_rsp_word.read(); } else if(r_write_to_tgt_rsp_req) r_tgt_rsp_fsm = TGT_RSP_WRITE; else if(r_cas_to_tgt_rsp_req) r_tgt_rsp_fsm = TGT_RSP_CAS ; else if(r_xram_rsp_to_tgt_rsp_req) { r_tgt_rsp_fsm = TGT_RSP_XRAM; r_tgt_rsp_cpt = r_xram_rsp_to_tgt_rsp_word.read(); } break; } /////////////////////// case TGT_RSP_INIT_IDLE: // cleanup requests have the highest priority { if(r_cleanup_to_tgt_rsp_req) r_tgt_rsp_fsm = TGT_RSP_CLEANUP; else if(r_read_to_tgt_rsp_req) { r_tgt_rsp_fsm = TGT_RSP_READ; r_tgt_rsp_cpt = r_read_to_tgt_rsp_word.read(); } else if(r_write_to_tgt_rsp_req) r_tgt_rsp_fsm = TGT_RSP_WRITE; else if(r_cas_to_tgt_rsp_req) r_tgt_rsp_fsm = TGT_RSP_CAS ; else if(r_xram_rsp_to_tgt_rsp_req) { r_tgt_rsp_fsm = TGT_RSP_XRAM; r_tgt_rsp_cpt = r_xram_rsp_to_tgt_rsp_word.read(); } else if(r_multi_ack_to_tgt_rsp_req) r_tgt_rsp_fsm = TGT_RSP_INIT; break; } /////////////////////// case TGT_RSP_CLEANUP_IDLE: // read requests have the highest priority { if(r_read_to_tgt_rsp_req) { r_tgt_rsp_fsm = TGT_RSP_READ; r_tgt_rsp_cpt = r_read_to_tgt_rsp_word.read(); } else if(r_write_to_tgt_rsp_req) r_tgt_rsp_fsm = TGT_RSP_WRITE; else if(r_cas_to_tgt_rsp_req) r_tgt_rsp_fsm = TGT_RSP_CAS ; else if(r_xram_rsp_to_tgt_rsp_req) { r_tgt_rsp_fsm = TGT_RSP_XRAM; r_tgt_rsp_cpt = r_xram_rsp_to_tgt_rsp_word.read(); } else if(r_multi_ack_to_tgt_rsp_req) r_tgt_rsp_fsm = TGT_RSP_INIT ; else if(r_cleanup_to_tgt_rsp_req) r_tgt_rsp_fsm = TGT_RSP_CLEANUP; break; } ////////////////// case TGT_RSP_READ: // send the response to a read { if(p_vci_tgt.rspack) { #if DEBUG_MEMC_TGT_RSP if(m_debug_tgt_rsp_fsm) { std::cout << " Read response" << " / rsrcid = " << std::dec << r_read_to_tgt_rsp_srcid.read() << " / rtrdid = " << r_read_to_tgt_rsp_trdid.read() << " / rpktid = " << r_read_to_tgt_rsp_pktid.read() << " / rdata = " << std::hex << r_read_to_tgt_rsp_data[r_tgt_rsp_cpt.read()].read() << " / cpt = " << std::dec << r_tgt_rsp_cpt.read() << std::endl; } #endif if(r_tgt_rsp_cpt.read() == (r_read_to_tgt_rsp_word.read() +r_read_to_tgt_rsp_length-1)) { r_tgt_rsp_fsm = TGT_RSP_READ_IDLE; r_read_to_tgt_rsp_req = false; } else { r_tgt_rsp_cpt = r_tgt_rsp_cpt.read() + 1; } } break; } /////////////////// case TGT_RSP_WRITE: // send the write acknowledge { if(p_vci_tgt.rspack) { #if DEBUG_MEMC_TGT_RSP if(m_debug_tgt_rsp_fsm) { std::cout << " Write response" << " / rsrcid = " << std::dec << r_write_to_tgt_rsp_srcid.read() << " / rtrdid = " << r_write_to_tgt_rsp_trdid.read() << " / rpktid = " << r_write_to_tgt_rsp_pktid.read() << std::endl; } #endif r_tgt_rsp_fsm = TGT_RSP_WRITE_IDLE; r_write_to_tgt_rsp_req = false; } break; } /////////////////// case TGT_RSP_CLEANUP: // pas clair pour moi (AG) { if(p_vci_tgt.rspack) { #if DEBUG_MEMC_TGT_RSP if(m_debug_tgt_rsp_fsm) { std::cout << " Cleanup response" << " / rsrcid = " << std::dec << r_cleanup_to_tgt_rsp_srcid.read() << " / rtrdid = " << r_cleanup_to_tgt_rsp_trdid.read() << " / rpktid = " << r_cleanup_to_tgt_rsp_pktid.read() << std::endl; } #endif r_tgt_rsp_fsm = TGT_RSP_CLEANUP_IDLE; r_cleanup_to_tgt_rsp_req = false; } break; } ////////////////// case TGT_RSP_CAS: // send one atomic word response { if(p_vci_tgt.rspack) { #if DEBUG_MEMC_TGT_RSP if(m_debug_tgt_rsp_fsm) { std::cout << " CAS response" << " / rsrcid = " << std::dec << r_cas_to_tgt_rsp_srcid.read() << " / rtrdid = " << r_cas_to_tgt_rsp_trdid.read() << " / rpktid = " << r_cas_to_tgt_rsp_pktid.read() << std::endl; } #endif r_tgt_rsp_fsm = TGT_RSP_CAS_IDLE; r_cas_to_tgt_rsp_req = false; } break; } /////////////////////// case TGT_RSP_XRAM: // send the response after XRAM access { if(p_vci_tgt.rspack) { #if DEBUG_MEMC_TGT_RSP if(m_debug_tgt_rsp_fsm) { std::cout << " Response following XRAM access" << " / rsrcid = " << std::dec << r_xram_rsp_to_tgt_rsp_srcid.read() << " / rtrdid = " << r_xram_rsp_to_tgt_rsp_trdid.read() << " / rpktid = " << r_xram_rsp_to_tgt_rsp_pktid.read() << " / rdata = " << std::hex << r_xram_rsp_to_tgt_rsp_data[r_tgt_rsp_cpt.read()].read() << " / cpt = " << std::dec << r_tgt_rsp_cpt.read() << std::endl; } #endif if((r_tgt_rsp_cpt.read() == (r_xram_rsp_to_tgt_rsp_word.read() +r_xram_rsp_to_tgt_rsp_length.read()-1)) || r_xram_rsp_to_tgt_rsp_rerror.read()) { r_tgt_rsp_fsm = TGT_RSP_XRAM_IDLE; r_xram_rsp_to_tgt_rsp_req = false; } else { r_tgt_rsp_cpt = r_tgt_rsp_cpt.read() + 1; } } break; } ////////////////// case TGT_RSP_INIT: // send the write response after coherence transaction { if(p_vci_tgt.rspack) { #if DEBUG_MEMC_TGT_RSP if(m_debug_tgt_rsp_fsm) { std::cout << " Write response after coherence transaction" << " / rsrcid = " << std::dec << r_multi_ack_to_tgt_rsp_srcid.read() << " / rtrdid = " << r_multi_ack_to_tgt_rsp_trdid.read() << " / rpktid = " << r_multi_ack_to_tgt_rsp_pktid.read() << std::endl; } #endif r_tgt_rsp_fsm = TGT_RSP_INIT_IDLE; r_multi_ack_to_tgt_rsp_req = false; } break; } } // end switch tgt_rsp_fsm //////////////////////////////////////////////////////////////////////////////////// // ALLOC_UPT FSM //////////////////////////////////////////////////////////////////////////////////// // The ALLOC_UPT FSM allocates the access to the Update/Inval Table (UPT). // with a round robin priority between three FSMs : MULTI_ACK > WRITE > XRAM_RSP > CLEANUP // - The WRITE FSM initiates update transactions and sets new entry in UPT. // - The XRAM_RSP FSM initiates inval transactions and sets new entry in UPT. // - The MULTI_ACK FSM complete those trasactions and erase the UPT entry. // - The CLEANUP FSM decrement an entry in UPT. // The resource is always allocated. ///////////////////////////////////////////////////////////////////////////////////// switch(r_alloc_upt_fsm.read()) { //////////////////////// case ALLOC_UPT_MULTI_ACK: if((r_multi_ack_fsm.read() != MULTI_ACK_UPT_LOCK) && (r_multi_ack_fsm.read() != MULTI_ACK_UPT_CLEAR)) { if((r_write_fsm.read() == WRITE_UPT_LOCK) || (r_write_fsm.read() == WRITE_BC_UPT_LOCK)) r_alloc_upt_fsm = ALLOC_UPT_WRITE; else if(r_xram_rsp_fsm.read() == XRAM_RSP_INVAL_LOCK) r_alloc_upt_fsm = ALLOC_UPT_XRAM_RSP; else if(r_cleanup_fsm.read() == CLEANUP_UPT_LOCK) r_alloc_upt_fsm = ALLOC_UPT_CLEANUP; else if((r_cas_fsm.read() == CAS_UPT_LOCK) || (r_cas_fsm.read() == CAS_BC_UPT_LOCK)) r_alloc_upt_fsm = ALLOC_UPT_CAS; } break; ///////////////////// case ALLOC_UPT_WRITE: if((r_write_fsm.read() != WRITE_UPT_LOCK) && (r_write_fsm.read() != WRITE_BC_UPT_LOCK)) { if(r_xram_rsp_fsm.read() == XRAM_RSP_INVAL_LOCK) r_alloc_upt_fsm = ALLOC_UPT_XRAM_RSP; else if(r_cleanup_fsm.read() == CLEANUP_UPT_LOCK) r_alloc_upt_fsm = ALLOC_UPT_CLEANUP; else if((r_cas_fsm.read() == CAS_UPT_LOCK) || (r_cas_fsm.read() == CAS_BC_UPT_LOCK)) r_alloc_upt_fsm = ALLOC_UPT_CAS; else if(r_multi_ack_fsm.read() == MULTI_ACK_UPT_LOCK) r_alloc_upt_fsm = ALLOC_UPT_MULTI_ACK; } break; //////////////////////// case ALLOC_UPT_XRAM_RSP: if(r_xram_rsp_fsm.read() != XRAM_RSP_INVAL_LOCK) { if(r_cleanup_fsm.read() == CLEANUP_UPT_LOCK) r_alloc_upt_fsm = ALLOC_UPT_CLEANUP; else if((r_cas_fsm.read() == CAS_UPT_LOCK) || (r_cas_fsm.read() == CAS_BC_UPT_LOCK)) r_alloc_upt_fsm = ALLOC_UPT_CAS; else if(r_multi_ack_fsm.read() == MULTI_ACK_UPT_LOCK) r_alloc_upt_fsm = ALLOC_UPT_MULTI_ACK; else if((r_write_fsm.read() == WRITE_UPT_LOCK) || (r_write_fsm.read() == WRITE_BC_UPT_LOCK)) r_alloc_upt_fsm = ALLOC_UPT_WRITE; } break; ////////////////////////// case ALLOC_UPT_CLEANUP: if(r_cleanup_fsm.read() != CLEANUP_UPT_LOCK) { if((r_cas_fsm.read() == CAS_UPT_LOCK) || (r_cas_fsm.read() == CAS_BC_UPT_LOCK)) r_alloc_upt_fsm = ALLOC_UPT_CAS; else if(r_multi_ack_fsm.read() == MULTI_ACK_UPT_LOCK) r_alloc_upt_fsm = ALLOC_UPT_MULTI_ACK; else if((r_write_fsm.read() == WRITE_UPT_LOCK) || (r_write_fsm.read() == WRITE_BC_UPT_LOCK)) r_alloc_upt_fsm = ALLOC_UPT_WRITE; else if(r_xram_rsp_fsm.read() == XRAM_RSP_INVAL_LOCK) r_alloc_upt_fsm = ALLOC_UPT_XRAM_RSP; } break; ////////////////////////// case ALLOC_UPT_CAS: if((r_cas_fsm.read() != CAS_UPT_LOCK) && (r_cas_fsm.read() != CAS_BC_UPT_LOCK)) { if(r_multi_ack_fsm.read() == MULTI_ACK_UPT_LOCK) r_alloc_upt_fsm = ALLOC_UPT_MULTI_ACK; else if((r_write_fsm.read() == WRITE_UPT_LOCK) || (r_write_fsm.read() == WRITE_BC_UPT_LOCK)) r_alloc_upt_fsm = ALLOC_UPT_WRITE; else if(r_xram_rsp_fsm.read() == XRAM_RSP_INVAL_LOCK) r_alloc_upt_fsm = ALLOC_UPT_XRAM_RSP; else if(r_cleanup_fsm.read() == CLEANUP_UPT_LOCK) r_alloc_upt_fsm = ALLOC_UPT_CLEANUP; } break; } // end switch r_alloc_upt_fsm //////////////////////////////////////////////////////////////////////////////////// // ALLOC_DIR FSM //////////////////////////////////////////////////////////////////////////////////// // The ALLOC_DIR FSM allocates the access to the directory and // the data cache with a round robin priority between 5 user FSMs : // The cyclic ordering is READ > WRITE > CAS > CLEANUP > XRAM_RSP // The ressource is always allocated. ///////////////////////////////////////////////////////////////////////////////////// switch(r_alloc_dir_fsm.read()) { case ALLOC_DIR_RESET: // Initializes the directory one SET each cycle. All the WAYS of a SET are // initialize in parallel r_alloc_dir_reset_cpt.write(r_alloc_dir_reset_cpt.read() + 1); if(r_alloc_dir_reset_cpt.read() == (m_sets - 1)) { m_cache_directory.init(); r_alloc_dir_fsm = ALLOC_DIR_READ; } break; //////////////////// case ALLOC_DIR_READ: if(((r_read_fsm.read() != READ_DIR_REQ) && (r_read_fsm.read() != READ_DIR_LOCK) && (r_read_fsm.read() != READ_TRT_LOCK) && (r_read_fsm.read() != READ_HEAP_REQ)) || ((r_read_fsm.read() == READ_TRT_LOCK) && (r_alloc_trt_fsm.read() == ALLOC_TRT_READ))) { if(r_write_fsm.read() == WRITE_DIR_REQ) r_alloc_dir_fsm = ALLOC_DIR_WRITE; else if(r_cas_fsm.read() == CAS_DIR_REQ) r_alloc_dir_fsm = ALLOC_DIR_CAS; else if(r_cleanup_fsm.read() == CLEANUP_DIR_REQ) r_alloc_dir_fsm = ALLOC_DIR_CLEANUP; else if(r_xram_rsp_fsm.read() == XRAM_RSP_DIR_LOCK) r_alloc_dir_fsm = ALLOC_DIR_XRAM_RSP; } break; ///////////////////// case ALLOC_DIR_WRITE: if(((r_write_fsm.read() != WRITE_DIR_REQ) && (r_write_fsm.read() != WRITE_DIR_LOCK) && (r_write_fsm.read() != WRITE_DIR_READ) && (r_write_fsm.read() != WRITE_DIR_HIT) && (r_write_fsm.read() != WRITE_BC_TRT_LOCK) && (r_write_fsm.read() != WRITE_BC_UPT_LOCK) && (r_write_fsm.read() != WRITE_MISS_TRT_LOCK) && (r_write_fsm.read() != WRITE_UPT_LOCK) && (r_write_fsm.read() != WRITE_UPT_HEAP_LOCK)) || ((r_write_fsm.read() == WRITE_UPT_HEAP_LOCK) && (r_alloc_heap_fsm.read() == ALLOC_HEAP_WRITE)) || ((r_write_fsm.read() == WRITE_MISS_TRT_LOCK) && (r_alloc_trt_fsm.read() == ALLOC_TRT_WRITE))) { if(r_cas_fsm.read() == CAS_DIR_REQ) r_alloc_dir_fsm = ALLOC_DIR_CAS; else if(r_cleanup_fsm.read() == CLEANUP_DIR_REQ) r_alloc_dir_fsm = ALLOC_DIR_CLEANUP; else if(r_xram_rsp_fsm.read() == XRAM_RSP_DIR_LOCK) r_alloc_dir_fsm = ALLOC_DIR_XRAM_RSP; else if(r_read_fsm.read() == READ_DIR_REQ) r_alloc_dir_fsm = ALLOC_DIR_READ; } break; //////////////////// case ALLOC_DIR_CAS: if(((r_cas_fsm.read() != CAS_DIR_REQ) && (r_cas_fsm.read() != CAS_DIR_LOCK) && (r_cas_fsm.read() != CAS_DIR_HIT_READ) && (r_cas_fsm.read() != CAS_DIR_HIT_COMPARE) && (r_cas_fsm.read() != CAS_DIR_HIT_WRITE) && (r_cas_fsm.read() != CAS_BC_TRT_LOCK) && (r_cas_fsm.read() != CAS_BC_UPT_LOCK) && (r_cas_fsm.read() != CAS_MISS_TRT_LOCK) && (r_cas_fsm.read() != CAS_UPT_LOCK) && (r_cas_fsm.read() != CAS_UPT_HEAP_LOCK)) || ((r_cas_fsm.read() == CAS_UPT_HEAP_LOCK) && (r_alloc_heap_fsm.read() == ALLOC_HEAP_CAS)) || ((r_cas_fsm.read() == CAS_MISS_TRT_LOCK) && (r_alloc_trt_fsm.read() == ALLOC_TRT_CAS))) { if(r_cleanup_fsm.read() == CLEANUP_DIR_REQ) r_alloc_dir_fsm = ALLOC_DIR_CLEANUP; else if(r_xram_rsp_fsm.read() == XRAM_RSP_DIR_LOCK) r_alloc_dir_fsm = ALLOC_DIR_XRAM_RSP; else if(r_read_fsm.read() == READ_DIR_REQ) r_alloc_dir_fsm = ALLOC_DIR_READ; else if(r_write_fsm.read() == WRITE_DIR_REQ) r_alloc_dir_fsm = ALLOC_DIR_WRITE; } break; /////////////////////// case ALLOC_DIR_CLEANUP: if((r_cleanup_fsm.read() != CLEANUP_DIR_REQ) && (r_cleanup_fsm.read() != CLEANUP_DIR_LOCK) && (r_cleanup_fsm.read() != CLEANUP_HEAP_REQ) && (r_cleanup_fsm.read() != CLEANUP_HEAP_LOCK)) { if(r_xram_rsp_fsm.read() == XRAM_RSP_DIR_LOCK) r_alloc_dir_fsm = ALLOC_DIR_XRAM_RSP; else if(r_read_fsm.read() == READ_DIR_REQ) r_alloc_dir_fsm = ALLOC_DIR_READ; else if(r_write_fsm.read() == WRITE_DIR_REQ) r_alloc_dir_fsm = ALLOC_DIR_WRITE; else if(r_cas_fsm.read() == CAS_DIR_REQ) r_alloc_dir_fsm = ALLOC_DIR_CAS; } break; //////////////////////// case ALLOC_DIR_XRAM_RSP: if((r_xram_rsp_fsm.read() != XRAM_RSP_DIR_LOCK) && (r_xram_rsp_fsm.read() != XRAM_RSP_TRT_COPY) && (r_xram_rsp_fsm.read() != XRAM_RSP_INVAL_LOCK)) { if(r_read_fsm.read() == READ_DIR_REQ) r_alloc_dir_fsm = ALLOC_DIR_READ; else if(r_write_fsm.read() == WRITE_DIR_REQ) r_alloc_dir_fsm = ALLOC_DIR_WRITE; else if(r_cas_fsm.read() == CAS_DIR_REQ) r_alloc_dir_fsm = ALLOC_DIR_CAS; else if(r_cleanup_fsm.read() == CLEANUP_DIR_REQ) r_alloc_dir_fsm = ALLOC_DIR_CLEANUP; } break; } // end switch alloc_dir_fsm //////////////////////////////////////////////////////////////////////////////////// // ALLOC_TRT FSM //////////////////////////////////////////////////////////////////////////////////// // The ALLOC_TRT fsm allocates the access to the Transaction Table (write buffer) // with a round robin priority between 4 user FSMs : // The cyclic priority is READ > WRITE > CAS > XRAM_RSP // The ressource is always allocated. /////////////////////////////////////////////////////////////////////////////////// switch(r_alloc_trt_fsm.read()) { //////////////////// case ALLOC_TRT_READ: if(r_read_fsm.read() != READ_TRT_LOCK) { if((r_write_fsm.read() == WRITE_MISS_TRT_LOCK) || (r_write_fsm.read() == WRITE_BC_TRT_LOCK)) r_alloc_trt_fsm = ALLOC_TRT_WRITE; else if((r_cas_fsm.read() == CAS_MISS_TRT_LOCK) || (r_cas_fsm.read() == CAS_BC_TRT_LOCK)) r_alloc_trt_fsm = ALLOC_TRT_CAS; else if((r_xram_rsp_fsm.read() == XRAM_RSP_DIR_LOCK) && (r_alloc_dir_fsm.read() == ALLOC_DIR_XRAM_RSP)) r_alloc_trt_fsm = ALLOC_TRT_XRAM_RSP; else if((r_ixr_rsp_fsm.read() == IXR_RSP_TRT_ERASE) || (r_ixr_rsp_fsm.read() == IXR_RSP_TRT_READ)) r_alloc_trt_fsm = ALLOC_TRT_IXR_RSP; } break; ///////////////////// case ALLOC_TRT_WRITE: if((r_write_fsm.read() != WRITE_MISS_TRT_LOCK) && (r_write_fsm.read() != WRITE_BC_TRT_LOCK) && (r_write_fsm.read() != WRITE_BC_UPT_LOCK)) { if((r_cas_fsm.read() == CAS_MISS_TRT_LOCK) || (r_cas_fsm.read() == CAS_BC_TRT_LOCK)) r_alloc_trt_fsm = ALLOC_TRT_CAS; else if((r_xram_rsp_fsm.read() == XRAM_RSP_DIR_LOCK) && (r_alloc_dir_fsm.read() == ALLOC_DIR_XRAM_RSP)) r_alloc_trt_fsm = ALLOC_TRT_XRAM_RSP; else if((r_ixr_rsp_fsm.read() == IXR_RSP_TRT_ERASE) || (r_ixr_rsp_fsm.read() == IXR_RSP_TRT_READ)) r_alloc_trt_fsm = ALLOC_TRT_IXR_RSP; else if(r_read_fsm.read() == READ_TRT_LOCK) r_alloc_trt_fsm = ALLOC_TRT_READ; } break; //////////////////// case ALLOC_TRT_CAS: if((r_cas_fsm.read() != CAS_MISS_TRT_LOCK) && (r_cas_fsm.read() != CAS_BC_TRT_LOCK) && (r_cas_fsm.read() != CAS_BC_UPT_LOCK)) { if((r_xram_rsp_fsm.read() == XRAM_RSP_DIR_LOCK) && (r_alloc_dir_fsm.read() == ALLOC_DIR_XRAM_RSP)) r_alloc_trt_fsm = ALLOC_TRT_XRAM_RSP; else if((r_ixr_rsp_fsm.read() == IXR_RSP_TRT_ERASE) || (r_ixr_rsp_fsm.read() == IXR_RSP_TRT_READ)) r_alloc_trt_fsm = ALLOC_TRT_IXR_RSP; else if(r_read_fsm.read() == READ_TRT_LOCK) r_alloc_trt_fsm = ALLOC_TRT_READ; else if((r_write_fsm.read() == WRITE_MISS_TRT_LOCK) || (r_write_fsm.read() == WRITE_BC_TRT_LOCK)) r_alloc_trt_fsm = ALLOC_TRT_WRITE; } break; //////////////////////// case ALLOC_TRT_XRAM_RSP: if(((r_xram_rsp_fsm.read() != XRAM_RSP_DIR_LOCK) || (r_alloc_dir_fsm.read() != ALLOC_DIR_XRAM_RSP)) && (r_xram_rsp_fsm.read() != XRAM_RSP_TRT_COPY) && (r_xram_rsp_fsm.read() != XRAM_RSP_DIR_UPDT) && (r_xram_rsp_fsm.read() != XRAM_RSP_INVAL_LOCK)) { if((r_ixr_rsp_fsm.read() == IXR_RSP_TRT_ERASE) || (r_ixr_rsp_fsm.read() == IXR_RSP_TRT_READ)) r_alloc_trt_fsm = ALLOC_TRT_IXR_RSP; else if(r_read_fsm.read() == READ_TRT_LOCK) r_alloc_trt_fsm = ALLOC_TRT_READ; else if((r_write_fsm.read() == WRITE_MISS_TRT_LOCK) || (r_write_fsm.read() == WRITE_BC_TRT_LOCK)) r_alloc_trt_fsm = ALLOC_TRT_WRITE; else if((r_cas_fsm.read() == CAS_MISS_TRT_LOCK) || (r_cas_fsm.read() == CAS_BC_TRT_LOCK)) r_alloc_trt_fsm = ALLOC_TRT_CAS; } break; //////////////////////// case ALLOC_TRT_IXR_RSP: if((r_ixr_rsp_fsm.read() != IXR_RSP_TRT_ERASE) && (r_ixr_rsp_fsm.read() != IXR_RSP_TRT_READ)) { if(r_read_fsm.read() == READ_TRT_LOCK) r_alloc_trt_fsm = ALLOC_TRT_READ; else if((r_write_fsm.read() == WRITE_MISS_TRT_LOCK) || (r_write_fsm.read() == WRITE_BC_TRT_LOCK)) r_alloc_trt_fsm = ALLOC_TRT_WRITE; else if((r_cas_fsm.read() == CAS_MISS_TRT_LOCK) || (r_cas_fsm.read() == CAS_BC_TRT_LOCK)) r_alloc_trt_fsm = ALLOC_TRT_CAS; else if((r_xram_rsp_fsm.read() == XRAM_RSP_DIR_LOCK) && (r_alloc_dir_fsm.read() == ALLOC_DIR_XRAM_RSP)) r_alloc_trt_fsm = ALLOC_TRT_XRAM_RSP; } break; } // end switch alloc_trt_fsm //////////////////////////////////////////////////////////////////////////////////// // ALLOC_HEAP FSM //////////////////////////////////////////////////////////////////////////////////// // The ALLOC_HEAP FSM allocates the access to the heap // with a round robin priority between 5 user FSMs : // The cyclic ordering is READ > WRITE > CAS > CLEANUP > XRAM_RSP // The ressource is always allocated. ///////////////////////////////////////////////////////////////////////////////////// switch(r_alloc_heap_fsm.read()) { //////////////////// case ALLOC_HEAP_RESET: // Initializes the heap one ENTRY each cycle. r_alloc_heap_reset_cpt.write(r_alloc_heap_reset_cpt.read() + 1); if(r_alloc_heap_reset_cpt.read() == (m_heap_size-1)) { m_heap.init(); r_alloc_heap_fsm = ALLOC_HEAP_READ; } break; //////////////////// case ALLOC_HEAP_READ: if((r_read_fsm.read() != READ_HEAP_REQ) && (r_read_fsm.read() != READ_HEAP_LOCK) && (r_read_fsm.read() != READ_HEAP_ERASE)) { if(r_write_fsm.read() == WRITE_UPT_HEAP_LOCK) r_alloc_heap_fsm = ALLOC_HEAP_WRITE; else if(r_cas_fsm.read() == CAS_UPT_HEAP_LOCK) r_alloc_heap_fsm = ALLOC_HEAP_CAS; else if(r_cleanup_fsm.read() == CLEANUP_HEAP_REQ) r_alloc_heap_fsm = ALLOC_HEAP_CLEANUP; else if(r_xram_rsp_fsm.read() == XRAM_RSP_HEAP_REQ) r_alloc_heap_fsm = ALLOC_HEAP_XRAM_RSP; } break; ///////////////////// case ALLOC_HEAP_WRITE: if((r_write_fsm.read() != WRITE_UPT_HEAP_LOCK) && (r_write_fsm.read() != WRITE_UPT_REQ) && (r_write_fsm.read() != WRITE_UPT_NEXT)) { if(r_cas_fsm.read() == CAS_UPT_HEAP_LOCK) r_alloc_heap_fsm = ALLOC_HEAP_CAS; else if(r_cleanup_fsm.read() == CLEANUP_HEAP_REQ) r_alloc_heap_fsm = ALLOC_HEAP_CLEANUP; else if(r_xram_rsp_fsm.read() == XRAM_RSP_HEAP_REQ) r_alloc_heap_fsm = ALLOC_HEAP_XRAM_RSP; else if(r_read_fsm.read() == READ_HEAP_REQ) r_alloc_heap_fsm = ALLOC_HEAP_READ; } break; //////////////////// case ALLOC_HEAP_CAS: if((r_cas_fsm.read() != CAS_UPT_HEAP_LOCK) && (r_cas_fsm.read() != CAS_UPT_REQ) && (r_cas_fsm.read() != CAS_UPT_NEXT)) { if(r_cleanup_fsm.read() == CLEANUP_HEAP_REQ) r_alloc_heap_fsm = ALLOC_HEAP_CLEANUP; else if(r_xram_rsp_fsm.read() == XRAM_RSP_HEAP_REQ) r_alloc_heap_fsm = ALLOC_HEAP_XRAM_RSP; else if(r_read_fsm.read() == READ_HEAP_REQ) r_alloc_heap_fsm = ALLOC_HEAP_READ; else if(r_write_fsm.read() == WRITE_UPT_HEAP_LOCK) r_alloc_heap_fsm = ALLOC_HEAP_WRITE; } break; /////////////////////// case ALLOC_HEAP_CLEANUP: if((r_cleanup_fsm.read() != CLEANUP_HEAP_REQ) && (r_cleanup_fsm.read() != CLEANUP_HEAP_LOCK) && (r_cleanup_fsm.read() != CLEANUP_HEAP_SEARCH) && (r_cleanup_fsm.read() != CLEANUP_HEAP_CLEAN)) { if(r_xram_rsp_fsm.read() == XRAM_RSP_HEAP_REQ) r_alloc_heap_fsm = ALLOC_HEAP_XRAM_RSP; else if(r_read_fsm.read() == READ_HEAP_REQ) r_alloc_heap_fsm = ALLOC_HEAP_READ; else if(r_write_fsm.read() == WRITE_UPT_HEAP_LOCK) r_alloc_heap_fsm = ALLOC_HEAP_WRITE; else if(r_cas_fsm.read() == CAS_UPT_HEAP_LOCK) r_alloc_heap_fsm = ALLOC_HEAP_CAS; } break; //////////////////////// case ALLOC_HEAP_XRAM_RSP: if((r_xram_rsp_fsm.read() != XRAM_RSP_HEAP_REQ) && (r_xram_rsp_fsm.read() != XRAM_RSP_HEAP_ERASE)) { if(r_read_fsm.read() == READ_HEAP_REQ) r_alloc_heap_fsm = ALLOC_HEAP_READ; else if(r_write_fsm.read() == WRITE_UPT_HEAP_LOCK) r_alloc_heap_fsm = ALLOC_HEAP_WRITE; else if(r_cas_fsm.read() == CAS_UPT_HEAP_LOCK) r_alloc_heap_fsm = ALLOC_HEAP_CAS; else if(r_cleanup_fsm.read() == CLEANUP_HEAP_REQ) r_alloc_heap_fsm = ALLOC_HEAP_CLEANUP; } break; } // end switch alloc_heap_fsm //////////////////////////////////////////////////////////////////////////////////// // TGT_CMD to READ FIFO //////////////////////////////////////////////////////////////////////////////////// if(cmd_read_fifo_put) { if(cmd_read_fifo_get) { m_cmd_read_addr_fifo.put_and_get((addr_t)(p_vci_tgt.address.read())); m_cmd_read_length_fifo.put_and_get(p_vci_tgt.plen.read() >>2); m_cmd_read_srcid_fifo.put_and_get(p_vci_tgt.srcid.read()); m_cmd_read_trdid_fifo.put_and_get(p_vci_tgt.trdid.read()); m_cmd_read_pktid_fifo.put_and_get(p_vci_tgt.pktid.read()); } else { m_cmd_read_addr_fifo.simple_put((addr_t)(p_vci_tgt.address.read())); m_cmd_read_length_fifo.simple_put(p_vci_tgt.plen.read() >>2); m_cmd_read_srcid_fifo.simple_put(p_vci_tgt.srcid.read()); m_cmd_read_trdid_fifo.simple_put(p_vci_tgt.trdid.read()); m_cmd_read_pktid_fifo.simple_put(p_vci_tgt.pktid.read()); } } else { if(cmd_read_fifo_get) { m_cmd_read_addr_fifo.simple_get(); m_cmd_read_length_fifo.simple_get(); m_cmd_read_srcid_fifo.simple_get(); m_cmd_read_trdid_fifo.simple_get(); m_cmd_read_pktid_fifo.simple_get(); } } ///////////////////////////////////////////////////////////////////// // TGT_CMD to WRITE FIFO ///////////////////////////////////////////////////////////////////// if(cmd_write_fifo_put) { if(cmd_write_fifo_get) { m_cmd_write_addr_fifo.put_and_get((addr_t)(p_vci_tgt.address.read())); m_cmd_write_eop_fifo.put_and_get(p_vci_tgt.eop.read()); m_cmd_write_srcid_fifo.put_and_get(p_vci_tgt.srcid.read()); m_cmd_write_trdid_fifo.put_and_get(p_vci_tgt.trdid.read()); m_cmd_write_pktid_fifo.put_and_get(p_vci_tgt.pktid.read()); m_cmd_write_data_fifo.put_and_get(p_vci_tgt.wdata.read()); m_cmd_write_be_fifo.put_and_get(p_vci_tgt.be.read()); } else { m_cmd_write_addr_fifo.simple_put((addr_t)(p_vci_tgt.address.read())); m_cmd_write_eop_fifo.simple_put(p_vci_tgt.eop.read()); m_cmd_write_srcid_fifo.simple_put(p_vci_tgt.srcid.read()); m_cmd_write_trdid_fifo.simple_put(p_vci_tgt.trdid.read()); m_cmd_write_pktid_fifo.simple_put(p_vci_tgt.pktid.read()); m_cmd_write_data_fifo.simple_put(p_vci_tgt.wdata.read()); m_cmd_write_be_fifo.simple_put(p_vci_tgt.be.read()); } } else { if(cmd_write_fifo_get) { m_cmd_write_addr_fifo.simple_get(); m_cmd_write_eop_fifo.simple_get(); m_cmd_write_srcid_fifo.simple_get(); m_cmd_write_trdid_fifo.simple_get(); m_cmd_write_pktid_fifo.simple_get(); m_cmd_write_data_fifo.simple_get(); m_cmd_write_be_fifo.simple_get(); } } //////////////////////////////////////////////////////////////////////////////////// // TGT_CMD to CAS FIFO //////////////////////////////////////////////////////////////////////////////////// if(cmd_cas_fifo_put) { if(cmd_cas_fifo_get) { m_cmd_cas_addr_fifo.put_and_get((addr_t)(p_vci_tgt.address.read())); m_cmd_cas_eop_fifo.put_and_get(p_vci_tgt.eop.read()); m_cmd_cas_srcid_fifo.put_and_get(p_vci_tgt.srcid.read()); m_cmd_cas_trdid_fifo.put_and_get(p_vci_tgt.trdid.read()); m_cmd_cas_pktid_fifo.put_and_get(p_vci_tgt.pktid.read()); m_cmd_cas_wdata_fifo.put_and_get(p_vci_tgt.wdata.read()); } else { m_cmd_cas_addr_fifo.simple_put((addr_t)(p_vci_tgt.address.read())); m_cmd_cas_eop_fifo.simple_put(p_vci_tgt.eop.read()); m_cmd_cas_srcid_fifo.simple_put(p_vci_tgt.srcid.read()); m_cmd_cas_trdid_fifo.simple_put(p_vci_tgt.trdid.read()); m_cmd_cas_pktid_fifo.simple_put(p_vci_tgt.pktid.read()); m_cmd_cas_wdata_fifo.simple_put(p_vci_tgt.wdata.read()); } } else { if(cmd_cas_fifo_get) { m_cmd_cas_addr_fifo.simple_get(); m_cmd_cas_eop_fifo.simple_get(); m_cmd_cas_srcid_fifo.simple_get(); m_cmd_cas_trdid_fifo.simple_get(); m_cmd_cas_pktid_fifo.simple_get(); m_cmd_cas_wdata_fifo.simple_get(); } } //////////////////////////////////////////////////////////////////////////////////// // CC_RECEIVE to CLEANUP FIFO //////////////////////////////////////////////////////////////////////////////////// if(cc_receive_to_cleanup_fifo_put) { if(cc_receive_to_cleanup_fifo_get) { m_cc_receive_to_cleanup_fifo.put_and_get(p_dspin_in.data.read()); } else { m_cc_receive_to_cleanup_fifo.simple_put(p_dspin_in.data.read()); } } else { if(cc_receive_to_cleanup_fifo_get) { m_cc_receive_to_cleanup_fifo.simple_get(); } } //////////////////////////////////////////////////////////////////////////////////// // CC_RECEIVE to MULTI_ACK FIFO //////////////////////////////////////////////////////////////////////////////////// if(cc_receive_to_multi_ack_fifo_put) { if(cc_receive_to_multi_ack_fifo_get) { m_cc_receive_to_multi_ack_fifo.put_and_get(p_dspin_in.data.read()); } else { m_cc_receive_to_multi_ack_fifo.simple_put(p_dspin_in.data.read()); } } else { if(cc_receive_to_multi_ack_fifo_get) { m_cc_receive_to_multi_ack_fifo.simple_get(); } } //////////////////////////////////////////////////////////////////////////////////// // WRITE to CC_SEND FIFO //////////////////////////////////////////////////////////////////////////////////// if(write_to_cc_send_fifo_put) { if(write_to_cc_send_fifo_get) { m_write_to_cc_send_inst_fifo.put_and_get(write_to_cc_send_fifo_inst); m_write_to_cc_send_srcid_fifo.put_and_get(write_to_cc_send_fifo_srcid); #if L1_MULTI_CACHE m_write_to_cc_send_cache_id_fifo.put_and_get(write_to_cc_send_fifo_cache_id); #endif } else { m_write_to_cc_send_inst_fifo.simple_put(write_to_cc_send_fifo_inst); m_write_to_cc_send_srcid_fifo.simple_put(write_to_cc_send_fifo_srcid); #if L1_MULTI_CACHE m_write_to_cc_send_cache_id_fifo.simple_put(write_to_cc_send_fifo_cache_id); #endif } } else { if(write_to_cc_send_fifo_get) { m_write_to_cc_send_inst_fifo.simple_get(); m_write_to_cc_send_srcid_fifo.simple_get(); #if L1_MULTI_CACHE m_write_to_cc_send_cache_id_fifo.simple_get(); #endif } } //////////////////////////////////////////////////////////////////////////////////// // XRAM_RSP to CC_SEND FIFO //////////////////////////////////////////////////////////////////////////////////// if(xram_rsp_to_cc_send_fifo_put) { if(xram_rsp_to_cc_send_fifo_get) { m_xram_rsp_to_cc_send_inst_fifo.put_and_get(xram_rsp_to_cc_send_fifo_inst); m_xram_rsp_to_cc_send_srcid_fifo.put_and_get(xram_rsp_to_cc_send_fifo_srcid); #if L1_MULTI_CACHE m_xram_rsp_to_cc_send_cache_id_fifo.put_and_get(xram_rsp_to_cc_send_fifo_cache_id); #endif } else { m_xram_rsp_to_cc_send_inst_fifo.simple_put(xram_rsp_to_cc_send_fifo_inst); m_xram_rsp_to_cc_send_srcid_fifo.simple_put(xram_rsp_to_cc_send_fifo_srcid); #if L1_MULTI_CACHE m_xram_rsp_to_cc_send_cache_id_fifo.simple_put(xram_rsp_to_cc_send_fifo_cache_id); #endif } } else { if(xram_rsp_to_cc_send_fifo_get) { m_xram_rsp_to_cc_send_inst_fifo.simple_get(); m_xram_rsp_to_cc_send_srcid_fifo.simple_get(); #if L1_MULTI_CACHE m_xram_rsp_to_cc_send_cache_id_fifo.simple_get(); #endif } } //////////////////////////////////////////////////////////////////////////////////// // CAS to CC_SEND FIFO //////////////////////////////////////////////////////////////////////////////////// if(cas_to_cc_send_fifo_put) { if(cas_to_cc_send_fifo_get) { m_cas_to_cc_send_inst_fifo.put_and_get(cas_to_cc_send_fifo_inst); m_cas_to_cc_send_srcid_fifo.put_and_get(cas_to_cc_send_fifo_srcid); #if L1_MULTI_CACHE m_cas_to_cc_send_cache_id_fifo.put_and_get(cas_to_cc_send_fifo_cache_id); #endif } else { m_cas_to_cc_send_inst_fifo.simple_put(cas_to_cc_send_fifo_inst); m_cas_to_cc_send_srcid_fifo.simple_put(cas_to_cc_send_fifo_srcid); #if L1_MULTI_CACHE m_cas_to_cc_send_cache_id_fifo.simple_put(cas_to_cc_send_fifo_cache_id); #endif } } else { if(cas_to_cc_send_fifo_get) { m_cas_to_cc_send_inst_fifo.simple_get(); m_cas_to_cc_send_srcid_fifo.simple_get(); #if L1_MULTI_CACHE m_cas_to_cc_send_cache_id_fifo.simple_get(); #endif } } m_cpt_cycles++; } // end transition() ///////////////////////////// tmpl(void)::genMoore() ///////////////////////////// { //////////////////////////////////////////////////////////// // Command signals on the p_vci_ixr port //////////////////////////////////////////////////////////// p_vci_ixr.be = 0xF; p_vci_ixr.pktid = 0; p_vci_ixr.srcid = m_srcid_ixr; p_vci_ixr.cons = false; p_vci_ixr.wrap = false; p_vci_ixr.contig = true; p_vci_ixr.clen = 0; p_vci_ixr.cfixed = false; if(r_ixr_cmd_fsm.read() == IXR_CMD_READ_NLINE) { p_vci_ixr.cmd = vci_param::CMD_READ; p_vci_ixr.cmdval = true; p_vci_ixr.address = (addr_t)(r_read_to_ixr_cmd_nline.read() *m_words*4); p_vci_ixr.plen = m_words*4; p_vci_ixr.wdata = 0x00000000; p_vci_ixr.trdid = r_read_to_ixr_cmd_trdid.read(); p_vci_ixr.eop = true; } else if(r_ixr_cmd_fsm.read() == IXR_CMD_CAS_NLINE) { if(r_cas_to_ixr_cmd_write.read()) { p_vci_ixr.cmd = vci_param::CMD_WRITE; p_vci_ixr.cmdval = true; p_vci_ixr.address = (addr_t)((r_cas_to_ixr_cmd_nline.read() *m_words+r_ixr_cmd_cpt.read()) *4); p_vci_ixr.plen = m_words*4; p_vci_ixr.wdata = r_cas_to_ixr_cmd_data[r_ixr_cmd_cpt.read()].read(); p_vci_ixr.trdid = r_cas_to_ixr_cmd_trdid.read(); p_vci_ixr.eop = (r_ixr_cmd_cpt == (m_words-1)); } else { p_vci_ixr.cmd = vci_param::CMD_READ; p_vci_ixr.cmdval = true; p_vci_ixr.address = (addr_t)(r_cas_to_ixr_cmd_nline.read() *m_words*4); p_vci_ixr.plen = m_words*4; p_vci_ixr.wdata = 0x00000000; p_vci_ixr.trdid = r_cas_to_ixr_cmd_trdid.read(); p_vci_ixr.eop = true; } } else if(r_ixr_cmd_fsm.read() == IXR_CMD_WRITE_NLINE) { if(r_write_to_ixr_cmd_write.read()) { p_vci_ixr.cmd = vci_param::CMD_WRITE; p_vci_ixr.cmdval = true; p_vci_ixr.address = (addr_t)((r_write_to_ixr_cmd_nline.read() *m_words+r_ixr_cmd_cpt.read()) *4); p_vci_ixr.plen = m_words*4; p_vci_ixr.wdata = r_write_to_ixr_cmd_data[r_ixr_cmd_cpt.read()].read(); p_vci_ixr.trdid = r_write_to_ixr_cmd_trdid.read(); p_vci_ixr.eop = (r_ixr_cmd_cpt == (m_words-1)); } else { p_vci_ixr.cmd = vci_param::CMD_READ; p_vci_ixr.cmdval = true; p_vci_ixr.address = (addr_t)(r_write_to_ixr_cmd_nline.read() *m_words*4); p_vci_ixr.plen = m_words*4; p_vci_ixr.wdata = 0x00000000; p_vci_ixr.trdid = r_write_to_ixr_cmd_trdid.read(); p_vci_ixr.eop = true; } } else if(r_ixr_cmd_fsm.read() == IXR_CMD_XRAM_DATA) { p_vci_ixr.cmd = vci_param::CMD_WRITE; p_vci_ixr.cmdval = true; p_vci_ixr.address = (addr_t)((r_xram_rsp_to_ixr_cmd_nline.read() *m_words+r_ixr_cmd_cpt.read()) *4); p_vci_ixr.plen = m_words*4; p_vci_ixr.wdata = r_xram_rsp_to_ixr_cmd_data[r_ixr_cmd_cpt.read()].read(); p_vci_ixr.trdid = r_xram_rsp_to_ixr_cmd_trdid.read(); p_vci_ixr.eop = (r_ixr_cmd_cpt == (m_words-1)); } else { p_vci_ixr.cmdval = false; p_vci_ixr.address = 0; p_vci_ixr.plen = 0; p_vci_ixr.wdata = 0; p_vci_ixr.trdid = 0; p_vci_ixr.eop = false; } //////////////////////////////////////////////////// // Response signals on the p_vci_ixr port //////////////////////////////////////////////////// if(((r_alloc_trt_fsm.read() == ALLOC_TRT_IXR_RSP) && (r_ixr_rsp_fsm.read() == IXR_RSP_TRT_READ)) || (r_ixr_rsp_fsm.read() == IXR_RSP_ACK)) p_vci_ixr.rspack = true; else p_vci_ixr.rspack = false; //////////////////////////////////////////////////// // Command signals on the p_vci_tgt port //////////////////////////////////////////////////// switch((tgt_cmd_fsm_state_e) r_tgt_cmd_fsm.read()) { case TGT_CMD_IDLE: p_vci_tgt.cmdack = false; break; case TGT_CMD_READ: p_vci_tgt.cmdack = m_cmd_read_addr_fifo.wok(); break; case TGT_CMD_WRITE: p_vci_tgt.cmdack = m_cmd_write_addr_fifo.wok(); break; case TGT_CMD_CAS: p_vci_tgt.cmdack = m_cmd_cas_addr_fifo.wok(); break; default: p_vci_tgt.cmdack = false; break; } //////////////////////////////////////////////////// // Response signals on the p_vci_tgt port //////////////////////////////////////////////////// switch(r_tgt_rsp_fsm.read()) { case TGT_RSP_READ_IDLE: case TGT_RSP_WRITE_IDLE: case TGT_RSP_CAS_IDLE: case TGT_RSP_XRAM_IDLE: case TGT_RSP_INIT_IDLE: case TGT_RSP_CLEANUP_IDLE: p_vci_tgt.rspval = false; p_vci_tgt.rsrcid = 0; p_vci_tgt.rdata = 0; p_vci_tgt.rpktid = 0; p_vci_tgt.rtrdid = 0; p_vci_tgt.rerror = 0; p_vci_tgt.reop = false; break; case TGT_RSP_READ: p_vci_tgt.rspval = true; if(((r_read_to_tgt_rsp_pktid.read() & 0x7) == TYPE_LL) && (r_tgt_rsp_cpt.read() == (r_read_to_tgt_rsp_word.read() +r_read_to_tgt_rsp_length-1))) p_vci_tgt.rdata = r_read_to_tgt_rsp_data[r_tgt_rsp_cpt.read()-1].read(); else if((r_read_to_tgt_rsp_pktid.read() & 0x7) == TYPE_LL) p_vci_tgt.rdata = r_read_to_tgt_rsp_ll_key.read(); else p_vci_tgt.rdata = r_read_to_tgt_rsp_data[r_tgt_rsp_cpt.read()].read(); p_vci_tgt.rsrcid = r_read_to_tgt_rsp_srcid.read(); p_vci_tgt.rtrdid = r_read_to_tgt_rsp_trdid.read(); p_vci_tgt.rpktid = r_read_to_tgt_rsp_pktid.read(); p_vci_tgt.rerror = 0; p_vci_tgt.reop = (r_tgt_rsp_cpt.read() == (r_read_to_tgt_rsp_word.read() +r_read_to_tgt_rsp_length-1)); break; case TGT_RSP_WRITE: p_vci_tgt.rspval = true; if(((r_write_to_tgt_rsp_pktid.read() & 0x7) == TYPE_SC) && r_write_to_tgt_rsp_sc_fail.read()) p_vci_tgt.rdata = 1; else p_vci_tgt.rdata = 0; p_vci_tgt.rsrcid = r_write_to_tgt_rsp_srcid.read(); p_vci_tgt.rtrdid = r_write_to_tgt_rsp_trdid.read(); p_vci_tgt.rpktid = r_write_to_tgt_rsp_pktid.read(); p_vci_tgt.rerror = 0; p_vci_tgt.reop = true; break; case TGT_RSP_CLEANUP: p_vci_tgt.rspval = true; p_vci_tgt.rdata = 0; p_vci_tgt.rsrcid = r_cleanup_to_tgt_rsp_srcid.read(); p_vci_tgt.rtrdid = r_cleanup_to_tgt_rsp_trdid.read(); p_vci_tgt.rpktid = r_cleanup_to_tgt_rsp_pktid.read(); p_vci_tgt.rerror = 0; // Can be a CAS rsp p_vci_tgt.reop = true; break; case TGT_RSP_CAS: p_vci_tgt.rspval = true; p_vci_tgt.rdata = r_cas_to_tgt_rsp_data.read(); p_vci_tgt.rsrcid = r_cas_to_tgt_rsp_srcid.read(); p_vci_tgt.rtrdid = r_cas_to_tgt_rsp_trdid.read(); p_vci_tgt.rpktid = r_cas_to_tgt_rsp_pktid.read(); p_vci_tgt.rerror = 0; p_vci_tgt.reop = true; break; case TGT_RSP_XRAM: p_vci_tgt.rspval = true; if(((r_xram_rsp_to_tgt_rsp_pktid.read() & 0x7) == TYPE_LL) && (r_tgt_rsp_cpt.read() == (r_xram_rsp_to_tgt_rsp_word.read() +r_xram_rsp_to_tgt_rsp_length-1))) p_vci_tgt.rdata = r_xram_rsp_to_tgt_rsp_ll_key.read(); else p_vci_tgt.rdata = r_xram_rsp_to_tgt_rsp_data[r_tgt_rsp_cpt.read()].read(); p_vci_tgt.rsrcid = r_xram_rsp_to_tgt_rsp_srcid.read(); p_vci_tgt.rtrdid = r_xram_rsp_to_tgt_rsp_trdid.read(); p_vci_tgt.rpktid = r_xram_rsp_to_tgt_rsp_pktid.read(); p_vci_tgt.rerror = r_xram_rsp_to_tgt_rsp_rerror.read(); p_vci_tgt.reop = ((r_tgt_rsp_cpt.read() == (r_xram_rsp_to_tgt_rsp_word.read() +r_xram_rsp_to_tgt_rsp_length.read()-1)) || r_xram_rsp_to_tgt_rsp_rerror.read()); break; case TGT_RSP_INIT: p_vci_tgt.rspval = true; p_vci_tgt.rdata = 0; // Can be a CAS or SC rsp p_vci_tgt.rsrcid = r_multi_ack_to_tgt_rsp_srcid.read(); p_vci_tgt.rtrdid = r_multi_ack_to_tgt_rsp_trdid.read(); p_vci_tgt.rpktid = r_multi_ack_to_tgt_rsp_pktid.read(); p_vci_tgt.rerror = 0; p_vci_tgt.reop = true; break; } // end switch r_tgt_rsp_fsm //////////////////////////////////////////////////////////////////// // Initiator command signals on the p_dspin_out port (CC_SEND FSM) //////////////////////////////////////////////////////////////////// p_dspin_out.write = false; p_dspin_out.data = 0; switch(r_cc_send_fsm.read()) { case CC_SEND_XRAM_RSP_IDLE: case CC_SEND_WRITE_IDLE: case CC_SEND_CAS_IDLE: case CC_SEND_CLEANUP_IDLE: break; case CC_SEND_CLEANUP_ACK: { uint64_t flit = 0; uint8_t cleanup_ack_type; if(r_cleanup_to_cc_send_inst.read()) { cleanup_ack_type = DspinDhccpParam::TYPE_CLEANUP_ACK_INST; } else { cleanup_ack_type = DspinDhccpParam::TYPE_CLEANUP_ACK_DATA; } DspinDhccpParam::dspin_set( flit, 1ULL, DspinDhccpParam::FROM_MC_EOP); DspinDhccpParam::dspin_set( flit, r_cleanup_to_cc_send_srcid.read(), DspinDhccpParam::CLEANUP_ACK_DEST); DspinDhccpParam::dspin_set( flit, r_cleanup_to_cc_send_set_index.read(), DspinDhccpParam::CLEANUP_ACK_SET); DspinDhccpParam::dspin_set( flit, r_cleanup_to_cc_send_way_index.read(), DspinDhccpParam::CLEANUP_ACK_WAY); DspinDhccpParam::dspin_set( flit, cleanup_ack_type, DspinDhccpParam::FROM_MC_TYPE); p_dspin_out.write = true; p_dspin_out.data = flit; break; } case CC_SEND_XRAM_RSP_INVAL_HEADER: { if(not m_xram_rsp_to_cc_send_inst_fifo.rok()) break; uint8_t multi_inval_type; if(m_xram_rsp_to_cc_send_inst_fifo.read()) { multi_inval_type = DspinDhccpParam::TYPE_MULTI_INVAL_INST; } else { multi_inval_type = DspinDhccpParam::TYPE_MULTI_INVAL_DATA; } uint64_t flit = 0; DspinDhccpParam::dspin_set( flit, m_xram_rsp_to_cc_send_srcid_fifo.read(), DspinDhccpParam::MULTI_INVAL_DEST); DspinDhccpParam::dspin_set( flit, m_srcid_ini, DspinDhccpParam::MULTI_INVAL_SRCID); DspinDhccpParam::dspin_set( flit, r_xram_rsp_to_cc_send_trdid.read(), DspinDhccpParam::MULTI_INVAL_UPDT_INDEX); DspinDhccpParam::dspin_set( flit, multi_inval_type, DspinDhccpParam::FROM_MC_TYPE); p_dspin_out.write = true; p_dspin_out.data = flit; break; } case CC_SEND_XRAM_RSP_INVAL_NLINE: { uint64_t flit = 0; DspinDhccpParam::dspin_set( flit, 1ULL, DspinDhccpParam::FROM_MC_EOP); DspinDhccpParam::dspin_set( flit, r_xram_rsp_to_cc_send_nline.read(), DspinDhccpParam::MULTI_INVAL_NLINE); p_dspin_out.write = true; p_dspin_out.data = flit; break; } case CC_SEND_XRAM_RSP_BRDCAST_HEADER: case CC_SEND_WRITE_BRDCAST_HEADER: case CC_SEND_CAS_BRDCAST_HEADER: { uint64_t flit = 0; DspinDhccpParam::dspin_set( flit, m_broadcast_address, DspinDhccpParam::BROADCAST_BOX); DspinDhccpParam::dspin_set( flit, m_srcid_ini, DspinDhccpParam::BROADCAST_SRCID); DspinDhccpParam::dspin_set( flit, 1ULL, DspinDhccpParam::FROM_MC_BC); p_dspin_out.write = true; p_dspin_out.data = flit; break; } case CC_SEND_XRAM_RSP_BRDCAST_NLINE: { uint64_t flit = 0; DspinDhccpParam::dspin_set( flit, 1ULL, DspinDhccpParam::FROM_MC_EOP); DspinDhccpParam::dspin_set( flit, r_xram_rsp_to_cc_send_nline.read(), DspinDhccpParam::BROADCAST_NLINE); p_dspin_out.write = true; p_dspin_out.data = flit; break; } case CC_SEND_WRITE_BRDCAST_NLINE: { uint64_t flit = 0; DspinDhccpParam::dspin_set( flit, 1ULL, DspinDhccpParam::FROM_MC_EOP); DspinDhccpParam::dspin_set( flit, r_write_to_cc_send_nline.read(), DspinDhccpParam::BROADCAST_NLINE); p_dspin_out.write = true; p_dspin_out.data = flit; break; } case CC_SEND_CAS_BRDCAST_NLINE: { uint64_t flit = 0; DspinDhccpParam::dspin_set( flit, 1ULL, DspinDhccpParam::FROM_MC_EOP); DspinDhccpParam::dspin_set( flit, r_cas_to_cc_send_nline.read(), DspinDhccpParam::BROADCAST_NLINE); p_dspin_out.write = true; p_dspin_out.data = flit; break; } case CC_SEND_WRITE_UPDT_HEADER: { if(not m_write_to_cc_send_inst_fifo.rok()) break; uint8_t multi_updt_type; if(m_write_to_cc_send_inst_fifo.read()) { multi_updt_type = DspinDhccpParam::TYPE_MULTI_UPDT_INST; } else { multi_updt_type = DspinDhccpParam::TYPE_MULTI_UPDT_DATA; } uint64_t flit = 0; DspinDhccpParam::dspin_set( flit, m_write_to_cc_send_srcid_fifo.read(), DspinDhccpParam::MULTI_UPDT_DEST); DspinDhccpParam::dspin_set( flit, m_srcid_ini, DspinDhccpParam::MULTI_UPDT_SRCID); DspinDhccpParam::dspin_set( flit, r_write_to_cc_send_trdid.read(), DspinDhccpParam::MULTI_UPDT_UPDT_INDEX); DspinDhccpParam::dspin_set( flit, multi_updt_type, DspinDhccpParam::FROM_MC_TYPE); p_dspin_out.write = true; p_dspin_out.data = flit; break; } case CC_SEND_WRITE_UPDT_NLINE: { uint64_t flit = 0; DspinDhccpParam::dspin_set( flit, r_write_to_cc_send_index.read(), DspinDhccpParam::MULTI_UPDT_WORD_INDEX); DspinDhccpParam::dspin_set( flit, r_write_to_cc_send_nline.read(), DspinDhccpParam::MULTI_UPDT_NLINE); p_dspin_out.write = true; p_dspin_out.data = flit; break; } case CC_SEND_WRITE_UPDT_DATA: { uint8_t multi_updt_eop; if( r_cc_send_cpt.read() == (r_write_to_cc_send_count.read()-1)) { multi_updt_eop = 1; } else { multi_updt_eop = 0; } uint8_t multi_updt_cpt = r_cc_send_cpt.read() + r_write_to_cc_send_index.read(); uint8_t multi_updt_be = r_write_to_cc_send_be[multi_updt_cpt].read(); uint32_t multi_updt_data = r_write_to_cc_send_data[multi_updt_cpt].read(); uint64_t flit = 0; DspinDhccpParam::dspin_set( flit, (uint64_t)multi_updt_eop, DspinDhccpParam::FROM_MC_EOP); DspinDhccpParam::dspin_set( flit, multi_updt_be, DspinDhccpParam::MULTI_UPDT_BE); DspinDhccpParam::dspin_set( flit, multi_updt_data, DspinDhccpParam::MULTI_UPDT_DATA); p_dspin_out.write = true; p_dspin_out.data = flit; break; } case CC_SEND_CAS_UPDT_HEADER: { if (not m_cas_to_cc_send_inst_fifo.rok()) break; uint8_t multi_updt_type; if(m_cas_to_cc_send_inst_fifo.read()) { multi_updt_type = DspinDhccpParam::TYPE_MULTI_UPDT_INST; } else { multi_updt_type = DspinDhccpParam::TYPE_MULTI_UPDT_DATA; } uint64_t flit = 0; DspinDhccpParam::dspin_set( flit, m_cas_to_cc_send_srcid_fifo.read(), DspinDhccpParam::MULTI_UPDT_DEST); DspinDhccpParam::dspin_set( flit, m_srcid_ini, DspinDhccpParam::MULTI_UPDT_SRCID); DspinDhccpParam::dspin_set( flit, r_cas_to_cc_send_trdid.read(), DspinDhccpParam::MULTI_UPDT_UPDT_INDEX); DspinDhccpParam::dspin_set( flit, multi_updt_type, DspinDhccpParam::FROM_MC_TYPE); p_dspin_out.write = true; p_dspin_out.data = flit; break; } case CC_SEND_CAS_UPDT_NLINE: { uint64_t flit = 0; DspinDhccpParam::dspin_set( flit, r_cas_to_cc_send_index.read(), DspinDhccpParam::MULTI_UPDT_WORD_INDEX); DspinDhccpParam::dspin_set( flit, r_cas_to_cc_send_nline.read(), DspinDhccpParam::MULTI_UPDT_NLINE); p_dspin_out.write = true; p_dspin_out.data = flit; break; } case CC_SEND_CAS_UPDT_DATA: { uint8_t multi_updt_eop; if(not r_cas_to_cc_send_is_long.read()) { multi_updt_eop = 1; } else { multi_updt_eop = 0; } uint64_t flit = 0; DspinDhccpParam::dspin_set( flit, (uint64_t)multi_updt_eop, DspinDhccpParam::FROM_MC_EOP); DspinDhccpParam::dspin_set( flit, 0xF, DspinDhccpParam::MULTI_UPDT_BE); DspinDhccpParam::dspin_set( flit, r_cas_to_cc_send_wdata.read(), DspinDhccpParam::MULTI_UPDT_DATA); p_dspin_out.write = true; p_dspin_out.data = flit; break; } case CC_SEND_CAS_UPDT_DATA_HIGH: { uint64_t flit = 0; DspinDhccpParam::dspin_set( flit, 1ULL, DspinDhccpParam::FROM_MC_EOP); DspinDhccpParam::dspin_set( flit, 0xF, DspinDhccpParam::MULTI_UPDT_BE); DspinDhccpParam::dspin_set( flit, r_cas_to_cc_send_wdata_high.read(), DspinDhccpParam::MULTI_UPDT_DATA); p_dspin_out.write = true; p_dspin_out.data = flit; break; } } /////////////////////////////////////////////////////////////////// // Target command signals from the p_dspin_in port (CC_RECEIVE FSM) /////////////////////////////////////////////////////////////////// p_dspin_in.read = false; switch(r_cc_receive_fsm.read()) { case CC_RECEIVE_IDLE: { break; } case CC_RECEIVE_CLEANUP: { p_dspin_in.read = m_cc_receive_to_cleanup_fifo.wok(); break; } case CC_RECEIVE_MULTI_ACK: { p_dspin_in.read = m_cc_receive_to_multi_ack_fifo.wok(); break; } } // end switch r_cc_send_fsm } // end genMoore() } } // end name space // Local Variables: // tab-width: 2 // c-basic-offset: 2 // c-file-offsets:((innamespace . 0)(inline-open . 0)) // indent-tabs-mode: nil // End: // vim: filetype=cpp:expandtab:shiftwidth=2:tabstop=2:softtabstop=2