#include "cpu.h"

void Cpu_state::setAF(u16 v)
{
  A         = (u8)(v >> 8);
  zero      = (v & 0x80 != 0);
  subtract  = (v & 0x40 != 0);
  halfcarry = (v & 0x20 != 0);
  carry     = (v & 0x10 != 0);
}

u16 Cpu_state::getAF()
{
  return ((u16)A << 8) |
    (zero      ? 0x80 : 0) |
    (subtract  ? 0x40 : 0) |
    (halfcarry ? 0x20 : 0) |
    (carry     ? 0x10 : 0);
}

void Cpu::aluop8(AluOp op, u8 lhs, u8 rhs, u8& out, bool update_carry)
{
  u16 rhs16 = rhs;
  u16 res16;
  u8 res;

  if ((op == ADC || op == SBC) && state.carry)
    rhs16++;

  u16 lhs_lower = lhs & 0x0F;
  u16 lhs_upper = lhs & 0xF0;
  u16 rhs_lower = rhs16 & 0x0F;
  u16 rhs_upper = rhs16 & 0x1F0;

  switch(op)
    {
    case ADD:
    case ADC:
      res16 = lhs_lower + rhs_lower;
      break;
    case SUB:
    case SBC:
    case CP:
      res16 = lhs_lower - rhs_lower;
      break;
    case AND:
      res16 = lhs_lower & rhs_lower;
      break;
    case OR:
      res16 = lhs_lower | rhs_lower;
      break;
    case XOR:
      res16 = lhs_lower ^ rhs_lower;
      break;
    }

  state.halfcarry = (res16 & 0x10 != 0) || op == AND;
  state.subtract = (op == SUB) || (op == SBC) || (op == CP);

  switch(op)
    {
    case ADD:
    case ADC:
      res16 += lhs_upper + rhs_upper;
      break;
    case SUB:
    case SBC:
    case CP:
      res16 += lhs_upper - rhs_upper;
      break;
    case AND:
      res16 |= lhs_upper & rhs_upper;
      break;
    case OR:
      res16 |= lhs_upper | rhs_upper;
      break;
    case XOR:
      res16 |= lhs_upper ^ rhs_upper;
      break;
    }

  res = (u8)(res16 & 0xFF);

  if(update_carry)
    state.carry = (res16 & 0x100 != 0);

  state.zero = (res == 0);

  if (op != CP)
    out = res;
}