/* -*- c++ -*-
 * File : vci_cc_xcache_wrapper_v4.h
 * Copyright (c) UPMC, Lip6, SoC
 * Authors : Alain GREINER
 * Date : 27/11/2011
 *
 * 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
 */
 
#ifndef SOCLIB_CABA_VCI_CC_XCACHE_WRAPPER_V4_H
#define SOCLIB_CABA_VCI_CC_XCACHE_WRAPPER_V4_H

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

namespace soclib {
namespace caba {

using namespace sc_core;

////////////////////////////////////////////
template<typename vci_param, typename iss_t>
class VciCcXCacheWrapperV4
///////////////////////////////////////////
    : public soclib::caba::BaseModule
{
    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,
        DCACHE_MISS_VICTIM,
        DCACHE_MISS_WAIT,
        DCACHE_MISS_UPDT,
        DCACHE_UNC_WAIT,
        DCACHE_INVAL,
        DCACHE_INVAL_GO,
        DCACHE_SYNC,
        DCACHE_ERROR,
        DCACHE_CC_CHECK,
        DCACHE_CC_INVAL,
        DCACHE_CC_UPDT,
    };

    enum icache_fsm_state_e 
    {
        ICACHE_IDLE,
        ICACHE_MISS_VICTIM,
        ICACHE_MISS_WAIT,
        ICACHE_MISS_UPDT,
        ICACHE_UNC_WAIT,
        ICACHE_ERROR,
        ICACHE_CC_CHECK,
        ICACHE_CC_INVAL,
        ICACHE_CC_UPDT,
    };

    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_cmd_fsm_state_e 
    {
        CLEANUP_DATA_IDLE,
        CLEANUP_INS_IDLE,
        CLEANUP_DATA_GO,
        CLEANUP_INS_GO,
    };

    enum transaction_type_d_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,
    };

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_d;
    soclib::caba::VciInitiator<vci_param>   p_vci_ini_c;
    soclib::caba::VciTarget<vci_param>      p_vci_tgt_c;

private:

    // STRUCTURAL PARAMETERS
    const soclib::common::AddressDecodingTable<vci_addr_t, bool>    	m_cacheability_table;
    const soclib::common::Segment                                   	m_segment;

    const uint32_t       						m_srcid_d;   
    const uint32_t       						m_srcid_c;   
    
    const size_t         						m_dcache_ways;
    const size_t         						m_icache_ways;

    const size_t         						m_cache_words;
    const size_t         						m_cache_words_shift;
    const vci_addr_t     						m_cache_yzmask;

    const uint32_t							    m_max_frozen_cycles;

    iss_t              			    * r_iss; 
    MultiWriteBuffer<vci_addr_t>	* r_wbuf;
    GenericCache<vci_addr_t> 		* r_icache;
    GenericCache<vci_addr_t> 		* r_dcache;

    sc_signal<int>          r_icache_fsm; 
    sc_signal<int>          r_icache_fsm_save;		// return state for coherence request
    sc_signal<vci_addr_t>   r_icache_addr_save;		// address requested by proc
    sc_signal<bool>         r_icache_miss_req;		// set by icache_fsm / reset by cmd_fsm
    sc_signal<bool>         r_icache_unc_req;		// set by icache_fsm / reset by cmd_fsm
    sc_signal<bool>         r_icache_cleanup_req;	// a victim line must be evicted   
    sc_signal<vci_addr_t>   r_icache_cleanup_line;	// address of the selected victim line
    sc_signal<size_t>       r_icache_cleanup_way;	// way of the selected victim line
    sc_signal<size_t>       r_icache_cleanup_set;	// set of the selected victim line
    sc_signal<bool>         r_icache_miss_inval;	// cancellation request for pending miss 
    sc_signal<size_t>       r_icache_update_word;	// word index for update (intern/extern)
    sc_signal<data_t>       r_icache_unc_buf;       // Non cacheable read buffer (one word) 
    sc_signal<bool>	        r_icache_unc_valid;     // Non cacheable read buffer valid
    sc_signal<size_t>       r_icache_cc_way;        // way index for coherence request
    sc_signal<size_t>       r_icache_cc_set;        // set index for coherence request

    sc_signal<int>          r_dcache_fsm;
    sc_signal<int>          r_dcache_fsm_save;		// return state when coherence request
    sc_signal<vci_addr_t>   r_dcache_addr_save;		// address requested by proc
    sc_signal<data_t>       r_dcache_wdata_save;	// data written (for dcache update)
    sc_signal<be_t>         r_dcache_be_save;		// byte enable (for dcache update)
    sc_signal<be_t>         r_dcache_way_save;		// selected way (in case of hit)
    sc_signal<be_t>         r_dcache_set_save;		// selected set (in case of hit)
    sc_signal<be_t>         r_dcache_word_save;		// selected word (in case of hit)
    sc_signal<bool>         r_dcache_cleanup_req;	// a victim line must be evicted
    sc_signal<vci_addr_t>   r_dcache_cleanup_line;	// address of the selected victim line
    sc_signal<size_t>       r_dcache_cleanup_way;	// way of the selected victim line
    sc_signal<size_t>       r_dcache_cleanup_set;	// set of the selected victim line
    sc_signal<bool>         r_dcache_miss_req;		// set by dcache_fsm / reset by cmd_fsm
    sc_signal<bool>         r_dcache_unc_req;		// set by dcache_fsm / reset by cmd_fsm
    sc_signal<bool>         r_dcache_sc_req;		// set by dcache_fsm / reset by cmd_fsm
    sc_signal<bool>         r_dcache_miss_inval;	// cancellation of a pending miss     
    sc_signal<size_t>       r_dcache_update_word;	// word index for update (intern/extern)
    sc_signal<data_t>       r_dcache_ll_data;		// LL reservation data
    sc_signal<vci_addr_t>   r_dcache_ll_addr;		// ll reservation address
    sc_signal<bool>         r_dcache_ll_valid;		// ll reservation valid
    sc_signal<bool>	        r_dcache_pending_unc_write; // Non cacheable write pending
    sc_signal<data_t>       r_dcache_unc_buf;       // Non cacheable read buffer (one word)
    sc_signal<bool>	        r_dcache_unc_valid;     // Non cacheable read buffer valid 
    sc_signal<size_t>       r_dcache_cc_way;        // way index for coherence request
    sc_signal<size_t>       r_dcache_cc_set;        // set index for coherence request
                                                   
    sc_signal<int>          r_vci_cmd_fsm;
    sc_signal<size_t>       r_vci_cmd_min;       	// min word index for a write burst
    sc_signal<size_t>       r_vci_cmd_max;       	// max word index for a write burst
    sc_signal<size_t>       r_vci_cmd_cpt;       
    sc_signal<bool>         r_vci_cmd_imiss_prio;	// round-robin flip-flop to access wbuf

    sc_signal<int>          r_vci_rsp_fsm;
    sc_signal<size_t>       r_vci_rsp_cpt;  
    sc_signal<bool>         r_vci_rsp_ins_error;	// set by rsp_fsm / reset by icache_fsm
    sc_signal<bool>         r_vci_rsp_data_error;	// set by rsp_fsm / reset by dcache_fsm
    GenericFifo<data_t>     r_vci_rsp_fifo_icache;	// response fifo to ICACHE FSM
    GenericFifo<data_t>     r_vci_rsp_fifo_dcache;	// response FIFO to DCACHE FSM

    sc_signal<int>          r_tgt_fsm;			    // target port on coherence network
    sc_signal<bool>         r_tgt_icache_rsp;		// VCI response required when true
    sc_signal<bool>         r_tgt_dcache_rsp;		// VCI response required when true
    sc_signal<vci_addr_t>   r_tgt_addr;			    // address of the target line
    sc_signal<size_t>       r_tgt_word_min;		    // index of the first word to be updated
    sc_signal<size_t>       r_tgt_word_max;		    // index of the last word to be updated
    sc_signal<size_t>       r_tgt_word_count;		// word counter to fill the tgt_buf
    sc_signal<bool>         r_tgt_update;		    // update request when true
    sc_signal<bool>         r_tgt_update_data;  	// update_data request when true
    sc_signal<size_t>       r_tgt_srcid;
    sc_signal<size_t>       r_tgt_pktid;
    sc_signal<size_t>       r_tgt_trdid;
    sc_signal<bool>         r_tgt_icache_req; 		// coherence request to ICACHE
    sc_signal<bool>         r_tgt_dcache_req;		// coherence request to DCACHE
    sc_signal<data_t>     * r_tgt_buf;          	// [m_cache_words]
    sc_signal<be_t>       * r_tgt_be;           	// [m_cache_words]

    sc_signal<int>          r_cleanup_fsm;	        // send cleanup commands
    sc_signal<size_t>       r_cleanup_trdid;        // index for trdid
    GenericCam<vci_addr_t>  r_cleanup_buffer;       // registration buffer for cleanups

    // ISS interface variables (used for communication 
    // between transition() and print_trace() functions
    bool					                m_ireq_valid;
    uint32_t				                m_ireq_addr;
    soclib::common::Iss2::ExecMode		    m_ireq_mode;
	
    bool					                m_irsp_valid;
    uint32_t				                m_irsp_instruction;
    bool					                m_irsp_error;
	
    bool					                m_dreq_valid;
    uint32_t				                m_dreq_addr;
    soclib::common::Iss2::ExecMode		    m_dreq_mode;
    soclib::common::Iss2::DataOperationType	m_dreq_type;
    uint32_t					            m_dreq_wdata;
    uint8_t					                m_dreq_be;

    bool					                m_drsp_valid;
    uint32_t					            m_drsp_rdata;
    bool					                m_drsp_error;

    // Activity counters (for power consumption evaluation)
    uint32_t   m_conso_dcache_data_read;           // DCACHE DATA READ activity
    uint32_t   m_conso_dcache_data_write;          // DCACHE DATA WRITE activity
    uint32_t   m_conso_dcache_dir_read;            // DCACHE DIR READ activity
    uint32_t   m_conso_dcache_dir_write;           // DCACHE DIR WRITE activity
                                                  
    uint32_t   m_conso_icache_data_read;           // ICACHE DATA READ activity
    uint32_t   m_conso_icache_data_write;          // ICACHE DATA WRITE activity
    uint32_t   m_conso_icache_dir_read;            // ICACHE DIR READ activity
    uint32_t   m_conso_icache_dir_write;           // ICACHE DIR WRITE activity
               
    uint32_t   m_conso_wbuf_read;		           // WBUF READ activity
    uint32_t   m_conso_wbuf_write;		           // WBUF WRITE activity

    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_icache;              // number of coherence inval packets	for icache
    uint32_t   m_cpt_cc_inval_dcache;              // number of coherence inval packets for dcache
    uint32_t   m_cpt_cc_inval_broadcast;           // number of coherence broadcast packets
               
    uint32_t   m_cpt_frz_cycles;	               // total number of cpu frozen cycles
    uint32_t   m_cpt_total_cycles;	               // total number of cycles from reset
    uint32_t   m_cpt_stop_simulation;	   	       // consecutive frozen cycles counter 
               
    uint32_t   m_cpt_ins_cacheable;                // number of cacheable instructions 
    uint32_t   m_cpt_ins_uncacheable;              // number of non cacheable instructions
    uint32_t   m_cpt_ins_miss;                     // number of cacheable instruction miss
               
    uint32_t   m_cpt_data_read_cacheable;          // number of cacheable data read
    uint32_t   m_cpt_data_read_miss;               // number of cacheable data read miss
    uint32_t   m_cpt_data_read_uncacheable;        // number of non cacheable data read 
    uint32_t   m_cpt_data_write_cacheable;         // number of cacheable write
    uint32_t   m_cpt_data_write_uncacheable;       // number of non cacheable write
    uint32_t   m_cpt_data_write_hit;               // number of cacheable write making hit
    uint32_t   m_cpt_data_ll;			           // number of LL requests
    uint32_t   m_cpt_data_sc;			           // number of SC requests

    uint32_t   m_cpt_xtn_dcache_inval;		       // dcache line invalidation request
    uint32_t   m_cpt_xtn_sync;		               // write buffer flush request

    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_ins_miss_frz;                // number of frozen cycles related to ins miss
               
    uint32_t   m_cpt_imiss_transaction;            // number of VCI inst read miss transactions
    uint32_t   m_cpt_dmiss_transaction;            // number of VCI data read miss transactions
    uint32_t   m_cpt_iunc_transaction;             // number of VCI uncacheable inst read transactions
    uint32_t   m_cpt_dunc_transaction;             // number of VCI uncacheable data read transactions
    uint32_t   m_cpt_write_transaction;            // number of VCI write transactions
    uint32_t   m_cpt_sc_transaction;               // number of VCI sc 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


    uint32_t * m_cpt_fsm_dcache;  		   // array of number of cycles per state
    uint32_t * m_cpt_fsm_icache; 		   // array of number of cycles per state
    uint32_t * m_cpt_fsm_cmd;			   // array of number of cycles per state
    uint32_t * m_cpt_fsm_rsp;			   // array of number of cycles per state
    uint32_t * m_cpt_fsm_tgt;			   // array of number of cycles per state
    uint32_t * m_cpt_fsm_cleanup;		   // array of number of cycles per state

protected:
    SC_HAS_PROCESS(VciCcXCacheWrapperV4);

public:

    VciCcXCacheWrapperV4(
                       sc_module_name 				insname,
                       int 					proc_id,
                       const soclib::common::MappingTable 	&mtd,
                       const soclib::common::MappingTable 	&mtc,
                       const soclib::common::IntTab 		&initiator_index_d,
                       const soclib::common::IntTab 		&initiator_index_c,
                       const soclib::common::IntTab 		&target_index_c,
                       size_t 					icache_ways,
                       size_t 					icache_sets,
                       size_t 					icache_words,
                       size_t 					dcache_ways,
                       size_t 					dcache_sets,
                       size_t 					dcache_words,
                       size_t 					wbuf_nwords,
                       size_t 					wbuf_nlines,
                       uint32_t					max_frozen_cycles = 1000);

    ~VciCcXCacheWrapperV4();

    void print_trace(size_t mode = 0);
    void print_cpi();
    void print_stats(bool print_wbuf=true, bool print_fsm=true);

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