#include "cpu/exec.h"
#include "cpu/cc.h"

void sign_extend_if_required(const Operand &dest, Operand &src) {
  if(dest.width > src.width) {
    rtl_sext(&src.val, &src.val, src.width);
    src.imm = src.val;
    src.width = dest.width;
  }
}

namespace EHelperImpl {
  using vaddr_t = uint32_t;

make_EHelper(test) {
  // `and` without write_back.
  sign_extend_if_required(*id_dest, *id_src);
  rtl_and(&t1, &id_dest->val, &id_src->val);

  rtl_update_ZFSF(&t1, id_dest->width);
  cpu_eflags::get<cpu_eflags::CF>() = cpu_eflags::get<cpu_eflags::OF>() = false;

  print_asm_template2(test);
}

make_EHelper(and) {
  rlib::printfln("before test, id_dest={}, src={}", *id_dest, *id_src);
  sign_extend_if_required(*id_dest, *id_src);
  rlib::printfln("after test, id_dest={}, src={}", *id_dest, *id_src);

  rtl_and(&id_dest->val, &id_dest->val, &id_src->val);
  operand_write(id_dest, &id_dest->val);

  rtl_update_ZFSF(&id_dest->val, id_dest->width);
  cpu_eflags::get<cpu_eflags::CF>() = cpu_eflags::get<cpu_eflags::OF>() = false;

  print_asm_template2(and);
}

make_EHelper(xor) {
  sign_extend_if_required(*id_dest, *id_src);

  rtl_xor(&id_dest->val, &id_dest->val, &id_src->val);
  operand_write(id_dest, &id_dest->val);

  rtl_update_ZFSF(&id_dest->val, id_dest->width);
  cpu_eflags::get<cpu_eflags::CF>() = cpu_eflags::get<cpu_eflags::OF>() = false;

  print_asm_template2(xor);
}

make_EHelper(or) {
  TODO();

  print_asm_template2(or);
}

make_EHelper(sar) {
  TODO();
  // unnecessary to update CF and OF in NEMU

  print_asm_template2(sar);
}

make_EHelper(shl) {
  TODO();
  // unnecessary to update CF and OF in NEMU

  print_asm_template2(shl);
}

make_EHelper(shr) {
  TODO();
  // unnecessary to update CF and OF in NEMU

  print_asm_template2(shr);
}

make_EHelper(setcc) {
  uint32_t cc = decoding.opcode & 0xf;

  rtl_setcc(&t2, cc);
  operand_write(id_dest, &t2);

  print_asm("set%s %s", get_cc_name(cc), id_dest->str);
}

make_EHelper(not) {
  TODO();

  print_asm_template1(not);
}

make_EHelper(rol) {
  TODO();

  print_asm_template1(rol);
}

} // end namespace ehelperimpl