#include "../include/Environment.h"

using namespace morpheo;

namespace environment {

  Environment::Environment (sc_module_name name, Parameters * param) :
    name (name)
  {
    this->param = param;

    component_cache       = new cache::Cache     ("cache", param->param_cache);

    component_tty         = new tty::TTY * [param->nb_component_tty];
    for (uint32_t i=0; i<param->nb_component_tty; i++)
    component_tty     [i] = new tty::TTY         ("tty_"+i    ,param->param_tty     [i]);
    
    component_ramlock     = new ramlock::RamLock * [param->nb_component_ramlock];
    for (uint32_t i=0; i<param->nb_component_ramlock; i++)
    component_ramlock [i] = new ramlock::RamLock ("ramlock_"+i,param->param_ramlock [i]);

    component_sim2os      = new sim2os::Sim2OS   ("sim2os" ,param->param_sim2os );
    component_data        = new data::Data       ("data"   ,param->param_data   );

    component_buffer_irsp = new queue::Sort_Queue<irsp_t*> * [param->nb_entity];
    component_buffer_drsp = new queue::Sort_Queue<drsp_t*> * [param->nb_entity];

    for (uint32_t i=0; i<param->nb_component_tty; i++)
      {
	uint32_t tty_size = param->param_tty[i]->nb_tty * 16;

	data::Entity entity = component_data->entity(param->tty_address[i], tty_size);
	if (entity.present == false)
	  {
	    std::cerr << "<Environnement::Environnement> The tty [" << i << "] have not a segment in the segment table" << std::endl;
	    exit (1);
	  }
	entity.segment->define_target(data::TYPE_TARGET_TTY,i);
      } 

    for (uint32_t i=0; i<param->nb_component_ramlock; i++)
      {
	uint32_t ramlock_size = param->param_ramlock[i]->_size;
	data::Entity entity = component_data->entity(param->ramlock_address[i], ramlock_size);
	if (entity.present == false)
	  {
	    std::cerr << "<Environnement::Environnement> The ramlock [" << i << "] have not a segment in the segment table" << std::endl;
	    exit (1);
	  }
	entity.segment->define_target(data::TYPE_TARGET_RAMLOCK,i);
      } 

      {
	data::Entity entity = component_data->entity(param->sim2os_address, param->sim2os_size);
	if (entity.present == false)
	  {
	    std::cerr << "<Environnement::Environnement> The sim2os  have not a segment in the segment table" << std::endl;
	    exit (1);
	  }
	entity.segment->define_target(data::TYPE_TARGET_SIM2OS,0);
      } 


    for (uint32_t i=0; i<param->nb_entity; i++)
      {
	component_buffer_irsp [i] = new queue::Sort_Queue<irsp_t*> ("buffer_irsp_"+i,param->param_buffer_irsp [i]);
	component_buffer_drsp [i] = new queue::Sort_Queue<drsp_t*> ("buffer_drsp_"+i,param->param_buffer_drsp [i]);
      }

    uint32_t max_nb_instruction   = morpheo::max<uint32_t>(param->iaccess_nb_instruction  ,param->nb_entity);
    uint32_t max_instruction_size = morpheo::max<uint32_t>(param->iaccess_size_instruction,param->nb_entity);
    uint32_t max_data_size        = morpheo::max<uint32_t>(param->daccess_size_data       ,param->nb_entity);
    
    read_iram  = new char * [max_nb_instruction];
    for (uint32_t i=0; i<max_nb_instruction; i++)
      read_iram [i] = new char [max_instruction_size];

    read_dram    = new char * [1];
    read_dram[0] = new char [max_data_size/8];
    write_dram   = new char [max_data_size/8];
    context_stop = new bool [param->nb_entity];
    for (uint32_t i=0; i<param->nb_entity; ++i)
      context_stop [i] = false;
    nb_context_stop = 0;

    // Port 
    CLOCK                 = new sc_in_clk   ("CLOCK ");
    NRESET                = new sc_in<bool> ("NRESET");

    ICACHE_REQ_VAL        = new sc_in <Tcontrol_t           >  ** [param->nb_entity];
    ICACHE_REQ_ACK        = new sc_out<Tcontrol_t           >  ** [param->nb_entity];
    ICACHE_REQ_CONTEXT_ID = new sc_in <Ticache_context_t    >  ** [param->nb_entity];
    ICACHE_REQ_PACKET_ID  = new sc_in <Ticache_packet_t     >  ** [param->nb_entity];
    ICACHE_REQ_ADDRESS    = new sc_in <Ticache_address_t    >  ** [param->nb_entity];
    ICACHE_REQ_TYPE       = new sc_in <Ticache_type_t       >  ** [param->nb_entity];

    ICACHE_RSP_VAL        = new sc_out<Tcontrol_t           >  ** [param->nb_entity];
    ICACHE_RSP_ACK        = new sc_in <Tcontrol_t           >  ** [param->nb_entity];
    ICACHE_RSP_CONTEXT_ID = new sc_out<Ticache_context_t    >  ** [param->nb_entity];
    ICACHE_RSP_PACKET_ID  = new sc_out<Ticache_packet_t     >  ** [param->nb_entity];

    ICACHE_RSP_INSTRUCTION= new sc_out<Ticache_instruction_t> *** [param->nb_entity];//[nb_instruction]
    ICACHE_RSP_ERROR      = new sc_out<Ticache_error_t      >  ** [param->nb_entity];

    DCACHE_REQ_VAL        = new sc_in <Tcontrol_t           >  ** [param->nb_entity];
    DCACHE_REQ_ACK        = new sc_out<Tcontrol_t           >  ** [param->nb_entity];
    DCACHE_REQ_CONTEXT_ID = new sc_in <Tdcache_context_t    >  ** [param->nb_entity];
    DCACHE_REQ_PACKET_ID  = new sc_in <Tdcache_packet_t     >  ** [param->nb_entity];
    DCACHE_REQ_ADDRESS    = new sc_in <Tdcache_address_t    >  ** [param->nb_entity];
    DCACHE_REQ_TYPE       = new sc_in <Tdcache_type_t       >  ** [param->nb_entity];
    DCACHE_REQ_WDATA      = new sc_in <Tdcache_data_t       >  ** [param->nb_entity];

    DCACHE_RSP_VAL        = new sc_out<Tcontrol_t           >  ** [param->nb_entity];
    DCACHE_RSP_ACK        = new sc_in <Tcontrol_t           >  ** [param->nb_entity];
    DCACHE_RSP_CONTEXT_ID = new sc_out<Tdcache_context_t    >  ** [param->nb_entity];
    DCACHE_RSP_PACKET_ID  = new sc_out<Tdcache_packet_t     >  ** [param->nb_entity];
    DCACHE_RSP_RDATA      = new sc_out<Tdcache_data_t       >  ** [param->nb_entity];
    DCACHE_RSP_ERROR      = new sc_out<Tdcache_error_t      >  ** [param->nb_entity];

    for (uint32_t i=0; i<param->nb_entity; i++)
      {
	ICACHE_REQ_VAL        [i] = new sc_in <Tcontrol_t           >  * [param->icache_dedicated_nb_port[i]];
	ICACHE_REQ_ACK        [i] = new sc_out<Tcontrol_t           >  * [param->icache_dedicated_nb_port[i]];
	ICACHE_REQ_CONTEXT_ID [i] = new sc_in <Ticache_context_t    >  * [param->icache_dedicated_nb_port[i]];
	ICACHE_REQ_PACKET_ID  [i] = new sc_in <Ticache_packet_t     >  * [param->icache_dedicated_nb_port[i]];
	ICACHE_REQ_ADDRESS    [i] = new sc_in <Ticache_address_t    >  * [param->icache_dedicated_nb_port[i]];
	ICACHE_REQ_TYPE       [i] = new sc_in <Ticache_type_t       >  * [param->icache_dedicated_nb_port[i]];

	ICACHE_RSP_VAL        [i] = new sc_out<Tcontrol_t           >  * [param->icache_dedicated_nb_port[i]];
	ICACHE_RSP_ACK        [i] = new sc_in <Tcontrol_t           >  * [param->icache_dedicated_nb_port[i]];
	ICACHE_RSP_CONTEXT_ID [i] = new sc_out<Ticache_context_t    >  * [param->icache_dedicated_nb_port[i]];
	ICACHE_RSP_PACKET_ID  [i] = new sc_out<Ticache_packet_t     >  * [param->icache_dedicated_nb_port[i]];
	ICACHE_RSP_INSTRUCTION[i] = new sc_out<Ticache_instruction_t> ** [param->icache_dedicated_nb_port[i]];//[nb_instruction]
	ICACHE_RSP_ERROR      [i] = new sc_out<Ticache_error_t      >  * [param->icache_dedicated_nb_port[i]];
	
	for (uint32_t j=0; j<param->icache_dedicated_nb_port[i]; j++)
	  {
	    ICACHE_REQ_VAL         [i][j] = new sc_in <Tcontrol_t           > ("");
	    ICACHE_REQ_ACK         [i][j] = new sc_out<Tcontrol_t           > ("");
	    ICACHE_REQ_CONTEXT_ID  [i][j] = new sc_in <Ticache_context_t    > ("");
	    ICACHE_REQ_PACKET_ID   [i][j] = new sc_in <Ticache_packet_t     > ("");
	    ICACHE_REQ_ADDRESS     [i][j] = new sc_in <Ticache_address_t    > ("");
	    ICACHE_REQ_TYPE        [i][j] = new sc_in <Ticache_type_t       > ("");
	    
	    ICACHE_RSP_VAL         [i][j] = new sc_out<Tcontrol_t           > ("");
	    ICACHE_RSP_ACK         [i][j] = new sc_in <Tcontrol_t           > ("");
	    ICACHE_RSP_CONTEXT_ID  [i][j] = new sc_out<Ticache_context_t    > ("");
	    ICACHE_RSP_PACKET_ID   [i][j] = new sc_out<Ticache_packet_t     > ("");
	    ICACHE_RSP_ERROR       [i][j] = new sc_out<Ticache_error_t      > ("");
	    
	    ICACHE_RSP_INSTRUCTION [i][j] = new sc_out<Ticache_instruction_t> * [param->iaccess_nb_instruction[i]];
	    
	    for (uint32_t k=0; k<param->iaccess_nb_instruction[i]; k++)
	      ICACHE_RSP_INSTRUCTION [i][j][k] = new sc_out<Ticache_instruction_t> ("");
	  }
	
	DCACHE_REQ_VAL        [i] = new sc_in <Tcontrol_t           >  * [param->dcache_dedicated_nb_port[i]];
	DCACHE_REQ_ACK        [i] = new sc_out<Tcontrol_t           >  * [param->dcache_dedicated_nb_port[i]];
	DCACHE_REQ_CONTEXT_ID [i] = new sc_in <Tdcache_context_t    >  * [param->dcache_dedicated_nb_port[i]];
	DCACHE_REQ_PACKET_ID  [i] = new sc_in <Tdcache_packet_t     >  * [param->dcache_dedicated_nb_port[i]];
	DCACHE_REQ_ADDRESS    [i] = new sc_in <Tdcache_address_t    >  * [param->dcache_dedicated_nb_port[i]];
	DCACHE_REQ_TYPE       [i] = new sc_in <Tdcache_type_t       >  * [param->dcache_dedicated_nb_port[i]];
	DCACHE_REQ_WDATA      [i] = new sc_in <Tdcache_data_t       >  * [param->dcache_dedicated_nb_port[i]];

	DCACHE_RSP_VAL        [i] = new sc_out<Tcontrol_t           >  * [param->dcache_dedicated_nb_port[i]];
	DCACHE_RSP_ACK        [i] = new sc_in <Tcontrol_t           >  * [param->dcache_dedicated_nb_port[i]];
	DCACHE_RSP_CONTEXT_ID [i] = new sc_out<Tdcache_context_t    >  * [param->dcache_dedicated_nb_port[i]];
	DCACHE_RSP_PACKET_ID  [i] = new sc_out<Tdcache_packet_t     >  * [param->dcache_dedicated_nb_port[i]];
	DCACHE_RSP_RDATA      [i] = new sc_out<Tdcache_data_t       >  * [param->dcache_dedicated_nb_port[i]];
	DCACHE_RSP_ERROR      [i] = new sc_out<Tdcache_error_t      >  * [param->dcache_dedicated_nb_port[i]];
	
	for (uint32_t j=0; j<param->dcache_dedicated_nb_port[i]; j++)
	  {
	    DCACHE_REQ_VAL        [i][j] = new sc_in <Tcontrol_t           > ("");
	    DCACHE_REQ_ACK        [i][j] = new sc_out<Tcontrol_t           > ("");
	    DCACHE_REQ_CONTEXT_ID [i][j] = new sc_in <Tdcache_context_t    > ("");
	    DCACHE_REQ_PACKET_ID  [i][j] = new sc_in <Tdcache_packet_t     > ("");
	    DCACHE_REQ_ADDRESS    [i][j] = new sc_in <Tdcache_address_t    > ("");
	    DCACHE_REQ_TYPE       [i][j] = new sc_in <Tdcache_type_t       > ("");
	    DCACHE_REQ_WDATA      [i][j] = new sc_in <Tdcache_data_t       > ("");
	    
	    DCACHE_RSP_VAL        [i][j] = new sc_out<Tcontrol_t           > ("");
	    DCACHE_RSP_ACK        [i][j] = new sc_in <Tcontrol_t           > ("");
	    DCACHE_RSP_CONTEXT_ID [i][j] = new sc_out<Tdcache_context_t    > ("");
	    DCACHE_RSP_PACKET_ID  [i][j] = new sc_out<Tdcache_packet_t     > ("");
	    DCACHE_RSP_RDATA      [i][j] = new sc_out<Tdcache_data_t       > ("");
	    DCACHE_RSP_ERROR      [i][j] = new sc_out<Tdcache_error_t      > ("");
	  }
      }

    icache_req_ack = new Tcontrol_t * [param->nb_entity];
    icache_rsp_val = new Tcontrol_t * [param->nb_entity];
    dcache_req_ack = new Tcontrol_t * [param->nb_entity];
    dcache_rsp_val = new Tcontrol_t * [param->nb_entity];

    for (uint32_t i=0; i<param->nb_entity; i++)
      {
	icache_req_ack [i] = new Tcontrol_t [param->icache_dedicated_nb_port[i]];
	icache_rsp_val [i] = new Tcontrol_t [param->icache_dedicated_nb_port[i]];
	dcache_req_ack [i] = new Tcontrol_t [param->dcache_dedicated_nb_port[i]];
	dcache_rsp_val [i] = new Tcontrol_t [param->dcache_dedicated_nb_port[i]];
      }
    // *****[ Definition of method ]*****
    SC_METHOD (transition);
    dont_initialize ();
    sensitive << (*(CLOCK)).pos();
    
    SC_METHOD (genMoore);
    dont_initialize ();
    sensitive << (*(CLOCK)).neg();
  }

  Environment::~Environment (void)
  {
    for (uint32_t i=0; i<param->nb_entity; i++)
      {
	delete [] icache_req_ack [i];
	delete [] icache_rsp_val [i];
	delete [] dcache_req_ack [i];
	delete [] dcache_rsp_val [i];
      }

    delete [] icache_req_ack;
    delete [] icache_rsp_val;
    delete [] dcache_req_ack;
    delete [] dcache_rsp_val;

    delete CLOCK ;
    delete NRESET;
    
    for (uint32_t i=0; i<param->nb_entity; i++)
      {
	for (uint32_t j=0; j<param->icache_dedicated_nb_port[i]; j++)
	  {
	    delete ICACHE_REQ_VAL         [i][j];
	    delete ICACHE_REQ_ACK         [i][j];
	    delete ICACHE_REQ_CONTEXT_ID  [i][j];
	    delete ICACHE_REQ_PACKET_ID   [i][j];
	    delete ICACHE_REQ_ADDRESS     [i][j];
	    delete ICACHE_REQ_TYPE        [i][j];
	    delete ICACHE_RSP_VAL         [i][j];
	    delete ICACHE_RSP_ACK         [i][j];
	    delete ICACHE_RSP_CONTEXT_ID  [i][j];
	    delete ICACHE_RSP_PACKET_ID   [i][j];
	    delete ICACHE_RSP_ERROR       [i][j];

	    for (uint32_t k=0; k<param->iaccess_nb_instruction[i]; k++)
	      delete ICACHE_RSP_INSTRUCTION [i][j][k];

	    delete [] ICACHE_RSP_INSTRUCTION [i][j];
	  }
	delete [] ICACHE_REQ_VAL         [i];
	delete [] ICACHE_REQ_ACK         [i];
	delete [] ICACHE_REQ_CONTEXT_ID  [i];
	delete [] ICACHE_REQ_PACKET_ID   [i];
	delete [] ICACHE_REQ_ADDRESS     [i];
	delete [] ICACHE_REQ_TYPE        [i];
	delete [] ICACHE_RSP_VAL         [i];
	delete [] ICACHE_RSP_ACK         [i];
	delete [] ICACHE_RSP_CONTEXT_ID  [i];
	delete [] ICACHE_RSP_PACKET_ID   [i];
	delete [] ICACHE_RSP_ERROR       [i];
	delete [] ICACHE_RSP_INSTRUCTION [i];
      }
    
    delete [] ICACHE_REQ_VAL        ;
    delete [] ICACHE_REQ_ACK        ;
    delete [] ICACHE_REQ_CONTEXT_ID ;
    delete [] ICACHE_REQ_PACKET_ID  ;
    delete [] ICACHE_REQ_ADDRESS    ;
    delete [] ICACHE_REQ_TYPE       ;
    delete [] ICACHE_RSP_VAL        ;
    delete [] ICACHE_RSP_ACK        ;
    delete [] ICACHE_RSP_CONTEXT_ID ;
    delete [] ICACHE_RSP_PACKET_ID  ;
    delete [] ICACHE_RSP_INSTRUCTION;
    delete [] ICACHE_RSP_ERROR      ;
    
    for (uint32_t i=0; i<param->nb_entity; i++)
      {
	for (uint32_t j=0; j<param->icache_dedicated_nb_port[i]; j++)
	  {
	    delete DCACHE_REQ_VAL        [i][j];
	    delete DCACHE_REQ_ACK        [i][j];
	    delete DCACHE_REQ_CONTEXT_ID [i][j];
	    delete DCACHE_REQ_PACKET_ID  [i][j];
	    delete DCACHE_REQ_ADDRESS    [i][j];
	    delete DCACHE_REQ_TYPE       [i][j];
	    delete DCACHE_REQ_WDATA      [i][j];
	    delete DCACHE_RSP_VAL        [i][j];
	    delete DCACHE_RSP_ACK        [i][j];
	    delete DCACHE_RSP_CONTEXT_ID [i][j];
	    delete DCACHE_RSP_PACKET_ID  [i][j];
	    delete DCACHE_RSP_RDATA      [i][j];
	    delete DCACHE_RSP_ERROR      [i][j];
	  }

	delete [] DCACHE_REQ_VAL        [i];
	delete [] DCACHE_REQ_ACK        [i];
	delete [] DCACHE_REQ_CONTEXT_ID [i];
	delete [] DCACHE_REQ_PACKET_ID  [i];
	delete [] DCACHE_REQ_ADDRESS    [i];
	delete [] DCACHE_REQ_TYPE       [i];
	delete [] DCACHE_REQ_WDATA      [i];
	delete [] DCACHE_RSP_VAL        [i];
	delete [] DCACHE_RSP_ACK        [i];
	delete [] DCACHE_RSP_CONTEXT_ID [i];
	delete [] DCACHE_RSP_PACKET_ID  [i];
	delete [] DCACHE_RSP_RDATA      [i];
	delete [] DCACHE_RSP_ERROR      [i];
      }

    delete [] DCACHE_REQ_VAL        ;
    delete [] DCACHE_REQ_ACK        ;
    delete [] DCACHE_REQ_CONTEXT_ID ;
    delete [] DCACHE_REQ_PACKET_ID  ;
    delete [] DCACHE_REQ_ADDRESS    ;
    delete [] DCACHE_REQ_TYPE       ;
    delete [] DCACHE_REQ_WDATA      ;
    delete [] DCACHE_RSP_VAL        ;
    delete [] DCACHE_RSP_ACK        ;
    delete [] DCACHE_RSP_CONTEXT_ID ;
    delete [] DCACHE_RSP_PACKET_ID  ;
    delete [] DCACHE_RSP_RDATA      ;
    delete [] DCACHE_RSP_ERROR      ;

    delete [] context_stop;
    delete [] write_dram;
    delete [] read_dram [0];
    delete [] read_dram;

    uint32_t max_nb_instruction   = morpheo::max<uint32_t>(param->iaccess_nb_instruction,param->nb_entity);
    for (uint32_t i=0; i<max_nb_instruction; i++)
      delete [] read_iram [i];
    delete [] read_iram;

    for (uint32_t i=0; i<param->nb_entity; i++)
      {
	while (not component_buffer_irsp [i]->empty())
	  {
	    delete component_buffer_irsp [i]->read(0)._data;
	    component_buffer_irsp [i]->pop();
	  }
	while (not component_buffer_drsp [i]->empty())
	  {
	    delete component_buffer_drsp [i]->read(0)._data;
	    component_buffer_drsp [i]->pop();
	  }

	delete component_buffer_irsp [i];
	delete component_buffer_drsp [i];
      }
    delete [] component_buffer_irsp;
    delete [] component_buffer_drsp;

    delete    component_data;
    delete    component_sim2os;
    for (uint32_t i=0; i<param->nb_component_ramlock; i++)
    delete    component_ramlock [i];
    delete [] component_ramlock;
    for (uint32_t i=0; i<param->nb_component_tty; i++)
    delete    component_tty [i];
    delete [] component_tty;
    delete    component_cache;

  }

};
