#include "Behavioural/include/SPR_access_mode.h"

namespace morpheo {
namespace behavioural {

  void SPR_access_mode::implement_group (uint32_t num_group, uint32_t nb_reg )
    {
      if (_spr_generic[num_group] != NULL)
	throw ERRORMORPHEO("SPR_access_mode::implement_group", "implement more once a group.");

      _max_register_by_group[num_group] = nb_reg;
      _spr_generic [num_group] = new spr_access_mode_t [nb_reg];
    }

  uint32_t SPR_access_mode::implement_group (uint32_t num_group)
    {
      if (_spr_generic[num_group] != NULL)
	throw ERRORMORPHEO("SPR_access_mode::implement_group", "implement more once a group.");

      switch (num_group)
	{
	case GROUP_SYSTEM_AND_CONTROL  : 
	  {
    	    implement_group(GROUP_SYSTEM_AND_CONTROL  ,NB_REG_GROUP_SYSTEM_AND_CONTROL  );

    	    for (uint32_t i=0 ; i<=8 ; i++)
    	    _spr_generic [GROUP_SYSTEM_AND_CONTROL ][   i]._supervisor_access_mode = SPR_ACCESS_MODE_READ_ONLY;
    	    for (uint32_t i=16; i<=18; i++)
    	    _spr_generic [GROUP_SYSTEM_AND_CONTROL ][   i]._supervisor_access_mode = SPR_ACCESS_MODE_READ_WRITE;
    	    _spr_generic [GROUP_SYSTEM_AND_CONTROL ][  19]._user_access_mode       = SPR_ACCESS_MODE_READ_ONLY;
    	    _spr_generic [GROUP_SYSTEM_AND_CONTROL ][  19]._supervisor_access_mode = SPR_ACCESS_MODE_READ_WRITE;
    	    _spr_generic [GROUP_SYSTEM_AND_CONTROL ][  20]._user_access_mode       = SPR_ACCESS_MODE_READ_ONLY_COND;
    	    _spr_generic [GROUP_SYSTEM_AND_CONTROL ][  20]._supervisor_access_mode = SPR_ACCESS_MODE_READ_WRITE;
    	    
    	    const uint32_t nb_shadow = 1; // max 16
    	    
    	    for (uint32_t i=32; i<32+nb_shadow; i++)
    	    _spr_generic [GROUP_SYSTEM_AND_CONTROL ][   i]._supervisor_access_mode = SPR_ACCESS_MODE_READ_WRITE;
    	    for (uint32_t i=48; i<48+nb_shadow; i++)
    	    _spr_generic [GROUP_SYSTEM_AND_CONTROL ][   i]._supervisor_access_mode = SPR_ACCESS_MODE_READ_WRITE;
    	    for (uint32_t i=64; i<64+nb_shadow; i++)
    	    _spr_generic [GROUP_SYSTEM_AND_CONTROL ][   i]._supervisor_access_mode = SPR_ACCESS_MODE_READ_WRITE;
//     	    for (uint32_t i=1024; i<1024+32*nb_shadow; i++)
//     	    _spr_generic [GROUP_SYSTEM_AND_CONTROL ][   i]._supervisor_access_mode = SPR_ACCESS_MODE_READ_WRITE;

	    break;
	  }
	case GROUP_DMMU                :
	  {
	    implement_group(GROUP_DMMU                ,NB_REG_GROUP_DMMU                );

	    for (uint32_t i=0; i<=2; i++)
	    _spr_generic [GROUP_DMMU               ][   i]._supervisor_access_mode = SPR_ACCESS_MODE_READ_WRITE;
	    _spr_generic [GROUP_DMMU               ][   2]._supervisor_access_mode = SPR_ACCESS_MODE_WRITE_ONLY;
	    for (uint32_t i=4; i<=11; i++)
	    _spr_generic [GROUP_DMMU               ][   i]._supervisor_access_mode = SPR_ACCESS_MODE_READ_WRITE;
	    for (uint32_t i=512; i<=1535; i++)
	    _spr_generic [GROUP_DMMU               ][   i]._supervisor_access_mode = SPR_ACCESS_MODE_READ_WRITE;

	    break;
	  }
	case GROUP_IMMU                :
	  {
	    implement_group(GROUP_IMMU                ,NB_REG_GROUP_IMMU                );

	    for (uint32_t i=0; i<=2; i++)
	    _spr_generic [GROUP_IMMU               ][   i]._supervisor_access_mode = SPR_ACCESS_MODE_READ_WRITE;
	    _spr_generic [GROUP_IMMU               ][   2]._supervisor_access_mode = SPR_ACCESS_MODE_WRITE_ONLY;
	    for (uint32_t i=4; i<=11; i++)
	    _spr_generic [GROUP_IMMU               ][   i]._supervisor_access_mode = SPR_ACCESS_MODE_READ_WRITE;
	    for (uint32_t i=512; i<=1536; i++)
	    _spr_generic [GROUP_IMMU               ][   i]._supervisor_access_mode = SPR_ACCESS_MODE_READ_WRITE;
	    
	    break;
	  }
	case GROUP_DCACHE              :
	  {
	    implement_group(GROUP_DCACHE              ,NB_REG_GROUP_DCACHE              );

	    _spr_generic [GROUP_DCACHE             ][   0]._supervisor_access_mode = SPR_ACCESS_MODE_READ_WRITE;
	    for (uint32_t i=1; i<=5; i++)
	    	{
	    _spr_generic [GROUP_DCACHE             ][   i]._supervisor_access_mode = SPR_ACCESS_MODE_WRITE_ONLY;
	    _spr_generic [GROUP_DCACHE             ][   i]._user_access_mode       = SPR_ACCESS_MODE_WRITE_ONLY;
	    	}
	    _spr_generic [GROUP_DCACHE             ][   3]._user_access_mode       = SPR_ACCESS_MODE_NONE;
	    
	    break;
	  }
	case GROUP_ICACHE              :
	  {
	    implement_group(GROUP_ICACHE              ,NB_REG_GROUP_ICACHE              );

	    _spr_generic [GROUP_ICACHE             ][   0]._supervisor_access_mode = SPR_ACCESS_MODE_READ_WRITE;
	    for (uint32_t i=1; i<=3; i++)
	    	{
	    _spr_generic [GROUP_ICACHE             ][   i]._supervisor_access_mode = SPR_ACCESS_MODE_WRITE_ONLY;
	    _spr_generic [GROUP_ICACHE             ][   i]._user_access_mode       = SPR_ACCESS_MODE_WRITE_ONLY;
	    	}
	    _spr_generic [GROUP_ICACHE             ][   2]._user_access_mode       = SPR_ACCESS_MODE_NONE;
	    
	    break;
	  }
	case GROUP_MAC                 :
	  {
	    implement_group(GROUP_MAC                 ,NB_REG_GROUP_MAC                 );

	    for (uint32_t i=1; i<=2; i++)
	    	{
	    _spr_generic [GROUP_MAC                ][   i]._supervisor_access_mode = SPR_ACCESS_MODE_READ_WRITE;
	    _spr_generic [GROUP_MAC                ][   i]._user_access_mode       = SPR_ACCESS_MODE_READ_WRITE;
	    	}
	    
	    break;
	  }
	case GROUP_DEBUG               :
	  {
	    implement_group(GROUP_DEBUG               ,NB_REG_GROUP_DEBUG               );

	    for (uint32_t i=0; i<=21; i++)
	    _spr_generic [GROUP_DEBUG              ][   i]._supervisor_access_mode = SPR_ACCESS_MODE_READ_WRITE;
	    
	    break;
	  }
	case GROUP_PERFORMANCE_COUNTER :
	  {
	    implement_group(GROUP_PERFORMANCE_COUNTER ,NB_REG_GROUP_PERFORMANCE_COUNTER );

	    for (uint32_t i=0; i<=7; i++)
	    	{
	    _spr_generic [GROUP_PERFORMANCE_COUNTER][   i]._user_access_mode       = SPR_ACCESS_MODE_READ_ONLY_COND;
	    _spr_generic [GROUP_PERFORMANCE_COUNTER][   i]._supervisor_access_mode = SPR_ACCESS_MODE_READ_WRITE;
	    	}
	    for (uint32_t i=8; i<=15; i++)
	    _spr_generic [GROUP_PERFORMANCE_COUNTER][   i]._supervisor_access_mode = SPR_ACCESS_MODE_READ_WRITE;
	    
	    break;
	  }
	case GROUP_POWER_MANAGEMENT    :
	  {
	    implement_group(GROUP_POWER_MANAGEMENT    ,NB_REG_GROUP_POWER_MANAGEMENT    );

	    _spr_generic [GROUP_POWER_MANAGEMENT   ][   0]._supervisor_access_mode = SPR_ACCESS_MODE_READ_WRITE;
	    
	    break;
	  }
	case GROUP_PIC                 :
	  {
	    implement_group(GROUP_PIC                 ,NB_REG_GROUP_PIC                 );

	    _spr_generic [GROUP_PIC                ][   0]._supervisor_access_mode = SPR_ACCESS_MODE_READ_WRITE;
	    _spr_generic [GROUP_PIC                ][   2]._supervisor_access_mode = SPR_ACCESS_MODE_READ_WRITE;
	    
	    break;
	  }
	case GROUP_TICK_TIMER          :
	  {
	    implement_group(GROUP_TICK_TIMER          ,NB_REG_GROUP_TICK_TIMER          );

	    _spr_generic [GROUP_TICK_TIMER         ][   0]._supervisor_access_mode = SPR_ACCESS_MODE_READ_WRITE;
	    _spr_generic [GROUP_TICK_TIMER         ][   1]._supervisor_access_mode = SPR_ACCESS_MODE_READ_WRITE;
	    _spr_generic [GROUP_TICK_TIMER         ][   1]._user_access_mode       = SPR_ACCESS_MODE_READ_ONLY_COND;
	    
	    break;
	  }
	case GROUP_FLOATING_POINT      :
	  {
	    implement_group(GROUP_FLOATING_POINT      ,NB_REG_GROUP_FLOATING_POINT      );
	    break;
	  }
	case GROUP_RESERVED_1          : 
	case GROUP_RESERVED_2          : 
	case GROUP_RESERVED_3          : 
	case GROUP_RESERVED_4          : 
	case GROUP_RESERVED_5          : 
	case GROUP_RESERVED_6          : 
	case GROUP_RESERVED_7          : 
	case GROUP_RESERVED_8          : 
	case GROUP_RESERVED_9          : 
	case GROUP_RESERVED_10         : 
	case GROUP_RESERVED_11         : 
	case GROUP_RESERVED_12         : 
	  {
	    throw ERRORMORPHEO("SPR_access_mode::implement_group", "group number is invalid : it's a reserved group.");
	    break;
	  }
	case GROUP_CUSTOM_1            : 
	case GROUP_CUSTOM_2            : 
	case GROUP_CUSTOM_3            : 
	case GROUP_CUSTOM_4            : 
	case GROUP_CUSTOM_5            : 
	case GROUP_CUSTOM_6            : 
	case GROUP_CUSTOM_7            : 
	case GROUP_CUSTOM_8            :
	  {
	    throw ERRORMORPHEO("SPR_access_mode::implement_group", "group number is invalid : it's a custom group.");
	    break;
	  }
	default :
	  {
	    throw ERRORMORPHEO("SPR_access_mode::implement_group", "group number is invalid : it's a unknow group.");
	    break;
	  }
	}

      return _max_register_by_group[num_group];
    }

}; // end namespace behavioural
}; // end namespace morpheo              

