/* i*- c++ -*-C
 * File : vci_io_bridge.cpp
 * Copyright (c) UPMC, Lip6, SoC
 *
 * 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
 */

#include <cassert>
#include "arithmetics.h"
#include "alloc_elems.h"
#include "../include/vci_io_bridge.h"

//////   debug services   ///////////////////////////////////////////////////////
// All debug messages are conditionned by two variables:
// - compile time : DEBUG_*** : defined below
// - execution time : m_debug_***  : defined by constructor arguments
//    m_debug_* = (m_debug_ok) and (m_cpt_cycle > m_debug_start_cycle)
/////////////////////////////////////////////////////////////////////////////////

#define DEBUG_DMA_CMD	    	1
#define DEBUG_DMA_RSP	    	1
#define DEBUG_DMA_TLB	    	1
#define DEBUG_CONFIG_CMD		1
#define DEBUG_CONFIG_RSP		1
#define DEBUG_MISS_INIT 		1

#define NEW_XRAM_VCI            0
    
#define IOMMU_ID		4097

namespace soclib { 
namespace caba {

namespace {

//DMA 
const char *dma_cmd_fsm_state_str[] = {
        "DMA_CMD_IDLE",
        "DMA_CMD_TRT_LOCK",
        "DMA_CMD_TRT_WAIT",
        "DMA_CMD_TRT_SET",
        "DMA_CMD_FIFO_PUT",
        "DMA_CMD_FIFO_MISS_PUT",
        "DMA_CMD_TLB_MISS_WAIT",
        "DMA_CMD_TLB_MISS_STORE",
        "DMA_CMD_ERROR",
    };

const char *dma_rsp_fsm_state_str[] = {
        "DMA_RSP_IDLE",
        "DMA_RSP_TRT_LOCK",
        "DMA_RSP_FIFO_PUT",
        "DMA_RSP_FIFO_ERROR_PUT",
 };

const char *alloc_trt_dma_fsm_state_str[] = {
        "ALLOC_TRT_DMA_CMD",
        "ALLOC_TRT_DMA_RSP",
    };

const char *dma_tlb_fsm_state_str[] = {
        "DMA_TLB_IDLE",
        "DMA_TLB_MISS",
        "DMA_TLB_PTE1_GET",
        "DMA_TLB_PTE1_SELECT",
        "DMA_TLB_PTE1_UPDT",
        "DMA_TLB_PTE2_GET",                                                  
        "DMA_TLB_PTE2_SELECT",
        "DMA_TLB_PTE2_UPDT",
        "DMA_TLB_WAIT_TRANSACTION",
        "DMA_TLB_RETURN",
        "DMA_TLB_INVAL_CHECK",
        "DMA_TLB_INVAL_SCAN",
    };

//CONFIG 
const char *config_cmd_fsm_state_str[] = {
        "CONFIG_CMD_IDLE",
        "CONFIG_CMD_TRT_LOCK",
        "CONFIG_CMD_TRT_WAIT",
        "CONFIG_CMD_TRT_SET",
        "CONFIG_CMD_FIFO_PUT",
         
        // IOB private configuration segment 
        "CONFIG_CMD_PTPR_WRITE",
        "CONFIG_CMD_PTPR_READ",
        "CONFIG_CMD_ACTIVE_WRITE",
        "CONFIG_CMD_ACTIVE_READ",
        "CONFIG_CMD_BVAR_READ",
        "CONFIG_CMD_ETR_READ",
        "CONFIG_CMD_BAD_ID_READ",
        "CONFIG_CMD_INVAL_REQ",
        "CONFIG_CMD_INVAL",
        "CONFIG_CMD_IT_ADDR_IOMMU_WRITE_1",
        "CONFIG_CMD_IT_ADDR_IOMMU_WRITE_2",
        "CONFIG_CMD_IT_ADDR_IOMMU_READ_1",
        "CONFIG_CMD_IT_ADDR_IOMMU_READ_2",
        "CONFIG_CMD_IT_ADDR_WRITE_1",
        "CONFIG_CMD_IT_ADDR_WRITE_2",
        "CONFIG_CMD_IT_ADDR_READ_1",
        "CONFIG_CMD_IT_ADDR_READ_2",
        "CONFIG_CMD_ERROR_WAIT",
        "CONFIG_CMD_ERROR_RSP",
    };

const char *config_rsp_fsm_state_str[] = {
        "CONFIG_RSP_IDLE",
        "CONFIG_RSP_TRT_LOCK",
        "CONFIG_RSP_FIFO_PUT", 
    };

const char *alloc_trt_config_fsm_state_str[] = {
        "ALLOC_TRT_CONFIG_CMD",
        "ALLOC_TRT_CONFIG_RSP",
    };

//MISS TRANSACTIONS (to Direct Network) 
const char *miss_init_fsm_state_str[] = {  
        "MISS_INIT_IDLE_MISS",
        "MISS_INIT_IDLE_IRQ",
        "MISS_INIT_IRQ_CMD",
        "MISS_INIT_IRQ_RSP",
        "MISS_INIT_TLB_MISS_CMD",
        "MISS_INIT_TLB_MISS_RSP",
    };
}

#define tmpl(...)  template<typename vci_param_d,typename vci_param_x, typename vci_param_io> __VA_ARGS__ VciIoBridge<vci_param_d,vci_param_x,vci_param_io>

/////////////////////////////////
tmpl(/**/)::VciIoBridge(
    sc_module_name 			            name,
    size_t                              nb_periph,
    const soclib::common::MappingTable 	&mtx,
    const soclib::common::MappingTable 	&mtd,
    const soclib::common::MappingTable 	&mtio,
    const soclib::common::Segment       &seg_config_iob,
    const soclib::common::IntTab 	    &tgt_index_iocluster,
//    const soclib::common::IntTab 	    &tgt_index_config,
    const soclib::common::IntTab 	    &init_index_direct,
    const soclib::common::IntTab 	    &tgt_index_iospace,
    const soclib::common::IntTab 	    &init_index_iospace,
    const soclib::common::IntTab 	    &init_index_dma,
    size_t                              dcache_words,
    size_t 				                iotlb_ways,
    size_t 				                iotlb_sets,
    uint32_t				            debug_start_cycle,
    bool				                debug_ok)
    : soclib::caba::BaseModule(name),

      p_clk("clk"),
      p_resetn("resetn"),
      p_irq_in(soclib::common::alloc_elems<sc_core::sc_in<bool> >("irq_in", nb_periph)),
      p_vci_ini_dma("vci_ini_dma"),
      p_vci_tgt_dma("vci_tgt_dma"),
      p_vci_ini_config("vci_ini_config"),
      p_vci_tgt_config("vci_tgt_config"),
      p_vci_ini_miss("vci_ini_miss"),

      m_words(dcache_words),
      m_nb_periph(nb_periph),
      
      // m_locality_table_config(mtd.getLocalityTable<unsigned long>(tgt_index_iocluster)),
      // These structures simulate what in hardware will be a correspondence table
      // Between segments' base address on the direct space and on the IO space
      // m_routing_table_config(mtd.getRoutingTable<unsigned long>(tgt_index_iocluster)), 
      //m_mtio(mtio),
      
      m_transaction_tab_dma(2),
      m_transaction_tab_config(1),
      //Direct Network
//      m_segment_config(mtd.getSegment(tgt_index_config)),
      m_segment_config(seg_config_iob),
      m_srcid_miss(mtx.indexForId(init_index_direct)), 
      //XRAM Network
      m_srcid_dma(mtx.indexForId(init_index_dma)),
      //IO Network
      m_segment_io(mtio.getSegment(tgt_index_iospace)),
      m_srcid_config(mtio.indexForId(init_index_iospace)),

      m_iotlb_ways(iotlb_ways),
      m_iotlb_sets(iotlb_sets),
      m_paddr_nbits(vci_param_d::N),

      m_debug_start_cycle(debug_start_cycle),
      m_debug_ok(debug_ok),

      r_iommu_ptpr("r_iommu_ptpr"),
      r_iommu_active("r_iommu_active"),
      r_iommu_bvar("r_iommu_bvar"),
      r_iommu_etr("r_iommu_etr"),
      r_iommu_bad_id("r_iommu_bad_id"),
      r_it_addr_iommu("r_it_addr_iommu"),

      // DMA_CMD 
      r_dma_cmd_fsm("r_dma_cmd_fsm"),
      r_dma_cmd_fsm_save("r_dma_cmd_fsm_save"),      
      r_miss_interrupt("r_miss_interrupt"),
      r_dma_cmd_count("r_dma_cmd_count"),
      r_dma_cmd_trt_index("r_dma_cmd_trt_index"),
      r_dma_paddr("r_dma_paddr"),
      // FIFOs
      m_dma_cmd_addr_fifo("m_dma_cmd_addr_fifo",4),
      //m_dma_cmd_length_fifo("m_dma_cmd_length_fifo",4),
      m_dma_cmd_srcid_fifo("m_dma_cmd_srcid_fifo",4), 
      m_dma_cmd_trdid_fifo("m_dma_cmd_trdid_fifo",4), 
      m_dma_cmd_pktid_fifo("m_dma_cmd_pktid_fifo",4), 
      m_dma_cmd_be_fifo("m_dma_cmd_be_fifo",4), 
      m_dma_cmd_cmd_fifo("m_dma_cmd_cmd_fifo",4), 
      m_dma_cmd_contig_fifo("m_dma_cmd_contig_fifo",4), 
      m_dma_cmd_data_fifo("m_dma_cmd_data_fifo",4), 
      m_dma_cmd_eop_fifo("m_dma_cmd_eop_fifo",4),
      m_dma_cmd_cons_fifo("m_dma_cmd_cons_fifo",4), 
      m_dma_cmd_plen_fifo("m_dma_cmd_plen_fifo",4), 
      m_dma_cmd_wrap_fifo("m_dma_cmd_wrap_fifo",4), 
      m_dma_cmd_cfixed_fifo("m_dma_cmd_cfixed_fifo",4),
      m_dma_cmd_clen_fifo("m_dma_cmd_clen_fifo",4), 

      r_miss_paddr       ("r_miss_paddr"), 
      r_miss_cmd         ("r_miss_cmd"), 
      r_miss_contig      ("r_miss_contig"),
      r_miss_cons        ("r_miss_cons"),
      r_miss_plen        ("r_miss_plen"),
      r_miss_wrap        ("r_miss_wrap"),
      r_miss_cfixed      ("r_miss_cfixed"),    
      r_miss_clen        ("r_miss_clen"),
      r_miss_srcid       ("r_miss_srcid"),
      r_miss_trdid       ("r_miss_trdid"),
      r_miss_pktid       ("r_miss_pktid"),

      r_dma_error_type("r_dma_error_type"),      
      r_dma_error_trdid("r_dma_error_trdid"), 
      r_dma_error_pktid("r_dma_error_pktid"), 

 
      r_dma_tlb_fsm("r_dma_tlb_fsm"),
      r_waiting_transaction("r_waiting_transaction"),
      r_tlb_miss_type("r_tlb_miss_type"),

                     
      r_iotlb_vaddr("r_iotlb_vaddr"),		 // virtual address for a tlb miss
      r_iotlb_paddr("r_iotlb_paddr"),		 // physical address of pte
      r_iotlb_pte_flags("r_iotlb_pte_flags"),// pte1 or first word of pte2
      r_iotlb_pte_ppn("r_iotlb_pte_ppn"),	 // second word of pte2
      r_iotlb_way("r_iotlb_way"),		     // selected way in tlb    
      r_iotlb_set("r_iotlb_set"),		     // selected set in tlb    

      r_iotlb("iotlb", IOMMU_ID, iotlb_ways,iotlb_sets,vci_param_d::N),
      
      //DMA_RSP
      r_dma_rsp_fsm("r_dma_rsp_fsm"),
      r_dma_rtrdid("r_dma_rtrdid"),
      r_dma_rsrcid("r_dma_rsrcid"),
      //Fifo's
      m_dma_rsp_data_fifo("m_dma_rsp_data_fifo",4),
      m_dma_rsp_rsrcid_fifo("m_dma_rsp_rsrcid_fifo",4),
      m_dma_rsp_rtrdid_fifo("m_dma_rsp_rtrdid_fifo",4),
      m_dma_rsp_rpktid_fifo("m_dma_rsp_rpktid_fifo",4),
      m_dma_rsp_reop_fifo("m_dma_rsp_reop_fifo",4),
      m_dma_rsp_rerror_fifo("m_dma_rsp_rerror_fifo",4),
      
      r_dma_cmd_rsp_erase_req("r_dma_cmd_rsp_erase_req"),
      r_dma_cmd_error_req("r_dma_cmd_error_req"),
      r_dma_tlb_req("r_dma_tlb_req"),
      r_tlb_dma_untreated("r_tlb_dma_untreated"), 
      r_dma_tlb_error_req("r_dma_tlb_error_req"),
      r_config_tlb_req("r_config_tlb_req"),
      r_config_tlb_inval_vaddr("r_config_tlb_inval_vaddr"), 
      
      // ALLOC TRT DMA
      r_alloc_trt_dma_fsm("r_alloc_trt_dma_fsm"),
      
      // CONFIG CMD
      r_config_cmd_fsm("r_config_cmd_fsm"),
      r_config_cmd_trt_index("r_config_cmd_trt_index"),
     
      m_config_cmd_addr_fifo("m_config_cmd_addr_fifo",4),
      //m_config_cmd_length_fifo("m_config_cmd_length_fifo",4),
      m_config_cmd_srcid_fifo("m_config_cmd_srcid_fifo",4),
      m_config_cmd_trdid_fifo("m_config_cmd_trdid_fifo",4),
      m_config_cmd_pktid_fifo("m_config_cmd_pktid_fifo",4),
      m_config_cmd_be_fifo("m_config_cmd_be_fifo",4),
      m_config_cmd_cmd_fifo("m_config_cmd_cmd_fifo",4),
      m_config_cmd_contig_fifo("m_config_cmd_contig_fifo",4),
      m_config_cmd_data_fifo("m_config_cmd_data_fifo",4),
      m_config_cmd_eop_fifo("m_config_cmd_eop_fifo",4),
      m_config_cmd_cons_fifo("m_config_cmd_cons_fifo",4),
      m_config_cmd_plen_fifo("m_config_cmd_plen_fifo",4),
      m_config_cmd_wrap_fifo("m_config_cmd_wrap_fifo",4),
      m_config_cmd_cfixed_fifo("m_config_cmd_cfixed_fifo",4),
      m_config_cmd_clen_fifo("m_config_cmd_clen_fifo",4),
      // Private configuration registers
      r_config_error_type("r_config_error_type"),
      r_config_first_word("r_config_first_word"),
      r_it_index("r_it_index"),
      //Fifo's
      m_config_local_data_fifo("m_config_local_data_fifo",4),     
      m_config_local_rsrcid_fifo("m_config_local_rsrcid_fifo",4),
      m_config_local_rtrdid_fifo("m_config_local_rtrdid_fifo",4),
      m_config_local_rpktid_fifo("m_config_local_rpktid_fifo",4),
      m_config_local_reop_fifo("m_config_local_reop_fifo",4),
      m_config_local_rerror_fifo("m_config_local_rerror_fifo",4),    
      r_config_vaddr("r_config_vaddr"),
    
      // CONFIG RSP  
      r_config_rsp_fsm("r_config_rsp_fsm"),
      r_config_rtrdid("r_config_rtrdid"),
      r_config_rsrcid("r_config_rsrcid"),
      //Fifo's
      m_config_rsp_data_fifo("m_config_rsp_data_fifo",4),     
      m_config_rsp_rsrcid_fifo("m_config_rsp_rsrcid_fifo",4),
      m_config_rsp_rtrdid_fifo("m_config_rsp_rtrdid_fifo",4),
      m_config_rsp_rpktid_fifo("m_config_rsp_rpktid_fifo",4),
      m_config_rsp_reop_fifo("m_config_rsp_reop_fifo",4),
      m_config_rsp_rerror_fifo("m_config_rsp_rerror_fifo",4),    

      // Communication between CONFIG CMD and CONFIG RSP
      r_config_cmd_rsp_erase_req("r_config_cmd_rsp_erase_req"),      
    
      // ALLOC TRT CONFIG 
      r_alloc_trt_config_fsm("r_alloc_trt_config_fsm"), 
      // MISS INIT
      r_miss_init_fsm("r_miss_init_fsm"), 
      r_miss_rdata("r_miss_rdata"),
      r_miss_rpktid("r_miss_rpktid"),
      r_miss_rtrdid("r_miss_rtrdid"),
      r_miss_rerror("r_miss_rerror"),
      r_miss_reop("r_miss_reop"),
      //r_miss_rsrcid("r_miss_rsrcid"),
      r_miss_rsp_cpt("r_miss_rsp_cpt"),
      //IRQ
      r_irq_pending("r_irq_pending"),
      r_irq_mask("r_irq_mask"),
      r_irq_chosen("r_irq_chosen"),
      
      r_tlb_miss_init_req("r_tlb_miss_init_req"),
      r_miss_init_error("r_miss_init_error"),
      
      r_miss_buf_valid("r_miss_buf_valid"),
      r_miss_buf_tag("r_miss_buf_tag")
{
    assert( (vci_param_d::N <=  64) and
            "ADDRESS cannot be bigger than 64 bits");
    assert( (vci_param_d::B ==  vci_param_io::B) and
            "DATA field must have the same size in Direct and IO Network");
    assert ( (vci_param_d::B)*8 == 32 
        and "Error: data field in Direct Noc must be 32 bits" );
                    
    
    // Interruption Address vector, one entry for each IO
    r_it_addr           = new paddr_t[nb_periph];
    // One cache line buffer
    r_miss_buf_data     = new vci_data_t[dcache_words];
    // Command storage in case of miss TLB
    // (dcache_words/2) => Maximal size of a write command 
    r_miss_data     = new vci_data_t[dcache_words]; 
    r_miss_be     = new vci_be_t[dcache_words];
    
    SC_METHOD(transition);
    dont_initialize();
    sensitive << p_clk.pos();
  
    SC_METHOD(genMoore);
    dont_initialize();
    sensitive << p_clk.neg();

 }

/////////////////////////////////////
tmpl(/**/)::~VciIoBridge()
/////////////////////////////////////
{
    delete [] r_it_addr;
    delete [] r_miss_buf_data;
    delete [] r_miss_data;
    delete [] r_miss_be;
    soclib::common::dealloc_elems(p_irq_in, m_nb_periph);
}

////////////////////////////////////
tmpl(void)::print_trace(size_t mode)
////////////////////////////////////
{
    // b0 : IOtlb trace

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

    std::cout << "  " << dma_cmd_fsm_state_str[r_dma_cmd_fsm.read()]
              << " | " << dma_rsp_fsm_state_str[r_dma_rsp_fsm.read()]
              << " | " << dma_tlb_fsm_state_str[r_dma_tlb_fsm.read()]
              << " | " << alloc_trt_dma_fsm_state_str[r_alloc_trt_dma_fsm.read()]
              << " | " << config_cmd_fsm_state_str[r_config_cmd_fsm.read()]
              << " | " << config_rsp_fsm_state_str[r_config_rsp_fsm.read()]
              << " | " << alloc_trt_config_fsm_state_str[r_alloc_trt_config_fsm.read()]
              << " | " << miss_init_fsm_state_str[r_miss_init_fsm.read()];
    std::cout << std::endl;

    if(mode & 0x01)
    {
        std::cout << "  IOTLB" << std::endl;
        r_iotlb.printTrace();
    }
    if(mode & 0x02)
    {
    	
    }
}



////////////////////////
tmpl(void)::print_stats()
////////////////////////
{
    std::cout << name() << std::endl
        << "- IOTLB MISS RATE      = " << (float)m_cpt_iotlb_miss/m_cpt_iotlb_read << std::endl
        << "- IOTLB MISS COST         = " << (float)m_cost_iotlb_miss/m_cpt_iotlb_miss << std::endl
        << "- IOTLB MISS TRANSACTION COST  = " << (float)m_cost_iotlbmiss_transaction/m_cpt_iotlbmiss_transaction << std::endl
        << "- IOTLB MISS TRANSACTION RATE (OVER ALL MISSES)  = " << (float)m_cpt_iotlbmiss_transaction/m_cpt_iotlb_miss << std::endl;
}

////////////////////////
tmpl(void)::clear_stats()
////////////////////////
{
    m_cpt_iotlb_read                = 0;             
    m_cpt_iotlb_miss                = 0;             
    m_cost_iotlb_miss               = 0;
    m_cpt_iotlbmiss_transaction     = 0;    
    m_cost_iotlbmiss_transaction    = 0;   
        
    m_cpt_trt_dma_full          = 0;
    m_cpt_trt_dma_full_cost     = 0;
    m_cpt_trt_config_full          = 0;
    m_cpt_trt_config_full_cost     = 0;
}

/////////////////////////
tmpl(void)::transition()
/////////////////////////
{
    if ( not p_resetn.read() ) 
    {

        r_dma_cmd_fsm		    = DMA_CMD_IDLE;
        r_dma_rsp_fsm		    = DMA_RSP_IDLE;
        r_alloc_trt_dma_fsm     = ALLOC_TRT_DMA_CMD;
        r_dma_tlb_fsm	        = DMA_TLB_IDLE;
        r_config_cmd_fsm	    = CONFIG_CMD_IDLE;
        r_config_rsp_fsm	    = CONFIG_RSP_IDLE;
        r_alloc_trt_config_fsm  = ALLOC_TRT_CONFIG_CMD;
        r_miss_init_fsm		    = MISS_INIT_IDLE_MISS;

        //miss buffer invalidation
        r_miss_buf_valid = false; 
        
		r_iommu_active = false;

        r_dma_cmd_count = 0;
        
        // initializing FIFOs
        m_dma_cmd_addr_fifo.init();
        m_dma_cmd_srcid_fifo.init();
        m_dma_cmd_trdid_fifo.init();
        m_dma_cmd_pktid_fifo.init();
        m_dma_cmd_be_fifo.init();
        m_dma_cmd_cmd_fifo.init();
        m_dma_cmd_contig_fifo.init();
        m_dma_cmd_data_fifo.init();
        m_dma_cmd_eop_fifo.init();
        m_dma_cmd_cons_fifo.init();
        m_dma_cmd_plen_fifo.init();
        m_dma_cmd_wrap_fifo.init();
        m_dma_cmd_cfixed_fifo.init();
        m_dma_cmd_clen_fifo.init();
        
        m_dma_rsp_rsrcid_fifo.init();
        m_dma_rsp_rtrdid_fifo.init();
        m_dma_rsp_rpktid_fifo.init();
        m_dma_rsp_data_fifo.init();
        m_dma_rsp_rerror_fifo.init();
        m_dma_rsp_reop_fifo.init();
        
        m_config_cmd_addr_fifo.init();
        m_config_cmd_srcid_fifo.init();
        m_config_cmd_trdid_fifo.init();
        m_config_cmd_pktid_fifo.init();
        m_config_cmd_be_fifo.init();
        m_config_cmd_cmd_fifo.init();
        m_config_cmd_contig_fifo.init();
        m_config_cmd_data_fifo.init();
        m_config_cmd_eop_fifo.init();
        m_config_cmd_cons_fifo.init();
        m_config_cmd_plen_fifo.init();
        m_config_cmd_wrap_fifo.init();
        m_config_cmd_cfixed_fifo.init();
        m_config_cmd_clen_fifo.init();
        
        m_config_rsp_rsrcid_fifo.init();
        m_config_rsp_rtrdid_fifo.init();
        m_config_rsp_rpktid_fifo.init();
        m_config_rsp_data_fifo.init();
        m_config_rsp_rerror_fifo.init();
        m_config_rsp_reop_fifo.init();
        
        m_config_local_rsrcid_fifo.init();
        m_config_local_rtrdid_fifo.init();
        m_config_local_rpktid_fifo.init();
        m_config_local_data_fifo.init();
        m_config_local_rerror_fifo.init();
        m_config_local_reop_fifo.init();

        //Communication between DMA_CMD and DMA_RSP
        r_dma_cmd_rsp_erase_req		=false;
        r_dma_cmd_error_req         =false;
        //Communication between DMA_CMD and TLB 
        r_dma_tlb_req		        =false;
        r_tlb_dma_untreated		    =false; 
        //Communication betweeen TLB and CONFIG_CMD
        r_config_tlb_req		    =false;
        r_config_tlb_inval_vaddr	=false;
	    r_dma_tlb_error_req         =false; 
        r_tlb_error_type            =false;   
        //Communication between CONFIG_CMD and CONFIG_RSP
        r_config_cmd_rsp_erase_req  =false;
        //Communication between TLB_MISS and MISS_INIT 
        r_tlb_miss_init_req         =false;
        r_miss_init_error           =false;
        // Debug variables
		m_debug_dma_rsp_fsm	        = false;
		m_debug_dma_cmd_fsm         = false;
        m_debug_dma_tlb_fsm         = false;
        m_debug_config_cmd_fsm      = false;
        m_debug_config_rsp_fsm      = false;
        m_debug_miss_init_fsm       = false;
        
        r_irq_mask              = 0xFFFFFFFF;
        r_irq_chosen            = 0;
          
	    // activity counters
	    m_cpt_total_cycles      = 0;
        m_cpt_iotlb_read       = 0;             
        m_cpt_iotlb_miss       = 0;             
        m_cpt_iotlbmiss_transaction      = 0;    
        m_cost_iotlbmiss_transaction      = 0;   
        
        m_cpt_trt_dma_full          = 0;
        m_cpt_trt_dma_full_cost     = 0;
        m_cpt_trt_config_full          = 0;
        m_cpt_trt_config_full_cost     = 0;

        for (uint32_t i=0; i<32 ; ++i) m_cpt_fsm_dma_cmd            [i]   = 0;
        for (uint32_t i=0; i<32 ; ++i) m_cpt_fsm_dma_rsp            [i]   = 0;
        for (uint32_t i=0; i<32 ; ++i) m_cpt_fsm_dma_tlb            [i]   = 0;
        for (uint32_t i=0; i<32 ; ++i) m_cpt_fsm_alloc_trt_dma      [i]   = 0;
        for (uint32_t i=0; i<32 ; ++i) m_cpt_fsm_config_cmd         [i]   = 0;
        for (uint32_t i=0; i<32 ; ++i) m_cpt_fsm_config_rsp         [i]   = 0;
        for (uint32_t i=0; i<32 ; ++i) m_cpt_fsm_alloc_trt_config   [i]   = 0;
        for (uint32_t i=0; i<32 ; ++i) m_cpt_fsm_miss_init          [i]   = 0;
        return;
    }

    
    //bool        miss_unposted      = false;
    bool        dma_cmd_fifo_put    = false;
    bool        dma_cmd_fifo_get    = false;
    bool        dma_rsp_fifo_put    = false; 
    bool        dma_rsp_fifo_get    = false; 
    
    bool        config_cmd_fifo_put = false;
    bool        config_cmd_fifo_get = false;
    bool        config_rsp_fifo_put = false;
    bool        config_rsp_fifo_get = false;
    bool        config_local_fifo_put = false;
    bool        config_local_fifo_get = false;

#ifdef INSTRUMENTATION
    m_cpt_fsm_dma_cmd	        [r_dma_cmd_fsm.read()] ++;
    m_cpt_fsm_dma_rsp	        [r_dma_rsp_fsm.read() ] ++;
    m_cpt_fsm_dma_tlb   	    [r_dma_tlb_fsm.read() ] ++;
    m_cpt_fsm_alloc_trt_dma  	[r_alloc_trt_dma_fsm.read() ] ++;
    m_cpt_fsm_config_cmd	    [r_config_cmd_fsm.read() ] ++;
    m_cpt_fsm_config_rsp	    [r_config_rsp_fsm.read() ] ++;
    m_cpt_fsm_alloc_trt_config  [r_alloc_trt_config_fsm.read() ] ++;
    m_cpt_fsm_miss_init	        [r_miss_init_fsm.read() ] ++;
#endif

    m_cpt_total_cycles++;

    m_debug_dma_cmd_fsm        = (m_cpt_total_cycles > m_debug_start_cycle) and m_debug_ok;
    m_debug_dma_rsp_fsm         = (m_cpt_total_cycles > m_debug_start_cycle) and m_debug_ok;
    m_debug_dma_tlb_fsm    = (m_cpt_total_cycles > m_debug_start_cycle) and m_debug_ok;
    m_debug_config_cmd_fsm      = (m_cpt_total_cycles > m_debug_start_cycle) and m_debug_ok;
    m_debug_config_rsp_fsm     = (m_cpt_total_cycles > m_debug_start_cycle) and m_debug_ok;
    m_debug_miss_init_fsm       = (m_cpt_total_cycles > m_debug_start_cycle) and m_debug_ok;

    /////////////////////////////////////////////////////////////////////
    // The DMA_CMD_FSM controls the following ressources:
    // - r_dma_cmd_fsm
    // - r_dma_srcid
    // - r_dma_tlb_req (set)
    // - r_tlb_dma_untreated (reset)
    // - r_dma_cmd_rsp_erase_req (set)
    ///////////////////////////////////////////////////////////////////////////////

    switch( r_dma_cmd_fsm.read() ) 
    {
    //////////////
    case DMA_CMD_IDLE:
    {
        // Treats an eventual request from TLB_MISS fsm 
        // to send a command whose miss treatment is now finished
        if ( r_tlb_dma_untreated.read() )
        {
            r_dma_cmd_fsm    = DMA_CMD_TRT_LOCK;//before posting we must update TRT
            r_dma_cmd_fsm_save = DMA_CMD_IDLE;
            r_miss_interrupt = true;
            break;
        }
        // Error during miss treatment
        else if (r_dma_tlb_error_req.read())
        {
            r_iommu_etr     = r_tlb_error_type.read(); 
            r_iommu_bvar    = r_iotlb_vaddr.read();
            r_iommu_bad_id  = r_miss_srcid.read();
            // For DMA_RSP FSM
            if(r_miss_cmd.read() == vci_param_io::CMD_WRITE) r_dma_error_type = WRITE_ERROR;
            else r_dma_error_type = READ_ERROR;
            r_dma_error_trdid   = r_miss_trdid.read(); 
            r_dma_error_pktid   = r_miss_pktid.read(); 
 
            r_dma_tlb_error_req = false; 
            r_dma_cmd_fsm   = DMA_CMD_ERROR;
        }

        if ( p_vci_tgt_dma.cmdval.read() )
        { 
            if ( not r_iommu_active.read()) 	// iotlb not activated 
            {
                // physical address
                r_dma_paddr = (paddr_t)p_vci_tgt_dma.address.read();
                r_dma_cmd_fsm	= DMA_CMD_TRT_LOCK;
            }
            else if (r_dma_tlb_fsm.read() == DMA_TLB_IDLE ||
                     r_dma_tlb_fsm.read() == DMA_TLB_WAIT_TRANSACTION )	  // iotlb activated
            {
                paddr_t	paddr;

                
                // We compute physical address and check access rights :
                // - If MMU not activated :the physical address is equal to the virtual 
                //address (identity mapping) and there is no access rights checking
                // - If MMU activated : cacheability is defined by the C bit in the PTE,
                //   the physical address is obtained from the TLB, and the access rights are
                //   defined by the W bit in the PTE.

                paddr_t		iotlb_paddr;
                pte_info_t  iotlb_flags; 
                size_t      iotlb_way;  
                size_t      iotlb_set;
                paddr_t     iotlb_nline;
                bool		iotlb_hit   = false;;  


#ifdef INSTRUMENTATION
m_cpt_iotlb_read++;
#endif

                iotlb_hit = r_iotlb.translate(p_vci_tgt_dma.address.read(),
                                            &iotlb_paddr,
                                            &iotlb_flags,
                                            &iotlb_nline,// unused
                                            &iotlb_way,	 // unused
                                            &iotlb_set );// unused
            
            
                if ( iotlb_hit )	// tlb hit
                { 
                    paddr       = iotlb_paddr;
					
                    // access rights checking 
                    if ( not iotlb_flags.w and 
                        (p_vci_tgt_dma.cmd.read() == vci_param_io::CMD_WRITE) ) 
                    {
                        r_iommu_etr     = MMU_WRITE_ACCES_VIOLATION;  
                        r_iommu_bvar    = p_vci_tgt_dma.address.read();
                        r_iommu_bad_id  = p_vci_tgt_dma.srcid.read();
                        r_dma_cmd_fsm   = DMA_CMD_ERROR;
                        // For DMA_RSP
                        r_dma_error_type    = WRITE_ERROR; 
                        r_dma_error_trdid   = p_vci_tgt_dma.trdid.read(); 
                        r_dma_error_pktid   = p_vci_tgt_dma.pktid.read(); 
#if DEBUG_DMA_CMD
if( m_debug_dma_cmd_fsm )
{
    std::cout << "  <IOB.DMA_CMD_IDLE> HIT in iotlb, but writable violation" << std::endl;
}
#endif
                    break;
                    }

                    // Physical address registration 
                    r_dma_paddr   = paddr;			
                    r_dma_cmd_fsm	= DMA_CMD_TRT_LOCK;
                }
                // TLB miss: we enter TLB_MISS treatment sub-fsm
                else 
                {

#ifdef INSTRUMENTATION
m_cpt_iotlb_miss++;
#endif
                    if( r_dma_tlb_req.read() || r_tlb_dma_untreated.read() || r_dma_tlb_error_req.read() )
                    {
                        // There's already a ongoing request
                        // or a completed request but not yet put on FIFO.
                        // We stay blocked
                        r_dma_cmd_fsm = DMA_CMD_TLB_MISS_WAIT;
#if DEBUG_DMA_CMD
if( m_debug_dma_cmd_fsm )
{
    std::cout << "  <IOB.DMA_CMD_IDLE> MISS in iotlb. There is a pending request." << std::endl;
}
#endif
                    }
                    else
                    {
                        // We register request virtual address, to be used by DMA_TLB_MISS FSM
		                r_iotlb_vaddr = p_vci_tgt_dma.address.read();
                        assert((r_dma_cmd_count.read() == 0)
                                and "ERROR: TRT counter should be 0");
                        r_dma_tlb_req   = true;
                        r_dma_cmd_fsm   = DMA_CMD_TLB_MISS_STORE;
#if DEBUG_DMA_CMD
if( m_debug_dma_cmd_fsm )
{
    std::cout << "  <IOB.DMA_CMD_IDLE> MISS in iotlb. No pending request." << std::endl;
}
#endif
                    }
                } // end !hit 
            } // end if tlb_activated
        } // end if cmdval
        break;
    }
    /////////////////////////
    case DMA_CMD_TRT_LOCK:	// Waiting for the lock to modify Transaction Table
    {
        if ( r_alloc_trt_dma_fsm.read() == ALLOC_TRT_DMA_CMD ) 
        {

#if DEBUG_DMA_CMD
if( m_debug_dma_cmd_fsm )
{
    std::cout << "  <IOB.DMA_CMD_TRT_LOCK> Check the TRT" << std::endl;
}
#endif
            size_t 		wok_index = 0;
            bool 		wok       = !m_transaction_tab_dma.full(wok_index);

            if ( wok ) 	// TRT isn't full. Write the new transaction. 
            {
                r_dma_cmd_trt_index = (vci_trdid_t)wok_index;
                r_dma_cmd_fsm       = DMA_CMD_TRT_SET;
            } 
            else 		// wait an empty entry in TRT
            {
                r_dma_cmd_rsp_erase_req = true;
                r_dma_cmd_fsm       = DMA_CMD_TRT_WAIT;
#if DEBUG_DMA_CMD
if( m_debug_dma_cmd_fsm )
{
    std::cout << "  <IOB.DMA_CMD_TRT_LOCK> TRT is full. Going to TRT_WAIT state" << std::endl;
}
#endif
            
#ifdef INSTRUMENTATION        
m_cpt_trt_dma_full++;
#endif
            }
        }
        break;
    }
    ////////////////
    case DMA_CMD_TRT_WAIT:	// release the lock protecting the transaction tab
                            // waits that RSP erases an entry 
    { 
#ifdef INSTRUMENTATION        
m_cpt_trt_dma_full_cost++;
#endif
        // DMA_RSP will notify an erase action by reseting this register
        if(!r_dma_cmd_rsp_erase_req.read())
        {
            r_dma_cmd_fsm = DMA_CMD_TRT_LOCK; // take the lock again
        }
        break;
    }
    ////////////////////////
    case DMA_CMD_TRT_SET:	// register a new transaction in TRT
    {  
        if ( r_alloc_trt_dma_fsm.read() == ALLOC_TRT_DMA_CMD ) 
        {
            if(r_miss_interrupt.read())
            {
                m_transaction_tab_dma.set(r_dma_cmd_trt_index.read(),
                                      r_miss_srcid.read(), 
                                      r_miss_trdid.read() );
                r_dma_cmd_fsm = DMA_CMD_FIFO_MISS_PUT;
            }
            else
            {
                m_transaction_tab_dma.set(r_dma_cmd_trt_index.read(),
                                          p_vci_tgt_dma.srcid.read(), 
                                          p_vci_tgt_dma.trdid.read() );
                r_dma_cmd_fsm = DMA_CMD_FIFO_PUT;
            }
#if DEBUG_DMA_CMD
if( m_debug_dma_cmd_fsm )
{
    std::cout << "  <IOB.DMA_CMD_TRT_SET> Set a new entry in TRT" << std::endl;
    if(r_miss_interrupt.read()) std::cout << " From the Network " << std::endl;
    else std::cout << " From miss interruption" << std::endl;
}
#endif
        }
        break;
    }  
    ///////////////////////
    case DMA_CMD_FIFO_PUT:	 
    {
        if ( p_vci_tgt_dma.cmdval && m_dma_cmd_addr_fifo.wok() ) 
        {
            dma_cmd_fifo_put = true;
            //miss_unposted = false;
            if(  p_vci_tgt_dma.contig )    r_dma_paddr = r_dma_paddr.read() + 4;
            if(  p_vci_tgt_dma.eop )    r_dma_cmd_fsm = DMA_CMD_IDLE;
           
#if DEBUG_DMA_CMD
if( m_debug_dma_cmd_fsm ) 
{
    std::cout << "  <IOB.DMA_CMD_FIFO_PUT> Push into cmd_fifo:" 
              << " address = " << std::hex << r_dma_paddr.read()
              << " srcid = " << std::dec << m_srcid_dma
              << " trdid = " << r_dma_cmd_trt_index.read()
              << " wdata = " << std::hex << p_vci_tgt_dma.wdata.read()
              << " be = " << p_vci_tgt_dma.be.read()
              << " contig = " << p_vci_tgt_dma.contig.read()
              << " eop = " << std::dec << p_vci_tgt_dma.eop.read() 
              << " plen = " << std::dec << p_vci_tgt_dma.plen.read() << std::endl;
}
#endif
        }
        break;
    }
    ///////////////////////
    case DMA_CMD_FIFO_MISS_PUT:	 
    {
        if ( m_dma_cmd_addr_fifo.wok() ) 
        {
            dma_cmd_fifo_put    = true;
            //miss_unposted       = true;
            if( r_miss_contig.read() )    r_miss_paddr = r_miss_paddr.read() + 4;
            
            if( r_dma_cmd_count.read() == 1 ) 
            {
                r_tlb_dma_untreated = false;
                r_miss_interrupt = false;
                r_dma_cmd_fsm = r_dma_cmd_fsm_save.read();
            }
            r_dma_cmd_count = r_dma_cmd_count.read() - 1;

#if DEBUG_DMA_CMD
if( m_debug_dma_cmd_fsm ) 
{
    std::cout << "  <IOB.DMA_CMD_FIFO_MISS_PUT> Push into cmd_fifo:" 
              << " counter = " << std::hex << r_dma_cmd_count.read()
              << " address = " << std::hex << r_miss_paddr.read()
              << " srcid = " << std::dec << r_miss_srcid.read()
              << " trdid = " << r_miss_trdid.read()
              << " wdata = " << std::hex << r_miss_data
              << " be = " << r_miss_be
              << " plen = " << std::dec << r_miss_plen.read() << std::endl;
}
#endif
        }
        break;
    }
    ///////////////////
    case DMA_CMD_TLB_MISS_WAIT: // to store the miss request there must be 
                                // neither an ongoing request, nor a unposted finished request
    {
        // Treats an eventual request from TLB_MISS fsm 
        // to send a command whose miss treatment is now finished
        if ( r_tlb_dma_untreated.read() )
        {
            r_dma_cmd_fsm    = DMA_CMD_TRT_LOCK; //before posting we must update TRT
            r_dma_cmd_fsm_save = DMA_CMD_TLB_MISS_WAIT;
            r_miss_interrupt = true;
            break;
        }
        // Error during miss treatment
        else if (r_dma_tlb_error_req.read())
        {
            r_iommu_etr     = r_tlb_error_type.read(); 
            r_iommu_bvar    = r_iotlb_vaddr.read();
            r_iommu_bad_id  = r_miss_srcid.read();
            // For DMA_RSP FSM
            if(r_miss_cmd.read() == vci_param_io::CMD_WRITE) r_dma_error_type = WRITE_ERROR;
            else r_dma_error_type = READ_ERROR;
            r_dma_error_trdid   = r_miss_trdid.read(); 
            r_dma_error_pktid   = r_miss_pktid.read(); 
 
            r_dma_tlb_error_req = false; 
            r_dma_cmd_fsm   = DMA_CMD_ERROR;
        }

#ifdef INSTRUMENTATION        
m_cost_iotlb_miss++;  // Now it represents misses' total blocking cost (not the treatment cost itself)
#endif
        else if (not r_dma_tlb_req.read())
        {
            r_dma_cmd_fsm   = DMA_CMD_TLB_MISS_STORE;
            assert((r_dma_cmd_count.read() == 0) and "ERROR: TRT counter should be 0");
        }
        break;
    }
    ///////////////////
    case DMA_CMD_TLB_MISS_STORE:
    {
        if ( p_vci_tgt_dma.cmdval.read()) 
        {
            if(r_dma_cmd_count.read() == 0)
            {
                r_miss_cmd = p_vci_tgt_dma.cmd.read();
                r_miss_contig = p_vci_tgt_dma.contig.read();
                r_miss_cons = p_vci_tgt_dma.cons.read();
                r_miss_plen = p_vci_tgt_dma.plen.read();
                r_miss_wrap = p_vci_tgt_dma.wrap.read();
                r_miss_cfixed = p_vci_tgt_dma.cfixed.read();
                r_miss_clen = p_vci_tgt_dma.clen.read();
                r_miss_srcid = p_vci_tgt_dma.srcid.read();
                r_miss_trdid = p_vci_tgt_dma.trdid.read();
                r_miss_pktid = p_vci_tgt_dma.pktid.read();
                
//                r_dma_tlb_req   = true;
            }
            
            r_miss_data[r_dma_cmd_count.read()] = p_vci_tgt_dma.wdata.read();
            r_miss_be[r_dma_cmd_count.read()] = p_vci_tgt_dma.be.read();
            
            r_dma_cmd_count = r_dma_cmd_count.read() + 1;
            
            if(  p_vci_tgt_dma.eop )  r_dma_cmd_fsm = DMA_CMD_IDLE;
           
#if DEBUG_DMA_CMD
if( m_debug_dma_cmd_fsm ) 
{
    std::cout << "  <IOB.DMA_CMD_TLB_MISS_STORE> Storing VCI fields of command that originate the Miss:" 
              << " counter = " << std::hex << r_dma_cmd_count.read()
              << " address = " << std::hex << p_vci_tgt_dma.address.read()
              << " srcid = " << std::dec << p_vci_tgt_dma.srcid.read()
              << " trdid = " << p_vci_tgt_dma.trdid.read()
              << " wdata = " << std::hex << p_vci_tgt_dma.wdata.read()
              << " be = " << p_vci_tgt_dma.be.read()
              << " plen = " << std::dec << p_vci_tgt_dma.plen.read() << std::endl;
}
#endif
        }
        break;
    }
    ///////////////////
    case DMA_CMD_ERROR:
    {
        // Wait in case of pending request
        // it isn't the case, generally
        if(!r_dma_cmd_error_req.read())
        { 
            r_dma_cmd_error_req = true; 
            r_dma_cmd_fsm       = DMA_CMD_IDLE;
        }
        break;
    }
    } // end switch DMA_CMD_FSM

    /////////////////////////////////////////////////////////////////////
    // The DMA_RSP_FSM controls the following ressources:
    // - r_dma_rsp_fsm
    // - r_dma_cmd_rsp_erase_req (reset) 
    // - r_fma_error_req (reset)
    // - 
    //////////////////////////////////////////////////////////////////////////////
    switch( r_dma_rsp_fsm.read() ) 
    {
    /////////////////////
    case DMA_RSP_IDLE:
    {    	
        // Interruption from DMA_CMD following an error
        if(r_dma_cmd_error_req.read()) r_dma_rsp_fsm = DMA_RSP_FIFO_ERROR_PUT;
        
        if(p_vci_ini_dma.rspval.read()) 
		{
			r_dma_rsp_fsm = DMA_RSP_TRT_LOCK;
		}
		break;
    }
    /////////////////////
    case DMA_RSP_TRT_LOCK:
    {    	
        if ( r_alloc_trt_dma_fsm.read() == ALLOC_TRT_DMA_RSP ) 
        {
            
#if DEBUG_DMA_RSP
if( m_debug_dma_rsp_fsm )
{
    std::cout << "  <IOB.DMA_RSP_TRT_LOCK> Erase entry" << std::endl;
}
#endif
            uint32_t trdid_xram = p_vci_ini_dma.rtrdid.read(); 
            
            r_dma_rsrcid = (vci_srcid_t)m_transaction_tab_dma.readSrcid(trdid_xram);
            r_dma_rtrdid = (vci_trdid_t)m_transaction_tab_dma.readTrdid(trdid_xram);
            m_transaction_tab_dma.erase(trdid_xram);
            if (r_dma_cmd_rsp_erase_req.read()) r_dma_cmd_rsp_erase_req = false;
            r_dma_rsp_fsm       = DMA_RSP_FIFO_PUT;
        }        
		break;
    }
    //////////////////
    case DMA_RSP_FIFO_PUT:
    {
        if(p_vci_ini_dma.rspval.read() && m_dma_rsp_data_fifo.wok())
    	{
            dma_rsp_fifo_put = true;
            if(p_vci_ini_dma.reop.read())   r_dma_rsp_fsm = DMA_RSP_IDLE;	

#if DEBUG_DMA_RSP
if( m_debug_dma_rsp_fsm ) 
{
    std::cout << "  <IOB.DMA_RSP_FIFO_PUT> Push into rsp_fifo:" 
              << " rsrcid = " << std::dec << r_dma_rsrcid.read()
              << " rtrdid = " << r_dma_rtrdid.read()
              << " rdata = " << std::hex << p_vci_ini_dma.rdata.read()
    << std::endl;
}
#endif
    			
    	}
    	break;
    }
    //////////////////
    case DMA_RSP_FIFO_ERROR_PUT:
    {
        if(m_dma_rsp_data_fifo.wok())
    	{
            dma_rsp_fifo_put = true;
            r_dma_rsp_fsm = DMA_RSP_IDLE;	

#if DEBUG_DMA_RSP
if( m_debug_dma_rsp_fsm ) 
{
    std::cout << "  <IOB.DMA_RSP_FIFO_ERROR_PUT> Push into rsp_fifo:" 
              << " rsrcid = " << std::dec << r_iommu_bad_id.read()
              << " rtrdid = " << r_dma_error_trdid.read()
              << " rerror = " << r_dma_error_type.read()
              << " rdata = " << std::hex << 0
    << std::endl;
}
#endif
    			
    	}
    	break;
    }
    } // end switch DMA_RSP_FSM 

    ////////////////////////////////////////////////////////////////////////////
    // The ALLOC_TRT_DMA fsm allocates the access to the Transaction Table (m_transaction_tab_dma)
    // with a round robin priority between 2 user FSMs :
    // - DMA_CMD : to set a new entry
    // - DMA_RSP : to read and erase an entry
    // The ressource is always allocated.
    ////////////////////////////////////////////////////////////////////////////
    
    switch ( r_alloc_trt_dma_fsm.read() ) 
    {
    ///////////////////
    case ALLOC_TRT_DMA_CMD:
    {
        if ( r_dma_cmd_fsm.read() != DMA_CMD_TRT_LOCK ) 
        {
          if (r_dma_rsp_fsm.read() == DMA_RSP_TRT_LOCK) r_alloc_trt_dma_fsm = ALLOC_TRT_DMA_RSP;
        }
        break;
    }
    ///////////////////
    case ALLOC_TRT_DMA_RSP:
    {
        if (r_dma_rsp_fsm.read() != DMA_RSP_TRT_LOCK) 
        {
            if (r_dma_cmd_fsm.read() == DMA_CMD_TRT_LOCK) r_alloc_trt_dma_fsm = ALLOC_TRT_DMA_CMD;
        }
        break;
    }
    } // end switch r_alloc_trt_dma_fsm
    

    ////////////////////////////////////////////////////////////////////////////
    // The DMA_TLB_MISS FSM handles an IOTLB miss. It blocks the TGT_FSM.
    // Input argument is:
    // - r_iotlb_vaddr
    // - r_dma_tlb_req (reset)
    // - r_tlb_miss_init_req (set)
    // - r_config_tlb_req (reset)
    // - r_tlb_dma_untreated (set)
    // 
    // This fsm searchs the requested PTE on the  prefetch buffer.
    // In case of miss,  it accesses the XRAM to find the missing TLB entry,
    // It bypass the first level page table access if possible.
    // It directly updates the iotlb, and writes into the 
    // r_mmu_ins_* or r_mmu_data* error reporting registers.
    ////////////////////////////////////////////////////////////////////////////////////
    switch (r_dma_tlb_fsm.read())
    {
    case DMA_TLB_IDLE:
    {
        if(r_config_tlb_req)
        {
            r_config_tlb_req = false;
            r_waiting_transaction = false;
            r_dma_tlb_fsm = DMA_TLB_INVAL_CHECK;
        // Request from CONFIG FSM following an PTE invalidation signal by OS
        }
        // Miss in IOTLB
        else if(r_dma_tlb_req.read())   
        {
        // Checking prefetch buffer, by the virtual address
        if(!r_miss_buf_first_level)
        {
            if( r_miss_buf_valid &&
                (r_miss_buf_vaddr_begin.read() == 
                (r_iotlb_vaddr.read()& ~PTE2_LINE_OFFSET & ~K_PAGE_OFFSET_MASK)))
            {
              // Hit
                size_t pte_offset = (r_iotlb_vaddr.read()& PTE2_LINE_OFFSET)>>12; 
              

                uint32_t pte_flags = r_miss_buf_data[2*pte_offset];
                uint32_t pte_ppn = r_miss_buf_data[2*pte_offset+1]; //because PTE2 is 2 words long
                
                // Bit valid checking
                if ( not ( pte_flags & PTE_V_MASK) )	// unmapped
                {
                    //must not occur!
                    std::cout << "IOMMU ERROR : " << name() << " DMA_TLB_IDLE state" << std::endl
                                  << "The Page Table entry ins't valid (unmapped)" << std::endl;
                       
                    r_tlb_error_type          = MMU_READ_PT2_UNMAPPED;
                    r_dma_tlb_error_req       = true;
                    r_dma_tlb_req             = false;
                        
#if DEBUG_DMA_TLB
if ( m_debug_dma_tlb_fsm )
{
    std::cout << "  <IOB.DMA_TLB_IDLE> PTE2 Unmapped"
              << std::hex << " / paddr = " << r_iotlb_paddr.read()
              << std::hex << " / PTE (first word) = " << pte_flags << std::endl;
}
#endif
                    break; 
                }

                r_iotlb_pte_flags       = pte_flags; 
                r_iotlb_pte_ppn         = pte_ppn;
                r_dma_tlb_fsm           = DMA_TLB_PTE2_SELECT;
                
#if DEBUG_DMA_TLB
if ( m_debug_dma_tlb_fsm )
{
    std::cout << "  <IOB.DMA_TLB_IDLE> Hit on the prefetch buffer for PTE2:"
              << " PTE_FLAGS = " << std::hex << pte_flags 
              << " PTE_PPN = " << std::hex << pte_ppn << std::endl;
}
#endif
                break;    
            }
        }
        else    // First level entries on buffer. Unused if only small pages
        {
           if( r_miss_buf_valid &&
              (r_miss_buf_vaddr_begin.read() == 
               (r_iotlb_vaddr.read()& ~PTE1_LINE_OFFSET & ~M_PAGE_OFFSET_MASK ))) 
            // The virtual address corresponds to one entry on the buffer line
            {
              // Hit
                size_t pte_offset = (r_iotlb_vaddr.read()& PTE1_LINE_OFFSET)>>21; 
              
                uint32_t pte_flags = r_miss_buf_data[pte_offset];
                            
                // Bit valid checking
                if ( not ( pte_flags & PTE_V_MASK) )	// unmapped
                {
                    //must not occur!
                    std::cout << "IOMMU ERROR " << name() << "DMA_TLB_IDLE state" << std::endl
                                  << "The Page Table entry ins't valid (unmapped)" << std::endl;
                       
                    r_tlb_error_type          = MMU_READ_PT1_UNMAPPED;
                    r_dma_tlb_error_req       = true;
                    r_dma_tlb_req             = false;
                        
#if DEBUG_DMA_TLB
if ( m_debug_dma_tlb_fsm )
{
    std::cout << "  <IOB.DMA_TLB_IDLE> First level entry Unmapped"
              << std::hex << " / paddr = " << r_iotlb_paddr.read()
              << std::hex << " / PTE = " << pte_flags << std::endl;
}
#endif
                    break; 
                }
                
                if( pte_flags & PTE_T_MASK ) 	//  PTD : me must access PT2
                {
                    // register bypass
                    r_iotlb.set_bypass( r_iotlb_vaddr.read(),
                                      pte_flags & ((1 << (m_paddr_nbits-PAGE_K_NBITS)) - 1), 
                                     0); //nline, unused 

                    //&PTE2 = PTBA + IX2 * 8
                    // ps: PAGE_K_NBITS corresponds also to the size of a second level page table
                    r_iotlb_paddr = (paddr_t)(pte_flags & ((1<<(m_paddr_nbits-PAGE_K_NBITS))-1)) << PAGE_K_NBITS |
                                  (paddr_t)(((r_iotlb_vaddr.read() & PTD_ID2_MASK) >> PAGE_K_NBITS) << 3);
                    r_tlb_miss_init_req     = true;
                    r_tlb_miss_type         = PTE2_MISS;
                    r_dma_tlb_fsm           = DMA_TLB_WAIT_TRANSACTION;
#ifdef INSTRUMENTATION
m_cpt_iotlbmiss_transaction++;
#endif

#if DEBUG_DMA_TLB
if ( m_debug_dma_tlb_fsm )
{
    std::cout << "  <IOB.DMA_TLB_IDLE> Hit on prefetch, but it is a PTD.Search PTE2"
              << std::hex << " / paddr = " << r_iotlb_paddr.read()
              << std::hex << " / PTD = " << pte_flags << std::endl;
}
#endif
                }
                else			//  PTE1 :  we must update the TLB
                            //  Should not occur if working only with small pages
                {
                    r_iotlb_pte_flags   = pte_flags;
                    r_dma_tlb_fsm  = DMA_TLB_PTE1_SELECT;

#if DEBUG_DMA_TLB
if ( m_debug_dma_tlb_fsm )
{
    std::cout << "  <IOB.DMA_TLB_PTE1_GET> Success. Big page"
              << std::hex << " / paddr = " << r_iotlb_paddr.read()
              << std::hex << " / PTE1 = " << pte_flags << std::endl;
}
#endif
                }
                break;
            }
        }
       
        r_dma_tlb_fsm = DMA_TLB_MISS; 

#if DEBUG_DMA_TLB
if ( m_debug_dma_tlb_fsm )
{
    std::cout << "  <IOB.DMA_TLB_IDLE> Miss on prefetch."
              << std::hex << " / vaddr = " << r_iotlb_vaddr.read() << std::endl;
}
#endif
        }
        break;
    }
    /////////////////////
    case DMA_TLB_MISS: // handling all tlb miss
    {
        uint32_t	ptba = 0; //28 bits en TSAR
        bool		bypass;
        paddr_t		pte_paddr;

        // evaluate bypass in order to skip first level page table access
        bypass = r_iotlb.get_bypass(r_iotlb_vaddr.read(), &ptba);
        
        //Request to MISS_INIT_FSM to start transaction on Direct Network       
        if ( not bypass )     // Read PTE1/PTD1 in XRAM
        {
        // VOIR CONVENTION >> 13
            pte_paddr = (paddr_t)((r_iommu_ptpr.read()) << (INDEX1_NBITS+2)) |
                        (paddr_t)((r_iotlb_vaddr.read() >> PAGE_M_NBITS) << 2);
            r_iotlb_paddr = pte_paddr;
            
            r_tlb_miss_init_req     = true;
            r_tlb_miss_type         = PTE1_MISS;
            r_dma_tlb_fsm           = DMA_TLB_WAIT_TRANSACTION;
#ifdef INSTRUMENTATION
m_cpt_iotlbmiss_transaction++;
#endif
        }
        else                  // Read PTE2 in XRAM
        {
            //&PTE2 = PTBA + IX2 * 8
            pte_paddr = (paddr_t)ptba << PAGE_K_NBITS |
                        (paddr_t)(r_iotlb_vaddr.read()&PTD_ID2_MASK)>>(PAGE_K_NBITS-3);
            
            r_iotlb_paddr = pte_paddr;
            
            r_tlb_miss_init_req     = true;
            r_tlb_miss_type         = PTE2_MISS;
            r_dma_tlb_fsm           = DMA_TLB_WAIT_TRANSACTION;
#ifdef INSTRUMENTATION
m_cpt_iotlbmiss_transaction++;
#endif
        }

#if DEBUG_DMA_TLB
if ( m_debug_dma_tlb_fsm )
{
    std::cout << "  <IOB.DMA_TLB_MISS> IOTLB miss";
    std::cout << " / VADDR = " << std::hex << r_iotlb_vaddr.read()
              << " / BYPASS = " << bypass 
              << " / PTE_ADR = " << pte_paddr << std::endl;
}
#endif
  
        break;
    }
    /////////////////////////  
    case DMA_TLB_PTE1_GET:	// Try to read a PT1 entry in the miss buffer
    {
        
        uint32_t  entry;
        
        paddr_t line_number  = (paddr_t)((r_iotlb_paddr.read())&(CACHE_LINE_MASK));
        size_t word_position = (size_t)( ((r_iotlb_paddr.read())&(~CACHE_LINE_MASK))>>2 );

        // Hit test. Just to verify. 
        // Hit must happen, since we've just finished its' miss transaction
        bool hit = (r_miss_buf_valid && (r_miss_buf_tag.read()== line_number) ); 
        assert(hit and "Error: No hit on prefetch buffer after Miss Transaction"); 
        
        entry = r_miss_buf_data[word_position];
            
        // Bit valid checking
        if ( not ( entry & PTE_V_MASK) )	// unmapped
        {
            //must not occur!
            std::cout << "IOMMU ERROR " << name() << "DMA_TLB_IDLE state" << std::endl
                      << "The Page Table entry ins't valid (unmapped)" << std::endl;
                       
            r_tlb_error_type          = MMU_READ_PT1_UNMAPPED;
            r_dma_tlb_error_req       = true;
            r_dma_tlb_req             = false;
            r_dma_tlb_fsm             = DMA_TLB_IDLE;            
#if DEBUG_DMA_TLB
if ( m_debug_dma_tlb_fsm )
{
    std::cout << "  <IOB.DMA_PTE1_GET> First level entry Unmapped"
              << std::hex << " / paddr = " << r_iotlb_paddr.read()
              << std::hex << " / PTE = " << entry << std::endl;
}
#endif
                    break; 
        }
    
        if( entry & PTE_T_MASK ) 	//  PTD : me must access PT2
        {
            // register bypass
            r_iotlb.set_bypass( r_iotlb_vaddr.read(),
                                entry & ((1 << (m_paddr_nbits-PAGE_K_NBITS)) - 1), 
                                0); //nline, unused 

            //&PTE2 = PTBA + IX2 * 8
            // ps: PAGE_K_NBITS corresponds also to the size of a second level page table
            r_iotlb_paddr = (paddr_t)(entry & ((1<<(m_paddr_nbits-PAGE_K_NBITS))-1)) << PAGE_K_NBITS |
                                (paddr_t)(((r_iotlb_vaddr.read() & PTD_ID2_MASK) >> PAGE_K_NBITS) << 3);
            r_tlb_miss_init_req     = true;
            r_tlb_miss_type         = PTE2_MISS;
            r_dma_tlb_fsm           = DMA_TLB_WAIT_TRANSACTION;
#ifdef INSTRUMENTATION
m_cpt_iotlbmiss_transaction++;
#endif

#if DEBUG_DMA_TLB
if ( m_debug_dma_tlb_fsm )
{
    std::cout << "  <IOB.DMA_TLB_PTE1_GET> Success. Search PTE2"
              << std::hex << " / paddr = " << r_iotlb_paddr.read()
              << std::hex << " / PTD = " << entry << std::endl;
}
#endif
        }
        else			//  PTE1 :  we must update the IOTLB
                        //  Should not occur if working only with small pages
        {
            r_iotlb_pte_flags   = entry;
            r_dma_tlb_fsm  = DMA_TLB_PTE1_SELECT;

#if DEBUG_DMA_TLB
if ( m_debug_dma_tlb_fsm )
{
    std::cout << "  <IOB.DMA_TLB_PTE1_GET> Success. Big page"
              << std::hex << " / paddr = " << r_iotlb_paddr.read()
              << std::hex << " / PTE1 = " << entry << std::endl;
}
#endif
        }
        
        break;
    }
    ////////////////////////////
    case DMA_TLB_PTE1_SELECT:	// select a slot for PTE1 
    {
        size_t 	way;
        size_t 	set;
        
        r_iotlb.select(  r_iotlb_vaddr.read(),
                        true,  // PTE1 
                        &way,
                        &set );
#ifdef INSTRUMENTATION
m_cpt_iotlb_read++;
#endif

#if DEBUG_DMA_TLB
if ( m_debug_dma_tlb_fsm )
{
    std::cout << "  <IOB.DMA_TLB_PTE1_SELECT> Select a slot in IOTLB:";
    std::cout << " way = " << std::dec << way
                  << " / set = " << set << std::endl;
}
#endif
        r_iotlb_way = way;
        r_iotlb_set = set;
        r_dma_tlb_fsm     = DMA_TLB_PTE1_UPDT;
        break;
    }
    //////////////////////////
    case DMA_TLB_PTE1_UPDT:     // write a new PTE1 in tlb
                                // not necessary to treat the L/R bit
    {
        //(OLD) paddr_t	  nline = r_dcache_tlb_paddr.read() >> (uint32_log2(m_dcache_words)+2);   
        uint32_t  pte   = r_iotlb_pte_flags.read();
        
        r_miss_paddr = (paddr_t)( ((r_iotlb_pte_flags.read() & PPN1_MASK) << 21)
                        | (r_iotlb_vaddr.read()& M_PAGE_OFFSET_MASK) );
        
        // update TLB
        r_iotlb.write( true,		// 2M page
                      pte,
                      0,		// argument unused for a PTE1
                      r_iotlb_vaddr.read(),    
                      r_iotlb_way.read(), 
                      r_iotlb_set.read(),
                      0 );      //we set nline = 0
#ifdef INSTRUMENTATION
m_cpt_iotlb_write++;
#endif

#if DEBUG_DMA_TLB
if ( m_debug_dma_tlb_fsm )
{
    std::cout   << "  <IOB.DMA_TLB_PTE1_UPDT> write PTE1 in IOTLB";
    std::cout   << " / set = " << std::dec << r_iotlb_set.read()
                << " / way = " << r_iotlb_way.read() << std::endl;
    r_iotlb.printTrace();
}
#endif
        // next state
        r_dma_tlb_fsm = DMA_TLB_RETURN;	// exit sub-fsm
        break;
    }
    /////////////////////////
    case DMA_TLB_PTE2_GET:	// Try to read a PTE2 (64 bits) in the miss buffer
    {    
        uint32_t 	pte_flags;
        uint32_t 	pte_ppn;
        
        paddr_t line_number  = (paddr_t)((r_iotlb_paddr.read())&(CACHE_LINE_MASK));
        size_t word_position = (size_t)( ((r_iotlb_paddr.read())&(~CACHE_LINE_MASK))>>2 );
        
        
        // Hit test. Just to verify.
        bool hit = (r_miss_buf_valid && (r_miss_buf_tag.read()== line_number) ); 
        assert(hit and "Error: No hit on prefetch buffer after Miss Transaction"); 
        pte_flags= r_miss_buf_data[word_position];
        pte_ppn= r_miss_buf_data[word_position+1]; //because PTE2 is 2 words long
        // Bit valid checking
        if ( not ( pte_flags & PTE_V_MASK) )	// unmapped
        {
            //must not occur!
            std::cout << "IOMMU ERROR " << name() << "DMA_TLB_IDLE state" << std::endl
                      << "The Page Table entry ins't valid (unmapped)" << std::endl;
                       
            r_tlb_error_type          = MMU_READ_PT2_UNMAPPED;
            r_dma_tlb_error_req       = true;
            r_dma_tlb_req             = false;
            r_dma_tlb_fsm             = DMA_TLB_IDLE;            
#if DEBUG_DMA_TLB
if ( m_debug_dma_tlb_fsm )
{
    std::cout << "  <IOB.DMA_TLB_PTE2_GET> PTE2 Unmapped"
              << std::hex << " / paddr = " << r_iotlb_paddr.read()
              << std::hex << " / PTE = " << pte_flags << std::endl;
}
#endif
                    break; 
        }
            
        r_iotlb_pte_flags       = pte_flags; 
        r_iotlb_pte_ppn         = pte_ppn;
        r_dma_tlb_fsm           = DMA_TLB_PTE2_SELECT;
                
#if DEBUG_DMA_TLB
if ( m_debug_dma_tlb_fsm )
{
    std::cout << "  <IOB.DMA_TLB_PTE2_GET> Mapped:"
              << " PTE_FLAGS = " << std::hex << pte_flags 
              << " PTE_PPN = " << std::hex << pte_ppn << std::endl;
}
#endif
        break;
    }
    ////////////////////////////
    case DMA_TLB_PTE2_SELECT:    // select a slot for PTE2
    {
        size_t way;
        size_t set;

        r_iotlb.select( r_iotlb_vaddr.read(),
                        false,	// PTE2 
                        &way,
                        &set );
#ifdef INSTRUMENTATION
m_cpt_iotlb_read++;
#endif

#if DEBUG_DMA_TLB
if ( m_debug_dma_tlb_fsm )
{
        std::cout << "  <IOB.DMA_TLB_PTE2_SELECT> Select a slot in IOTLB:";
        std::cout << " way = " << std::dec << way
                  << " / set = " << set << std::endl;
}
#endif
        r_iotlb_way = way;
        r_iotlb_set = set;
        r_dma_tlb_fsm     = DMA_TLB_PTE2_UPDT;
        break;
    }
    //////////////////////////
    case DMA_TLB_PTE2_UPDT:      	// write a new PTE2 in tlb
                                    // not necessary to treat the L/R bit
    {
        //(OLD) paddr_t	        nline     = r_dcache_tlb_paddr.read() >> (uint32_log2(m_dcache_words)+2);   
        uint32_t        pte_flags = r_iotlb_pte_flags.read();
        uint32_t        pte_ppn   = r_iotlb_pte_ppn.read();
        
        r_miss_paddr = (paddr_t)( ((r_iotlb_pte_ppn.read() & PPN2_MASK) << 12)
                        | (r_iotlb_vaddr.read()& K_PAGE_OFFSET_MASK) );
        
        // update TLB for a PTE2
        r_iotlb.write( false,	// 4K page
                       pte_flags,
                       pte_ppn,
                       r_iotlb_vaddr.read(),    
                       r_iotlb_way.read(), 
                       r_iotlb_set.read(),
                       0 );     // nline = 0
#ifdef INSTRUMENTATION
m_cpt_iotlb_write++;
#endif

#if DEBUG_DMA_TLB
if ( m_debug_dma_tlb_fsm )
{
        std::cout << "  <IOB.DMA_TLB_PTE2_UPDT> write PTE2 in IOTLB";
        std::cout << " / set = " << std::dec << r_iotlb_set.read()
                  << " / way = " << r_iotlb_way.read() << std::endl;
        r_iotlb.printTrace();
}
#endif
        // next state
        r_dma_tlb_fsm = DMA_TLB_RETURN;	// exit sub-fsm
        break;
    }
    ///////////////////////
    case DMA_TLB_WAIT_TRANSACTION:
    {
        // CONFIG FSM request following a invalidation signal sent by OS.
        if(r_config_tlb_req)
        {
            r_config_tlb_req = false;
            r_waiting_transaction = true;
            r_dma_tlb_fsm = DMA_TLB_INVAL_CHECK;
        }

#ifdef INSTRUMENTATION
m_cost_iotlbmiss_transaction++;
#endif
        if ( not r_tlb_miss_init_req )	//  Miss transaction is done 
        { 
	        if ( r_miss_init_error.read() ) // bus error 
	        {
                r_miss_init_error  = false;
                r_tlb_error_type    = MMU_READ_DATA_ILLEGAL_ACCESS;
                r_dma_tlb_error_req     = true;
                r_dma_tlb_req           = false;
                r_dma_tlb_fsm = DMA_TLB_IDLE;
            }
            else if(r_tlb_miss_type == PTE1_MISS)
            {
                r_dma_tlb_fsm = DMA_TLB_PTE1_GET; 
        
            }
            else
            {
                r_dma_tlb_fsm = DMA_TLB_PTE2_GET;
            }
        }
        break;
    }
    ///////////////////////
    case DMA_TLB_RETURN:		// return to caller depending on tlb miss type
    {
#if DEBUG_DMA_TLB
if ( m_debug_dma_tlb_fsm )
{
    std::cout << "  <IOB.DMA_TLB_RETURN> IOTLB MISS completed" << std::endl;
}
#endif
        r_dma_tlb_req = false;
        r_tlb_dma_untreated = true;
        r_dma_tlb_fsm = DMA_TLB_IDLE;
        break;
    }
    //////////////////////
    case DMA_TLB_INVAL_CHECK:   // request from CONFIG FSM to invalidate all PTE on a given line
                                // This state checks the necessity to invalidate prefetch buffer
    {
        // If a transaction is pending, no need to invalidate the prefetch
        // We can ignore it, since we'll replace the line.
        // The new line is necessarily up-to-date
        if(!r_waiting_transaction.read() && r_miss_buf_valid)
        {
            if(!r_miss_buf_first_level)
            {
               if( r_miss_buf_vaddr_begin.read() == 
                   (r_config_tlb_inval_vaddr.read()& ~PTE2_LINE_OFFSET) ) 
                // The virtual address corresponds to one entry on the buffer line
                {
                    r_miss_buf_valid = false;   //change here for individual invalidation
                }
            }
            else    // First level entries on buffer. Unused if only small pages
            {
               if( r_miss_buf_vaddr_begin.read() == 
                   (r_config_tlb_inval_vaddr.read()& ~PTE1_LINE_OFFSET) ) 
                // The virtual address corresponds to one entry on the buffer line
                {
                    r_miss_buf_valid = false;   //change here for individual invalidation
                }
            }
        }
        
        // Invalidation on IOTLB
        bool    ok;
        ok = r_iotlb.inval(r_config_tlb_inval_vaddr.read());
         
        if(r_waiting_transaction.read()) r_dma_tlb_fsm =DMA_TLB_WAIT_TRANSACTION; 
        else r_dma_tlb_fsm = DMA_TLB_IDLE;
        break; 
    }
    } //end switch r_dma_tlb_fsm
    
    
    /////////////////////////////////////////////////////////////////////
    // The CONFIG_CMD_FSM is similar to the DMA_CMD_FSM, but without miss TLB treatmentcontrols the following ressources:
    // - r_config_cmd_fsm
    //
    // - r_config_cmd_rsp_erase_req (set)
    // - r_config_tlb_req (set)
    /////////////////////////////////////////////////////////////////////

    switch( r_config_cmd_fsm.read() ) 
    {
    //////////////
    case CONFIG_CMD_IDLE:
    {
        if ( p_vci_tgt_config.cmdval.read() ) 
        {
#if DEBUG_CONFIG_CMD
if( m_debug_config_cmd_fsm )
{
    std::cout << "  <IOB.CONFIG_CMD_IDLE> Configuration command received!" <<std::endl;
    std::cout << " address = " << std::hex << p_vci_tgt_config.address.read()
              << " srcid = " << std::dec << p_vci_tgt_config.srcid.read()
              << " trdid = " << p_vci_tgt_config.trdid.read()
              << " wdata = " << std::hex << p_vci_tgt_config.wdata.read()
              << " be = " << p_vci_tgt_config.be.read()
              << " plen = " << std::dec << p_vci_tgt_config.plen.read() << std::endl;
}
#endif
            paddr_t config_paddr = p_vci_tgt_config.address.read();
   
//           // Just to verify 
//           if(! m_locality_table_config[config_paddr] ) //cannot receive remote packets
//           {
//           std::cout << "IOB ERROR " << name() << " CONFIG_CMD_IDLE state" << std::endl
//                         << "Received a remote packet" << std::endl;
//               exit(0);
//           }

            bool read = (p_vci_tgt_config.cmd.read() == vci_param_d::CMD_READ);
            
            uint32_t              cell    = (uint32_t)((config_paddr & 0x1FF)>>2); 
            
            // Treatement of received command
            // Verifies error, tests if the the command is for IOB itself 
 
            // To IOB itself
            if(m_segment_config.contains(config_paddr))
            {
                if(!read && (cell == IOB_IOMMU_PTPR)) 
                    r_config_cmd_fsm = CONFIG_CMD_PTPR_WRITE;
                else if(read && (cell == IOB_IOMMU_PTPR)) 
                    r_config_cmd_fsm = CONFIG_CMD_PTPR_READ;
                else if(!read && (cell == IOB_IOMMU_ACTIVE)) 
                    r_config_cmd_fsm = CONFIG_CMD_ACTIVE_WRITE;
                else if(read && (cell == IOB_IOMMU_ACTIVE)) 
                    r_config_cmd_fsm = CONFIG_CMD_ACTIVE_READ;
                else if(read && (cell == IOB_IOMMU_BVAR)) 
                    r_config_cmd_fsm = CONFIG_CMD_BVAR_READ;
                else if(read && (cell == IOB_IOMMU_ETR)) 
                    r_config_cmd_fsm = CONFIG_CMD_ETR_READ;
                else if(read && (cell == IOB_IOMMU_BAD_ID)) 
                    r_config_cmd_fsm = CONFIG_CMD_BAD_ID_READ;
                // PTE invalidation signaled by the OS
                else if(!read && (cell == IOB_INVAL_PTE))
                    r_config_cmd_fsm = CONFIG_CMD_INVAL_REQ;
                else if(!read && (cell == IOB_IT_ADDR_IOMMU_LO)) 
                    r_config_cmd_fsm = CONFIG_CMD_IT_ADDR_IOMMU_WRITE_1;
                else if(read && (cell == IOB_IT_ADDR_IOMMU_LO)) 
                    r_config_cmd_fsm = CONFIG_CMD_IT_ADDR_IOMMU_READ_1;
                else if( !read && ((cell >= IOB_IT_ADDR_BEGIN)&&
                        ( cell< (IOB_IT_ADDR_BEGIN +2*m_nb_periph-1) ) ) )
                {
                    // a factor two shows up because the registres come in couples
                    r_it_index = (cell - IOB_IT_ADDR_BEGIN)/2;
                    r_config_cmd_fsm = CONFIG_CMD_IT_ADDR_WRITE_1;
                } 
                else if( read && ((cell >= IOB_IT_ADDR_BEGIN)&&
                        (cell< (IOB_IT_ADDR_BEGIN +2*m_nb_periph-1))) ) 
                {
                    r_it_index = (cell - IOB_IT_ADDR_BEGIN)/2;
                    r_config_cmd_fsm = CONFIG_CMD_IT_ADDR_READ_1;
                }
                else
                //Error. Wrong address, or invalid operation.
                {
                    if(read)    r_config_error_type = READ_ERROR;
                    else        r_config_error_type = WRITE_ERROR;
                    r_config_cmd_fsm = CONFIG_CMD_ERROR_WAIT; 
                }
            }
            // Must route the command to the correct IO
            else
            {
                if(!p_vci_tgt_config.eop.read())
                {
                    //Error
                    if(read)    r_config_error_type = READ_ERROR;
                    else        r_config_error_type = WRITE_ERROR;
                    r_config_cmd_fsm = CONFIG_CMD_ERROR_WAIT; 
                }
                
                // Find the corresponding address on IO Space
//                int tgt_index = m_routing_table_config[config_paddr];
//#if DEBUG_CONFIG_CMD
//if( m_debug_config_cmd_fsm )
//{
//    std::cout << "  <IOB.CONFIG_CMD_IDLE> Routing a configuration packet" <<std::endl
//            << "Target Index on Direct NoC: " << tgt_index << std::endl;
//}
//#endif
//                soclib::common::Segment io_segment = m_mtio.getSegment(IntTab(tgt_index));
//               #define L2 soclib::common::uint32_log2 
//               paddr_t offset_mask = ( (1 << L2(io_segment.size())) - 1);
//               #undef L2
//               r_config_vaddr = (vaddr_t)( io_segment.baseAddress() | 
//                               (vaddr_t)(config_paddr & offset_mask) ); 
                
                // TODO So far, it is in identity mapping
                r_config_vaddr = (vaddr_t) config_paddr ; 
                r_config_cmd_fsm	= CONFIG_CMD_TRT_LOCK;

            }


        } // end if cmdval
        break;
    }
    /////////////////////////
    case CONFIG_CMD_TRT_LOCK: // Waiting for the lock to modify Transaction Table
    {
        if ( r_alloc_trt_config_fsm.read() == ALLOC_TRT_CONFIG_CMD ) 
        {

#if DEBUG_CONFIG_CMD
if( m_debug_config_cmd_fsm )
{
    std::cout << "  <IOB.CONFIG_CMD_TRT_LOCK> Check the TRT" << std::endl;
}
#endif
            size_t 		wok_index = 0;
            bool 		wok       = !m_transaction_tab_config.full(wok_index);

            if ( wok ) 	// TRT isn't full. Write the new transaction. 
            {
                r_config_cmd_trt_index = (vci_trdid_t)wok_index;
                r_config_cmd_fsm       = CONFIG_CMD_TRT_SET;
            } 
            else 		// wait an empty entry in TRT
            {
                r_config_cmd_fsm       = CONFIG_CMD_TRT_WAIT;
                r_config_cmd_rsp_erase_req = true;
#if DEBUG_CONFIG_CMD
if( m_debug_config_cmd_fsm )
{
    std::cout << "  <IOB.CONFIG_CMD_TRT_LOCK> TRT is full. Going to TRT_WAIT state" << std::endl;
}
#endif
            
#ifdef INSTRUMENTATION        
m_cpt_trt_config_full++;
#endif
            }
        }
        break;
    }
    ////////////////
    case CONFIG_CMD_TRT_WAIT:	// release the lock protecting the transaction tab
                                // waits that RSP erases an entry 
    { 
#ifdef INSTRUMENTATION        
m_cpt_trt_config_full_cost++;
#endif
        // CONFIG_RSP will notify an erase action by reseting this register
        if(!r_config_cmd_rsp_erase_req.read())
        {
            r_config_cmd_fsm = CONFIG_CMD_TRT_LOCK; // take the lock again
        }
        break;
    }
    ////////////////////////
    case CONFIG_CMD_TRT_SET:	// register a new transaction in TRT
    {  
        if ( r_alloc_trt_config_fsm.read() == ALLOC_TRT_CONFIG_CMD ) 
        {
            m_transaction_tab_config.set(   r_config_cmd_trt_index.read(),
                                            p_vci_tgt_config.srcid.read(), 
                                            p_vci_tgt_config.trdid.read() );
            
            r_config_cmd_fsm = CONFIG_CMD_FIFO_PUT;
#if DEBUG_CONFIG_CMD
if( m_debug_config_cmd_fsm )
{
    std::cout << "  <IOB.CONFIG_CMD_TRT_SET> Set a new entry in TRT" << std::endl;
}
#endif
        }
        break;
    }  
    ///////////////////////
    case CONFIG_CMD_FIFO_PUT:	 
    {
        if ( p_vci_tgt_config.cmdval && m_config_cmd_addr_fifo.wok() ) 
        {
            config_cmd_fifo_put = true;
            if(  p_vci_tgt_config.eop )    r_config_cmd_fsm = CONFIG_CMD_IDLE;
           
#if DEBUG_CONFIG_CMD
if( m_debug_config_cmd_fsm ) 
{
    std::cout << "  <IOB.CONFIG_CMD_FIFO_PUT> Push into config_cmd_fifo:" 
              << " address = " << std::hex << r_config_vaddr.read()
              << " srcid = " << std::dec << m_srcid_config
              << " trdid = " << r_config_cmd_trt_index.read()
              << " wdata = " << std::hex << p_vci_tgt_config.wdata.read()
              << " be = " << p_vci_tgt_config.be.read()
              << " plen = " << std::dec << p_vci_tgt_config.plen.read() << std::endl;
}
#endif
        }
        break;
    }
    
    ///////////////////////////////
    // Private Configuration States
    ///////////////////////////////

    //////////////////
    case CONFIG_CMD_PTPR_WRITE: // Convention- The word received is in the format:
                                // 00000 BASE_ADDRESS[39:13]
                                // Same pattern as in iommu_ptpr register
    {
        if ( p_vci_tgt_config.cmdval.read() && m_config_local_data_fifo.wok()
            && r_dma_tlb_fsm == DMA_TLB_IDLE )
        {
            // This verification could have been done on IDLE state
            // It would save us one cycle 
            if ( !p_vci_tgt_config.eop.read() )
            {
                std::cout << "CONFIG_CMD ERROR " << name() << " CONFIG_CMD_PTPR_WRITE state" << std::endl;
                std::cout << " PTPR write command must contain one single flit" << std::endl;
                r_config_error_type = WRITE_ERROR;
                r_config_cmd_fsm = CONFIG_CMD_ERROR_WAIT; 
                break;
            }
            
            // Depends on the convention
            r_iommu_ptpr = (uint32_t)(p_vci_tgt_config.wdata.read()); 
            
            config_local_fifo_put = true;
            r_config_cmd_fsm = CONFIG_CMD_IDLE;

#if DEBUG_CONFIG_CMD
if( m_debug_config_cmd_fsm ) 
{
    std::cout << "  <IOB.CONFIG_CMD_PTPR_WRITE> PTPR received:" 
              << "r_iommu_ptpr = " << std::hex << (p_vci_tgt_config.wdata.read())
              <<std::endl;
}
#endif
        } 
        break;
    }
    /////////////////////
    case CONFIG_CMD_ACTIVE_WRITE: 
    {
        if ( p_vci_tgt_config.cmdval.read() && m_config_local_data_fifo.wok() 
            && r_dma_tlb_fsm == DMA_TLB_IDLE )
        {
            // This verification could have been done on IDLE state
            // It would save us one cycle 
            if ( !p_vci_tgt_config.eop.read() )
            {
                std::cout << "CONFIG_CMD ERROR " << name() << " CONFIG_CMD_ACTIVE_WRITE state" << std::endl;
                std::cout << " ACTIVE write command must contain one single flit" << std::endl;
                r_config_error_type = WRITE_ERROR;
                r_config_cmd_fsm = CONFIG_CMD_ERROR_WAIT; 
                break;
            }
            
            r_iommu_active = (p_vci_tgt_config.wdata.read() != 0);
            
            config_local_fifo_put = true;
            r_config_cmd_fsm = CONFIG_CMD_IDLE;
        } 
        break;
    }
    ///////////////////
    case CONFIG_CMD_INVAL_REQ: // Blocks in case of untreated request
    {   
        if ( !r_config_tlb_req.read() )
        {
            r_config_tlb_req = true;     
            r_config_cmd_fsm = CONFIG_CMD_INVAL;
        } 
        break;
    }
    ///////////////////
    case CONFIG_CMD_INVAL: // Consuming the 32bit Virtual Address of the invalidated page
    {
        if ( p_vci_tgt_config.cmdval.read() && 
                m_config_local_data_fifo.wok() ) 
        {
            
            if ( !p_vci_tgt_config.eop.read() )
            {
                std::cout << "CONFIG_CMD ERROR " << name() << " CONFIG_CMD_INVAL state" << std::endl;
                std::cout << " PTE invalidation commands must contain one single flit" << std::endl;
                r_config_error_type = WRITE_ERROR;
                r_config_cmd_fsm = CONFIG_CMD_ERROR_WAIT; 
                break;
            }
            
            assert( (p_vci_tgt_config.wdata.read()& K_PAGE_OFFSET_MASK) == 0 
                    and " Error : Invalid format for Page Virtual Address. At least the 12 LSB bits must be zero");

            r_config_tlb_inval_vaddr = (vaddr_t)(p_vci_tgt_config.wdata.read());
             
            config_local_fifo_put = true;
            r_config_cmd_fsm = CONFIG_CMD_IDLE;
        } 
        break;
    }
    //////////////////
    case CONFIG_CMD_IT_ADDR_IOMMU_WRITE_1: 
    {
        if ( p_vci_tgt_config.cmdval.read() && m_config_local_data_fifo.wok())
        {
            if(vci_param_d::N <= 32)
            {
            // address holds in one single flit
                if (!p_vci_tgt_config.eop.read() )
                {
                    
                    std::cout << "CONFIG_CMD ERROR " << name() << " CONFIG_CMD_IT_ADDR_IOMMU_WRITE_1 state" << std::endl;
                    std::cout << " PTE invalidation command should contain just one flit" << std::endl;
                    r_config_error_type = WRITE_ERROR;
                    r_config_cmd_fsm = CONFIG_CMD_ERROR_WAIT;
                }
                else
                {
                    // If physical address holds on a single word
                    r_it_addr[r_it_index.read()] = (paddr_t)(p_vci_tgt_config.wdata.read()); 
                 
                    config_local_fifo_put = true; 
                    r_config_cmd_fsm = CONFIG_CMD_IDLE;
                }
        
            }
            else
            {
            // two flits are required to send address
                if ( p_vci_tgt_config.eop.read() )
                {
                    
                    std::cout << "CONFIG_CMD ERROR " << name() << " CONFIG_CMD_IT_ADDR_IOMMU_WRITE_1 state" << std::endl;
                    std::cout << " PTE invalidation commands should contain two flits" << std::endl;
                    r_config_error_type = WRITE_ERROR;
                    r_config_cmd_fsm = CONFIG_CMD_ERROR_RSP;
                }
                else
                {
                    r_config_first_word = p_vci_tgt_config.wdata.read(); 
                    r_config_cmd_fsm = CONFIG_CMD_IT_ADDR_IOMMU_WRITE_2;
                }
            }
        } 
        break;
    }
    /////////////////
    case CONFIG_CMD_IT_ADDR_IOMMU_WRITE_2: 
    {
        if ( p_vci_tgt_config.cmdval.read() && m_config_local_data_fifo.wok() )
        {
            if ( !p_vci_tgt_config.eop.read() )
            {
                std::cout << "CONFIG_CMD ERROR " << name() << " CONFIG_CMD_IT_IOMMU_WRITE_2 state" << std::endl;
                std::cout << " PTE invalidation commands must contain two flits" << std::endl;
                r_config_error_type = WRITE_ERROR;
                r_config_cmd_fsm = CONFIG_CMD_ERROR_WAIT; 
                break;
            }
            
            // Depends on the convention
            size_t mask_msb = (1 << (vci_param_d::N - 32)) - 1 ;
            r_it_addr_iommu = (paddr_t)(r_config_first_word.read() |
                                   ((p_vci_tgt_config.wdata.read()& mask_msb)<<32)); 
             
            config_local_fifo_put = true;
            r_config_cmd_fsm = CONFIG_CMD_IDLE;
        } 
    }
    //////////////////
    case CONFIG_CMD_IT_ADDR_WRITE_1: 
    {
        if ( p_vci_tgt_config.cmdval.read() && m_config_local_data_fifo.wok())
        {
            if(vci_param_d::N <= 32)
            {
            // address holds in one single flit
                if (!p_vci_tgt_config.eop.read() )
                {
                    
                    std::cout << "CONFIG_CMD ERROR " << name() << " CONFIG_CMD_IT_ADDR_WRITE_1 state" << std::endl;
                    std::cout << " PTE invalidation command should contain just one flit" << std::endl;
                    r_config_error_type = WRITE_ERROR;
                    r_config_cmd_fsm = CONFIG_CMD_ERROR_WAIT;
                    
                   
                }
                else
                {
                    // If physical address holds on a single word
                    r_it_addr[r_it_index.read()] = (paddr_t)(p_vci_tgt_config.wdata.read()); 
                 
                    config_local_fifo_put = true; 
                    r_config_cmd_fsm = CONFIG_CMD_IDLE;
                }
        
            }
            else
            {
            // two flits are required to send address
                if ( p_vci_tgt_config.eop.read() )
                {
                    
                    std::cout << "CONFIG_CMD ERROR " << name() << " CONFIG_CMD_IT_ADDR_WRITE_1 state" << std::endl;
                    std::cout << " PTE invalidation commands should contain two flits" << std::endl;
                    r_config_error_type = WRITE_ERROR;
                    r_config_cmd_fsm = CONFIG_CMD_ERROR_RSP;
                }
                else
                {
                    r_config_first_word = p_vci_tgt_config.wdata.read();
                    r_config_cmd_fsm = CONFIG_CMD_IT_ADDR_WRITE_2;
                }
            } 
        } 
        break;
    }
    /////////////////
    case CONFIG_CMD_IT_ADDR_WRITE_2: 
    {
        if ( p_vci_tgt_config.cmdval.read() && m_config_local_data_fifo.wok() )
        {
            if ( !p_vci_tgt_config.eop.read() )
            {
                std::cout << "CONFIG_CMD ERROR " << name() << " CONFIG_CMD_IT_ADDR_WRITE_2 state" << std::endl;
                std::cout << " PTE invalidation commands must contain two flits" << std::endl;
                r_config_error_type = WRITE_ERROR;
                r_config_cmd_fsm = CONFIG_CMD_ERROR_WAIT; 
                break;
            }
            
            // Depends on the convention
            size_t mask_msb = (1 << (vci_param_d::N - 32)) - 1 ;
            r_it_addr[r_it_index.read()] = (paddr_t)(r_config_first_word.read() |
                                ((p_vci_tgt_config.wdata.read()& mask_msb)<<32)); 
             
            config_local_fifo_put = true;
            r_config_cmd_fsm = CONFIG_CMD_IDLE;
        } 
    }
    //////////////////
    case CONFIG_CMD_PTPR_READ: 
    case CONFIG_CMD_ACTIVE_READ:
    case CONFIG_CMD_BVAR_READ:
    case CONFIG_CMD_ETR_READ:
    case CONFIG_CMD_BAD_ID_READ:
    case CONFIG_CMD_IT_ADDR_IOMMU_READ_1:
    case CONFIG_CMD_IT_ADDR_READ_1:
    {
        if ( p_vci_tgt_config.cmdval.read() && m_config_local_data_fifo.wok() )
        {
            // This verification could have been done on IDLE state
            // It would save us one cycle 
            if ( !p_vci_tgt_config.eop.read() )
            {
                std::cout << "CONFIG_CMD ERROR " << name() << config_cmd_fsm_state_str[r_config_cmd_fsm.read()] << std::endl;
                std::cout << " Read commands must contain one single flit" << std::endl;
                r_config_error_type = READ_ERROR;
                r_config_cmd_fsm = CONFIG_CMD_ERROR_WAIT; 
                break;
            }
            
            // fifo data receives the content of the corresponding register 
            // (depending on the current state) 
            config_local_fifo_put = true;
            if(r_config_cmd_fsm.read()== CONFIG_CMD_IT_ADDR_READ_1)
            r_config_cmd_fsm = CONFIG_CMD_IT_ADDR_READ_2;
            else if(r_config_cmd_fsm.read()== CONFIG_CMD_IT_ADDR_IOMMU_READ_1)
            r_config_cmd_fsm = CONFIG_CMD_IT_ADDR_IOMMU_READ_2;
            else
            r_config_cmd_fsm = CONFIG_CMD_IDLE;
        } 
        break;
    }
    //////////////////
    case CONFIG_CMD_IT_ADDR_READ_2:
    case CONFIG_CMD_IT_ADDR_IOMMU_READ_2:
    {
        if ( p_vci_tgt_config.cmdval.read() && m_config_local_data_fifo.wok() )
        {
            config_local_fifo_put = true;
            r_config_cmd_fsm = CONFIG_CMD_IDLE;
        } 
    }
    //////////////////
    case CONFIG_CMD_ERROR_WAIT: //receives the other flits of the same transaction
    {
        if ( p_vci_tgt_config.cmdval.read() && p_vci_tgt_config.eop.read() ) 
        r_config_cmd_fsm = CONFIG_CMD_ERROR_RSP; 
    }
    ///////////////////
    case CONFIG_CMD_ERROR_RSP:
    {
        if ( m_config_local_data_fifo.wok() )
        {
            config_local_fifo_put = true;
            r_config_cmd_fsm = CONFIG_CMD_IDLE;
        }
        break;
    }

    } // end switch CONFIG_CMD FSM

    /////////////////////////////////////////////////////////////////////
    // The CONFIG_RSP_FSM controls the following ressources:
    // - r_config_rsp_fsm
    // - r_config_cmd_rsp_erase_req (reset) 
    // - 
    // - 
    //////////////////////////////////////////////////////////////////////////////
    switch( r_config_rsp_fsm.read() ) 
    {
    /////////////////////
    case CONFIG_RSP_IDLE:
    {    	
        if(p_vci_ini_config.rspval.read()) 
		{
            r_config_rsp_fsm = CONFIG_RSP_TRT_LOCK;
		}
		break;
    }
    /////////////////////
    case CONFIG_RSP_TRT_LOCK:
    {    	
        if ( r_alloc_trt_config_fsm.read() == ALLOC_TRT_CONFIG_RSP ) 
        {
            
#if DEBUG_CONFIG_RSP
if( m_debug_config_rsp_fsm )
{
    std::cout << "  <IOB.CONFIG_RSP_TRT_LOCK> Read and erase entry" << std::endl;
}
#endif
            uint32_t trdid_iospace = p_vci_ini_config.rtrdid.read(); 
            
            r_config_rsrcid = (vci_srcid_t)m_transaction_tab_config.readSrcid(trdid_iospace);
            r_config_rtrdid = (vci_trdid_t)m_transaction_tab_config.readTrdid(trdid_iospace);
            m_transaction_tab_config.erase(trdid_iospace);
            if (r_config_cmd_rsp_erase_req.read()) r_config_cmd_rsp_erase_req = false;
            r_config_rsp_fsm       = CONFIG_RSP_FIFO_PUT;
        }        
		break;
    }
    //////////////////
    case CONFIG_RSP_FIFO_PUT:
    {
        if(p_vci_ini_config.rspval.read() && m_config_rsp_data_fifo.wok())
    	{
            config_rsp_fifo_put = true;
            if(p_vci_ini_config.reop.read())   r_config_rsp_fsm = CONFIG_RSP_IDLE;	

#if DEBUG_CONFIG_RSP
if( m_debug_config_rsp_fsm ) 
{
    std::cout << "  <IOB.CONFIG_RSP_FIFO_PUT> Push into rsp_fifo:" 
              << " rsrcid = " << std::dec << r_config_rsrcid.read()
              << " rtrdid = " << r_config_rtrdid.read()
              << " rdata = " << std::hex << p_vci_ini_config.rdata.read()
    << std::endl;
}
#endif
    			
    	}
    	break;
    }
    } // end switch CONFIG_RSP FSM


    ////////////////////////////////////////////////////////////////////////////
    // The ALLOC_TRT_CONFIG fsm allocates the access to the Transaction Table (m_transaction_tab_config)
    // with a round robin priority between 2 user FSMs :
    // - CONFIG_CMD : to set a new entry
    // - CONFIG_RSP : to read and erase an entry
    // The ressource is always allocated.
    ////////////////////////////////////////////////////////////////////////////////////
    
    switch ( r_alloc_trt_config_fsm.read() ) 
    {
    ///////////////////
    case ALLOC_TRT_CONFIG_CMD:
    {
        if ( r_config_cmd_fsm.read() != CONFIG_CMD_TRT_LOCK ) 
        {
          if (r_config_rsp_fsm.read() == CONFIG_RSP_TRT_LOCK) r_alloc_trt_config_fsm = ALLOC_TRT_CONFIG_RSP;
        }
    }
    ///////////////////
    case ALLOC_TRT_CONFIG_RSP:
    {
        if (r_config_rsp_fsm.read() != CONFIG_RSP_TRT_LOCK) 
        {
            if (r_config_cmd_fsm.read() == CONFIG_CMD_TRT_LOCK) r_alloc_trt_config_fsm = ALLOC_TRT_CONFIG_CMD;
        }
    }
    } // end switch r_alloc_trt_config_fsm

    ////////////////////////////////////////////////////////////////////////////
    // The MISS_INIT FSM sends a page table entry miss request into Direct Noc
    // It controls the following ressources:
    // - r_miss_init_fsm
    // - r_tlb_miss_init_req (reset)
    // - r_miss_buf_data
    // - r_miss_buf_valid
    // - r_miss_buf_tag
    ////////////////////////////////////////////////////////////////////////////////////

    // Building the interruption vector (systematically)
    uint32_t irq_demands = 0;
    for ( size_t i = 0; i<m_nb_periph; ++i )
        irq_demands |= (p_irq_in[i].read() ? 1 : 0) << i;
    
    // For next cycle:
        // Afectation of the new pending vector. 
        // Not useful, unless Irq choice is postponed to next cycle
    r_irq_pending = irq_demands & r_irq_mask.read();
        // Updating Mask
    r_irq_mask = r_irq_mask.read()| ~irq_demands;  
    
 
    switch ( r_miss_init_fsm.read() ) 
    {
        //////////////
        case MISS_INIT_IDLE_MISS:
        {
            if(r_tlb_miss_init_req.read())
            {
                r_miss_init_fsm = MISS_INIT_TLB_MISS_CMD;
            }
            else if (irq_demands & r_irq_mask.read()){
                // Choosing one interruption to send            
                // Find the first bit 1 
                // starting by the bit just after the last chosen
                size_t i = (r_irq_chosen.read() + 1)% m_nb_periph;
                bool found = false;
                do
                {
                    if(irq_demands & r_irq_mask.read() & (1<<i)) 
                    {
                        r_irq_chosen = i;
                        found = true;
                    }
                    i = (i+1) % m_nb_periph;
                }
                while(i != r_irq_chosen.read()+1 && !found); 

                r_miss_init_fsm = MISS_INIT_IRQ_CMD;
            }
			break;
        }
        //////////////
        case MISS_INIT_IDLE_IRQ:
        {
            if (irq_demands & r_irq_mask.read()){
                // Choosing one interruption to send            
                // Find the first bit 1 
                // starting by the bit just after the last chosen
                size_t i = (r_irq_chosen.read() + 1)% m_nb_periph;
                bool found = false;
                do
                {
                    if(irq_demands & r_irq_mask.read() & (1<<i)) 
                    {
                        r_irq_chosen = i;
                        found = true;
                    }
                    i = (i+1) % m_nb_periph;
                }
                while(i != r_irq_chosen.read()+1 && !found); 

                r_miss_init_fsm = MISS_INIT_IRQ_CMD;
            }
            else if(r_tlb_miss_init_req.read())
            {
                r_miss_init_fsm = MISS_INIT_TLB_MISS_CMD;
            }
			break;
        }
        /////////////////////////       // send a read request to Direct Network
        case MISS_INIT_IRQ_CMD: 
        {
        if ( p_vci_ini_miss.cmdack ) 
        {
            // Masking chosen interruption, until it is resolved 
            r_irq_mask = r_irq_mask.read() & ~(1<<r_irq_chosen.read());
            r_miss_init_fsm = MISS_INIT_IRQ_RSP;		

#if DEBUG_MISS_INIT
if( m_debug_miss_init_fsm )
{
    std::cout << "  <IOB.MISS_INIT_IRQ_CMD> Send write (irq) command to XICU"
              << " irq ID = " << std::dec << r_irq_chosen.read()
              << " new mask = " << std::hex << (r_irq_mask.read() & ~(1<<r_irq_chosen.read()))
     << std::endl;
}
#endif
        }
            break;
        }
        //////////////////
        case MISS_INIT_IRQ_RSP:	
        {
            if ( p_vci_ini_miss.rspval.read() ) 
            {
                // It is a WRITE command, response in one single flit long
                assert( p_vci_ini_miss.reop.read() and "Write answer should have one single flit" ); 
                bool error;
                
                if ( (p_vci_ini_miss.rerror.read()&0x1) != 0 )  // error reported
                {
                    // TODO traiter error
                    error = true;
                }
                r_miss_init_fsm = MISS_INIT_IDLE_MISS;
            }
            break;
        }
        /////////////////////////       // send a read request to Direct Network
        case MISS_INIT_TLB_MISS_CMD: 
        {
        if ( p_vci_ini_miss.cmdack ) 
        {
            r_miss_rsp_cpt  = 0;    //counter for the response flits
            r_miss_buf_tag  = ( (r_iotlb_paddr.read()) & CACHE_LINE_MASK ); 
            r_miss_buf_valid = true;
            
            if(r_tlb_miss_type.read()== PTE1_MISS)
                r_miss_buf_vaddr_begin =(r_iotlb_vaddr.read() & ~M_PAGE_OFFSET_MASK & ~PTE1_LINE_OFFSET);
            else
                r_miss_buf_vaddr_begin =(r_iotlb_vaddr.read() & ~K_PAGE_OFFSET_MASK & ~PTE2_LINE_OFFSET);
                
            r_miss_init_fsm = MISS_INIT_TLB_MISS_RSP;		

#if DEBUG_MISS_INIT
if( m_debug_miss_init_fsm )
{
    std::cout << "  <IOB.MISS_INIT_TLB_MISS_CMD> Send read (tlb entry) request to MEM CACHE: "
    << " | address :  "<< std::hex <<(paddr_t)((r_iotlb_paddr.read())& CACHE_LINE_MASK)
    << std::endl;
}
#endif
        }
            break;
        }
        //////////////////
        case MISS_INIT_TLB_MISS_RSP:	
        {
            if ( p_vci_ini_miss.rspval.read() ) 
            {
                if ( (p_vci_ini_miss.rerror.read()&0x1) != 0 )  // error reported
                {
                    r_miss_init_error = true;
                    if ( p_vci_ini_miss.reop.read() ) 
                    {    
                        r_miss_init_fsm = MISS_INIT_IDLE_IRQ;
                        r_tlb_miss_init_req = false; 
                    }
#if DEBUG_MISS_INIT
if( m_debug_miss_init_fsm ) 
{
    std::cout << " <IOB.MISS_INIT_TLB_MISS_RSP> ERROR " << std::endl; 
}
#endif
                }
                else
                { 
                    bool   eop  	= p_vci_ini_miss.reop.read();


#if DEBUG_MISS_INIT
if( m_debug_miss_init_fsm ) 
{
    std::cout << "  <IOB.MISS_INIT_TLB_MISS_RSP> Response from Mem Cache to a read (tlb entry) transaction. Count = " << r_miss_rsp_cpt.read()
    <<" | Data = " << std::hex << p_vci_ini_miss.rdata.read() << std::endl; 
}
#endif

                    assert(((eop == (r_miss_rsp_cpt.read() == (m_words-1))) ) 
                        and "Error : invalid length for a response from MEM CACHE");
                    r_miss_buf_data[r_miss_rsp_cpt] =  (uint32_t)p_vci_ini_miss.rdata.read();
                    
                    r_miss_rsp_cpt = r_miss_rsp_cpt.read() + 1;
                    
                    if ( eop ) 
                    {
                        r_tlb_miss_init_req = false;     //reset the request flip-flop
                        r_miss_init_fsm = MISS_INIT_IDLE_IRQ;		
                    }

                }
            }
            break;
        }

    } // end  switch r_miss_init_fsm
    
    //////////////////////////////////
    // Fifo consumption arbitration //
    //////////////////////////////////
    
    // Round Robin priority for CONFIG_RSP FIFO consumption
    r_config_rsp_fifo_local_priority = ! r_config_rsp_fifo_local_priority.read(); 
    
    //DMA CMD
    dma_cmd_fifo_get = (p_vci_ini_dma.cmdack.read() && m_dma_cmd_addr_fifo.rok());
    // DMA RSP
    dma_rsp_fifo_get = (p_vci_tgt_dma.rspack.read() && m_dma_rsp_data_fifo.rok());
    // CONFIG CMD
    config_cmd_fifo_get = (p_vci_ini_config.cmdack.read() && m_config_cmd_addr_fifo.rok() );
    // CONFIG RSP, detemines wich fifo to consume 
    if(r_config_rsp_fifo_local_priority)
    {
        if(m_config_local_data_fifo.rok()) config_local_fifo_get = p_vci_tgt_config.rspack.read();
        else if (m_config_rsp_data_fifo.rok()) config_rsp_fifo_get = p_vci_tgt_config.rspack.read();
            
    }
    else
    {
        if (m_config_rsp_data_fifo.rok()) config_rsp_fifo_get = p_vci_tgt_config.rspack.read();
        else if(m_config_local_data_fifo.rok()) config_local_fifo_get = p_vci_tgt_config.rspack.read();
    }
    ///////////////
    //DMA_CMD Fifo
    ///////////////
    if(r_miss_interrupt)
    {
        m_dma_cmd_addr_fifo.update( dma_cmd_fifo_get,
                                    dma_cmd_fifo_put,
                                    r_miss_paddr.read() );
        m_dma_cmd_cmd_fifo.update( dma_cmd_fifo_get,
                                    dma_cmd_fifo_put,
                                    r_miss_cmd.read() );
        m_dma_cmd_contig_fifo.update( dma_cmd_fifo_get,
                                    dma_cmd_fifo_put,
                                    r_miss_contig.read() );
        m_dma_cmd_cons_fifo.update( dma_cmd_fifo_get,
                                    dma_cmd_fifo_put,
                                    r_miss_cons.read() );
        m_dma_cmd_plen_fifo.update( dma_cmd_fifo_get,
                                    dma_cmd_fifo_put,
                                    r_miss_plen.read() );
        m_dma_cmd_wrap_fifo.update( dma_cmd_fifo_get,
                                    dma_cmd_fifo_put,
                                    r_miss_wrap.read() );
        m_dma_cmd_cfixed_fifo.update( dma_cmd_fifo_get,
                                    dma_cmd_fifo_put,
                                    r_miss_cfixed.read() );
        m_dma_cmd_clen_fifo.update( dma_cmd_fifo_get,
                                    dma_cmd_fifo_put,
                                    r_miss_clen.read() );
        m_dma_cmd_srcid_fifo.update( dma_cmd_fifo_get,
                                    dma_cmd_fifo_put,
                                    m_srcid_dma ); //r_miss_srcid.read()
        m_dma_cmd_trdid_fifo.update( dma_cmd_fifo_get,
                                    dma_cmd_fifo_put,
                                    r_miss_trdid.read() );
        m_dma_cmd_pktid_fifo.update( dma_cmd_fifo_get,
                                    dma_cmd_fifo_put,
                                    r_miss_pktid.read() );
        m_dma_cmd_data_fifo.update( dma_cmd_fifo_get,
                                    dma_cmd_fifo_put,
                                    r_miss_data[r_dma_cmd_count.read()-1] );
        m_dma_cmd_be_fifo.update( dma_cmd_fifo_get,
                                    dma_cmd_fifo_put,
                                    r_miss_be[r_dma_cmd_count.read()-1] );
        m_dma_cmd_eop_fifo.update( dma_cmd_fifo_get,
                                    dma_cmd_fifo_put,
                                    (r_dma_cmd_count.read() == 1) );
    }
    else 
    {
        m_dma_cmd_addr_fifo.update( dma_cmd_fifo_get,
                                    dma_cmd_fifo_put,
                                    r_dma_paddr.read() ); 
        m_dma_cmd_cmd_fifo.update( dma_cmd_fifo_get,
                                    dma_cmd_fifo_put,
                                    p_vci_tgt_dma.cmd.read() );
        m_dma_cmd_contig_fifo.update( dma_cmd_fifo_get,
                                    dma_cmd_fifo_put,
                                    p_vci_tgt_dma.contig.read() );
        m_dma_cmd_cons_fifo.update( dma_cmd_fifo_get,
                                    dma_cmd_fifo_put,
                                    p_vci_tgt_dma.cons.read() );
        m_dma_cmd_plen_fifo.update( dma_cmd_fifo_get,
                                    dma_cmd_fifo_put,
                                    p_vci_tgt_dma.plen.read() );
        m_dma_cmd_wrap_fifo.update( dma_cmd_fifo_get,
                                    dma_cmd_fifo_put,
                                    p_vci_tgt_dma.wrap.read() );
        m_dma_cmd_cfixed_fifo.update( dma_cmd_fifo_get,
                                    dma_cmd_fifo_put,
                                    p_vci_tgt_dma.cfixed.read() );
        m_dma_cmd_clen_fifo.update( dma_cmd_fifo_get,
                                    dma_cmd_fifo_put,
                                    p_vci_tgt_dma.clen.read() );
        m_dma_cmd_srcid_fifo.update( dma_cmd_fifo_get,
                                    dma_cmd_fifo_put,
                                    m_srcid_dma );
        m_dma_cmd_trdid_fifo.update( dma_cmd_fifo_get,
                                    dma_cmd_fifo_put,
                                    r_dma_cmd_trt_index.read() );
        m_dma_cmd_pktid_fifo.update( dma_cmd_fifo_get,
                                    dma_cmd_fifo_put,
                                    p_vci_tgt_dma.pktid.read() );
        m_dma_cmd_data_fifo.update( dma_cmd_fifo_get,
                                    dma_cmd_fifo_put,
                                    p_vci_tgt_dma.wdata.read() ); // TODO change
                                                            // For 64bits XRAM
        m_dma_cmd_be_fifo.update( dma_cmd_fifo_get,
                                    dma_cmd_fifo_put,
                                    p_vci_tgt_dma.be.read() ); 
        m_dma_cmd_eop_fifo.update( dma_cmd_fifo_get,
                                    dma_cmd_fifo_put,
                                     p_vci_tgt_dma.eop.read() );
    }

    ///////////////
    //DMA_RSP Fifo
    ///////////////
    if(r_dma_rsp_fsm.read() == DMA_RSP_FIFO_ERROR_PUT)
    {
        m_dma_rsp_data_fifo.update( dma_rsp_fifo_get,
                                    dma_rsp_fifo_put,
                                    0 );
        m_dma_rsp_rsrcid_fifo.update( dma_rsp_fifo_get,
                                    dma_rsp_fifo_put,
                                    r_iommu_bad_id.read() ); 
        m_dma_rsp_rtrdid_fifo.update( dma_rsp_fifo_get,
                                    dma_rsp_fifo_put,
                                    r_dma_error_trdid.read() ); 
        m_dma_rsp_rpktid_fifo.update( dma_rsp_fifo_get,
                                    dma_rsp_fifo_put,
                                    r_dma_error_pktid.read() );
        m_dma_rsp_reop_fifo.update( dma_rsp_fifo_get,
                                   dma_rsp_fifo_put,
                                   true );
        m_dma_rsp_rerror_fifo.update( dma_rsp_fifo_get,
                                      dma_rsp_fifo_put,
                                      r_dma_error_type.read() );
    }
    else
    {
        m_dma_rsp_data_fifo.update( dma_rsp_fifo_get,
                                    dma_rsp_fifo_put,
                                    p_vci_ini_dma.rdata.read() );
        m_dma_rsp_rsrcid_fifo.update( dma_rsp_fifo_get,
                                    dma_rsp_fifo_put,
                                    r_dma_rsrcid.read() ); 
        m_dma_rsp_rtrdid_fifo.update( dma_rsp_fifo_get,
                                    dma_rsp_fifo_put,
                                    r_dma_rtrdid.read() ); 
        m_dma_rsp_rpktid_fifo.update( dma_rsp_fifo_get,
                                    dma_rsp_fifo_put,
                                    p_vci_ini_dma.rpktid.read() );
        m_dma_rsp_reop_fifo.update( dma_rsp_fifo_get,
                                   dma_rsp_fifo_put,
                                   p_vci_ini_dma.reop.read() );
        m_dma_rsp_rerror_fifo.update( dma_rsp_fifo_get,
                                      dma_rsp_fifo_put,
                                      p_vci_ini_dma.rerror.read() );
    }

    //////////////////
    //CONFIG_CMD Fifo
    //////////////////
    m_config_cmd_addr_fifo.update( config_cmd_fifo_get,
                                config_cmd_fifo_put,
                                r_config_vaddr.read() ); 
    m_config_cmd_cmd_fifo.update( config_cmd_fifo_get,
                                config_cmd_fifo_put,
                                p_vci_tgt_config.cmd.read() );
    m_config_cmd_contig_fifo.update( config_cmd_fifo_get,
                                config_cmd_fifo_put,
                                p_vci_tgt_config.contig.read() );
    m_config_cmd_cons_fifo.update( config_cmd_fifo_get,
                                config_cmd_fifo_put,
                                p_vci_tgt_config.cons.read() );
    m_config_cmd_plen_fifo.update( config_cmd_fifo_get,
                                config_cmd_fifo_put,
                                p_vci_tgt_config.plen.read() );
    m_config_cmd_wrap_fifo.update( config_cmd_fifo_get,
                                config_cmd_fifo_put,
                                p_vci_tgt_config.wrap.read() );
    m_config_cmd_cfixed_fifo.update( config_cmd_fifo_get,
                                config_cmd_fifo_put,
                                p_vci_tgt_config.cfixed.read() );
    m_config_cmd_clen_fifo.update( config_cmd_fifo_get,
                                config_cmd_fifo_put,
                                p_vci_tgt_config.clen.read() );
    m_config_cmd_srcid_fifo.update( config_cmd_fifo_get,
                                config_cmd_fifo_put,
                                m_srcid_config );
    m_config_cmd_trdid_fifo.update( config_cmd_fifo_get,
                                config_cmd_fifo_put,
                                r_config_cmd_trt_index.read() ); 
    m_config_cmd_pktid_fifo.update( config_cmd_fifo_get,
                                config_cmd_fifo_put,
                                p_vci_tgt_config.pktid.read() );
    m_config_cmd_data_fifo.update( config_cmd_fifo_get,
                                config_cmd_fifo_put,
                                p_vci_tgt_config.wdata.read() );
    m_config_cmd_be_fifo.update( config_cmd_fifo_get,
                                config_cmd_fifo_put,
                                p_vci_tgt_config.be.read() );
    m_config_cmd_eop_fifo.update( config_cmd_fifo_get,
                                    config_cmd_fifo_put,
                                     p_vci_tgt_config.eop.read() );
    
    //////////////////
    //CONFIG_RSP Fifo
    //////////////////
    m_config_rsp_data_fifo.update( config_rsp_fifo_get,
                                config_rsp_fifo_put,
                                p_vci_ini_config.rdata.read() );
    m_config_rsp_rsrcid_fifo.update( config_rsp_fifo_get,
                                config_rsp_fifo_put,
                                r_config_rsrcid.read() );
    m_config_rsp_rtrdid_fifo.update( config_rsp_fifo_get,
                                config_rsp_fifo_put,
                                r_config_rtrdid.read() );
    m_config_rsp_rpktid_fifo.update( config_rsp_fifo_get,
                                config_rsp_fifo_put,
                                p_vci_ini_config.rpktid.read() );
    m_config_rsp_reop_fifo.update( config_rsp_fifo_get,
                               config_rsp_fifo_put,
                               p_vci_ini_config.reop.read() );
    m_config_rsp_rerror_fifo.update( config_rsp_fifo_get,
                                  config_rsp_fifo_put,
                                  p_vci_ini_config.rerror.read() );
    
    ///////////////////////
    //CONFIG Local RSP Fifo
    ///////////////////////
    m_config_local_rsrcid_fifo.update( config_local_fifo_get,
                                config_local_fifo_put,
                                p_vci_tgt_config.srcid.read() );
    m_config_local_rtrdid_fifo.update( config_local_fifo_get,
                                config_local_fifo_put,
                                p_vci_tgt_config.trdid.read() );
    m_config_local_rpktid_fifo.update( config_local_fifo_get,
                                config_local_fifo_put,
                                p_vci_tgt_config.pktid.read() );
    
    switch( r_config_cmd_fsm.read() ) 
    {
    case CONFIG_CMD_PTPR_WRITE:
    case CONFIG_CMD_ACTIVE_WRITE:
    case CONFIG_CMD_IT_ADDR_IOMMU_WRITE_2:
    case CONFIG_CMD_IT_ADDR_WRITE_2:
    case CONFIG_CMD_INVAL:
        m_config_local_data_fifo.update( config_local_fifo_get,
                                config_local_fifo_put,
                                0); 
        m_config_local_rerror_fifo.update( config_local_fifo_get,
                                        config_local_fifo_put,
                                        WRITE_OK );
        m_config_local_reop_fifo.update( config_local_fifo_get,
                                        config_local_fifo_put,
                                        true );
        break;
    case CONFIG_CMD_PTPR_READ:
        m_config_local_data_fifo.update( config_local_fifo_get,
                                config_local_fifo_put,
                                r_iommu_ptpr.read()); 
        m_config_local_rerror_fifo.update( config_local_fifo_get,
                                        config_local_fifo_put,
                                        READ_OK );
        m_config_local_reop_fifo.update( config_local_fifo_get,
                                        config_local_fifo_put,
                                        true );
        break;
    case CONFIG_CMD_ACTIVE_READ:
        m_config_local_data_fifo.update( config_local_fifo_get,
                                config_local_fifo_put,
                                r_iommu_active.read()); 
        m_config_local_rerror_fifo.update( config_local_fifo_get,
                                        config_local_fifo_put,
                                        READ_OK );
        m_config_local_reop_fifo.update( config_local_fifo_get,
                                        config_local_fifo_put,
                                        true );
        break;
    case CONFIG_CMD_BVAR_READ:
        m_config_local_data_fifo.update( config_local_fifo_get,
                                config_local_fifo_put,
                                r_iommu_bvar.read()); 
        m_config_local_rerror_fifo.update( config_local_fifo_get,
                                        config_local_fifo_put,
                                        READ_OK );
        m_config_local_reop_fifo.update( config_local_fifo_get,
                                        config_local_fifo_put,
                                        true );
        break;
    case CONFIG_CMD_ETR_READ:
        m_config_local_data_fifo.update( config_local_fifo_get,
                                config_local_fifo_put,
                                r_iommu_etr.read()); 
        m_config_local_rerror_fifo.update( config_local_fifo_get,
                                        config_local_fifo_put,
                                        READ_OK );
        m_config_local_reop_fifo.update( config_local_fifo_get,
                                        config_local_fifo_put,
                                        true );
        break;
    case CONFIG_CMD_BAD_ID_READ:
        m_config_local_data_fifo.update( config_local_fifo_get,
                                config_local_fifo_put,
                                r_iommu_bad_id.read()); 
        m_config_local_rerror_fifo.update( config_local_fifo_get,
                                        config_local_fifo_put,
                                        READ_OK );
        m_config_local_reop_fifo.update( config_local_fifo_get,
                                        config_local_fifo_put,
                                        true );
        break;
    case CONFIG_CMD_IT_ADDR_IOMMU_READ_1:
        m_config_local_data_fifo.update( config_local_fifo_get,
                                config_local_fifo_put,
                                (uint32_t)(r_it_addr_iommu.read() & 0xFFFFFFFF) ); 
        m_config_local_rerror_fifo.update( config_local_fifo_get,
                                        config_local_fifo_put,
                                        READ_OK );
        m_config_local_reop_fifo.update( config_local_fifo_get,
                                        config_local_fifo_put,
                                        false );
        break;
    case CONFIG_CMD_IT_ADDR_IOMMU_READ_2:
        m_config_local_data_fifo.update( config_local_fifo_get,
                                config_local_fifo_put,
                               (uint32_t)((r_it_addr_iommu.read()>>32)&0xFF) ); 
        m_config_local_rerror_fifo.update( config_local_fifo_get,
                                        config_local_fifo_put,
                                        READ_OK );
        m_config_local_reop_fifo.update( config_local_fifo_get,
                                        config_local_fifo_put,
                                        true );
        break;
    case CONFIG_CMD_IT_ADDR_READ_1:
        m_config_local_data_fifo.update( config_local_fifo_get,
                                config_local_fifo_put,
                               (uint32_t)(r_it_addr[r_it_index.read()] & 0xFFFFFFFF) ); 
        m_config_local_rerror_fifo.update( config_local_fifo_get,
                                        config_local_fifo_put,
                                        READ_OK );
        m_config_local_reop_fifo.update( config_local_fifo_get,
                                        config_local_fifo_put,
                                        false );
        break;
    case CONFIG_CMD_IT_ADDR_READ_2:
        m_config_local_data_fifo.update( config_local_fifo_get,
                                config_local_fifo_put,
                                (uint32_t)((r_it_addr[r_it_index.read()]>>32)&0xFF) ); 
        m_config_local_rerror_fifo.update( config_local_fifo_get,
                                        config_local_fifo_put,
                                        READ_OK );
        m_config_local_reop_fifo.update( config_local_fifo_get,
                                        config_local_fifo_put,
                                        true );
        break;
    case CONFIG_CMD_ERROR_RSP:
        m_config_local_data_fifo.update( config_local_fifo_get,
                                        config_local_fifo_put,
                                        0); 
        m_config_local_rerror_fifo.update( config_local_fifo_get,
                                        config_local_fifo_put,
                                        r_config_error_type.read() );
        m_config_local_reop_fifo.update( config_local_fifo_get,
                                        config_local_fifo_put,
                                        true );
        break;
    default:
        m_config_local_data_fifo.update( config_local_fifo_get,
                                config_local_fifo_put,
                                0); 
        m_config_local_rerror_fifo.update( config_local_fifo_get,
                                        config_local_fifo_put,
                                        0 );
        m_config_local_reop_fifo.update( config_local_fifo_get,
                               config_local_fifo_put,
                               false );
        break;
    }

} // end transition()

///////////////////////
tmpl(void)::genMoore()
///////////////////////
{
    //////////////////
    // DMA Commands //
    //////////////////
    
    // VCI initiator command on the xram network
    if(m_dma_cmd_addr_fifo.rok()) 
    //&& p_vci_ini_dma.cmdack.read())
    {
        p_vci_ini_dma.cmdval  = true;
        #if NEW_XRAM_VCI
        p_vci_ini_dma.address = (paddr_t_x)(m_dma_cmd_addr_fifo.read() >> 6 )
        #else
        p_vci_ini_dma.address = m_dma_cmd_addr_fifo.read();
        #endif
        
        p_vci_ini_dma.be      = m_dma_cmd_be_fifo.read();
        p_vci_ini_dma.cmd     = m_dma_cmd_cmd_fifo.read();
        p_vci_ini_dma.contig  = m_dma_cmd_contig_fifo.read();
        #if NEW_XRAM_VCI
        //TODO for 64 bits field
        #else
        p_vci_ini_dma.wdata   = m_dma_cmd_data_fifo.read(); // The first is in param_x
                                                    // the second in param_io
        #endif
        p_vci_ini_dma.eop     = m_dma_cmd_eop_fifo.read();
        p_vci_ini_dma.cons    = m_dma_cmd_cons_fifo.read();
        p_vci_ini_dma.plen    = m_dma_cmd_plen_fifo.read();
        p_vci_ini_dma.wrap    = m_dma_cmd_wrap_fifo.read();
        p_vci_ini_dma.cfixed  = m_dma_cmd_cfixed_fifo.read();
        p_vci_ini_dma.clen    = m_dma_cmd_clen_fifo.read();
        p_vci_ini_dma.trdid   = m_dma_cmd_trdid_fifo.read();
        p_vci_ini_dma.pktid   = m_dma_cmd_pktid_fifo.read();
        p_vci_ini_dma.srcid   = m_dma_cmd_srcid_fifo.read();
    }
    else
    {
        p_vci_ini_dma.cmdval  = false;
        p_vci_ini_dma.address = 0;
        p_vci_ini_dma.be      = 0;
        p_vci_ini_dma.cmd     = vci_param_x::CMD_NOP;
        p_vci_ini_dma.contig  = false;
        p_vci_ini_dma.wdata   = 0;
        p_vci_ini_dma.eop     = false;
        p_vci_ini_dma.cons    = true;
        p_vci_ini_dma.plen    = 0;
        p_vci_ini_dma.wrap    = false;
        p_vci_ini_dma.cfixed  = false;
        p_vci_ini_dma.clen    = 0;
        p_vci_ini_dma.trdid   = 0;
        p_vci_ini_dma.pktid   = 0; 
    }
    
    // VCI target command on the IO network
    // it depends on the DMA_CMD FSM state

    switch ( r_dma_cmd_fsm.read() ) 
    {
    case DMA_CMD_IDLE:
    case DMA_CMD_TRT_LOCK:	
    case DMA_CMD_TRT_WAIT:	
    case DMA_CMD_TRT_SET:	
        p_vci_tgt_dma.cmdack  = false;
        break;
    case DMA_CMD_FIFO_PUT:
    case DMA_CMD_FIFO_MISS_PUT:
        p_vci_tgt_dma.cmdack  = m_dma_cmd_addr_fifo.wok();
        break;
    case DMA_CMD_TLB_MISS_WAIT:
        p_vci_tgt_dma.cmdack  = false;
        break;
    case DMA_CMD_TLB_MISS_STORE:
        p_vci_tgt_dma.cmdack  = true;
        break;
    case DMA_CMD_ERROR:
        p_vci_tgt_dma.cmdack  = !r_dma_cmd_error_req.read();
        break; 
    }// end switch r_dma_cmd_fsm

    //////////////////
    // DMA Responses//
    //////////////////
    
    // VCI target response on the IO network
    if(m_dma_rsp_data_fifo.rok())
    {
        p_vci_tgt_dma.rspval  = true;
		p_vci_tgt_dma.rsrcid  = m_dma_rsp_rsrcid_fifo.read();
        p_vci_tgt_dma.rtrdid  = m_dma_rsp_rtrdid_fifo.read();
        
        p_vci_tgt_dma.rpktid  = m_dma_rsp_rpktid_fifo.read();
    
        #if NEW_XRAM_VCI
        //TODO for 64 bit data field
        #else 
        p_vci_tgt_dma.rdata   = m_dma_rsp_data_fifo.read(); // The first is in param_io
                                                    // the second in param_x
        #endif 
        
        p_vci_tgt_dma.rerror  = m_dma_rsp_rerror_fifo.read();
        p_vci_tgt_dma.reop    = m_dma_rsp_reop_fifo.read();
    }
    else
    {
        p_vci_tgt_dma.rspval  = false;
        
		p_vci_tgt_dma.rsrcid  = 0;
		p_vci_tgt_dma.rdata   = 0;
		p_vci_tgt_dma.rpktid  = 0;
		p_vci_tgt_dma.rtrdid  = 0;
		p_vci_tgt_dma.rerror  = 0;
		p_vci_tgt_dma.reop    = false;

    }

    // VCI initiator response on the Xram Network
    // it depends on the DMA_RSP FSM state
    switch ( r_dma_rsp_fsm.read() ) 
    {
    case DMA_RSP_IDLE:
    case DMA_RSP_TRT_LOCK:
    case DMA_RSP_FIFO_ERROR_PUT:
    {
		p_vci_ini_dma.rspack = false;
        break;
    }
    case DMA_RSP_FIFO_PUT:
	{
    	p_vci_ini_dma.rspack = m_dma_rsp_data_fifo.wok();
        break;
    }
    }// end switch r_dma_rsp_fsm

    /////////////////////
    // CONFIG Commands //
    /////////////////////

    // VCI initiator command on the IO network
    if(m_config_cmd_addr_fifo.rok())
    {
        p_vci_ini_config.cmdval  = true;
        #if NEW_XRAM_VCI
        p_vci_ini_config.address = (paddr_t_x)(m_config_cmd_addr_fifo.read() >> 6 )
        #else
        p_vci_ini_config.address = m_config_cmd_addr_fifo.read();
        #endif
        
        p_vci_ini_config.be      = m_config_cmd_be_fifo.read();
        p_vci_ini_config.cmd     = m_config_cmd_cmd_fifo.read();
        p_vci_ini_config.contig  = m_config_cmd_contig_fifo.read();
        #if NEW_XRAM_VCI
        //TODO
        #else
        p_vci_ini_config.wdata   = m_config_cmd_data_fifo.read(); // The first is in param_x
                                                    // the second in param_io
        #endif
        p_vci_ini_config.eop     = m_config_cmd_eop_fifo.read();
        p_vci_ini_config.cons    = m_config_cmd_cons_fifo.read();
        p_vci_ini_config.plen    = m_config_cmd_plen_fifo.read();
        p_vci_ini_config.wrap    = m_config_cmd_wrap_fifo.read();
        p_vci_ini_config.cfixed  = m_config_cmd_cfixed_fifo.read();
        p_vci_ini_config.clen    = m_config_cmd_clen_fifo.read();
        p_vci_ini_config.trdid   = m_config_cmd_trdid_fifo.read();
        p_vci_ini_config.pktid   = m_config_cmd_pktid_fifo.read();
    }
    else
    {
        p_vci_ini_config.cmdval  = false;
        p_vci_ini_config.address = 0;
        p_vci_ini_config.be      = 0;
        p_vci_ini_config.cmd     = vci_param_io::CMD_NOP;
        p_vci_ini_config.contig  = false;
        p_vci_ini_config.wdata   = 0;
        p_vci_ini_config.eop     = false;
        p_vci_ini_config.cons    = true;
        p_vci_ini_config.plen    = 0;
        p_vci_ini_config.wrap    = false;
        p_vci_ini_config.cfixed  = false;
        p_vci_ini_config.clen    = 0;
        p_vci_ini_config.trdid   = 0;
        p_vci_ini_config.pktid   = 0; 
    }
    
    // VCI target command on the Direct network
    // it depends on the CONFIG_CMD FSM state

    switch ( r_config_cmd_fsm.read() ) 
    {
    case CONFIG_CMD_IDLE:
    case CONFIG_CMD_TRT_LOCK:   
    case CONFIG_CMD_TRT_WAIT: 
    case CONFIG_CMD_TRT_SET: 
    case CONFIG_CMD_IT_ADDR_IOMMU_READ_1:
    case CONFIG_CMD_IT_ADDR_READ_1:
    case CONFIG_CMD_ERROR_RSP:  
    case CONFIG_CMD_INVAL_REQ:
        p_vci_tgt_config.cmdack  = false;
        break;
    case CONFIG_CMD_FIFO_PUT:	  
    case CONFIG_CMD_PTPR_WRITE:
    case CONFIG_CMD_PTPR_READ:
    case CONFIG_CMD_ACTIVE_WRITE:
    case CONFIG_CMD_ACTIVE_READ:
    case CONFIG_CMD_BVAR_READ:
    case CONFIG_CMD_ETR_READ:
    case CONFIG_CMD_BAD_ID_READ:
    case CONFIG_CMD_IT_ADDR_IOMMU_WRITE_2:
    case CONFIG_CMD_IT_ADDR_IOMMU_READ_2:
    case CONFIG_CMD_IT_ADDR_WRITE_2:
    case CONFIG_CMD_IT_ADDR_READ_2:
    case CONFIG_CMD_INVAL: 
        p_vci_tgt_config.cmdack  = m_config_cmd_addr_fifo.wok();
        break;
    case CONFIG_CMD_IT_ADDR_IOMMU_WRITE_1:
    case CONFIG_CMD_IT_ADDR_WRITE_1:
    case CONFIG_CMD_ERROR_WAIT: 
        p_vci_tgt_config.cmdack = true; 
        break;
    default: 
        p_vci_tgt_config.cmdack  = false;
        break;
    }// end switch r_config_cmd_fsm

    /////////////////////
    // CONFIG Responses//
    /////////////////////
    
    // VCI target response on the Direct network
    if(r_config_rsp_fifo_local_priority)
    {
    if( m_config_local_data_fifo.rok() )
    {
        p_vci_tgt_config.rspval  = true;
		p_vci_tgt_config.rsrcid  = m_config_local_rsrcid_fifo.read();
        p_vci_tgt_config.rtrdid  = m_config_local_rtrdid_fifo.read();
        p_vci_tgt_config.rpktid  = m_config_local_rpktid_fifo.read();
        p_vci_tgt_config.rdata   = m_config_local_data_fifo.read();
        p_vci_tgt_config.rerror  = m_config_local_rerror_fifo.read();
        p_vci_tgt_config.reop    = m_config_local_reop_fifo.read();
    }
    else if(m_config_rsp_data_fifo.rok() )
    {
        p_vci_tgt_config.rspval  = true;
		p_vci_tgt_config.rsrcid  = m_config_rsp_rsrcid_fifo.read();
        p_vci_tgt_config.rtrdid  = m_config_rsp_rtrdid_fifo.read();
        
        p_vci_tgt_config.rpktid  = m_config_rsp_rpktid_fifo.read();
    
        p_vci_tgt_config.rdata   = m_config_rsp_data_fifo.read(); // The first is in param_d
                                                    // the second in param_io
        p_vci_tgt_config.rerror  = m_config_rsp_rerror_fifo.read();
        p_vci_tgt_config.reop    = m_config_rsp_reop_fifo.read();
    }
    else
    {
        p_vci_tgt_config.rspval  = false;
        
		p_vci_tgt_config.rsrcid  = 0;
		p_vci_tgt_config.rdata   = 0;
		p_vci_tgt_config.rpktid  = 0;
		p_vci_tgt_config.rtrdid  = 0;
		p_vci_tgt_config.rerror  = 0;
		p_vci_tgt_config.reop    = false;

    }
    }
    else
    {
    if(m_config_rsp_data_fifo.rok() )
    {
        p_vci_tgt_config.rspval  = true;
		p_vci_tgt_config.rsrcid  = m_config_rsp_rsrcid_fifo.read();
        p_vci_tgt_config.rtrdid  = m_config_rsp_rtrdid_fifo.read();
        
        p_vci_tgt_config.rpktid  = m_config_rsp_rpktid_fifo.read();
    
        p_vci_tgt_config.rdata   = m_config_rsp_data_fifo.read(); // The first is in param_d
                                                    // the second in param_io
        p_vci_tgt_config.rerror  = m_config_rsp_rerror_fifo.read();
        p_vci_tgt_config.reop    = m_config_rsp_reop_fifo.read();
    }
    else if( m_config_local_data_fifo.rok() )
    {
        p_vci_tgt_config.rspval  = true;
		p_vci_tgt_config.rsrcid  = m_config_local_rsrcid_fifo.read();
        p_vci_tgt_config.rtrdid  = m_config_local_rtrdid_fifo.read();
        p_vci_tgt_config.rpktid  = m_config_local_rpktid_fifo.read();
        p_vci_tgt_config.rdata   = m_config_local_data_fifo.read();
        p_vci_tgt_config.rerror  = m_config_local_rerror_fifo.read();
        p_vci_tgt_config.reop    = m_config_local_reop_fifo.read();
    }
    else
    {
        p_vci_tgt_config.rspval  = false;
        
		p_vci_tgt_config.rsrcid  = 0;
		p_vci_tgt_config.rdata   = 0;
		p_vci_tgt_config.rpktid  = 0;
		p_vci_tgt_config.rtrdid  = 0;
		p_vci_tgt_config.rerror  = 0;
		p_vci_tgt_config.reop    = false;

    }
    }
    
    // VCI initiator response on the IO Network
    // it depends on the CONFIG_RSP FSM state
    switch ( r_config_rsp_fsm.read() ) 
    {
    case CONFIG_RSP_IDLE:
    case CONFIG_RSP_TRT_LOCK:
	p_vci_ini_config.rspack = false;
        break;
    case CONFIG_RSP_FIFO_PUT:
		p_vci_ini_config.rspack = m_config_rsp_data_fifo.wok();
        break;
    }// end switch r_config_rsp_fsm

    ////////////////////////////////////////////////////////////////
    // VCI initiator command and response on from the Direct network 
    // for Miss Transactions
    p_vci_ini_miss.srcid   = m_srcid_miss;
    
    switch ( r_miss_init_fsm.read() ) 
    {   
    case MISS_INIT_IDLE_MISS:
    case MISS_INIT_IDLE_IRQ:
		p_vci_ini_miss.cmdval  = false;
        p_vci_ini_miss.address = 0;
        p_vci_ini_miss.be      = 0;
        p_vci_ini_miss.cmd     = vci_param_d::CMD_NOP;
        p_vci_ini_miss.contig  = false;
        p_vci_ini_miss.wdata   = 0;
        p_vci_ini_miss.eop     = false;
        p_vci_ini_miss.cons    = true;
        p_vci_ini_miss.plen    = 0;
        p_vci_ini_miss.wrap    = false;
        p_vci_ini_miss.cfixed  = false;
        p_vci_ini_miss.clen    = 0;
        p_vci_ini_miss.trdid   = 0;
        p_vci_ini_miss.pktid   = 0;

		p_vci_ini_miss.rspack = false;
        break;
    
    case MISS_INIT_IRQ_CMD:
        p_vci_ini_miss.cmdval  = true;
        p_vci_ini_miss.address = (paddr_t)r_it_addr[r_irq_chosen.read()]; 
        p_vci_ini_miss.wdata   = 0;
        p_vci_ini_miss.plen    = vci_param_d::B;
        p_vci_ini_miss.trdid   = 0;  
        p_vci_ini_miss.cmd     = vci_param_d::CMD_READ;
        p_vci_ini_miss.eop     = true;
        
        p_vci_ini_miss.be      = 0xF;
        p_vci_ini_miss.pktid   = 0;
        p_vci_ini_miss.cons    = false;
        p_vci_ini_miss.wrap    = false;
        p_vci_ini_miss.contig  = true;
        p_vci_ini_miss.clen    = 0;
        p_vci_ini_miss.cfixed  = false;
        break;
    
    case MISS_INIT_IRQ_RSP:
    case MISS_INIT_TLB_MISS_RSP:
        p_vci_ini_miss.cmdval  = false;
        p_vci_ini_miss.address = 0;
        p_vci_ini_miss.be      = 0;
        p_vci_ini_miss.cmd     = vci_param_d::CMD_NOP;
        p_vci_ini_miss.contig  = false;
        p_vci_ini_miss.wdata   = 0;
        p_vci_ini_miss.eop     = false;
        p_vci_ini_miss.cons    = true;
        p_vci_ini_miss.plen    = 0;
        p_vci_ini_miss.wrap    = false;
        p_vci_ini_miss.cfixed  = false;
        p_vci_ini_miss.clen    = 0;
        p_vci_ini_miss.trdid   = 0;
        p_vci_ini_miss.pktid   = 0;
        
        p_vci_ini_miss.rspack = true;
 
        break;
   
    case MISS_INIT_TLB_MISS_CMD:
        p_vci_ini_miss.cmdval  = true;
        p_vci_ini_miss.address = (paddr_t)((r_iotlb_paddr.read())& CACHE_LINE_MASK);
        p_vci_ini_miss.wdata   = 0x00000000;
        p_vci_ini_miss.plen    = m_words*(vci_param_d::B);
        p_vci_ini_miss.trdid   = 0;  //could be used as the index on a miss transaction table
        p_vci_ini_miss.cmd     = vci_param_d::CMD_READ;
        p_vci_ini_miss.eop     = true;
        
        p_vci_ini_miss.be      = 0xF;
        p_vci_ini_miss.pktid   = 0;
        p_vci_ini_miss.cons    = false;
        p_vci_ini_miss.wrap    = false;
        p_vci_ini_miss.contig  = true;
        p_vci_ini_miss.clen    = 0;
        p_vci_ini_miss.cfixed  = false;
        break;

    } // end switch r_miss_init_fsm
} // end genMoore

}}

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