#include <cpu_prog_model.h>
#include <cpu6502_addrm.h>



void ADC_imm( code)
PM *code;
{
   short Value,
         Komp_Acc,
         Komp_Value,
         Old_Acc,
         Old_Carry;

   Value = code->Me [imm_address( code)];

   Komp_Acc = code->Ac;
   if (Komp_Acc >= 0x80)
      Komp_Acc |= (-1 ^ 0xFF);

   Komp_Value = Value;
   if (Komp_Value >= 0x80)
      Komp_Value |= (-1 ^ 0xFF);

   Old_Acc   = code->Ac;
   Old_Carry = code->Ca;

   (code->Ac) += (Value + code->Ca);
   code->Ca = (code->Ac > 0xFF);
   (code->Ac) &= 0xFF;
   set_neg_zero_stat( code, code->Ac);

   code->Ov = ( (Komp_Acc + Komp_Value + Old_Carry) >= 0x80) ||
              ( !(code->Ne) && (Old_Acc >= 0x80) && (Value >= 0x80) );
}

void ADC_zer( code)
PM *code;
{
   unsigned short int address;

   short Value,
         Komp_Acc,
         Komp_Value,
         Old_Acc,
         Old_Carry;

   address = zero_address( code);
   mem_check( address, &(code->Me [address]), code, Func_LOAD);
   Value = code->Me [address];

   Komp_Acc = code->Ac;
   if (Komp_Acc >= 0x80)
      Komp_Acc |= (-1 ^ 0xFF);

   Komp_Value = Value;
   if (Komp_Value >= 0x80)
      Komp_Value |= (-1 ^ 0xFF);

   Old_Acc   = code->Ac;
   Old_Carry = code->Ca;

   (code->Ac) += (Value + code->Ca);
   code->Ca = (code->Ac > 0xFF);
   (code->Ac) &= 0xFF;
   set_neg_zero_stat( code, code->Ac);

   code->Ov = ( (Komp_Acc + Komp_Value + Old_Carry) >= 0x80) ||
              ( !(code->Ne) && (Old_Acc >= 0x80) && (Value >= 0x80) );
}

void ADC_zex( code)
PM *code;
{
   unsigned short int address;

   short Value,
         Komp_Acc,
         Komp_Value,
         Old_Acc,
         Old_Carry;

   address = zero_x_address( code);
   mem_check( address, &(code->Me [address]), code, Func_LOAD);
   Value = code->Me [address];

   Komp_Acc = code->Ac;
   if (Komp_Acc >= 0x80)
      Komp_Acc |= (-1 ^ 0xFF);

   Komp_Value = Value;
   if (Komp_Value >= 0x80)
      Komp_Value |= (-1 ^ 0xFF);

   Old_Acc   = code->Ac;
   Old_Carry = code->Ca;

   (code->Ac) += (Value + code->Ca);
   code->Ca = (code->Ac > 0xFF);
   (code->Ac) &= 0xFF;
   set_neg_zero_stat( code, code->Ac);

   code->Ov = ( (Komp_Acc + Komp_Value + Old_Carry) >= 0x80) ||
              ( !(code->Ne) && (Old_Acc >= 0x80) && (Value >= 0x80) );
}

void ADC_abs( code)
PM *code;
{
   unsigned short int address;

   short Value,
         Komp_Acc,
         Komp_Value,
         Old_Acc,
         Komp_Old_Acc,
         Old_Carry;

   address = abs_address( code);

   Value = code->Me [address];
   mem_check( address, &Value, code, Func_LOAD);

   Komp_Old_Acc = code->Ac;
   if (Komp_Acc >= 0x80)
      Komp_Acc |= (-1 ^ 0xFF);

   Komp_Value = Value;
   if (Komp_Value >= 0x80)
      Komp_Value |= (-1 ^ 0xFF);

   Old_Acc   = code->Ac;
   Old_Carry = code->Ca;

   (code->Ac) += (Value + code->Ca);
   code->Ca = (code->Ac > 0xFF);
   (code->Ac) &= 0xFF;

   Komp_Acc = code->Ac;
   if (Komp_Acc >= 0x80)
      Komp_Acc |= (-1 ^ 0xFF);

   set_neg_zero_stat( code, code->Ac);

   code->Ov = ( (Komp_Old_Acc + Komp_Value + Old_Carry) >= 0x80) ||
              ( !(code->Ne) && (Old_Acc >= 0x80) && (Value >= 0x80) );
}

void ADC_abx( code)
PM *code;
{
   unsigned short int address;

   short Value,
         Komp_Acc,
         Komp_Value,
         Old_Acc,
         Old_Carry;

   address = abs_x_address( code);

   Value = code->Me [address];
   mem_check( address, &Value, code, Func_LOAD);

   Komp_Acc = code->Ac;
   if (Komp_Acc >= 0x80)
      Komp_Acc |= (-1 ^ 0xFF);

   Komp_Value = Value;
   if (Komp_Value >= 0x80)
      Komp_Value |= (-1 ^ 0xFF);

   Old_Acc   = code->Ac;
   Old_Carry = code->Ca;

   (code->Ac) += (Value + code->Ca);
   code->Ca = (code->Ac > 0xFF);
   (code->Ac) &= 0xFF;
   set_neg_zero_stat( code, code->Ac);

   code->Ov = ( (Komp_Acc + Komp_Value + Old_Carry) >= 0x80) ||
              ( !(code->Ne) && (Old_Acc >= 0x80) && (Value >= 0x80) );
}

void ADC_aby( code)
PM *code;
{
   unsigned short int address;

   short Value,
         Komp_Acc,
         Komp_Value,
         Old_Acc,
         Old_Carry;

   address = abs_y_address( code);

   Value = code->Me [address];
   mem_check( address, &Value, code, Func_LOAD);

   Komp_Acc = code->Ac;
   if (Komp_Acc >= 0x80)
      Komp_Acc |= (-1 ^ 0xFF);

   Komp_Value = Value;
   if (Komp_Value >= 0x80)
      Komp_Value |= (-1 ^ 0xFF);

   Old_Acc   = code->Ac;
   Old_Carry = code->Ca;

   (code->Ac) += (Value + code->Ca);
   code->Ca = (code->Ac > 0xFF);
   (code->Ac) &= 0xFF;
   set_neg_zero_stat( code, code->Ac);

   code->Ov = ( (Komp_Acc + Komp_Value + Old_Carry) >= 0x80) ||
              ( !(code->Ne) && (Old_Acc >= 0x80) && (Value >= 0x80) );
}

void ADC_inx( code)
PM *code;
{
   unsigned short int address;

   short Value,
         Komp_Acc,
         Komp_Value,
         Old_Acc,
         Old_Carry;

   address = ind_x_address( code);
   mem_check( address, &(code->Me [address]), code, Func_LOAD);
   Value = code->Me [address];

   Komp_Acc = code->Ac;
   if (Komp_Acc >= 0x80)
      Komp_Acc |= (-1 ^ 0xFF);

   Komp_Value = Value;
   if (Komp_Value >= 0x80)
      Komp_Value |= (-1 ^ 0xFF);

   Old_Acc   = code->Ac;
   Old_Carry = code->Ca;

   (code->Ac) += (Value + code->Ca);
   code->Ca = (code->Ac > 0xFF);
   (code->Ac) &= 0xFF;
   set_neg_zero_stat( code, code->Ac);

   code->Ov = ( (Komp_Acc + Komp_Value + Old_Carry) >= 0x80) ||
              ( !(code->Ne) && (Old_Acc >= 0x80) && (Value >= 0x80) );
}

void ADC_iny( code)
PM *code;
{
   unsigned short int address;

   short Value,
         Komp_Acc,
         Komp_Value,
         Old_Acc,
         Old_Carry;

   address = ind_y_address( code);
   mem_check( address, &(code->Me [address]), code, Func_LOAD);
   Value = code->Me [address];

   Komp_Acc = code->Ac;
   if (Komp_Acc >= 0x80)
      Komp_Acc |= (-1 ^ 0xFF);

   Komp_Value = Value;
   if (Komp_Value >= 0x80)
      Komp_Value |= (-1 ^ 0xFF);

   Old_Acc   = code->Ac;
   Old_Carry = code->Ca;

   (code->Ac) += (Value + code->Ca);
   code->Ca = (code->Ac > 0xFF);
   (code->Ac) &= 0xFF;
   set_neg_zero_stat( code, code->Ac);

   code->Ov = ( (Komp_Acc + Komp_Value + Old_Carry) >= 0x80) ||
              ( !(code->Ne) && (Old_Acc >= 0x80) && (Value >= 0x80) );
}

void SBC_imm( code)
PM *code;
{
   short  memory,
          Acc_flag,
          Mem_flag,
          Ans_flag;

   memory = code->Me [imm_address( code)];
   Mem_flag = (memory >= 0x80);
   Acc_flag = (code->Ac >= 0x80);
   code->Ac = code->Ac - memory - !code->Ca;
   Ans_flag = (code->Ac >= 0x80);

   code->Ca = (code->Ac >= 0);
   code->Ac &= 0xFF;
   code->Ov = (Ans_flag ^ (Acc_flag && Mem_flag)) && !(Acc_flag ^ Mem_flag);
   set_neg_zero_stat( code, code->Ac);
}


void SBC_zer( code)
PM *code;
{
   unsigned short int address;

   short  memory,
          Acc_flag,
          Mem_flag,
          Ans_flag;

   address = zero_address( code);

   mem_check( address, &(code->Me [address]), code, Func_LOAD);
   memory = code->Me [address];

   Mem_flag = (memory >= 0x80);
   Acc_flag = (code->Ac >= 0x80);
   code->Ac = code->Ac - memory - !code->Ca;
   Ans_flag = (code->Ac >= 0x80);

   code->Ca = (code->Ac >= 0);
   code->Ac &= 0xFF;
   code->Ov = (Ans_flag ^ (Acc_flag && Mem_flag)) && !(Acc_flag ^ Mem_flag);
   set_neg_zero_stat( code, code->Ac);
}

void SBC_zex( code)
PM *code;
{
   unsigned short int address;

   short  memory,
          Acc_flag,
          Mem_flag,
          Ans_flag;

   address = zero_x_address( code);

   mem_check( address, &(code->Me [address]), code, Func_LOAD);
   memory = code->Me [address];

   Mem_flag = (memory >= 0x80);
   Acc_flag = (code->Ac >= 0x80);
   code->Ac = code->Ac - memory - !code->Ca;
   Ans_flag = (code->Ac >= 0x80);

   code->Ca = (code->Ac >= 0);
   code->Ac &= 0xFF;
   code->Ov = (Ans_flag ^ (Acc_flag && Mem_flag)) && !(Acc_flag ^ Mem_flag);
   set_neg_zero_stat( code, code->Ac);
}
void SBC_abs( code)
PM *code;
{
   unsigned short int address;

   short  memory,
          Acc_flag,
          Mem_flag,
          Ans_flag;

   address = abs_address( code);

   mem_check( address, &(code->Me [address]), code, Func_LOAD);
   memory = code->Me [address];

   Mem_flag = (memory >= 0x80);
   Acc_flag = (code->Ac >= 0x80);
   code->Ac = code->Ac - memory - !code->Ca;
   Ans_flag = (code->Ac >= 0x80);

   code->Ca = (code->Ac >= 0);
   code->Ac &= 0xFF;
   code->Ov = (Ans_flag ^ (Acc_flag && Mem_flag)) && !(Acc_flag ^ Mem_flag);
   set_neg_zero_stat( code, code->Ac);
}

void SBC_abx( code)
PM *code;
{
   unsigned short int address;

   short  memory,
          Acc_flag,
          Mem_flag,
          Ans_flag;

   address = abs_x_address( code);

   mem_check( address, &(code->Me [address]), code, Func_LOAD);
   memory = code->Me [address];

   Mem_flag = (memory >= 0x80);
   Acc_flag = (code->Ac >= 0x80);
   code->Ac = code->Ac - memory - !code->Ca;
   Ans_flag = (code->Ac >= 0x80);

   code->Ca = (code->Ac >= 0);
   code->Ac &= 0xFF;
   code->Ov = (Ans_flag ^ (Acc_flag && Mem_flag)) && !(Acc_flag ^ Mem_flag);
   set_neg_zero_stat( code, code->Ac);
}

void SBC_aby( code)
PM *code;
{
   unsigned short int address;

   short  memory,
          Acc_flag,
          Mem_flag,
          Ans_flag;

   address = abs_y_address( code);

   mem_check( address, &(code->Me [address]), code, Func_LOAD);
   memory = code->Me [address];

   Mem_flag = (memory >= 0x80);
   Acc_flag = (code->Ac >= 0x80);
   code->Ac = code->Ac - memory - !code->Ca;
   Ans_flag = (code->Ac >= 0x80);

   code->Ca = (code->Ac >= 0);
   code->Ac &= 0xFF;
   code->Ov = (Ans_flag ^ (Acc_flag && Mem_flag)) && !(Acc_flag ^ Mem_flag);
   set_neg_zero_stat( code, code->Ac);
}


void SBC_inx( code)
PM *code;
{
   unsigned short int   address;
   short                memory,
                        Acc_flag,
                        Mem_flag,
                        Ans_flag;

   address = ind_x_address( code);

   memory = code->Me [address];
   Mem_flag = (memory >= 0x80);
   Acc_flag = (code->Ac >= 0x80);
   code->Ac = code->Ac - memory - !code->Ca;
   Ans_flag = (code->Ac >= 0x80);

   code->Ca = (code->Ac >= 0);
   code->Ac &= 0xFF;
   code->Ov = (Ans_flag ^ (Acc_flag && Mem_flag)) && !(Acc_flag ^ Mem_flag);
   set_neg_zero_stat( code, code->Ac);
}

void SBC_iny( code)
PM *code;
{
   unsigned short int   address;
   short                memory,
                        Acc_flag,
                        Mem_flag,
                        Ans_flag;

   address = ind_y_address( code);

   memory = code->Me [address];
   Mem_flag = (memory >= 0x80);
   Acc_flag = (code->Ac >= 0x80);
   code->Ac = code->Ac - memory - !code->Ca;
   Ans_flag = (code->Ac >= 0x80);

   code->Ca = (code->Ac >= 0);
   code->Ac &= 0xFF;
   code->Ov = (Ans_flag ^ (Acc_flag && Mem_flag)) && !(Acc_flag ^ Mem_flag);
   set_neg_zero_stat( code, code->Ac);
}


