/*
 * 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 "generic_fifo.h"
#include "my_interfaces.h"

SC_MODULE(MT_Ctrl)
{

public:
  sc_in<bool>                         p_clk;
  sc_in<bool>                         p_resetn;

  sc_in<uint32_t>                     p_b_address;
  sc_in<uint32_t>                     p_mb_address;
  sc_in<uint32_t>                     p_size;

  //input inteface
  INTEGRITY_CTRL_CMD_IN               cmd_in;
  INTEGRITY_CTRL_ACK_OUT              ack_out;
  //ht cache controller if
  CACHE_CTRL_CMD_OUT                  hash_out_cmd;
  DATA_OUT<2>                         hash_out_wdata;
  CACHE_CTRL_ACK_IN                   hash_in_ack;
  DATA_IN<2>                          hash_in_rdata;
  //security context if
  SECURITY_CTX_CMD_OUT                sc_out_cmd;
  DATA_OUT<2>                         sc_out_wdata;
  //read security context registers
  CTX_REGISTER_READ_IN                sc_register_in;
  MASTER_CTX_REG_READ_IN              master_sc_reg_in;
  MASTER_CTX_REG_READ_OUT             master_sc_reg_out;
  //hash generator if
  CRYPTO_CMD_OUT                      hash_generator_out_cmd;
  DATA_OUT<12>                        hash_generator_out_data;
  DATA_IN<2>                          hash_generator_in_data;
  DATA_REGISTER_READ_IN               register_0_in;
  //register 1
  DATA_REGISTER_READ_IN               register_1_in;
  //register 2
  DATA_REGISTER_READ_IN               register_2_in;
  //memory interface for initialisation
  MEMORY_CTRL_CMD_OUT                 memory_out_cmd;
  DATA_OUT<2>                         memory_out_wdata;

  IRQ_OUT                             irq;

  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
    I_WAIT_INTERRUPT
  };
  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,
    C_WAIT_INTERRUPT
  };

  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,
    U_WAIT_INTERRUPT
  };
  //internal signals
  sc_signal<int> initialize_state;
  sc_signal<int> check_state;
  sc_signal<int> 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<size_t> 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;
  sc_signal<bool> write_master_hv_s;
  sc_signal<bool> is_init_s;
  sc_signal<uint32_t> src_s;

  uint32_t *check_register_s;
  uint32_t *rhv_s;
  uint32_t *hash_s;
  uint32_t *new_hash_s;
  uint32_t *reference_hash_s;
  pspe_t new_spspe_s;
  uint32_t *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;

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

  void print_stats();
  void reset_stats();

  uint32_t cycle;

  //Constructor
  MT_Ctrl(sc_module_name name);

  SC_HAS_PROCESS(MT_Ctrl);

};

#endif
