#ifdef SYSTEMC
/*
 * $Id$
 *
 * [ Description ]
 * 
 */

#include "Behavioural/Core/Multi_Execute_loop/Execute_loop/Multi_Execute_unit/Execute_unit/Functionnal_unit/Operation/include/Operation.h"

#define neg(data)                  (~(data)+1)
#define sign(data)                 ((data)>>(param->_size_data-1))
#define unsigned(data)             (data)
#define signed(data)               ((sign(data)==0)?(data):neg(data))
#define ovf(op1, op2, res)         ((sign(op1) == sign(op2))?(sign(op1) xor sign(res)):0)
#define carry(op1, op2, res)       (((res)<(op1)) or ((res)<(op2)))
#define set_flag(data,flag,is_set) (((is_set)==1)?((data)|(flag)):((data)&~(flag)))
#define get_flag(data,flag)	   (((data)&(flag))!=0)
#define concatenation_bool(a,b)    (((a)<<1) | (b))

namespace morpheo                    {
namespace behavioural {
namespace core {
namespace multi_execute_loop {
namespace execute_loop {
namespace multi_execute_unit {
namespace execute_unit {
namespace functionnal_unit {

#undef  FUNCTION
#define FUNCTION "Functionnal_unit::operation_unimplemented"
  void operation_unimplemented (execute_operation_t * op, execute_register_t * reg, execute_param_t * param)
  {
    log_printf(TRACE,Functionnal_unit,FUNCTION,"Operation : unimplemented");

    throw ERRORMORPHEO(FUNCTION,"The operation '"+toString(op->_operation)+"' is not implemented in this Functionnal_unit");
  };

#undef  FUNCTION
#define FUNCTION "Functionnal_unit::operation_l_add"
  void operation_l_add         (execute_operation_t * op, execute_register_t * reg, execute_param_t * param)
  {
    log_printf(TRACE,Functionnal_unit,FUNCTION,"Operation : l_add");

    Tgeneral_data_t gpr1      = unsigned(op->_data_ra);
    Tgeneral_data_t gpr2      = unsigned((op->_has_immediat==1)?op->_immediat:op->_data_rb);
    
    Tgeneral_data_t gpr3      = param->_mask_data & (gpr1 + gpr2);

    bool            overflow  = ovf  (gpr1,gpr2,gpr3);
    bool            carry_out = carry(gpr1,gpr2,gpr3);

    // Result
    op->_timing       = param->_timing[op->_type][op->_operation];
    op->_data_rd      = gpr3;
    op->_data_re      = 0;
    op->_data_re      = set_flag(op->_data_re,FLAG_OV,overflow );
    op->_data_re      = set_flag(op->_data_re,FLAG_CY,carry_out);
    op->_exception    = (overflow==1)?EXCEPTION_ALU_RANGE:EXCEPTION_ALU_NONE;
    op->_no_sequence  = 0;
  //op->_address      = 0;
  };

#undef  FUNCTION
#define FUNCTION "Functionnal_unit::operation_l_addc"
  void operation_l_addc        (execute_operation_t * op, execute_register_t * reg, execute_param_t * param)
  {
    log_printf(TRACE,Functionnal_unit,FUNCTION,"Operation : l_addc");

    Tgeneral_data_t carry_in   = get_flag(op->_data_rc,FLAG_CY);

    Tgeneral_data_t gpr1       = unsigned(op->_data_ra);
    Tgeneral_data_t gpr2       = unsigned((op->_has_immediat==1)?op->_immediat:op->_data_rb);
    Tgeneral_data_t gpr3       = param->_mask_data & (gpr1 + gpr2 + carry_in);

    bool            overflow   = ovf  (gpr1,gpr2,gpr3);
    bool            carry_out  = carry(gpr1,gpr2,gpr3);

    // Result
    op->_timing       = param->_timing[op->_type][op->_operation];
    op->_data_rd      = gpr3;
    op->_data_re      = 0;
    op->_data_re      = set_flag(op->_data_re,FLAG_OV,overflow );
    op->_data_re      = set_flag(op->_data_re,FLAG_CY,carry_out);
    op->_exception    = (overflow==1)?EXCEPTION_ALU_RANGE:EXCEPTION_ALU_NONE;
    op->_no_sequence  = 0;
  //op->_address      = 0;
  };

#undef  FUNCTION
#define FUNCTION "Functionnal_unit::operation_l_sub"
  void operation_l_sub         (execute_operation_t * op, execute_register_t * reg, execute_param_t * param)
  {
    log_printf(TRACE,Functionnal_unit,FUNCTION,"Operation : l_sub");

    Tgeneral_data_t gpr1      =     unsigned(op->_data_ra);
    Tgeneral_data_t gpr2      = neg(unsigned(op->_data_rb));
    Tgeneral_data_t gpr3      = param->_mask_data & (gpr1 + gpr2);

    bool            overflow  = ovf  (gpr1,gpr2,gpr3);
    bool            carry_out = carry(gpr1,gpr2,gpr3);

    // Result
    op->_timing       = param->_timing[op->_type][op->_operation];
    op->_data_rd      = gpr3;
    op->_data_re      = 0;
    op->_data_re      = set_flag(op->_data_re,FLAG_OV,overflow );
    op->_data_re      = set_flag(op->_data_re,FLAG_CY,carry_out);
    op->_exception    = (overflow==1)?EXCEPTION_ALU_RANGE:EXCEPTION_ALU_NONE;
    op->_no_sequence  = 0;
  //op->_address      = 0;
  };

#undef  FUNCTION
#define FUNCTION "Functionnal_unit::operation_l_and"
  void operation_l_and         (execute_operation_t * op, execute_register_t * reg, execute_param_t * param)
  {
    log_printf(TRACE,Functionnal_unit,FUNCTION,"Operation : l_and");

    Tgeneral_data_t gpr1       = unsigned(op->_data_ra);
    Tgeneral_data_t gpr2       = unsigned((op->_has_immediat==1)?op->_immediat:op->_data_rb);
    Tgeneral_data_t gpr3       = (gpr1 & gpr2);

    // Result
    op->_timing       = param->_timing[op->_type][op->_operation];
    op->_data_rd      = gpr3;
  //op->_data_re      = 0;
    op->_exception    = EXCEPTION_ALU_NONE;
    op->_no_sequence  = 0;
  //op->_address      = 0;
  };

#undef  FUNCTION
#define FUNCTION "Functionnal_unit::operation_l_or"
  void operation_l_or          (execute_operation_t * op, execute_register_t * reg, execute_param_t * param)
  {
    log_printf(TRACE,Functionnal_unit,FUNCTION,"Operation : l_or");

    Tgeneral_data_t gpr1       = unsigned(op->_data_ra);
    Tgeneral_data_t gpr2       = unsigned((op->_has_immediat==1)?op->_immediat:op->_data_rb);
    Tgeneral_data_t gpr3       = (gpr1 | gpr2);

    // Result
    op->_timing       = param->_timing[op->_type][op->_operation];
    op->_data_rd      = gpr3;
  //op->_data_re      = 0;
    op->_exception    = EXCEPTION_ALU_NONE;
    op->_no_sequence  = 0;
  //op->_address      = 0;
  };

#undef  FUNCTION
#define FUNCTION "Functionnal_unit::operation_l_xor"
  void operation_l_xor         (execute_operation_t * op, execute_register_t * reg, execute_param_t * param)
  {
    log_printf(TRACE,Functionnal_unit,FUNCTION,"Operation : l_xor");

    Tgeneral_data_t gpr1       = unsigned(op->_data_ra);
    Tgeneral_data_t gpr2       = unsigned((op->_has_immediat==1)?op->_immediat:op->_data_rb);
    Tgeneral_data_t gpr3       = (gpr1 ^ gpr2);

    // Result
    op->_timing       = param->_timing[op->_type][op->_operation];
    op->_data_rd      = gpr3;
  //op->_data_re      = 0;
    op->_exception    = EXCEPTION_ALU_NONE;
    op->_no_sequence  = 0;
  //op->_address      = 0;
  };

#undef  FUNCTION
#define FUNCTION "Functionnal_unit::operation_l_movhi"
  void operation_l_movhi       (execute_operation_t * op, execute_register_t * reg, execute_param_t * param)
  {
    log_printf(TRACE,Functionnal_unit,FUNCTION,"Operation : l_movhi");

    Tgeneral_data_t gpr1       = unsigned(op->_immediat);
    Tgeneral_data_t gpr2       = param->_mask_data & (gpr1<<16);

    // Result
    op->_timing       = param->_timing[op->_type][op->_operation];
    op->_data_rd      = gpr2;
  //op->_data_re      = 0;
    op->_exception    = EXCEPTION_ALU_NONE;
    op->_no_sequence  = 0;
  //op->_address      = 0;
  };

#undef  FUNCTION
#define FUNCTION "Functionnal_unit::operation_l_cmov"
  void operation_l_cmov        (execute_operation_t * op, execute_register_t * reg, execute_param_t * param)
  {
    log_printf(TRACE,Functionnal_unit,FUNCTION,"Operation : l_cmov");

    Tgeneral_data_t f_in       = get_flag(op->_data_rc,FLAG_F);

    Tgeneral_data_t gpr1       = unsigned(op->_data_ra);
    Tgeneral_data_t gpr2       = unsigned(op->_data_rb);
    Tgeneral_data_t gpr3       = ((f_in==0)?gpr2:gpr1);

    // Result
    op->_timing       = param->_timing[op->_type][op->_operation];
    op->_data_rd      = gpr3;
  //op->_data_re      = 0;
    op->_exception    = EXCEPTION_ALU_NONE;
    op->_no_sequence  = 0;
  //op->_address      = 0;
  };

#undef  FUNCTION
#define FUNCTION "Functionnal_unit::operation_l_test_f"
  void operation_l_test_f      (execute_operation_t * op, execute_register_t * reg, execute_param_t * param)
  {
    log_printf(TRACE,Functionnal_unit,FUNCTION,"Operation : l_test_f");

    Tgeneral_data_t f_in       = get_flag(op->_data_rc,FLAG_F);
    Tgeneral_data_t imm        = unsigned(op->_immediat);

    // Result
    op->_timing       = param->_timing[op->_type][op->_operation];
  //op->_data_rd      = 0;
  //op->_data_re      = 0;
    op->_exception    = EXCEPTION_ALU_NONE;
    op->_no_sequence  = f_in != 0;
    op->_address      = imm;
  };

#undef  FUNCTION
#define FUNCTION "Functionnal_unit::operation_l_test_nf"
  void operation_l_test_nf     (execute_operation_t * op, execute_register_t * reg, execute_param_t * param)
  {
    log_printf(TRACE,Functionnal_unit,FUNCTION,"Operation : l_test_nf");

    Tgeneral_data_t f_in       = get_flag(op->_data_rc,FLAG_F);
    Tgeneral_data_t imm        = unsigned(op->_immediat);

    // Result
    op->_timing       = param->_timing[op->_type][op->_operation];
  //op->_data_rd      = 0;
  //op->_data_re      = 0;
    op->_exception    = EXCEPTION_ALU_NONE;
    op->_no_sequence  = f_in == 0;
    op->_address      = imm;
  };

#undef  FUNCTION
#define FUNCTION "Functionnal_unit::operation_l_jalr"
  void operation_l_jalr        (execute_operation_t * op, execute_register_t * reg, execute_param_t * param)
  {
    log_printf(TRACE,Functionnal_unit,FUNCTION,"Operation : l_jalr");
    // jal  : has_imm = 1, write_rd = 1, read_rb = 0
    // jalr : has_imm = 1, write_rd = 1, read_rb = 1
    // jr   : has_imm = 0, write_rd = 0, read_rb = 1


    Tgeneral_data_t gpr        = unsigned(op->_data_rb);
    Tgeneral_data_t imm        = unsigned(op->_immediat);

    // Result
    op->_timing       = param->_timing[op->_type][op->_operation];
    op->_data_rd      = imm;
  //op->_data_re      = 0;
    op->_exception    = EXCEPTION_ALU_NONE;
    op->_no_sequence  = 1;
    op->_address      = gpr;
  };

#undef  FUNCTION
#define FUNCTION "Functionnal_unit::operation_l_extend_s"
  void operation_l_extend_s    (execute_operation_t * op, execute_register_t * reg, execute_param_t * param)
  {
    log_printf(TRACE,Functionnal_unit,FUNCTION,"Operation : l_extend_s");

    Tgeneral_data_t imm        = unsigned(op->_immediat);
    Tgeneral_data_t gpr1       = unsigned(op->_data_ra);
    Tgeneral_data_t gpr2       = extend<Tgeneral_data_t>(param->_size_data, gpr1, true , imm);

    // Result
    op->_timing       = param->_timing[op->_type][op->_operation];
    op->_data_rd      = gpr2;
  //op->_data_re      = 0;
    op->_exception    = EXCEPTION_ALU_NONE;
    op->_no_sequence  = 0;
  //op->_address      = 0;
  };

#undef  FUNCTION
#define FUNCTION "Functionnal_unit::operation_l_extend_z"
  void operation_l_extend_z    (execute_operation_t * op, execute_register_t * reg, execute_param_t * param)
  {
    log_printf(TRACE,Functionnal_unit,FUNCTION,"Operation : l_extend_z");

    Tgeneral_data_t imm        = unsigned(op->_immediat);
    Tgeneral_data_t gpr1       = unsigned(op->_data_ra);
    Tgeneral_data_t gpr2       = extend<Tgeneral_data_t>(param->_size_data, gpr1, false , imm);

    // Result
    op->_timing       = param->_timing[op->_type][op->_operation];
    op->_data_rd      = gpr2;
  //op->_data_re      = 0;
    op->_exception    = EXCEPTION_ALU_NONE;
    op->_no_sequence  = 0;
  //op->_address      = 0;
  };

#undef  FUNCTION
#define FUNCTION "Functionnal_unit::operation_l_sll"
  void operation_l_sll         (execute_operation_t * op, execute_register_t * reg, execute_param_t * param)
  {
    log_printf(TRACE,Functionnal_unit,FUNCTION,"Operation : l_sll");

    Tgeneral_data_t gpr1       = unsigned(op->_data_ra);
    Tgeneral_data_t gpr2       = param->_mask_shift & unsigned((op->_has_immediat==1)?op->_immediat:op->_data_rb);
    Tgeneral_data_t gpr3       = shift_logic_left<Tgeneral_data_t>(param->_size_data, gpr1, gpr2);

    // Result
    op->_timing       = param->_timing[op->_type][op->_operation];
    op->_data_rd      = gpr3;
  //op->_data_re      = 0;
    op->_exception    = EXCEPTION_ALU_NONE;
    op->_no_sequence  = 0;
  //op->_address      = 0;
  };

#undef  FUNCTION
#define FUNCTION "Functionnal_unit::operation_l_srl"
  void operation_l_srl         (execute_operation_t * op, execute_register_t * reg, execute_param_t * param)
  {
    log_printf(TRACE,Functionnal_unit,FUNCTION,"Operation : l_srl");

    Tgeneral_data_t gpr1       = unsigned(op->_data_ra);
    Tgeneral_data_t gpr2       = param->_mask_shift & unsigned((op->_has_immediat==1)?op->_immediat:op->_data_rb);
    Tgeneral_data_t gpr3       = shift_logic_right<Tgeneral_data_t>(param->_size_data, gpr1, gpr2);

    // Result
    op->_timing       = param->_timing[op->_type][op->_operation];
    op->_data_rd      = gpr3;
  //op->_data_re      = 0;
    op->_exception    = EXCEPTION_ALU_NONE;
    op->_no_sequence  = 0;
  //op->_address      = 0;
  };

#undef  FUNCTION
#define FUNCTION "Functionnal_unit::operation_l_sra"
  void operation_l_sra         (execute_operation_t * op, execute_register_t * reg, execute_param_t * param)
  {
    log_printf(TRACE,Functionnal_unit,FUNCTION,"Operation : l_sra");

    Tgeneral_data_t gpr1       = unsigned(op->_data_ra);
    Tgeneral_data_t gpr2       = param->_mask_shift & unsigned((op->_has_immediat==1)?op->_immediat:op->_data_rb);
    Tgeneral_data_t gpr3       = shift_arithmetic_right<Tgeneral_data_t>(param->_size_data, gpr1, gpr2);

    // Result
    op->_timing       = param->_timing[op->_type][op->_operation];
    op->_data_rd      = gpr3;
  //op->_data_re      = 0;
    op->_exception    = EXCEPTION_ALU_NONE;
    op->_no_sequence  = 0;
  //op->_address      = 0;
  };

#undef  FUNCTION
#define FUNCTION "Functionnal_unit::operation_l_ror"
  void operation_l_ror         (execute_operation_t * op, execute_register_t * reg, execute_param_t * param)
  {
    log_printf(TRACE,Functionnal_unit,FUNCTION,"Operation : l_ror");

    Tgeneral_data_t gpr1       = unsigned(op->_data_ra);
    Tgeneral_data_t gpr2       = param->_mask_shift & unsigned((op->_has_immediat==1)?op->_immediat:op->_data_rb);
    Tgeneral_data_t gpr3       = rotate_right<Tgeneral_data_t>(param->_size_data, gpr1, gpr2);

    // Result
    op->_timing       = param->_timing[op->_type][op->_operation];
    op->_data_rd      = gpr3;
  //op->_data_re      = 0;
    op->_exception    = EXCEPTION_ALU_NONE;
    op->_no_sequence  = 0;
  //op->_address      = 0;
  };

#undef  FUNCTION
#define FUNCTION "Functionnal_unit::operation_l_ff1"
  void operation_l_ff1         (execute_operation_t * op, execute_register_t * reg, execute_param_t * param)
  {
    log_printf(TRACE,Functionnal_unit,FUNCTION,"Operation : l_ff1");

    Tgeneral_data_t gpr        = unsigned(op->_data_ra);
    Tgeneral_data_t index;

    for (index=0; (index<param->_size_data) and (((gpr>>index)&1)!= 1); index++);

    // Result
    op->_timing       = param->_timing[op->_type][op->_operation];
    op->_data_rd      = (index==param->_size_data)?0:(index+1);
  //op->_data_re      = 0;
    op->_exception    = EXCEPTION_ALU_NONE;
    op->_no_sequence  = 0;
  //op->_address      = 0;
  };

#undef  FUNCTION
#define FUNCTION "Functionnal_unit::operation_l_fl1"
  void operation_l_fl1         (execute_operation_t * op, execute_register_t * reg, execute_param_t * param)
  {
    log_printf(TRACE,Functionnal_unit,FUNCTION,"Operation : l_fl1");

    Tgeneral_data_t gpr        = unsigned(op->_data_ra);
    Tgeneral_data_t index;

    for (index=param->_size_data; (index>0) and (((gpr>>(index-1))&1)!= 1); index--);

    // Result
    op->_timing       = param->_timing[op->_type][op->_operation];
    op->_data_rd      = index;
  //op->_data_re      = 0;
    op->_exception    = EXCEPTION_ALU_NONE;
    op->_no_sequence  = 0;
  //op->_address      = 0;
  };

#undef  FUNCTION
#define FUNCTION "Functionnal_unit::operation_l_sfeq"
  void operation_l_sfeq        (execute_operation_t * op, execute_register_t * reg, execute_param_t * param)
  {
    log_printf(TRACE,Functionnal_unit,FUNCTION,"Operation : l_sfeq");

    Tgeneral_data_t gpr1       = unsigned(op->_data_ra);
    Tgeneral_data_t gpr2       = unsigned((op->_has_immediat==1)?op->_immediat:op->_data_rb);

    bool            f_out      = (gpr1 == gpr2);

    // Result
    op->_timing       = param->_timing[op->_type][op->_operation];
  //op->_data_rd      = 0;
    op->_data_re      = set_flag(op->_data_re,FLAG_F,f_out);
    op->_exception    = EXCEPTION_ALU_NONE;
    op->_no_sequence  = 0;
  //op->_address      = 0;
  };

#undef  FUNCTION
#define FUNCTION "Functionnal_unit::operation_l_sfne"
  void operation_l_sfne        (execute_operation_t * op, execute_register_t * reg, execute_param_t * param)
  {
    log_printf(TRACE,Functionnal_unit,FUNCTION,"Operation : l_sfne");

    Tgeneral_data_t gpr1       = unsigned(op->_data_ra);
    Tgeneral_data_t gpr2       = unsigned((op->_has_immediat==1)?op->_immediat:op->_data_rb);

    bool            f_out      = (gpr1 != gpr2);

    // Result
    op->_timing       = param->_timing[op->_type][op->_operation];
  //op->_data_rd      = 0;
    op->_data_re      = set_flag(op->_data_re,FLAG_F,f_out);
    op->_exception    = EXCEPTION_ALU_NONE;
    op->_no_sequence  = 0;
  //op->_address      = 0;
  };

#undef  FUNCTION
#define FUNCTION "Functionnal_unit::operation_l_sfgeu"
  void operation_l_sfgeu       (execute_operation_t * op, execute_register_t * reg, execute_param_t * param)
  {
    log_printf(TRACE,Functionnal_unit,FUNCTION,"Operation : l_sfgeu");

    Tgeneral_data_t gpr1       = unsigned(op->_data_ra);
    Tgeneral_data_t gpr2       = unsigned((op->_has_immediat==1)?op->_immediat:op->_data_rb);

    bool            f_out      = (gpr1 >= gpr2);

    // Result
    op->_timing       = param->_timing[op->_type][op->_operation];
  //op->_data_rd      = 0;
    op->_data_re      = set_flag(op->_data_re,FLAG_F,f_out);
    op->_exception    = EXCEPTION_ALU_NONE;
    op->_no_sequence  = 0;
  //op->_address      = 0;
  };

#undef  FUNCTION
#define FUNCTION "Functionnal_unit::operation_l_sfgtu"
  void operation_l_sfgtu       (execute_operation_t * op, execute_register_t * reg, execute_param_t * param)
  {
    log_printf(TRACE,Functionnal_unit,FUNCTION,"Operation : l_sfgtu");

    Tgeneral_data_t gpr1       = unsigned(op->_data_ra);
    Tgeneral_data_t gpr2       = unsigned((op->_has_immediat==1)?op->_immediat:op->_data_rb);

    bool            f_out      = (gpr1 >  gpr2);

    // Result
    op->_timing       = param->_timing[op->_type][op->_operation];
  //op->_data_rd      = 0;
    op->_data_re      = set_flag(op->_data_re,FLAG_F,f_out);
    op->_exception    = EXCEPTION_ALU_NONE;
    op->_no_sequence  = 0;
  //op->_address      = 0;
  };

#undef  FUNCTION
#define FUNCTION "Functionnal_unit::operation_l_sfleu"
  void operation_l_sfleu       (execute_operation_t * op, execute_register_t * reg, execute_param_t * param)
  {
    log_printf(TRACE,Functionnal_unit,FUNCTION,"Operation : l_sfleu");

    Tgeneral_data_t gpr1       = unsigned(op->_data_ra);
    Tgeneral_data_t gpr2       = unsigned((op->_has_immediat==1)?op->_immediat:op->_data_rb);

    bool            f_out      = (gpr1 <= gpr2);

    // Result
    op->_timing       = param->_timing[op->_type][op->_operation];
  //op->_data_rd      = 0;
    op->_data_re      = set_flag(op->_data_re,FLAG_F,f_out);
    op->_exception    = EXCEPTION_ALU_NONE;
    op->_no_sequence  = 0;
  //op->_address      = 0;
  };

#undef  FUNCTION
#define FUNCTION "Functionnal_unit::operation_l_sfltu"
  void operation_l_sfltu       (execute_operation_t * op, execute_register_t * reg, execute_param_t * param)
  {
    log_printf(TRACE,Functionnal_unit,FUNCTION,"Operation : l_sfltu");

    Tgeneral_data_t gpr1       = unsigned(op->_data_ra);
    Tgeneral_data_t gpr2       = unsigned((op->_has_immediat==1)?op->_immediat:op->_data_rb);

    bool            f_out      = (gpr1 <  gpr2);

    // Result
    op->_timing       = param->_timing[op->_type][op->_operation];
  //op->_data_rd      = 0;
    op->_data_re      = set_flag(op->_data_re,FLAG_F,f_out);
    op->_exception    = EXCEPTION_ALU_NONE;
    op->_no_sequence  = 0;
  //op->_address      = 0;
  };

#undef  FUNCTION
#define FUNCTION "Functionnal_unit::operation_l_sfges"
  void operation_l_sfges       (execute_operation_t * op, execute_register_t * reg, execute_param_t * param)
  {
    log_printf(TRACE,Functionnal_unit,FUNCTION,"Operation : l_sfges");

    Tgeneral_data_t gpr1       =   op->_data_ra;
    Tgeneral_data_t gpr2       =   (op->_has_immediat==1)?op->_immediat:op->_data_rb;
    
    log_printf(TRACE,Functionnal_unit,FUNCTION," * data_ra  : %.8x",unsigned(op->_data_ra));
    log_printf(TRACE,Functionnal_unit,FUNCTION," * data_ras : %.8x",  signed(op->_data_ra));
    log_printf(TRACE,Functionnal_unit,FUNCTION," * data_rb  : %.8x",unsigned((op->_has_immediat==1)?op->_immediat:op->_data_rb));
    log_printf(TRACE,Functionnal_unit,FUNCTION," * data_rbs : %.8x",  signed((op->_has_immediat==1)?op->_immediat:op->_data_rb));
    
    bool            f_out;

    switch (concatenation_bool(sign(gpr1),sign(gpr2)))
      {
      case 1 /*b01*/ : f_out = 1                               ; break;
      case 2 /*b10*/ : f_out = 0                               ; break;
      default        : f_out = signed(gpr1) >= signed(gpr2); break;
      }

    log_printf(TRACE,Functionnal_unit,FUNCTION," * f_out    : %.8x",f_out);

    // Result
    op->_timing       = param->_timing[op->_type][op->_operation];
  //op->_data_rd      = 0;
    op->_data_re      = set_flag(op->_data_re,FLAG_F,f_out);
    op->_exception    = EXCEPTION_ALU_NONE;
    op->_no_sequence  = 0;
  //op->_address      = 0;
  };

#undef  FUNCTION
#define FUNCTION "Functionnal_unit::operation_l_sfgts"
  void operation_l_sfgts       (execute_operation_t * op, execute_register_t * reg, execute_param_t * param)
  {
    log_printf(TRACE,Functionnal_unit,FUNCTION,"Operation : l_sfgts");

    Tgeneral_data_t gpr1       = op->_data_ra ;
    Tgeneral_data_t gpr2       = (op->_has_immediat==1)?op->_immediat:op->_data_rb ;

    bool            f_out;

    switch (concatenation_bool(sign(gpr1),sign(gpr2)))
      {
      case 1 /*b01*/ : f_out = 1; break;
      case 2 /*b10*/ : f_out = 0; break;
      default        : f_out = signed(gpr1) >  signed(gpr2); break;
      }

    // Result
    op->_timing       = param->_timing[op->_type][op->_operation];
  //op->_data_rd      = 0;
    op->_data_re      = set_flag(op->_data_re,FLAG_F,f_out);
    op->_exception    = EXCEPTION_ALU_NONE;
    op->_no_sequence  = 0;
  //op->_address      = 0;
  };

#undef  FUNCTION
#define FUNCTION "Functionnal_unit::operation_l_sfles"
  void operation_l_sfles       (execute_operation_t * op, execute_register_t * reg, execute_param_t * param)
  {
    log_printf(TRACE,Functionnal_unit,FUNCTION,"Operation : l_sfles");

    Tgeneral_data_t gpr1       = op->_data_ra ;
    Tgeneral_data_t gpr2       = (op->_has_immediat==1)?op->_immediat:op->_data_rb ;

    bool            f_out;

    switch (concatenation_bool(sign(gpr1),sign(gpr2)))
      {
      case 1 /*b01*/ : f_out = 0; break;
      case 2 /*b10*/ : f_out = 1; break;
      default        : f_out = signed(gpr1) <= signed(gpr2); break;
      }
    
    // Result
    op->_timing       = param->_timing[op->_type][op->_operation];
  //op->_data_rd      = 0;
    op->_data_re      = set_flag(op->_data_re,FLAG_F,f_out);
    op->_exception    = EXCEPTION_ALU_NONE;
    op->_no_sequence  = 0;
  //op->_address      = 0;
  };

#undef  FUNCTION
#define FUNCTION "Functionnal_unit::operation_l_sflts"
  void operation_l_sflts       (execute_operation_t * op, execute_register_t * reg, execute_param_t * param)
  {
    log_printf(TRACE,Functionnal_unit,FUNCTION,"Operation : l_sflts");

    Tgeneral_data_t gpr1       = op->_data_ra ;
    Tgeneral_data_t gpr2       = (op->_has_immediat==1)?op->_immediat:op->_data_rb;

    bool            f_out;

    switch (concatenation_bool(sign(gpr1),sign(gpr2)))
      {
      case 1 /*b01*/ : f_out = 0; break;
      case 2 /*b10*/ : f_out = 1; break;
      default        : f_out = signed(gpr1) <  signed(gpr2); break;
      }

    // Result
    op->_timing       = param->_timing[op->_type][op->_operation];
  //op->_data_rd      = 0;
    op->_data_re      = set_flag(op->_data_re,FLAG_F,f_out);
    op->_exception    = EXCEPTION_ALU_NONE;
    op->_no_sequence  = 0;
  //op->_address      = 0;
  };

#undef  FUNCTION
#define FUNCTION "Functionnal_unit::operation_l_mtspr"
  void operation_l_mtspr       (execute_operation_t * op, execute_register_t * reg, execute_param_t * param)
  {
    log_printf(TRACE,Functionnal_unit,FUNCTION,"Operation : l_mtspr");

    Tgeneral_data_t imm        = unsigned(op->_immediat);
    Tgeneral_data_t gpr1       = unsigned(op->_data_ra);
    Tgeneral_data_t gpr2       = unsigned(op->_data_rb);
    Tgeneral_data_t addr       = range<Tgeneral_data_t>(gpr1|imm,16);

    Texception_t    exception;

    // HACK : use the field num_reg_re to pass the SM and SUMRA flag.
    Tcontrol_t      flag_SM    = get_flag(op->_num_reg_re, 0x1);
    Tcontrol_t      flag_SUMRA = get_flag(op->_num_reg_re, 0x2);

    spr_address_t   spr_addr   = reg->_spr_access_mode->translate_address(addr);
    
    // Test if this group is implemented in this functionnal_unit
    if (reg->_spr_access_mode->valid(spr_addr))
      {
	if (reg->_spr_access_mode->write(spr_addr, flag_SM, flag_SUMRA))
	  {
	    reg->_i_write_spr         = true;
	    reg->_access_num_group    = spr_addr._group;
	    reg->_access_num_register = spr_addr._register;
	    reg->_spr_old             = reg->_spr[spr_addr._group][spr_addr._register];
	    reg->_spr[spr_addr._group][spr_addr._register] = gpr2;

	    exception = EXCEPTION_ALU_NONE;
	  }
	else
	  {
	    exception = EXCEPTION_ALU_SPR_ACCESS_INVALID;
	  }
      }
    else
      {
	exception = EXCEPTION_ALU_SPR_ACCESS_NOT_COMPLETE;
      }
    
    // Result
    op->_timing       = param->_timing[op->_type][op->_operation];
    op->_data_rd      = gpr2; // data_rb
  //op->_data_re      = 0;
    op->_exception    = exception;
    op->_no_sequence  = 0;
    op->_address      = addr; // data_ra or imm
  };

#undef  FUNCTION
#define FUNCTION "Functionnal_unit::operation_l_mfspr"
  void operation_l_mfspr       (execute_operation_t * op, execute_register_t * reg, execute_param_t * param)
  {
    log_printf(TRACE,Functionnal_unit,FUNCTION,"Operation : l_mfspr");

    Tgeneral_data_t imm        = unsigned(op->_immediat);
    Tgeneral_data_t gpr1       = unsigned(op->_data_ra);
    Tgeneral_data_t gpr2       = 0;
    Tgeneral_data_t addr       = range<Tgeneral_data_t>(gpr1|imm,16);

    Texception_t    exception;

    // HACK : use the field num_reg_re to pass the SM and SUMRA flag.
    Tcontrol_t      flag_SM    = get_flag(op->_num_reg_re, 0x1);
    Tcontrol_t      flag_SUMRA = get_flag(op->_num_reg_re, 0x2);

    spr_address_t   spr_addr   = reg->_spr_access_mode->translate_address(addr);
    
    // Test if this group is implemented in this functionnal_unit
    if (reg->_spr_access_mode->valid(spr_addr))
      {
	if (reg->_spr_access_mode->read(spr_addr, flag_SM, flag_SUMRA))
	  {
	    reg->_i_read_spr          = true;
	    reg->_access_num_group    = spr_addr._group;
	    reg->_access_num_register = spr_addr._register;
	    
	    gpr2 = reg->_spr[spr_addr._group][spr_addr._register];

	    exception = EXCEPTION_ALU_NONE;
	  }
	else
	  {
	    exception = EXCEPTION_ALU_SPR_ACCESS_INVALID;
	  }
      }
    else
      {
	exception = EXCEPTION_ALU_SPR_ACCESS_NOT_COMPLETE;
      }

    // Result
    op->_timing       = param->_timing[op->_type][op->_operation];
    op->_write_rd     = (exception == EXCEPTION_ALU_NONE);
    op->_data_rd      = gpr2; // spr
  //op->_data_re      = 0;
    op->_exception    = exception;
    op->_no_sequence  = 0;
    op->_address      = addr; // data_ra or imm
  };

#undef  FUNCTION
#define FUNCTION "Functionnal_unit::operation_l_macrc"
  void operation_l_macrc        (execute_operation_t * op, execute_register_t * reg, execute_param_t * param)
  {
    log_printf(TRACE,Functionnal_unit,FUNCTION,"Operation : l_macrc");

    Tgeneral_data_t gpr = static_cast<Tgeneral_data_t>(range<uint64_t>((static_cast<uint64_t>(reg->_spr[GROUP_MAC][SPR_MACHI]) << 32) | static_cast<uint64_t>(reg->_spr[GROUP_MAC][SPR_MACLO]), param->_size_data));

    reg->_spr[GROUP_MAC][SPR_MACLO] = 0;
    reg->_spr[GROUP_MAC][SPR_MACHI] = 0;

    // Result
    op->_timing       = param->_timing[op->_type][op->_operation];
    op->_data_rd      = gpr;
  //op->_data_re      = 0;
    op->_exception    = EXCEPTION_ALU_NONE;
    op->_no_sequence  = 0;
  //op->_address      = 0;
  };

#undef  FUNCTION
#define FUNCTION "Functionnal_unit::operation_l_mac"
  void operation_l_mac          (execute_operation_t * op, execute_register_t * reg, execute_param_t * param)
  {
    log_printf(TRACE,Functionnal_unit,FUNCTION,"Operation : l_mac");

    Tgeneral_data_t gpr1 = unsigned(op->_data_ra);
    Tgeneral_data_t gpr2 = unsigned((op->_has_immediat==1)?op->_immediat:op->_data_rb);
    uint64_t        temp = range<uint64_t>(gpr1 * gpr2, 32);

    temp = ((static_cast<uint64_t>(reg->_spr[GROUP_MAC][SPR_MACHI]) << 32) | static_cast<uint64_t>(reg->_spr[GROUP_MAC][SPR_MACLO])) + temp;

    reg->_spr[GROUP_MAC][SPR_MACLO] = range<Tgeneral_data_t>(temp    ,32);
    reg->_spr[GROUP_MAC][SPR_MACHI] = range<Tgeneral_data_t>(temp>>32,32);
    
    // Result
    op->_timing       = param->_timing[op->_type][op->_operation];
  //op->_data_rd      = 0;
  //op->_data_re      = 0;
    op->_exception    = EXCEPTION_ALU_NONE;
    op->_no_sequence  = 0;
  //op->_address      = 0;
  };

#undef  FUNCTION
#define FUNCTION "Functionnal_unit::operation_l_msb"
  void operation_l_msb          (execute_operation_t * op, execute_register_t * reg, execute_param_t * param)
  {
    log_printf(TRACE,Functionnal_unit,FUNCTION,"Operation : l_msb");

    Tgeneral_data_t gpr1 = unsigned(op->_data_ra);
    Tgeneral_data_t gpr2 = unsigned((op->_has_immediat==1)?op->_immediat:op->_data_rb);
    uint64_t        temp = range<uint64_t>(gpr1 * gpr2, 32);

    temp = ((static_cast<uint64_t>(reg->_spr[GROUP_MAC][SPR_MACHI]) << 32) | static_cast<uint64_t>(reg->_spr[GROUP_MAC][SPR_MACLO])) - temp;

    reg->_spr[GROUP_MAC][SPR_MACLO] = range<Tgeneral_data_t>(temp    ,32);
    reg->_spr[GROUP_MAC][SPR_MACHI] = range<Tgeneral_data_t>(temp>>32,32);
    
    // Result
    op->_timing       = param->_timing[op->_type][op->_operation];
  //op->_data_rd      = 0;
  //op->_data_re      = 0;
    op->_exception    = EXCEPTION_ALU_NONE;
    op->_no_sequence  = 0;
  //op->_address      = 0;
  };

}; // end namespace functionnal_unit
}; // end namespace execute_unit
}; // end namespace multi_execute_unit
}; // end namespace execute_loop
}; // end namespace multi_execute_loop
}; // end namespace core
}; // end namespace behavioural
}; // end namespace morpheo              
#endif
