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

#include <inttypes.h>
#include <systemc>
#include <queue>
#include "caba_base_module.h"
#include "multi_write_buffer.h"
#include "generic_cache.h"
#include "vci_initiator.h"
#include "vci_target.h"
#include "mapping_table.h"
#include "static_assert.h"

/*
 * CC_XCACHE_WRAPPER_SELECT_VICTIM :
 *   The selection and the update of cache (after a read miss)
 *   are separated in two step
 *   Also, the cleanup can be send in parallel at the read miss.
 *
 * CC_XCACHE_WRAPPER_FIFO_RSP
 *   Two simple fifo (each 2x32 depth) receive the cache line from
 *   RAM. Instead of two buffers (m_icache_words and m_dcache_words)
 *   
 * CC_XCACHE_WRAPPER_CC_UPDATE_MULTI_CYCLE
 *   Update cache in "2*cache_words" cycles (read+mask, write)
 *   
 * CC_XCACHE_WRAPPER_CC_UPDATE_MULTI_CYCLE_OPT
 *   Update cache with only modified data (be != 0)
 *   
 * CC_XCACHE_WRAPPER_WBUF_UPDATE_SCHEME
 *   Write buffer scheme for update step :
 *     1    - multi_scan
 *     2    - round_robin_scan
 *     3    - one_scan
 *     else - default scheme
 *
 * CC_XCACHE_WRAPPER_VCI_CMD_PRIORITY
 *   Write buffer access is conditionnal with dcache_miss_req and icache_miss_req
 *     1    - two access authorized
 *     2    - one access with static priority (dcache prior)
 *     3    - one access with static priority (icache prior)
 *     4    - one access with round robin priority
 * 
 * CC_XCACHE_WRAPPER_STOP_SIMULATION :
 *   stop simulation if processor is stall after a long time
 *   (configurable with "stop_simulation" function)
 *
 * CC_XCACHE_WRAPPER_DEBUG :
 *   Add log to help the debugging
 *
 * CC_XCACHE_WRAPPER_DEBUG_CYCLE_MIN :
 *   Number of cycle before to prinf debug message
 *
 * CC_XCACHE_WRAPPER_DEBUG_DCACHE_TRANSACTION
 *   Print transaction between the cpu and the cache
 */

// implementation
#ifndef CC_XCACHE_WRAPPER_SELECT_VICTIM
#define CC_XCACHE_WRAPPER_SELECT_VICTIM             0
#endif
#ifndef CC_XCACHE_WRAPPER_FIFO_RSP
#define CC_XCACHE_WRAPPER_FIFO_RSP                  0
#endif
#ifndef CC_XCACHE_WRAPPER_CC_UPDATE_MULTI_CYCLE
#define CC_XCACHE_WRAPPER_CC_UPDATE_MULTI_CYCLE     1
#endif
#ifndef CC_XCACHE_WRAPPER_CC_UPDATE_MULTI_CYCLE_OPT
#define CC_XCACHE_WRAPPER_CC_UPDATE_MULTI_CYCLE_OPT 1
#endif
#ifndef CC_XCACHE_WRAPPER_WBUF_UPDATE_SCHEME
#define CC_XCACHE_WRAPPER_WBUF_UPDATE_SCHEME        0
#endif
#ifndef CC_XCACHE_WRAPPER_VCI_CMD_PRIORITY
#define CC_XCACHE_WRAPPER_VCI_CMD_PRIORITY          2
#endif  
// debugging
#ifndef CC_XCACHE_WRAPPER_STOP_SIMULATION
#define CC_XCACHE_WRAPPER_STOP_SIMULATION           1
#endif
#ifndef CC_XCACHE_WRAPPER_DEBUG
#define CC_XCACHE_WRAPPER_DEBUG                     0
#endif
#ifndef CC_XCACHE_WRAPPER_DEBUG_CYCLE_MIN
#define CC_XCACHE_WRAPPER_DEBUG_CYCLE_MIN           200000
#endif
#ifndef CC_XCACHE_WRAPPER_DEBUG_DCACHE_TRANSACTION
#define CC_XCACHE_WRAPPER_DEBUG_DCACHE_TRANSACTION  0
#endif

namespace soclib {
namespace caba {

using namespace sc_core;

////////////////////////////////////////////
template<typename vci_param, typename iss_t>
class VciCcXCacheWrapperV4
///////////////////////////////////////////
    : public soclib::caba::BaseModule
{
    typedef sc_dt::sc_uint<40> 	addr_40;
    typedef sc_dt::sc_uint<64>  data_64;
    typedef uint32_t    	data_t;
    typedef uint32_t    	tag_t;
    typedef uint32_t    	be_t;
    typedef typename vci_param::fast_addr_t vci_addr_t;

    enum dcache_fsm_state_e {
        DCACHE_IDLE,
        DCACHE_WRITE_UPDT,
#if CC_XCACHE_WRAPPER_SELECT_VICTIM
        DCACHE_MISS_VICTIM,
#endif
        DCACHE_MISS_WAIT,
        DCACHE_MISS_UPDT,
        DCACHE_UNC_WAIT,
        DCACHE_SC_WAIT,
        DCACHE_INVAL,
        DCACHE_SYNC,
        DCACHE_ERROR,
        DCACHE_CC_CHECK,
        DCACHE_CC_INVAL,
        DCACHE_CC_UPDT,
        DCACHE_CC_CLEANUP,
    };

    enum icache_fsm_state_e {
        ICACHE_IDLE,
#if CC_XCACHE_WRAPPER_SELECT_VICTIM
        ICACHE_MISS_VICTIM,
#endif
        ICACHE_MISS_WAIT,
        ICACHE_MISS_UPDT,
        ICACHE_UNC_WAIT,
        ICACHE_ERROR,
        ICACHE_CC_CLEANUP, 
        ICACHE_CC_CHECK,
        ICACHE_CC_INVAL,
        ICACHE_CC_UPDT,
    };

    enum cmd_fsm_state_e {
        CMD_IDLE,
        CMD_INS_MISS,
        CMD_INS_UNC,
        CMD_DATA_MISS,
        CMD_DATA_UNC,
        CMD_DATA_WRITE,
        CMD_DATA_SC,
    };

    enum rsp_fsm_state_e {
        RSP_IDLE,
        RSP_INS_MISS,
        RSP_INS_UNC,
        RSP_DATA_MISS,
        RSP_DATA_UNC,
        RSP_DATA_WRITE,
        RSP_DATA_SC,
    };

    enum tgt_fsm_state_e {
        TGT_IDLE,
        TGT_UPDT_WORD,
        TGT_UPDT_DATA,
        TGT_REQ_BROADCAST,
        TGT_REQ_ICACHE,
        TGT_REQ_DCACHE,
        TGT_RSP_BROADCAST,
        TGT_RSP_ICACHE,
        TGT_RSP_DCACHE,
    };

    enum cleanup_fsm_state_e {
        CLEANUP_IDLE,
        CLEANUP_DCACHE,
        CLEANUP_ICACHE,
    };

    enum transaction_type_c_e {
        // convention with memcache
        TYPE_DATA_CLEANUP = 0x0,
        TYPE_INS_CLEANUP  = 0x1
    };

    enum transaction_type_rw_e {
        // convention with memcache
        // b0 : 1 if cached
        // b1 : 1 if instruction
        // b2 : 1 if sc
        TYPE_DATA_UNC     = 0x0,
        TYPE_DATA_MISS    = 0x1,
        TYPE_INS_UNC      = 0x2,
        TYPE_INS_MISS     = 0x3,
        TYPE_DATA_SC      = 0x4, // sc is data and no cached
    };

public:

    // PORTS
    sc_in<bool>                             p_clk;
    sc_in<bool>                             p_resetn;
    sc_in<bool>                             p_irq[iss_t::n_irq];
    soclib::caba::VciInitiator<vci_param>   p_vci_ini_rw;
    soclib::caba::VciInitiator<vci_param>   p_vci_ini_c;
    soclib::caba::VciTarget<vci_param>      p_vci_tgt;

private:

    // STRUCTURAL PARAMETERS
    const soclib::common::AddressDecodingTable<vci_addr_t, bool>    m_cacheability_table;
    const soclib::common::Segment                                   m_segment;
    iss_t               m_iss;
    const uint32_t      m_srcid_rw;   
    const uint32_t      m_srcid_c;   
    
    const size_t        m_dcache_ways;
    const size_t        m_dcache_words;
    const uint32_t      m_dcache_words_shift;
    const size_t        m_dcache_yzmask;
    const size_t        m_icache_ways;
    const size_t        m_icache_words;
    const uint32_t      m_icache_words_shift;
    const size_t        m_icache_yzmask;
    const size_t        m_cache_words; // max between m_dcache_words and m_icache_words

#if CC_XCACHE_WRAPPER_STOP_SIMULATION
    bool                m_stop_simulation;
    uint32_t            m_stop_simulation_nb_frz_cycles_max;
    uint32_t            m_stop_simulation_nb_frz_cycles;
#endif // CC_XCACHE_WRAPPER_STOP_SIMULATION

    // REGISTERS
    sc_signal<int>          r_dcache_fsm;
    sc_signal<int>          r_dcache_fsm_save;
    sc_signal<addr_40>      r_dcache_addr_save;
    sc_signal<data_t>       r_dcache_wdata_save;
    sc_signal<data_t>       r_dcache_rdata_save;
    sc_signal<int>          r_dcache_type_save;
    sc_signal<be_t>         r_dcache_be_save;
    sc_signal<bool>         r_dcache_cached_save;
    sc_signal<bool>         r_dcache_cleanup_req;
    sc_signal<addr_40>      r_dcache_cleanup_line;
    sc_signal<bool>         r_dcache_miss_req;
    sc_signal<size_t>       r_dcache_miss_way;
    sc_signal<size_t>       r_dcache_miss_set;
    sc_signal<bool>         r_dcache_unc_req;
    sc_signal<bool>         r_dcache_sc_req;
    sc_signal<bool>         r_dcache_inval_rsp;
    sc_signal<size_t>       r_dcache_update_addr;
    sc_signal<data_64>      r_dcache_ll_data;
    sc_signal<addr_40>      r_dcache_ll_addr;
    sc_signal<bool>         r_dcache_ll_valid;
    sc_signal<bool>         r_dcache_previous_unc;

    sc_signal<int>          r_icache_fsm;
    sc_signal<int>          r_icache_fsm_save;
    sc_signal<addr_40>      r_icache_addr_save;
    sc_signal<bool>         r_icache_miss_req;
    sc_signal<size_t>       r_icache_miss_way;
    sc_signal<size_t>       r_icache_miss_set;
    sc_signal<bool>         r_icache_unc_req;
    sc_signal<bool>         r_icache_cleanup_req;
    sc_signal<addr_40>      r_icache_cleanup_line;
    sc_signal<bool>         r_icache_inval_rsp;
    sc_signal<size_t>       r_icache_update_addr;

    sc_signal<int>          r_vci_cmd_fsm;
    sc_signal<size_t>       r_vci_cmd_min;       
    sc_signal<size_t>       r_vci_cmd_max;       
    sc_signal<size_t>       r_vci_cmd_cpt;       
    sc_signal<bool>         r_vci_cmd_dcache_prior;
      
    sc_signal<int>          r_vci_rsp_fsm;
    sc_signal<bool>         r_vci_rsp_ins_error;    
    sc_signal<bool>         r_vci_rsp_data_error;    
    sc_signal<size_t>       r_vci_rsp_cpt;  
    sc_signal<bool>         r_vci_rsp_ack;

#if CC_XCACHE_WRAPPER_FIFO_RSP
    std::queue<data_t>      r_icache_miss_buf;
    std::queue<data_t>      r_dcache_miss_buf;
#else
    bool                   *r_icache_miss_val;    //[m_icache_words]
    data_t                 *r_icache_miss_buf;    //[m_icache_words]
    bool                   *r_dcache_miss_val;    //[m_dcache_words]
    data_t                 *r_dcache_miss_buf;    //[m_dcache_words]
#endif
    sc_signal<bool>         r_icache_buf_unc_valid;

    data_t                 *r_tgt_buf;            //[m_cache_words]
    be_t                   *r_tgt_be;             //[m_cache_words]
#if CC_XCACHE_WRAPPER_CC_UPDATE_MULTI_CYCLE
    sc_signal<uint32_t>     r_cache_word;
#endif

    sc_signal<int>          r_vci_tgt_fsm;
    sc_signal<addr_40>      r_tgt_addr;
    sc_signal<size_t>       r_tgt_word;
    sc_signal<bool>         r_tgt_update;
    sc_signal<bool>         r_tgt_update_data;
  //sc_signal<bool>         r_tgt_brdcast;
    sc_signal<size_t>       r_tgt_srcid;
    sc_signal<size_t>       r_tgt_pktid;
    sc_signal<size_t>       r_tgt_trdid;
  //sc_signal<size_t>       r_tgt_plen;
    sc_signal<bool>         r_tgt_icache_req;
    sc_signal<bool>         r_tgt_dcache_req;
    sc_signal<bool>         r_tgt_icache_rsp;
    sc_signal<bool>         r_tgt_dcache_rsp;

    sc_signal<int>          r_cleanup_fsm;		// controls initiator port of the coherence network

    MultiWriteBuffer<addr_40>   r_wbuf;
    GenericCache<vci_addr_t>    r_icache;
    GenericCache<vci_addr_t>    r_dcache;

#if CC_XCACHE_WRAPPER_DEBUG_DCACHE_TRANSACTION
    std::ofstream               log_dcache_transaction_file;
#endif

    // Activity counters
    uint32_t m_cpt_dcache_data_read;             // * DCACHE DATA READ
    uint32_t m_cpt_dcache_data_write;            // * DCACHE DATA WRITE
    uint32_t m_cpt_dcache_dir_read;              // * DCACHE DIR READ
    uint32_t m_cpt_dcache_dir_write;             // * DCACHE DIR WRITE
                                                 
    uint32_t m_cpt_icache_data_read;             // * ICACHE DATA READ
    uint32_t m_cpt_icache_data_write;            // * ICACHE DATA WRITE
    uint32_t m_cpt_icache_dir_read;              // * ICACHE DIR READ
    uint32_t m_cpt_icache_dir_write;             // * ICACHE DIR WRITE

    uint32_t m_cpt_cc_update_icache;             // number of coherence update packets (for icache)
    uint32_t m_cpt_cc_update_dcache;             // number of coherence update packets (for dcache)
    uint32_t m_cpt_cc_inval_broadcast;           // number of coherence inval packets
    uint32_t m_cpt_cc_inval_icache;              // number of coherence inval packets
    uint32_t m_cpt_cc_inval_dcache;              // number of coherence inval packets
    uint32_t m_cpt_cc_update_icache_word_useful; // number of valid word in coherence update packets
    uint32_t m_cpt_cc_update_dcache_word_useful; // number of valid word in coherence update packets

    uint32_t m_cpt_frz_cycles;	                 // * number of cycles where the cpu is frozen
    uint32_t m_cpt_total_cycles;	             // total number of cycles 

    uint32_t m_cpt_data_read;                    //   number of data read
    uint32_t m_cpt_data_read_miss;               //   number of data read miss
    uint32_t m_cpt_data_read_uncached;           //   number of data read uncached
    uint32_t m_cpt_data_write;                   //   number of data write
    uint32_t m_cpt_data_write_miss;              //   number of data write miss
    uint32_t m_cpt_data_write_uncached;          //   number of data write uncached
    uint32_t m_cpt_ins_miss;                     // * number of instruction miss

    uint32_t m_cost_write_frz;                   // * number of frozen cycles related to write buffer         
    uint32_t m_cost_data_miss_frz;               // * number of frozen cycles related to data miss
    uint32_t m_cost_unc_read_frz;                // * number of frozen cycles related to uncached read
    uint32_t m_cost_ins_miss_frz;                // * number of frozen cycles related to ins miss

    uint32_t m_cpt_imiss_transaction;            // * number of VCI instruction miss transactions
    uint32_t m_cpt_dmiss_transaction;            // * number of VCI data miss transactions
    uint32_t m_cpt_unc_transaction;              // * number of VCI uncached read transactions
    uint32_t m_cpt_data_write_transaction;       // * number of VCI write transactions

    uint32_t m_cost_imiss_transaction;           // * cumulated duration for VCI IMISS transactions
    uint32_t m_cost_dmiss_transaction;           // * cumulated duration for VCI DMISS transactions
    uint32_t m_cost_unc_transaction;             // * cumulated duration for VCI UNC transactions
    uint32_t m_cost_write_transaction;           // * cumulated duration for VCI WRITE transactions
    uint32_t m_length_write_transaction;         // * cumulated length for VCI WRITE transactions

protected:
    SC_HAS_PROCESS(VciCcXCacheWrapperV4);

public:

    VciCcXCacheWrapperV4(
                       sc_module_name insname,
                       int proc_id,
                       const soclib::common::MappingTable &mtp,
                       const soclib::common::MappingTable &mtc,
                       const soclib::common::IntTab &initiator_index_rw,
                       const soclib::common::IntTab &initiator_index_c,
                       const soclib::common::IntTab &target_index,
                       size_t icache_ways,
                       size_t icache_sets,
                       size_t icache_words,
                       size_t dcache_ways,
                       size_t dcache_sets,
                       size_t dcache_words,
                       size_t wbuf_nwords,
                       size_t wbuf_nlines,
                       size_t wbuf_timeout
                         );

    ~VciCcXCacheWrapperV4();

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

// #if CC_XCACHE_WRAPPER_STOP_SIMULATION
    void stop_simulation (uint32_t);
// #endif // CC_XCACHE_WRAPPER_STOP_SIMULATION

private:

    void transition();
    void genMoore();

    soclib_static_assert((int)iss_t::SC_ATOMIC == (int)vci_param::STORE_COND_ATOMIC);
    soclib_static_assert((int)iss_t::SC_NOT_ATOMIC == (int)vci_param::STORE_COND_NOT_ATOMIC);
};

}}

#endif /* SOCLIB_CABA_VCI_CC_XCACHE_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
