/*
 * SecBus - This file is part of SecBus
 * Copyright (C) 2012 - Telecom ParisTech
 * 
 * This file must be used under the terms of the CeCILL.
 * This source file is licensed as described in the file COPYING, which
 * you should have received as part of this distribution.  The terms
 * are also available at    
 * http://www.cecill.info/licences/Licence_CeCILL_V1.1-US.txt
 *
 */


#ifndef _HASHCONTROLLER_H_
#define _HASHCONTROLLER_H_

#include "secbus_lib.h"
#include <systemc>
#include "types.h"
#include "cryptolib.h"
#include "generic_fifo.h"
#include "my_interfaces.h"




SC_MODULE(HashTreeController)
{

  public:

    sc_in<bool>                         clk;
    sc_in<bool>                         reset;
    //input inteface
    INTEGRITY_CONTROLLER_CMD_IN         cmd_in;
    INTEGRITY_CONTROLLER_ACK_OUT        ack_out;
    //ht cache controller if
    CACHE_CONTROLLER_CMD_OUT            hash_out_cmd;
    DATA_OUT<2>                         hash_out_wdata;
    CACHE_CONTROLLER_ACK_IN             hash_in_ack;
    DATA_IN<2>                          hash_in_rdata;
    //security context if
    SECURITY_CONTEXT_CMD_OUT            sc_out_cmd;
    DATA_OUT<2>                         sc_out_wdata;
    ACK_IN                              sc_in_ack;
    //read security context registers
    SECURITY_CONTEXT_REGISTER_READ_OUT  sc_register_in;
    //hash generator if
    CRYPTOGRAPHIC_ENGINE_CMD_OUT        hash_generator_out_cmd;
    DATA_OUT<12>                        hash_generator_out_data;
    DATA_OUT<2>                         hash_generator_out_iv;
    sc_in<bool>                         hash_generator_in_ack;
    DATA_IN<2>                          hash_generator_in_data;
    //register 1
    DATA_REGISTER_READ_IN               register_1_in;
    //register 2
    DATA_REGISTER_READ_IN               register_2_in;
    //memory interface for initialisation
    MEMORY_CONTROLLER_CMD_OUT           memory_out_cmd;
    DATA_OUT <2>                        memory_out_wdata;
    ACK_IN                              memory_in_ack;

    enum htc_init_mht
    {
      MHT_IDLE = 0,
      MHT_INIT,
      MHT_READ_SET,
      MHT_WAIT_READ_SET,
      MHT_HASH_GEN,
      MHT_WAIT_HASH_GEN,
      MHT_WRITE_REF,
      MHT_WAIT_WRITE_REF,
      MHT_READ_LAST_LEVEL,
      MHT_WAIT_READ_LAST_LEVEL,
      MHT_READ_LAST_LEVEL2,
      MHT_WAIT_READ_LAST_LEVEL2,
      MHT_HASH_LAST_LEVEL,
      MHT_WAIT_HASH_LAST_LEVEL
    };
    enum htc_initialize_step_e
    {
      HTI_IDLE = 0,
      I_START_WRITE_NULL_BROTHER,
      I_WAIT_WRITE_NULL_BROTHER,//2
      I_START_RESTORE_BROTHER,
      I_WAIT_RESTORE_BROTHER,
      I_START_CHECK_LAST_SET,
      I_WAIT_CHECK_LAST_SET,
      I_START_READ_SET,
      I_START_IV_GENERATION,//8
      I_WAIT_IV_GENERATION,
      I_WAIT_LAST_IV_GENERATION,
      I_START_UPDATE_LEAVE_PARENT,
      I_WAIT_UPDATE_LEAVE_PARENT,//12
      I_START_UPDATE_PARENT_M,
      I_WAIT_UPDATE_PARENT_M,
      I_START_UPDATE_ROOT_M,
      I_WAIT_UPDATE_ROOT_M,//16
      I_START_WRITE_PSPE,
      I_WAIT_WRITE_PSPE,
      I_INTEGRITY_ERROR//20
    };
    enum htc_check_step_e
    {
      HTC_IDLE = 0,
      C_START_IV_GENERATION,
      C_START_HASH_GENERATION,
      C_WAIT_HASH_GENERATION,
      C_START_READ_REFERENCE_PARENT,
      C_START_CHECK_REFERENCE_PARENT,
      C_WAIT_READ_REFERENCE_PARENT,
      C_START_LAST_IC,//2
      C_WAIT_LAST_IC,
      C_START_RESTORE_REFERENCE_PARENT_BROTHERS,//5
      C_WAIT_RESTORE_REFERENCE_PARENT_BROTHERS,
      C_INTEGRITY_ERROR,

    };
    enum htc_update_step_e
    {
      HTU_IDLE = 0,
      U_START_PARENT_UPDATE,
      U_WAIT_PARENT_UPDATE,//2
      U_START_WRITE_NEW_PARENT,
      U_WAIT_WRITE_NEW_PARENT,//4
      U_START_READ_SLAVE_PSPE,
      U_WAIT_READ_SLAVE_PSPE,//6
      U_START_READ_VICTIM_SET,
      U_WAIT_READ_VICTIM_HASH_SET,//8
      U_START_NEW_HASH_GENERATION,
      U_WAIT_NEW_HASH_GENERATION,//10
      U_START_RESTORE_DIRTY_VICTIM_BROTHERS,
      U_WAIT_RESTORE_DIRTY_VICTIM_BROTHERS,//12
      U_START_READ_REFERENCE_PARENT,
      U_WAIT_READ_REFERENCE_PARENT,//14
      U_START_LAST_IC,
      U_WAIT_LAST_IC,//16
      U_START_SYNCHRONIZE_DIRTY_VICTIM_BROTHERS,
      U_WAIT_SYNCHRONIZE_DIRTY_VICTIM_BROTHERS,//18
      U_START_WRITE_PSPE,//19
      U_WAIT_WRITE_PSPE,
      U_START_RESTORE_REFERENCE_PARENT_BROTHERS,//21
      U_WAIT_RESTORE_REFERENCE_PARENT_BROTHERS,
      U_INTEGRITY_ERROR
    };
    //internal signals
    sc_signal<htc_init_mht> init_mht;
    sc_signal<htc_initialize_step_e> initialize_state;
    sc_signal<htc_check_step_e> check_state;
    sc_signal<htc_update_step_e> update_state;
    sc_signal<addr_t> victim_address_s;
    sc_signal<addr_t> set_address_s;
    sc_signal<addr_t> brother_address_s;
    sc_signal<addr_t> restore_address_s;
    sc_signal<addr_t> synchronize_address_s;
    sc_signal<addr_t> ht_start_address_s;
    sc_signal<addr_t> r_parent_address_s;
    sc_signal<addr_t> w_parent_address_s;
    sc_signal<addr_t> mb_size_s;
    sc_signal<PageSize_e> ht_page_size_s;
    sc_signal<addr_t> mb_address;
    sc_signal<bool> master_tree_s;
    sc_signal<bool> leaves_s;
    sc_signal<unsigned int> brother_cpt_s;
    sc_signal<unsigned int> hit_cpt_s;
    sc_signal<unsigned int> index_s;
    sc_signal<unsigned int> level_s;
    sc_signal<unsigned int> 	state_s;

    int *check_register_s;
    int *rhv_s;
    int *hash_s;
    int *new_hash_s;
    int *reference_hash_s;
    int *new_spspe_s;
    int *M;

    //Synchronous process
    void ps();
    //Conbinatory process
    void pc();

    //Fifo for restore and synchronize addresses storage
    GenericFifo<addr_t>  * restore_fifo;
    GenericFifo<addr_t>  * synchronize_fifo;

    ofstream *soutput;
    ofstream *doutput;

    // cycle counters
    unsigned long int m_cpt_c;
    unsigned long int m_cpt_u;
    unsigned long int hash_count;

    void print_stats(ofstream & file);
    void reset_stats();


    //Constructor
    HashTreeController(sc_module_name name, ofstream * dfile, ofstream * sfile);

    SC_HAS_PROCESS(HashTreeController);

};

#endif

/*   sc_trace (TRACEFILE, secbus->hash_tree_controller.init_mht, "init_mht");
   sc_trace (TRACEFILE, secbus->hash_tree_controller.initialize_state, "initialize_state");
   sc_trace (TRACEFILE, secbus->hash_tree_controller.check_state, "check_state");
   sc_trace (TRACEFILE, secbus->hash_tree_controller.update_state, "update_state");
   sc_trace (TRACEFILE, secbus->hash_tree_controller.victim_address_s, "victim_address_s");
   sc_trace (TRACEFILE, secbus->hash_tree_controller.set_address_s, "set_address_s");
   sc_trace (TRACEFILE, secbus->hash_tree_controller.brother_address_s, "brother_address_s");
   sc_trace (TRACEFILE, secbus->hash_tree_controller.restore_address_s, "restore_address_s");
   sc_trace (TRACEFILE, secbus->hash_tree_controller.synchronize_address_s, "synchronize_address_s");
   sc_trace (TRACEFILE, secbus->hash_tree_controller.ht_start_address_s, "ht_start_address_s");
   sc_trace (TRACEFILE, secbus->hash_tree_controller.r_parent_address_s, "r_parent_address_s");
   sc_trace (TRACEFILE, secbus->hash_tree_controller.w_parent_address_s, "w_parent_address_s");
   sc_trace (TRACEFILE, secbus->hash_tree_controller.mb_size_s, "mb_size_s");
   sc_trace (TRACEFILE, secbus->hash_tree_controller.ht_page_size_s, "ht_page_size_s");
   sc_trace (TRACEFILE, secbus->hash_tree_controller.mb_address, "mb_address");
   sc_trace (TRACEFILE, secbus->hash_tree_controller.master_tree_s, "master_tree_s");
   sc_trace (TRACEFILE, secbus->hash_tree_controller.leaves_s, "leaves_s");
   sc_trace (TRACEFILE, secbus->hash_tree_controller.brother_cpt_s, "brother_cpt_s");
   sc_trace (TRACEFILE, secbus->hash_tree_controller.hit_cpt_s, "hit_cpt_s");
   sc_trace (TRACEFILE, secbus->hash_tree_controller.index_s, "index_s");
   sc_trace (TRACEFILE, secbus->hash_tree_controller.level_s, "level_s");
   sc_trace (TRACEFILE, secbus->hash_tree_controller.m_cpt_c, "m_cpt_c");
   sc_trace (TRACEFILE, secbus->hash_tree_controller.m_cpt_u, "m_cpt_u");
   sc_trace (TRACEFILE, secbus->hash_tree_controller.hash_count, "hash_count");*/
