/* -*- c++ -*-
 * File : vci_io_bridge.h
 * Copyright (c) UPMC, Lip6, SoC
 * Date : 16/04/2012
 * Authors: Cassio Fraga, Alain Greiner
 *
 * SOCLIB_LGPL_HEADER_BEGIN
 * 
 * This file is part of SoCLib, GNU LGPLv2.1.
 * 
 * SoCLib is free software; you can redistribute it and/or modify it
 * under the terms of the GNU Lesser General Public License as published
 * by the Free Software Foundation; version 2.1 of the License.
 * 
 * SoCLib is distributed in the hope that it will be useful, but
 * WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 * 
 * You should have received a copy of the GNU Lesser General Public
 * License along with SoCLib; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
 * 02110-1301 USA
 * 
 * SOCLIB_LGPL_HEADER_END
 */
/////////////////////////////////////////////////////////////////////////////////
// This TSAR component is a bridge to access external peripherals
// connected to an external I/O bus (such as Hypertransport or PCIe).
// It connects three VCI networks:
//
// - INT network : to receive both configuration requests from processors
//                 or software driven data access to peripherals.
// - RAM network : to send DMA transactions initiated by peripherals
//                 directly to the RAM (or L3 caches).
// - IOX network : to receive DMA transactions from peripherals, or to send
//                 configuration or data transactions to peripherals.
//
// Regarding DMA transactions initiated by external peripherals, it provides
// an - optional - IOMMU service : the 32 bits virtual address is translated
// to a (up to) 40 bits physical address by a standard SoCLib generic TLB.
// In case of TLB MISS, the DMA transaction is stalled until the TLB is updated.
// In case of page fault (illegal access), a VCI error is returned to the
// faulty peripheral.
/////////////////////////////////////////////////////////////////////////////////
//   General Constraints:
//
// - All VCI fields have the same widths on the RAM and IOX networks,
//   and the VCI DATA field is 64 bits.
// - Only the VCI DATA field differ between INT and IOX/RAM networks,
//   as the VCI DATA field is 32 bits.
// - The common VCI ADDRESS width cannot be larger than 64 bits.
// - All VCI transactions must be included in a single cache line.
// - Page Tables must have the format required by the SoCLib generic_tlb.
// - IO's segments must be the same in INT and IOX networks
// - Write operations on IOMMU configuration registers (PTPR, ACTIVE) are
//   delayed until DMA_TLB FSM is IDLE. It should, preferably, be done before
//   starting any transfers. Pseudo register INVAL may be modified any time.
////////////////////////////////////////////////////////////////////////////////

 
///////TODO List///////////////////////////////////////////////////////////////
// - Ne pas garder tous les champs WRITE CMD dans les FIFO a chaque flit
//   (seulement 'data' et 'be')
// - Traiter complêtement les codes d'erreur en réponse à une transaction
//   WTI write
///////////////////////////////////////////////////////////////////////////////

#ifndef SOCLIB_CABA_VCI_IO_BRIDGE_H
#define SOCLIB_CABA_VCI_IO_BRIDGE_H

#include <inttypes.h>
#include <systemc>
#include "caba_base_module.h"
#include "generic_fifo.h"
#include "generic_tlb.h"
#include "mapping_table.h"
#include "address_decoding_table.h" 
#include "static_assert.h"
#include "vci_initiator.h"
#include "vci_target.h"
#include "../../../include/soclib/io_bridge.h"

namespace soclib {
namespace caba {

using namespace soclib::common;

///////////////////////////////////////////////////////////////////////////////////
template<typename vci_param_int,
         typename vci_param_ext>
class VciIoBridge
///////////////////////////////////////////////////////////////////////////////////
    : public soclib::caba::BaseModule
{
    // Data and be fields have different widths on INT and EXT networks
    typedef typename vci_param_ext::data_t          ext_data_t;
    typedef typename vci_param_int::data_t          int_data_t;
    typedef typename vci_param_ext::be_t            ext_be_t;
    typedef typename vci_param_int::be_t            ext_in_t;

    // Other fields must be equal   
    typedef typename vci_param_int::fast_addr_t     vci_addr_t; 
    typedef typename vci_param_int::srcid_t         vci_srcid_t;  
    typedef typename vci_param_int::trdid_t         vci_trdid_t;
    typedef typename vci_param_int::pktid_t         vci_pktid_t;
    typedef typename vci_param_int::plen_t          vci_plen_t;
    typedef typename vci_param_int::cmd_t           vci_cmd_t;
    typedef typename vci_param_int::contig_t        vci_contig_t;
    typedef typename vci_param_int::eop_t           vci_eop_t;
    typedef typename vci_param_int::const_t         vci_cons_t;
    typedef typename vci_param_int::wrap_t          vci_wrap_t;
    typedef typename vci_param_int::clen_t          vci_clen_t;
    typedef typename vci_param_int::cfixed_t        vci_cfixed_t;
    typedef typename vci_param_int::rerror_t        vci_rerror_t;

    enum 
    {
        CACHE_LINE_MASK    = 0xFFFFFFFFC0LL,  
        PPN1_MASK          = 0x0007FFFF,  
        PPN2_MASK          = 0x0FFFFFFF,  
        K_PAGE_OFFSET_MASK = 0x00000FFF,  
        M_PAGE_OFFSET_MASK = 0x001FFFFF,
        PTE2_LINE_OFFSET   = 0x00007000, // bits 12,13,14.
        PTE1_LINE_OFFSET   = 0x01E00000, // bits 21,22,23,24 
    };
 
    // States for DMA_CMD FSM (from IOX to RAM)
    enum dma_cmd_fsm_state 
    {  
        DMA_CMD_IDLE,
        DMA_CMD_FIFO_PUT_CMD,
        DMA_CMD_FIFO_PUT_RSP,
        DMA_CMD_MISS_WAIT,
        DMA_CMD_WAIT_EOP,
    };
   
    // States for DMA_RSP FSM (from RAM to IOX)
    enum dma_rsp_fsm_state 
    {  
        DMA_RSP_IDLE,
        DMA_RSP_FIFO_PUT, 
    };
    
    // States for TLB_MISS FSM
    enum dma_tlb_fsm_state 
    {   
        TLB_IDLE,
        TLB_MISS,
        TLB_PTE1_GET,
        TLB_PTE1_SELECT,
        TLB_PTE1_UPDT,
        TLB_PTE2_GET,                                                  
        TLB_PTE2_SELECT,
        TLB_PTE2_UPDT,
        TLB_WAIT,
        TLB_RETURN,
        TLB_INVAL_CHECK,
	};
    
    // States for CONFIG_CMD FSM (from INT to IOX)
    enum config_cmd_fsm_state 
    {  
        CONFIG_CMD_IDLE,
        CONFIG_CMD_NEXT,
        CONFIG_CMD_PUT,
        CONFIG_CMD_RSP,
	};
    
    // states for CONFIG_RSP FSM (from IOX to INT)
    enum config_rsp_fsm_state 
    {  
        CONFIG_RSP_IDLE,
        CONFIG_RSP_PUT_LO,
        CONFIG_RSP_PUT_HI,
        CONFIG_RSP_PUT_UNC,
    };
    
    // States for MISS_WTI_CMD FSM (to INT network) 
    enum miss_wti_cmd_state 
    {  
        MISS_WTI_CMD_IDLE,
        MISS_WTI_CMD_WTI,
        MISS_WTI_CMD_MISS,
	};
    
    // States for MISS_WTI_RSP FSM (from INT network) 
    enum miss_wti_rsp_state 
    {  
        MISS_WTI_RSP_IDLE,
        MISS_WTI_RSP_WTI,
        MISS_WTI_RSP_MISS,
	};

    // PKTID values for TLB MISS and WTI transactions
    enum pktid_values_e
    {
        PKTID_READ  = 0x0,  // TSAR code for read data uncached
        PKTID_WRITE = 0x4,  // TSAR code for write
    };
   
    // Miss types for iotlb
    enum tlb_miss_type_e
    {
        PTE1_MISS, 
        PTE2_MISS,
	};
    
public:
    sc_in<bool>                               p_clk;
    sc_in<bool>                               p_resetn;
    sc_in<bool>*                              p_irq[32];     // not always constructed
    
    soclib::caba::VciInitiator<vci_param_ext> p_vci_ini_ram; 

    soclib::caba::VciTarget<vci_param_ext>    p_vci_tgt_iox;
    soclib::caba::VciInitiator<vci_param_ext> p_vci_ini_iox;

    soclib::caba::VciTarget<vci_param_int>    p_vci_tgt_int;
    soclib::caba::VciInitiator<vci_param_int> p_vci_ini_int;

private:
    const size_t  	                          m_words;
    const bool                                m_has_irqs;

    // INT & IOX Networks
    std::list<soclib::common::Segment>        m_int_seglist;
    const vci_srcid_t              	          m_int_srcid;  // local SRCID on INT network
    std::list<soclib::common::Segment>        m_iox_seglist;

    // TLB parameters
    const size_t  					          m_iotlb_ways;
    const size_t  					          m_iotlb_sets;

    // debug variables 
    uint32_t                                  m_debug_start_cycle;
    bool                                      m_debug_ok;
    bool                                      m_debug_activated;

    ///////////////////////////////
    // MEMORY MAPPED REGISTERS
    ///////////////////////////////
    sc_signal<uint32_t>         r_iommu_ptpr;           // page table pointer register
    sc_signal<bool>             r_iommu_active;         // iotlb mode
    sc_signal<uint32_t>         r_iommu_bvar;           // iommu bad virtual address
    sc_signal<uint32_t>         r_iommu_etr;            // iommu error type
    sc_signal<uint32_t>         r_iommu_bad_id;         // SRCID of faulty peripheral 
    sc_signal<uint32_t>         r_iommu_wti_enable;     // enable WTI transactions  
    sc_signal<vci_addr_t>       r_iommu_wti_paddr;      // address of IOMMU WTI 
    sc_signal<vci_addr_t>*      r_iommu_peri_wti;       // array[32] WTI for peripherals 
 
	///////////////////////////////////
    // DMA_CMD FSM REGISTERS
    ///////////////////////////////////
    sc_signal<int>              r_dma_cmd_fsm;		
    sc_signal<uint32_t>         r_dma_cmd_vaddr;        // input virtual address 
    sc_signal<vci_addr_t>       r_dma_cmd_paddr;        // output physical address

    ///////////////////////////////////
    // DMA_RSP FSM REGISTERS
    ///////////////////////////////////
    sc_signal<int>              r_dma_rsp_fsm;
    
    ///////////////////////////////////
    // CONFIG_CMD FSM REGISTERS
    ///////////////////////////////////
    sc_signal<int>              r_config_cmd_fsm;
    sc_signal<uint32_t>         r_config_cmd_rdata;
    sc_signal<bool>             r_config_cmd_error;
    sc_signal<uint32_t>         r_config_cmd_inval_vaddr;

    sc_signal<ext_data_t>       r_config_cmd_wdata;
    sc_signal<ext_be_t>         r_config_cmd_be;
    sc_signal<vci_plen_t>       r_config_cmd_cmd;
    sc_signal<vci_addr_t>       r_config_cmd_address;
    sc_signal<vci_srcid_t>      r_config_cmd_srcid;
    sc_signal<vci_pktid_t>      r_config_cmd_pktid;
    sc_signal<vci_trdid_t>      r_config_cmd_trdid;
    sc_signal<vci_plen_t>       r_config_cmd_plen;
    sc_signal<vci_clen_t>       r_config_cmd_clen;
    sc_signal<vci_cons_t>       r_config_cmd_cons;
    sc_signal<vci_contig_t>     r_config_cmd_contig;
    sc_signal<vci_cfixed_t>     r_config_cmd_cfixed;
    sc_signal<vci_wrap_t>       r_config_cmd_wrap;
    sc_signal<vci_eop_t>        r_config_cmd_eop;

    ///////////////////////////////////
    // CONFIG_RSP FSM REGISTERS
    ///////////////////////////////////
    sc_signal<int>              r_config_rsp_fsm;

    ///////////////////////////////////
    // TLB FSM REGISTERS
    ///////////////////////////////////
    sc_signal<int>              r_tlb_fsm;		        // state register 
    sc_signal<bool>             r_waiting_transaction;  // Flag for returning from
    sc_signal<int>              r_tlb_miss_type;
	sc_signal<bool>             r_tlb_miss_error; 

    sc_signal<vci_addr_t>       r_tlb_paddr;		    // physical address of pte
    sc_signal<uint32_t>         r_tlb_pte_flags;	    // pte1 or first word of pte2
    sc_signal<uint32_t>         r_tlb_pte_ppn;	        // second word of pte2
    sc_signal<size_t>           r_tlb_way;		        // selected way in tlb    
    sc_signal<size_t>           r_tlb_set;		        // selected set in tlb    

    uint32_t*                   r_tlb_buf_data;         // prefetch buffer for PTEs
    sc_signal<bool>             r_tlb_buf_valid;        // one valit flag for all PTEs
    sc_signal<vci_addr_t>       r_tlb_buf_tag;          // cache line number  
    sc_signal<vci_addr_t>       r_tlb_buf_vaddr;        // virtual address first PTE  
    sc_signal<bool>             r_tlb_buf_big_page;     // ???

    ///////////////////////////////////
    // MISS_WTI_CMD FSM REGISTERS
    ///////////////////////////////////
    sc_signal<int>              r_miss_wti_cmd_fsm;
    sc_signal<size_t>	        r_miss_wti_cmd_index;

    ///////////////////////////////////
    // MISS_WTI_RSP FSM REGISTERS
    ///////////////////////////////////
    sc_signal<int>              r_miss_wti_rsp_fsm;
    sc_signal<bool>             r_miss_wti_rsp_error; 
    sc_signal<size_t>           r_miss_wti_rsp_count; 
    
    /////////////////////////////////////////////////////
    //  ALLOCATORS for CONFIG_RSP fifo & DMA_RSP fifo
    /////////////////////////////////////////////////////
    sc_signal<bool>             r_alloc_fifo_config_rsp_local;  
    sc_signal<bool>             r_alloc_fifo_dma_rsp_local;  

    //////////////////////////////////
    // IRQ FSM registers
    //////////////////////////////////
	sc_signal<bool>*            r_irq_pending;  // array[32]
	sc_signal<bool>*            r_irq_request;  // array[32]
   
    //////////////////////////////////////////////////////////////////
    // IOTLB  
    //////////////////////////////////////////////////////////////////
    GenericTlb<vci_addr_t>      r_iotlb;
	
    //////////////////////////////////////////////////////////////////
    // Inter-FSM communications
    //////////////////////////////////////////////////////////////////
    
    // between DMA_CMD and TLB FSM 
    sc_signal<bool>             r_dma_tlb_req;

    // between CONFIG_CMD FSM and TLB FSM
    sc_signal<bool>             r_config_tlb_req;
    
    // between TLB FSM and MISS_WTI FSM 
    sc_signal<bool>             r_tlb_miss_req;
    
    /////////////////////////
    // FIFOs
    /////////////////////////

    // ouput FIFO to VCI INI port on RAM network (VCI command)
    GenericFifo<vci_addr_t>     m_dma_cmd_addr_fifo;
    GenericFifo<vci_srcid_t>    m_dma_cmd_srcid_fifo;
    GenericFifo<vci_trdid_t>    m_dma_cmd_trdid_fifo;
    GenericFifo<vci_pktid_t>    m_dma_cmd_pktid_fifo;
    GenericFifo<ext_be_t>       m_dma_cmd_be_fifo;
    GenericFifo<vci_cmd_t>      m_dma_cmd_cmd_fifo;
    GenericFifo<vci_contig_t>   m_dma_cmd_contig_fifo;
    GenericFifo<ext_data_t>     m_dma_cmd_data_fifo;
    GenericFifo<vci_eop_t>      m_dma_cmd_eop_fifo;
    GenericFifo<vci_cons_t>     m_dma_cmd_cons_fifo;
    GenericFifo<vci_plen_t>     m_dma_cmd_plen_fifo;
    GenericFifo<vci_wrap_t>     m_dma_cmd_wrap_fifo;
    GenericFifo<vci_cfixed_t>   m_dma_cmd_cfixed_fifo;
    GenericFifo<vci_clen_t>     m_dma_cmd_clen_fifo;

    // output FIFO to VCI TGT port on IOX network (VCI response)
    GenericFifo<ext_data_t>     m_dma_rsp_data_fifo;
    GenericFifo<vci_srcid_t>    m_dma_rsp_rsrcid_fifo;
    GenericFifo<vci_trdid_t>    m_dma_rsp_rtrdid_fifo;
    GenericFifo<vci_pktid_t>    m_dma_rsp_rpktid_fifo;
    GenericFifo<vci_eop_t>      m_dma_rsp_reop_fifo;
    GenericFifo<vci_rerror_t>   m_dma_rsp_rerror_fifo;
	
    // output FIFO to VCI INI port on IOX network (VCI command)
    GenericFifo<vci_addr_t>     m_config_cmd_addr_fifo;
    GenericFifo<vci_srcid_t>    m_config_cmd_srcid_fifo;
    GenericFifo<vci_trdid_t>    m_config_cmd_trdid_fifo;
    GenericFifo<vci_pktid_t>    m_config_cmd_pktid_fifo;
    GenericFifo<ext_be_t>       m_config_cmd_be_fifo;
    GenericFifo<vci_cmd_t>      m_config_cmd_cmd_fifo;
    GenericFifo<vci_contig_t>   m_config_cmd_contig_fifo;
    GenericFifo<ext_data_t>     m_config_cmd_data_fifo;
    GenericFifo<vci_eop_t>      m_config_cmd_eop_fifo;
    GenericFifo<vci_cons_t>     m_config_cmd_cons_fifo;
    GenericFifo<vci_plen_t>     m_config_cmd_plen_fifo;
    GenericFifo<vci_wrap_t>     m_config_cmd_wrap_fifo;
    GenericFifo<vci_cfixed_t>   m_config_cmd_cfixed_fifo;
    GenericFifo<vci_clen_t>     m_config_cmd_clen_fifo;
    
    // output FIFO to VCI TGT port on INT network (VCI response)  
    GenericFifo<int_data_t>     m_config_rsp_data_fifo;
    GenericFifo<vci_srcid_t>    m_config_rsp_rsrcid_fifo;
    GenericFifo<vci_trdid_t>    m_config_rsp_rtrdid_fifo;
    GenericFifo<vci_pktid_t>    m_config_rsp_rpktid_fifo;
    GenericFifo<vci_eop_t>      m_config_rsp_reop_fifo;
    GenericFifo<vci_rerror_t>   m_config_rsp_rerror_fifo;
	
   
    ////////////////////////////////
    // Activity counters
    ////////////////////////////////
    
    uint32_t m_cpt_total_cycles;            // total number of cycles
    
    // TLB activity counters
    uint32_t m_cpt_iotlb_read;              // number of iotlb read
    uint32_t m_cpt_iotlb_miss;              // number of iotlb miss
    uint32_t m_cost_iotlb_miss;             // number of wait cycles (not treatment itself)
    uint32_t m_cpt_iotlbmiss_transaction;   // number of tlb miss transactions 
    uint32_t m_cost_iotlbmiss_transaction;  // cumulated duration tlb miss transactions

    //Transaction Tabs (TRTs) activity counters
    uint32_t m_cpt_trt_dma_full;            // DMA TRT full when a new command arrives
    uint32_t m_cpt_trt_dma_full_cost;       // total number of cycles blocked
    uint32_t m_cpt_trt_config_full;         // Config TRT full when a new command arrives
    uint32_t m_cpt_trt_config_full_cost;    // total number of cycles blocked

    // FSM activity counters
    // unused on print_stats
    uint32_t m_cpt_fsm_dma_cmd          [32]; 
    uint32_t m_cpt_fsm_dma_rsp          [32]; 
    uint32_t m_cpt_fsm_tlb              [32]; 
    uint32_t m_cpt_fsm_config_cmd       [32]; 
    uint32_t m_cpt_fsm_config_rsp       [32]; 
    uint32_t m_cpt_fsm_miss_wti_cmd     [32]; 
    uint32_t m_cpt_fsm_miss_wti_rsp     [32];
 
protected:
    SC_HAS_PROCESS(VciIoBridge);

public:
    VciIoBridge(
        sc_module_name insname,
        const    soclib::common::MappingTable  &mt_ext,      // external network
        const    soclib::common::MappingTable  &mt_int,      // internal network
        const    soclib::common::MappingTable  &mt_iox,      // iox network
        const    soclib::common::IntTab        &int_tgtid,   // INT network TGTID
        const    soclib::common::IntTab        &int_srcid,   // INT network SRCID
        const    soclib::common::IntTab        &iox_tgtid,   // IOX network TGTID
        const    bool                          has_irqs,     // component has irq ports
        const    size_t                        dcache_words,
        const    size_t                        iotlb_ways,
        const    size_t                        iotlb_sets,
        const    uint32_t                      debug_start_cycle,
        const    bool                          debug_ok );

    ~VciIoBridge();

    void print_stats();
    void clear_stats();
    void print_trace(size_t mode = 0);
    

private:
    void transition();
    void genMoore();
};

}}

#endif /* SOCLIB_CABA_VCI_CC_VCACHE_WRAPPER_V4_H */

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




