/* -*- c++ -*-
 * File         : vci_cc_xcache_wrapper_v4.cpp
 * Date         : 26/11/2011
 * Copyright    : UPMC / LIP6
 * Authors      : Alain Greiner 
 *
 * SOCLIB_LGPL_HEADER_BEGIN
 * 
 * This file is part of SoCLib, GNU LGPLv2.1.
 * 
 * SoCLib is free software; you can redistribute it and/or modify it
 * under the terms of the GNU Lesser General Public License as published
 * by the Free Software Foundation; version 2.1 of the License.
 * 
 * SoCLib is distributed in the hope that it will be useful, but
 * WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 * 
 * You should have received a copy of the GNU Lesser General Public
 * License along with SoCLib; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
 * 02110-1301 USA
 * 
 * SOCLIB_LGPL_HEADER_END
 *
 * Copyright (c) UPMC, Lip6
 *         Alain Greiner <alain.greiner@lip6.fr>, 2011
 *
 * Maintainers: alain 
 */

#include "../include/vci_cc_xcache_wrapper_v4.h"

#define DEBUG_GLOBAL		0
#define DEBUG_DCACHE		0
#define DEBUG_ICACHE		0

#define DEBUG_START_CYCLE	0
#define DEBUG_ID		    0

namespace soclib { namespace caba {

    namespace {
      const char *dcache_fsm_state_str[] = 
      {
        "DCACHE_IDLE",
        "DCACHE_WRITE_UPDT",
        "DCACHE_MISS_VICTIM",
        "DCACHE_MISS_WAIT",
        "DCACHE_MISS_UPDT",
        "DCACHE_UNC_WAIT",
        "DCACHE_INVAL",
        "DCACHE_INVAL_GO",
        "DCACHE_SYNC",
        "DCACHE_ERROR",
        "DCACHE_CC_CHECK",
        "DCACHE_CC_INVAL",
        "DCACHE_CC_UPDT",
      };
      const char *icache_fsm_state_str[] = 
      {
        "ICACHE_IDLE",
        "ICACHE_MISS_VICTIM",
        "ICACHE_MISS_WAIT",
        "ICACHE_MISS_UPDT",
        "ICACHE_UNC_WAIT",
        "ICACHE_ERROR",
        "ICACHE_CC_CHECK",
        "ICACHE_CC_INVAL",
        "ICACHE_CC_UPDT",
      };
      const char *cmd_fsm_state_str[] = 
      {
        "CMD_IDLE",
        "CMD_INS_MISS",
        "CMD_INS_UNC",
        "CMD_DATA_MISS",
        "CMD_DATA_UNC",
        "CMD_DATA_WRITE",
        "CMD_DATA_SC",
      };
      const char *rsp_fsm_state_str[] = 
      {
        "RSP_IDLE",
        "RSP_INS_MISS",
        "RSP_INS_UNC",
        "RSP_DATA_MISS",
        "RSP_DATA_UNC",
        "RSP_DATA_WRITE",
        "RSP_DATA_SC",
      };
      const char *tgt_fsm_state_str[] = 
      {
        "TGT_IDLE",
        "TGT_UPDT_WORD",
        "TGT_UPDT_DATA",
        "TGT_REQ_BROADCAST",
        "TGT_REQ_ICACHE",
        "TGT_REQ_DCACHE",
        "TGT_RSP_BROADCAST",
        "TGT_RSP_ICACHE",
        "TGT_RSP_DCACHE",
      };

      const char *cleanup_fsm_state_str[] = 
      {
        "CLEANUP_DATA_IDLE",
        "CLEANUP_DATA_GO",
        "CLEANUP_INS_IDLE",
        "CLEANUP_INS_GO",
      };
    }

#define tmpl(...) template<typename vci_param, typename iss_t> __VA_ARGS__ VciCcXCacheWrapperV4<vci_param, iss_t>

using soclib::common::uint32_log2;

/////////////////////////////////
tmpl(/**/)::VciCcXCacheWrapperV4(
    sc_module_name                      name,
    int                                 proc_id,
    const soclib::common::MappingTable  &mtp,
    const soclib::common::MappingTable  &mtc,
    const soclib::common::IntTab        &initiator_index_d,
    const soclib::common::IntTab        &initiator_index_c,
    const soclib::common::IntTab        &target_index_c,
    size_t                              icache_ways,
    size_t                              icache_sets,
    size_t                              icache_words,
    size_t                              dcache_ways,
    size_t                              dcache_sets,
    size_t                              dcache_words,
    size_t                              wbuf_nwords,
    size_t                              wbuf_nlines,
    uint32_t				            max_frozen_cycles)
     : 
     soclib::caba::BaseModule(name),

     p_clk       ("clk"),
     p_resetn    ("resetn"),
     p_vci_ini_d ("vci_ini_d"),
     p_vci_ini_c ("vci_ini_c"),
     p_vci_tgt_c ("vci_tgt_c"),

     m_cacheability_table(mtp.getCacheabilityTable<vci_addr_t>()),
     m_segment(mtc.getSegment(target_index_c)),
     m_srcid_d(mtp.indexForId(initiator_index_d)),
     m_srcid_c(mtc.indexForId(initiator_index_c)),

     m_dcache_ways(dcache_ways),
     m_icache_ways(icache_ways),

     m_cache_words(icache_words),
     m_cache_words_shift(uint32_log2(icache_words)+uint32_log2(sizeof(data_t))),
     m_cache_yzmask((~0)<<m_cache_words_shift),

     m_max_frozen_cycles(max_frozen_cycles),

     r_icache_fsm("r_icache_fsm"),
     r_icache_fsm_save("r_icache_fsm_save"),
     r_icache_addr_save("r_icache_addr_save"),
     r_icache_miss_req("r_icache_miss_req"),
     r_icache_unc_req("r_icache_unc_req"),
     r_icache_cleanup_req("r_icache_cleanup_req"),
     r_icache_cleanup_line("r_icache_cleanup_line"),
     r_icache_cleanup_way("r_icache_cleanup_way"),
     r_icache_cleanup_set("r_icache_cleanup_set"),
     r_icache_miss_inval("r_icache_miss_inval"),
     r_icache_update_word("r_icache_update_word"),

     r_dcache_fsm("r_dcache_fsm"),
     r_dcache_fsm_save("r_dcache_fsm_save"),
     r_dcache_addr_save("r_dcache_addr_save"),
     r_dcache_wdata_save("r_dcache_wdata_save"),
     r_dcache_be_save("r_dcache_be_save"),
     r_dcache_way_save("r_dcache_way_save"),
     r_dcache_set_save("r_dcache_set_save"),
     r_dcache_word_save("r_dcache_word_save"),
     r_dcache_cleanup_req("r_dcache_cleanup_req"),
     r_dcache_cleanup_line("r_dcache_cleanup_line"),
     r_dcache_cleanup_way("r_dcache_cleanup_way"),
     r_dcache_cleanup_set("r_dcache_cleanup_set"),
     r_dcache_miss_req("r_dcache_miss_req"),
     r_dcache_unc_req("r_dcache_unc_req"),
     r_dcache_sc_req("r_dcache_sc_req"),
     r_dcache_miss_inval("r_dcache_miss_inval"),
     r_dcache_update_word("r_dcache_update_word"),
     r_dcache_ll_data("r_dcache_ll_data"),
     r_dcache_ll_addr("r_dcache_ll_addr"),
     r_dcache_ll_valid("r_dcache_ll_valid"),

     r_vci_cmd_fsm("r_vci_cmd_fsm"),
     r_vci_cmd_min("r_vci_cmd_min"),
     r_vci_cmd_max("r_vci_cmd_max"),
     r_vci_cmd_cpt("r_vci_cmd_cpt"),
     r_vci_cmd_imiss_prio("r_vci_cmd_imiss_prio"),

     r_vci_rsp_fsm("r_vci_rsp_fsm"),
     r_vci_rsp_cpt("r_vci_rsp_cpt"),
     r_vci_rsp_ins_error("r_vci_rsp_ins_error"),
     r_vci_rsp_data_error("r_vci_rsp_data_error"),
     r_vci_rsp_fifo_icache("r_vci_rsp_fifo_icache" ,2),     // two words depth
     r_vci_rsp_fifo_dcache("r_vci_rsp_fifo_dcache" ,2),     // two words depth

     r_tgt_fsm("r_tgt_fsm"),
     r_tgt_icache_rsp("r_tgt_icache_rsp"),
     r_tgt_dcache_rsp("r_tgt_dcache_rsp"),
     r_tgt_addr("r_tgt_daddr"),
     r_tgt_word_min("r_tgt_word_min"),
     r_tgt_word_max("r_tgt_word_max"),
     r_tgt_word_count("r_tgt_word_count"),
     r_tgt_update("r_tgt_update"),
     r_tgt_update_data("r_tgt_update_data"),
     r_tgt_srcid("r_tgt_srcid"),
     r_tgt_pktid("r_tgt_pktid"),
     r_tgt_trdid("r_tgt_trdid"),
     r_tgt_icache_req("r_tgt_icache_req"),
     r_tgt_dcache_req("r_tgt_dcache_req"),

     r_cleanup_fsm("r_cleanup_fsm"),
     r_cleanup_trdid("r_cleanup_trdid"),
     r_cleanup_buffer(16)                   // up to 16 simultaneous cleanup transactions
{
    assert( ((icache_words*vci_param::B) < (1<<vci_param::K)) and
             "Need more PLEN bits.");

    assert( (vci_param::T > 2) and ((1<<(vci_param::T-1)) >= (wbuf_nlines)) and
             "Need more TRDID bits.");

    assert( (icache_words == dcache_words) and
             "icache_words must be equal at dcache_words.");

    p_irq  = new sc_in<bool> [iss_t::n_irq];

    r_iss     = new iss_t (this->name() , proc_id);
    r_icache  = new GenericCache<vci_addr_t>("icache", icache_ways, icache_sets, icache_words);
    r_dcache  = new GenericCache<vci_addr_t>("dcache", dcache_ways, dcache_sets, dcache_words);
    r_wbuf    = new MultiWriteBuffer<vci_addr_t>("wbuf", wbuf_nwords, wbuf_nlines, dcache_words);
                
    r_tgt_buf = new sc_signal<data_t> [m_cache_words];
    r_tgt_be  = new sc_signal<be_t>   [m_cache_words];

    m_cpt_fsm_dcache  = new uint32_t [32];
    m_cpt_fsm_icache  = new uint32_t [32];
    m_cpt_fsm_cmd     = new uint32_t [32];
    m_cpt_fsm_rsp     = new uint32_t [32];
    m_cpt_fsm_tgt     = new uint32_t [32];
    m_cpt_fsm_cleanup = new uint32_t [32];

    SC_METHOD(transition);
    dont_initialize();
    sensitive << p_clk.pos();

    SC_METHOD(genMoore);
    dont_initialize();
    sensitive << p_clk.neg();

    typename iss_t::CacheInfo cache_info;
    cache_info.has_mmu          = false;
    cache_info.icache_line_size = icache_words*sizeof(data_t);
    cache_info.icache_assoc     = icache_ways;
    cache_info.icache_n_lines   = icache_sets;
    cache_info.dcache_line_size = dcache_words*sizeof(data_t);
    cache_info.dcache_assoc     = dcache_ways;
    cache_info.dcache_n_lines   = dcache_sets;

    r_iss->setCacheInfo(cache_info);
    
} // end constructor

///////////////////////////////////
tmpl(/**/)::~VciCcXCacheWrapperV4()
{
    delete r_icache ;
    delete r_wbuf   ;
    delete r_dcache ;
    delete r_iss;
    delete [] p_irq;
    delete [] r_tgt_buf;
    delete [] r_tgt_be;
}

////////////////////////
tmpl(void)::print_cpi()
{
    std::cout << "CPU " << m_srcid_d << " : CPI = " 
              << (float)m_cpt_total_cycles/(m_cpt_total_cycles - m_cpt_frz_cycles) 
              << std::endl ;
}

/*

////////////////////////////////////////////////////////
tmpl(void)::print_stats(bool print_wbuf, bool print_fsm)
{
    std::cout << "------------------------------------" << std:: dec << std::endl;
    std::cout << "CPU " << m_srcid_d << " / Time = " << m_cpt_total_cycles << std::endl;

    float run_cycles = (float)(m_cpt_total_cycles - m_cpt_frz_cycles);

    std::cout << "- CPI                            : " 
              << (float)m_cpt_total_cycles/run_cycles << std::endl ;

    std::cout << "- CACHABLE INSTRUCTIONS          : " 
              << m_cpt_ins_cacheable << std::endl ;

    std::cout << "- INSTRUCTION CACHE MISS RATE    : "
              << (float)m_cpt_ins_miss*100.0/(float)m_cpt_ins_cacheable 
              << " %" << std::endl ;

    std::cout << "- NON CACHABLE INSTRUCTIONS      : " 
              << m_cpt_ins_uncacheable << std::endl ;

    std::cout << "- CACHABLE DATA READ             : " 
              << m_cpt_data_read_cacheable << std::endl;

    std::cout << "- DATA CACHE MISS RATE           : "
              << (float)m_cpt_data_read_miss*100.0/(float)m_cpt_data_read_cacheable 
              << " %" << std::endl;

    std::cout << "- CACHABLE DATA WRITE            : " 
              << m_cpt_data_write_cacheable << std::endl ;

    std::cout << "- CACHED WRITE RATE              : "
              << (float)m_cpt_data_write_hit*100.0/(float)m_cpt_data_write_cacheable 
              << " %" << std::endl;

    std::cout << "- NON CACHABLE DATA READ         : " 
              << m_cpt_data_read_uncacheable << std::endl;

    std::cout << "- NON CACHABLE DATA WRITE        : " 
              << m_cpt_data_write_uncacheable << std::endl;

    std::cout << "- WRITE RATE                     : " 
              << (float)m_cpt_data_write_cacheable*100.0/(float)m_cpt_ins_cacheable
              << " %" << std::endl;

    std::cout << "- READ RATE                      : " 
              << (float)m_cpt_data_read_cacheable*100.0/(float)m_cpt_ins_cacheable
              << " %" << std::endl;

    std::cout << "- AVERAGE INSTRUCTION MISS COST  : " 
              << (float)m_cost_ins_miss_frz/(float)m_cpt_ins_miss << std::endl;

    std::cout << "- AVERAGE DATA MISS COST         : " 
              << (float)m_cost_data_miss_frz/m_cpt_data_read_miss << std::endl;

    std::cout << "- AVERAGE WRITE COST             : " 
              << (float)m_cost_write_frz/m_cpt_data_write_cacheable << std::endl;

    std::cout << "- CC_UPDATE_ICACHE               : " 
              << m_cpt_cc_update_icache  << std::endl;

    std::cout << "- CC_UPDATE_DCACHE               : " 
              << m_cpt_cc_update_dcache  << std::endl;

    std::cout << "- CC_INVAL_ICACHE                : " 
              << m_cpt_cc_inval_icache << std::endl;

    std::cout << "- CC_INVAL_ICACHE                : " 
              << m_cpt_cc_inval_icache << std::endl;

    std::cout << "-CC_BROADCAST                    : " 
              << m_cpt_cc_inval_broadcast << std::endl;

//  this part is removed because soclib::common::size() not found ...

    if (print_fsm)
    {
        std::cout << "- DCACHE FSM" << std::endl;
        for (uint32_t i=0; i<soclib::common::size(dcache_fsm_state_str ); ++i)
            std::cout << "  + "  << dcache_fsm_state_str[i] << " : "
                      << m_cpt_fsm_dcache [i] << std::endl; 

        std::cout << "- ICACHE FSM" << std::endl;
        for (uint32_t i=0; i<soclib::common::size(icache_fsm_state_str ); ++i)
            std::cout << "  + "  << icache_fsm_state_str[i] << " : "
                      << m_cpt_fsm_icache [i] << std::endl; 

        std::cout << "- CMD FSM" << std::endl;
        for (uint32_t i=0; i<soclib::common::size(cmd_fsm_state_str ); ++i)
            std::cout << "  + " << cmd_fsm_state_str[i] << " : " 
                      << m_cpt_fsm_cmd [i] << std::endl;

        std::cout << "- RSP FSM" << std::endl;
        for (uint32_t i=0; i<soclib::common::size(rsp_fsm_state_str ); ++i)
            std::cout << "  + " << rsp_fsm_state_str[i] << " : "
                      << m_cpt_fsm_rsp [i] << std::endl;

        std::cout << "- TGT FSM" << std::endl;
        for (uint32_t i=0; i<soclib::common::size(tgt_fsm_state_str ); ++i)
            std::cout << "  + "  << tgt_fsm_state_str[i] << " : " 
                      << m_cpt_fsm_tgt [i] << std::endl;

        std::cout << "- CLEANUP FSM" << std::endl;
        for (uint32_t i=0; i<soclib::common::size(cleanup_fsm_state_str ); ++i)
            std::cout << "  + "  << cleanup_fsm_state_str[i] << " : " 
                      << m_cpt_fsm_cleanup [i] << std::endl;
    }

    if (print_wbuf) r_wbuf->printStatistics();
}

*/
////////////////////////////////////
tmpl(void)::print_trace(size_t mode)
{
    // b0 : write buffer print trace
    // b1 : write buffer verbose
    // b2 : dcache print trace
    // b3 : icache print trace

    typename iss_t::InstructionRequest  ireq;
    typename iss_t::InstructionResponse irsp;
    typename iss_t::DataRequest         dreq;
    typename iss_t::DataResponse        drsp;

    ireq.valid       = m_ireq_valid;
    ireq.addr        = m_ireq_addr;
    ireq.mode        = m_ireq_mode;

    irsp.valid       = m_irsp_valid;
    irsp.instruction = m_irsp_instruction;
    irsp.error       = m_irsp_error;

    dreq.valid       = m_dreq_valid;
    dreq.addr        = m_dreq_addr;
    dreq.mode        = m_dreq_mode;
    dreq.type        = m_dreq_type;
    dreq.wdata       = m_dreq_wdata;
    dreq.be          = m_dreq_be;

    drsp.valid       = m_drsp_valid;
    drsp.rdata       = m_drsp_rdata;
    drsp.error       = m_drsp_error;

    std::cout << std::dec << "Proc " << name() << std::endl;

    std::cout << "  " << ireq << std::endl;
    std::cout << "  " << irsp << std::endl;
    std::cout << "  " << dreq << std::endl;
    std::cout << "  " << drsp << std::endl;
 
    std::cout << "  " << icache_fsm_state_str[r_icache_fsm.read()]
              << " | " << dcache_fsm_state_str[r_dcache_fsm.read()]
              << " | " << cmd_fsm_state_str[r_vci_cmd_fsm.read()]
              << " | " << rsp_fsm_state_str[r_vci_rsp_fsm.read()]
              << " | " << tgt_fsm_state_str[r_tgt_fsm.read()]
              << " | " << cleanup_fsm_state_str[r_cleanup_fsm.read()] << std::endl;

    if(mode & 0x1)
    {
        std::cout << "  Write Buffer" << std::endl;
        r_wbuf->printTrace((mode>>1)&1);
    }
    if(mode & 0x4)
    {
        std::cout << "  Data cache" << std::endl;
        r_dcache->printTrace();
    }
    if(mode & 0x8)
    {
        std::cout << "  Instruction cache" << std::endl;
        r_icache->printTrace();
    }
}

//////////////////////////
tmpl(void)::transition()
//////////////////////////
{
    // Reset
    if ( not p_resetn.read() ) 
    {
        // iss, write buffer & caches
        r_iss->reset();
        r_wbuf->reset();
        r_dcache->reset();
        r_icache->reset();
        r_cleanup_buffer.reset();

        // FSM states
        r_icache_fsm                = ICACHE_IDLE;
        r_dcache_fsm                = DCACHE_IDLE;
        r_vci_cmd_fsm               = CMD_IDLE;
        r_vci_rsp_fsm               = RSP_IDLE;
        r_tgt_fsm                   = TGT_IDLE;
        r_cleanup_fsm               = CLEANUP_DATA_IDLE;

        // synchronisation flip-flops between TGT FSM and ICACHE/DCACHE FSMs
        r_tgt_icache_req            = false;
        r_tgt_dcache_req            = false;

        // synchronisation flip-flops between ICACHE/DCACHE FSMs and CLEANUP FSM
        r_icache_cleanup_req        = false;
        r_dcache_cleanup_req        = false;

        // synchronisation flip-flops between ICACHE FSMs and VCI FSMs
        r_icache_miss_req           = false;
        r_icache_unc_req            = false;
        r_icache_miss_inval         = false;
        r_vci_rsp_ins_error         = false;

        // synchronisation flip-flops between DCACHE FSMs and VCI FSMs
        r_dcache_miss_req           = false;
        r_dcache_unc_req            = false;
        r_dcache_sc_req             = false;
        r_dcache_miss_inval         = false;
        r_vci_rsp_data_error        = false;

        // pending non cacheable write
        r_dcache_pending_unc_write  = false;

        // linked load reservation flip-flop
        r_dcache_ll_valid           = false;

        // uncacheable read buffers
        r_icache_unc_valid          = false;
        r_dcache_unc_valid          = false;

        // response FIFOs 
        r_vci_rsp_fifo_icache.init();
        r_vci_rsp_fifo_dcache.init();
      
        // activity counters (consommation)
        m_conso_dcache_data_read     = 0;
        m_conso_dcache_data_write    = 0;
        m_conso_dcache_dir_read      = 0;
        m_conso_dcache_dir_write     = 0;

        m_conso_icache_data_read     = 0;
        m_conso_icache_data_write    = 0;
        m_conso_icache_dir_read      = 0;
        m_conso_icache_dir_write     = 0;

        m_conso_wbuf_read            = 0;
        m_conso_wbuf_write           = 0;

        // coherence request counters
        m_cpt_cc_update_icache       = 0;
        m_cpt_cc_update_dcache       = 0;
        m_cpt_cc_inval_icache        = 0;
        m_cpt_cc_inval_dcache        = 0;
        m_cpt_cc_inval_broadcast     = 0;

        // CPI computation
        m_cpt_frz_cycles             = 0;
        m_cpt_total_cycles           = 0;
        m_cpt_stop_simulation        = 0;

        // number of executed instructions
        m_cpt_ins_cacheable          = 0;
        m_cpt_ins_uncacheable        = 0;
        m_cpt_ins_miss               = 0;

        // number of data requests
        m_cpt_data_read_cacheable    = 0;
        m_cpt_data_read_miss         = 0;
        m_cpt_data_read_uncacheable  = 0;
        m_cpt_data_write_cacheable   = 0;
        m_cpt_data_write_uncacheable = 0;
        m_cpt_data_write_hit         = 0;
        m_cpt_data_ll                = 0;
        m_cpt_data_sc                = 0;

        // number of external register requests
        m_cpt_xtn_dcache_inval       = 0;
        m_cpt_xtn_sync               = 0;

        // cumulated cost (frozen cycles) for write and miss
        m_cost_write_frz             = 0;
        m_cost_data_miss_frz         = 0;
        m_cost_ins_miss_frz          = 0;

        m_cpt_imiss_transaction      = 0;
        m_cpt_dmiss_transaction      = 0;
        m_cpt_iunc_transaction       = 0;
        m_cpt_dunc_transaction       = 0;
        m_cpt_write_transaction      = 0;
        m_cpt_sc_transaction         = 0;

        m_cost_imiss_transaction    = 0;
        m_cost_dmiss_transaction    = 0;
        m_cost_unc_transaction      = 0;
        m_cost_write_transaction    = 0;
        m_length_write_transaction  = 0;

        for (uint32_t i=0; i<32 ; ++i) 
            m_cpt_fsm_icache  [i]   = 0;
        for (uint32_t i=0; i<32 ; ++i) 
            m_cpt_fsm_dcache  [i]   = 0;
        for (uint32_t i=0; i<32 ; ++i) 
            m_cpt_fsm_cmd     [i]   = 0;
        for (uint32_t i=0; i<32 ; ++i) 
            m_cpt_fsm_rsp     [i]   = 0;
        for (uint32_t i=0; i<32 ; ++i) 
            m_cpt_fsm_tgt     [i]   = 0;
        for (uint32_t i=0; i<32 ; ++i) 
            m_cpt_fsm_cleanup [i]   = 0;

        return; 
    }

    // Response FIFOs default values
    bool     vci_rsp_fifo_icache_get       = false;
    bool     vci_rsp_fifo_icache_put       = false;
    data_t   vci_rsp_fifo_icache_data      = 0;

    bool     vci_rsp_fifo_dcache_get       = false;
    bool     vci_rsp_fifo_dcache_put       = false;
    data_t   vci_rsp_fifo_dcache_data      = 0;

    // FSMs activity
    m_cpt_fsm_dcache  [r_dcache_fsm.read() ] ++;
    m_cpt_fsm_icache  [r_icache_fsm.read() ] ++;
    m_cpt_fsm_cmd     [r_vci_cmd_fsm.read()] ++;
    m_cpt_fsm_rsp     [r_vci_rsp_fsm.read()] ++;
    m_cpt_fsm_tgt     [r_tgt_fsm.read()    ] ++;
    m_cpt_fsm_cleanup [r_cleanup_fsm.read()] ++;

    m_cpt_total_cycles++;

    //////////////////////////////////////////////////////////////////////////////
    // The TGT_FSM receives the coherence requests.
    // It controls the following ressources:
    // - r_tgt_fsm
    // - r_tgt_buf[nwords]
    // - r_tgt_be[nwords]
    // - r_tgt_update
    // - r_tgt_word_min
    // - r_tgt_word_max
    // - r_tgt_word_count
    // - r_tgt_addr
    // - r_tgt_srcid
    // - r_tgt_trdid
    // - r_tgt_pktid
    // - r_tgt_icache_req (set)
    // - r_tgt_dcache_req (set)
    //
    // All VCI commands must be CMD_WRITE.
    // - If the 2 LSB bits of the VCI address are 11, it is a broadcast request.
    //   It is a multicast request otherwise.
    // - For multicast requests, the ADDRESS[2] bit distinguishes DATA/INS
    //   (0 for data / 1 for instruction), and the ADDRESS[3] bit distinguishes
    //   INVAL/UPDATE (0 for invalidate / 1 for UPDATE).
    //
    // For all types of coherence resqests, the line index (i.e. the Z & Y fields) 
    // is coded on 34 bits, and is contained in the WDATA and BE fields 
    // of the first VCI flit.
    // -  for a multicast invalidate or for a broadcast invalidate request
    //    the VCI packet length is 1 word. 
    // -  for an update request the VCI packet length is (n+2) words.
    //    The WDATA field of the second VCI word contains the word index.
    //    The WDATA field of the n following words contains the values.
    // -  for all transaction types, the VCI response is one single word.
    // In case of errors in the VCI command packet, the simulation
    // is stopped with an error message.
    //
    // This FSM is NOT pipelined : It consumes a new request on the VCI port
    // only when the previous request is completed.
    //
    // The VCI_TGT FSM stores the external request arguments in the
    // IDLE, UPDT_WORD & UPDT_DATA states. It sets the r_tgt_icache_req 
    // and/or the r_tgt_dcache_req flip-flops to signal the coherence request 
    // to the ICACHE & DCACHE FSMs in the REQ_ICACHE, REQ_DCACHE & REQ_BROADCAST
    // states. It waits the completion of the coherence request  by polling the
    // r_tgt_*cache_req flip-flops in the RSP_ICACHE, RSP_DCACHE & RSP_BROADCAST
    // states. These flip-flops are reset by the ICACHE_FSM and/or DCACHE_FSM. 
    // These two FSMs signal if a VCI answer must be send by setting
    // the r_tgt_icache_rsp and/or the r_tgt_dcache_rsp flip_flops.
    ///////////////////////////////////////////////////////////////////////////////

    switch( r_tgt_fsm.read() ) 
    {
        //////////////
        case TGT_IDLE:
        {
            vci_addr_t tgt_addr; 
            
            if ( p_vci_tgt_c.cmdval.read() ) 
            {
                vci_addr_t address = p_vci_tgt_c.address.read();

                if ( p_vci_tgt_c.cmd.read() != vci_param::CMD_WRITE) 
                {
                    std::cout << "error in component VCI_CC_XCACHE_WRAPPER " 
                              << name() << std::endl;
                    std::cout << "coherence request is not a write" 
                              << std::endl;
                    exit(0);
                }

                // address checking for multi-update or multi-invalidate 
                if ( ((address&0x3) != 0x3) and (not m_segment.contains(address)) ) 
                {
                    std::cout << "error in component VCI_CC_XCACHE_WRAPPER "
                              << name() << std::endl;
                    std::cout << "out of segment coherence request"
                              << std::endl;
                    exit(0);
                }
            
                // address of the target cache line = nline * m_cache_words * 4
                tgt_addr  = (vci_addr_t)(((((uint64_t)p_vci_tgt_c.be.read() & 0x3) << 32) | 
                                  (uint64_t)p_vci_tgt_c.wdata.read() ) << m_cache_words_shift);

                r_tgt_srcid    	= p_vci_tgt_c.srcid.read();
                r_tgt_trdid    	= p_vci_tgt_c.trdid.read();
                r_tgt_pktid    	= p_vci_tgt_c.pktid.read();
                r_tgt_addr 	= tgt_addr;             // target line (for *CACHE FSMs)
                    
                if ( (address&0x3) == 0x3 )   // broadcast invalidate 
                {
                    if ( not p_vci_tgt_c.eop.read() ) 
                    {
                        std::cout << "error in component VCI_CC_XCACHE_WRAPPER " 
                                  << name() << std::endl;
                        std::cout << "the BROADCAST INVALIDATE command length must be one word"
                                  << std::endl;
                        exit(0);
                    }
                    r_tgt_update = false; 
                    r_tgt_fsm = TGT_REQ_BROADCAST;

                    m_cpt_cc_inval_broadcast++ ;
                }
                else                    // multi-update or multi-invalidate
                { 
                    uint32_t cell = address - m_segment.baseAddress(); 
                    if (cell == 0)                           // invalidate data
                    {
                        if ( not p_vci_tgt_c.eop.read() ) 
                        {
                            std::cout << "error in component VCI_CC_XCACHE_WRAPPER " 
                                      << name() << std::endl;
                            std::cout << "the MULTI-INVALIDATE command length must be one word"
                                      << std::endl;
                            exit(0);
                        }
                        r_tgt_update 		= false; 
                        r_tgt_fsm 		= TGT_REQ_DCACHE;

                        m_cpt_cc_inval_dcache++ ;
                    } 
                    else if (cell == 4)                     // invalidate instruction
                    {                         
                        if ( not p_vci_tgt_c.eop.read() ) 
                        {
                            std::cout << "error in component VCI_CC_VCACHE_WRAPPER " 
                                      << name() << std::endl;
                            std::cout << "the MULTI-INVALIDATE command length must be one word"
                                      << std::endl;
                            exit(0);
                        }
                        r_tgt_update 		= false; 
                        r_tgt_fsm 		= TGT_REQ_ICACHE;

                        m_cpt_cc_inval_icache++ ;
                    } 
                    else if (cell == 8)    			// update data 
                    {                                
                        if ( p_vci_tgt_c.eop.read() ) 
                        {
                            std::cout << "error in component VCI_CC_VCACHE_WRAPPER " 
                                      << name() << std::endl;
                            std::cout << "the MULTI-UPDATE command length must be N+2 words" 
                                      << std::endl;
                            exit(0);
                        }
                        r_tgt_update      	= true;
                        r_tgt_update_data 	= true;
                        r_tgt_fsm 		= TGT_UPDT_WORD;

                        m_cpt_cc_update_dcache++;
                    }
                    else					// update instruction
                    {


                        if ( p_vci_tgt_c.eop.read() ) 
                        {
                            std::cout << "error in component VCI_CC_VCACHE_WRAPPER " 
                                      << name() << std::endl;
                            std::cout << "the MULTI-UPDATE command length must be N+2 words" 
                                      << std::endl;
                            exit(0);
                        }
                        r_tgt_update      	= true;
                        r_tgt_update_data 	= false;
                        r_tgt_fsm 		= TGT_UPDT_WORD;

                        m_cpt_cc_update_icache++;
                    }
                } // end if multi
            } // end if cmdval
            break;
        }
        //////////////////
        case TGT_UPDT_WORD:	 // first word index acquisition fo update requests

        {
            if (p_vci_tgt_c.cmdval.read()) 
            {
                if ( p_vci_tgt_c.eop.read() ) 
                {
                    std::cout << "error in component VCI_CC_XCACHE_WRAPPER " 
                              << name() << std::endl;
                    std::cout << "the MULTI-UPDATE command length must be N+2 words" 
                              << std::endl;
                    exit(0);
                }

                for ( size_t i=0 ; i<m_cache_words ; i++ ) r_tgt_be[i] = 0;

                r_tgt_word_min   = p_vci_tgt_c.wdata.read();  // first modified word 
                r_tgt_word_count = p_vci_tgt_c.wdata.read();  // initializes the word counter
                r_tgt_fsm   = TGT_UPDT_DATA;
            }
            break;
        }
        ///////////////////
        case TGT_UPDT_DATA:  // data acquisition for update requests
        {
            if (p_vci_tgt_c.cmdval.read()) 
            {
                size_t word = r_tgt_word_count.read();
                if ( word >= m_cache_words ) 
                {
                    std::cout << "error in component VCI_CC_XCACHE_WRAPPER " 
                              << name() << std::endl;
                    std::cout << "the reveived MULTI-UPDATE command length is wrong" 
                              << std::endl;
                    exit(0);
                }

                r_tgt_buf[word] = p_vci_tgt_c.wdata.read();
                r_tgt_be [word] = p_vci_tgt_c.be.read();

                r_tgt_word_count = word + 1;
                if (p_vci_tgt_c.eop.read())  // last word 
                {
                    r_tgt_word_max = word;          // last modified word 
              	    if(r_tgt_update_data.read()) 	r_tgt_fsm = TGT_REQ_DCACHE;
                    else 			        r_tgt_fsm = TGT_REQ_ICACHE;
                }
            }
            break;
        }
        ///////////////////////
        case TGT_REQ_BROADCAST: // set the requests (if no previous request pending)
        {
            if (not r_tgt_icache_req.read() and not r_tgt_dcache_req.read()) 
            {
                r_tgt_fsm = TGT_RSP_BROADCAST; 
                r_tgt_icache_req = true;
                r_tgt_dcache_req = true;
            }
            break;
        }
        ////////////////////
        case TGT_REQ_ICACHE: // set the request (if no previous request pending)
        {
            if ( not r_tgt_icache_req.read() ) 
            {
                r_tgt_fsm = TGT_RSP_ICACHE; 
                r_tgt_icache_req = true;
            }
            break;
        }
        ////////////////////
        case TGT_REQ_DCACHE: // set the request (if no previous request pending)
        {
            if ( not r_tgt_dcache_req.read() ) 
            {
                r_tgt_fsm = TGT_RSP_DCACHE; 
                r_tgt_dcache_req = true;
            }
            break;
        }
        ///////////////////////
        case TGT_RSP_BROADCAST:  // waiting acknowlege from both dcache fsm and icache fsm
                                 // no VCI response when the r_tgt_*cache_rsp flip_flop is false
        {
            if ( not r_tgt_icache_req.read() and not r_tgt_dcache_req.read() )
            {
                if ( r_tgt_icache_rsp.read() or r_tgt_dcache_rsp.read() )  // at least one response
                {
                    if ( p_vci_tgt_c.rspack.read())
                    {
                        // reset dcache first if activated
                        if (r_tgt_dcache_rsp) 	r_tgt_dcache_rsp = false;
                        else 		        r_tgt_icache_rsp = false;
                    }
                }
                else
                {
                    r_tgt_fsm = TGT_IDLE;
                }
            }
            break;
        }
        ////////////////////
        case TGT_RSP_ICACHE:  // waiting acknowledge from the icache fsm
        {
            // no VCI response when the r_tgt_icache_rsp flip_flop is false
            if ( not r_tgt_icache_req.read() and p_vci_tgt_c.rspack.read() )
            {
                r_tgt_fsm = TGT_IDLE;
                r_tgt_icache_rsp = false; 
            }
            break;
        }
        ////////////////////
        case TGT_RSP_DCACHE:  // waiting acknowledge from the dcache fsm
        {
            // no VCI response when the r_tgt_dcache_rsp flip_flop is false
            if ( not r_tgt_dcache_req.read() and p_vci_tgt_c.rspack.read() )
            {
                r_tgt_fsm = TGT_IDLE;
                r_tgt_dcache_rsp = false; 
            }
            break;
        }
    } // end switch TGT_FSM

    /////////////////////////////////////////////////////////////////////
    // Get data and instruction requests from processor
    ///////////////////////////////////////////////////////////////////////

    typename iss_t::InstructionRequest  ireq = ISS_IREQ_INITIALIZER;
    typename iss_t::DataRequest         dreq = ISS_DREQ_INITIALIZER;

    r_iss->getRequests(ireq, dreq);

    ///////////////////////////////////////////////////////////////////////////////
    // The ICACHE FSM controls the following ressources:
    // - r_icache_fsm
    // - r_icache_fsm_save
    // - r_icache_addr_save
    // - r_icache_miss_req (set)
    // - r_icache_unc_req (set)
    // - r_icache_cleanup_req (set)
    // - r_icache_cleanup_line
    // - r_icache_cleanup_set
    // - r_icache_cleanup_way
    // - r_icache_miss_inval
    // - r_icache (instruction cache access)
    // - r_vci_rsp_ins_error (reset)
    // - r_tgt_icache_req (reset)
    // - r_tgt_icache_rsp
    // - ireq & irsp structures for communication with the processor
    //
    // 1/ Coherence requests (update or invalidate) have highest priority.
    //    They are taken into account in IDLE, UNC_WAIT, and MISS_WAIT states.
    //    In case of coherence request the ICACHE FSM goes to the CC_CHECK
    //    state to test the cache hit, and then to the CC_INVAL or
    //    CC_UPDATE states to execute the request. It reset the r_tgt_icache_req 
    //    flip_flop to signal completion, writes in the r_tgt_icache_rsp
    //    to allow the VCI response, and returns in the pre-empted state.
    //    
    // 2/ Processor requests are taken into account only in the IDLE state.
    //    In case of miss, or in case of uncached instruction, the FSM 
    //    writes the missing address line in the r_icache_addr_save register 
    //    and sets the r_icache_miss_req or the r_icache_unc_req flip-flops.
    //    These request flip-flops are reset by the VCI_RSP FSM
    //    when the VCI transaction is completed.
    //
    // 3/ In case of uncacheable instruction, the VCI_RSP FSM writes the
    //    requested instruction in the r_icache_unc_buf register, and
    //    sets the r_icache_unc_valid flip_flop. This flip_flop is reset
    //    by the ICACHE FSM.
    //
    // 4/ In case of bus error, the VCI_RSP FSM sets the r_vci_rsp_ins_error 
    //    flip-flop, and does not write any data in the response FIFO.
    //    The r_vci_rsp_ins_error flip-flop is reset by the ICACHE FSM.
    ////////////////////////////////////////////////////////////////////////////////
        
    // The default value for irsp.valid is false
    typename iss_t::InstructionResponse irsp = ISS_IRSP_INITIALIZER;

    switch( r_icache_fsm.read() ) 
    {
        /////////////////
        case ICACHE_IDLE:
        {
            if ( r_tgt_icache_req.read() )    // coherence request
            {
                r_icache_fsm = ICACHE_CC_CHECK;
                r_icache_fsm_save = r_icache_fsm.read();
                break;
            } 
            if ( ireq.valid )  // processor request
            {
                bool     cacheable = m_cacheability_table[ireq.addr];
                vci_addr_t addr     = (vci_addr_t)ireq.addr;

                if ( cacheable )	 // cacheable
                {
                    data_t   inst;
                    bool     hit = r_icache->read(addr, &inst);
                    m_conso_icache_dir_read++;
                    m_conso_icache_data_read++;
                    if ( !hit )     // cacheable miss
                    {
                        // in order to avoid a dead-lock with the mem_cache
                        // (in case of simultaneous broadcast for example),
                        // we check that the previous cleanup request is completed
                        // and the ICACHE FSM is blocked in IDLE state until completion
                        if ( not r_icache_cleanup_req.read() )
                        {
                            r_icache_fsm       = ICACHE_MISS_VICTIM;
                            r_icache_miss_req  = true;
                            r_icache_addr_save = addr;
                            m_cpt_ins_miss++;
                            m_cost_ins_miss_frz++;
                        }
                    }
                    else            // cacheable hit
                    {
                        irsp.valid          = true;
                        irsp.instruction    = inst;
                        m_cpt_ins_cacheable++;
                    }
                } 
                else 		    // non cacheable
                {
                    if ( r_icache_unc_valid.read() and (addr == r_icache_addr_save.read()) )
                    {
                        r_icache_unc_valid  = false;
                        irsp.valid          = true;
                        irsp.instruction    = r_icache_unc_buf.read();
                        m_cpt_ins_uncacheable++;
                    }
                    else
                    {
                        r_icache_unc_valid  = false;
                        r_icache_fsm       = ICACHE_UNC_WAIT;
                        r_icache_unc_req   = true;
                        r_icache_addr_save = addr;
                    }
                }
            }
            break;
        }
        ////////////////////////
        case ICACHE_MISS_VICTIM:           // Selects (and invalidates) a victim line
        {                                  // Set the r_icache_cleanup_req flip-flop 
                                           // when the selected slot is not empty
            m_cost_ins_miss_frz++;

            size_t       way;
            size_t       set;
            vci_addr_t   victim;
                        
            r_icache_cleanup_req  = r_icache->victim_select( r_icache_addr_save.read(), 
                                                             &victim, 
                                                             &way, 
                                                             &set );
            r_icache_cleanup_line = victim;
            r_icache_cleanup_way  = way;
            r_icache_cleanup_set  = set;
            r_icache_fsm = ICACHE_MISS_WAIT;
            break;
        }
        //////////////////////
        case ICACHE_MISS_WAIT:            // waiting the response to a miss request
        {                                 // to test a bus error
            m_cost_ins_miss_frz++;

            if ( r_tgt_icache_req.read() )    // coherence request
            {
                r_icache_fsm      = ICACHE_CC_CHECK;
                r_icache_fsm_save = r_icache_fsm.read();
                break;
            }

            if ( r_vci_rsp_ins_error.read() ) 
            {
                r_icache_fsm = ICACHE_ERROR;
            } 
            else if ( r_vci_rsp_fifo_icache.rok() )
            {
                r_icache_update_word = 0;
                r_icache_fsm = ICACHE_MISS_UPDT;
            }
            break;
        }
        //////////////////////
        case ICACHE_MISS_UPDT:          // Update the cache (one word per cycle) 
        {
            m_cost_ins_miss_frz++;
            if ( r_vci_rsp_fifo_icache.rok() )
            {
                size_t      word = r_icache_update_word.read();
                vci_addr_t  addr = r_icache_addr_save.read();
                size_t      way  = r_icache_cleanup_way.read();
                size_t      set  = r_icache_cleanup_set.read();

                m_conso_icache_data_write++;
                // if the pending miss is cancelled by a matching coherence request
                // we pop the FIFO, but we don't update the cache
                if ( not r_icache_miss_inval.read() )
                      r_icache->write( way, 
                                       set, 
                                       word, 
                                       r_vci_rsp_fifo_icache.read() );

                vci_rsp_fifo_icache_get = true;
                r_icache_update_word = word+1;

                // if last word, finish the update
                if ( word == m_cache_words-1 )
                {
                    if ( not r_icache_miss_inval.read() )
                    {
                        m_conso_icache_dir_write++;
                        r_icache->victim_update_tag(addr, way, set);
                    }
                    r_icache_miss_inval = false;
                    r_icache_fsm = ICACHE_IDLE;
                }
            }
            break;
        }
        /////////////////////
        case ICACHE_UNC_WAIT:           // waiting the response to an uncached request
        {
            if ( r_tgt_icache_req.read() )   // coherence request
            {
                r_icache_fsm      = ICACHE_CC_CHECK;
                r_icache_fsm_save = r_icache_fsm.read();
                break;
            }
            if ( r_vci_rsp_ins_error ) 	
            {
                r_icache_fsm = ICACHE_ERROR;
            }
            else if ( r_vci_rsp_fifo_icache.rok() )
            {
                vci_rsp_fifo_icache_get = true;
                r_icache_unc_buf        = r_vci_rsp_fifo_icache.read();
                r_icache_unc_valid      = true;                
                r_icache_fsm            = ICACHE_IDLE;
            }
            break;
        }
        //////////////////
        case ICACHE_ERROR:
        {
            irsp.error          = true;
            irsp.valid          = true;
            r_icache_fsm        = ICACHE_IDLE;
            r_vci_rsp_ins_error = false;
            break;
        }
        /////////////////////
        case ICACHE_CC_CHECK:   // check directory in case of coherence request
        {
            vci_addr_t 	addr = r_tgt_addr.read();
            vci_addr_t 	mask = ~((m_cache_words<<2)-1);

            if( (r_icache_fsm_save.read() == ICACHE_MISS_WAIT) and 
                ((r_icache_addr_save.read() & mask) == (addr & mask))) 
                // The coherence request matches a pending miss
            {
                r_icache_miss_inval = true;
                r_tgt_icache_req    = false;
                r_tgt_icache_rsp    = r_tgt_update.read();
                r_icache_fsm        = r_icache_fsm_save.read();  
            } 
            else  // no match for a pending miss
            {
                size_t way;
                size_t set;
                size_t word;
                bool   hit = r_icache->hit(addr, 
                                           &way, 
                                           &set, 
                                           &word);
                r_icache_cc_way = way;
                r_icache_cc_set = set;

                m_conso_icache_dir_read++;

                if ( hit and r_tgt_update.read() )           // hit update
                {
                      r_icache_fsm         = ICACHE_CC_UPDT;
                      r_icache_update_word = r_tgt_word_min.read();
                } 
                else if ( hit and not r_tgt_update.read() )  // hit inval
                {
                    r_icache_fsm = ICACHE_CC_INVAL;
                } 
                else  				                        // miss can happen
                {
                    r_tgt_icache_req = false;
                    r_tgt_icache_rsp = r_tgt_update.read(); 
                    r_icache_fsm     = r_icache_fsm_save.read();
                }
            }
            break;
        }
        /////////////////////
        case ICACHE_CC_INVAL:  
        {                      
              vci_addr_t nline; 
              r_icache->inval( r_icache_cc_way.read(),
                               r_icache_cc_way.read(),
                               &nline );
              r_tgt_icache_req = false;
              r_tgt_icache_rsp = true;
              r_icache_fsm     = r_icache_fsm_save.read();
              break;
        }    
        /////////////////////
        case ICACHE_CC_UPDT:
        {                       
            size_t  word = r_icache_update_word.read();
            r_icache->write( r_icache_cc_way.read(),
                             r_icache_cc_set.read(),
                             word,
                             r_tgt_buf[word].read(),
                             r_tgt_be[word].read() );
            r_icache_update_word = word+1;

            if ( word == r_tgt_word_max.read() )  // last word
            {
                r_tgt_icache_req = false;
                r_tgt_icache_rsp = true;
                r_icache_fsm     = r_icache_fsm_save.read();
            }
            break;
        }    
    } // end switch r_icache_fsm

    // save the IREQ and IRSP fields for the print_trace() function
    m_ireq_valid        = ireq.valid;
    m_ireq_addr         = ireq.addr;
    m_ireq_mode         = ireq.mode;
    
    m_irsp_valid        = irsp.valid;
    m_irsp_instruction  = irsp.instruction;
    m_irsp_error        = irsp.error;

    //////////////////////////////////////////////////////////////////////://///////////
    // The DCACHE FSM controls the following ressources:
    // - r_dcache_fsm
    // - r_dcache_fsm_save
    // - r_dcache (data cache access)
    // - r_dcache_addr_save
    // - r_dcache_wdata_save
    // - r_dcache_be_save
    // - r_dcache_way_save
    // - r_dcache_set_save
    // - r_dcache_word_save
    // - r_dcache_miss_req (set)
    // - r_dcache_unc_req (set)
    // - r_dcache_sc_req (set)
    // - r_dcache_cleanup_req (set)
    // - r_vci_rsp_data_error (reset)
    // - r_tgt_dcache_req (reset)
    // - r_wbuf write
    // - drsp structure 
    //
    // 1/ Coherence requests : 
    //    There is a coherence request when the tgt_dcache_req flip-flop is set,
    //    requesting a line invalidation or a line update. 
    //    Coherence requests are taken into account in IDLE, UNC_WAIT, MISS_WAIT states, 
    //    and have the highest priority.
    //    The actions associated to the pre-empted state are not executed, the DCACHE FSM
    //    goes to the CC_CHECK state to execute the requested action, and returns to the
    //    pre-empted state.
    //
    // 2/ processor requests : 
    //    Processor READ requests are taken into account in IDLE state only.
    //    In order to support WRITE bursts, write requests are taken into account 
    //    in the WRITE_UPDT state as well as in the IDLE state.
    //    - The processor read requests cannot be satisfied if
    //    there is a cached read miss, or an uncached read.
    //    - The processor write requests cannot be satisfied when the write buffer is full.
    //
    // 3/ Atomic instructions LL/SC
    //    The reservation registers (r_dcache_ll_valid, r_dcache_ll_addr and
    //    r_dcache_ll_data are stored in the L1 cache controller, and not in the 
    //    memory controller. 
    //    - LL requests from the processor and are transmitted as standard 
    //      VCI read transactions (one word / one line, depending on the cacheability).
    //    - SC requests from the processor are systematically transmitted to the 
    //      memory cache as compare&swap requests (both the data value stored in the
    //      r_dcache_ll_data register and the new value). 
    //    The LL/SC address can be cacheable or not cacheable.
    //
    // 4/ Non cacheable access
    //    This component implement a strong order between non cacheable access
    //    (read or write) : A new non cacheable VCI transaction starts only when
    //    the previous non cacheable transaction is completed. Both cacheable and
    //    non cacheable transactions use the write buffer, but the DCACHE FSM registers
    //    a non cacheable write transaction posted in the write buffer by setting the
    //    r_dcache_pending_unc_write flip_flop. All other non cacheable requests
    //    are stalled until this flip-flop is reset by the VCI_RSP_FSM (when the 
    //    pending non cacheable write transaction completes).
    //
    // 5/ Error handling :  Read Bus Errors are synchronous events, but
    //    Write Bus Errors are asynchronous events (processor is not frozen).
    //    - If a Read Bus Error is detected, the VCI_RSP FSM sets the
    //      r_vci_rsp_data_error flip-flop, without writing any data in the
    //      r_vci_rsp_fifo_dcache FIFO, and the synchronous error is signaled
    //      by the DCACHE FSM.
    //    - If a Write Bus Error is detected, the VCI_RSP FSM  signals
    //      the asynchronous error using the setWriteBerr() method.
    ///////////////////////////////////////////////////////////////////////////////////

    // The default value for drsp.valid is false
    typename iss_t::DataResponse  drsp = ISS_DRSP_INITIALIZER;

    switch ( r_dcache_fsm.read() ) 
    {
        /////////////////
        case DCACHE_IDLE:       // waiting requests from processor
        {
            if ( r_tgt_dcache_req.read() )  // coherence request
            { 
                r_dcache_fsm      = DCACHE_CC_CHECK;
                r_dcache_fsm_save = r_dcache_fsm.read();
                break;
            } 
            if ( dreq.valid )  // processor request
            {
                bool     	cacheable      = m_cacheability_table[dreq.addr];
                vci_addr_t	addr          = (vci_addr_t)dreq.addr;

                switch( dreq.type ) 
                {
                    case iss_t::DATA_LL:
                    case iss_t::DATA_READ:
                    {
                        if ( cacheable )	// cacheable read   
                        {
                            data_t   rdata;
                            bool     hit = r_dcache->read(addr, &rdata);
                            m_conso_dcache_dir_read++;
                            m_conso_dcache_data_read++;
                            if ( !hit )         // cacheable read miss
                            {
                                // in order to avoid a dead-lock with the mem_cache
                                // (in case of simultaneous broadcast for example),
                                // we check that the previous cleanup request is completed
                                // if not the DCACHE_FSM is blocked in IDLE state until completion
                                if ( not r_dcache_cleanup_req.read() )
                                {
                                    r_dcache_fsm       = DCACHE_MISS_VICTIM;
                                    r_dcache_miss_req  = true;
                                    r_dcache_addr_save = addr;
                                    m_cpt_data_read_miss++;
                                    m_cost_data_miss_frz++;
                                }
                            }
                            else                // cacheable read hit
                            {
                                m_cpt_data_read_cacheable++;
                                drsp.valid   = true;
                                drsp.rdata   = rdata;

                                // makes reservation in case of LL
                                if( dreq.type == iss_t::DATA_LL )
                                {
                                    m_cpt_data_ll++;
                                    r_dcache_ll_valid = true;
                                    r_dcache_ll_data  = rdata;
                                    r_dcache_ll_addr  = addr;
                                }
                            }
                        }
                        else            // non cacheable read   
                        {
                            // non cacheable accesses must be strongly ordered
                            // A non cacheable read must be delayed if there is 
                            // a pending uncacheable write in the write buffer 
                            if ( not r_dcache_pending_unc_write.read() )
                            {
                                if ( r_dcache_unc_valid.read() and 			// hit
                                           (addr == r_dcache_addr_save.read()) )
                                {
                                    r_dcache_unc_valid = false;
                                    drsp.valid         = true;
                                    drsp.rdata         = r_dcache_unc_buf.read();
                                    m_cpt_data_read_uncacheable++;

                                    // makes reservation in case of uncacheable LL
                                    if( dreq.type == iss_t::DATA_LL )
                                    {
                                        m_cpt_data_ll++;
                                        r_dcache_ll_valid = true;
                                        r_dcache_ll_data  = r_dcache_unc_buf.read();
                                        r_dcache_ll_addr  = addr;
                                    }
                                }
                                else							// miss
                                {
                                    r_dcache_unc_valid = false;
                                    r_dcache_unc_req   = true;
                                    r_dcache_fsm       = DCACHE_UNC_WAIT;
                                    r_dcache_addr_save = addr;
                                }
                            } // end if pending_unc_write
                        }                        
                        break;
                    }
                    case iss_t::DATA_SC:
                    {
                        // - if a previous LL (with the same address) is registered, 
                        // we makes a SC transaction, that will store the response
                        // in the r_dcache_unc_buf register (0 if success).
                        // As for the non cacheable read, we must test the 
                        // r_dcache_unc_valid flip-flop to detect the SC completion,
                        // return the value stored in r_dcache_unc_buf, and invalidate
                        // the LL reservation.
                        // - if there is no registerd LL, we just stay in IDLE state 
                        // and return 1 (atomic access failed)

                        if( r_dcache_ll_valid.read() and (r_dcache_ll_addr.read() == addr))
                        {
                            if ( r_dcache_unc_valid.read() and 		// SC done
                                    (addr == r_dcache_addr_save.read()) )
                            {
                                r_dcache_ll_valid  = false;
                                r_dcache_unc_valid = false;
                                drsp.valid         = true;
                                drsp.rdata         = r_dcache_unc_buf.read();
                                m_cpt_data_sc++;
                            }
                            else					// SC to be done
                            {
                                r_dcache_sc_req     = true;
                                r_dcache_fsm        = DCACHE_UNC_WAIT;
                                r_dcache_addr_save  = addr;
                                r_dcache_wdata_save = dreq.wdata;
                            }
                        } 
                        else 					// no registered LL
                        {
                            drsp.valid = true;
                            drsp.rdata = 1; 
                            r_dcache_ll_valid = false;
                        }
                        break;
                    }
                    case iss_t::XTN_READ:
                    case iss_t::XTN_WRITE:
                    {
                        // only DCACHE INVALIDATE and SYNC requests are supported
                        if ( dreq.addr>>2 == iss_t::XTN_DCACHE_INVAL ) 
                        {
                            m_cpt_xtn_dcache_inval++;
                            r_dcache_fsm        = DCACHE_INVAL;
                            r_dcache_wdata_save = dreq.wdata;
                        } 
                        else if ( dreq.addr>>2 == iss_t::XTN_SYNC )
                        {
                            m_cpt_xtn_sync++;
                            // Test if write buffer is already empty
                            if ( r_wbuf->empty() )
                            {
                                drsp.valid = true;
                                r_dcache_fsm  = DCACHE_IDLE;
                            }
                            else
                            {
                                r_dcache_fsm  = DCACHE_SYNC;
                            }
                        }
                        else
                        {
                            std::cout << "Warning in VCI_CC_XCACHE_WRAPPER " 
                                      << name() << std::endl;
                            std::cout << "Unsupported  external access : " 
                                      << (dreq.addr>>2) << std::endl;
                            drsp.valid = true;
                            r_dcache_fsm  = DCACHE_IDLE;
                        }
                        break;
                    }
                    case iss_t::DATA_WRITE:
                    {
                        if ( cacheable )     // cacheable write
                        {
                            bool    hit;
                            size_t  way		= 0;
                            size_t  set		= 0;
                            size_t  word	= 0;

                            m_conso_dcache_dir_read++;
                            hit = r_dcache->hit(addr, &way, &set, &word);
                            m_conso_wbuf_write++;
                            bool wok = r_wbuf->write(addr, dreq.be, dreq.wdata, cacheable);
                            if ( wok )
                            {
                                m_cpt_data_write_cacheable++;
                                drsp.valid = true;
                                if (hit)    // cached write
                                {
                                    m_cpt_data_write_hit++;
                                    r_dcache_fsm          = DCACHE_WRITE_UPDT; 
                                    r_dcache_addr_save    = addr;
                                    r_dcache_wdata_save   = dreq.wdata;
                                    r_dcache_be_save      = dreq.be;
                                    r_dcache_way_save     = way;
                                    r_dcache_set_save     = set;
                                    r_dcache_word_save    = word;
                                }
                                else	  // non cached
                                {
                                    r_dcache_fsm = DCACHE_IDLE;
                                }
                            }
                            else  // write miss into write buffer
                            {
                                r_dcache_fsm = DCACHE_IDLE;
                                m_cost_write_frz++;
                            }
                        }
                        else                // non cacheable write 
                        {
                            // non cacheable accesses must be strongly ordered
                            // A non cacahble write must be delayed if there is 
                            // a pending uncacheable write in the write buffer 
                            if ( not r_dcache_pending_unc_write.read() )
                            {
                                m_conso_wbuf_write++;
                                bool wok = r_wbuf->write(addr, dreq.be, dreq.wdata, cacheable);
                                if ( wok ) 
                                {
                                    m_cpt_data_write_uncacheable++;
                                    drsp.valid = true;
                                }
                            }
                            r_dcache_fsm = DCACHE_IDLE;
                        }

                        break;
                    }
                }   // end switch dreq.type
            }   // end if dreq.valid
            break;
        }
        ///////////////////////
        case DCACHE_WRITE_UPDT:
        {
            // cache update (address, data & be from the previous cycle)
            m_conso_dcache_data_write++;
            r_dcache->write( r_dcache_way_save.read(),         
                             r_dcache_set_save.read(),        
                             r_dcache_word_save.read(),
                             r_dcache_wdata_save.read(),  
                             r_dcache_be_save.read() );  

#if DEBUG_DCACHE
if ( (m_cpt_total_cycles > DEBUG_START_CYCLE) and (m_srcid_d == DEBUG_ID) )
{
    std::cout << "  <PROC.DCACHE_WRITE_UPDT> Writing one word :" << std::hex
              << " data = " << r_dcache_wdata_save.read()
              << " / be = " << r_dcache_be_save.read()
              << " / way = " << r_dcache_way_save.read()
              << " / set = " << r_dcache_set_save.read()
              << " / word = " << r_dcache_word_save.read() << std::endl;
}
#endif

            // possible write after write
            if ( dreq.valid and (dreq.type == iss_t::DATA_WRITE) )
            {
                bool     cacheable = m_cacheability_table[dreq.addr];
                vci_addr_t addr     = (vci_addr_t)dreq.addr;

                if ( cacheable ) // cacheable write
                {
                    bool    hit;
                    size_t  way  = 0;
                    size_t  set  = 0;
                    size_t  word = 0;

                    m_conso_dcache_dir_read++;
                    hit = r_dcache->hit(addr, &way, &set, &word);
                    m_conso_wbuf_write++;
                    bool wok = r_wbuf->write(addr, dreq.be, dreq.wdata, cacheable);
                    if (wok)   
                    {
                        m_cpt_data_write_cacheable++;
                        drsp.valid = true;
                        if (hit)        // cached write
                        {
                            m_cpt_data_write_hit++;
                            r_dcache_fsm          = DCACHE_WRITE_UPDT; 
                            r_dcache_addr_save    = addr;
                            r_dcache_wdata_save   = dreq.wdata;
                            r_dcache_be_save      = dreq.be;
                            r_dcache_way_save     = way;
                            r_dcache_set_save     = set;
                            r_dcache_word_save    = word;
                        }
                        else   // uncached write
                        {
                            r_dcache_fsm = DCACHE_IDLE;
                        }
                    }
                    else   // write miss into write buffer
                    {
                        m_cost_write_frz++;
                        r_dcache_fsm = DCACHE_IDLE;
                    }
                }
                else  // non cacheable write
                {
                    // non cacheable accesses must be strongly ordered 
                    // A non cacahble write must be delayed if there is 
                    // a pending uncacheable write in the write buffer 
                    if ( not r_dcache_pending_unc_write.read() )
                    {
                        m_conso_wbuf_write++;
                        bool wok = r_wbuf->write(addr, dreq.be, dreq.wdata, cacheable);
                        if ( wok ) 
                        {
                            m_cpt_data_write_uncacheable++;
                            drsp.valid = true;
                        }
                    }
                    r_dcache_fsm = DCACHE_IDLE;
                }
            }
            else    // no valid write request
            {
                r_dcache_fsm = DCACHE_IDLE;
            }
            break;
        }
        ////////////////////////
        case DCACHE_MISS_VICTIM:           // Selects (and invalidates) a victim line
        {                                  // Set the r_dcache_cleanup_req flip-flop 
                                           // when the selected slot is not empty
            m_cost_data_miss_frz++;

            size_t     way;
            size_t     set;
            vci_addr_t   addr = r_dcache_addr_save.read();
            vci_addr_t   victim;
                        
            bool cleanup_requested = r_dcache->victim_select( addr, &victim, &way, &set );

            r_dcache_cleanup_line = victim;
            r_dcache_cleanup_way  = way;
            r_dcache_cleanup_set  = set;
            r_dcache_cleanup_req  = cleanup_requested;
            r_dcache_fsm = DCACHE_MISS_WAIT;
            break;
        }
        //////////////////////
        case DCACHE_MISS_WAIT:          // Waiting the response to a miss request
        {                               // to test a bus error
            m_cost_data_miss_frz++;

            if ( r_tgt_dcache_req.read() )    // coherence request
            {
                r_dcache_fsm      = DCACHE_CC_CHECK;
                r_dcache_fsm_save = r_dcache_fsm.read();
                break;
            }

            if ( r_vci_rsp_data_error.read() ) 
            {
                r_dcache_fsm = DCACHE_ERROR;
            } 
            else if ( r_vci_rsp_fifo_dcache.rok() )
            {
                r_dcache_update_word = 0;
                r_dcache_fsm = DCACHE_MISS_UPDT;
            }
            break;
        }
        //////////////////////
        case DCACHE_MISS_UPDT:      // Update the cache (one word per cycle)
        {
            m_cost_data_miss_frz++;

            size_t       word = r_dcache_update_word.read();
            vci_addr_t   addr = r_dcache_addr_save.read();
            size_t       way  = r_dcache_cleanup_way.read();
            size_t       set  = r_dcache_cleanup_set.read();
                    
            if ( r_vci_rsp_fifo_dcache.rok() )
            {
                if ( not r_dcache_miss_inval.read() )  // no matching coherence request
                {
                    m_conso_dcache_data_write++;
                    r_dcache->write( way, 
                                     set, 
                                     word, 
                                     r_vci_rsp_fifo_dcache.read() );

                    if ( word == m_cache_words-1 )	// last word
                    {
                        m_conso_dcache_dir_write++;
                        r_dcache->victim_update_tag(addr, way, set);
                        r_dcache_fsm = DCACHE_IDLE;
                    }
                    vci_rsp_fifo_dcache_get = true;
                    r_dcache_update_word = word+1;
                }
                else	// if there is a matching coherence request :
                        // we pop the response FIFO, but we don't update the cache
                        // when we receive the last word, we send a cleanup for the
                        // missing line and return to the IDLE state
                {
                    if ( word < m_cache_words-1 ) 
                    {
                        vci_rsp_fifo_dcache_get = true;
                        r_dcache_update_word = word+1;
                    }
                    else	// last word
                    {
                        if ( not r_dcache_cleanup_req )
                        {
                            vci_rsp_fifo_dcache_get = true;
                            r_dcache_cleanup_req  = true;
                            r_dcache_cleanup_line = r_dcache_addr_save.read() >> m_cache_words_shift;
                            r_dcache_miss_inval    = false;
                            r_dcache_fsm          = DCACHE_IDLE;
                        }
                    }
                }

#if DEBUG_DCACHE
if ( (m_cpt_total_cycles > DEBUG_START_CYCLE) and (m_srcid_d == DEBUG_ID) )
{
    if ( r_dcache_miss_inval.read() )
    {
        if ( word < m_cache_words-1 ) 
        {
            std::cout << "  <PROC.DCACHE_MISS_UPDT> Matching coherence request:"
                      << "  pop the FIFO, don't update the cache" << std::endl;
        }
        else
        {
            std::cout << "  <PROC.DCACHE_MISS_UPDT> Matching coherence request:"
                      << " last word : send a cleanup request " << std::endl;
        }
    }
    else
    {
        std::cout << "  <PROC.DCACHE_MISS_UPDT> Write one word:"
                  << " address = " << addr 
                  << " / data = " << r_vci_rsp_fifo_dcache.read()
                  << " / way = " << way 
                  << " / set = " << set
                  << " / word = " << word << std::endl; 
    }
}
#endif
            }
            break;
        }
        /////////////////////
        case DCACHE_UNC_WAIT:       // Waiting the response to an uncached request
        {
            if ( r_tgt_dcache_req )    // coherence request
            {
                r_dcache_fsm      = DCACHE_CC_CHECK;
                r_dcache_fsm_save = r_dcache_fsm;
                break;
            } 

            if ( r_vci_rsp_data_error ) 
            {
                r_dcache_fsm = DCACHE_ERROR;
            }
            else if ( r_vci_rsp_fifo_dcache.rok() )
            {
                vci_rsp_fifo_dcache_get = true;
                r_dcache_unc_valid      = true;
                r_dcache_unc_buf        = r_vci_rsp_fifo_dcache.read();
                r_dcache_fsm            = DCACHE_IDLE;
            }
            break;
        }
        //////////////////
        case DCACHE_ERROR:      // signal a read bus error to the processor
        {
            r_dcache_fsm         = DCACHE_IDLE;
            r_vci_rsp_data_error = false;
            drsp.error           = true;
            drsp.valid           = true;
            break;
        }
        //////////////////    
        case DCACHE_INVAL:      // XTN inval is done in two cycles
                                // In this state we test the cache hit
        {                   
            uint32_t    data;   // unused
            size_t      word;   // unused
            size_t      way;
            size_t      set;
            bool        hit = r_dcache->read( r_dcache_wdata_save.read(),
                                              &data,
                                              &way,
                                              &set,
                                              &word );
            if ( hit )  // inval to be done
            {
                r_dcache_way_save = way;
                r_dcache_set_save = set;
                r_dcache_fsm      = DCACHE_INVAL_GO;
            }
            else        // nothing to do
            {
                drsp.valid        = true;
                r_dcache_fsm      = DCACHE_IDLE;
            }
            break;
        }
        /////////////////////    
        case DCACHE_INVAL_GO:   // XTN inval is done in two cycles
                                // In this state we wait to post a cleanup request
                                // and make the inval when cleanup is possible
        {

            if ( r_tgt_dcache_req )  // coherence request
            {   
                r_dcache_fsm      = DCACHE_CC_CHECK;
                r_dcache_fsm_save = r_dcache_fsm;
                break;
            } 

            if ( not r_dcache_cleanup_req .read() )
            {
                vci_addr_t  nline;
                r_dcache_cleanup_req  = r_dcache->inval( r_dcache_way_save.read(),
                                                         r_dcache_set_save.read(),
                                                         &nline );

                r_dcache_cleanup_line = r_dcache_wdata_save.read() >> m_cache_words_shift;
                r_dcache_fsm          = DCACHE_IDLE;
                drsp.valid            = true;      
            }
            break;
        }
        /////////////////
        case DCACHE_SYNC:       // waiting until the write buffer is empty
        {
            if ( r_tgt_dcache_req )  // coherence request
            {   
                r_dcache_fsm      = DCACHE_CC_CHECK;
                r_dcache_fsm_save = r_dcache_fsm;
                break;
            } 

            if ( r_wbuf->empty() );
            {
                drsp.valid    = true;      
                r_dcache_fsm  = DCACHE_IDLE;
            }
            break;
        }
        /////////////////////
        case DCACHE_CC_CHECK:   // read directory in case of coherence request
        {
            vci_addr_t  addr  = r_tgt_addr.read();
            vci_addr_t  mask  = ~((m_cache_words<<2)-1);

            if( (r_dcache_fsm_save.read() == DCACHE_MISS_WAIT) and 
                 ((r_dcache_addr_save.read() & mask) == (addr & mask)) )
                 // The coherence request matches a pending miss
            {
                r_dcache_miss_inval = true;
                r_tgt_dcache_req    = false;
                r_tgt_dcache_rsp    = r_tgt_update.read();
                r_dcache_fsm        = r_dcache_fsm_save.read();
            }
            else    // no match for a pending miss
            {
                size_t  way;
                size_t  set;
                size_t  word;
                bool    hit   = r_dcache->hit( addr, 
                                               &way, 
                                               &set, 
                                               &word );
                r_dcache_cc_way = way;
                r_dcache_cc_set = set;

                m_conso_dcache_dir_read++;

                if ( hit and r_tgt_update.read() )          // hit update
                {
                    r_dcache_fsm         = DCACHE_CC_UPDT;
                    r_dcache_update_word = r_tgt_word_min.read();
                }
                else if (hit and not r_tgt_update.read() )  // hit inval
                {
                    r_dcache_fsm         = DCACHE_CC_INVAL;
                }
                else                                        // miss can happen
                {
                    r_tgt_dcache_req = false;
                    r_tgt_dcache_rsp = r_tgt_update.read();
                    r_dcache_fsm     = r_dcache_fsm_save.read();
                }
            }
            break;
        }
        /////////////////////
        case DCACHE_CC_INVAL:  
        {
            vci_addr_t  nline;
            r_dcache->inval( r_dcache_cc_way.read(),
                             r_dcache_cc_set.read(),
                             &nline );
            r_tgt_dcache_req = false;
            r_tgt_dcache_rsp = true;
            r_dcache_fsm     = r_dcache_fsm_save.read();
            break;
        }
        ////////////////////
        case DCACHE_CC_UPDT:   
        {
              size_t word = r_dcache_update_word.read();
              r_dcache->write( r_dcache_cc_way.read(),
                               r_dcache_cc_set.read(),
                               word,
                               r_tgt_buf[ word].read(),
                               r_tgt_be[word].read() );

              r_dcache_update_word = word+1;
              if ( word == r_tgt_word_max.read() )      // last word
              {
                  r_tgt_dcache_req = false;
                  r_tgt_dcache_rsp = true;
                  r_dcache_fsm     = r_dcache_fsm_save.read();
              }
              break;
          }
    } // end switch r_dcache_fsm
        
    // save the DREQ and DRSP fields for the print_trace() function
    m_dreq_valid = dreq.valid;
    m_dreq_addr  = dreq.addr;
    m_dreq_mode  = dreq.mode;
    m_dreq_type  = dreq.type;
    m_dreq_wdata = dreq.wdata;
    m_dreq_be    = dreq.be;
    
    m_drsp_valid = drsp.valid;
    m_drsp_rdata = drsp.rdata;
    m_drsp_error = drsp.error;

    ////////// write buffer state update  ////////////////////////////////////////////
    // The update() method must be called at each cycle to update the internal state.

    r_wbuf->update ();

    /////////// test processor frozen /////////////////////////////////////////////
    // The simulation exit if the number of consecutive frozen cycles
    // is larger than the m_max_frozen_cycles (constructor parameter)
    if ( (ireq.valid and not irsp.valid) or (dreq.valid and not drsp.valid) )       
    {
        m_cpt_frz_cycles++;         // used for instrumentation
        m_cpt_stop_simulation++;    // used for processor stop if frozen
        if ( m_cpt_stop_simulation > m_max_frozen_cycles )
        {
            std::cout << std::dec << "ERROR in CC_XCACHE_WRAPPER " << name()
                      << " frozen since cycle " << m_cpt_total_cycles - m_max_frozen_cycles 
                      << std::endl;
            exit(1);
        }
    }
    else
    {
        m_cpt_stop_simulation = 0;
    }

    /////////// execute one iss cycle /////////////////////////////////////////////

    uint32_t it = 0;
    for (size_t i=0; i<(size_t)iss_t::n_irq; i++) if ( p_irq[i].read() ) it |= (1<<i);
                
    r_iss->executeNCycles(1, irsp, drsp, it);

    ////////////////////////////////////////////////////////////////////////////////
    // The CLEANUP FSM send the cleanup commands on the coherence network,
    // and supports simultaneous cleanup transactions, but two simultaneous
    // transactions mut address different cache lines.
    // Therefore, the line number is registered in an associative
    // registration buffer (Content Adressable Memory) by the CLEANUP FSM,
    // and the corresponding slot (identified by the VCI TRDID field) is cleared 
    // when the cleanup transaction response is received.
    // It handles cleanup requests from both the DCACHE FSM & ICACHE FSM
    // with a round robin priority, and can support up to 16 simultaneous 
    // cleanup transactions (16 slots in the registration buffer).
    // The r_dcache_cleanup_req (or r_icache_cleanup_req) flip-flops are reset
    // when the command has been sent.
    // The VCI TRDID field is used to distinguish data/instruction cleanups:
    // - if data cleanup        : TRDID = 2*index + 0
    // - if instruction cleanup : TRDID = 2*index + 1
    ////////////////////////////////////////////////////////////////////////////

    switch ( r_cleanup_fsm.read() ) 
    {
        ///////////////////////
        case CLEANUP_DATA_IDLE:     // dcache has highest priority
        {
            size_t  index = 0;
            bool    ok;
            if ( r_dcache_cleanup_req.read() )      // dcache request
            {
                ok = r_cleanup_buffer.register_value( r_dcache_cleanup_line.read(), 
                                                      &index );   
                if ( ok )   // successful registration
                {
                    r_cleanup_fsm   = CLEANUP_DATA_GO; 
                    r_cleanup_trdid = index<<1;
                }
            }
            else if ( r_icache_cleanup_req.read() ) // icache request
            {
                ok = r_cleanup_buffer.register_value( r_icache_cleanup_line.read(), 
                                                      &index );   
                if ( ok )   // successful registration
                {
                    r_cleanup_fsm   = CLEANUP_INS_GO; 
                    r_cleanup_trdid = index<<1 + 1;
                }
            }
            break;
        }
        //////////////////////
        case CLEANUP_INS_IDLE:     // icache has highest priority
        {
            size_t  index = 0;
            bool    ok;
            if ( r_icache_cleanup_req.read() )      // icache request
            {
                ok = r_cleanup_buffer.register_value( r_icache_cleanup_line.read(),
                                                      &index );   
                if ( ok )   // successful registration
                {
                    r_cleanup_fsm   = CLEANUP_INS_GO;
                    r_cleanup_trdid = index<<1 + 1;
                }
            }
            else if ( r_dcache_cleanup_req.read() ) // dcache request
            {
                ok = r_cleanup_buffer.register_value( r_dcache_cleanup_line.read(),
                                                      &index );   
                if ( ok )   // successful registration
                {
                    r_cleanup_fsm   = CLEANUP_DATA_GO;
                    r_cleanup_trdid = index<<1;
                }
            }
            break;
        }
        /////////////////////
        case CLEANUP_DATA_GO:
        {
            if ( p_vci_ini_c.cmdack.read() )
            {
                r_dcache_cleanup_req = false;
                r_cleanup_fsm    = CLEANUP_INS_IDLE;
            }
        }
        ////////////////////////
        case CLEANUP_INS_GO:
        {
            if ( p_vci_ini_c.cmdack.read() )
            {
                r_icache_cleanup_req = false;
                r_cleanup_fsm    = CLEANUP_DATA_IDLE;
            }
        }
    } // end switch CLEANUP FSM

    //////////////// Handling  cleanup responses //////////////////
    if ( p_vci_ini_c.rspval.read() )    // valid response
    {
        r_cleanup_buffer.cancel_index( p_vci_ini_c.rtrdid.read() >> 1);
    }

    ////////////////////////////////////////////////////////////////////////////
    // The VCI_CMD FSM controls the following ressources:
    // - r_vci_cmd_fsm
    // - r_vci_cmd_min
    // - r_vci_cmd_max
    // - r_vci_cmd_cpt
    // - r_vci_cmd_imiss_prio
    // - wbuf (reset)
    // - r_icache_miss_req (reset)
    // - r_icache_unc_req (reset)
    // - r_dcache_miss_req (reset)
    // - r_dcache_unc_req (reset)
    // - r_dcache_sc_req (reset)
    //
    // This FSM handles requests from both the DCACHE FSM & the ICACHE FSM.
    // There is 6 request types, with the following priorities : 
    // 1 - Data Read Miss         : r_dcache_miss_req and miss in the write buffer
    // 2 - Data Read Uncacheable   : r_dcache_unc_req  
    // 3 - Instruction Miss       : r_icache_miss_req and miss in the write buffer
    // 4 - Instruction Uncacheable : r_icache_unc_req 
    // 5 - Data Write             : r_wbuf.rok()      
    // 6 - Data Store Conditionnal: r_dcache_sc_req
    //
    // As we want to support several simultaneous VCI transactions, the VCI_CMD_FSM 
    // and the VCI_RSP_FSM are fully desynchronized.
    //
    // VCI formats:
    // According to the VCI advanced specification, all read requests packets 
    // (data Uncached, Miss data, instruction Uncached, Miss instruction) 
    // are one word packets.
    // For write burst packets, all words are in the same cache line,
    // and addresses must be contiguous (the BE field is 0 in case of "holes").
    // The sc command packet implements actually a compare-and-swap mechanism
    // and the packet contains two flits. 
    //////////////////////////////////////////////////////////////////////////////

    switch ( r_vci_cmd_fsm.read() ) 
    {
        //////////////
        case CMD_IDLE:
        {
            // r_dcache_miss_req and r_icache_miss_req require both a write_buffer access 
            // to check a possible pending write on the same cache line. 
            // As there is only one possible access per cycle to write buffer, we implement 
            // a round-robin priority for this access, using the r_vci_cmd_imiss_prio flip-flop.

            size_t	wbuf_min;
            size_t	wbuf_max;

            bool dcache_miss_req = r_dcache_miss_req.read() 
                 and ( not r_icache_miss_req.read() or not r_vci_cmd_imiss_prio.read() );
            bool icache_miss_req = r_icache_miss_req.read() 
                 and ( not r_dcache_miss_req.read() or r_vci_cmd_imiss_prio.read() );

            // 1 - Data Read Miss
            if ( dcache_miss_req and r_wbuf->miss(r_dcache_addr_save.read()) )
            { 
                r_vci_cmd_fsm        = CMD_DATA_MISS;
                r_dcache_miss_req    = false;
                r_vci_cmd_imiss_prio = true;
                m_cpt_dmiss_transaction++; 
            } 
            // 2 - Data Read Uncacheable
            else if ( r_dcache_unc_req.read() )
            { 
                r_vci_cmd_fsm    = CMD_DATA_UNC;
                r_dcache_unc_req = false;
                m_cpt_dunc_transaction++; 
            }
            // 3 - Instruction Miss
            else if ( icache_miss_req and r_wbuf->miss(r_icache_addr_save.read()) )
            {
                r_vci_cmd_fsm        = CMD_INS_MISS; 
                r_icache_miss_req    = false;
                r_vci_cmd_imiss_prio = false;
                m_cpt_imiss_transaction++;
            } 
            // 4 - Instruction Uncacheable
            else if ( r_icache_unc_req.read() )
            { 
                r_vci_cmd_fsm    = CMD_INS_UNC; 
                r_icache_unc_req = false;
                m_cpt_iunc_transaction++;
            }
            // 5 - Data Write
            else if ( r_wbuf->rok(&wbuf_min, &wbuf_max) )
            { 
                r_vci_cmd_fsm       = CMD_DATA_WRITE;
                r_vci_cmd_cpt       = wbuf_min;
                r_vci_cmd_min       = wbuf_min;
                r_vci_cmd_max       = wbuf_max;
                m_cpt_write_transaction++; 
                m_length_write_transaction += (wbuf_max-wbuf_min+1); 
            } 
            // 6 - Data Store Conditionnal
            else if ( r_dcache_sc_req.read() )
            { 
                r_vci_cmd_fsm       = CMD_DATA_SC;
                r_dcache_sc_req = false;
                r_vci_cmd_cpt       = 0;
                m_cpt_sc_transaction++; 
            }
            break;
        }
        ////////////////////
        case CMD_DATA_WRITE:
        {
            if ( p_vci_ini_d.cmdack.read() ) 
            {
                m_conso_wbuf_read++;
                r_vci_cmd_cpt = r_vci_cmd_cpt + 1;
                if (r_vci_cmd_cpt == r_vci_cmd_max) // last flit sent
                {
                    r_vci_cmd_fsm = CMD_IDLE ;
                    r_wbuf->sent() ;
                }
            }
            break;
        }
        /////////////////
        case CMD_DATA_SC:
        {
            // The SC VCI command contains two flits
            if ( p_vci_ini_d.cmdack.read() ) 
            {
               r_vci_cmd_cpt = r_vci_cmd_cpt + 1;
               if (r_vci_cmd_cpt == 1) r_vci_cmd_fsm = CMD_IDLE ;
            }
            break;
        }
        //////////////////
        case CMD_INS_MISS:
        case CMD_INS_UNC:
        case CMD_DATA_MISS:
        case CMD_DATA_UNC:
        {
            // all read VCI commands contain one single flit
            if ( p_vci_ini_d.cmdack.read() )  r_vci_cmd_fsm = CMD_IDLE; 
            break;
        }

    } // end  switch r_vci_cmd_fsm

    ///////////////////////////////////////////////////////////////////////////////
    // The VCI_RSP FSM controls the following ressources:
    // - r_vci_rsp_fsm:
    // - r_vci_rsp_fifo_icache (push)
    // - r_vci_rsp_fifo_dcache (push)
    // - r_vci_rsp_data_error (set)
    // - r_vci_rsp_ins_error (set)
    // - r_vci_rsp_cpt
    // 
    // As we support several simultaneous transactions, this FSM uses
    // the VCI TRDID field to identify the transactions.
    //
    // VCI vormat:
    // This component Rcheks the response packet length and accepts only
    // single word packets for write response packets. 
    //
    // Error handling:
    // This FSM analyzes the VCI error code and signals directly the Write Bus Error. 
    // In case of Read Data Error, the VCI_RSP FSM sets the r_vci_rsp_data_error 
    // flip_flop and the error is signaled by the DCACHE FSM.  
    // In case of Instruction Error, the VCI_RSP FSM sets the r_vci_rsp_ins_error 
    // flip_flop and the error is signaled by the DCACHE FSM.  
    // In case of Cleanup Error, the simulation stops with an error message...
    /////////////////////////////////////////////////////////////////////////////////

    switch ( r_vci_rsp_fsm.read() ) 
    {
        //////////////
        case RSP_IDLE:
        {
            if( p_vci_ini_d.rspval.read() )
            {
                r_vci_rsp_cpt = 0;

                if ( (p_vci_ini_d.rtrdid.read()>>(vci_param::T-1)) != 0 )
                {
                    r_vci_rsp_fsm = RSP_DATA_WRITE;
                }
                else if ( p_vci_ini_d.rtrdid.read() == TYPE_INS_MISS )
                {
                    r_vci_rsp_fsm = RSP_INS_MISS;
                }
                else if ( p_vci_ini_d.rtrdid.read() == TYPE_INS_UNC )
                {
                    r_vci_rsp_fsm = RSP_INS_UNC;
                }
                else if ( p_vci_ini_d.rtrdid.read() == TYPE_DATA_MISS )
                {
                    r_vci_rsp_fsm = RSP_DATA_MISS;
                }
                else if ( p_vci_ini_d.rtrdid.read() == TYPE_DATA_UNC )
                {
                    r_vci_rsp_fsm = RSP_DATA_UNC;
                }
                else
                {
                    assert(false and "Unexpected response");
                }
            }
            break;
        }
        //////////////////
        case RSP_INS_MISS:
        {        
            if ( p_vci_ini_d.rspval.read() )
            {
                if ( (p_vci_ini_d.rerror.read()&0x1) != 0 )  // error reported
                {
                    r_vci_rsp_ins_error = true;
                    if ( p_vci_ini_d.reop.read() ) r_vci_rsp_fsm = RSP_IDLE;
                }
                else                                        // no error reported
                {
                    if ( r_vci_rsp_fifo_icache.wok() )
                    {
                        assert( (r_vci_rsp_cpt.read() < m_cache_words) and
                        "The VCI response packet for instruction miss is too long" );

                        r_vci_rsp_cpt                 = r_vci_rsp_cpt.read() + 1;
                        vci_rsp_fifo_icache_put       = true,
                        vci_rsp_fifo_icache_data      = p_vci_ini_d.rdata.read();
                        if ( p_vci_ini_d.reop.read() ) 
                        {
                            assert( (r_vci_rsp_cpt.read() == m_cache_words - 1) and 
                            "The VCI response packet for instruction miss is too short");

                            r_vci_rsp_fsm    = RSP_IDLE;
                        }
                    }
                }
            }
            break;
        }
        /////////////////
        case RSP_INS_UNC:
        {
            if (p_vci_ini_d.rspval.read() )
            {
                assert( p_vci_ini_d.reop.read() and
                "illegal VCI response packet for uncacheable instruction");

                if ( (p_vci_ini_d.rerror.read()&0x1) != 0 )  // error reported
                {
                    r_vci_rsp_ins_error = true;
                    r_vci_rsp_fsm = RSP_IDLE;
                }
                else                                         // no error reported
                {   
                    if ( r_vci_rsp_fifo_icache.wok())
                    {
                        vci_rsp_fifo_icache_put       = true;
                        vci_rsp_fifo_icache_data      = p_vci_ini_d.rdata.read();
                        r_vci_rsp_fsm = RSP_IDLE;
                    }
                }
            }
            break;
        }
        ///////////////////
        case RSP_DATA_MISS:
        {
            if ( p_vci_ini_d.rspval.read() )
            {
                if ( (p_vci_ini_d.rerror.read()&0x1) != 0 )  // error reported
                {
                    r_vci_rsp_data_error = true;
                    if ( p_vci_ini_d.reop.read() ) r_vci_rsp_fsm = RSP_IDLE;
                }
                else                                        // no error reported
                {
                    if ( r_vci_rsp_fifo_dcache.wok() )
                    {
                        assert( (r_vci_rsp_cpt.read() < m_cache_words) and
                        "The VCI response packet for data miss is too long");

                        r_vci_rsp_cpt                 = r_vci_rsp_cpt.read() + 1;
                        vci_rsp_fifo_dcache_put       = true,
                        vci_rsp_fifo_dcache_data      = p_vci_ini_d.rdata.read();
                        if ( p_vci_ini_d.reop.read() ) 
                        {
                            assert( (r_vci_rsp_cpt.read() == m_cache_words - 1) and
                            "The VCI response packet for data miss is too short");

                            r_vci_rsp_fsm     = RSP_IDLE;
                        }
                    }
                }
            }
            break;
        }
        //////////////////
        case RSP_DATA_UNC:
        {
            if (p_vci_ini_d.rspval.read() )
            {
                assert( p_vci_ini_d.reop.read() and
                "illegal VCI response packet for uncacheable read data");

                if ( (p_vci_ini_d.rerror.read()&0x1) != 0 )  // error reported
                {
                    r_vci_rsp_data_error = true;
                    r_vci_rsp_fsm = RSP_IDLE;
                }
                else                                         // no error reported
                {   
                    if ( r_vci_rsp_fifo_dcache.wok())
                    {
                        vci_rsp_fifo_dcache_put       = true;
                        vci_rsp_fifo_dcache_data      = p_vci_ini_d.rdata.read();
                        r_vci_rsp_fsm = RSP_IDLE;
                    }
                }
            }
            break;
        }
        ////////////////////
        case RSP_DATA_WRITE:
        {
            if (p_vci_ini_d.rspval.read())
            {
                assert( p_vci_ini_d.reop.read() and
                "a VCI response packet must contain one flit for a write transaction");

                r_vci_rsp_fsm = RSP_IDLE;
                uint32_t wbuf_index = p_vci_ini_d.rtrdid.read() - (1<<(vci_param::T-1));
                bool     cacheable  = r_wbuf->completed(wbuf_index);
                if ( not cacheable ) r_dcache_pending_unc_write = false;
                if ( (p_vci_ini_d.rerror.read()&0x1) != 0 ) r_iss->setWriteBerr();
            }
            break;
        }
    } // end switch r_vci_rsp_fsm

    // FIFO_RSP update

    r_vci_rsp_fifo_icache.update(vci_rsp_fifo_icache_get, 
                                 vci_rsp_fifo_icache_put, 
                                 vci_rsp_fifo_icache_data);
      
    r_vci_rsp_fifo_dcache.update(vci_rsp_fifo_dcache_get, 
                                 vci_rsp_fifo_dcache_put, 
                                 vci_rsp_fifo_dcache_data);

} // end transition()

//////////////////////////
tmpl(void)::genMoore()
//////////////////////////
{
    ////////////////////////////////////////////////////////////////
    // VCI initiator command on the coherence network (cleanup)

    vci_addr_t  address;

    if ( r_cleanup_fsm.read() == CLEANUP_DATA_GO )
        address = (vci_addr_t)r_dcache_cleanup_line.read()<<m_cache_words_shift;
    else if ( r_cleanup_fsm.read() == CLEANUP_INS_GO )
        address = (vci_addr_t)r_icache_cleanup_line.read()<<m_cache_words_shift;
    else
        address = 0;

    p_vci_ini_c.cmdval  = ((r_cleanup_fsm.read() == CLEANUP_DATA_GO) or
                           (r_cleanup_fsm.read() == CLEANUP_INS_GO) );
    p_vci_ini_c.address = address;
    p_vci_ini_c.wdata   = 0;
    p_vci_ini_c.be      = 0xF;
    p_vci_ini_c.plen    = 4;
    p_vci_ini_c.cmd     = vci_param::CMD_WRITE;
    p_vci_ini_c.trdid   = r_cleanup_trdid.read();
    p_vci_ini_c.pktid   = 0;
    p_vci_ini_c.srcid   = m_srcid_c;
    p_vci_ini_c.cons    = false;
    p_vci_ini_c.wrap    = false;
    p_vci_ini_c.contig  = false;
    p_vci_ini_c.clen    = 0;
    p_vci_ini_c.cfixed  = false;
    p_vci_ini_c.eop     = true;

    /////////////////////////////////////////////////////////////////
    // VCI initiator response on the coherence network (cleanup)

    p_vci_ini_c.rspack  = true;

    //////////////////////////////////////////////
    // VCI initiator command on the direct network
    switch (r_vci_cmd_fsm.read() ) 
    {
        case CMD_IDLE:
        {
            p_vci_ini_d.cmdval  = false;
            p_vci_ini_d.address = 0;
            p_vci_ini_d.wdata   = 0;
            p_vci_ini_d.be      = 0;
            p_vci_ini_d.plen    = 0;
            p_vci_ini_d.cmd     = vci_param::CMD_NOP;
            p_vci_ini_d.trdid   = 0;
            p_vci_ini_d.pktid   = 0;
            p_vci_ini_d.srcid   = 0;
            p_vci_ini_d.cons    = false;
            p_vci_ini_d.wrap    = false;
            p_vci_ini_d.contig  = false;
            p_vci_ini_d.clen    = 0;
            p_vci_ini_d.cfixed  = false;
            p_vci_ini_d.eop     = false;
            break;
        }
        case CMD_DATA_UNC:
        {
            p_vci_ini_d.cmdval  = true;
            p_vci_ini_d.address = (vci_addr_t) r_dcache_addr_save.read() & ~0x3;
            p_vci_ini_d.wdata   = 0;
            p_vci_ini_d.be      = r_dcache_be_save.read();
            p_vci_ini_d.cmd     = vci_param::CMD_READ;
            p_vci_ini_d.plen    = 4;
            p_vci_ini_d.trdid   = TYPE_DATA_UNC; 
            p_vci_ini_d.pktid   = 0;
            p_vci_ini_d.srcid   = m_srcid_d;
            p_vci_ini_d.cons    = false;
            p_vci_ini_d.wrap    = false;
            p_vci_ini_d.contig  = true;
            p_vci_ini_d.clen    = 0;
            p_vci_ini_d.cfixed  = false;
            p_vci_ini_d.eop     = true;
            break;
        }
        case CMD_DATA_SC:
        {
            p_vci_ini_d.cmdval  = true;
            p_vci_ini_d.address = (vci_addr_t)r_dcache_addr_save.read() & ~0x3;
            if ( r_vci_cmd_cpt.read() == 0 ) p_vci_ini_d.wdata = r_dcache_ll_data.read();
            else                             p_vci_ini_d.wdata = r_dcache_wdata_save.read();
            p_vci_ini_d.be      = 0xF;
            p_vci_ini_d.cmd     = vci_param::CMD_STORE_COND;
            p_vci_ini_d.plen    = 8;
            p_vci_ini_d.trdid   = TYPE_DATA_UNC; 
            p_vci_ini_d.pktid   = 0;
            p_vci_ini_d.srcid   = m_srcid_d;
            p_vci_ini_d.cons    = true;
            p_vci_ini_d.wrap    = false;
            p_vci_ini_d.contig  = false;
            p_vci_ini_d.clen    = 0;
            p_vci_ini_d.cfixed  = false;
            p_vci_ini_d.eop     = (r_vci_cmd_cpt.read() == 1);
            break;
        }
        case CMD_DATA_WRITE:
        {
            p_vci_ini_d.cmdval  = true;
            p_vci_ini_d.address = (vci_addr_t)r_wbuf->getAddress(r_vci_cmd_cpt.read())&~0x3;
            p_vci_ini_d.wdata   = r_wbuf->getData(r_vci_cmd_cpt.read());
            p_vci_ini_d.be      = r_wbuf->getBe(r_vci_cmd_cpt.read());
            p_vci_ini_d.plen    = (r_vci_cmd_max - r_vci_cmd_min + 1)<<2;
            p_vci_ini_d.cmd     = vci_param::CMD_WRITE;
            p_vci_ini_d.trdid   = r_wbuf->getIndex() + (1<<(vci_param::T-1));
            p_vci_ini_d.pktid   = 0;
            p_vci_ini_d.srcid   = m_srcid_d;
            p_vci_ini_d.cons    = false;
            p_vci_ini_d.wrap    = false;
            p_vci_ini_d.contig  = true;
            p_vci_ini_d.clen    = 0;
            p_vci_ini_d.cfixed  = false;
            p_vci_ini_d.eop     = (r_vci_cmd_cpt.read() == r_vci_cmd_max.read());
            break;
        }
        case CMD_DATA_MISS:
        {
            p_vci_ini_d.cmdval  = true;
            p_vci_ini_d.address = (vci_addr_t)r_dcache_addr_save.read() & (vci_addr_t)m_cache_yzmask;
            p_vci_ini_d.be      = 0xF;
            p_vci_ini_d.plen    = m_cache_words << 2;
            p_vci_ini_d.cmd     = vci_param::CMD_READ;
            p_vci_ini_d.trdid   = TYPE_DATA_MISS; 
            p_vci_ini_d.pktid   = 0;
            p_vci_ini_d.srcid   = m_srcid_d;
            p_vci_ini_d.cons    = false;
            p_vci_ini_d.wrap    = false;
            p_vci_ini_d.contig  = true;
            p_vci_ini_d.clen    = 0;
            p_vci_ini_d.cfixed  = false;
            p_vci_ini_d.eop     = true;
            break;
        }
        case CMD_INS_MISS:
        {
            p_vci_ini_d.cmdval  = true;
            p_vci_ini_d.address = (vci_addr_t)r_icache_addr_save.read() & (vci_addr_t)m_cache_yzmask;
            p_vci_ini_d.be      = 0xF;
            p_vci_ini_d.plen    = m_cache_words << 2;
            p_vci_ini_d.cmd     = vci_param::CMD_READ;
            p_vci_ini_d.trdid   = TYPE_INS_MISS; 
            p_vci_ini_d.pktid   = 0;
            p_vci_ini_d.srcid   = m_srcid_d;
            p_vci_ini_d.cons    = false;
            p_vci_ini_d.wrap    = false;
            p_vci_ini_d.contig  = true;
            p_vci_ini_d.clen    = 0;
            p_vci_ini_d.cfixed  = false;
            p_vci_ini_d.eop     = true;
            break;
        }
        case CMD_INS_UNC:
        {
            p_vci_ini_d.cmdval  = true;
            p_vci_ini_d.address = (vci_addr_t)r_icache_addr_save.read() & ~0x3;
            p_vci_ini_d.be      = 0xF;
            p_vci_ini_d.plen    = 4;
            p_vci_ini_d.cmd     = vci_param::CMD_READ;
            p_vci_ini_d.trdid   = TYPE_INS_UNC;  
            p_vci_ini_d.pktid   = 0;
            p_vci_ini_d.srcid   = m_srcid_d;
            p_vci_ini_d.cons    = false;
            p_vci_ini_d.wrap    = false;
            p_vci_ini_d.contig  = true;
            p_vci_ini_d.clen    = 0;
            p_vci_ini_d.cfixed  = false;
            p_vci_ini_d.eop     = true;
            break;
        }
    } // end switch r_vci_cmd_fsm

    ///////////////////////////////////////////////
    // VCI initiator response on the direct network
    switch (r_vci_rsp_fsm.read() ) 
    {
        case RSP_DATA_WRITE : p_vci_ini_d.rspack = true; break;
        case RSP_INS_MISS   :
        case RSP_INS_UNC    : p_vci_ini_d.rspack = r_vci_rsp_fifo_icache.wok(); break;
        case RSP_DATA_MISS  :
        case RSP_DATA_UNC   :
        case RSP_DATA_SC    : p_vci_ini_d.rspack = r_vci_rsp_fifo_dcache.wok(); break;
        case RSP_IDLE       :
        default             : p_vci_ini_d.rspack = false; break;
    } // end switch r_vci_rsp_fsm

    ////////////////////////////////////////////////////////////
    // VCI target command and  response on the coherence network
    switch ( r_tgt_fsm.read() ) 
    {
        case TGT_IDLE:
        case TGT_UPDT_WORD:
        case TGT_UPDT_DATA:
        {
            p_vci_tgt_c.cmdack  = true;
            p_vci_tgt_c.rspval  = false;
            break;
        }
        case TGT_RSP_BROADCAST:
        {
            p_vci_tgt_c.cmdack  = false;
            p_vci_tgt_c.rspval  = (not r_tgt_icache_req.read() and not r_tgt_dcache_req.read()) 
                                  and (r_tgt_icache_rsp.read() or r_tgt_dcache_rsp.read());
            p_vci_tgt_c.rsrcid  = r_tgt_srcid.read();
            p_vci_tgt_c.rpktid  = r_tgt_pktid.read();
            p_vci_tgt_c.rtrdid  = r_tgt_trdid.read();
            p_vci_tgt_c.rdata   = 0;
            p_vci_tgt_c.rerror  = 0; 
            p_vci_tgt_c.reop    = true;
            break;
        }
        case TGT_RSP_ICACHE:
        {
            p_vci_tgt_c.cmdack  = false;
            p_vci_tgt_c.rspval  = not r_tgt_icache_req.read() and r_tgt_icache_rsp.read();
            p_vci_tgt_c.rsrcid  = r_tgt_srcid.read();
            p_vci_tgt_c.rpktid  = r_tgt_pktid.read();
            p_vci_tgt_c.rtrdid  = r_tgt_trdid.read();
            p_vci_tgt_c.rdata   = 0;
            p_vci_tgt_c.rerror  = 0; 
            p_vci_tgt_c.reop    = true;
            break;
        }
        case TGT_RSP_DCACHE:
        {
            p_vci_tgt_c.cmdack  = false;
            p_vci_tgt_c.rspval  = not r_tgt_dcache_req.read() and r_tgt_dcache_rsp.read();
            p_vci_tgt_c.rsrcid  = r_tgt_srcid.read();
            p_vci_tgt_c.rpktid  = r_tgt_pktid.read();
            p_vci_tgt_c.rtrdid  = r_tgt_trdid.read();
            p_vci_tgt_c.rdata   = 0;
            p_vci_tgt_c.rerror  = 0;
            p_vci_tgt_c.reop    = true;
            break;
        }
        case TGT_REQ_BROADCAST:
        case TGT_REQ_ICACHE:
        case TGT_REQ_DCACHE:
        {
            p_vci_tgt_c.cmdack  = false;
            p_vci_tgt_c.rspval  = false;
            break;
        }
    } // end switch TGT_FSM
} // end genMoore()
  

}} // end namespace

// Local Variables:
// tab-width: 4
// c-basic-offset: 4
// c-file-offsets:((innamespace . 0)(inline-open . 0))
// indent-tabs-mode: nil
// End:

// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=4:softtabstop=4
