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

#include "../include/vci_secbus.h"
#include <stdlib.h>
#include <iostream>
#include <iomanip>


//PSPE
unsigned int PSPE_BASE_ADDRESS	;
unsigned int PSPE_BLOCK_SIZE	= 0x800000;
unsigned int PSPE_END_ADDRESS	;
unsigned int PSPE_SIZE		= 2;
unsigned int PSPE_SIZE_IN_BYTES = PSPE_SIZE * sizeof(int);
//SP
unsigned int SP_BASE_ADDRESS	;
unsigned int SP_BLOCK_SIZE	= 0x400000;
unsigned int SP_END_ADDRESS	;
unsigned int SP_SIZE		= 4;
unsigned int SP_SIZE_IN_BYTES	= SP_SIZE * sizeof(int);
//SC
unsigned int SC_SIZE 		= 10;
//Tree levels
unsigned int MAX_TREE_LEVEL	= 10;
//Master HT
unsigned int MHT_BASE_ADDRESS	;
unsigned int MHT_BLOCK_SIZE	= 0x400000; 
unsigned int MHT_END_ADDRESS	;
//DES latency
unsigned int DES_L		= 4;
//Useful sizes
unsigned int SIZE_64_IN_WORDS	= 2;
unsigned int SIZE_64_IN_BYTES	= SIZE_64_IN_WORDS * sizeof(int);
unsigned int SIZE_256_IN_WORDS	= 8;
unsigned int SIZE_256_IN_BYTES	= SIZE_256_IN_WORDS * sizeof(int);
//MAC input size
unsigned int MS_SIZE		= SIZE_256_IN_WORDS;
unsigned int MS_SIZE_IN_BYTES	= MS_SIZE * sizeof(int);
//MAC output size
unsigned int MAC_ARITY		= MS_SIZE/SIZE_64_IN_WORDS ;
//Hash input size
unsigned int HS_SIZE		= SIZE_256_IN_WORDS;
unsigned int LAST_HS_SIZE	= 12;
unsigned int HS_SIZE_IN_BYTES	= HS_SIZE * sizeof(int);
unsigned int LAST_HS_SIZE_IN_BYTES = LAST_HS_SIZE * sizeof(int);
//Hash output size
unsigned int HASH_ARITY		= HS_SIZE/SIZE_64_IN_WORDS;
unsigned int LAST_HASH_ARITY	= LAST_HS_SIZE/SIZE_64_IN_WORDS;
//Master KEY and HV root
int MASTER_HV[2] = {0, 0};
int MASTER_KEY[4]= {0, 1, 2, 3};
//cycle counter
unsigned long int m;

namespace soclib {
  namespace caba {

#define tmpl(x) template<typename vci_param> x vci_secbus<vci_param>

    tmpl(/**/)::vci_secbus(
        sc_module_name name,
        const MappingTable &mt,
        const IntTab &tgtid)
      : 
        soclib::caba::BaseModule(name), 
        p_clk("clk"), 
        p_resetn("resetn"), 
        p_vci_target("p_vci_target"),
        p_vci_initiator("p_vci_initiator"),
        p_vci_io_target("p_vci_io_target"), 
        m_vci_target_fsm(p_vci_io_target, mt.getSegmentList(tgtid)),
        security_controller("security_controller", &debug_info), 
        register_0_mux("register_0_mux"),
        register_0("register_0", &debug_info), 
        register_1_mux("register_1_mux"),
        register_1("register_1", &debug_info), 
        register_2("register_2", &debug_info),
        hash_tree_controller_mux("hash_tree_controller_mux"),
        hash_tree_controller("hash_tree_controller", &debug_info, &stat_info), 
        cipher_block_chaining_mux("cipher_block_chaining_mux"),
        cipher_block("cipher_block"),
        cipher_block_chaining("cipher_block_chaining"),
        memory_controller_mux("memory_controller_mux"),
        mac_controller_mux("mac_controller_mux") 
    {
      addr_t mb_base_address = 0;
      reset_cpt_address = 0;


      const std::list<soclib::common::Segment> seglist = mt.getAllSegmentList();
      std::list<soclib::common::Segment>::const_iterator seg = seglist.begin();
      while ( seg != seglist.end()) {
        if ( seg->name() ==  std::string("masterblock") )
          mb_base_address = seg->baseAddress();
        else if ( seg->name() == std::string("reset_cpt") )
          reset_cpt_address = seg->baseAddress();
        ++seg;
      }
      if (mb_base_address == 0 || reset_cpt_address == 0)
      {
        _secbus_debug(cerr, NONE, "error: you should define mb_base_address and reset_cpt_address"<<"\n");
        exit(0);
      }

      m=0;

      //PSPE
      PSPE_BASE_ADDRESS	= mb_base_address;
      PSPE_END_ADDRESS	= PSPE_BASE_ADDRESS + PSPE_BLOCK_SIZE;
      //SP
      SP_BASE_ADDRESS	= PSPE_END_ADDRESS;
      SP_END_ADDRESS	= SP_BASE_ADDRESS + SP_BLOCK_SIZE;
      //Master HT
      MHT_BASE_ADDRESS	= SP_END_ADDRESS;
      MHT_END_ADDRESS	= MHT_BASE_ADDRESS + MHT_BLOCK_SIZE;

      m_vci_target_fsm.on_read_write(on_read, on_write);

      //Files used to store input/output requests control signals and some statistics
      dump_in.open("dump_in.txt");
      dump_out.open("dump_out.txt");
      debug_info.open("debug_info.txt");
      stat_info.open("stat_info.txt");

      setvbuf(stdout, NULL, _IONBF, 0); 
      //SECBUS CACHE PARAMETERS//

      //PSPE cache
      strcpy(pspe_cache.name,"PSPE");
      pspe_cache.enable = true;
      pspe_cache.associativity = 4;
      pspe_cache.block_size = PSPE_SIZE;
      pspe_cache.replacement_policy = FIFO;
      pspe_cache.set_number = 1;
      pspe_cache.write_policy = WRITE_THROUGH;
      //SP Cache
      strcpy(sp_cache.name,"SP");
      sp_cache.enable = true;
      sp_cache.associativity = 2;
      sp_cache.block_size = SP_SIZE;
      sp_cache.replacement_policy = FIFO;
      sp_cache.set_number = 4;
      sp_cache.write_policy = WRITE_THROUGH;
      //Mac Cache
      strcpy(mac_cache.name,"MAC");
      mac_cache.enable = true;
      mac_cache.associativity = 4;
      mac_cache.block_size = SIZE_64_IN_WORDS;
      mac_cache.replacement_policy = FIFO;
      mac_cache.set_number = 32;
      mac_cache.write_policy = WRITE_BACK;
      //HASH Cache
      strcpy(hash_cache.name,"HASH");
      hash_cache.enable = true;
      hash_cache.associativity = 4;
      hash_cache.block_size = SIZE_64_IN_WORDS;
      hash_cache.replacement_policy = FIFO;
      hash_cache.set_number = 16;
      hash_cache.write_policy = WRITE_THROUGH;
      hash_cache.threshold = hash_cache.associativity/2;

      //Security Context controller
      security_context_controller = new SecurityContextController("security_context_controller", pspe_cache, sp_cache, &debug_info, &stat_info); 
      //cache controllers instantiation
      mac_cache_controller	= new MacCacheController	("mac_cache_controller", mac_cache, &debug_info);
      hash_cache_controller	= new HashCacheController	("hash_cache_controller", hash_cache, &debug_info);
      //instanciation of mac controller
      mac_controller          = new MacController("mac_controller", &debug_info, mac_cache.enable);
      _secbus_debug(cout, NONE, "BUILDING SECBUS ..."<<"\n");

      //netlist
      //security controller
      security_controller.clk			(p_clk);
      security_controller.reset			(p_resetn);
      security_controller.cb_out_cmd		(cb_cmd_sig);
      security_controller.cb_out_data		(cb_data_in_sig);
      security_controller.cb_in_ack		(cb_ack_sig);
      security_controller.cb_in_data		(cb_data_out_sig);
      security_controller.in			(security_controller_regular_sig);
      security_controller.mb_in_cmd		(mb_controller_cmd_sig);
      security_controller.mb_in_wdata		(mb_controller_wdata_sig);
      security_controller.mb_out_ack		(mb_controller_ack_sig);
      security_controller.mb_out_rdata		(mb_controller_rdata_sig);
      security_controller.sc_register		(sc_register_read_sig);
      security_controller.out_cmd		(memory_security_controller_cmd_sig);
      security_controller.in_ack		(memory_ack_sig);
      security_controller.mac_cmd_out		(mac_controller_cmd_1_sig);
      security_controller.hash_cmd_out		(hash_controller_cmd_1_sig);
      security_controller.mac_ack_in		(mac_controller_ack_sig);
      security_controller.hash_ack_in		(hash_controller_ack_sig);
      security_controller.register_0_in		(register_0_out_sig);
      security_controller.register_0_out	(register_0_in_security_controller_sig);
      security_controller.register_1_in		(register_1_out_sig);
      security_controller.register_1_out	(register_1_in_security_controller_sig);
      //security context controller
      security_context_controller->clk		(p_clk);
      security_context_controller->reset 	(p_resetn);
      security_context_controller->out_ack	(sc_controller_ack_sig);
      security_context_controller->reg_in_cmd	(sc_controller_regular_cmd_sig);
      security_context_controller->reg_in_data	(sc_controller_regular_data_sig);
      security_context_controller->htm_in_cmd	(sc_controller_ht_cmd_sig);
      security_context_controller->htm_in_data	(sc_controller_ht_data_sig);
      security_context_controller->sc_out_cmd 	(mb_controller_cmd_sig);
      security_context_controller->sc_out_wdata (mb_controller_wdata_sig);
      security_context_controller->sc_in_ack 	(mb_controller_ack_sig);
      security_context_controller->sc_in_rdata 	(mb_controller_rdata_sig);
      security_context_controller->scr_out 	(sc_register_read_sig);
      //hash tree controller
      hash_tree_controller.clk			(p_clk);
      hash_tree_controller.reset		(p_resetn);
      hash_tree_controller.cmd_in		(hash_controller_cmd_sig);
      hash_tree_controller.ack_out		(hash_controller_ack_sig);
      hash_tree_controller.sc_register_in	(sc_register_read_sig);
      hash_tree_controller.hash_out_cmd		(hash_cache_cmd_sig);
      hash_tree_controller.hash_out_wdata	(hash_cache_wdata_sig);
      hash_tree_controller.hash_in_ack		(hash_cache_ack_sig);
      hash_tree_controller.hash_in_rdata	(hash_cache_rdata_sig);
      hash_tree_controller.sc_out_cmd		(sc_controller_ht_cmd_sig);
      hash_tree_controller.sc_out_wdata		(sc_controller_ht_data_sig);
      hash_tree_controller.sc_in_ack		(sc_controller_ack_sig);
      hash_tree_controller.register_1_in	(register_1_out_sig);
      hash_tree_controller.register_2_in	(register_2_out_sig);
      hash_tree_controller.hash_generator_out_cmd(hash_cmd_sig);
      hash_tree_controller.hash_generator_out_data(hash_data_in_sig);
      hash_tree_controller.hash_generator_out_iv(hash_iv_sig);
      hash_tree_controller.hash_generator_in_ack(cbc_ack_sig);
      hash_tree_controller.hash_generator_in_data(cbc_data_out_sig);
      hash_tree_controller.memory_out_cmd	(memory_ht_controller_cmd_sig);
      hash_tree_controller.memory_out_wdata	(memory_ht_controller_data_sig);
      hash_tree_controller.memory_in_ack	(memory_ack_sig);
      //mac controller
      mac_controller->clk			(p_clk);
      mac_controller->reset			(p_resetn);
      mac_controller->cmd_in			(mac_controller_cmd_sig);
      mac_controller->ack_out			(mac_controller_ack_sig);
      mac_controller->sc_register		(sc_register_read_sig);
      mac_controller->cache_out_cmd		(mac_cache_cmd_sig);
      mac_controller->cache_out_wdata		(mac_cache_wdata_sig);
      mac_controller->cache_in_ack		(mac_cache_ack_sig);
      mac_controller->cache_in_rdata		(mac_cache_rdata_sig);
      mac_controller->mac_generator_out_cmd	(mac_cmd_sig);
      mac_controller->mac_generator_out_data	(mac_data_in_sig);
      mac_controller->mac_generator_out_iv	(mac_iv_sig);
      mac_controller->mac_generator_in_ack	(cbc_ack_sig);
      mac_controller->mac_generator_in_data	(cbc_data_out_sig);
      mac_controller->register_1_in		(register_1_out_sig);
      mac_controller->register_2_in		(register_2_out_sig);
      mac_controller->memory_out_cmd		(memory_mac_controller_cmd_sig);
      mac_controller->memory_out_wdata		(memory_mac_controller_data_sig);
      mac_controller->memory_in_ack		(memory_ack_sig);
      //cache controller
      //mac
      mac_cache_controller->clk			(p_clk);
      mac_cache_controller->reset		(p_resetn);
      mac_cache_controller->in_cmd		(mac_cache_cmd_sig);
      mac_cache_controller->in_wdata		(mac_cache_wdata_sig);
      mac_cache_controller->out_ack		(mac_cache_ack_sig);
      mac_cache_controller->out_rdata		(mac_cache_rdata_sig);
      mac_cache_controller->out_cmd		(memory_mac_cache_cmd_sig);
      mac_cache_controller->out_wdata		(memory_mac_cache_data_sig);
      mac_cache_controller->in_ack		(memory_ack_sig);
      mac_cache_controller->register_2_in	(register_2_out_sig);
      //hash
      hash_cache_controller->clk		(p_clk);
      hash_cache_controller->reset		(p_resetn);
      hash_cache_controller->in_cmd		(hash_cache_cmd_sig);
      hash_cache_controller->in_wdata		(hash_cache_wdata_sig);
      hash_cache_controller->out_ack		(hash_cache_ack_sig);
      hash_cache_controller->out_rdata		(hash_cache_rdata_sig);
      hash_cache_controller->out_cmd		(memory_hash_cache_cmd_sig);
      hash_cache_controller->out_wdata		(memory_hash_cache_data_sig);
      hash_cache_controller->in_ack		(memory_ack_sig);
      hash_cache_controller->register_2_in	(register_2_out_sig);
      //cryptographic engines
      cipher_block.clk				(p_clk);
      cipher_block.reset			(p_resetn);
      cipher_block.in_cmd			(cb_cmd_sig);
      cipher_block.in_data			(cb_data_in_sig);
      cipher_block.out_ack			(cb_ack_sig);
      cipher_block.out_data			(cb_data_out_sig);
      cipher_block_chaining.clk			(p_clk);
      cipher_block_chaining.reset		(p_resetn);
      cipher_block_chaining.in_cmd		(cbc_cmd_sig);
      cipher_block_chaining.in_data		(cbc_data_in_sig);
      cipher_block_chaining.in_iv		(cbc_iv_sig);
      cipher_block_chaining.out_ack		(cbc_ack_sig);
      cipher_block_chaining.out_data		(cbc_data_out_sig);
      //mux
      cipher_block_chaining_mux.mac_cmd		(mac_cmd_sig);
      cipher_block_chaining_mux.mac_data	(mac_data_in_sig);
      cipher_block_chaining_mux.mac_iv		(mac_iv_sig);
      cipher_block_chaining_mux.hash_cmd	(hash_cmd_sig);
      cipher_block_chaining_mux.hash_data	(hash_data_in_sig);
      cipher_block_chaining_mux.hash_iv		(hash_iv_sig);
      cipher_block_chaining_mux.out_cmd		(cbc_cmd_sig);
      cipher_block_chaining_mux.out_data	(cbc_data_in_sig);
      cipher_block_chaining_mux.out_iv		(cbc_iv_sig);
      //hash tree controller mux
      hash_tree_controller_mux.out		(hash_controller_cmd_sig);
      hash_tree_controller_mux.in1		(hash_controller_cmd_1_sig);
      hash_tree_controller_mux.in2		(hash_controller_cmd_2_sig);
      //mac controller mux
      mac_controller_mux.out			(mac_controller_cmd_sig);
      mac_controller_mux.in1			(mac_controller_cmd_1_sig);
      mac_controller_mux.in2			(mac_controller_cmd_2_sig);
      //memory controller mux
      memory_controller_mux.security_controller_cmd		(memory_security_controller_cmd_sig);
      memory_controller_mux.hash_cache_controller_cmd		(memory_hash_cache_cmd_sig);
      memory_controller_mux.hash_tree_controller_cmd		(memory_ht_controller_cmd_sig);
      memory_controller_mux.mac_controller_cmd			(memory_mac_controller_cmd_sig);
      memory_controller_mux.mac_cache_controller_cmd		(memory_mac_cache_cmd_sig);
      memory_controller_mux.memory_out_cmd			(initiator_cmd_in_sig);
      //data register mux's	
      register_0_mux.in1			(register_0_in_target_sig);
      register_0_mux.in2			(register_0_in_security_controller_sig);
      register_0_mux.in3			(register_0_in_initiator_sig);
      register_0_mux.out			(register_0_in_sig);
      register_1_mux.in1			(register_1_in_initiator_sig);
      register_1_mux.in2			(register_1_in_security_controller_sig);
      register_1_mux.out			(register_1_in_sig);
      //data registers
      register_0.clk				(p_clk);
      register_0.reset				(p_resetn);
      register_0.in				(register_0_in_sig);
      register_0.out				(register_0_out_sig);
      register_1.clk				(p_clk);
      register_1.reset				(p_resetn);
      register_1.in				(register_1_in_sig);
      register_1.out				(register_1_out_sig);
      register_2.clk				(p_clk);
      register_2.reset				(p_resetn);
      register_2.in				(register_2_in_initiator_sig);
      register_2.out				(register_2_out_sig);


      SC_METHOD(ps);
      dont_initialize();
      sensitive << p_clk.pos();

      SC_METHOD(pc);
      dont_initialize();
      sensitive << p_clk.neg();
	
      _secbus_debug(cout, NONE, "SECBUS BUILT"<<"\n");
    }


    tmpl(/**/)::~vci_secbus()
    {
      dump_in.close();
      dump_out.close();
    }

    tmpl(void)::print_stats()
    {
      //Print number of cycle,
      _secbus_debug(debug_info, NONE, "CYCLE"<<"\n");
      _secbus_debug(debug_info, NONE, dec<< dec<< "- CYCLE NUMBER	= " <<m<<"\n");
      //Print number of accesses/misses in security context register
      _secbus_debug(debug_info, NONE, "SCR"<<"\n");
      _secbus_debug(debug_info, NONE, dec<< "- SCR ACCESS NUMBER	= " <<scr_accesses<<"\n");
      _secbus_debug(debug_info, NONE, dec<< "- SCR MISS NUMBER		= " <<scr_misses<<"\n");
      _secbus_debug(debug_info, NONE, dec<< "- SCR MISS RATE		= " <<(float)scr_misses/scr_accesses<<"\n");
    }
    tmpl(void)::reset_stats()
    {
      scr_accesses = 0;
      scr_misses   = 0;
      m_cpt_r   = 0;
      m_cpt_w  = 0;

    }
    //Management of secbus commands from processor
    tmpl(bool)::on_write(int seg, typename vci_param::addr_t addr, typename vci_param::data_t data, int be)
    {
      int cell = (int)addr / vci_param::B;
      _secbus_debug(debug_info, DEBUG, dec<<name()<< " write register "<< cell<< " with data 0x"<< hex << data<<"\n");
      _secbus_debug(dump_in, TRACE,	"W"<<"	"<<setw(8)<<hex<<m_vci_target_fsm.getBase(seg) + addr<<"	"<<setw(8)<<data<<"	"<<be<<"	"<<4<<"	"<<dec<<m<<"\n");
      switch ((secbus_io_register_e)cell) 
      {
        case CMD:
          cmd_s		= data;
          return true;
        case ARG_0:
          arg_0_s	= data;
          return true;
        case ARG_1:
          arg_1_s	= data;
          return true;
        case ARG_2:
          arg_2_s	= data;
          return true;
        case RUN:
          run_s		= true;
          statut_s	= SECBUS_BUSY;
          return true;
        default:
          cout<<"error when write in secbus io register"<<"\n";
          return false;
      }
    }

    tmpl(bool)::on_read(int seg, typename vci_param::addr_t addr, typename vci_param::data_t &data)
    {
      int cell = (int)addr / vci_param::B;
      _secbus_debug(debug_info, DEBUG, dec<<name()<<" read register "<< cell<<"\n");
      _secbus_debug(dump_in, TRACE,	"R"<<"	"<<setw(8)<<hex<<m_vci_target_fsm.getBase(seg) + addr<<"	"<<setw(8)<<statut_s<<"	"<<0xF<<"	"<<4<<"	"<<dec<<m<<"\n");
      assert((secbus_io_register_e)cell == STATUT );
      data = statut_s;
      return true;
    }

    tmpl(void)::ps()
    {
      //Increment cycle counter		
      m++;
      //Print 
      _secbus_debug(debug_info, TRACE, dec<<"CYCLE:		"<<m<<"\n");
      _secbus_debug(debug_info, TRACE, dec<<"VCI_INITIATOR_CMD_STATE:"<<vci_initiator_cmd_state<<"\n");
      _secbus_debug(debug_info, TRACE, dec<<"VCI_INITIATOR_RSP_STATE:"<<vci_initiator_rsp_state<<"\n");
      _secbus_debug(debug_info, TRACE, dec<<"VCI_TARGET_STATE:		"<<vci_target_state<<"\n");
      if (!p_resetn) 
      {
        vci_target_state	= TARGET_IDLE;
        vci_initiator_cmd_state	= CMD_IDLE;
        vci_initiator_rsp_state	= RSP_IDLE;
        m			= 0;
        m_cpt_r			= 0;
        m_cpt_w			= 0;
        m_cpt_rcycle 		= 0;
        m_cpt_wcycle 		= 0;
        statut_s 		= SECBUS_IDLE;
        scr_misses 		= 0;
        m_vci_target_fsm.reset();
        target_pending_packet_s	= false;
        read_immediate_s = false;
        return;
      }

      cmdack_s		= false;
      write_register	= false;
      ready_to_read_s = false;
      ht_update_idle	= hash_controller_ack_sig.uack;
      ht_idle		= ht_update_idle && hash_controller_ack_sig.cack && hash_controller_ack_sig.alap_ack && hash_controller_ack_sig.init_mbht_ack;

      typename vci_param::addr_t address = p_vci_target.address.read();


      switch (vci_target_state) 
      {
        case TARGET_IDLE:

          if (!ht_update_idle)
            break;

          if (run_s)
            //io request
          {
            switch ((secbus_cmd_e)cmd_s.read()) 
            {
              case CREATE_SP:
                //build a new security policy
                cout << "build a new security policy " << m << endl;
                target_address_s		= SP_BASE_ADDRESS;
                vci_target_state		= WRITE_SECURITY_CONTEXT;
                break;

              case CREATE_PSPE:
                //build a new pspe
                cout << "build a new pspe (" << m << ") addr " << arg_2_s << endl;
                target_address_s		= arg_2_s;
                vci_target_state		= WRITE_SECURITY_CONTEXT;
                break;

              case INITIALIZE_INTEGRITY:
                //build a integrity page
                cout << "build an integrity page" << endl;
                target_address_s		= arg_0_s;
                vci_target_state		= READ_SECURITY_CONTEXT;
                break;

              case INIT_MBHT:
                cout << "initialization of mbht" << endl;
                vci_target_state    = START_INIT_MASTER_TREE;
                break;

              default:
                cout<<"ERROR ON SECBUS CMD REGISTER "<< (secbus_cmd_e)cmd_s.read() << "\n";
            }
          }
          else if (p_vci_target.cmdval.read())
            //regular request
          {
	    srcid_s		       	= p_vci_target.srcid.read();
	    trdid_s		       	= p_vci_target.trdid.read();
	    pktid_s		       	= p_vci_target.pktid.read();
	    target_cmd_s	      	= p_vci_target.cmd.read();
	    target_wdata_s  	     	= p_vci_target.wdata.read();
	    target_be_s		      	= p_vci_target.be.read() & 0xF;
	    target_address_s	    	= address;
	    target_start_address_s	= address;
	    target_eop_s	      	= p_vci_target.eop;
	    target_plen_s	      	= p_vci_target.plen.read();
	    target_index_s        	= index(address, SIZE_256_IN_BYTES);
	    cmdack_s	        	= true;
	    scr_accesses ++;


            if (p_vci_target.address.read() == reset_cpt_address)
            {
              _secbus_debug(std::cout, TRACE, "Reset Secbus counters"<<"\n");
              mac_cache_controller->reset_stats();
              hash_cache_controller->reset_stats();
              cipher_block.reset_stats();
              mac_controller->reset_stats();
              hash_tree_controller.reset_stats();
              reset_stats();
            }  	

            int ctc;
	    switch (p_vci_target.cmd.read()) 
	    {
	    case vci_param::CMD_READ:
	      m_cpt_r++;
	      m_cpt_rcycle = m;
		
	      ctc = ((p_vci_target.plen.read() + _ctz(p_vci_target.be.read(), vci_param::B) + vci_param::B - 1)/vci_param::B) - 1; // ((p_vci_target.plen.read() + vci_param::B -1)/vci_param::B) - 1;
		
	      target_cells_to_come_s = ctc;

	      if (register_0_out_sig.address == aligned(address, SIZE_256_IN_BYTES)
		  && (((register_0_out_sig.be >> index(address, SIZE_256_IN_BYTES)*4) & 0xF) == 0xF))
		//data is already in input register
		vci_target_state	= TARGET_CMD_ACK;
	      else
	      {
		if (getSizeBit(sc_register_read_sig.mpspe) == SIZE_4K)
		{
		  if (get4kPageAddress(address) == sc_register_read_sig.page_address)
		  {
		    //cout << "4k ctx ok start read" << endl;
		    vci_target_state	= START_READ;
		  }
		  else
		  {
		    //  cout << "4k ctx missing" <<(hex)<< get4kPageAddress(address) << " sc_register " << sc_register_read_sig.page_address << endl;
		    vci_target_state	= READ_SECURITY_CONTEXT;
		  }
		  /*  //security context of this 4k page is already in read buffer
		      vci_target_state	= START_READ;
		      else
		      vci_target_state	= READ_SECURITY_CONTEXT;*/
		}
		else if (getSizeBit(sc_register_read_sig.mpspe) == SIZE_4M)
		{
		  if (get4mPageAddress(address) == sc_register_read_sig.page_address)
		    //security context of this 4k page is already in read buffer
		  {
		    //cout << "4m ctx ok start read" << endl;
		    vci_target_state	= START_READ;
		  }
		  else
		  {
		    vci_target_state	= READ_SECURITY_CONTEXT;
		    //cout << "4m ctx missing" <<(hex)<< get4mPageAddress(address) << " sc_register " << sc_register_read_sig.page_address << endl;
		  }
		}
		
		break;
		
	      case vci_param::CMD_WRITE:
		
		m_cpt_w++;
		m_cpt_wcycle = m;

		ctc = ((p_vci_target.plen.read() + _ctz(p_vci_target.be.read(), vci_param::B) + vci_param::B - 1)/vci_param::B); 
		target_cells_to_come_s = ctc;

		if ( p_vci_target.eop.read()) 
		  assert(p_vci_target.plen.read() <= vci_param::B );

		if (register_0_out_sig.address == aligned(address, SIZE_256_IN_BYTES))
		  //data is already in input register
		  vci_target_state	= TARGET_CMD_ACK;
		else
		{
		  if (getSizeBit(sc_register_read_sig.mpspe) == SIZE_4K)
		  {
		    //cout << "!4K";
		    if (get4kPageAddress(address) == sc_register_read_sig.page_address)
		      //security context of this 4k page is already in read buffer
		    {
		      // cout << "ctx ok flush register" << endl;
		      vci_target_state	= FLUSH_REGISTER_0;
		    }
		    else
		    {
		      //cout << "ctx missing" <<(hex)<< get4kPageAddress(address) << " sc_register " << sc_register_read_sig.page_address << endl;
		      vci_target_state	= READ_SECURITY_CONTEXT;
		    }
		  }
		  else if (get4mPageAddress(address) == sc_register_read_sig.page_address)
		    //security context of this 4m page is already is read buffer
		  {
		    // cout << "4m ctx ok flush register" << endl;
		    vci_target_state	= FLUSH_REGISTER_0;
		  }
		  else
		  {
		    // cout << "4m ctx missing" <<(hex)<< get4mPageAddress(address) << " sc_register " << sc_register_read_sig.page_address << endl;
		    vci_target_state	= READ_SECURITY_CONTEXT;
		  }
		}
		break;

	      default:
		cout<<"ERROR : UNKNOWN TARGET COMMAND " <<p_vci_target.cmd.read()<<"\n"; 
		break;
	      }
	    }
/*
  else
  {
  switch(p_vci_target.cmd.read())
  {
  case vci_param::CMD_READ:
  ctc = ((p_vci_target.plen.read() + _ctz(p_vci_target.be.read(), vci_param::B) + vci_param::B - 1)/vci_param::B) - 1; // ((p_vci_target.plen.read() + vci_param::B -1)/vci_param::B) - 1;
		
  target_cells_to_come_s = ctc;
  vci_target_state = READ_THROUGH;

  break;

  case vci_param::CDM_WRITE:
  ctc = ((p_vci_target.plen.read() + _ctz(p_vci_target.be.read(), vci_param::B) + vci_param::B - 1)/vci_param::B); 
  target_cells_to_come_s = ctc;

  if ( p_vci_target.eop.read()) 
  assert(p_vci_target.plen.read() <= vci_param::B );

  vci_target_state = WRITE_THROUGH;
  break;

  default:
  cout << "ERROR : UNKNOWN TARGET COMMAND\n";
  }
  }*/
          }
          break;
/*
  case READ_THROUGH:
  vci_target_state = WAIT_READ_THROUGH;
  break;

  case WAIT_READ_THROUGH:
  if (p_vci_initiator.rspval.read())
  {
  vci_target_state = READ_THROUGH_RSP;
  }
  break;

  case READ_THROUGH_RSP:
  if (!p_vci_target.rspack.read())
  break;

  target_cells_to_come_s = target_cells_to_comes - 1;
  if (target_cells_to_come_s == 0)
  vci_target_state = TARGET_IDLE;
  break;

  case WRITE_THROUGH:
  vci_target_state = WAIT_WRITE_THROUGH;
  break;

  case WAIT_WRITE_THROUGH:
  if (p_vci_initiator.rspval.read())
  vci_target_state = WRITE_THROUGH_RSP;
  break;

  case WRITE_THROUGH_RSP:
  break;
*/
      case TARGET_CMD_ACK:
	switch (p_vci_target.cmd.read()) 
	{
	case vci_param::CMD_READ:
	  target_address_s	= target_address_s + vci_param::B;
	  target_rdata_s	= register_0_out_sig.data[index(target_address_s, SIZE_256_IN_BYTES)];
	  vci_target_state	= READ_RSP;
	  break;
	
	case vci_param::CMD_WRITE:
	  vci_target_state	= WRITE_REGISTER_0;
	  cmdack_s		= !p_vci_target.eop;
	  break;
	
	default:
	  cout<<"ERROR : UNKNOWN TARGET COMMAND"<<"\n"; 
	  break;
	}
	break;

      case READ_RSP:
	if (!p_vci_target.rspack.read())
	  break;

	target_cells_to_come_s	= target_cells_to_come_s - 1;

	if (register_0_out_sig.address == aligned(target_address_s, SIZE_256_IN_BYTES)
	    && (((register_0_out_sig.be >> index(target_address_s, SIZE_256_IN_BYTES)*4) & 0xF) == 0xF))
	  //data is already in input register
	{
	  target_address_s	= target_address_s + sizeof(int);
	  target_rdata_s	= register_0_out_sig.data[index(target_address_s, SIZE_256_IN_BYTES)];
	  vci_target_state	= READ_RSP;
	}
	else
	{
	  scr_accesses ++;

	  if (getSizeBit(sc_register_read_sig.mpspe) == SIZE_4K)
	  {
	    if (get4kPageAddress(target_address_s) == sc_register_read_sig.page_address)
	      //security context of this 4k page is already in read buffer
	      vci_target_state = START_READ;
	    else
	      vci_target_state = READ_SECURITY_CONTEXT;
	  }
	  else if (getSizeBit(sc_register_read_sig.mpspe) == SIZE_4M)
	  {
	    if (get4mPageAddress(target_address_s) == sc_register_read_sig.page_address)
	      //security context of this 4k page is already in read buffer
	      vci_target_state = START_READ;
	    else
	      vci_target_state = READ_SECURITY_CONTEXT;
	  }
	  else
	    cout<<"ERROR : SIZE BIT CONTAINED IN SECURITY CONTEXT REGISTER NON VALID"<<"\n"; 
	}

	if (target_cells_to_come_s == 0)
	{
	  _secbus_debug(stat_info, STAT, dec<<"@"<<m_cpt_rcycle<<" IC_R "<<m - m_cpt_rcycle<<" cycles\n");
	  vci_target_state	= TARGET_IDLE;
	}
	break;

      case READ_SECURITY_CONTEXT:
	if(run_s)
	  vci_target_state = WAIT_READ_SECURITY_CONTEXT;
	else if (target_cmd_s.read() == vci_param::CMD_READ)
	{	
	  scr_misses ++;
	  vci_target_state = WAIT_READ_SECURITY_CONTEXT;
	}
	else
	{
	  scr_misses ++;
	  cmdack_s			= !target_eop_s;
	  vci_target_state	= WRITE_REGISTER_0;
	}
	break;

      case WAIT_READ_SECURITY_CONTEXT:
	if (sc_controller_ack_sig.rack)
	{
	  if(run_s)
	  {
	    if(ht_idle)
	      vci_target_state	= START_INITIALIZE_INTEGRITY;
	  }
	  else if (target_cmd_s.read() == vci_param::CMD_READ)
	    vci_target_state = START_READ;
	  else
	    vci_target_state = START_WRITE;
	}
	break;

      case WRITE_SECURITY_CONTEXT:
	vci_target_state	= WAIT_WRITE_SECURITY_CONTEXT;
	break;

      case WAIT_WRITE_SECURITY_CONTEXT:
	if (sc_controller_ack_sig.wack)
	{
	  statut_s		= SECBUS_IDLE;
	  run_s		= false;
	  vci_target_state	= TARGET_IDLE;
	}
	break;


      case START_READ:
	read_immediate_s = false;
	vci_target_state = WAIT_READ;
	break;

      case WAIT_READ:
	//cout << "wait_read : " <<dec<<m<< endl;
	if (security_controller_regular_sig.rack || ready_to_read_s.read())
	{
	  if (!read_immediate_s)
	  {
	    target_address_s	= target_address_s + sizeof(int);
	    target_rdata_s	= register_0_out_sig.data[index(target_address_s, SIZE_256_IN_BYTES)];
	    vci_target_state	= READ_RSP;
	  }
	  else
	  {
	    vci_target_state = IMMEDIATE_RSP;
	    target_address_s	= target_address_s + sizeof(int);
	  }
	}
	break;

      case IMMEDIATE_RSP:
	if (!p_vci_target.rspack.read())
	  break;

	target_cells_to_come_s = target_cells_to_come_s - 1;
	target_address_s	= target_address_s + sizeof(int);
	if (target_cells_to_come_s == 0)
	  vci_target_state = TARGET_IDLE;

	break;

      case FLUSH_REGISTER_0:
	cmdack_s		= !target_eop_s;
	vci_target_state	= WRITE_REGISTER_0;
	break;

      case WRITE_REGISTER_0:

/*          if (target_cells_to_come_s == 1)
            assert(p_vci_target.eop.read() == true );
*/
	if (target_cells_to_come_s == 1)
	  //end of packet
	{
	  target_end_address_s= target_address_s;
	  target_eop_s	= p_vci_target.eop;

	  if (sc_controller_ack_sig.rack)
	    vci_target_state 	= START_WRITE;
	  else
	    vci_target_state 	= WAIT_READ_SECURITY_CONTEXT;
	}
	else if (aligned(target_address_s, SIZE_256_IN_BYTES)!= aligned(address, SIZE_256_IN_BYTES))
	  //register 0 miss
	{
	  target_end_address_s = target_address_s;
	  target_cells_to_come_s = target_cells_to_come_s - 1;
	  target_address_s	= address;
	  target_index_s	= index(address, SIZE_256_IN_BYTES);
	  target_wdata_s	= p_vci_target.wdata.read();
	  target_be_s		= p_vci_target.be.read() & 0xF;
	  target_pending_packet_s = true;
	  target_eop_s	= p_vci_target.eop;

	  //start processing of data contained in input register
	  if (sc_controller_ack_sig.rack)
	    vci_target_state = START_WRITE;
	  else
	    vci_target_state = WAIT_READ_SECURITY_CONTEXT;
	}
	else
	{

	  target_cells_to_come_s	= target_cells_to_come_s - 1;
	  target_address_s		= address;
	  target_index_s		= index(address, SIZE_256_IN_BYTES);
	  target_wdata_s		= p_vci_target.wdata.read();
	  target_be_s			= p_vci_target.be.read() & 0xF;
	  target_eop_s		= p_vci_target.eop;
	  cmdack_s			= !p_vci_target.eop;

	  vci_target_state = WRITE_REGISTER_0;
	}
	break;

      case START_WRITE:
	vci_target_state = WAIT_WRITE;
	break;

      case WAIT_WRITE:
	if (security_controller_regular_sig.wack)
	{
	  if (target_pending_packet_s)
	    //previous packet not ended
	  {
	    if (!ht_update_idle)
	      break;

	    scr_accesses ++;

	    target_start_address_s	= target_address_s;
	    target_pending_packet_s	= false;

	    if (getSizeBit(sc_register_read_sig.mpspe) == SIZE_4K)
	    {
	      if (get4kPageAddress(target_address_s) == sc_register_read_sig.page_address)
		//security context of this 4k page is already in read buffer
		vci_target_state	= FLUSH_REGISTER_0;
	      else
		vci_target_state	= READ_SECURITY_CONTEXT;
	    }
	    else if (get4mPageAddress(target_address_s) == sc_register_read_sig.page_address)
	      //security context of this 4m page is already is read buffer
	      vci_target_state	= FLUSH_REGISTER_0;
	    else
	      vci_target_state	= READ_SECURITY_CONTEXT;
	  }
	  else
	  { 
	    vci_target_state	= TARGET_IDLE;
	    _secbus_debug(stat_info, STAT, dec<<"@"<<m_cpt_wcycle<<" IC_W "<<m - m_cpt_wcycle<<" cycles\n");
	  }
	}
	break;

      case START_INIT_MASTER_TREE:
	vci_target_state = WAIT_INIT_MASTER_TREE;
	break;

      case WAIT_INIT_MASTER_TREE:
	if (hash_controller_ack_sig.init_mbht_ack)
	{
	  run_s = false;
	  statut_s = SECBUS_IDLE;
	  vci_target_state = TARGET_IDLE;
	}
	break;

      case START_INITIALIZE_INTEGRITY:
	vci_target_state	= WAIT_INITIALIZE_INTEGRITY;
	break;

      case WAIT_INITIALIZE_INTEGRITY:
	if (hash_controller_ack_sig.initialize_ack && mac_controller_ack_sig.initialize_ack)
	{
	  statut_s		= SECBUS_IDLE;
	  run_s		= false;
	  vci_target_state	= TARGET_IDLE;
	}
	break;

      default:
	break;
      }

      switch (vci_initiator_cmd_state) 
      {
      case CMD_IDLE:

	if ( !initiator_cmd_in_sig.enable )
	  break;
	index_v		= index(initiator_cmd_in_sig.start_address, SIZE_256_IN_BYTES);
	initiator_cmd_cpt_s	= 0;
	initiator_address_s	= initiator_cmd_in_sig.start_address;
	initiator_cmd_s	= initiator_cmd_in_sig.cmd;
	initiator_id_s	= initiator_cmd_in_sig.id;
	initiator_index_s	= index_v;
	initiator_cells_to_come_s = initiator_cmd_in_sig.plen/vci_param::B;

	switch (initiator_cmd_in_sig.cmd)
	{
	case READ:
	  //cout << "READ REQUEST TO MEMORY" << dec << m << " @" << hex << initiator_cmd_in_sig.start_address << endl;
	  initiator_be_s	= 0xF;
	  vci_initiator_cmd_state = CMD_READ;	
	  initiator_plen_s	= initiator_cmd_in_sig.plen;
	  break;

	case WRITE:
	  if (initiator_cmd_in_sig.id == 1)
	    //data from register 1
	  {
	    initiator_be_s	= (register_1_out_sig.be>>index_v*4) & 0xF;
	    //we use plen field
	    initiator_plen_s = initiator_cmd_in_sig.plen;
	  }
	  else if (initiator_cmd_in_sig.id  == 0)
	    //data from register 0
	  {
	    initiator_be_s		= (register_0_out_sig.be>>index_v*4) & 0xF;
	    //we disable plen field
	    initiator_plen_s	= 0;
	  }
	  else if (initiator_cmd_in_sig.id  == 7)
	    //data from register 1
	  {
	    initiator_be_s		= (register_1_out_sig.be>>index_v*4) & 0xF;
	    //we disable plen field
	    initiator_plen_s	= 0;
	  }
	  else
	  {
	    initiator_plen_s	= initiator_cmd_in_sig.plen;
	    initiator_be_s		= 0xF;
	  }
	  vci_initiator_cmd_state = CMD_WRITE;
	  break;

	case IMMEDIATE:
	  vci_initiator_cmd_state = CMD_IMMEDIATE;
	  break;

	default:
	  cout << "UNKNOWN MEMORY OUT CMD " << initiator_cmd_in_sig.cmd << endl;
	  break;
	}	
	break;

      case CMD_READ:
	if (p_vci_initiator.cmdack.read())
	  vci_initiator_cmd_state = CMD_IDLE;
	break;

      case CMD_WRITE:
	if (p_vci_initiator.cmdack.read())
	{
	  index_v			= initiator_index_s + 1;
	  initiator_address_s		= initiator_address_s + vci_param::B;
	  initiator_cmd_cpt_s		= initiator_cmd_cpt_s + 1;
	  initiator_index_s		= index_v;

	  if (initiator_id_s == 1 || initiator_id_s == 7)
	    initiator_be_s		= (register_1_out_sig.be>>index_v*4) & 0xF;
	  else if (initiator_id_s == 0)
	    initiator_be_s		= (register_0_out_sig.be>>index_v*4) & 0xF;
	  else
	    initiator_be_s		= 0xF;

	  if (initiator_cmd_cpt_s + 1 == initiator_cells_to_come_s) 
	    vci_initiator_cmd_state = CMD_IDLE ; 
	}
	break;

      case CMD_IMMEDIATE:
	//cout << "VCI_INITIATOR_CMD_STATE = CMD_IMMEDIATE" << endl;
	read_immediate_s = true;
	if (p_vci_initiator.cmdack.read())
	  vci_initiator_cmd_state = CMD_IDLE;

	break;

      default:
	break;

      } 

      switch (vci_initiator_rsp_state) 
      {
      case RSP_IDLE:
	//cout << "rsp_idle : " <<dec<<m<<endl;
	if ( ! initiator_cmd_in_sig.enable )
	  break;

	initiator_rsp_cpt_s = 0;

	if (initiator_cmd_in_sig.cmd == READ)
	  vci_initiator_rsp_state = RSP_READ;
	else if (initiator_cmd_in_sig.cmd == WRITE) 
	  vci_initiator_rsp_state = RSP_WRITE;
	else if (initiator_cmd_in_sig.cmd == IMMEDIATE) 
	  vci_initiator_rsp_state = RSP_IMMEDIATE;
	else 
	  cout<<"UNKNOWN MEMORY OUT CMD"; 

	assert( ! p_vci_initiator.rspval.read() && "UNEXPECTED RESPONSE" );
	break;

      case RSP_READ:
	//cout << "----- READ RSP FROM MEMORY : " << dec << m << " @ :" << hex << initiator_address_s << endl;
	if ( ! p_vci_initiator.rspval.read() )
	  break;

	initiator_data_s =  p_vci_initiator.rdata.read();

	initiator_rsp_cpt_s	= initiator_rsp_cpt_s + vci_param::B;
	initiator_address_s	= initiator_address_s + vci_param::B;
	initiator_index_s	= index(initiator_address_s, SIZE_256_IN_BYTES);

	write_register = true;

	if ( p_vci_initiator.reop.read())
	{
	  assert( (initiator_rsp_cpt_s == initiator_plen_s - vci_param::B) &&
		  "THE VCI READ RESPONSE PACKET IS TOO SHORT");

	  vci_initiator_rsp_state = RSP_LAST_READ;
	}

	if ( p_vci_initiator.rerror.read() != vci_param::ERR_NORMAL )
	{
	  cout<<"UNEXPECTED RERROR " << p_vci_initiator.rerror.read() << endl;
	  cout << (hex) << initiator_address_s << endl;
	}

	break;

      case RSP_LAST_READ:
	//cout << "READ FULL RSP FROM MEMORY : " << dec << m << " @ : " << hex << initiator_address_s << endl;
	vci_initiator_rsp_state = RSP_IDLE;
	break;

      case RSP_IMMEDIATE:
	ready_to_read_s = true;
	if (!p_vci_initiator.rspval.read())
	  break;

	target_rdata_s = p_vci_initiator.rdata.read();
	//vci_initiator_rsp_state = RSP_IDLE;
	if (p_vci_initiator.reop.read())
	  vci_initiator_rsp_state = RSP_LAST_IMMEDIATE;

	break;

      case RSP_LAST_IMMEDIATE:
	vci_initiator_rsp_state = RSP_IDLE;

      case RSP_WRITE:
	if ( ! p_vci_initiator.rspval.read() )
	  break;
	if ( p_vci_initiator.reop.read() ) 
	  vci_initiator_rsp_state = RSP_IDLE;
	if ( p_vci_initiator.rerror.read() != vci_param::ERR_NORMAL )
	{
	  cout<<"UNEXPECTED RERROR" << p_vci_initiator.rerror.read() << endl;
	  cout << (hex) << initiator_address_s << endl;
	}
	break;

      default :
	break;
      }


      m_vci_target_fsm.transition();
      flush(debug_info);
      flush(dump_in);
      flush(dump_out);
    }
    tmpl(void)::pc()
    {
      p_vci_target.rspval			= false;
      p_vci_target.rsrcid			= srcid_s;			
      p_vci_target.rtrdid			= trdid_s;
      p_vci_target.rpktid			= pktid_s;	
      p_vci_target.rerror			= false;
      //to registers
      //target
      register_0_in_target_sig.enable		= false;
      register_0_in_target_sig.flush		= false;
      //initiator
      register_0_in_initiator_sig.enable	= false;
      register_0_in_initiator_sig.flush		= false;
      register_2_in_initiator_sig.enable	= false;
      register_2_in_initiator_sig.flush		= false;
      register_1_in_initiator_sig.enable	= false;
      register_1_in_initiator_sig.flush		= false;
      //to security context controller
      sc_controller_regular_cmd_sig.enable	= false;
      //to security controller
      security_controller_regular_sig.enable	= false;
      //to hash/mac/security controller
      memory_ack_sig.rack			= false;
      memory_ack_sig.wack			= false;
      //response ack always true
      p_vci_initiator.rspack			= true;
      //to cpu
      p_vci_target.cmdack			= cmdack_s;
      //to hash tree controller
      hash_controller_cmd_2_sig.enable		= false;
      mac_controller_cmd_2_sig.enable		= false;

      if (vci_initiator_rsp_state == RSP_IDLE) memory_ack_sig.rack = true;
      if (vci_initiator_rsp_state == RSP_IDLE) memory_ack_sig.wack = true;

      switch (vci_target_state)
      {

      case TARGET_IDLE:
	break;

      case READ_SECURITY_CONTEXT:
	sc_controller_regular_cmd_sig.address	= target_address_s;
	sc_controller_regular_cmd_sig.enable	= true;
	sc_controller_regular_cmd_sig.cmd	= READ_SC;
	//flush input register
	register_0_in_target_sig.enable	= true;
	register_0_in_target_sig.flush	= true;
	break;

      case WRITE_SECURITY_CONTEXT:
	sc_controller_regular_cmd_sig.address	= target_address_s;
	sc_controller_regular_cmd_sig.enable	= true;
	if (cmd_s == CREATE_PSPE)
	  sc_controller_regular_cmd_sig.cmd 	= WRITE_PSPE;
	else
	  sc_controller_regular_cmd_sig.cmd 	= WRITE_SP;
	sc_controller_regular_cmd_sig.initiator = MASTER;
	sc_controller_regular_data_sig.data[0]= arg_0_s;
	sc_controller_regular_data_sig.data[1]= arg_1_s;
	break;

      case START_READ:
	security_controller_regular_sig.enable	= true;
	security_controller_regular_sig.address	= target_address_s;
	security_controller_regular_sig.cmd		= READ;
	break;

      case READ_RSP:
	_secbus_debug(dump_in, TRACE,	"R"<<"	"<<setw(8)<<hex<<target_address_s - 4<<"	"<<setw(8)<<target_rdata_s<<"	"<<0xF<<"	"<<target_plen_s<<"	"<<initiator_id_s<<" "<<dec<<m<<"\n");
	p_vci_target.rspRead(target_cells_to_come_s == 0, target_rdata_s);
	break;

      case IMMEDIATE_RSP:
	_secbus_debug(dump_in, TRACE,	"R"<<"	"<<setw(8)<<hex<<target_address_s - 4<<"	"<<setw(8)<<target_rdata_s<<"	"<<0xF<<"	"<<target_plen_s<<"	"<<initiator_id_s<<" "<<dec<<m<<"\n");
	p_vci_target.rspRead(target_cells_to_come_s == 0, target_rdata_s);
	break;

      case FLUSH_REGISTER_0:
	register_0_in_target_sig.enable	= true;
	register_0_in_target_sig.flush	= true;
	break;

      case WRITE_REGISTER_0:
	register_0_in_target_sig.enable	= true;
	register_0_in_target_sig.be		= (target_be_s & 0xF)<<target_index_s*4;
	register_0_in_target_sig.address	= target_address_s.read();
	register_0_in_target_sig.data[target_index_s]	= target_wdata_s;
	//Send response
	if (target_cells_to_come_s == 1)
	  p_vci_target.rspWrite(true);

	_secbus_debug(dump_in, TRACE,	"W"<<"	"<<setw(8)<<hex<<target_address_s<<"	"<<setw(8)<<target_wdata_s<<"	"<<target_be_s<<"	"<<target_plen_s<<"	"<<initiator_id_s<<" "<<dec<<m<<"\n");
	break;

      case START_WRITE :
	security_controller_regular_sig.enable	= true;
	security_controller_regular_sig.address	= target_start_address_s;
	security_controller_regular_sig.end_address	= target_end_address_s;
	security_controller_regular_sig.cmd		= WRITE;
	break;

      case START_INIT_MASTER_TREE:
	hash_controller_cmd_2_sig.enable 	= true;
	hash_controller_cmd_2_sig.cmd  	= INIT_MHT;
	break;

      case START_INITIALIZE_INTEGRITY:
	if (arg_1_s == 1)
	{
	  mac_controller_cmd_2_sig.enable	= true;
	  mac_controller_cmd_2_sig.cmd	= INITIALIZE;
	  mac_controller_cmd_2_sig.address	= target_address_s;
	}
	else if (arg_1_s == 2)
	{
	  hash_controller_cmd_2_sig.enable	= true;
	  hash_controller_cmd_2_sig.cmd	= (bool)arg_2_s ? INITIALIZE_PAGE : INITIALIZE;
	  hash_controller_cmd_2_sig.address	= target_address_s;
	}
	else
	  cout<<"ERROR: UNKNOW ARGUMENT 1 VALUE FOR INITIALIZING INTEGRITY"<<"\n";
	break;

      default:
	break;

      }

      switch (vci_initiator_cmd_state) 
      {

      case CMD_IDLE:
	p_vci_initiator.cmdval  = false;
	p_vci_initiator.address = 0;
	p_vci_initiator.wdata   = 0;
	p_vci_initiator.be      = 0;
	p_vci_initiator.plen    = 0;
	p_vci_initiator.cmd     = vci_param::CMD_WRITE;
	p_vci_initiator.trdid   = 0;
	p_vci_initiator.pktid   = 0;
	p_vci_initiator.srcid   = 0;
	p_vci_initiator.cons    = false;
	p_vci_initiator.wrap    = false;
	p_vci_initiator.contig  = false;
	p_vci_initiator.clen    = 0;
	p_vci_initiator.cfixed  = false;
	p_vci_initiator.eop     = false;
	break;

      case CMD_READ:
	p_vci_initiator.cmdval  = true;
	p_vci_initiator.address = initiator_address_s.read();
	p_vci_initiator.be      = 0xF;
	p_vci_initiator.plen    = initiator_plen_s.read();
	p_vci_initiator.cmd     = vci_param::CMD_READ;
	p_vci_initiator.trdid   = 0;
	p_vci_initiator.pktid   = 0;
	p_vci_initiator.srcid   = srcid_s;
	p_vci_initiator.cons    = false;
	p_vci_initiator.wrap    = false;
	p_vci_initiator.contig  = true;
	p_vci_initiator.clen    = 0;
	p_vci_initiator.cfixed  = false;
	p_vci_initiator.eop     = true;
	initiator_data_s   = register_1_out_sig.data[initiator_index_s].read();
	if (initiator_id_s == 6 || initiator_id_s == 5 || initiator_id_s == 4 || initiator_id_s == 3)
	{
	  register_2_in_initiator_sig.enable	= true;
	  register_2_in_initiator_sig.flush	= true;
	}
	break;
        
      case CMD_IMMEDIATE:
	p_vci_initiator.cmdval  = true;
	p_vci_initiator.address = target_address_s.read();
	p_vci_initiator.be      = target_be_s;
	p_vci_initiator.plen    = target_plen_s.read();
	p_vci_initiator.cmd     = vci_param::CMD_READ;
	p_vci_initiator.trdid   = 0;
	p_vci_initiator.pktid   = 0;
	p_vci_initiator.srcid   = srcid_s.read();
	p_vci_initiator.cons    = false;
	p_vci_initiator.wrap    = false;
	p_vci_initiator.contig  = true;
	p_vci_initiator.clen    = 0;
	p_vci_initiator.cfixed  = false;
	p_vci_initiator.eop     = true;
	break;

      case CMD_WRITE:
	p_vci_initiator.cmdval  = true;
	p_vci_initiator.address = initiator_address_s.read();
	p_vci_initiator.plen    = initiator_plen_s.read();
	p_vci_initiator.cmd     = vci_param::CMD_WRITE;
	p_vci_initiator.trdid   = trdid_s;
	p_vci_initiator.pktid   = 0;
	p_vci_initiator.srcid   = srcid_s;
	p_vci_initiator.cons    = false;
	p_vci_initiator.wrap    = false;
	p_vci_initiator.contig  = true;
	p_vci_initiator.clen    = 0;
	p_vci_initiator.cfixed  = false;
	p_vci_initiator.eop     = (initiator_cmd_cpt_s + 1 == initiator_cells_to_come_s);
	p_vci_initiator.be      = initiator_be_s.read();

	if (initiator_id_s == 1 || initiator_id_s == 6 || initiator_id_s == 7)
	  //data from register 1
	  initiator_data_s   = register_1_out_sig.data[initiator_index_s].read();
	if (initiator_id_s == 0)
	  //data from register 0
	  initiator_data_s   = register_0_out_sig.data[initiator_index_s].read();
	else if (initiator_id_s == 2)
	  //data from hash cache module
	  initiator_data_s   = memory_hash_cache_data_sig.data[initiator_index_s % SIZE_64_IN_WORDS].read();
	else if (initiator_id_s == 3)
	  //data from mac cache module
	  initiator_data_s   = memory_mac_cache_data_sig.data[initiator_index_s % SIZE_64_IN_WORDS].read();
	else if (initiator_id_s == 4)
	  //data from ht controller module
	  initiator_data_s   = memory_ht_controller_data_sig.data[initiator_index_s % SIZE_64_IN_WORDS].read();
	else if (initiator_id_s == 5)
	  //data from mac controller module
	  initiator_data_s   = memory_mac_controller_data_sig.data[initiator_index_s % SIZE_64_IN_WORDS].read();
	p_vci_initiator.wdata = initiator_data_s;

	if (register_2_out_sig.address == aligned(initiator_address_s, SIZE_256_IN_BYTES))
	{
	  register_2_in_initiator_sig.enable			= true;
	  register_2_in_initiator_sig.be			= 0xF<<(initiator_index_s * vci_param::B);
	  register_2_in_initiator_sig.address			= initiator_address_s;
	  register_2_in_initiator_sig.data[initiator_index_s]	= initiator_data_s;
	}
	_secbus_debug(dump_out, TRACE,	"W"<<"	"<<setw(8)<<hex<<initiator_address_s<<"	"<<setw(8)<<initiator_data_s<<"	"<<initiator_be_s<<"	"<<initiator_plen_s<<"	"<<dec<<m<<"\n");

	break;

      default:
	break;
      }

      // ---------------------------------------------------------- vci_initiator_rsp_state --------------------------------//

      if (write_register)
      {

	if (initiator_id_s == 0)
	  //Write in register 0
	{
	  register_0_in_initiator_sig.enable			= true;
	  register_0_in_initiator_sig.be				= 0xF<<(initiator_index_s * vci_param::B);
	  register_0_in_initiator_sig.address			= initiator_address_s - vci_param::B;
	  register_0_in_initiator_sig.data[initiator_index_s]	= initiator_data_s;
	}
	else if (initiator_id_s == 1) 
	  //Write in register 1
	{
	  register_1_in_initiator_sig.enable			= true;
	  register_1_in_initiator_sig.be				= 0xF<<(initiator_index_s * vci_param::B);
	  register_1_in_initiator_sig.address			= initiator_address_s - vci_param::B;
	  register_1_in_initiator_sig.data[initiator_index_s]	= initiator_data_s;
	}
	else if (initiator_id_s == 2 || initiator_id_s == 3 || initiator_id_s == 4 || initiator_id_s == 5 )
	  //Write in register 2
	{
	  register_2_in_initiator_sig.enable			= true;
	  register_2_in_initiator_sig.be				= 0xF<<(initiator_index_s * vci_param::B);
	  register_2_in_initiator_sig.address			= initiator_address_s - vci_param::B;
	  register_2_in_initiator_sig.data[initiator_index_s]	= initiator_data_s;
	}
	else if (initiator_id_s == 6) 
	  //Write in register 1 and register 2
	{
	  register_1_in_initiator_sig.enable			= true;
	  register_1_in_initiator_sig.be				= 0xF<<(initiator_index_s * vci_param::B);
	  register_1_in_initiator_sig.address			= initiator_address_s - vci_param::B;
	  register_1_in_initiator_sig.data[initiator_index_s]	= initiator_data_s;

	  register_2_in_initiator_sig.enable			= true;
	  register_2_in_initiator_sig.be				= 0xF<<(initiator_index_s * vci_param::B);
	  register_2_in_initiator_sig.address			= initiator_address_s - vci_param::B;
	  register_2_in_initiator_sig.data[initiator_index_s]	= initiator_data_s;
	}
      }
	
      //----------------------------------------------------------------------------------------------------------------------------
      m_vci_target_fsm.genMoore();
    }

  }
}
