#ifndef morpheo_behavioural_Constants_h
#define morpheo_behavioural_Constants_h

/*
  WARNING : 
  
  I Use reserved exception : 

  0x10 - EXCEPTION_MEMORY_MISS_SPECULATION   - Load miss speculation
  0x11 - EXCEPTION_MEMORY_LOAD_SPECULATIVE   - The load is speculative : write in register file, but don't commit
  0x12 - EXCEPTION_ALU_SPR_ACCESS_INVALID    - SPR     present in ALU but not compatible privilege
  0x13 - EXCEPTION_ALU_SPR_ACCESS_MUST_READ  - SPR not present in ALU
  0x14 - EXCEPTION_ALU_SPR_ACCESS_MUST_WRITE - SPR not present in ALU

  I Use reserved SPR :
  [0][21] - SPR_CID : Context Id      
  [0][22] - SPR_TID : Thread  Id      
  [0][23] - SPR_TSR : Thread  Status Register (Priority)
*/

#include "Common/include/ToString.h"

namespace morpheo {
namespace behavioural {

#  define SET_FLAG(     x,pos)  {(x) |=  (1<<(pos));} while (0)
#  define UNSET_FLAG(   x,pos)  {(x) &= ~(1<<(pos));} while (0)
#  define IS_SET_FLAG(  x,pos) (((x) &   (1<<(pos))) != 0)
#  define IS_UNSET_FLAG(x,pos) (((x) &   (1<<(pos))) == 0)
#  define CHANGE_FLAG(  x,pos,f) \
   {                        \
     if (f)                 \
       {SET_FLAG(x,pos);}   \
     else                   \
       {UNSET_FLAG(x,pos);} \
   } while (0)

  //=========================================================[ Type ]=====
typedef enum
  {
    TYPE_ALU                               = 0x0,       // 0000 - unit multiple
    TYPE_SHIFT                             = 0x1,       // 0000 - unit multiple
    TYPE_MOVE                              = 0x2,       // 0000 - unit multiple
    TYPE_TEST                              = 0x3,       // 0000 - unit multiple
    TYPE_MUL                               = 0x4,       // 0000 - unit multiple
    TYPE_DIV                               = 0x5,       // 0000 - unit multiple, type optionnal
    TYPE_EXTEND                            = 0x6,       // 0000 - unit multiple, type optionnal
    TYPE_FIND                              = 0x7,       // 0000 - unit multiple, type optionnal
    TYPE_SPECIAL                           = 0x8,       // 0000 - unit uniq
    TYPE_CUSTOM                            = 0x9,       // 0000 - unit uniq    , type optionnal
    TYPE_BRANCH                            = 0xa,       // 0000 - unit multiple
    TYPE_MEMORY                            = 0xb,       // 0000 - unit uniq    , type exclusive
    TYPE_INVALID                           = 0xf        // 1111 - none
  } type_t;

//#define NB_TYPE                                  11
#  define SIZE_TYPE                                5
#  define MAX_TYPE                                 (1<<SIZE_TYPE)

    // TYPE         | multiple? | Optionnal? | Exclusive? | Comment
    //--------------+-----------+------------+------------+---------
    // TYPE_ALU     |     X     |            |            |
    // TYPE_SHIFT   |     X     |            |            | ror is optionnal
    // TYPE_MOVE    |     X     |            |            | cmov is optionnal
    // TYPE_TEST    |     X     |            |            |
    // TYPE_MUL     |     X     |            |            |
    // TYPE_DIV     |     X     |     X      |            |
    // TYPE_EXTEND  |     X     |     X      |            |
    // TYPE_FIND    |     X     |     X      |            |
    // TYPE_SPECIAL |           |            |            | mac unit is optionnal
    // TYPE_CUSTOM  |           |     X      |            |
    // TYPE_BRANCH  |     X     |            |            |
    // TYPE_MEMORY  |           |            |     X      |

#  define is_type_valid(x) \
  ((x == TYPE_ALU    ) or \
   (x == TYPE_SHIFT  ) or \
   (x == TYPE_MOVE   ) or \
   (x == TYPE_TEST   ) or \
   (x == TYPE_MUL    ) or \
   (x == TYPE_DIV    ) or \
   (x == TYPE_EXTEND ) or \
   (x == TYPE_FIND   ) or \
   (x == TYPE_SPECIAL) or \
   (x == TYPE_CUSTOM ) or \
   (x == TYPE_BRANCH ) or \
   (x == TYPE_MEMORY ))

#  define is_type_uniq(x) \
  ((x == TYPE_SPECIAL) or \
   (x == TYPE_CUSTOM ) or \
   (x == TYPE_MEMORY ))

#  define is_type_optionnal(x) \
  ((x == TYPE_DIV    ) or \
   (x == TYPE_EXTEND ) or \
   (x == TYPE_FIND   ) or \
   (x == TYPE_CUSTOM ))

#  define is_type_exclusive(x) \
  ((x == TYPE_MEMORY ))

  //====================================================[ Operation ]=====

  //-------------------------------------------------------[ Memory ]-----
#  define OPERATION_MEMORY_LOAD_8_Z                0x08       // 0_1000
#  define OPERATION_MEMORY_LOAD_16_Z               0x09       // 0_1001
#  define OPERATION_MEMORY_LOAD_32_Z               0x0a       // 0_1010
#  define OPERATION_MEMORY_LOAD_64_Z               0x0b       // 0_1011
#  define OPERATION_MEMORY_LOAD_8_S                0x18       // 1_1000
#  define OPERATION_MEMORY_LOAD_16_S               0x19       // 1_1001
#  define OPERATION_MEMORY_LOAD_32_S               0x1a       // 1_1010
#  define OPERATION_MEMORY_LOAD_64_S               0x1b       // 1_1011

#  define OPERATION_MEMORY_STORE_8                 0x0c       // 0_1100
#  define OPERATION_MEMORY_STORE_16                0x0d       // 0_1101
#  define OPERATION_MEMORY_STORE_32                0x0e       // 0_1110
#  define OPERATION_MEMORY_STORE_64                0x0f       // 0_1111
#  define OPERATION_MEMORY_STORE_HEAD_OK           0x1c       // 1_1100
#  define OPERATION_MEMORY_STORE_HEAD_KO           0x1d       // 1_1101

#  define OPERATION_MEMORY_LOCK                    0x01       // 0_0001
#  define OPERATION_MEMORY_INVALIDATE              0x02       // 0_0010
#  define OPERATION_MEMORY_PREFETCH                0x03       // 0_0011
#  define OPERATION_MEMORY_FLUSH                   0x06       // 0_0110
#  define OPERATION_MEMORY_SYNCHRONIZATION         0x07       // 0_0111
  
#define is_operation_memory_load(x)             \
  ((x == OPERATION_MEMORY_LOAD_8_Z ) or		\
   (x == OPERATION_MEMORY_LOAD_16_Z) or		\
   (x == OPERATION_MEMORY_LOAD_32_Z) or		\
   (x == OPERATION_MEMORY_LOAD_64_Z) or		\
   (x == OPERATION_MEMORY_LOAD_8_S ) or		\
   (x == OPERATION_MEMORY_LOAD_16_S) or		\
   (x == OPERATION_MEMORY_LOAD_32_S) or		\
   (x == OPERATION_MEMORY_LOAD_64_S) )
  
#define is_operation_memory_store(x)		\
  ((x == OPERATION_MEMORY_STORE_8      ) or	\
   (x == OPERATION_MEMORY_STORE_16     ) or	\
   (x == OPERATION_MEMORY_STORE_32     ) or	\
   (x == OPERATION_MEMORY_STORE_64     ) or	\
   (x == OPERATION_MEMORY_STORE_HEAD_OK) or	\
   (x == OPERATION_MEMORY_STORE_HEAD_KO))

#define is_operation_memory_store_head(x)       \
  ((x == OPERATION_MEMORY_STORE_HEAD_OK) or	\
   (x == OPERATION_MEMORY_STORE_HEAD_KO))
  
#define is_operation_memory_load_signed(x)      \
  ((x == OPERATION_MEMORY_LOAD_8_S ) or		\
   (x == OPERATION_MEMORY_LOAD_16_S) or		\
   (x == OPERATION_MEMORY_LOAD_32_S) or		\
   (x == OPERATION_MEMORY_LOAD_64_S) )

#  define MEMORY_ACCESS_8                          0x0
#  define MEMORY_ACCESS_16                         0x1
#  define MEMORY_ACCESS_32                         0x2
#  define MEMORY_ACCESS_64                         0x3

#  define MEMORY_SIZE_8                            8 
#  define MEMORY_SIZE_16                           16
#  define MEMORY_SIZE_32                           32
#  define MEMORY_SIZE_64                           64

#  define MASK_MEMORY_ACCESS_8                     0x0
#  define MASK_MEMORY_ACCESS_16                    0x1
#  define MASK_MEMORY_ACCESS_32                    0x3
#  define MASK_MEMORY_ACCESS_64                    0x7

#define memory_size(x)							\
  (((x==OPERATION_MEMORY_LOAD_16_Z)or					\
    (x==OPERATION_MEMORY_LOAD_16_S)or					\
    (x==OPERATION_MEMORY_STORE_16 ))?MEMORY_SIZE_16:			\
   (((x==OPERATION_MEMORY_LOAD_32_Z)or					\
     (x==OPERATION_MEMORY_LOAD_32_S)or					\
     (x==OPERATION_MEMORY_STORE_32 ))?MEMORY_SIZE_32:			\
    (((x==OPERATION_MEMORY_LOAD_64_Z)or					\
      (x==OPERATION_MEMORY_LOAD_64_S)or					\
      (x==OPERATION_MEMORY_STORE_64 ))?MEMORY_SIZE_64:MEMORY_SIZE_8)))
  
#define memory_access(x)						\
  (((x==OPERATION_MEMORY_LOAD_16_Z)or					\
    (x==OPERATION_MEMORY_LOAD_16_S)or					\
    (x==OPERATION_MEMORY_STORE_16 ))?MEMORY_ACCESS_16:			\
   (((x==OPERATION_MEMORY_LOAD_32_Z)or					\
     (x==OPERATION_MEMORY_LOAD_32_S)or					\
     (x==OPERATION_MEMORY_STORE_32 ))?MEMORY_ACCESS_32:			\
    (((x==OPERATION_MEMORY_LOAD_64_Z)or					\
      (x==OPERATION_MEMORY_LOAD_64_S)or					\
      (x==OPERATION_MEMORY_STORE_64 ))?MEMORY_ACCESS_64:MEMORY_ACCESS_8)))
  
#define mask_memory_access(x)						\
  (((x==OPERATION_MEMORY_LOAD_16_Z)or					\
    (x==OPERATION_MEMORY_LOAD_16_S)or					\
    (x==OPERATION_MEMORY_STORE_16 ))?MASK_MEMORY_ACCESS_16:		\
   (((x==OPERATION_MEMORY_LOAD_32_Z)or					\
     (x==OPERATION_MEMORY_LOAD_32_S)or					\
     (x==OPERATION_MEMORY_STORE_32 ))?MASK_MEMORY_ACCESS_32:		\
    (((x==OPERATION_MEMORY_LOAD_64_Z)or					\
      (x==OPERATION_MEMORY_LOAD_64_S)or					\
      (x==OPERATION_MEMORY_STORE_64 ))?MASK_MEMORY_ACCESS_64:MASK_MEMORY_ACCESS_8)))

  //---------------------------------------------[ Functionnal Unit ]-----

  // WARNING : Operations are coded in a one-hot implementation that is used in the functional unit's vhdl code.
  //           Do not change that (you can still change the values as long as it respects the one-hot encoding).

#  define OPERATION_ALU_L_ADD                      0x1        // 000_0001 l.add   , l.addi
#  define OPERATION_ALU_L_ADDC                     0x2        // 000_0010 l.addc  , l.addic
#  define OPERATION_ALU_L_SUB                      0x4        // 000_0100 l.sub
#  define OPERATION_ALU_L_AND                      0x8        // 000_1000 l.and   , l.andi
#  define OPERATION_ALU_L_OR                       0x10       // 001_0000 l.or    , l.ori
#  define OPERATION_ALU_L_XOR                      0x20       // 010_0000 l.xor   , l.xori

  // WARNING : Shift and rotate operation codes are hard-coded in the functional unit's vhdl code,
  //           with bit 0 corresponding to the direction (0 for right, and 1 for left),
  //           bit 1 to the type (0 for shift, 1 for rotate) and bit 2 is to be set to 0 for a logic
  //           operation and 1 for an arithmetic operation.
  //           Do not change that (unless you respect the one-hot encoding described above).

#  define OPERATION_SHIFT_L_SLL                    0x1        // 000_0001 l.sll   , l.slli
#  define OPERATION_SHIFT_L_SRA                    0x4        // 000_0100 l.sra   , l.srai
#  define OPERATION_SHIFT_L_SRL                    0x0        // 000_0000 l.srl   , l.srli
#  define OPERATION_SHIFT_L_ROR                    0x2        // 000_0010 l.ror   , l.rori

#  define OPERATION_MOVE_L_MOVHI                   0x1        // 000_0001 l.movhi
#  define OPERATION_MOVE_L_CMOV                    0x2        // 000_0010 l.cmov

#  define OPERATION_TEST_L_SFGES                   0x45       // 100_0101 l.sfges , l.sfges
#  define OPERATION_TEST_L_SFGEU                   0x5        // 000_0101 l.sfgeu , l.sfgeu
#  define OPERATION_TEST_L_SFGTS                   0x46       // 100_0110 L.sfgts , l.sfgts
#  define OPERATION_TEST_L_SFGTU                   0x6        // 000_0110 l.sfgtu , l.sfgtu
#  define OPERATION_TEST_L_SFLES                   0x49       // 100_1001 l.sfles , l.sfles
#  define OPERATION_TEST_L_SFLEU                   0x9        // 000_1001 l.sfleu , l.sfleu
#  define OPERATION_TEST_L_SFLTS                   0x4A       // 100_1010 l.sflts , l.sflts
#  define OPERATION_TEST_L_SFLTU                   0xA        // 000_1010 l.sfltu , l.sfltu
#  define OPERATION_TEST_L_SFEQ                    0x10       // 001_0000 l.sfeq  , l.sfeqi
#  define OPERATION_TEST_L_SFNE                    0x20       // 010_0000 l.sfne  , l.sfnei

#  define OPERATION_MUL_L_MUL                      0x1        // 000_0001 l.mul   , l.muli
#  define OPERATION_MUL_L_MULU                     0x2        // 000_0010 l.mulu

#  define OPERATION_DIV_L_DIV                      0x1        // 000_0001 l.div
#  define OPERATION_DIV_L_DIVU                     0x2        // 000_0010 l.divu

#  define OPERATION_EXTEND_L_EXTEND_Z              0x1        // 000_0001 l.extbz , l.exthz, l.extwz
#  define OPERATION_EXTEND_L_EXTEND_S              0x2        // 000_0010 l.extbs , l.exths, l.extws

#  define OPERATION_FIND_L_FF1                     0x1        // 000_0001 l.ff1
#  define OPERATION_FIND_L_FL1                     0x2        // 000_0010 l.fl1

#  define OPERATION_SPECIAL_L_NOP                  0x7f       // 111_1111 l.nop   
#  define OPERATION_SPECIAL_L_MFSPR                0x1        // 000_0001 l.mfspr
#  define OPERATION_SPECIAL_L_MTSPR                0x2        // 000_0010 l.mtspr
#  define OPERATION_SPECIAL_L_RFE                  0x4        // 000_0100 l.rfe  
#  define OPERATION_SPECIAL_L_MAC                  0x11       // 001_0001 l.mac   , l.maci
#  define OPERATION_SPECIAL_L_MACRC                0x12       // 001_0010 l.macrc
#  define OPERATION_SPECIAL_L_MSB                  0x14       // 001_0100 l.msb
//#define OPERATION_SPECIAL_L_MSYNC                0x21       // 010_0001 l.msync
//#define OPERATION_SPECIAL_L_PSYNC                0x22       // 010_0010 l.psync
//#define OPERATION_SPECIAL_L_CSYNC                0x24       // 010_0100 l.csync
#  define OPERATION_SPECIAL_L_SYS                  0x41       // 100_0001 l.sys  
#  define OPERATION_SPECIAL_L_TRAP                 0x42       // 100_0010 l.trap 

#  define OPERATION_BRANCH_NONE                    0x1        // 000_0001 l.j
#  define OPERATION_BRANCH_L_TEST_NF               0x2        // 000_0010 l.bnf
#  define OPERATION_BRANCH_L_TEST_F                0x4        // 000_0100 l.bf
#  define OPERATION_BRANCH_L_JALR                  0x8        // 000_1000 l.jal   , l.jalr , l.jr

  //-------------------------------------------------------[ Custom ]-----

#  define OPERATION_CUSTOM_L_1                     0x40       // 100_0000
#  define OPERATION_CUSTOM_L_2                     0x41       // 100_0001
#  define OPERATION_CUSTOM_L_3                     0x42       // 100_0010
#  define OPERATION_CUSTOM_L_4                     0x43       // 100_0011
#  define OPERATION_CUSTOM_L_5                     0x44       // 100_0100
#  define OPERATION_CUSTOM_L_6                     0x45       // 100_0101
#  define OPERATION_CUSTOM_L_7                     0x46       // 100_0110
#  define OPERATION_CUSTOM_L_8                     0x47       // 100_0111
#  define OPERATION_CUSTOM_LF_1_D                  0x48       // 100_1000
#  define OPERATION_CUSTOM_LF_1_S                  0x49       // 100_1001
#  define OPERATION_CUSTOM_LV_1                    0x4c       // 100_1100
#  define OPERATION_CUSTOM_LV_2                    0x4d       // 100_1101
#  define OPERATION_CUSTOM_LV_3                    0x4e       // 100_1110
#  define OPERATION_CUSTOM_LV_4                    0x4f       // 100_1111

#  define SIZE_OPERATION                           7
#  define MAX_OPERATION                            (1<<SIZE_OPERATION)

  //====================================================[ Exception ]=====
  // Exception - OpenRISC

#  define SIZE_EXCEPTION                           5
#  define SIZE_EXCEPTION_USE                       4
#  define SIZE_EXCEPTION_MEMORY                    5
#  define SIZE_EXCEPTION_CUSTOM                    5
#  define SIZE_EXCEPTION_ALU                       5
#  define SIZE_EXCEPTION_DECOD                     5
#  define SIZE_EXCEPTION_IFETCH                    5

#  define EXCEPTION_NONE                           0x00       // none exception
#  define EXCEPTION_RESET                          0x01       // software or hardware reset
#  define EXCEPTION_BUS_ERROR                      0x02       // Access at a invalid physical adress
#  define EXCEPTION_DATA_PAGE                      0x03       // No matching or page violation protection in pages tables
#  define EXCEPTION_INSTRUCTION_PAGE               0x04       // No matching or page violation protection in pages tables
#  define EXCEPTION_TICK_TIMER                     0x05       // Tick timer interruption
#  define EXCEPTION_ALIGNMENT                      0x06       // Load/Store access is not aligned
#  define EXCEPTION_ILLEGAL_INSTRUCTION            0x07       // Instruction is illegal (no implemented)
#  define EXCEPTION_INTERRUPT                      0x08       // External interruption 
#  define EXCEPTION_DATA_TLB                       0x09       // DTLB miss
#  define EXCEPTION_INSTRUCTION_TLB                0x0a       // ITLB miss
#  define EXCEPTION_RANGE                          0x0b       // Overflow or access at a unimplemented register or context
#  define EXCEPTION_SYSCALL                        0x0c       // System Call
#  define EXCEPTION_FLOATING_POINT                 0x0d       // Caused by a floating instruction
#  define EXCEPTION_TRAP                           0x0e       // L.trap or debug unit
#  define EXCEPTION_RESERVED_0                     0x0f       // Reserved for a futur usage
#  define EXCEPTION_RESERVED_1                     0x10       // Reserved for a futur usage
#  define EXCEPTION_RESERVED_2                     0x11       // Reserved for a futur usage
#  define EXCEPTION_RESERVED_3                     0x12       // Reserved for a futur usage
#  define EXCEPTION_RESERVED_4                     0x13       // Reserved for a futur usage
#  define EXCEPTION_RESERVED_5                     0x14       // Reserved for a futur usage
#  define EXCEPTION_RESERVED_6                     0x15       // Reserved for implemented specific exceptions
#  define EXCEPTION_RESERVED_7                     0x16       // Reserved for implemented specific exceptions
#  define EXCEPTION_RESERVED_8                     0x17       // Reserved for implemented specific exceptions
#  define EXCEPTION_RESERVED_9                     0x18       // Reserved for implemented specific exceptions
#  define EXCEPTION_CUSTOM_0                       0x19       // Reserved for custom exceptions
#  define EXCEPTION_CUSTOM_1                       0x1a       // Reserved for custom exceptions
#  define EXCEPTION_CUSTOM_2                       0x1b       // Reserved for custom exceptions
#  define EXCEPTION_CUSTOM_3                       0x1c       // Reserved for custom exceptions
#  define EXCEPTION_CUSTOM_4                       0x1d       // Reserved for custom exceptions
#  define EXCEPTION_CUSTOM_5                       0x1e       // Reserved for custom exceptions
#  define EXCEPTION_CUSTOM_6                       0x1f       // Reserved for custom exceptions

  //SR[14].EPH : Exception Prefix High
  // EPH = 0 Exceptions vectors are located in memory area starting at 0x0
  // EPH = 1 Exception vectors are located in memory area starting at 0xF0000000

#define exception_to_address(eph,x) (((eph==0)?0x0:0xF0000000)+(x<<8))

  // Exception Execution
#  define EXCEPTION_IFETCH_NONE                    0x00       //   Fetch Unit generate none exception
#  define EXCEPTION_IFETCH_INSTRUCTION_TLB         0x0a       //   ITLB miss
#  define EXCEPTION_IFETCH_INSTRUCTION_PAGE        0x04       //   No matching or page violation protection in pages tables
#  define EXCEPTION_IFETCH_BUS_ERROR               0x02       //   Access at a invalid physical address
                                                                   
#  define EXCEPTION_DECOD_NONE                     0x00       //   none exception
#  define EXCEPTION_DECOD_ILLEGAL_INSTRUCTION      0x01       //   Instruction is illegal (no implemented)
#  define EXCEPTION_DECOD_SYSCALL                  0x02       //   System Call
//#define EXCEPTION_DECOD_TRAP                     0x0e       //   L.trap or debug unit (note : must read SR !)
#  define EXCEPTION_DECOD_INSTRUCTION_TLB          0x0a       //   ITLB miss
#  define EXCEPTION_DECOD_INSTRUCTION_PAGE         0x04       //   No matching or page violation protection in pages tables
#  define EXCEPTION_DECOD_BUS_ERROR                0x02       //   Access at a invalid physical address
                                                                   
  // WARNING : Keep EXCEPTION_ALU_NONE value at 0x00 (kind of hard coded in functional unit's vhdl code).
#  define EXCEPTION_ALU_NONE                       0x00       //   Functionnal unit generate none exception
#  define EXCEPTION_ALU_RANGE                      0x0b       //   
#  define EXCEPTION_ALU_SPR_ACCESS_INVALID         0x12       // * SPR     present in ALU but not compatible privilege
#  define EXCEPTION_ALU_SPR_ACCESS_MUST_READ       0x13       // * SPR not present in ALU
#  define EXCEPTION_ALU_SPR_ACCESS_MUST_WRITE      0x14       // * SPR not present in ALU
                                                                   
#  define EXCEPTION_MEMORY_NONE                    0x00       //   Load/Store generate none exception
#  define EXCEPTION_MEMORY_ALIGNMENT               0x06       //   Load/Store access is not aligned
#  define EXCEPTION_MEMORY_DATA_TLB                0x09       //   DTLB miss
#  define EXCEPTION_MEMORY_DATA_PAGE               0x03       //   No matching or page violation protection in pages tables
#  define EXCEPTION_MEMORY_BUS_ERROR               0x02       //   Access at a invalid physical address
#  define EXCEPTION_MEMORY_MISS_SPECULATION        0x10       // * Load miss speculation
#  define EXCEPTION_MEMORY_LOAD_SPECULATIVE        0x11       // * The load is speculative : write in register file, but don't commit
                                                                   
#  define EXCEPTION_CUSTOM_NONE                    0x00       //   Custom unit generate none exception
#  define EXCEPTION_CUSTOM_CUST_0                  0x19       //   Reserved for custom exceptions
#  define EXCEPTION_CUSTOM_CUST_1                  0x1a       //   Reserved for custom exceptions
#  define EXCEPTION_CUSTOM_CUST_2                  0x1b       //   Reserved for custom exceptions
#  define EXCEPTION_CUSTOM_CUST_3                  0x1c       //   Reserved for custom exceptions
#  define EXCEPTION_CUSTOM_CUST_4                  0x1d       //   Reserved for custom exceptions
#  define EXCEPTION_CUSTOM_CUST_5                  0x1e       //   Reserved for custom exceptions
#  define EXCEPTION_CUSTOM_CUST_6                  0x1f       //   Reserved for custom exceptions
                                                                   
#  define EXCEPTION_USE_NONE                       0x00       //   
#  define EXCEPTION_USE_ILLEGAL_INSTRUCTION        0x01       //   illegal_instruction
#  define EXCEPTION_USE_RANGE                      0x02       //   range
#  define EXCEPTION_USE_MEMORY_WITH_ALIGNMENT      0x03       //   TLB miss, page fault, bus error, alignment
#  define EXCEPTION_USE_MEMORY_WITHOUT_ALIGNMENT   0x04       //   TLB miss, page fault, bus error
#  define EXCEPTION_USE_SYSCALL                    0x05       //   syscall
#  define EXCEPTION_USE_TRAP                       0x06       //   trap
#  define EXCEPTION_USE_CUSTOM_0                   0x07       //   
#  define EXCEPTION_USE_CUSTOM_1                   0x08       //   
#  define EXCEPTION_USE_CUSTOM_2                   0x09       //   
#  define EXCEPTION_USE_CUSTOM_3                   0x0a       //   
#  define EXCEPTION_USE_CUSTOM_4                   0x0b       //   
#  define EXCEPTION_USE_CUSTOM_5                   0x0c       //   
#  define EXCEPTION_USE_CUSTOM_6                   0x0d       //   

#  define exception_ifetch_to_exception_decod(x) x
#  define exception_decod_to_exception(x)        x
#  define exception_alu_to_exception(x)          x
#  define exception_memory_to_exception(x)       x
#  define exception_custom_to_exception(x)       x

  //=======================================================[ icache ]=====

  //--------------------------------------------------[ icache_type ]-----

#  define SIZE_ICACHE_TYPE                         2

#  define ICACHE_TYPE_LOAD                         0x0        // 0000
#  define ICACHE_TYPE_LOCK                         0x1        // 0001
#  define ICACHE_TYPE_INVALIDATE                   0x2        // 0010
#  define ICACHE_TYPE_PREFETCH                     0x3        // 0011

// just take the 2 less significative bits.
#define operation_to_icache_type(x) (x&0x3)

  //-------------------------------------------------[ icache_error ]-----

#  define SIZE_ICACHE_ERROR                        1

#  define ICACHE_ERROR_NONE                        0x0
#  define ICACHE_ERROR_BUS_ERROR                   0x1

  //=======================================================[ dcache ]=====

  //--------------------------------------------------[ dcache_type ]-----

#  define SIZE_DCACHE_TYPE                         4

//#define DCACHE_TYPE_                             0x0        // 0000
#  define DCACHE_TYPE_LOCK                         0x1        // 0001
#  define DCACHE_TYPE_INVALIDATE                   0x2        // 0010
#  define DCACHE_TYPE_PREFETCH                     0x3        // 0011
//#define DCACHE_TYPE_                             0x4        // 0100
//#define DCACHE_TYPE_                             0x5        // 0101
#  define DCACHE_TYPE_FLUSH                        0x6        // 0110
#  define DCACHE_TYPE_SYNCHRONIZATION              0x7        // 0111
#  define DCACHE_TYPE_LOAD_8                       0x8        // 1000
#  define DCACHE_TYPE_LOAD_16                      0x9        // 1001
#  define DCACHE_TYPE_LOAD_32                      0xa        // 1010
#  define DCACHE_TYPE_LOAD_64                      0xb        // 1011
#  define DCACHE_TYPE_STORE_8                      0xc        // 1100
#  define DCACHE_TYPE_STORE_16                     0xd        // 1101
#  define DCACHE_TYPE_STORE_32                     0xe        // 1110
#  define DCACHE_TYPE_STORE_64                     0xf        // 1111

// just take the 4 less significative bits.
#define operation_to_dcache_type(x) (x&0xf)

  //-------------------------------------------------[ dcache_error ]-----

#  define SIZE_DCACHE_ERROR                        1

#  define DCACHE_ERROR_NONE                        0x0
#  define DCACHE_ERROR_BUS_ERROR                   0x1

  //=================================================[ special_data ]=====

#  define SIZE_SPECIAL_DATA                        2

// Position of flag in "rename register SR" (NOT IN "SR")
#  define FLAG_POSITION_F                          0x0         // Conditionnal branch flag
#  define FLAG_POSITION_CY                         0x1         // Carry was produced by last arithmetic operation
#  define FLAG_POSITION_OV                         0x0         // Overflow occured during last arithmetic operation

#  define FLAG_F                                   (1<<FLAG_POSITION_F ) // Conditionnal branch flag
#  define FLAG_CY                                  (1<<FLAG_POSITION_CY) // Carry was produced by last arithmetic operation
#  define FLAG_OV                                  (1<<FLAG_POSITION_OV) // Overflow occured during last arithmetic operation

  //==========================================================[ spr ]=====

  enum
    {
      GROUP_SYSTEM_AND_CONTROL,  // 0
      GROUP_DMMU,                // 1
      GROUP_IMMU,                // 2
      GROUP_DCACHE,              // 3
      GROUP_ICACHE,              // 4
      GROUP_MAC,                 // 5
      GROUP_DEBUG,               // 6
      GROUP_PERFORMANCE_COUNTER, // 7
      GROUP_POWER_MANAGEMENT,    // 8
      GROUP_PIC,                 // 9
      GROUP_TICK_TIMER,          // 10
      GROUP_FLOATING_POINT,      // 11
      GROUP_RESERVED_1,          // 12     
      GROUP_RESERVED_2,          // 13     
      GROUP_RESERVED_3,          // 14     
      GROUP_RESERVED_4,          // 15     
      GROUP_RESERVED_5,          // 16     
      GROUP_RESERVED_6,          // 17     
      GROUP_RESERVED_7,          // 18     
      GROUP_RESERVED_8,          // 19     
      GROUP_RESERVED_9,          // 20     
      GROUP_RESERVED_10,         // 21     
      GROUP_RESERVED_11,         // 22     
      GROUP_RESERVED_12,         // 23
      GROUP_CUSTOM_1,            // 24     
      GROUP_CUSTOM_2,            // 25     
      GROUP_CUSTOM_3,            // 26     
      GROUP_CUSTOM_4,            // 27     
      GROUP_CUSTOM_5,            // 28     
      GROUP_CUSTOM_6,            // 29     
      GROUP_CUSTOM_7,            // 30     
      GROUP_CUSTOM_8,            // 31     
      NB_GROUP
    };

#  define NB_REG_GROUP_SYSTEM_AND_CONTROL          1536
#  define NB_REG_GROUP_DMMU                        1536
#  define NB_REG_GROUP_IMMU                        1536
#  define NB_REG_GROUP_DCACHE                      6
#  define NB_REG_GROUP_ICACHE                      4
#  define NB_REG_GROUP_MAC                         3
#  define NB_REG_GROUP_DEBUG                       22
#  define NB_REG_GROUP_PERFORMANCE_COUNTER         16
#  define NB_REG_GROUP_POWER_MANAGEMENT            1
#  define NB_REG_GROUP_PIC                         3
#  define NB_REG_GROUP_TICK_TIMER                  2
#  define NB_REG_GROUP_FLOATING_POINT              0
#  define NB_REG_GROUP_RESERVED_1                  0
#  define NB_REG_GROUP_RESERVED_2                  0
#  define NB_REG_GROUP_RESERVED_3                  0
#  define NB_REG_GROUP_RESERVED_4                  0
#  define NB_REG_GROUP_RESERVED_5                  0
#  define NB_REG_GROUP_RESERVED_6                  0
#  define NB_REG_GROUP_RESERVED_7                  0
#  define NB_REG_GROUP_RESERVED_8                  0
#  define NB_REG_GROUP_RESERVED_9                  0
#  define NB_REG_GROUP_RESERVED_10                 0
#  define NB_REG_GROUP_RESERVED_11                 0
#  define NB_REG_GROUP_RESERVED_12                 0
#  define NB_REG_GROUP_CUSTOM_1                    0
#  define NB_REG_GROUP_CUSTOM_2                    0
#  define NB_REG_GROUP_CUSTOM_3                    0
#  define NB_REG_GROUP_CUSTOM_4                    0
#  define NB_REG_GROUP_CUSTOM_5                    0
#  define NB_REG_GROUP_CUSTOM_6                    0
#  define NB_REG_GROUP_CUSTOM_7                    0
#  define NB_REG_GROUP_CUSTOM_8                    0

  static const uint32_t NB_REG_GROUP [] =
    {NB_REG_GROUP_SYSTEM_AND_CONTROL  ,
     NB_REG_GROUP_DMMU                ,
     NB_REG_GROUP_IMMU                ,
     NB_REG_GROUP_DCACHE              ,
     NB_REG_GROUP_ICACHE              ,
     NB_REG_GROUP_MAC                 ,
     NB_REG_GROUP_DEBUG               ,
     NB_REG_GROUP_PERFORMANCE_COUNTER ,
     NB_REG_GROUP_POWER_MANAGEMENT    ,
     NB_REG_GROUP_PIC                 ,
     NB_REG_GROUP_TICK_TIMER          ,
     NB_REG_GROUP_FLOATING_POINT      ,
     NB_REG_GROUP_RESERVED_1          ,
     NB_REG_GROUP_RESERVED_2          ,
     NB_REG_GROUP_RESERVED_3          ,
     NB_REG_GROUP_RESERVED_4          ,
     NB_REG_GROUP_RESERVED_5          ,
     NB_REG_GROUP_RESERVED_6          ,
     NB_REG_GROUP_RESERVED_7          ,
     NB_REG_GROUP_RESERVED_8          ,
     NB_REG_GROUP_RESERVED_9          ,
     NB_REG_GROUP_RESERVED_10         ,
     NB_REG_GROUP_RESERVED_11         ,
     NB_REG_GROUP_RESERVED_12         ,
     NB_REG_GROUP_CUSTOM_1            ,
     NB_REG_GROUP_CUSTOM_2            ,
     NB_REG_GROUP_CUSTOM_3            ,
     NB_REG_GROUP_CUSTOM_4            ,
     NB_REG_GROUP_CUSTOM_5            ,
     NB_REG_GROUP_CUSTOM_6            ,
     NB_REG_GROUP_CUSTOM_7            ,
     NB_REG_GROUP_CUSTOM_8            };
  
  // GROUP_SYSTEM_AND_CONTROL
#  define SPR_VR                                   0          // Version register
#  define SPR_UPR                                  1          // Unit Present register
#  define SPR_CPUCFGR                              2          // CPU Configuration register
#  define SPR_DMMUCFGR                             3          // Data MMU Configuration register
#  define SPR_IMMUCFGR                             4          // Instruction MMU Configuration register
#  define SPR_DCCFGR                               5          // Data Cache Configuration register
#  define SPR_ICCFGR                               6          // Instruction Cache Configuration register
#  define SPR_DCFGR                                7          // Debug Configuration register
#  define SPR_PCCFGR                               8          // Performance Counters Configuration register
#  define SPR_NPC                                  16         // PC mapped to SPR space (next PC)
#  define SPR_SR                                   17         // Supervision register
#  define SPR_PPC                                  18         // PC mapped to SPR space (previous PC)
#  define SPR_FPCSR                                20         // FP Control Status register
#  define SPR_CID                                  21         // Context Id
#  define SPR_TID                                  22         // Thread  Id
#  define SPR_TSR                                  23         // Thread  Priority
#  define SPR_EPCR                                 32         // Exception PC register
#  define SPR_EEAR                                 48         // Exception EA register
#  define SPR_ESR                                  64         // Exception SR register
#  define SPR_GPR                                  1024       // GPRs mappted to SPR space
  
  // GROUP_DCACHE
#  define SPR_DCCR                                 0          // DC Control register
#  define SPR_DCBPR                                1          // DC Block Prefetch register
#  define SPR_DCBFR                                2          // DC Block Flush register
#  define SPR_DCBIR                                3          // DC Block Invalidate register
#  define SPR_DCBWR                                4          // DC Block Write-back register
#  define SPR_DCBLR                                5          // DC Block Lock register

  // GROUP_ICACHE
#  define SPR_ICCR                                 0          // IC Control register
#  define SPR_ICBPR                                1          // IC Block Prefetch register
#  define SPR_ICBIR                                2          // IC Block Invalidate register
#  define SPR_ICBLR                                3          // IC Block Lock register
					           
  // GROUP_MAC				           
#  define SPR_MACLO                                1          // MAC Low
#  define SPR_MACHI                                2          // MAC High

  // SR RENAME
#  define NB_SPR_LOGIC                             2
#  define LOG2_NB_SPR_LOGIC                        1
  // SPR_LOGIC[0] = F
  // SPR_LOGIC[1] = Carry, Overflow
#  define SPR_LOGIC_SR_F                           0x0        // Status register bit F                   (size = 1)
#  define SPR_LOGIC_SR_CY_OV                       0x1        // Status register bit overflow and carry  (size = 2)

  //----------------------------------------------[ spr_mode_access ]-----

#  define SPR_ACCESS_MODE_NONE                     0x0        // 000
#  define SPR_ACCESS_MODE_READ_ONLY                0x1        // 001
#  define SPR_ACCESS_MODE_WRITE_ONLY               0x2        // 010
#  define SPR_ACCESS_MODE_READ_WRITE               0x3        // 011
#  define SPR_ACCESS_MODE_READ_ONLY_COND           0x5        // 101 special read

  //--------------------------------------------------------[ event ]-----
#  define SIZE_EVENT_STATE                         2

#  define EVENT_STATE_NO_EVENT                     0          // no event : current case
#  define EVENT_STATE_EVENT                        1          // Have a event : make necessary to manage the event
#  define EVENT_STATE_WAITEND                      2          // Wait end of manage event (restaure a good context)
#  define EVENT_STATE_END                          3          // CPU can continue
                                                     
#  define SIZE_EVENT_TYPE                          3 
                                                     
#  define EVENT_TYPE_NONE                          0          // no event
#  define EVENT_TYPE_BRANCH_MISS_SPECULATION       1          // miss of speculation (load or branch miss speculation)
#  define EVENT_TYPE_LOAD_MISS_SPECULATION         2          // miss of speculation (load or branch miss speculation)
#  define EVENT_TYPE_EXCEPTION                     3          // exception or interruption occure
//#define EVENT_TYPE_BRANCH_NO_ACCURATE            3          // branch is no accurate (old speculation is a miss)
#  define EVENT_TYPE_SPR_ACCESS                    4          // decod a mtspr or mfspr instruction
#  define EVENT_TYPE_MSYNC                         5          // decod a memory   synchronization
#  define EVENT_TYPE_PSYNC                         6          // decod a pipeline synchronization
#  define EVENT_TYPE_CSYNC                         7          // decod a context  synchronization

  //-------------------------------------------------[ branch_state ]-----
#  define SIZE_BRANCH_STATE                        2

#  define BRANCH_STATE_NONE                        0x0        // 0 0
#  define BRANCH_STATE_NSPEC_TAKE                  0x1        // 0 1  -> incondionnal
#  define BRANCH_STATE_SPEC_NTAKE                  0x2        // 1 0
#  define BRANCH_STATE_SPEC_TAKE                   0x3        // 1 1

  //---------------------------------------------[ branch_condition ]-----

#  define SIZE_BRANCH_CONDITION                    4
#  define MAX_BRANCH_CONDITION                     (1<<SIZE_BRANCH_CONDITION)
  typedef enum
    {
      BRANCH_CONDITION_NONE_WITHOUT_WRITE_STACK          = 0x0,        // None condition (jump)
      BRANCH_CONDITION_NONE_WITH_WRITE_STACK             = 0x8,        // None condition (jump)
      BRANCH_CONDITION_FLAG_UNSET                        = 0x2,        // Branch if Flag is clear
      BRANCH_CONDITION_FLAG_SET                          = 0x3,        // Branch if Flag is set
      BRANCH_CONDITION_READ_REGISTER_WITHOUT_WRITE_STACK = 0x4,        // Branch if a register is read
      BRANCH_CONDITION_READ_REGISTER_WITH_WRITE_STACK    = 0xc,        // Branch if a register is read
      BRANCH_CONDITION_READ_STACK                        = 0xf         // Branch with pop  in stack pointer
    } branch_condition_t;

#  define is_branch_condition_valid(x)                           \
  (( x == BRANCH_CONDITION_NONE_WITHOUT_WRITE_STACK         ) or \
   ( x == BRANCH_CONDITION_NONE_WITH_WRITE_STACK            ) or \
   ( x == BRANCH_CONDITION_FLAG_UNSET                       ) or \
   ( x == BRANCH_CONDITION_FLAG_SET                         ) or \
   ( x == BRANCH_CONDITION_READ_REGISTER_WITHOUT_WRITE_STACK) or \
   ( x == BRANCH_CONDITION_READ_REGISTER_WITH_WRITE_STACK   ) or \
   ( x == BRANCH_CONDITION_READ_STACK                       ))


  /*
enum
  {
    BRANCH_TYPE_SEQUENTIAL,
    BRANCH_TYPE_JUMP,
    BRANCH_TYPE_CONDITIONNAL,
    BRANCH_TYPE_REGISTER,
    BRANCH_TYPE_CALL,
    BRANCH_TYPE_RETURN,
    NB_BRANCH_TYPE
  };

#  define branch_condition_to_type(x)                                   \
  (x == BRANCH_CONDITION_NONE_WITHOUT_WRITE_STACK         )?BRANCH_TYPE_JUMP: \
  ((x == BRANCH_CONDITION_NONE_WITH_WRITE_STACK            )?BRANCH_TYPE_CALL: \
   ((x == BRANCH_CONDITION_FLAG_UNSET                       )?BRANCH_TYPE_CONDITIONNAL: \
    ((x == BRANCH_CONDITION_FLAG_SET                         )?BRANCH_TYPE_CONDITIONNAL: \
     ((x == BRANCH_CONDITION_READ_REGISTER_WITHOUT_WRITE_STACK)?BRANCH_TYPE_REGISTER: \
      ((x == BRANCH_CONDITION_READ_REGISTER_WITH_WRITE_STACK   )?BRANCH_TYPE_CALL: \
       ((x == BRANCH_CONDITION_READ_STACK                       )?BRANCH_TYPE_RETURN:BRANCH_TYPE_SEQUENTIAL))))));
  */
  
  //--------------------------------------------------[ instruction ]-----
#  define NB_INSTRUCTION                           213        // 92 ORBIS, 30 ORFPX (15 simple, 15 double), 91 ORVDX (38 on byte, 41 on half, 12 independant format)

  enum 
    {
      // ORBIS
      INSTRUCTION_L_ADD,                         //0
      INSTRUCTION_L_ADDC,                        //1
      INSTRUCTION_L_ADDI,                        //2
      INSTRUCTION_L_ADDIC,                       //3
      INSTRUCTION_L_AND,                         //4
      INSTRUCTION_L_ANDI,                        //5
      INSTRUCTION_L_BF,                          //6
      INSTRUCTION_L_BNF,                         //7
      INSTRUCTION_L_CMOV,                        //8
      INSTRUCTION_L_CSYNC,                       //9
      INSTRUCTION_L_CUST1,                       //10
      INSTRUCTION_L_CUST2,                       //11
      INSTRUCTION_L_CUST3,                       //12
      INSTRUCTION_L_CUST4,                       //13
      INSTRUCTION_L_CUST5,                       //14
      INSTRUCTION_L_CUST6,                       //15
      INSTRUCTION_L_CUST7,                       //16
      INSTRUCTION_L_CUST8,                       //17
      INSTRUCTION_L_DIV,                         //18
      INSTRUCTION_L_DIVU,                        //19
      INSTRUCTION_L_EXTBS,                       //20
      INSTRUCTION_L_EXTBZ,                       //21
      INSTRUCTION_L_EXTHS,                       //22
      INSTRUCTION_L_EXTHZ,                       //23
      INSTRUCTION_L_EXTWS,                       //24
      INSTRUCTION_L_EXTWZ,                       //25
      INSTRUCTION_L_FF1,                         //26
      INSTRUCTION_L_FL1,                         //27
      INSTRUCTION_L_J,                           //28
      INSTRUCTION_L_JAL,                         //29
      INSTRUCTION_L_JALR,                        //30
      INSTRUCTION_L_JR,                          //31
      INSTRUCTION_L_LBS,                         //32
      INSTRUCTION_L_LBZ,                         //33
      INSTRUCTION_L_LD,                          //34
      INSTRUCTION_L_LHS,                         //35
      INSTRUCTION_L_LHZ,                         //36
      INSTRUCTION_L_LWS,                         //37
      INSTRUCTION_L_LWZ,                         //38
      INSTRUCTION_L_MAC,                         //39
      INSTRUCTION_L_MACI,                        //40
      INSTRUCTION_L_MACRC,                       //41
      INSTRUCTION_L_MFSPR,                       //42
      INSTRUCTION_L_MOVHI,                       //43
      INSTRUCTION_L_MSB,                         //44
      INSTRUCTION_L_MSYNC,                       //45
      INSTRUCTION_L_MTSPR,                       //46
      INSTRUCTION_L_MUL,                         //47
      INSTRUCTION_L_MULI,                        //48
      INSTRUCTION_L_MULU,                        //49
      INSTRUCTION_L_NOP,                         //50
      INSTRUCTION_L_OR,                          //51
      INSTRUCTION_L_ORI,                         //52
      INSTRUCTION_L_PSYNC,                       //53
      INSTRUCTION_L_RFE,                         //54
      INSTRUCTION_L_ROR,                         //55
      INSTRUCTION_L_RORI,                        //56
      INSTRUCTION_L_SB,                          //57
      INSTRUCTION_L_SD,                          //58
      INSTRUCTION_L_SFEQ,                        //59
      INSTRUCTION_L_SFEQI,                       //60
      INSTRUCTION_L_SFGES,                       //61
      INSTRUCTION_L_SFGESI,                      //62
      INSTRUCTION_L_SFGEU,                       //63
      INSTRUCTION_L_SFGEUI,                      //64
      INSTRUCTION_L_SFGTS,                       //65
      INSTRUCTION_L_SFGTSI,                      //66
      INSTRUCTION_L_SFGTU,                       //67
      INSTRUCTION_L_SFGTUI,                      //68
      INSTRUCTION_L_SFLES,                       //69
      INSTRUCTION_L_SFLESI,                      //70
      INSTRUCTION_L_SFLEU,                       //71
      INSTRUCTION_L_SFLEUI,                      //72
      INSTRUCTION_L_SFLTS,                       //73
      INSTRUCTION_L_SFLTSI,                      //74
      INSTRUCTION_L_SFLTU,                       //75
      INSTRUCTION_L_SFLTUI,                      //76
      INSTRUCTION_L_SFNE,                        //77
      INSTRUCTION_L_SFNEI,                       //78
      INSTRUCTION_L_SH,                          //79
      INSTRUCTION_L_SLL,                         //80
      INSTRUCTION_L_SLLI,                        //81
      INSTRUCTION_L_SRA,                         //82
      INSTRUCTION_L_SRAI,                        //83
      INSTRUCTION_L_SRL,                         //84
      INSTRUCTION_L_SRLI,                        //85
      INSTRUCTION_L_SUB,                         //86
      INSTRUCTION_L_SW,                          //87
      INSTRUCTION_L_SYS,                         //88
      INSTRUCTION_L_TRAP,                        //89
      INSTRUCTION_L_XOR,                         //90
      INSTRUCTION_L_XORI,                        //91
      // ORFPX                                     
      INSTRUCTION_LF_ADD_D,                      //92
      INSTRUCTION_LF_ADD_S,                      //93
      INSTRUCTION_LF_CUST1_D,                    //94
      INSTRUCTION_LF_CUST1_S,                    //95
      INSTRUCTION_LF_DIV_D,                      //96
      INSTRUCTION_LF_DIV_S,                      //97
      INSTRUCTION_LF_FTOI_D,                     //98
      INSTRUCTION_LF_FTOI_S,                     //99
      INSTRUCTION_LF_ITOF_D,                     //100
      INSTRUCTION_LF_ITOF_S,                     //101
      INSTRUCTION_LF_MADD_D,                     //102
      INSTRUCTION_LF_MADD_S,                     //103
      INSTRUCTION_LF_MUL_D,                      //104
      INSTRUCTION_LF_MUL_S,                      //105
      INSTRUCTION_LF_REM_D,                      //106
      INSTRUCTION_LF_REM_S,                      //107
      INSTRUCTION_LF_SFEQ_D,                     //108
      INSTRUCTION_LF_SFEQ_S,                     //109
      INSTRUCTION_LF_SFGE_D,                     //110
      INSTRUCTION_LF_SFGE_S,                     //111
      INSTRUCTION_LF_SFGT_D,                     //112
      INSTRUCTION_LF_SFGT_S,                     //113
      INSTRUCTION_LF_SFLE_D,                     //114
      INSTRUCTION_LF_SFLE_S,                     //115
      INSTRUCTION_LF_SFLT_D,                     //116
      INSTRUCTION_LF_SFLT_S,                     //117
      INSTRUCTION_LF_SFNE_D,                     //118
      INSTRUCTION_LF_SFNE_S,                     //119
      INSTRUCTION_LF_SUB_D,                      //120
      INSTRUCTION_LF_SUB_S,                      //121
      // ORVDX                                     
      INSTRUCTION_LV_ADD_B,                      //122
      INSTRUCTION_LV_ADD_H,                      //123
      INSTRUCTION_LV_ADDS_B,                     //124
      INSTRUCTION_LV_ADDS_H,                     //125
      INSTRUCTION_LV_ADDU_B,                     //126
      INSTRUCTION_LV_ADDU_H,                     //127
      INSTRUCTION_LV_ADDUS_B,                    //128
      INSTRUCTION_LV_ADDUS_H,                    //129
      INSTRUCTION_LV_ALL_EQ_B,                   //130
      INSTRUCTION_LV_ALL_EQ_H,                   //131
      INSTRUCTION_LV_ALL_GE_B,                   //132
      INSTRUCTION_LV_ALL_GE_H,                   //133
      INSTRUCTION_LV_ALL_GT_B,                   //134
      INSTRUCTION_LV_ALL_GT_H,                   //135
      INSTRUCTION_LV_ALL_LE_B,                   //136
      INSTRUCTION_LV_ALL_LE_H,                   //137
      INSTRUCTION_LV_ALL_LT_B,                   //138
      INSTRUCTION_LV_ALL_LT_H,                   //139
      INSTRUCTION_LV_ALL_NE_B,                   //140
      INSTRUCTION_LV_ALL_NE_H,                   //141
      INSTRUCTION_LV_AND,                        //142
      INSTRUCTION_LV_ANY_EQ_B,                   //143
      INSTRUCTION_LV_ANY_EQ_H,                   //144
      INSTRUCTION_LV_ANY_GE_B,                   //145
      INSTRUCTION_LV_ANY_GE_H,                   //146
      INSTRUCTION_LV_ANY_GT_B,                   //147
      INSTRUCTION_LV_ANY_GT_H,                   //148
      INSTRUCTION_LV_ANY_LE_B,                   //149
      INSTRUCTION_LV_ANY_LE_H,                   //150
      INSTRUCTION_LV_ANY_LT_B,                   //151
      INSTRUCTION_LV_ANY_LT_H,                   //152
      INSTRUCTION_LV_ANY_NE_B,                   //153
      INSTRUCTION_LV_ANY_NE_H,                   //154
      INSTRUCTION_LV_AVG_B,                      //155
      INSTRUCTION_LV_AVG_H,                      //156
      INSTRUCTION_LV_CMP_EQ_B,                   //157
      INSTRUCTION_LV_CMP_EQ_H,                   //158
      INSTRUCTION_LV_CMP_GE_B,                   //159
      INSTRUCTION_LV_CMP_GE_H,                   //160
      INSTRUCTION_LV_CMP_GT_B,                   //161
      INSTRUCTION_LV_CMP_GT_H,                   //162
      INSTRUCTION_LV_CMP_LE_B,                   //163
      INSTRUCTION_LV_CMP_LE_H,                   //164
      INSTRUCTION_LV_CMP_LT_B,                   //165
      INSTRUCTION_LV_CMP_LT_H,                   //166
      INSTRUCTION_LV_CMP_NE_B,                   //167
      INSTRUCTION_LV_CMP_NE_H,                   //168
      INSTRUCTION_LV_CUST1,                      //169
      INSTRUCTION_LV_CUST2,                      //170
      INSTRUCTION_LV_CUST3,                      //171
      INSTRUCTION_LV_CUST4,                      //172
      INSTRUCTION_LV_MADDS_H,                    //173
      INSTRUCTION_LV_MAX_B,                      //174
      INSTRUCTION_LV_MAX_H,                      //175
      INSTRUCTION_LV_MERGE_B,                    //176
      INSTRUCTION_LV_MERGE_H,                    //177
      INSTRUCTION_LV_MIN_B,                      //178
      INSTRUCTION_LV_MIN_H,                      //179
      INSTRUCTION_LV_MSUBS_H,                    //180
      INSTRUCTION_LV_MULS_H,                     //181
      INSTRUCTION_LV_NAND,                       //182
      INSTRUCTION_LV_NOR,                        //183
      INSTRUCTION_LV_OR,                         //184
      INSTRUCTION_LV_PACK_B,                     //185
      INSTRUCTION_LV_PACK_H,                     //186
      INSTRUCTION_LV_PACKS_B,                    //187
      INSTRUCTION_LV_PACKS_H,                    //188
      INSTRUCTION_LV_PACKUS_B,                   //189
      INSTRUCTION_LV_PACKUS_H,                   //290
      INSTRUCTION_LV_PERM_N,                     //291
      INSTRUCTION_LV_RL_B,                       //292
      INSTRUCTION_LV_RL_H,                       //293
      INSTRUCTION_LV_SLL,                        //294
      INSTRUCTION_LV_SLL_B,                      //295
      INSTRUCTION_LV_SLL_H,                      //296
      INSTRUCTION_LV_SRA_B,                      //297
      INSTRUCTION_LV_SRA_H,                      //298
      INSTRUCTION_LV_SRL,                        //299
      INSTRUCTION_LV_SRL_B,                      //200
      INSTRUCTION_LV_SRL_H,                      //201
      INSTRUCTION_LV_SUB_B,                      //202
      INSTRUCTION_LV_SUB_H,                      //203
      INSTRUCTION_LV_SUBS_B,                     //204
      INSTRUCTION_LV_SUBS_H,                     //205
      INSTRUCTION_LV_SUBU_B,                     //206
      INSTRUCTION_LV_SUBU_H,                     //207
      INSTRUCTION_LV_SUBUS_B,                    //208
      INSTRUCTION_LV_SUBUS_H,                    //209
      INSTRUCTION_LV_UNPACK_B,                   //210
      INSTRUCTION_LV_UNPACK_H,                   //211
      INSTRUCTION_LV_XOR                         //212
    };

  //-----------------------------------------------[ Code Operation ]-----

#  define MAX_OPCOD_0                              64            // Instructions with immediat
#  define MAX_OPCOD_1                              64            // Instruction ORFPX32/64                  
#  define MAX_OPCOD_2                              256           // Instruction ORVDX64
#  define MAX_OPCOD_3                              256           // Instructions Register-Register
#  define MAX_OPCOD_4                              32            // Instructions "set flag" with register
#  define MAX_OPCOD_5                              32            // Instructions "set flag" with immediat
#  define MAX_OPCOD_6                              4             // Instruction Shift/Rotate with immediat
#  define MAX_OPCOD_7                              16            // Instructions multiply with HI-LO
#  define MAX_OPCOD_8                              2             // Instructions acces at HI-LO 
#  define MAX_OPCOD_9                              8             // Instructions special	
#  define MAX_OPCOD_10                             4             // Instructions no operation
#  define MAX_OPCOD_11                             4             // Instruction Shift/Rotate with register
#  define MAX_OPCOD_12                             4             // Instructions extend
#  define MAX_OPCOD_13                             4             // Instructions extend (64b)

// OPCOD_0                                         - [31:26]      Instructions with immediat
#  define OPCOD_L_J                                0x00          // 000_000
#  define OPCOD_L_JAL                              0x01          // 000_001
#  define OPCOD_L_BNF                              0x03          // 000_011
#  define OPCOD_L_BF                               0x04          // 000_100
#  define OPCOD_L_RFE                              0x09          // 001_001
#  define OPCOD_L_JR                               0x11          // 010_001
#  define OPCOD_L_JALR                             0x12          // 010_010
#  define OPCOD_L_MACI                             0x13          // 010_011
#  define OPCOD_L_CUST1                            0x1c          // 011_100
#  define OPCOD_L_CUST2                            0x1d          // 011_101
#  define OPCOD_L_CUST3                            0x1e          // 011_110
#  define OPCOD_L_CUST4                            0x1f          // 011_111
#  define OPCOD_L_CUST5                            0x3c          // 111_100
#  define OPCOD_L_CUST6                            0x3d          // 111_101
#  define OPCOD_L_CUST7                            0x3e          // 111_110
#  define OPCOD_L_CUST8                            0x3f          // 111_111
#  define OPCOD_L_LD                               0x20          // 100_000
#  define OPCOD_L_LWZ                              0x21          // 100_001
#  define OPCOD_L_LWS                              0x22          // 100_010
#  define OPCOD_L_LBZ                              0x23          // 100_011
#  define OPCOD_L_LBS                              0x24          // 100_100
#  define OPCOD_L_LHZ                              0x25          // 100_101
#  define OPCOD_L_LHS                              0x26          // 100_110
#  define OPCOD_L_ADDI                             0x27          // 100_111
#  define OPCOD_L_ADDIC                            0x28          // 101_000
#  define OPCOD_L_ANDI                             0x29          // 101_001
#  define OPCOD_L_ORI                              0x2a          // 101_010
#  define OPCOD_L_XORI                             0x2b          // 101_011
#  define OPCOD_L_MULI                             0x2c          // 101_100
#  define OPCOD_L_MFSPR                            0x2d          // 101_101
#  define OPCOD_L_MTSPR                            0x30          // 110_000
#  define OPCOD_L_SD                               0x34          // 110_100
#  define OPCOD_L_SW                               0x35          // 110_101
#  define OPCOD_L_SB                               0x36          // 110_110
#  define OPCOD_L_SH                               0x37          // 110_111
				                   
#  define OPCOD_1                                  0x33          // 110_011         // Instruction ORFPX32/64
#  define OPCOD_2                                  0x0a          // 001_010         // Instruction ORVDX64
#  define OPCOD_3                                  0x38          // 111_000         // Instructions Register-Register
#  define OPCOD_4                                  0x39          // 111_001         // Instructions "set flag" with register
#  define OPCOD_5                                  0x2f          // 101_111         // Instructions "set flag" with immediat
#  define OPCOD_6                                  0x2e          // 101_110         // Instruction Shift/Rotate with immediat
#  define OPCOD_7                                  0x31          // 110_001         // Instructions multiply with HI-LO
#  define OPCOD_8                                  0x06          // 000_110         // Instructions acces at HI-LO 
#  define OPCOD_9                                  0x08          // 001_000         // Instructions special
#  define OPCOD_10                                 0x05          // 000_101         // Instructions no operation
				                   
// OPCOD_3         instructions                    - [9:8] [3:0]  Instructions Register-Register
#  define OPCOD_L_ADD                              0x00          // 00_0000
#  define OPCOD_L_ADDC                             0x01          // 00_0001
#  define OPCOD_L_SUB                              0x02          // 00_0010
#  define OPCOD_L_AND                              0x03          // 00_0011
#  define OPCOD_L_OR                               0x04          // 00_0100
#  define OPCOD_L_XOR                              0x05          // 00_0101
#  define OPCOD_L_CMOV                             0x0e          // 00_1110
#  define OPCOD_L_FF1                              0x0f          // 00_1111
#  define OPCOD_L_FL1                              0x1f          // 01_1111
#  define OPCOD_L_MUL                              0x36          // 11_0110
#  define OPCOD_L_DIV                              0x39          // 11_1001
#  define OPCOD_L_DIVU                             0x3a          // 11_1010
#  define OPCOD_L_MULU                             0x3b          // 11_1011
				                   
#  define OPCOD_11                                 0x8           // 1000          // Instruction Shift/Rotate with register
#  define OPCOD_12                                 0xc           // 1100          // Instructions extend
#  define OPCOD_13                                 0xd           // 1101          // Instructions extend (64b)
				                   
// OPCOD_4         instructions                    - [25:21]      Instructions "set flag" with register
#  define OPCOD_L_SFEQ                             0x00          // 00000
#  define OPCOD_L_SFNE                             0x01          // 00001
#  define OPCOD_L_SFGTU                            0x02          // 00010
#  define OPCOD_L_SFGEU                            0x03          // 00011
#  define OPCOD_L_SFLTU                            0x04          // 00100
#  define OPCOD_L_SFLEU                            0x05          // 00101
#  define OPCOD_L_SFGTS                            0x0a          // 01010
#  define OPCOD_L_SFGES                            0x0b          // 01011
#  define OPCOD_L_SFLTS                            0x0c          // 01100
#  define OPCOD_L_SFLES                            0x0d          // 01101
				                   
// OPCOD_5         instructions                    - [25:21]      Instructions "set flag" with immediat
#  define OPCOD_L_SFEQI                            0x00          // 00000
#  define OPCOD_L_SFNEI                            0x01          // 00001
#  define OPCOD_L_SFGTUI                           0x02          // 00010
#  define OPCOD_L_SFGEUI                           0x03          // 00011
#  define OPCOD_L_SFLTUI                           0x04          // 00100
#  define OPCOD_L_SFLEUI                           0x05          // 00101
#  define OPCOD_L_SFGTSI                           0x0a          // 01010
#  define OPCOD_L_SFGESI                           0x0b          // 01011
#  define OPCOD_L_SFLTSI                           0x0c          // 01100
#  define OPCOD_L_SFLESI                           0x0d          // 01101
				                   
// OPCOD_6         instructions                    - [7:6]        Instruction Shift/Rotate with immediat
#  define OPCOD_L_SLLI                             0x0           // 00
#  define OPCOD_L_SRLI                             0x1           // 01
#  define OPCOD_L_SRAI                             0x2           // 10
#  define OPCOD_L_RORI                             0x3           // 11
				                   
// OPCOD_7         instructions                    - [3:0]        Instructions multiply with HI-LO
#  define OPCOD_L_MAC                              0x1           // 0001
#  define OPCOD_L_MSB                              0x2           // 0010
				                   
// OPCOD_8         instructions                    - [17]         Instructions acces at HI-LO 
#  define OPCOD_L_MOVHI                            0x0           // 0
#  define OPCOD_L_MACRC                            0x1           // 1

// OPCOD_9         instructions                    - [25:23]      Instruction special
#  define OPCOD_L_SYS                              0x0           // 000
#  define OPCOD_L_TRAP                             0x2           // 010
#  define OPCOD_L_MSYNC                            0x4           // 100
#  define OPCOD_L_PSYNC                            0x5           // 101
#  define OPCOD_L_CSYNC                            0x6           // 110

// OPCOD_10        instructions                    - [25:24]      Instruction no operation
#  define OPCOD_L_NOP                              0x1           // 01
				                   
// OPCOD_11        instructions                    - [7:6]        Instruction Shift/Rotate with register
#  define OPCOD_L_SLL                              0x0           // 00
#  define OPCOD_L_SRL                              0x1           // 01
#  define OPCOD_L_SRA                              0x2           // 10
#  define OPCOD_L_ROR                              0x3           // 11
				                   
// OPCOD_12        instructions                    - [9:6]          Instructions extend
#  define OPCOD_L_EXTHS                            0x0           // 0000
#  define OPCOD_L_EXTHZ                            0x2           // 0010
#  define OPCOD_L_EXTBS                            0x1           // 0001
#  define OPCOD_L_EXTBZ                            0x3           // 0011
				                   
// OPCOD_13        instructions                    - [9:6]        Instructions extend (64b)
#  define OPCOD_L_EXTWS                            0x0           // 0000
#  define OPCOD_L_EXTWZ                            0x1           // 0001

}; // end namespace behavioural

  template<> inline std::string toString<morpheo::behavioural::type_t>(const morpheo::behavioural::type_t& x)
  {
    switch (x)
      {
      case morpheo::behavioural::TYPE_ALU     : return "ALU"        ;
      case morpheo::behavioural::TYPE_SHIFT   : return "SHIFT"      ;
      case morpheo::behavioural::TYPE_MOVE    : return "MOVE"       ;
      case morpheo::behavioural::TYPE_TEST    : return "TEST"       ;
      case morpheo::behavioural::TYPE_MUL     : return "MUL"        ;
      case morpheo::behavioural::TYPE_DIV     : return "DIV"        ;
      case morpheo::behavioural::TYPE_EXTEND  : return "EXTEND"     ;
      case morpheo::behavioural::TYPE_FIND    : return "FIND"       ;
      case morpheo::behavioural::TYPE_SPECIAL : return "SPECIAL"    ;
      case morpheo::behavioural::TYPE_CUSTOM  : return "CUSTOM"     ;
      case morpheo::behavioural::TYPE_BRANCH  : return "BRANCH"     ;
      case morpheo::behavioural::TYPE_MEMORY  : return "MEMORY"     ;
      default : return "";
      }
  };

  template<> inline std::string toString<morpheo::behavioural::branch_condition_t>(const morpheo::behavioural::branch_condition_t& x)
  {
    switch (x)
      {
      case morpheo::behavioural::BRANCH_CONDITION_NONE_WITHOUT_WRITE_STACK          : return "none_without_write_stack"         ;
      case morpheo::behavioural::BRANCH_CONDITION_NONE_WITH_WRITE_STACK             : return "none_with_write_stack"            ;
      case morpheo::behavioural::BRANCH_CONDITION_FLAG_UNSET                        : return "flag_unset"                       ;
      case morpheo::behavioural::BRANCH_CONDITION_FLAG_SET                          : return "flag_set"                         ;
      case morpheo::behavioural::BRANCH_CONDITION_READ_REGISTER_WITHOUT_WRITE_STACK : return "read_register_without_write_stack";
      case morpheo::behavioural::BRANCH_CONDITION_READ_REGISTER_WITH_WRITE_STACK    : return "read_register_with_write_stack"   ;
      case morpheo::behavioural::BRANCH_CONDITION_READ_STACK                        : return "read_stack"                       ;
      default : return "";
      }
  };

//   template<> inline std::string toString<morpheo::behavioural::event_state_t>(const morpheo::behavioural::event_state_t& x)
//   {
//     switch (x)
//       {
//       case morpheo::behavioural::EVENT_STATE_NO_EVENT : return "EVENT_STATE_NO_EVENT";
//       case morpheo::behavioural::EVENT_STATE_EVENT    : return "EVENT_STATE_EVENT"   ;
//       case morpheo::behavioural::EVENT_STATE_WAITEND  : return "EVENT_STATE_WAITEND" ;
//       case morpheo::behavioural::EVENT_STATE_END      : return "EVENT_STATE_END"     ;
//       default : return "";
//       }
//   };

//   template<> inline std::string toString<morpheo::behavioural::event_type_t>(const morpheo::behavioural::event_type_t& x)
//   {
//     switch (x)
//       {
//       case morpheo::behavioural::EVENT_TYPE_NONE               : return "EVENT_TYPE_NONE"              ;
//       case morpheo::behavioural::EVENT_TYPE_MISS_SPECULATION   : return "EVENT_TYPE_MISS_SPECULATION"  ;
//       case morpheo::behavioural::EVENT_TYPE_EXCEPTION          : return "EVENT_TYPE_EXCEPTION"         ;
//       case morpheo::behavioural::EVENT_TYPE_BRANCH_NO_ACCURATE : return "EVENT_TYPE_BRANCH_NO_ACCURATE";
//       case morpheo::behavioural::EVENT_TYPE_SPR_ACCESS         : return "EVENT_TYPE_SPR_ACCESS"        ;
//       case morpheo::behavioural::EVENT_TYPE_MSYNC              : return "EVENT_TYPE_MSYNC"             ;
//       case morpheo::behavioural::EVENT_TYPE_PSYNC              : return "EVENT_TYPE_PSYNC"             ;
//       case morpheo::behavioural::EVENT_TYPE_CSYNC              : return "EVENT_TYPE_CSYNC"             ;
//       default : return "";
//       }
//   };

}; // end namespace morpheo              

#endif
