 /* -*- c++ -*-
 * File       : vci_mem_cache_v4.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_v4.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_INIT_CMD 1 // detailed trace of INIT_CMD FSM
#define DEBUG_MEMC_INIT_RSP 1 // detailed trace of INIT_RSP 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 *init_cmd_fsm_str[] = {
    "INIT_CMD_INVAL_IDLE",
    "INIT_CMD_INVAL_NLINE",
    "INIT_CMD_XRAM_BRDCAST",
    "INIT_CMD_UPDT_IDLE",
    "INIT_CMD_WRITE_BRDCAST",
    "INIT_CMD_UPDT_NLINE",
    "INIT_CMD_UPDT_INDEX",
    "INIT_CMD_UPDT_DATA",
    "INIT_CMD_CAS_UPDT_IDLE",
    "INIT_CMD_CAS_BRDCAST",
    "INIT_CMD_CAS_UPDT_NLINE",
    "INIT_CMD_CAS_UPDT_INDEX",
    "INIT_CMD_CAS_UPDT_DATA",
    "INIT_CMD_CAS_UPDT_DATA_HIGH"
  };
  const char *init_rsp_fsm_str[] = {
    "INIT_RSP_IDLE",
    "INIT_RSP_UPT_LOCK",
    "INIT_RSP_UPT_CLEAR",
    "INIT_RSP_END"
  };
  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_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_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_WRITE",
    "CLEANUP_WRITE_RSP",
    "CLEANUP_RSP"
  };
  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_INIT_RSP",
    "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<typename vci_param> x VciMemCacheV4<vci_param>

  using soclib::common::uint32_log2;

  ////////////////////////////////
  //  Constructor
  ////////////////////////////////

  tmpl(/**/)::VciMemCacheV4(
      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_tgt_cleanup("vci_tgt_cleanup"),
    p_vci_ini("vci_ini"),
    p_vci_ixr("vci_ixr"),

    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

    //  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),

    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_init_cmd_inst_fifo("m_write_to_init_cmd_inst_fifo",8),
    m_write_to_init_cmd_srcid_fifo("m_write_to_init_cmd_srcid_fifo",8),
#if L1_MULTI_CACHE
    m_write_to_init_cmd_cache_id_fifo("m_write_to_init_cmd_cache_id_fifo",8),
#endif

    r_init_rsp_fsm("r_init_rsp_fsm"),
    r_cleanup_fsm("r_cleanup_fsm"),

    r_cas_fsm("r_cas_fsm"),

    m_cas_to_init_cmd_inst_fifo("m_cas_to_init_cmd_inst_fifo",8),
    m_cas_to_init_cmd_srcid_fifo("m_cas_to_init_cmd_srcid_fifo",8),
#if L1_MULTI_CACHE
    m_cas_to_init_cmd_cache_id_fifo("m_cas_to_init_cmd_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_init_cmd_inst_fifo("m_xram_rsp_to_init_cmd_inst_fifo",8),
    m_xram_rsp_to_init_cmd_srcid_fifo("m_xram_rsp_to_init_cmd_srcid_fifo",8),
#if L1_MULTI_CACHE
    m_xram_rsp_to_init_cmd_cache_id_fifo("m_xram_rsp_to_init_cmd_cache_id_fifo",8),
#endif

    r_ixr_cmd_fsm("r_ixr_cmd_fsm"),

    r_tgt_rsp_fsm("r_tgt_rsp_fsm"),

    r_init_cmd_fsm("r_init_cmd_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");

      // Set the broadcast address with Xmin,Xmax,Ymin,Ymax set to maximum
      m_broadcast_address = 0x3 | (0x7C1F << (vci_param::N-20));

      // Get the segments associated to the MemCache
      std::list<soclib::common::Segment>::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<bool>[m_transaction_tab_lines];

      // Allocation for XRAM_RSP FSM
      r_xram_rsp_victim_data      = new sc_signal<data_t>[nwords];
      r_xram_rsp_to_tgt_rsp_data  = new sc_signal<data_t>[nwords];
      r_xram_rsp_to_ixr_cmd_data  = new sc_signal<data_t>[nwords];

      // Allocation for READ FSM
      r_read_data                 = new sc_signal<data_t>[nwords];
      r_read_to_tgt_rsp_data      = new sc_signal<data_t>[nwords];

      // Allocation for WRITE FSM
      r_write_data                = new sc_signal<data_t>[nwords];
      r_write_be                  = new sc_signal<be_t>[nwords];
      r_write_to_init_cmd_data    = new sc_signal<data_t>[nwords];
      r_write_to_init_cmd_be      = new sc_signal<be_t>[nwords];
      r_write_to_ixr_cmd_data     = new sc_signal<data_t>[nwords];

      // Allocation for CAS FSM
      r_cas_to_ixr_cmd_data        = new sc_signal<data_t>[nwords];
      r_cas_rdata                  = new sc_signal<data_t>[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 << 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 << "  "  << init_cmd_fsm_str[r_init_cmd_fsm]
              << " | " << init_rsp_fsm_str[r_init_rsp_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(/**/)::~VciMemCacheV4()
    /////////////////////////////////
  {
    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_init_cmd_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_init_cmd_fsm   = INIT_CMD_INVAL_IDLE;
    r_init_rsp_fsm   = INIT_RSP_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_init_cmd_fsm   = false;
    m_debug_init_rsp_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();

    // 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_init_cmd_multi_req   = false;
    r_write_to_init_cmd_brdcast_req = false;
    r_write_to_init_rsp_req         = false;

    m_write_to_init_cmd_inst_fifo.init();
    m_write_to_init_cmd_srcid_fifo.init();
#if L1_MULTI_CACHE
    m_write_to_init_cmd_cache_id_fifo.init();
#endif

    r_cleanup_to_tgt_rsp_req      = false;

    r_init_rsp_to_tgt_rsp_req     = false;

    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_init_cmd_multi_req   = false;
    r_cas_to_init_cmd_brdcast_req = false;

    m_cas_to_init_cmd_inst_fifo.init();
    m_cas_to_init_cmd_srcid_fifo.init();
#if L1_MULTI_CACHE
    m_cas_to_init_cmd_cache_id_fifo.init();
#endif

    for(size_t i=0; i<m_transaction_tab_lines ; i++){
      r_ixr_rsp_to_xram_rsp_rok[i] = false;
    }

    r_xram_rsp_to_tgt_rsp_req          = false;
    r_xram_rsp_to_init_cmd_multi_req   = false;
    r_xram_rsp_to_init_cmd_brdcast_req = false;
    r_xram_rsp_to_ixr_cmd_req          = false;
    r_xram_rsp_trt_index               = 0;

    m_xram_rsp_to_init_cmd_inst_fifo.init();
    m_xram_rsp_to_init_cmd_srcid_fifo.init();
#if L1_MULTI_CACHE
    m_xram_rsp_to_init_cmd_cache_id_fifo.init();
#endif

    r_ixr_cmd_cpt          = 0;
    r_alloc_dir_reset_cpt  = 0;
    r_alloc_heap_reset_cpt = 0;

    r_copies_limit         = 3;

    // Activity counters
    m_cpt_cycles        = 0;
    m_cpt_read          = 0;
    m_cpt_read_miss     = 0;
    m_cpt_write         = 0;
    m_cpt_write_miss    = 0;
    m_cpt_write_cells   = 0;
    m_cpt_write_dirty   = 0;
    m_cpt_update        = 0;
    m_cpt_update_mult   = 0;
    m_cpt_inval_brdcast = 0;
    m_cpt_inval         = 0;
    m_cpt_inval_mult    = 0;
    m_cpt_cleanup       = 0;
    m_cpt_ll            = 0;
    m_cpt_sc            = 0;
    m_cpt_cas           = 0;
    m_cpt_trt_full      = 0;
    m_cpt_trt_rb        = 0;

    return;
  }

  bool    cmd_read_fifo_put = false;
  bool    cmd_read_fifo_get = false;

  bool    cmd_write_fifo_put = false;
  bool    cmd_write_fifo_get = false;

  bool    cmd_cas_fifo_put = false;
  bool    cmd_cas_fifo_get = false;

  bool    write_to_init_cmd_fifo_put   = false;
  bool    write_to_init_cmd_fifo_get   = false;
  bool    write_to_init_cmd_fifo_inst  = false;
  size_t  write_to_init_cmd_fifo_srcid = 0;

#if L1_MULTI_CACHE
  size_t  write_to_init_cmd_fifo_cache_id = 0;
#endif

  bool    xram_rsp_to_init_cmd_fifo_put   = false;
  bool    xram_rsp_to_init_cmd_fifo_get   = false;
  bool    xram_rsp_to_init_cmd_fifo_inst  = false;
  size_t  xram_rsp_to_init_cmd_fifo_srcid = 0;

#if L1_MULTI_CACHE
  size_t  xram_rsp_to_init_cmd_fifo_cache_id = 0;
#endif

  bool    cas_to_init_cmd_fifo_put   = false;
  bool    cas_to_init_cmd_fifo_get   = false;
  bool    cas_to_init_cmd_fifo_inst  = false;
  size_t  cas_to_init_cmd_fifo_srcid = 0;

#if L1_MULTI_CACHE
  size_t  cas_to_init_cmd_fifo_cache_id = 0;
#endif

  m_debug_global       = (m_cpt_cycles > 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_init_cmd_fsm = (m_cpt_cycles > m_debug_start_cycle) and m_debug_ok;
  m_debug_init_rsp_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] << std::endl
      << " - TGT_RSP FSM    = " << tgt_rsp_fsm_str[r_tgt_rsp_fsm] << std::endl
      << " - INIT_CMD FSM   = " << init_cmd_fsm_str[r_init_cmd_fsm] << std::endl
      << " - INIT_RSP FSM   = " << init_rsp_fsm_str[r_init_rsp_fsm] << std::endl
      << " - READ FSM       = " << read_fsm_str[r_read_fsm] << std::endl
      << " - WRITE FSM      = " << write_fsm_str[r_write_fsm] << std::endl
      << " - CAS FSM        = " << cas_fsm_str[r_cas_fsm] << std::endl
      << " - CLEANUP FSM    = " << cleanup_fsm_str[r_cleanup_fsm] << std::endl
      << " - IXR_CMD FSM    = " << ixr_cmd_fsm_str[r_ixr_cmd_fsm] << std::endl
      << " - IXR_RSP FSM    = " << ixr_rsp_fsm_str[r_ixr_rsp_fsm] << std::endl
      << " - XRAM_RSP FSM   = " << xram_rsp_fsm_str[r_xram_rsp_fsm] << std::endl
      << " - ALLOC_DIR FSM  = " << alloc_dir_fsm_str[r_alloc_dir_fsm] << std::endl
      << " - ALLOC_TRT FSM  = " << alloc_trt_fsm_str[r_alloc_trt_fsm] << std::endl
      << " - ALLOC_UPT FSM  = " << alloc_upt_fsm_str[r_alloc_upt_fsm] << std::endl
      << " - ALLOC_HEAP FSM = " << alloc_heap_fsm_str[r_alloc_heap_fsm] << 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
            << "  <MEMC " << name() << ".TGT_CMD_IDLE> 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.cmdval && m_cmd_read_addr_fifo.wok() )
      {

#if DEBUG_MEMC_TGT_CMD
        if( m_debug_tgt_cmd_fsm )
        {
          std::cout << "  <MEMC " << name() << ".TGT_CMD_READ> 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 << "  <MEMC " << name() << ".TGT_CMD_WRITE> 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 << "  <MEMC " << name() << ".TGT_CMD_CAS> 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

  /////////////////////////////////////////////////////////////////////////
  //    INIT_RSP FSM
  /////////////////////////////////////////////////////////////////////////
  // This FSM controls the response to the update or 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 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 word, compact
  // packets complying with the VCI advanced format.
  // The index in the Table is defined in the RTRDID field, and
  // the transaction type is defined in the UPT entry.
  /////////////////////////////////////////////////////////////////////

  switch ( r_init_rsp_fsm.read() )
  {
    ///////////////////
    case INIT_RSP_IDLE:   // wait a response for a coherence transaction
      if ( p_vci_ini.rspval )
      {

#if DEBUG_MEMC_INIT_RSP
        if( m_debug_init_rsp_fsm )
        {
          std::cout <<  "  <MEMC " << name() << ".INIT_RSP_IDLE> Response for UPT entry "
            << p_vci_ini.rtrdid.read() << std::endl;
        }
#endif
        if ( p_vci_ini.rtrdid.read() >= m_update_tab.size() )
        {
          std::cout
            << "VCI_MEM_CACHE ERROR " << name()
            << " INIT_RSP_IDLE state" << std::endl
            << "index too large for UPT: "
            << " / rtrdid = " << std::dec << p_vci_ini.rtrdid.read()
            << " / UPT size = " << std::dec << m_update_tab.size()
            << std::endl;

          exit(0);
        }
        if ( !p_vci_ini.reop.read() )
        {
          std::cout
            << "VCI_MEM_CACHE ERROR " << name()
            << " INIT_RSP_IDLE state" << std::endl
            << "all coherence response packets must be one flit"
            << std::endl;

          exit(0);
        }

        r_init_rsp_upt_index = p_vci_ini.rtrdid.read();
        r_init_rsp_fsm = INIT_RSP_UPT_LOCK;
      }
      else if( r_write_to_init_rsp_req.read() )
      {
        r_init_rsp_upt_index = r_write_to_init_rsp_upt_index.read();
        r_write_to_init_rsp_req = false;
        r_init_rsp_fsm = INIT_RSP_UPT_LOCK;
      }
      break;

    ///////////////////////
    case INIT_RSP_UPT_LOCK: // decrement the number of expected responses
      if ( r_alloc_upt_fsm.read() == ALLOC_UPT_INIT_RSP )
      {
        size_t count = 0;
        bool valid   = m_update_tab.decrement(r_init_rsp_upt_index.read(), count);

#if DEBUG_MEMC_INIT_RSP
        if( m_debug_init_rsp_fsm )
        {
          std::cout << "  <MEMC " << name() << ".INIT_RSP_UPT_LOCK> Decrement the responses counter for UPT:"
            << " entry = " << r_init_rsp_upt_index.read()
            << " / rsp_count = " << std::dec << count << std::endl;
        }
#endif
        if ( not valid )
        {
          std::cout << "VCI_MEM_CACHE ERROR " << name()
            << " INIT_RSP_UPT_LOCK state" << std::endl
            << "unsuccessful access to decrement the UPT" << std::endl;

          exit(0);
        }

        if ( count == 0 ) r_init_rsp_fsm = INIT_RSP_UPT_CLEAR;
        else              r_init_rsp_fsm = INIT_RSP_IDLE;
      }
      break;

      ////////////////////////
    case INIT_RSP_UPT_CLEAR:  // clear the UPT entry
      if ( r_alloc_upt_fsm.read() == ALLOC_UPT_INIT_RSP )
      {
        r_init_rsp_srcid = m_update_tab.srcid(r_init_rsp_upt_index.read());
        r_init_rsp_trdid = m_update_tab.trdid(r_init_rsp_upt_index.read());
        r_init_rsp_pktid = m_update_tab.pktid(r_init_rsp_upt_index.read());
        r_init_rsp_nline = m_update_tab.nline(r_init_rsp_upt_index.read());
        bool need_rsp    = m_update_tab.need_rsp(r_init_rsp_upt_index.read());

        if ( need_rsp ) r_init_rsp_fsm = INIT_RSP_END;
        else            r_init_rsp_fsm = INIT_RSP_IDLE;

        m_update_tab.clear(r_init_rsp_upt_index.read());

#if DEBUG_MEMC_INIT_RSP
        if ( m_debug_init_rsp_fsm )
        {
          std::cout <<  "  <MEMC " << name() << ".INIT_RSP_UPT_CLEAR> Clear UPT entry "
            << r_init_rsp_upt_index.read() <<  std::endl;
        }
#endif
      }
      break;

    //////////////////
    case INIT_RSP_END:  // Post a request to TGT_RSP FSM
      if ( !r_init_rsp_to_tgt_rsp_req )
      {
        r_init_rsp_to_tgt_rsp_req   = true;
        r_init_rsp_to_tgt_rsp_srcid = r_init_rsp_srcid.read();
        r_init_rsp_to_tgt_rsp_trdid = r_init_rsp_trdid.read();
        r_init_rsp_to_tgt_rsp_pktid = r_init_rsp_pktid.read();
        r_init_rsp_fsm = INIT_RSP_IDLE;

#if DEBUG_MEMC_INIT_RSP
        if ( m_debug_init_rsp_fsm )
        {
          std::cout
            << "  <MEMC " << name()
            << ".INIT_RSP_END> Request TGT_RSP FSM to send a response to srcid "
            << r_init_rsp_srcid.read()
            << std::endl;
        }
#endif
      }
      break;
  } // end switch r_init_rsp_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 << "  <MEMC " << name() << ".READ_IDLE> 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 
          << "  <MEMC " << name() << ".READ_DIR_REQ> 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
            << "  <MEMC " << name() << ".READ_DIR_LOCK> Accessing directory: "
            << " address = " << std::hex << m_cmd_read_addr_fifo.read()
            << " / hit = " << std::dec << entry.valid
            << " / count = " <<std::dec << entry.count
            << " / is_cnt = " << entry.is_cnt << std::endl;
            if((m_cmd_read_pktid_fifo.read() & 0x7) == TYPE_LL)
            {
              std::cout
                << "  <MEMC " << name() << ".READ_DIR_LOCK> 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);
        // 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
            << "  <MEMC " << name() << ".READ_DIR_HIT> Update directory entry:"
            << " 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

        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( 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 
          << "  <MEMC " << name() << ".READ_HEAP_REQ> 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 << "  <MEMC " << name() << ".READ_HEAP_LOCK> 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);

        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
            << "  <MEMC " << name() << ".READ_HEAP_WRITE> 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<m_words ; i++ )  r_read_to_tgt_rsp_data[i] = r_read_data[i];
        r_read_to_tgt_rsp_word   = m_x[(vci_addr_t)m_cmd_read_addr_fifo.read()];
        r_read_to_tgt_rsp_length = m_cmd_read_length_fifo.read();
        r_read_to_tgt_rsp_srcid  = m_cmd_read_srcid_fifo.read();
        r_read_to_tgt_rsp_trdid  = m_cmd_read_trdid_fifo.read();
        r_read_to_tgt_rsp_pktid  = m_cmd_read_pktid_fifo.read();
        r_read_to_tgt_rsp_ll_key = r_read_ll_key.read();
        cmd_read_fifo_get        = true;
        r_read_to_tgt_rsp_req    = true;
        r_read_fsm               = READ_IDLE;

#if DEBUG_MEMC_READ
        if( m_debug_read_fsm )
        {
          std::cout << "  <MEMC " << name() << ".READ_RSP> 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 << "  <MEMC " << name() << ".READ_TRT_LOCK> 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<be_t>(m_words,0),
            std::vector<data_t>(m_words,0),
            r_read_ll_key.read());
#if DEBUG_MEMC_READ
        if( m_debug_read_fsm )
        {
          std::cout << "  <MEMC " << name() << ".READ_TRT_SET> 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
            << "  <MEMC " << name() << ".READ_TRT_REQ> 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 INIT_CMD FSM. In case of coherence transaction, the WRITE FSM
  //   does not respond to the writing processor, as this response will be sent by
  //   the INIT_RSP 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;
        r_write_pending_sc  = false;
        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();

        // initialize the be field for all words
        for ( size_t word=0 ; word<m_words ; word++ )
        {
          if ( word == index ) r_write_be[word] = m_cmd_write_be_fifo.read();
          else                 r_write_be[word] = 0x0;
        }

        if( m_cmd_write_eop_fifo.read() || ((m_cmd_write_pktid_fifo.read() & 0x7)  == TYPE_SC) )
        {
          r_write_fsm = WRITE_DIR_REQ;
        }
        else
        {
          r_write_fsm = WRITE_NEXT;
        }

#if DEBUG_MEMC_WRITE
        if( m_debug_write_fsm )
        {
          std::cout << "  <MEMC " << name() << ".WRITE_IDLE> 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 << "  <MEMC " << name() << ".WRITE_NEXT> 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;
        r_write_pending_sc  = false;
        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
    {
      if ( r_alloc_dir_fsm.read() == ALLOC_DIR_WRITE )
      {
        if(((r_write_pktid.read() & 0x7) == TYPE_SC) && not r_write_pending_sc.read()) // check for an SC command (and check that its second flit is not already consumed)
        {
          if ( m_cmd_write_addr_fifo.rok() )
          {
            size_t index    = m_x[(vci_addr_t)(r_write_address.read())];
            bool sc_success = m_llsc_table.sc(r_write_address.read(),r_write_data[index].read());
            r_write_sc_fail = !sc_success;

            assert(m_cmd_write_eop_fifo.read() && "Error in VCI_MEM_CACHE : invalid packet format for SC command");
            // consume a word in the FIFO & write it in the local buffer
            cmd_write_fifo_get  = true;
            r_write_pending_sc  = true;
            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();
            if (!sc_success)
            {
              r_write_fsm = WRITE_RSP;
              break;
            }
          }
          else break;
        }
        //else it is a TYPE_WRITE, need a simple sw access to the
        // llsc_global_table
        else
        {
          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 
          << "  <MEMC " << name() << ".WRITE_DIR_REQ> 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 << "  <MEMC " << name() << ".WRITE_DIR_LOCK> 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 << "  <MEMC " << name() << ".WRITE_DIR_LOCK> global_llsc_table SC access" << std::endl;
          else
            std::cout << "  <MEMC " << name() << ".WRITE_DIR_LOCK> 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<m_words ; word++)
      {
        data_t mask = 0;
        if  (r_write_be[word].read() & 0x1) mask = mask | 0x000000FF;
        if  (r_write_be[word].read() & 0x2) mask = mask | 0x0000FF00;
        if  (r_write_be[word].read() & 0x4) mask = mask | 0x00FF0000;
        if  (r_write_be[word].read() & 0x8) mask = mask | 0xFF000000;

        // complete only if mask is not null (for energy consumption)
        r_write_data[word]  = (r_write_data[word].read() & mask) |
          (m_cache_data.read(way, set, word) & ~mask);

      } // end for

      // test if a coherence broadcast is required
      r_write_fsm = WRITE_BC_TRT_LOCK;

#if DEBUG_MEMC_WRITE
      if( m_debug_write_fsm )
      {
        std::cout << "  <MEMC " << name() << ".WRITE_DIR_READ> 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<m_words ; word++)
        {
          m_cache_data.write(way, set, word, r_write_data[word].read(), r_write_be[word].read());

          if ( m_monitor_ok )
          {
            vci_addr_t address = (r_write_address.read() & ~(vci_addr_t)0x3F) | word<<2;
            char buf[80];
            snprintf(buf, 80, "WRITE_DIR_HIT srcid %d", r_write_srcid.read());
            check_monitor( buf, address, r_write_data[word].read() );
          }
        }
      }

      if ( owner and not no_update and (r_write_pktid.read() != TYPE_SC))
      {
        r_write_count = r_write_count.read() - 1;
      }

      if ( no_update )
      // Write transaction completed
      {
        r_write_fsm = WRITE_RSP;
      }
      else
      // coherence update required
      {
        if( !r_write_to_init_cmd_multi_req.read()   &&
            !r_write_to_init_cmd_brdcast_req.read() )
        {
          r_write_fsm = WRITE_UPT_LOCK;
        }
        else
        {
          r_write_fsm = WRITE_WAIT;
        }
      }

#if DEBUG_MEMC_WRITE
      if( m_debug_write_fsm )
      {
        if ( no_update )
        {
          std::cout << "  <MEMC " << name() << ".WRITE_DIR_HIT> Write into cache / No coherence transaction"
            << std::endl;
        }
        else
        {
          std::cout << "  <MEMC " << name() << ".WRITE_DIR_HIT> 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<m_words ; word++)
          {
            m_cache_data.write(way, set, word, r_write_data[word].read(), r_write_be[word].read());

            if ( m_monitor_ok )
            {
              vci_addr_t address = (r_write_address.read() & ~(vci_addr_t)0x3F) | word<<2;
              char buf[80];
              snprintf(buf, 80, "WRITE_UPT_LOCK srcid %d", srcid);
              check_monitor(buf, address, r_write_data[word].read() );
            }
          }
        }

#if DEBUG_MEMC_WRITE
        if( m_debug_write_fsm )
        {
          if ( wok )
          {
            std::cout << "  <MEMC " << name() << ".WRITE_UPT_LOCK> 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 << "  <MEMC " << name() << ".WRITE_UPT_HEAP_LOCK> 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 INIT_CMD FSM
      // and write the first copy in the FIFO
      // send the request if only one copy

      if( !r_write_to_init_cmd_multi_req.read() &&
          !r_write_to_init_cmd_brdcast_req.read()  )  // no pending coherence request
      {
        r_write_to_init_cmd_brdcast_req  = false;
        r_write_to_init_cmd_trdid        = r_write_upt_index.read();
        r_write_to_init_cmd_nline        = m_nline[(vci_addr_t)(r_write_address.read())];
        r_write_to_init_cmd_index        = r_write_word_index.read();
        r_write_to_init_cmd_count        = r_write_word_count.read();

        for(size_t i=0; i<m_words ; i++) r_write_to_init_cmd_be[i]=r_write_be[i].read();

        size_t min = r_write_word_index.read();
        size_t max = r_write_word_index.read() + r_write_word_count.read();
        for (size_t i=min ; i<max ; i++) r_write_to_init_cmd_data[i] = r_write_data[i];

        if( (r_write_copy.read() != r_write_srcid.read()) or (r_write_pktid.read() == TYPE_SC) or
#if L1_MULTI_CACHE
            (r_write_copy_cache.read() != r_write_pktid.read()) or
#endif
            r_write_copy_inst.read() )
        {
          // put the first srcid in the fifo
          write_to_init_cmd_fifo_put     = true;
          write_to_init_cmd_fifo_inst    = r_write_copy_inst.read();
          write_to_init_cmd_fifo_srcid   = r_write_copy.read();
#if L1_MULTI_CACHE
          write_to_init_cmd_fifo_cache_id= r_write_copy_cache.read();
#endif
          if(r_write_count.read() == 1)
          {
            r_write_fsm = WRITE_IDLE;
            r_write_to_init_cmd_multi_req = true;
          }
          else
          {
            r_write_fsm = WRITE_UPT_NEXT;
            r_write_to_dec = false;

          }
        }
        else
        {
          r_write_fsm = WRITE_UPT_NEXT;
          r_write_to_dec = false;
        }

#if DEBUG_MEMC_WRITE
        if( m_debug_write_fsm )
        {
          std::cout << "  <MEMC " << name() << ".WRITE_UPT_REQ> Post first request to INIT_CMD 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 INIT_CMD 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_init_cmd_fifo_put      = true;
        write_to_init_cmd_fifo_inst     = entry.owner.inst;
        write_to_init_cmd_fifo_srcid    = entry.owner.srcid;
#if L1_MULTI_CACHE
        write_to_init_cmd_fifo_cache_id = entry.owner.cache_id;
#endif

#if DEBUG_MEMC_WRITE
        if( m_debug_write_fsm )
        {
          std::cout << "  <MEMC " << name() << ".WRITE_UPT_NEXT> Post another request to INIT_CMD 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 << "  <MEMC " << name() << ".WRITE_UPT_NEXT> 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_init_cmd_inst_fifo.wok() )
      {
        std::cout << "VCI_MEM_CACHE ERROR " << name() << " WRITE_UPT_NEXT state" << std::endl
          << "The write_to_init_cmd_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_init_cmd_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 INIT_RSP FSM.

      if ( !r_write_to_init_rsp_req.read() )
      {
        r_write_to_init_rsp_req = true;
        r_write_to_init_rsp_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;
          r_write_pending_sc  = false;
          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();

          // initialize the be field for all words
          for ( size_t word=0 ; word<m_words ; word++ )
          {
            if ( word == index ) r_write_be[word] = m_cmd_write_be_fifo.read();
            else                 r_write_be[word] = 0x0;
          }

          if( m_cmd_write_eop_fifo.read() || ((m_cmd_write_pktid_fifo.read() & 0x7)  == TYPE_SC) )
          {
            r_write_fsm = WRITE_DIR_REQ;
          }
          else
          {
            r_write_fsm = WRITE_NEXT;
          }
        }
        else
        {
          r_write_fsm = WRITE_IDLE;
        }

#if DEBUG_MEMC_WRITE
        if( m_debug_write_fsm )
        {
          std::cout << "  <MEMC " << name() << ".WRITE_RSP> 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 << "  <MEMC " << name() << ".WRITE_MISS_TRT_LOCK> 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 << "  <MEMC " << name() << ".WRITE_WAIT> 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_t>   be_vector;
        std::vector<data_t> data_vector;
        be_vector.clear();
        data_vector.clear();
        for ( size_t i=0; i<m_words; i++ )
        {
          be_vector.push_back(r_write_be[i]);
          data_vector.push_back(r_write_data[i]);
        }
        m_transaction_tab.set(r_write_trt_index.read(),
            true,     // read request to XRAM
            m_nline[(vci_addr_t)(r_write_address.read())],
            r_write_srcid.read(),
            r_write_trdid.read(),
            r_write_pktid.read(),
            false,      // not a processor read
            0,        // not a single word
            0,            // word index
            be_vector,
            data_vector);
        r_write_fsm = WRITE_MISS_XRAM_REQ;

#if DEBUG_MEMC_WRITE
        if( m_debug_write_fsm )
        {
          std::cout << "  <MEMC " << name() << ".WRITE_MISS_TRT_SET> 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_t> be_vector;
        std::vector<data_t> data_vector;
        be_vector.clear();
        data_vector.clear();
        for ( size_t i=0; i<m_words; i++ )
        {
          be_vector.push_back(r_write_be[i]);
          data_vector.push_back(r_write_data[i]);
        }
        m_transaction_tab.write_data_mask(r_write_trt_index.read(),
            be_vector,
            data_vector);
        r_write_fsm = WRITE_RSP;

#if DEBUG_MEMC_WRITE
        if( m_debug_write_fsm )
        {
          std::cout << "  <MEMC " << name() << ".WRITE_MISS_TRT_DATA> 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 << "  <MEMC " << name() << ".WRITE_MISS_XRAM_REQ> 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 << "  <MEMC " << name() << ".WRITE_BC_TRT_LOCK> 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 << "  <MEMC " << name() << ".WRITE_BC_UPT_LOCK> 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<be_t>(m_words,0),
          std::vector<data_t>(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 << "  <MEMC " << name() << ".WRITE_BC_DIR_INVAL> 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 INIT_CMD FSM
    {
      if ( !r_write_to_init_cmd_multi_req.read() && !r_write_to_init_cmd_brdcast_req.read() )
      {
        r_write_to_init_cmd_multi_req   = false;
        r_write_to_init_cmd_brdcast_req = true;
        r_write_to_init_cmd_trdid       = r_write_upt_index.read();
        r_write_to_init_cmd_nline       = m_nline[(vci_addr_t)(r_write_address.read())];
        r_write_to_init_cmd_index       = 0;
        r_write_to_init_cmd_count       = 0;

        for(size_t i=0; i<m_words ; i++)
        {
          r_write_to_init_cmd_be[i]=0;
          r_write_to_init_cmd_data[i] = 0;
        }
        r_write_fsm = WRITE_BC_XRAM_REQ;

#if DEBUG_MEMC_WRITE
        if( m_debug_write_fsm )
        {
          std::cout << "  <MEMC " << name() << ".WRITE_BC_CC_SEND> Post a broadcast request to INIT_CMD 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<m_words; i++) r_write_to_ixr_cmd_data[i] = r_write_data[i];

        r_write_fsm = WRITE_IDLE;

#if DEBUG_MEMC_WRITE
        if( m_debug_write_fsm )
        {
          std::cout << "  <MEMC " << name() << ".WRITE_BC_XRAM_REQ> 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 << "  <MEMC " << name() << ".IXR_CMD_READ_NLINE> 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 << "  <MEMC " << name() << ".IXR_CMD_WRITE_NLINE> 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 << "  <MEMC " << name() << ".IXR_CMD_WRITE_NLINE> 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 << "  <MEMC " << name() << ".IXR_CMD_CAS_NLINE> 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 << "  <MEMC " << name() << ".IXR_CMD_CAS_NLINE> 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 << "  <MEMC " << name() << ".IXR_CMD_XRAM_DATA> 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 << "  <MEMC " << name() << ".IXR_RSP_IDLE> 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 << "  <MEMC " << name() << ".IXR_RSP_IDLE> 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 << "  <MEMC " << name() << ".IXR_RSP_ACK>" << 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 << "  <MEMC " << name() << ".IXR_RSP_TRT_ERASE> 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 << "  <MEMC " << name() << ".IXR_RSP_TRT_READ> 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<lines ; i++)
            {
                size_t index=(i+ptr+1)%lines;
                if ( r_ixr_rsp_to_xram_rsp_rok[index] )
                {
                    r_xram_rsp_trt_index             = index;
                    r_ixr_rsp_to_xram_rsp_rok[index] = false;
                    r_xram_rsp_fsm                   = XRAM_RSP_DIR_LOCK;

#if DEBUG_MEMC_XRAM_RSP
if( m_debug_xram_rsp_fsm )
{
    std::cout << "  <MEMC " << name() << ".XRAM_RSP_IDLE> 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 << "  <MEMC " << name() << ".XRAM_RSP_DIR_LOCK> 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 << "  <MEMC " << name() << ".XRAM_RSP_TRT_COPY> 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 << "  <MEMC " << name() << ".XRAM_RSP_INVAL_LOCK> 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 << "  <MEMC " << name() << ".XRAM_RSP_INVAL_LOCK> 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 << "  <MEMC " << name() << ".XRAM_RSP_INVAL_LOCK> 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<m_words ; word++)
            {
                m_cache_data.write(way, set, word, r_xram_rsp_trt_buf.wdata[word]);

                if ( m_monitor_ok )
                {
                    vci_addr_t address = r_xram_rsp_trt_buf.nline<<6 | word<<2;
                    check_monitor("XRAM_RSP_DIR_UPDT", address, r_xram_rsp_trt_buf.wdata[word]);
                }
            }
            // compute dirty
            bool dirty = false;
            for(size_t i=0; i<m_words;i++) dirty = dirty || (r_xram_rsp_trt_buf.wdata_be[i] != 0);
            // update directory
            DirectoryEntry entry;
            entry.valid   = true;
            entry.is_cnt  = false;
            entry.lock    = false;
            entry.dirty   = dirty;
            entry.tag     = r_xram_rsp_trt_buf.nline / m_sets;
            entry.ptr     = 0;
            if(cached_read)
            {
                entry.owner.srcid   = r_xram_rsp_trt_buf.srcid;
#if L1_MULTI_CACHE
                entry.owner.cache_id= r_xram_rsp_trt_buf.pktid;
#endif
                entry.owner.inst    = inst_read;
                entry.count         = 1;
            }
            else
            {
                entry.owner.srcid    = 0;
#if L1_MULTI_CACHE
                entry.owner.cache_id = 0;
#endif
                entry.owner.inst     = 0;
                entry.count          = 0;
            }
            m_cache_directory.write(set, way, entry);

            if (r_xram_rsp_victim_inval.read())
            {
                bool   brdcast    = r_xram_rsp_victim_is_cnt.read();
                size_t index    = 0;
                size_t count_copies   = r_xram_rsp_victim_count.read();

                bool   wok = m_update_tab.set(  false,    // it's an inval transaction
                        brdcast,  // set brdcast bit
                        false,    // it does not need a response
                        0,    // srcid
                        0,    // trdid
                        0,    // pktid
                        r_xram_rsp_victim_nline.read(),
                        count_copies,
                        index);
                r_xram_rsp_upt_index = index;

                if (!wok)
                {
                    std::cout << "VCI_MEM_CACHE ERROR " << name() << " XRAM_RSP_HEAP_LAST state" << std::endl;
                    std::cout << "an update_tab entry was free but write is unsuccessful" << std::endl;
                    exit(0);
                }
            }

#if DEBUG_MEMC_XRAM_RSP
if( m_debug_xram_rsp_fsm )
{
    std::cout << "  <MEMC " << name() << ".XRAM_RSP_DIR_UPDT> Directory update: "
              << " way = " << std::dec << way
              << " / set = " << set
              << " / 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<be_t>(m_words,0),
                                       std::vector<data_t>(m_words,0) );

#if DEBUG_MEMC_XRAM_RSP
if( m_debug_xram_rsp_fsm )
{
    std::cout << "  <MEMC " << name() << ".XRAM_RSP_TRT_DIRTY> 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 << "  <MEMC " << name() << ".XRAM_RSP_DIR_RSP> 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 INIT_CMD FSM
        {
            if(   !r_xram_rsp_to_init_cmd_multi_req.read() &&
                  !r_xram_rsp_to_init_cmd_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_init_cmd_multi_req    = last_multi_req;
                r_xram_rsp_to_init_cmd_brdcast_req  = r_xram_rsp_victim_is_cnt.read();
                r_xram_rsp_to_init_cmd_nline        = r_xram_rsp_victim_nline.read();
                r_xram_rsp_to_init_cmd_trdid        = r_xram_rsp_upt_index;
                xram_rsp_to_init_cmd_fifo_srcid     = r_xram_rsp_victim_copy.read();
                xram_rsp_to_init_cmd_fifo_inst      = r_xram_rsp_victim_copy_inst.read();
#if L1_MULTI_CACHE
                xram_rsp_to_init_cmd_fifo_cache_id  = r_xram_rsp_victim_copy_cache.read();
#endif
                xram_rsp_to_init_cmd_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 << "  <MEMC " << name() << ".XRAM_RSP_INVAL> Send an inval request to INIT_CMD 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<m_words ; i++) r_xram_rsp_to_ixr_cmd_data[i] = r_xram_rsp_victim_data[i];
                m_cpt_write_dirty++;

                bool multi_req = !r_xram_rsp_victim_is_cnt.read() && r_xram_rsp_victim_inval.read();
                bool not_last_multi_req = multi_req && (r_xram_rsp_victim_count.read() != 1);
                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 << "  <MEMC " << name() << ".XRAM_RSP_WRITE_DIRTY> 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 
              << "  <MEMC " << name() << ".XRAM_RSP_HEAP_REQ> 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_init_cmd_fifo_srcid    = entry.owner.srcid;
#if L1_MULTI_CACHE
                xram_rsp_to_init_cmd_fifo_cache_id = entry.owner.cache_id;
#endif
                xram_rsp_to_init_cmd_fifo_inst  = entry.owner.inst;
                xram_rsp_to_init_cmd_fifo_put   = true;
                if( m_xram_rsp_to_init_cmd_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_init_cmd_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 << "  <MEMC " << name() << ".XRAM_RSP_HEAP_ERASE> 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 << "  <MEMC " << name() << ".XRAM_RSP_HEAP_LAST> 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 << "  <MEMC " << name() << ".XRAM_RSP_ERROR_ERASE> 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 << "  <MEMC " << name() << ".XRAM_RSP_ERROR_RSP> 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:
      {
        if ( p_vci_tgt_cleanup.cmdval.read() )
        {
          if (p_vci_tgt_cleanup.srcid.read() >= m_initiators )
          {
            std::cout << "VCI_MEM_CACHE ERROR " << name()
              << " CLEANUP_IDLE state" << std::endl;
            std::cout << "illegal srcid for  cleanup request" << std::endl;
            exit(0);
          }

          bool reached = false;
          for ( size_t index = 0 ; index < m_ncseg && !reached ; index++ )
          {
            if ( m_cseg[index]->contains((addr_t)(p_vci_tgt_cleanup.address.read())) )
              reached = true;
          }
          // only write request to a mapped address that are not broadcast are handled
          if (( p_vci_tgt_cleanup.cmd.read() == vci_param::CMD_WRITE ) &&
              (( p_vci_tgt_cleanup.address.read() & 0x3 ) == 0 ) && reached )
          {
            addr_t line =(((addr_t) p_vci_tgt_cleanup.be.read() << (vci_param::B*8))) |
              (((addr_t) p_vci_tgt_cleanup.wdata.read()));

            r_cleanup_nline = line;
            r_cleanup_srcid = p_vci_tgt_cleanup.srcid.read();
            r_cleanup_trdid = p_vci_tgt_cleanup.trdid.read();
            r_cleanup_pktid = p_vci_tgt_cleanup.pktid.read();
            r_cleanup_fsm   = CLEANUP_DIR_REQ;

  #if DEBUG_MEMC_CLEANUP
            if( m_debug_cleanup_fsm )
            {
              std::cout << "  <MEMC " << name() << ".CLEANUP_IDLE> Cleanup request:" << std::hex
                << " line addr = " << line * m_words * 4
                << " / owner_id = " << p_vci_tgt_cleanup.srcid.read()
                << " / owner_ins = " << (p_vci_tgt_cleanup.trdid.read()&0x1)
                << std::endl;
            }
  #endif
            m_cpt_cleanup++;
          }
        }
        break;
      }

      //////////////////////
      case CLEANUP_DIR_REQ:
      // Get the lock to the directory
      {
        if ( r_alloc_dir_fsm.read() == ALLOC_DIR_CLEANUP )
        {
          r_cleanup_fsm = CLEANUP_DIR_LOCK;
        }

#if DEBUG_MEMC_CLEANUP
        if( m_debug_cleanup_fsm )
        {
          std::cout 
            << "  <MEMC " << name() << ".CLEANUP_DIR_REQ> Requesting DIR lock "
            << std::endl;
        }
#endif
        break;
      }

      //////////////////////
      case CLEANUP_DIR_LOCK:  // test directory status
      {
        if ( r_alloc_dir_fsm.read() == ALLOC_DIR_CLEANUP )
        {
          // 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_copy         = entry.owner.srcid;
#if L1_MULTI_CACHE
          r_cleanup_copy_cache   = entry.owner.cache_id;
#endif
          r_cleanup_copy_inst    = entry.owner.inst;
          r_cleanup_count        = entry.count;
          r_cleanup_ptr          = entry.ptr;

          if( entry.valid) //  hit : the copy must be cleared
          {
            if ( (entry.count==1) || (entry.is_cnt) )  // no access to the heap
            {
              r_cleanup_fsm = CLEANUP_DIR_WRITE;
            }
            else          // access to the heap
            {
              r_cleanup_fsm = CLEANUP_HEAP_REQ;
            }
          }
          else    // miss : we must check the update table
          {
            r_cleanup_fsm = CLEANUP_UPT_LOCK;
          }

#if DEBUG_MEMC_CLEANUP
          if( m_debug_cleanup_fsm )
          {
            std::cout
              << "  <MEMC " << name()
              << ".CLEANUP_DIR_LOCK> Test directory status: " << std::hex
              << " line = " << r_cleanup_nline.read() * m_words * 4
              << " / hit = " << entry.valid
              << " / dir_id = " << entry.owner.srcid
              << " / dir_ins = " << entry.owner.inst
              << " / search_id = " << r_cleanup_srcid.read()
              << " / search_ins = " << (r_cleanup_trdid.read()&0x1)
              << " / count = " << entry.count
              << " / is_cnt = " << entry.is_cnt << std::endl;
          }
#endif
        }
        else
        {
          std::cout << "VCI_MEM_CACHE ERROR " << name()
            << " CLEANUP_DIR_LOCK state"
            << " bad DIR allocation" << std::endl;

          exit(0);
        }
        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 cleanup_inst  = r_cleanup_trdid.read() & 0x1;
        bool match_srcid   = ((r_cleanup_copy.read() == r_cleanup_srcid.read())
#if L1_MULTI_CACHE
            and (r_cleanup_copy_cache.read() == r_cleanup_pktid.read())
#endif
            );
        bool match_inst    = (r_cleanup_copy_inst.read()  == cleanup_inst);
        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_RSP;

#if DEBUG_MEMC_CLEANUP
        if( m_debug_cleanup_fsm )
        {
          std::cout
            << "  <MEMC " << name()
            << ".CLEANUP_DIR_WRITE> Update directory:" << std::hex
            << " line = " << 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 )
        {
          r_cleanup_fsm = CLEANUP_HEAP_LOCK;
        }

#if DEBUG_MEMC_CLEANUP
        if( m_debug_cleanup_fsm )
        {
          std::cout 
            << "  <MEMC " << name() << ".CLEANUP_HEAP_REQ> Requesting HEAP lock "
            << std::endl;
        }
#endif
        break;
      }

      ///////////////////////
      case CLEANUP_HEAP_LOCK:
      // two cases are handled in this state:
      // - the matching copy is directly in the directory
      // - the matching copy is the first copy in the heap
      {
        if ( r_alloc_heap_fsm.read() == ALLOC_HEAP_CLEANUP )
        {
          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());
          bool cleanup_inst       = r_cleanup_trdid.read() & 0x1;

          // match_dir computation
          bool match_dir_srcid    = (r_cleanup_copy.read() == r_cleanup_srcid.read());
          bool match_dir_inst     = (r_cleanup_copy_inst.read()  == cleanup_inst);
          bool match_dir          = match_dir_srcid and match_dir_inst;
#if L1_MULTI_CACHE
          match_dir = match_dir and (r_cleanup_copy_cache.read() == r_cleanup_pktid.read());
#endif

          // match_heap computation
          bool match_heap_srcid   = (heap_entry.owner.srcid == r_cleanup_srcid.read());
          bool match_heap_inst    = (heap_entry.owner.inst  == cleanup_inst);
          bool match_heap         = match_heap_srcid and match_heap_inst;
#if L1_MULTI_CACHE
          match_heap = match_heap and (heap_entry.owner.cache_id == r_cleanup_pktid.read());
#endif

          r_cleanup_prev_ptr      = r_cleanup_ptr.read();
          r_cleanup_prev_srcid    = heap_entry.owner.srcid;
#if L1_MULTI_CACHE
          r_cleanup_prev_cache_id = heap_entry.owner.cache_id;
#endif
          r_cleanup_prev_inst     = heap_entry.owner.inst;

          if (match_dir)
          // the matching copy is registered in the directory
          {
            // the copy registered in the directory must be replaced
            // by the first copy registered in the heap
            // and the corresponding entry must be freed
            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.ptr            = heap_entry.next;
            dir_entry.count          = r_cleanup_count.read()-1;
            dir_entry.owner.srcid    = heap_entry.owner.srcid;
#if L1_MULTI_CACHE
            dir_entry.owner.cache_id = heap_entry.owner.cache_id;
#endif
            dir_entry.owner.inst     = heap_entry.owner.inst;

            m_cache_directory.write(set,way,dir_entry);

            r_cleanup_next_ptr       = r_cleanup_ptr.read();
            r_cleanup_fsm            = CLEANUP_HEAP_FREE;
          }
          else if (match_heap)
          // the matching copy is the first copy in the heap
          {
            // The first copy in heap must be freed
            // and the copy registered in directory must point to the next copy in heap
            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.ptr            = heap_entry.next;
            dir_entry.count          = r_cleanup_count.read()-1;
            dir_entry.owner.srcid    = r_cleanup_copy.read();
#if L1_MULTI_CACHE
            dir_entry.owner.cache_id = r_cleanup_copy_cache.read();
#endif
            dir_entry.owner.inst     = r_cleanup_copy_inst.read();

            m_cache_directory.write(set,way,dir_entry);

            r_cleanup_next_ptr       = r_cleanup_ptr.read();
            r_cleanup_fsm            = CLEANUP_HEAP_FREE;
          }
          else if(!last)
          // The matching copy is in the heap, but is not the first copy
          {
            // The directory entry must be modified to decrement count
            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.ptr            = r_cleanup_ptr.read();
            dir_entry.count          = r_cleanup_count.read()-1;
            dir_entry.owner.srcid    = r_cleanup_copy.read();
#if L1_MULTI_CACHE
            dir_entry.owner.cache_id = r_cleanup_copy_cache.read();
#endif
            dir_entry.owner.inst     = r_cleanup_copy_inst.read();

            m_cache_directory.write(set,way,dir_entry);

            r_cleanup_next_ptr       = heap_entry.next;
            r_cleanup_fsm            = CLEANUP_HEAP_SEARCH;
          }
          else
          {
            std::cout << "VCI_MEM_CACHE ERROR " << name()
              << " CLEANUP_HEAP_LOCK state"
              << " hit but copy not found" << std::endl;
            exit(0);
          }

#if DEBUG_MEMC_CLEANUP
          if( m_debug_cleanup_fsm )
          {
            std::cout
              << "  <MEMC " << name() << ".CLEANUP_HEAP_LOCK> Checks matching:"
              << " line = " << 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_trdid.read()&0x1) << std::endl;
          }
#endif
        }
        else
        {
          std::cout << "VCI_MEM_CACHE ERROR " << name()
            << " CLEANUP_HEAP_LOCK state"
            << " bad HEAP allocation" << std::endl;

          exit(0);
        }
        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 cleanup_inst     = r_cleanup_trdid.read() & 0x1;
        bool match_heap_srcid = (heap_entry.owner.srcid == r_cleanup_srcid.read());
        bool match_heap_inst  = (heap_entry.owner.inst  == cleanup_inst);
        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 DEBUG_MEMC_CLEANUP
        if( m_debug_cleanup_fsm )
        {
          std::cout << "  <MEMC " << name() << ".CLEANUP_HEAP_SEARCH> Cheks matching:"
            << " line = " << 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_trdid.read()&0x1)
            << " / last = " << last << std::endl;
        }
#endif
        if(match_heap) // the matching copy must be removed
        {
          r_cleanup_ptr = heap_entry.next; // reuse ressources
          r_cleanup_fsm = CLEANUP_HEAP_CLEAN;
        }
        else
        {
          if ( last )
          {
            std::cout << "VCI_MEM_CACHE_ERROR " << name()
              << " CLEANUP_HEAP_SEARCH state"
              << " cleanup hit but copy not found" << std::endl;
            exit(0);
          }
          else // test the next in the linked list
          {
            r_cleanup_prev_ptr      = r_cleanup_next_ptr.read();
            r_cleanup_prev_srcid    = heap_entry.owner.srcid;
#if L1_MULTI_CACHE
            r_cleanup_prev_cache_id = heap_entry.owner.cache_id;
#endif
            r_cleanup_prev_inst     = heap_entry.owner.inst;
            r_cleanup_next_ptr      = heap_entry.next;
            r_cleanup_fsm           = CLEANUP_HEAP_SEARCH;

#if DEBUG_MEMC_CLEANUP
            if( m_debug_cleanup_fsm )
            {
              std::cout << "  <MEMC " << name() << ".CLEANUP_HEAP_SEARCH> Matching copy not found, search next:"
                << " line = " << 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_trdid.read()&0x1) << 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);
        }

        bool last = (r_cleanup_next_ptr.read() == r_cleanup_ptr.read());
        HeapEntry heap_entry;
        heap_entry.owner.srcid    = r_cleanup_prev_srcid.read();
#if L1_MULTI_CACHE
        heap_entry.owner.cache_id = r_cleanup_prev_cache_id.read();
#endif
        heap_entry.owner.inst     = r_cleanup_prev_inst.read();
        
        if(last) // this is the last entry of the list of copies
        {
          heap_entry.next     = r_cleanup_prev_ptr.read();
        }
        else  // this is not the last entry
        {
          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 << "  <MEMC " << name() << ".CLEANUP_HEAP_SEARCH> 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;
#if L1_MULTI_CACHE
        heap_entry.owner.cache_id = 0;
#endif
        heap_entry.owner.inst     = false;

        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_RSP;

#if DEBUG_MEMC_CLEANUP
        if( m_debug_cleanup_fsm )
        {
          std::cout << "  <MEMC " << name() << ".CLEANUP_HEAP_SEARCH> Update the list of free entries" << std::endl;
        }
#endif
        break;
      }

      //////////////////////
      case CLEANUP_UPT_LOCK:
      {
        if ( r_alloc_upt_fsm.read() == ALLOC_UPT_CLEANUP )
        {
          size_t index = 0;
          bool hit_inval;
          hit_inval = m_update_tab.search_inval(r_cleanup_nline.read(),index);

          if ( !hit_inval ) // no pending inval
          {

#if DEBUG_MEMC_CLEANUP
            if( m_debug_cleanup_fsm )
            {
              std::cout << "  <MEMC " << name() << ".CLEANUP_UPT_LOCK> Unexpected cleanup with no corresponding UPT entry:"
                << " address = " << std::hex << (r_cleanup_nline.read()*4*m_words) << std::endl;
            }
#endif
            r_cleanup_fsm = CLEANUP_RSP;
          }
          else    // 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_need_rsp    = m_update_tab.need_rsp(index);
            r_cleanup_fsm = CLEANUP_UPT_WRITE;
          }
          r_cleanup_index.write(index) ;
        }
        break;
      }

      ///////////////////////
      case CLEANUP_UPT_WRITE:  // decrement response counter
      {
        size_t count = 0;
        m_update_tab.decrement(r_cleanup_index.read(), count);
        if ( count == 0 )
        {
          m_update_tab.clear(r_cleanup_index.read());

#if DEBUG_MEMC_CLEANUP
          if( m_debug_cleanup_fsm )
          {
            std::cout << "  <MEMC " << name() << ".CLEANUP_UPT_WRITE> Decrement response counter in UPT:"
              << " UPT_index = " << r_cleanup_index.read()
              << " rsp_count = " << count << std::endl;
          }
#endif
          if( r_cleanup_need_rsp.read() ) r_cleanup_fsm = CLEANUP_WRITE_RSP ;
          else                      r_cleanup_fsm = CLEANUP_RSP;
        }
        else
        {
          r_cleanup_fsm = CLEANUP_RSP ;
        }
        break;
      }

      ///////////////////////
      case CLEANUP_WRITE_RSP: // Response to a previous write on the direct network
      {
        if( !r_cleanup_to_tgt_rsp_req.read() )
        {
          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_RSP;

#if DEBUG_MEMC_CLEANUP
          if( m_debug_cleanup_fsm )
          {
            std::cout << "  <MEMC " << name() << ".CLEANUP_WRITE_RSP> Send a response to a cleanup request:"
              << " rsrcid = " << std::dec << r_cleanup_write_srcid.read()
              << " / rtrdid = " << std::dec << r_cleanup_write_trdid.read() << std::endl;
          }
#endif
        }
        break;
      }

      /////////////////
      case CLEANUP_RSP: // Response to a cleanup on the coherence network
      {
        if ( p_vci_tgt_cleanup.rspack.read() )
        {
          r_cleanup_fsm = CLEANUP_IDLE;

#if DEBUG_MEMC_CLEANUP
          if( m_debug_cleanup_fsm )
          {
            std::cout << "  <MEMC " << name() << ".CLEANUP_RSP> Send the response to a cleanup request:"
              << " rsrcid = " << std::dec << r_cleanup_write_srcid.read()
              << " / rtrdid = " << r_cleanup_write_trdid.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 << "  <MEMC " << name() << ".CAS_IDLE> 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 
                << "  <MEMC " << name() << ".CAS_DIR_REQ> 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 << "  <MEMC " << name() << ".CAS_DIR_LOCK> 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())];
            size_t word = m_x[(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);

            // read data in cache & check data change
            bool ok = ( r_cas_rdata[0].read() == m_cache_data.read(way, set, word) );
            if ( r_cas_cpt.read()==4 )  // 64 bits CAS
                ok &= ( r_cas_rdata[1] == m_cache_data.read(way, set, 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);

            if( ok and not forced_fail )  // no data change
            {
                r_cas_fsm = CAS_DIR_HIT_WRITE;
            }
            else                            // return failure
            {
                r_cas_fsm = CAS_RSP_FAIL;
            }

#if DEBUG_MEMC_CAS
if( m_debug_cas_fsm )
{
    std::cout << "  <MEMC " << name() << ".CAS_DIR_HIT_READ> Test if CAS success:"
              << " / expected value = " << r_cas_rdata[0].read()
              << " / actual value = " << m_cache_data.read(way, set, word)
              << " / 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_init_cmd_multi_req.read() &&
                         !r_cas_to_init_cmd_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());

                // 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() );
                }
                r_cas_fsm = CAS_RSP_SUCCESS;

#if DEBUG_MEMC_CAS
if( m_debug_cas_fsm )
{
    std::cout << "  <MEMC " << name() << ".CAS_DIR_HIT_WRITE> Update cache:"
              << " way = " << std::dec << way
              << " / set = " << set
              << " / word = " << word
              << " / value = " << r_cas_wdata.read()
              << " / count = " << r_cas_count.read() << std::endl;
    std::cout << "  <MEMC " << name() << ".CAS_DIR_HIT_WRITE> 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());

                    // 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() );
                    }

                    r_cas_upt_index = index;
                    r_cas_fsm = CAS_UPT_HEAP_LOCK;
                }
                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 << "  <MEMC " << name() << ".CAS_UPT_LOCK> 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 << "  <MEMC " << name() << ".CAS_WAIT> 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 << "  <MEMC " << name() << ".CAS_UPT_HEAP_LOCK> 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 INIT_CMD FSM
        {
            assert((r_alloc_heap_fsm.read() == ALLOC_HEAP_CAS) and
                   "VCI_MEM_CACHE ERROR : bad HEAP allocation");

            if( !r_cas_to_init_cmd_multi_req.read() && !r_cas_to_init_cmd_brdcast_req.read() )
            {
                r_cas_to_init_cmd_brdcast_req  = false;
                r_cas_to_init_cmd_trdid        = r_cas_upt_index.read();
                r_cas_to_init_cmd_nline        = m_nline[(vci_addr_t)(m_cmd_cas_addr_fifo.read())];
                r_cas_to_init_cmd_index        = m_x[(vci_addr_t)(m_cmd_cas_addr_fifo.read())];
                r_cas_to_init_cmd_wdata        = r_cas_wdata.read();

                if(r_cas_cpt.read() == 4)
                {
                    r_cas_to_init_cmd_is_long    = true;
                    r_cas_to_init_cmd_wdata_high = m_cmd_cas_wdata_fifo.read();
                }
                else
                {
                    r_cas_to_init_cmd_is_long    = false;
                    r_cas_to_init_cmd_wdata_high = 0;
                }

                // We put the first copy in the fifo
                cas_to_init_cmd_fifo_put     = true;
                cas_to_init_cmd_fifo_inst    = r_cas_copy_inst.read();
                cas_to_init_cmd_fifo_srcid   = r_cas_copy.read();
#if L1_MULTI_CACHE
                cas_to_init_cmd_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_init_cmd_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 << "  <MEMC " << name() << ".CAS_UPT_REQ> Send the first update request to INIT_CMD 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 INIT_CMD 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_init_cmd_fifo_srcid    = entry.owner.srcid;
#if L1_MULTI_CACHE
            cas_to_init_cmd_fifo_cache_id = entry.owner.cache_id;
#endif
            cas_to_init_cmd_fifo_inst     = entry.owner.inst;
            cas_to_init_cmd_fifo_put = true;

            if( m_cas_to_init_cmd_inst_fifo.wok() ) // request accepted by INIT_CMD FSM
            {
                r_cas_ptr = entry.next;
                if( entry.next == r_cas_ptr.read() )  // last copy
                {
                    r_cas_to_init_cmd_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 << "  <MEMC " << name() << ".CAS_UPT_NEXT> Send the next update request to INIT_CMD 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 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())];
                    for(size_t i = 0; i<m_words; i++)
                    {
                        if (i == word)
                        {
                            r_cas_to_ixr_cmd_data[i] = r_cas_wdata.read();
                        }
                        else if ( (i == word+1) && (r_cas_cpt.read()==4) ) // 64 bit CAS
                        {
                            r_cas_to_ixr_cmd_data[i] = m_cmd_cas_wdata_fifo.read();
                        }
                        else
                        {
                            r_cas_to_ixr_cmd_data[i] = m_cache_data.read(way, set, i);
                        }
                    }
                    size_t wok_index = 0;
                    bool   wok       = !m_transaction_tab.full(wok_index);
                    if ( wok )
                    {
                        r_cas_trt_index = wok_index;
                        r_cas_fsm       = CAS_BC_UPT_LOCK;
                    }
                    else
                    {
                        r_cas_fsm       = CAS_WAIT;
                    }
                }
                else
                {
                    r_cas_fsm = CAS_WAIT;
                }
            }
            break;
        }
        ///////////////////
        case CAS_BC_UPT_LOCK:  // register a broadcast inval transaction in UPT
                              // write data in cache in case of successful registration
        {
            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();

                // register a broadcast inval transaction in UPT
                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 ( wok )  // UPT not full
                {
                    // 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());

                    // 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() );
                    }
                    r_cas_upt_index = index;
                    r_cas_fsm = CAS_BC_DIR_INVAL;
#if DEBUG_MEMC_CAS
if( m_debug_cas_fsm )
{
    std::cout << "  <MEMC " << name() << ".CAS_BC_UPT_LOCK> 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<be_t>(m_words,0),
                                      std::vector<data_t>(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 << "  <MEMC " << name() << ".CAS_BC_DIR_INVAL> 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 INIT_CMD FSM
        {
            if ( !r_cas_to_init_cmd_multi_req.read() &&
                 !r_cas_to_init_cmd_brdcast_req.read())
            {
                r_cas_to_init_cmd_multi_req    = false;
                r_cas_to_init_cmd_brdcast_req  = true;
                r_cas_to_init_cmd_trdid        = r_cas_upt_index.read();
                r_cas_to_init_cmd_nline        = m_nline[(vci_addr_t)(m_cmd_cas_addr_fifo.read())];
                r_cas_to_init_cmd_index        = 0;
                r_cas_to_init_cmd_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 << "  <MEMC " << name() << ".CAS_BC_XRAM_REQ> 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 << "  <MEMC " << name() << ".CAS_RSP_FAIL> 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 << "  <MEMC " << name() << ".CAS_RSP_SUCCESS> 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 << "  <MEMC " << name() << ".CAS_MISS_TRT_LOCK> 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_t> be_vector;
                std::vector<data_t> data_vector;
                be_vector.clear();
                data_vector.clear();
                for ( size_t i=0; i<m_words; i++ )
                {
                    be_vector.push_back(0);
                    data_vector.push_back(0);
                }

                m_transaction_tab.set(r_cas_trt_index.read(),
                                      true,   // read request
                                      m_nline[(vci_addr_t)m_cmd_cas_addr_fifo.read()],
                                      m_cmd_cas_srcid_fifo.read(),
                                      m_cmd_cas_trdid_fifo.read(),
                                      m_cmd_cas_pktid_fifo.read(),
                                      false,    // write request from processor
                                      0,
                                      0,
                                      be_vector,
                                      data_vector);
                r_cas_fsm = CAS_MISS_XRAM_REQ;

#if DEBUG_MEMC_CAS
if( m_debug_cas_fsm )
{
    std::cout << "  <MEMC " << name() << ".CAS_MISS_TRT_SET> 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 << "  <MEMC " << name() << ".CAS_MISS_XRAM_REQ> 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


    //////////////////////////////////////////////////////////////////////////////
    //    INIT_CMD FSM
    //////////////////////////////////////////////////////////////////////////////
    // The INIT_CMD fsm controls the VCI CMD initiator port on the coherence
    // network, used to update or invalidate cache lines in L1 caches.
    //
    // It implements a round-robin priority between the three possible client FSMs
    // XRAM_RSP, WRITE and CAS. Each FSM can request two types of services:
    // - r_xram_rsp_to_init_cmd_multi_req : multi-inval
    //   r_xram_rsp_to_init_cmd_brdcast_req : broadcast-inval
    // - r_write_to_init_cmd_multi_req : multi-update
    //   r_write_to_init_cmd_brdcast_req : broadcast-inval
    // - r_cas_to_init_cmd_multi_req : multi-update
    //   r_cas_to_init_cmd_brdcast_req : broadcast-inval
    //
    // An inval request is a single cell VCI write command containing the
    // index of the line to be invalidated.
    // An update request is a multi-cells VCI write command : The first cell
    // contains the index of the cache line to be updated. The second cell contains
    // the index of the first modified word in the line. The following cells
    // contain the data.
    ///////////////////////////////////////////////////////////////////////////////

    switch ( r_init_cmd_fsm.read() )
    {
        ////////////////////////
        case INIT_CMD_UPDT_IDLE:  // XRAM_RSP FSM has highest priority
        {
            if ( m_xram_rsp_to_init_cmd_inst_fifo.rok() ||
                 r_xram_rsp_to_init_cmd_multi_req.read()  )
            {
                r_init_cmd_fsm = INIT_CMD_INVAL_NLINE;
                m_cpt_inval++;
            }
            else if ( r_xram_rsp_to_init_cmd_brdcast_req.read() )
            {
                r_init_cmd_fsm = INIT_CMD_XRAM_BRDCAST;
                m_cpt_inval++;
            }
            else if ( m_write_to_init_cmd_inst_fifo.rok() ||
                      r_write_to_init_cmd_multi_req.read() )
            {
                r_init_cmd_fsm = INIT_CMD_UPDT_NLINE;
                m_cpt_update++;
            }
            else if ( r_write_to_init_cmd_brdcast_req.read() )
            {
                r_init_cmd_fsm = INIT_CMD_WRITE_BRDCAST;
                m_cpt_inval++;
            }
            else if ( m_cas_to_init_cmd_inst_fifo.rok() ||
                      r_cas_to_init_cmd_multi_req.read()  )
            {
                r_init_cmd_fsm = INIT_CMD_CAS_UPDT_NLINE;
                m_cpt_update++;
            }
            else if( r_cas_to_init_cmd_brdcast_req.read() )
            {
                r_init_cmd_fsm = INIT_CMD_CAS_BRDCAST;
                m_cpt_inval++;
            }
            break;
        }
        /////////////////////////
        case INIT_CMD_INVAL_IDLE: // WRITE FSM has highest priority
        {
            if ( m_write_to_init_cmd_inst_fifo.rok() ||
                 r_write_to_init_cmd_multi_req.read() )
            {
                r_init_cmd_fsm = INIT_CMD_UPDT_NLINE;
                m_cpt_update++;
            }
            else if ( r_write_to_init_cmd_brdcast_req.read() )
            {
                r_init_cmd_fsm = INIT_CMD_WRITE_BRDCAST;
                m_cpt_inval++;
            }
            else if ( m_cas_to_init_cmd_inst_fifo.rok() ||
                      r_cas_to_init_cmd_multi_req.read()  )
            {
                r_init_cmd_fsm = INIT_CMD_CAS_UPDT_NLINE;
                m_cpt_update++;
            }
            else if( r_cas_to_init_cmd_brdcast_req.read() )
            {
                r_init_cmd_fsm = INIT_CMD_CAS_BRDCAST;
                m_cpt_inval++;
            }
            else if ( m_xram_rsp_to_init_cmd_inst_fifo.rok() ||
                      r_xram_rsp_to_init_cmd_multi_req.read()  )
            {
                r_init_cmd_fsm = INIT_CMD_INVAL_NLINE;
                m_cpt_inval++;
            }
            else if ( r_xram_rsp_to_init_cmd_brdcast_req.read() )
            {
                r_init_cmd_fsm = INIT_CMD_XRAM_BRDCAST;
                m_cpt_inval++;
            }
            break;
        }
        //////////////////////////
        case INIT_CMD_CAS_UPDT_IDLE: // CAS FSM has highest priority
        {
            if ( m_cas_to_init_cmd_inst_fifo.rok() ||
                 r_cas_to_init_cmd_multi_req.read()  )
            {
                r_init_cmd_fsm = INIT_CMD_CAS_UPDT_NLINE;
                m_cpt_update++;
            }
            else if( r_cas_to_init_cmd_brdcast_req.read() )
            {
                r_init_cmd_fsm = INIT_CMD_CAS_BRDCAST;
                m_cpt_inval++;
            }
            else if ( m_xram_rsp_to_init_cmd_inst_fifo.rok() ||
                      r_xram_rsp_to_init_cmd_multi_req.read()  )
            {
                r_init_cmd_fsm = INIT_CMD_INVAL_NLINE;
                m_cpt_inval++;
            }
            else if ( r_xram_rsp_to_init_cmd_brdcast_req.read() )
            {
                r_init_cmd_fsm = INIT_CMD_XRAM_BRDCAST;
                m_cpt_inval++;
            }
            else if ( m_write_to_init_cmd_inst_fifo.rok() ||
                      r_write_to_init_cmd_multi_req.read() )
            {
                r_init_cmd_fsm = INIT_CMD_UPDT_NLINE;
                m_cpt_update++;
            }
            else if ( r_write_to_init_cmd_brdcast_req.read() )
            {
                r_init_cmd_fsm = INIT_CMD_WRITE_BRDCAST;
                m_cpt_inval++;
            }
            break;
        }
        //////////////////////////
        case INIT_CMD_INVAL_NLINE:  // send a multi-inval (from XRAM_RSP)
        {
            if ( m_xram_rsp_to_init_cmd_inst_fifo.rok() )
            {
                if ( p_vci_ini.cmdack )
                {
                    m_cpt_inval_mult++;
                    r_init_cmd_fsm = INIT_CMD_INVAL_NLINE;
                    xram_rsp_to_init_cmd_fifo_get = true;
                }
            }
            else
            {
                if( r_xram_rsp_to_init_cmd_multi_req.read() ) r_xram_rsp_to_init_cmd_multi_req = false;
                r_init_cmd_fsm = INIT_CMD_INVAL_IDLE;
            }
            break;
        }
        ///////////////////////////
        case INIT_CMD_XRAM_BRDCAST: // send a broadcast-inval (from XRAM_RSP)
        {
            if ( p_vci_ini.cmdack )
            {
                m_cpt_inval_brdcast++;
                r_init_cmd_fsm = INIT_CMD_INVAL_IDLE;
                r_xram_rsp_to_init_cmd_brdcast_req = false;
            }
            break;
        }
        ////////////////////////////
        case INIT_CMD_WRITE_BRDCAST:  // send a broadcast-inval (from WRITE FSM)
        {
            if( p_vci_ini.cmdack )
            {

#if DEBUG_MEMC_INIT_CMD
if( m_debug_init_cmd_fsm )
{
    std::cout << "  <MEMC " << name() << ".INIT_CMD_WRITE_BRDCAST> Broadcast-Inval for line "
              << r_write_to_init_cmd_nline.read() << std::endl;
}
#endif
                m_cpt_inval_brdcast++;
                r_write_to_init_cmd_brdcast_req = false;
                r_init_cmd_fsm = INIT_CMD_UPDT_IDLE;
            }
            break;
        }
        /////////////////////////
        case INIT_CMD_UPDT_NLINE:  // send nline for a multi-update (from WRITE FSM)
        {
            if ( m_write_to_init_cmd_inst_fifo.rok() )
            {
                if ( p_vci_ini.cmdack )
                {
                    m_cpt_update_mult++;
                    r_init_cmd_fsm = INIT_CMD_UPDT_INDEX;
                    // write_to_init_cmd_fifo_get = true;
                }
            }
            else
            {
                if ( r_write_to_init_cmd_multi_req.read() ) r_write_to_init_cmd_multi_req = false;
                r_init_cmd_fsm = INIT_CMD_UPDT_IDLE;
            }
            break;
        }
        /////////////////////////
        case INIT_CMD_UPDT_INDEX:  // send word index for a multi-update (from WRITE FSM)
        {
            r_init_cmd_cpt    = 0;
            if ( p_vci_ini.cmdack )  r_init_cmd_fsm = INIT_CMD_UPDT_DATA;
            break;
        }
        ////////////////////////
        case INIT_CMD_UPDT_DATA:  // send the data for a multi-update (from WRITE FSM)
        {
            if ( p_vci_ini.cmdack )
            {
                if ( r_init_cmd_cpt.read() == (r_write_to_init_cmd_count.read()-1) )
                {
                    r_init_cmd_fsm = INIT_CMD_UPDT_NLINE;
                    write_to_init_cmd_fifo_get = true;
                }
                else
                {
                    r_init_cmd_cpt = r_init_cmd_cpt.read() + 1;
                }
            }
            break;
        }
        /////////////////////////
        case INIT_CMD_CAS_BRDCAST: // send a broadcast-inval (from CAS FSM)
        {
            if( p_vci_ini.cmdack )
            {
                m_cpt_inval_brdcast++;
                r_cas_to_init_cmd_brdcast_req = false;
                r_init_cmd_fsm = INIT_CMD_CAS_UPDT_IDLE;
            }
            break;
        }
        ////////////////////////////
        case INIT_CMD_CAS_UPDT_NLINE:   // send nline for a multi-update (from CAS FSM)
        {
            if ( m_cas_to_init_cmd_inst_fifo.rok() )
            {
                if ( p_vci_ini.cmdack )
                {
                    m_cpt_update_mult++;
                    r_init_cmd_fsm = INIT_CMD_CAS_UPDT_INDEX;
                }
            }
            else
            {
                if( r_cas_to_init_cmd_multi_req.read() ) r_cas_to_init_cmd_multi_req = false;
                r_init_cmd_fsm = INIT_CMD_CAS_UPDT_IDLE;
            }
            break;
        }
        ////////////////////////////
        case INIT_CMD_CAS_UPDT_INDEX:  // send word index for a multi-update (from CAS FSM)
        {
            if ( p_vci_ini.cmdack )  r_init_cmd_fsm = INIT_CMD_CAS_UPDT_DATA;
            break;
        }
        ///////////////////////////
        case INIT_CMD_CAS_UPDT_DATA:  // send first data for a multi-update (from CAS FSM)
        {
            if ( p_vci_ini.cmdack )
            {
                if ( r_cas_to_init_cmd_is_long.read() )
                {
                    r_init_cmd_fsm = INIT_CMD_CAS_UPDT_DATA_HIGH;
                }
                else
                {
                    cas_to_init_cmd_fifo_get = true;
                    r_init_cmd_fsm = INIT_CMD_CAS_UPDT_NLINE;
                }
            }
            break;
        }
        ////////////////////////
        case INIT_CMD_CAS_UPDT_DATA_HIGH:  // send second data for a multi-update (from CAS FSM)
        {
            if ( p_vci_ini.cmdack )
            {
                cas_to_init_cmd_fifo_get = true;
                r_init_cmd_fsm = INIT_CMD_CAS_UPDT_NLINE;
            }
            break;
        }
    } // end switch r_init_cmd_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_init_rsp_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_init_rsp_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_init_rsp_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_init_rsp_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_init_rsp_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_init_rsp_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_init_rsp_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 << "  <MEMC " << name() << ".TGT_RSP_READ> 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 << "  <MEMC " << name() << ".TGT_RSP_WRITE> 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 << "  <MEMC " << name() << ".TGT_RSP_CLEANUP> 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 << "  <MEMC " << name() << ".TGT_RSP_CAS> 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 << "  <MEMC " << name() << ".TGT_RSP_XRAM> 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 << "  <MEMC " << name() << ".TGT_RSP_INIT> Write response after coherence transaction"
              << " / rsrcid = " << std::dec << r_init_rsp_to_tgt_rsp_srcid.read()
              << " / rtrdid = " << r_init_rsp_to_tgt_rsp_trdid.read()
              << " / rpktid = " << r_init_rsp_to_tgt_rsp_pktid.read() << std::endl;
}
#endif
                r_tgt_rsp_fsm = TGT_RSP_INIT_IDLE;
                r_init_rsp_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 : INIT_RSP > 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 INIT_RSP 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_INIT_RSP:
        if (( r_init_rsp_fsm.read() != INIT_RSP_UPT_LOCK  ) &&
            ( r_init_rsp_fsm.read() != INIT_RSP_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_init_rsp_fsm.read() == INIT_RSP_UPT_LOCK )
            r_alloc_upt_fsm = ALLOC_UPT_INIT_RSP;
        }
        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_init_rsp_fsm.read() == INIT_RSP_UPT_LOCK )
            r_alloc_upt_fsm = ALLOC_UPT_INIT_RSP;

          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_init_rsp_fsm.read() == INIT_RSP_UPT_LOCK )
            r_alloc_upt_fsm = ALLOC_UPT_INIT_RSP;

          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_init_rsp_fsm.read() == INIT_RSP_UPT_LOCK )
            r_alloc_upt_fsm = ALLOC_UPT_INIT_RSP;

          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_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();
      }
    }
    ////////////////////////////////////////////////////////////////////////////////////
    //    WRITE to INIT_CMD FIFO
    ////////////////////////////////////////////////////////////////////////////////////

    if ( write_to_init_cmd_fifo_put ) {
      if ( write_to_init_cmd_fifo_get ) {
        m_write_to_init_cmd_inst_fifo.put_and_get(write_to_init_cmd_fifo_inst);
        m_write_to_init_cmd_srcid_fifo.put_and_get(write_to_init_cmd_fifo_srcid);
#if L1_MULTI_CACHE
        m_write_to_init_cmd_cache_id_fifo.put_and_get(write_to_init_cmd_fifo_cache_id);
#endif
      } else {
        m_write_to_init_cmd_inst_fifo.simple_put(write_to_init_cmd_fifo_inst);
        m_write_to_init_cmd_srcid_fifo.simple_put(write_to_init_cmd_fifo_srcid);
#if L1_MULTI_CACHE
        m_write_to_init_cmd_cache_id_fifo.simple_put(write_to_init_cmd_fifo_cache_id);
#endif
      }
    } else {
      if ( write_to_init_cmd_fifo_get ) {
        m_write_to_init_cmd_inst_fifo.simple_get();
        m_write_to_init_cmd_srcid_fifo.simple_get();
#if L1_MULTI_CACHE
        m_write_to_init_cmd_cache_id_fifo.simple_get();
#endif
      }
    }
    ////////////////////////////////////////////////////////////////////////////////////
    //    XRAM_RSP to INIT_CMD FIFO
    ////////////////////////////////////////////////////////////////////////////////////

    if ( xram_rsp_to_init_cmd_fifo_put ) {
      if ( xram_rsp_to_init_cmd_fifo_get ) {
        m_xram_rsp_to_init_cmd_inst_fifo.put_and_get(xram_rsp_to_init_cmd_fifo_inst);
        m_xram_rsp_to_init_cmd_srcid_fifo.put_and_get(xram_rsp_to_init_cmd_fifo_srcid);
#if L1_MULTI_CACHE
        m_xram_rsp_to_init_cmd_cache_id_fifo.put_and_get(xram_rsp_to_init_cmd_fifo_cache_id);
#endif
      } else {
        m_xram_rsp_to_init_cmd_inst_fifo.simple_put(xram_rsp_to_init_cmd_fifo_inst);
        m_xram_rsp_to_init_cmd_srcid_fifo.simple_put(xram_rsp_to_init_cmd_fifo_srcid);
#if L1_MULTI_CACHE
        m_xram_rsp_to_init_cmd_cache_id_fifo.simple_put(xram_rsp_to_init_cmd_fifo_cache_id);
#endif
      }
    } else {
      if ( xram_rsp_to_init_cmd_fifo_get ) {
        m_xram_rsp_to_init_cmd_inst_fifo.simple_get();
        m_xram_rsp_to_init_cmd_srcid_fifo.simple_get();
#if L1_MULTI_CACHE
        m_xram_rsp_to_init_cmd_cache_id_fifo.simple_get();
#endif
      }
    }
    ////////////////////////////////////////////////////////////////////////////////////
    //    CAS to INIT_CMD FIFO
    ////////////////////////////////////////////////////////////////////////////////////

    if ( cas_to_init_cmd_fifo_put ) {
      if ( cas_to_init_cmd_fifo_get ) {
        m_cas_to_init_cmd_inst_fifo.put_and_get(cas_to_init_cmd_fifo_inst);
        m_cas_to_init_cmd_srcid_fifo.put_and_get(cas_to_init_cmd_fifo_srcid);
#if L1_MULTI_CACHE
        m_cas_to_init_cmd_cache_id_fifo.put_and_get(cas_to_init_cmd_fifo_cache_id);
#endif
      } else {
          m_cas_to_init_cmd_inst_fifo.simple_put(cas_to_init_cmd_fifo_inst);
          m_cas_to_init_cmd_srcid_fifo.simple_put(cas_to_init_cmd_fifo_srcid);
#if L1_MULTI_CACHE
          m_cas_to_init_cmd_cache_id_fifo.simple_put(cas_to_init_cmd_fifo_cache_id);
#endif
      }
    } else {
        if ( cas_to_init_cmd_fifo_get ) {
            m_cas_to_init_cmd_inst_fifo.simple_get();
            m_cas_to_init_cmd_srcid_fifo.simple_get();
#if L1_MULTI_CACHE
            m_cas_to_init_cmd_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:
        /*if( ((r_write_to_tgt_rsp_pktid.read() & 0x7) == TYPE_SC) )
            {
              std::cout << "SC RSP / rsrcid = " << r_write_to_tgt_rsp_srcid.read() << " / rdata = " << r_write_to_tgt_rsp_sc_fail.read() << std::endl;
            }*/
        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   = 0x2 & ( (1 << vci_param::E) - 1);
        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_init_rsp_to_tgt_rsp_srcid.read();
        p_vci_tgt.rtrdid   = r_init_rsp_to_tgt_rsp_trdid.read();
        p_vci_tgt.rpktid   = r_init_rsp_to_tgt_rsp_pktid.read();
        p_vci_tgt.rerror   = 0;
        p_vci_tgt.reop     = true;
        break;
    } // end switch r_tgt_rsp_fsm

    ///////////////////////////////////////////////////
    // Command signals on the p_vci_ini port
    ///////////////////////////////////////////////////

    p_vci_ini.cmd     = vci_param::CMD_WRITE;
    p_vci_ini.srcid   = m_srcid_ini;
    p_vci_ini.cons    = true;
    p_vci_ini.wrap    = false;
    p_vci_ini.contig  = false;
    p_vci_ini.clen    = 0;
    p_vci_ini.cfixed  = false;

    vci_addr_t vci_ini_address = 0;
    switch ( r_init_cmd_fsm.read() ) {

      case INIT_CMD_UPDT_IDLE:
      case INIT_CMD_INVAL_IDLE:
      case INIT_CMD_CAS_UPDT_IDLE:
        p_vci_ini.cmdval  = false;
        p_vci_ini.address = 0;
        p_vci_ini.wdata   = 0;
        p_vci_ini.be      = 0;
        p_vci_ini.plen    = 0;
        p_vci_ini.trdid   = 0;
        p_vci_ini.pktid   = 0;
        p_vci_ini.eop     = false;
        break;
      case INIT_CMD_INVAL_NLINE:
      {
        vci_ini_address = (vci_addr_t)
            m_xram_rsp_to_init_cmd_srcid_fifo.read() << (vci_param::N - vci_param::S);

        p_vci_ini.cmdval  = m_xram_rsp_to_init_cmd_inst_fifo.rok();
        if(m_xram_rsp_to_init_cmd_inst_fifo.rok()){
          if(m_xram_rsp_to_init_cmd_inst_fifo.read()) {
              p_vci_ini.address = (addr_t) (vci_ini_address+4);
          } else {
              p_vci_ini.address = (addr_t) (vci_ini_address);
          }
        } else p_vci_ini.address = 0; // prevent segmentation faults by reading an empty fifo
        p_vci_ini.wdata   = (uint32_t)r_xram_rsp_to_init_cmd_nline.read();
        p_vci_ini.be      = ((r_xram_rsp_to_init_cmd_nline.read() >> 32) & 0x3);
        p_vci_ini.plen    = 4;
        p_vci_ini.trdid   = r_xram_rsp_to_init_cmd_trdid.read();
#if L1_MULTI_CACHE
        p_vci_ini.pktid   = m_xram_rsp_to_init_cmd_cache_id_fifo.read();
#endif
        p_vci_ini.eop     = true;
        break;
      }
      case INIT_CMD_XRAM_BRDCAST:
        p_vci_ini.cmdval  = true;
        p_vci_ini.address = m_broadcast_address;
        p_vci_ini.wdata   = (uint32_t)r_xram_rsp_to_init_cmd_nline.read();
        p_vci_ini.be      = ((r_xram_rsp_to_init_cmd_nline.read() >> 32) & 0x3);
        p_vci_ini.plen    = 4;
        p_vci_ini.trdid   = r_xram_rsp_to_init_cmd_trdid.read();
        p_vci_ini.pktid   = 0;
        p_vci_ini.eop     = true;
        break;

      case INIT_CMD_WRITE_BRDCAST:
        p_vci_ini.cmdval  = true;
        p_vci_ini.address = m_broadcast_address;
        p_vci_ini.wdata   = (addr_t)r_write_to_init_cmd_nline.read();
        p_vci_ini.be      = ((r_write_to_init_cmd_nline.read() >> 32) & 0x3);
        p_vci_ini.plen    = 4 ;
        p_vci_ini.eop     = true;
        p_vci_ini.trdid   = r_write_to_init_cmd_trdid.read();
        p_vci_ini.pktid   = 0;
        break;
      case INIT_CMD_UPDT_NLINE:
        vci_ini_address = (vci_addr_t)
            m_write_to_init_cmd_srcid_fifo.read() << (vci_param::N - vci_param::S);

        p_vci_ini.cmdval  = m_write_to_init_cmd_inst_fifo.rok();
        if(m_write_to_init_cmd_inst_fifo.rok()){
          if(m_write_to_init_cmd_inst_fifo.read()) {
            p_vci_ini.address = (addr_t)(vci_ini_address + 12);
          } else {
            p_vci_ini.address = (addr_t)(vci_ini_address + 8);
          }
        } else {
          p_vci_ini.address = 0;
        }
        p_vci_ini.wdata   = (uint32_t)r_write_to_init_cmd_nline.read();
        p_vci_ini.be      = ((r_write_to_init_cmd_nline.read() >> 32 ) & 0x3);
        p_vci_ini.plen    = 4 * (r_write_to_init_cmd_count.read() + 2);
        p_vci_ini.eop     = false;
        p_vci_ini.trdid   = r_write_to_init_cmd_trdid.read();
#if L1_MULTI_CACHE
        p_vci_ini.pktid   = m_write_to_init_cmd_cache_id_fifo.read();
#endif
        break;
      case INIT_CMD_UPDT_INDEX:
        vci_ini_address = (vci_addr_t)
            m_write_to_init_cmd_srcid_fifo.read() << (vci_param::N - vci_param::S);

        p_vci_ini.cmdval  = true;
        if(m_write_to_init_cmd_inst_fifo.read()) {
          p_vci_ini.address = (addr_t)(vci_ini_address + 12);
        } else {
          p_vci_ini.address = (addr_t)(vci_ini_address + 8);
        }
        p_vci_ini.wdata   = r_write_to_init_cmd_index.read();
        p_vci_ini.be      = 0xF;
        p_vci_ini.plen    = 4 * (r_write_to_init_cmd_count.read() + 2);
        p_vci_ini.trdid   = r_write_to_init_cmd_trdid.read();
#if L1_MULTI_CACHE
        p_vci_ini.pktid   = m_write_to_init_cmd_cache_id_fifo.read();
#endif
        p_vci_ini.eop     = false;
        break;
      case INIT_CMD_UPDT_DATA:
        vci_ini_address = (vci_addr_t)
            m_write_to_init_cmd_srcid_fifo.read() << (vci_param::N - vci_param::S);

        p_vci_ini.cmdval  = true;
        if(m_write_to_init_cmd_inst_fifo.read()) {
          p_vci_ini.address = (addr_t)(vci_ini_address + 12);
        } else {
          p_vci_ini.address = (addr_t)(vci_ini_address + 8);
        }
        p_vci_ini.wdata   = r_write_to_init_cmd_data[r_init_cmd_cpt.read() +
          r_write_to_init_cmd_index.read()].read();
        p_vci_ini.be      = r_write_to_init_cmd_be[r_init_cmd_cpt.read() +
            r_write_to_init_cmd_index.read()].read()  ;
        p_vci_ini.plen    = 4 * (r_write_to_init_cmd_count.read() + 2);
        p_vci_ini.trdid   = r_write_to_init_cmd_trdid.read();
#if L1_MULTI_CACHE
        p_vci_ini.pktid   = m_write_to_init_cmd_cache_id_fifo.read();
#endif
        p_vci_ini.eop     = ( r_init_cmd_cpt.read() == (r_write_to_init_cmd_count.read()-1) );
        break;

      case INIT_CMD_CAS_BRDCAST:
        p_vci_ini.cmdval  = true;
        p_vci_ini.address = m_broadcast_address;
        p_vci_ini.wdata   = (addr_t)r_cas_to_init_cmd_nline.read();
        p_vci_ini.be      = ((r_cas_to_init_cmd_nline.read() >> 32) & 0x3);
        p_vci_ini.plen    = 4 ;
        p_vci_ini.eop     = true;
        p_vci_ini.trdid   = r_cas_to_init_cmd_trdid.read();
        p_vci_ini.pktid   = 0;
        break;
      case INIT_CMD_CAS_UPDT_NLINE:
        vci_ini_address = (vci_addr_t)
            m_cas_to_init_cmd_srcid_fifo.read() << (vci_param::N - vci_param::S);

        p_vci_ini.cmdval  = m_cas_to_init_cmd_inst_fifo.rok();
        if(m_cas_to_init_cmd_inst_fifo.rok()){
          if( m_cas_to_init_cmd_inst_fifo.read() ) {
            p_vci_ini.address = (addr_t)(vci_ini_address + 12);
          } else {
            p_vci_ini.address = (addr_t)(vci_ini_address + 8);
          }
        } else {
          p_vci_ini.address = 0;
        }
        p_vci_ini.wdata   = (uint32_t)r_cas_to_init_cmd_nline.read();
        p_vci_ini.be      = ((r_cas_to_init_cmd_nline.read() >> 32 ) & 0x3);
        if(r_cas_to_init_cmd_is_long.read()){
            p_vci_ini.plen    = 4 * 4;
        } else {
            p_vci_ini.plen    = 4 * 3;
        }
        p_vci_ini.eop     = false;
        p_vci_ini.trdid   = r_cas_to_init_cmd_trdid.read();
#if L1_MULTI_CACHE
        p_vci_ini.pktid   = m_cas_to_init_cmd_cache_id_fifo.read();
#endif
        break;
      case INIT_CMD_CAS_UPDT_INDEX:
        vci_ini_address = (vci_addr_t)
            m_cas_to_init_cmd_srcid_fifo.read() << (vci_param::N - vci_param::S);

        p_vci_ini.cmdval  = true;
        if( m_cas_to_init_cmd_inst_fifo.read() ) {
          p_vci_ini.address = (addr_t)(vci_ini_address + 12);
        } else {
          p_vci_ini.address = (addr_t)(vci_ini_address + 8);
        }
        p_vci_ini.wdata   = r_cas_to_init_cmd_index.read();
        p_vci_ini.be      = 0xF;
        if(r_cas_to_init_cmd_is_long.read()){
            p_vci_ini.plen    = 4 * 4;
        } else {
            p_vci_ini.plen    = 4 * 3;
        }
        p_vci_ini.trdid   = r_cas_to_init_cmd_trdid.read();
#if L1_MULTI_CACHE
        p_vci_ini.pktid   = m_cas_to_init_cmd_cache_id_fifo.read();
#endif
        p_vci_ini.eop     = false;
        break;
      case INIT_CMD_CAS_UPDT_DATA:
        vci_ini_address = (vci_addr_t)
            m_cas_to_init_cmd_srcid_fifo.read() << (vci_param::N - vci_param::S);

        p_vci_ini.cmdval  = true;
        if( m_cas_to_init_cmd_inst_fifo.read() ) {
          p_vci_ini.address = (addr_t)(vci_ini_address + 12);
        } else {
          p_vci_ini.address = (addr_t)(vci_ini_address + 8);
        }
        p_vci_ini.wdata   = r_cas_to_init_cmd_wdata.read();
        p_vci_ini.be      = 0xF;
        p_vci_ini.trdid   = r_cas_to_init_cmd_trdid.read();
#if L1_MULTI_CACHE
        p_vci_ini.pktid   = m_cas_to_init_cmd_cache_id_fifo.read();
#endif
        if(r_cas_to_init_cmd_is_long.read()){
            p_vci_ini.plen    = 4 * 4;
            p_vci_ini.eop     = false;
        } else {
            p_vci_ini.plen    = 4 * 3;
            p_vci_ini.eop     = true;
        }
        break;
      case INIT_CMD_CAS_UPDT_DATA_HIGH:
        vci_ini_address = (vci_addr_t)
            m_cas_to_init_cmd_srcid_fifo.read() << (vci_param::N - vci_param::S);

        p_vci_ini.cmdval  = true;
        if( m_cas_to_init_cmd_inst_fifo.read() ) {
          p_vci_ini.address = (addr_t)(vci_ini_address + 12);
        } else {
          p_vci_ini.address = (addr_t)(vci_ini_address + 8);
        }
        p_vci_ini.wdata   = r_cas_to_init_cmd_wdata_high.read();
        p_vci_ini.be      = 0xF;
        p_vci_ini.plen    = 4 * 4;
        p_vci_ini.trdid   = r_cas_to_init_cmd_trdid.read();
#if L1_MULTI_CACHE
        p_vci_ini.pktid   = m_cas_to_init_cmd_cache_id_fifo.read();
#endif
        p_vci_ini.eop     = true;
        break;

    } // end switch r_init_cmd_fsm

    //////////////////////////////////////////////////////
    // Response signals on the p_vci_ini port
    //////////////////////////////////////////////////////

    if ( r_init_rsp_fsm.read() == INIT_RSP_IDLE ) p_vci_ini.rspack  = true;
    else                                          p_vci_ini.rspack  = false;

    //////////////////////////////////////////////////////
    // Response signals on the p_vci_tgt_cleanup port
    //////////////////////////////////////////////////////
    p_vci_tgt_cleanup.rspval = false;
    p_vci_tgt_cleanup.rsrcid = 0;
    p_vci_tgt_cleanup.rdata  = 0;
    p_vci_tgt_cleanup.rpktid = 0;
    p_vci_tgt_cleanup.rtrdid = 0;
    p_vci_tgt_cleanup.rerror = 0;
    p_vci_tgt_cleanup.reop   = false;
    p_vci_tgt_cleanup.cmdack = false ;

    switch(r_cleanup_fsm.read()){
      case CLEANUP_IDLE:
        {
          p_vci_tgt_cleanup.cmdack = true ;
          break;
        }
      case CLEANUP_RSP:
        {
          p_vci_tgt_cleanup.rspval = true;
          p_vci_tgt_cleanup.rdata  = 0;
          p_vci_tgt_cleanup.rsrcid = r_cleanup_srcid.read();
          p_vci_tgt_cleanup.rpktid = r_cleanup_pktid.read();
          p_vci_tgt_cleanup.rtrdid = r_cleanup_trdid.read();
          p_vci_tgt_cleanup.rerror = 0x2 & ( (1 << vci_param::E) - 1);
          p_vci_tgt_cleanup.reop   = 1;
          break;
        }

    }

} // 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
