|
|
|
@@ -7,6 +7,55 @@
|
|
|
|
|
#define LO_BYTE(x) ((uint8_t)((x) & 0xFF))
|
|
|
|
|
#define HI_BYTE(x) ((uint8_t)(((x) >> 8) & 0xFF))
|
|
|
|
|
|
|
|
|
|
static void doADC(CPU *cpu, uint8_t value) {
|
|
|
|
|
if (cpu->Flags.DecimalMode == 1) {
|
|
|
|
|
uint16_t al = (cpu->Accumulator & 0x0F) + (value & 0x0F) + cpu->Flags.CarryFlag;
|
|
|
|
|
if (al >= 0x0A) al = ((al + 0x06) & 0x0F) + 0x10;
|
|
|
|
|
|
|
|
|
|
uint16_t sum = (cpu->Accumulator & 0xF0) + (value & 0xF0) + al;
|
|
|
|
|
if (sum >= 0xA0) sum += 0x60;
|
|
|
|
|
|
|
|
|
|
// N/V/Z are hardware-quirky in decimal mode; derive from the binary sum
|
|
|
|
|
uint16_t binSum = cpu->Accumulator + value + cpu->Flags.CarryFlag;
|
|
|
|
|
cpu->Flags.OverflowFlag = ((cpu->Accumulator ^ binSum) & (value ^ binSum) & 0x80) != 0;
|
|
|
|
|
cpu->Flags.NegativeFlag = (sum & 0x80) != 0;
|
|
|
|
|
cpu->Flags.ZeroFlag = (uint8_t)binSum == 0;
|
|
|
|
|
|
|
|
|
|
cpu->Flags.CarryFlag = sum >= 0x100;
|
|
|
|
|
cpu->Accumulator = (uint8_t)sum;
|
|
|
|
|
} else {
|
|
|
|
|
uint16_t result = cpu->Accumulator + value + cpu->Flags.CarryFlag;
|
|
|
|
|
cpu->Flags.CarryFlag = result > 0xFF;
|
|
|
|
|
cpu->Flags.ZeroFlag = (uint8_t)result == 0;
|
|
|
|
|
cpu->Flags.OverflowFlag = ((cpu->Accumulator ^ result) & (value ^ result) & 0x80) != 0;
|
|
|
|
|
cpu->Flags.NegativeFlag = (result & 0x80) != 0;
|
|
|
|
|
cpu->Accumulator = (uint8_t)result;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void doSBC(CPU *cpu, uint8_t value) {
|
|
|
|
|
uint8_t carryIn = cpu->Flags.CarryFlag;
|
|
|
|
|
uint8_t inverted = value ^ 0xFF;
|
|
|
|
|
|
|
|
|
|
uint16_t binResult = cpu->Accumulator + inverted + carryIn;
|
|
|
|
|
cpu->Flags.CarryFlag = binResult > 0xFF;
|
|
|
|
|
cpu->Flags.ZeroFlag = (uint8_t)binResult == 0;
|
|
|
|
|
cpu->Flags.OverflowFlag = ((cpu->Accumulator ^ binResult) & (inverted ^ binResult) & 0x80) != 0;
|
|
|
|
|
cpu->Flags.NegativeFlag = (binResult & 0x80) != 0;
|
|
|
|
|
|
|
|
|
|
if (cpu->Flags.DecimalMode == 1) {
|
|
|
|
|
int16_t al = (cpu->Accumulator & 0x0F) - (value & 0x0F) - (1 - carryIn);
|
|
|
|
|
if (al < 0) al = ((al - 0x06) & 0x0F) - 0x10;
|
|
|
|
|
|
|
|
|
|
int16_t sum = (cpu->Accumulator & 0xF0) - (value & 0xF0) + al;
|
|
|
|
|
if (sum < 0) sum -= 0x60;
|
|
|
|
|
|
|
|
|
|
cpu->Accumulator = (uint8_t)sum;
|
|
|
|
|
} else {
|
|
|
|
|
cpu->Accumulator = (uint8_t)binResult;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void initCPU(CPU *cpu) {
|
|
|
|
|
#pragma clang diagnostic push
|
|
|
|
|
#pragma clang diagnostic ignored "-Wmissing-field-initializers"
|
|
|
|
@@ -20,7 +69,7 @@ void resetCPU(CPU *cpu, uint8_t *rom) {
|
|
|
|
|
cpu->ProgrammeCounter = COMBINE(high, low);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
useconds_t runCycle(CPU *cpu, uint8_t *ram, uint8_t *rom) {
|
|
|
|
|
uint8_t runCycle(CPU *cpu, uint8_t *ram, uint8_t *rom) {
|
|
|
|
|
// Fetch opcode
|
|
|
|
|
uint8_t opcode = readMemory(cpu->ProgrammeCounter++, ram, rom);
|
|
|
|
|
|
|
|
|
@@ -144,7 +193,7 @@ useconds_t runCycle(CPU *cpu, uint8_t *ram, uint8_t *rom) {
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
case BPL: {
|
|
|
|
|
useconds_t cycles = 2;
|
|
|
|
|
uint8_t cycles = 2;
|
|
|
|
|
|
|
|
|
|
// Get offset
|
|
|
|
|
int8_t offset = (int8_t)readMemory(cpu->ProgrammeCounter++, ram, rom);
|
|
|
|
@@ -399,7 +448,7 @@ useconds_t runCycle(CPU *cpu, uint8_t *ram, uint8_t *rom) {
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
case BMI: {
|
|
|
|
|
useconds_t cycles = 2;
|
|
|
|
|
uint8_t cycles = 2;
|
|
|
|
|
|
|
|
|
|
// Get offset
|
|
|
|
|
int8_t offset = (int8_t)readMemory(cpu->ProgrammeCounter++, ram, rom);
|
|
|
|
@@ -562,7 +611,7 @@ useconds_t runCycle(CPU *cpu, uint8_t *ram, uint8_t *rom) {
|
|
|
|
|
// Perform shift
|
|
|
|
|
cpu->Flags.CarryFlag = (value & 0x01) != 0;
|
|
|
|
|
value = (uint8_t)(value >> 1);
|
|
|
|
|
// Set flags, write to memory
|
|
|
|
|
// Set flags and write to memory
|
|
|
|
|
cpu->Flags.ZeroFlag = value == 0;
|
|
|
|
|
cpu->Flags.NegativeFlag = 0;
|
|
|
|
|
writeMemory(offset, value, ram, rom);
|
|
|
|
@@ -604,7 +653,17 @@ useconds_t runCycle(CPU *cpu, uint8_t *ram, uint8_t *rom) {
|
|
|
|
|
return 3;
|
|
|
|
|
}
|
|
|
|
|
case EOR_A: {
|
|
|
|
|
break;
|
|
|
|
|
// Load address
|
|
|
|
|
uint8_t low = readMemory(cpu->ProgrammeCounter++, ram, rom);
|
|
|
|
|
uint8_t high = readMemory(cpu->ProgrammeCounter++, ram, rom);
|
|
|
|
|
// Get value
|
|
|
|
|
uint8_t value = readMemory(COMBINE(high, low), ram, rom);
|
|
|
|
|
// Perform XOR, set flags
|
|
|
|
|
cpu->Accumulator ^= value;
|
|
|
|
|
cpu->Flags.ZeroFlag = cpu->Accumulator == 0;
|
|
|
|
|
cpu->Flags.NegativeFlag = (cpu->Accumulator & 0x80) != 0;
|
|
|
|
|
|
|
|
|
|
return 4;
|
|
|
|
|
}
|
|
|
|
|
case LSR_A: {
|
|
|
|
|
// Load address
|
|
|
|
@@ -615,7 +674,7 @@ useconds_t runCycle(CPU *cpu, uint8_t *ram, uint8_t *rom) {
|
|
|
|
|
// Perform shift
|
|
|
|
|
cpu->Flags.CarryFlag = (value & 0x01) != 0;
|
|
|
|
|
value = (uint8_t)(value >> 1);
|
|
|
|
|
// Set flags, write to memory
|
|
|
|
|
// Set flags and write to memory
|
|
|
|
|
cpu->Flags.ZeroFlag = value == 0;
|
|
|
|
|
cpu->Flags.NegativeFlag = 0;
|
|
|
|
|
writeMemory(COMBINE(high, low), value, ram, rom);
|
|
|
|
@@ -624,7 +683,7 @@ useconds_t runCycle(CPU *cpu, uint8_t *ram, uint8_t *rom) {
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
case BVC: {
|
|
|
|
|
useconds_t cycles = 2;
|
|
|
|
|
uint8_t cycles = 2;
|
|
|
|
|
|
|
|
|
|
// Get offset
|
|
|
|
|
int8_t offset = (int8_t)readMemory(cpu->ProgrammeCounter++, ram, rom);
|
|
|
|
@@ -678,7 +737,7 @@ useconds_t runCycle(CPU *cpu, uint8_t *ram, uint8_t *rom) {
|
|
|
|
|
// Perform shift
|
|
|
|
|
cpu->Flags.CarryFlag = (value & 0x01) != 0;
|
|
|
|
|
value = (uint8_t)(value >> 1);
|
|
|
|
|
// Set flags, write to memory
|
|
|
|
|
// Set flags and write to memory
|
|
|
|
|
cpu->Flags.ZeroFlag = value == 0;
|
|
|
|
|
cpu->Flags.NegativeFlag = 0;
|
|
|
|
|
writeMemory((uint8_t)(cpu->X + offset), value, ram, rom);
|
|
|
|
@@ -725,7 +784,7 @@ useconds_t runCycle(CPU *cpu, uint8_t *ram, uint8_t *rom) {
|
|
|
|
|
// Perform shift
|
|
|
|
|
cpu->Flags.CarryFlag = (value & 0x01) != 0;
|
|
|
|
|
value = (uint8_t)(value >> 1);
|
|
|
|
|
// Set flags, write to memory
|
|
|
|
|
// Set flags and write to memory
|
|
|
|
|
cpu->Flags.ZeroFlag = value == 0;
|
|
|
|
|
cpu->Flags.NegativeFlag = 0;
|
|
|
|
|
writeMemory(cpu->X + COMBINE(high, low), value, ram, rom);
|
|
|
|
@@ -752,17 +811,8 @@ useconds_t runCycle(CPU *cpu, uint8_t *ram, uint8_t *rom) {
|
|
|
|
|
uint8_t high = readMemory((uint8_t)(_address + 1), ram, rom);
|
|
|
|
|
// Get value
|
|
|
|
|
uint8_t value = readMemory(COMBINE(high, low), ram, rom);
|
|
|
|
|
// BCD
|
|
|
|
|
if (cpu->Flags.DecimalMode == 1) {
|
|
|
|
|
break; // TODO: BCD
|
|
|
|
|
} else {
|
|
|
|
|
uint16_t result = cpu->Accumulator + value + cpu->Flags.CarryFlag;
|
|
|
|
|
cpu->Flags.CarryFlag = result > 0xFF;
|
|
|
|
|
cpu->Flags.ZeroFlag = result == 0;
|
|
|
|
|
cpu->Flags.OverflowFlag = ((cpu->Accumulator ^ result) & (value ^ result) & 0x80) != 0;
|
|
|
|
|
cpu->Flags.NegativeFlag = (result & 0x80) != 0;
|
|
|
|
|
cpu->Accumulator = (uint8_t)result;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
doADC(cpu, value);
|
|
|
|
|
|
|
|
|
|
return 6;
|
|
|
|
|
}
|
|
|
|
@@ -771,22 +821,28 @@ useconds_t runCycle(CPU *cpu, uint8_t *ram, uint8_t *rom) {
|
|
|
|
|
uint8_t offset = readMemory(cpu->ProgrammeCounter++, ram, rom);
|
|
|
|
|
// Get value
|
|
|
|
|
uint8_t value = readMemory(offset, ram, rom);
|
|
|
|
|
// BCD
|
|
|
|
|
if (cpu->Flags.DecimalMode == 1) {
|
|
|
|
|
break; // TODO: BCD
|
|
|
|
|
} else {
|
|
|
|
|
uint16_t result = cpu->Accumulator + value + cpu->Flags.CarryFlag;
|
|
|
|
|
cpu->Flags.CarryFlag = result > 0xFF;
|
|
|
|
|
cpu->Flags.ZeroFlag = result == 0;
|
|
|
|
|
cpu->Flags.OverflowFlag = ((cpu->Accumulator ^ result) & (value ^ result) & 0x80) != 0;
|
|
|
|
|
cpu->Flags.NegativeFlag = (result & 0x80) != 0;
|
|
|
|
|
cpu->Accumulator = (uint8_t)result;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
doADC(cpu, value);
|
|
|
|
|
|
|
|
|
|
return 3;
|
|
|
|
|
}
|
|
|
|
|
case ROR_Z: {
|
|
|
|
|
break;
|
|
|
|
|
// Get offset
|
|
|
|
|
uint8_t offset = readMemory(cpu->ProgrammeCounter++, ram, rom);
|
|
|
|
|
// Get value
|
|
|
|
|
uint8_t value = readMemory(offset, ram, rom);
|
|
|
|
|
// Save bit 0, rotate, set bit 0
|
|
|
|
|
uint8_t bit0 = value & 0x1;
|
|
|
|
|
value = value >> 1;
|
|
|
|
|
value |= (cpu->Flags.CarryFlag << 7);
|
|
|
|
|
// Set flags
|
|
|
|
|
cpu->Flags.CarryFlag = bit0 != 0;
|
|
|
|
|
cpu->Flags.ZeroFlag = value == 0;
|
|
|
|
|
cpu->Flags.NegativeFlag = (value & 0x80) != 0;
|
|
|
|
|
// Write value
|
|
|
|
|
writeMemory(offset, value, ram, rom);
|
|
|
|
|
|
|
|
|
|
return 5;
|
|
|
|
|
}
|
|
|
|
|
case PLA: {
|
|
|
|
|
// Pull from stack
|
|
|
|
@@ -799,22 +855,22 @@ useconds_t runCycle(CPU *cpu, uint8_t *ram, uint8_t *rom) {
|
|
|
|
|
case ADC_I: {
|
|
|
|
|
// Get value
|
|
|
|
|
uint8_t value = readMemory(cpu->ProgrammeCounter++, ram, rom);
|
|
|
|
|
// BCD
|
|
|
|
|
if (cpu->Flags.DecimalMode == 1) {
|
|
|
|
|
break; // TODO: BCD
|
|
|
|
|
} else {
|
|
|
|
|
uint16_t result = cpu->Accumulator + value + cpu->Flags.CarryFlag;
|
|
|
|
|
cpu->Flags.CarryFlag = result > 0xFF;
|
|
|
|
|
cpu->Flags.ZeroFlag = result == 0;
|
|
|
|
|
cpu->Flags.OverflowFlag = ((cpu->Accumulator ^ result) & (value ^ result) & 0x80) != 0;
|
|
|
|
|
cpu->Flags.NegativeFlag = (result & 0x80) != 0;
|
|
|
|
|
cpu->Accumulator = (uint8_t)result;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
doADC(cpu, value);
|
|
|
|
|
|
|
|
|
|
return 2;
|
|
|
|
|
}
|
|
|
|
|
case ROR: {
|
|
|
|
|
break;
|
|
|
|
|
// Save bit 0, rotate, set bit 0
|
|
|
|
|
uint8_t bit0 = cpu->Accumulator & 0x1;
|
|
|
|
|
cpu->Accumulator = cpu->Accumulator >> 1;
|
|
|
|
|
cpu->Accumulator |= (cpu->Flags.CarryFlag << 7);
|
|
|
|
|
// Set flags
|
|
|
|
|
cpu->Flags.CarryFlag = bit0 != 0;
|
|
|
|
|
cpu->Flags.ZeroFlag = cpu->Accumulator == 0;
|
|
|
|
|
cpu->Flags.NegativeFlag = (cpu->Accumulator & 0x80) != 0;
|
|
|
|
|
|
|
|
|
|
return 2;
|
|
|
|
|
}
|
|
|
|
|
case JMP_Ai: {
|
|
|
|
|
// Load pointer address
|
|
|
|
@@ -836,26 +892,32 @@ useconds_t runCycle(CPU *cpu, uint8_t *ram, uint8_t *rom) {
|
|
|
|
|
// Get value
|
|
|
|
|
uint8_t value = readMemory(COMBINE(high, low), ram, rom);
|
|
|
|
|
|
|
|
|
|
// BCD
|
|
|
|
|
if (cpu->Flags.DecimalMode == 1) {
|
|
|
|
|
break; // TODO: BCD
|
|
|
|
|
} else {
|
|
|
|
|
uint16_t result = cpu->Accumulator + value + cpu->Flags.CarryFlag;
|
|
|
|
|
cpu->Flags.CarryFlag = result > 0xFF;
|
|
|
|
|
cpu->Flags.ZeroFlag = result == 0;
|
|
|
|
|
cpu->Flags.OverflowFlag = ((cpu->Accumulator ^ result) & (value ^ result) & 0x80) != 0;
|
|
|
|
|
cpu->Flags.NegativeFlag = (result & 0x80) != 0;
|
|
|
|
|
cpu->Accumulator = (uint8_t)result;
|
|
|
|
|
}
|
|
|
|
|
doADC(cpu, value);
|
|
|
|
|
|
|
|
|
|
return 4;
|
|
|
|
|
}
|
|
|
|
|
case ROR_A: {
|
|
|
|
|
break;
|
|
|
|
|
// Get address
|
|
|
|
|
uint8_t low = readMemory(cpu->ProgrammeCounter++, ram, rom);
|
|
|
|
|
uint8_t high = readMemory(cpu->ProgrammeCounter++, ram, rom);
|
|
|
|
|
// Get value
|
|
|
|
|
uint8_t value = readMemory(COMBINE(high, low), ram, rom);
|
|
|
|
|
// Save bit 7, rotate, set bit 0
|
|
|
|
|
uint8_t bit0 = value & 0x1;
|
|
|
|
|
value = value >> 1;
|
|
|
|
|
value |= (cpu->Flags.CarryFlag << 7);
|
|
|
|
|
// Set flags
|
|
|
|
|
cpu->Flags.CarryFlag = bit0 != 0;
|
|
|
|
|
cpu->Flags.ZeroFlag = value == 0;
|
|
|
|
|
cpu->Flags.NegativeFlag = (value & 0x80) != 0;
|
|
|
|
|
// Write value
|
|
|
|
|
writeMemory(COMBINE(high, low), value, ram, rom);
|
|
|
|
|
|
|
|
|
|
return 6;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
case BVS: {
|
|
|
|
|
useconds_t cycles = 2;
|
|
|
|
|
uint8_t cycles = 2;
|
|
|
|
|
|
|
|
|
|
// Get offset
|
|
|
|
|
int8_t offset = (int8_t)readMemory(cpu->ProgrammeCounter++, ram, rom);
|
|
|
|
@@ -882,17 +944,8 @@ useconds_t runCycle(CPU *cpu, uint8_t *ram, uint8_t *rom) {
|
|
|
|
|
uint16_t address = cpu->Y + COMBINE(high, low);
|
|
|
|
|
// Get value
|
|
|
|
|
uint8_t value = readMemory(address, ram, rom);
|
|
|
|
|
// BCD
|
|
|
|
|
if (cpu->Flags.DecimalMode == 1) {
|
|
|
|
|
break; // TODO: BCD
|
|
|
|
|
} else {
|
|
|
|
|
uint16_t result = cpu->Accumulator + value + cpu->Flags.CarryFlag;
|
|
|
|
|
cpu->Flags.CarryFlag = result > 0xFF;
|
|
|
|
|
cpu->Flags.ZeroFlag = result == 0;
|
|
|
|
|
cpu->Flags.OverflowFlag = ((cpu->Accumulator ^ result) & (value ^ result) & 0x80) != 0;
|
|
|
|
|
cpu->Flags.NegativeFlag = (result & 0x80) != 0;
|
|
|
|
|
cpu->Accumulator = (uint8_t)result;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
doADC(cpu, value);
|
|
|
|
|
|
|
|
|
|
return 5 + (((uint16_t)low + cpu->Y) > 0xFF);
|
|
|
|
|
}
|
|
|
|
@@ -901,22 +954,28 @@ useconds_t runCycle(CPU *cpu, uint8_t *ram, uint8_t *rom) {
|
|
|
|
|
uint8_t offset = readMemory(cpu->ProgrammeCounter++, ram, rom);
|
|
|
|
|
// Get value
|
|
|
|
|
uint8_t value = readMemory((uint8_t)(cpu->X + offset), ram, rom);
|
|
|
|
|
// BCD
|
|
|
|
|
if (cpu->Flags.DecimalMode == 1) {
|
|
|
|
|
break; // TODO: BCD
|
|
|
|
|
} else {
|
|
|
|
|
uint16_t result = cpu->Accumulator + value + cpu->Flags.CarryFlag;
|
|
|
|
|
cpu->Flags.CarryFlag = result > 0xFF;
|
|
|
|
|
cpu->Flags.ZeroFlag = result == 0;
|
|
|
|
|
cpu->Flags.OverflowFlag = ((cpu->Accumulator ^ result) & (value ^ result) & 0x80) != 0;
|
|
|
|
|
cpu->Flags.NegativeFlag = (result & 0x80) != 0;
|
|
|
|
|
cpu->Accumulator = (uint8_t)result;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
doADC(cpu, value);
|
|
|
|
|
|
|
|
|
|
return 4;
|
|
|
|
|
}
|
|
|
|
|
case ROR_XZ: {
|
|
|
|
|
break;
|
|
|
|
|
// Get offset
|
|
|
|
|
uint8_t offset = readMemory(cpu->ProgrammeCounter++, ram, rom);
|
|
|
|
|
// Get value
|
|
|
|
|
uint8_t value = readMemory((uint8_t)(cpu->X + offset), ram, rom);
|
|
|
|
|
// Save bit 0, rotate, set bit 0
|
|
|
|
|
uint8_t bit0 = value & 0x1;
|
|
|
|
|
value = value >> 1;
|
|
|
|
|
value |= (cpu->Flags.CarryFlag << 7);
|
|
|
|
|
// Set flags
|
|
|
|
|
cpu->Flags.CarryFlag = bit0 != 0;
|
|
|
|
|
cpu->Flags.ZeroFlag = value == 0;
|
|
|
|
|
cpu->Flags.NegativeFlag = (value & 0x80) != 0;
|
|
|
|
|
// Write value
|
|
|
|
|
writeMemory((uint8_t)(cpu->X + offset), value, ram, rom);
|
|
|
|
|
|
|
|
|
|
return 6;
|
|
|
|
|
}
|
|
|
|
|
case SEI: {
|
|
|
|
|
cpu->Flags.InterruptDisable = 1;
|
|
|
|
@@ -929,17 +988,8 @@ useconds_t runCycle(CPU *cpu, uint8_t *ram, uint8_t *rom) {
|
|
|
|
|
uint8_t high = readMemory(cpu->ProgrammeCounter++, ram, rom);
|
|
|
|
|
// Get value
|
|
|
|
|
uint8_t value = readMemory(cpu->Y + COMBINE(high, low), ram, rom);
|
|
|
|
|
// BCD
|
|
|
|
|
if (cpu->Flags.DecimalMode == 1) {
|
|
|
|
|
break; // TODO: BCD
|
|
|
|
|
} else {
|
|
|
|
|
uint16_t result = cpu->Accumulator + value + cpu->Flags.CarryFlag;
|
|
|
|
|
cpu->Flags.CarryFlag = result > 0xFF;
|
|
|
|
|
cpu->Flags.ZeroFlag = result == 0;
|
|
|
|
|
cpu->Flags.OverflowFlag = ((cpu->Accumulator ^ result) & (value ^ result) & 0x80) != 0;
|
|
|
|
|
cpu->Flags.NegativeFlag = (result & 0x80) != 0;
|
|
|
|
|
cpu->Accumulator = (uint8_t)result;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
doADC(cpu, value);
|
|
|
|
|
|
|
|
|
|
return 4 + (((uint16_t)low + cpu->Y) > 0xFF);
|
|
|
|
|
}
|
|
|
|
@@ -949,35 +999,67 @@ useconds_t runCycle(CPU *cpu, uint8_t *ram, uint8_t *rom) {
|
|
|
|
|
uint8_t high = readMemory(cpu->ProgrammeCounter++, ram, rom);
|
|
|
|
|
// Get value
|
|
|
|
|
uint8_t value = readMemory(cpu->X + COMBINE(high, low), ram, rom);
|
|
|
|
|
// BCD
|
|
|
|
|
if (cpu->Flags.DecimalMode == 1) {
|
|
|
|
|
break; // TODO: BCD
|
|
|
|
|
} else {
|
|
|
|
|
uint16_t result = cpu->Accumulator + value + cpu->Flags.CarryFlag;
|
|
|
|
|
cpu->Flags.CarryFlag = result > 0xFF;
|
|
|
|
|
cpu->Flags.ZeroFlag = result == 0;
|
|
|
|
|
cpu->Flags.OverflowFlag = ((cpu->Accumulator ^ result) & (value ^ result) & 0x80) != 0;
|
|
|
|
|
cpu->Flags.NegativeFlag = (result & 0x80) != 0;
|
|
|
|
|
cpu->Accumulator = (uint8_t)result;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
doADC(cpu, value);
|
|
|
|
|
|
|
|
|
|
return 4 + (((uint16_t)low + cpu->X) > 0xFF);
|
|
|
|
|
}
|
|
|
|
|
case ROR_XA: {
|
|
|
|
|
break;
|
|
|
|
|
// Get address
|
|
|
|
|
uint8_t low = readMemory(cpu->ProgrammeCounter++, ram, rom);
|
|
|
|
|
uint8_t high = readMemory(cpu->ProgrammeCounter++, ram, rom);
|
|
|
|
|
// Get value
|
|
|
|
|
uint8_t value = readMemory(cpu->X + COMBINE(high, low), ram, rom);
|
|
|
|
|
// Save bit 0, rotate, set bit 0
|
|
|
|
|
uint8_t bit0 = value & 0x1;
|
|
|
|
|
value = value >> 1;
|
|
|
|
|
value |= (cpu->Flags.CarryFlag << 7);
|
|
|
|
|
// Set flags
|
|
|
|
|
cpu->Flags.CarryFlag = bit0 != 0;
|
|
|
|
|
cpu->Flags.ZeroFlag = value == 0;
|
|
|
|
|
cpu->Flags.NegativeFlag = (value & 0x80) != 0;
|
|
|
|
|
// Write value
|
|
|
|
|
writeMemory(cpu->X + COMBINE(high, low), value, ram, rom);
|
|
|
|
|
|
|
|
|
|
return 7;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
case STA_XZi: {
|
|
|
|
|
break;
|
|
|
|
|
// Get offset
|
|
|
|
|
uint8_t offset = readMemory(cpu->ProgrammeCounter++, ram, rom);
|
|
|
|
|
// Get indirect address, discard carry
|
|
|
|
|
uint8_t _address = (uint8_t)(cpu->X + offset);
|
|
|
|
|
// Get final address, wrap around page
|
|
|
|
|
uint8_t low = readMemory(_address, ram, rom);
|
|
|
|
|
uint8_t high = readMemory((uint8_t)(_address + 1), ram, rom);
|
|
|
|
|
// Store accumulator at address
|
|
|
|
|
writeMemory(COMBINE(high, low), cpu->Accumulator, ram, rom);
|
|
|
|
|
|
|
|
|
|
return 6;
|
|
|
|
|
}
|
|
|
|
|
case STY_Z: {
|
|
|
|
|
break;
|
|
|
|
|
// Get offset
|
|
|
|
|
uint8_t offset = readMemory(cpu->ProgrammeCounter++, ram, rom);
|
|
|
|
|
// Store Y at address
|
|
|
|
|
writeMemory(offset, cpu->Y, ram, rom);
|
|
|
|
|
|
|
|
|
|
return 3;
|
|
|
|
|
}
|
|
|
|
|
case STA_Z: {
|
|
|
|
|
break;
|
|
|
|
|
// Get offset
|
|
|
|
|
uint8_t offset = readMemory(cpu->ProgrammeCounter++, ram, rom);
|
|
|
|
|
// Store accumulator at address
|
|
|
|
|
writeMemory(offset, cpu->Accumulator, ram, rom);
|
|
|
|
|
|
|
|
|
|
return 3;
|
|
|
|
|
}
|
|
|
|
|
case STX_Z: {
|
|
|
|
|
break;
|
|
|
|
|
// Get offset
|
|
|
|
|
uint8_t offset = readMemory(cpu->ProgrammeCounter++, ram, rom);
|
|
|
|
|
// Store X at address
|
|
|
|
|
writeMemory(offset, cpu->X, ram, rom);
|
|
|
|
|
|
|
|
|
|
return 3;
|
|
|
|
|
}
|
|
|
|
|
case DEY: {
|
|
|
|
|
// Decrement, set flags
|
|
|
|
@@ -996,7 +1078,13 @@ useconds_t runCycle(CPU *cpu, uint8_t *ram, uint8_t *rom) {
|
|
|
|
|
return 2;
|
|
|
|
|
}
|
|
|
|
|
case STY_A: {
|
|
|
|
|
break;
|
|
|
|
|
// Load address
|
|
|
|
|
uint8_t low = readMemory(cpu->ProgrammeCounter++, ram, rom);
|
|
|
|
|
uint8_t high = readMemory(cpu->ProgrammeCounter++, ram, rom);
|
|
|
|
|
// Store Y at address
|
|
|
|
|
writeMemory(COMBINE(high, low), cpu->Y, ram, rom);
|
|
|
|
|
|
|
|
|
|
return 4;
|
|
|
|
|
}
|
|
|
|
|
case STA_A: {
|
|
|
|
|
// Load address
|
|
|
|
@@ -1008,11 +1096,17 @@ useconds_t runCycle(CPU *cpu, uint8_t *ram, uint8_t *rom) {
|
|
|
|
|
return 4;
|
|
|
|
|
}
|
|
|
|
|
case STX_A: {
|
|
|
|
|
break;
|
|
|
|
|
// Load address
|
|
|
|
|
uint8_t low = readMemory(cpu->ProgrammeCounter++, ram, rom);
|
|
|
|
|
uint8_t high = readMemory(cpu->ProgrammeCounter++, ram, rom);
|
|
|
|
|
// Store X at address
|
|
|
|
|
writeMemory(COMBINE(high, low), cpu->X, ram, rom);
|
|
|
|
|
|
|
|
|
|
return 4;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
case BCC: {
|
|
|
|
|
useconds_t cycles = 2;
|
|
|
|
|
uint8_t cycles = 2;
|
|
|
|
|
|
|
|
|
|
// Get offset
|
|
|
|
|
int8_t offset = (int8_t)readMemory(cpu->ProgrammeCounter++, ram, rom);
|
|
|
|
@@ -1030,16 +1124,41 @@ useconds_t runCycle(CPU *cpu, uint8_t *ram, uint8_t *rom) {
|
|
|
|
|
return cycles;
|
|
|
|
|
}
|
|
|
|
|
case STA_ZiY: {
|
|
|
|
|
break;
|
|
|
|
|
// Get _address
|
|
|
|
|
uint8_t _address = readMemory(cpu->ProgrammeCounter++, ram, rom);
|
|
|
|
|
// Get offset
|
|
|
|
|
uint8_t low = readMemory(_address, ram, rom);
|
|
|
|
|
uint8_t high = readMemory((uint8_t)(_address + 1), ram, rom);
|
|
|
|
|
// Get address
|
|
|
|
|
uint16_t address = cpu->Y + COMBINE(high, low);
|
|
|
|
|
// Store accumulator at address
|
|
|
|
|
writeMemory(address, cpu->Accumulator, ram, rom);
|
|
|
|
|
|
|
|
|
|
return 6;
|
|
|
|
|
}
|
|
|
|
|
case STY_XZ: {
|
|
|
|
|
break;
|
|
|
|
|
// Get offset
|
|
|
|
|
uint8_t offset = readMemory(cpu->ProgrammeCounter++, ram, rom);
|
|
|
|
|
// Store accumulator at address
|
|
|
|
|
writeMemory((uint8_t)(cpu->X + offset), cpu->Y, ram, rom);
|
|
|
|
|
|
|
|
|
|
return 4;
|
|
|
|
|
}
|
|
|
|
|
case STA_XZ: {
|
|
|
|
|
break;
|
|
|
|
|
// Get offset
|
|
|
|
|
uint8_t offset = readMemory(cpu->ProgrammeCounter++, ram, rom);
|
|
|
|
|
// Store accumulator at address
|
|
|
|
|
writeMemory((uint8_t)(cpu->X + offset), cpu->Accumulator, ram, rom);
|
|
|
|
|
|
|
|
|
|
return 4;
|
|
|
|
|
}
|
|
|
|
|
case STX_YZ: {
|
|
|
|
|
break;
|
|
|
|
|
// Get offset
|
|
|
|
|
uint8_t offset = readMemory(cpu->ProgrammeCounter++, ram, rom);
|
|
|
|
|
// Store accumulator at address
|
|
|
|
|
writeMemory((uint8_t)(cpu->Y + offset), cpu->X, ram, rom);
|
|
|
|
|
|
|
|
|
|
return 4;
|
|
|
|
|
}
|
|
|
|
|
case TYA: {
|
|
|
|
|
cpu->Accumulator = cpu->Y;
|
|
|
|
@@ -1050,7 +1169,13 @@ useconds_t runCycle(CPU *cpu, uint8_t *ram, uint8_t *rom) {
|
|
|
|
|
return 2;
|
|
|
|
|
}
|
|
|
|
|
case STA_YA: {
|
|
|
|
|
break;
|
|
|
|
|
// Get address
|
|
|
|
|
uint8_t low = readMemory(cpu->ProgrammeCounter++, ram, rom);
|
|
|
|
|
uint8_t high = readMemory(cpu->ProgrammeCounter++, ram, rom);
|
|
|
|
|
// Store accumulator at address
|
|
|
|
|
writeMemory(cpu->Y + COMBINE(high, low), cpu->Accumulator, ram, rom);
|
|
|
|
|
|
|
|
|
|
return 5;
|
|
|
|
|
}
|
|
|
|
|
case TXS: {
|
|
|
|
|
cpu->StackPointer = cpu->X;
|
|
|
|
@@ -1058,7 +1183,13 @@ useconds_t runCycle(CPU *cpu, uint8_t *ram, uint8_t *rom) {
|
|
|
|
|
return 2;
|
|
|
|
|
}
|
|
|
|
|
case STA_XA: {
|
|
|
|
|
break;
|
|
|
|
|
// Get address
|
|
|
|
|
uint8_t low = readMemory(cpu->ProgrammeCounter++, ram, rom);
|
|
|
|
|
uint8_t high = readMemory(cpu->ProgrammeCounter++, ram, rom);
|
|
|
|
|
// Store accumulator at address
|
|
|
|
|
writeMemory(cpu->X + COMBINE(high, low), cpu->Accumulator, ram, rom);
|
|
|
|
|
|
|
|
|
|
return 5;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
case LDY_I: {
|
|
|
|
@@ -1201,7 +1332,7 @@ useconds_t runCycle(CPU *cpu, uint8_t *ram, uint8_t *rom) {
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
case BCS: {
|
|
|
|
|
useconds_t cycles = 2;
|
|
|
|
|
uint8_t cycles = 2;
|
|
|
|
|
|
|
|
|
|
// Get offset
|
|
|
|
|
int8_t offset = (int8_t)readMemory(cpu->ProgrammeCounter++, ram, rom);
|
|
|
|
@@ -1393,7 +1524,18 @@ useconds_t runCycle(CPU *cpu, uint8_t *ram, uint8_t *rom) {
|
|
|
|
|
return 3;
|
|
|
|
|
}
|
|
|
|
|
case DEC_Z: {
|
|
|
|
|
break;
|
|
|
|
|
// Get offset
|
|
|
|
|
uint8_t offset = readMemory(cpu->ProgrammeCounter++, ram, rom);
|
|
|
|
|
// Get value
|
|
|
|
|
uint8_t value = readMemory(offset, ram, rom);
|
|
|
|
|
// Decrement, set flags
|
|
|
|
|
value--;
|
|
|
|
|
cpu->Flags.ZeroFlag = value == 0;
|
|
|
|
|
cpu->Flags.NegativeFlag = (value & 0x80) != 0;
|
|
|
|
|
// Store at address
|
|
|
|
|
writeMemory(offset, value, ram, rom);
|
|
|
|
|
|
|
|
|
|
return 5;
|
|
|
|
|
}
|
|
|
|
|
case INY: {
|
|
|
|
|
// Increment, set flags
|
|
|
|
@@ -1454,11 +1596,23 @@ useconds_t runCycle(CPU *cpu, uint8_t *ram, uint8_t *rom) {
|
|
|
|
|
return 4;
|
|
|
|
|
}
|
|
|
|
|
case DEC_A: {
|
|
|
|
|
break;
|
|
|
|
|
// Load address
|
|
|
|
|
uint8_t low = readMemory(cpu->ProgrammeCounter++, ram, rom);
|
|
|
|
|
uint8_t high = readMemory(cpu->ProgrammeCounter++, ram, rom);
|
|
|
|
|
// Get value
|
|
|
|
|
uint8_t value = readMemory(COMBINE(high, low), ram, rom);
|
|
|
|
|
// Decrement, set flags
|
|
|
|
|
value--;
|
|
|
|
|
cpu->Flags.ZeroFlag = value == 0;
|
|
|
|
|
cpu->Flags.NegativeFlag = (value & 0x80) != 0;
|
|
|
|
|
// Store at address
|
|
|
|
|
writeMemory(COMBINE(high, low), value, ram, rom);
|
|
|
|
|
|
|
|
|
|
return 6;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
case BNE: {
|
|
|
|
|
useconds_t cycles = 2;
|
|
|
|
|
uint8_t cycles = 2;
|
|
|
|
|
|
|
|
|
|
// Get offset
|
|
|
|
|
int8_t offset = (int8_t)readMemory(cpu->ProgrammeCounter++, ram, rom);
|
|
|
|
@@ -1509,7 +1663,18 @@ useconds_t runCycle(CPU *cpu, uint8_t *ram, uint8_t *rom) {
|
|
|
|
|
return 4;
|
|
|
|
|
}
|
|
|
|
|
case DEC_XZ: {
|
|
|
|
|
break;
|
|
|
|
|
// Get offset
|
|
|
|
|
uint8_t offset = readMemory(cpu->ProgrammeCounter++, ram, rom);
|
|
|
|
|
// Get value
|
|
|
|
|
uint8_t value = readMemory((uint8_t)(cpu->X + offset), ram, rom);
|
|
|
|
|
// Decrement, set flags
|
|
|
|
|
value--;
|
|
|
|
|
cpu->Flags.ZeroFlag = value == 0;
|
|
|
|
|
cpu->Flags.NegativeFlag = (value & 0x80) != 0;
|
|
|
|
|
// Store at address
|
|
|
|
|
writeMemory((uint8_t)(cpu->X + offset), value, ram, rom);
|
|
|
|
|
|
|
|
|
|
return 6;
|
|
|
|
|
}
|
|
|
|
|
case CLD: {
|
|
|
|
|
cpu->Flags.DecimalMode = 0;
|
|
|
|
@@ -1547,7 +1712,19 @@ useconds_t runCycle(CPU *cpu, uint8_t *ram, uint8_t *rom) {
|
|
|
|
|
return 4 + (((uint16_t)low + cpu->X) > 0xFF);
|
|
|
|
|
}
|
|
|
|
|
case DEC_XA: {
|
|
|
|
|
break;
|
|
|
|
|
// Get address
|
|
|
|
|
uint8_t low = readMemory(cpu->ProgrammeCounter++, ram, rom);
|
|
|
|
|
uint8_t high = readMemory(cpu->ProgrammeCounter++, ram, rom);
|
|
|
|
|
// Get value
|
|
|
|
|
uint8_t value = readMemory(cpu->X + COMBINE(high, low), ram, rom);
|
|
|
|
|
// Decrement, set flags
|
|
|
|
|
value--;
|
|
|
|
|
cpu->Flags.ZeroFlag = value == 0;
|
|
|
|
|
cpu->Flags.NegativeFlag = (value & 0x80) != 0;
|
|
|
|
|
// Store at address
|
|
|
|
|
writeMemory(cpu->X + COMBINE(high, low), value, ram, rom);
|
|
|
|
|
|
|
|
|
|
return 7;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
case CPX_I: {
|
|
|
|
@@ -1563,7 +1740,19 @@ useconds_t runCycle(CPU *cpu, uint8_t *ram, uint8_t *rom) {
|
|
|
|
|
return 2;
|
|
|
|
|
}
|
|
|
|
|
case SBC_XZi: {
|
|
|
|
|
break;
|
|
|
|
|
// Get offset
|
|
|
|
|
uint8_t offset = readMemory(cpu->ProgrammeCounter++, ram, rom);
|
|
|
|
|
// Get indirect address, discard carry
|
|
|
|
|
uint8_t _address = (uint8_t)(cpu->X + offset);
|
|
|
|
|
// Get final address, wrap around page
|
|
|
|
|
uint8_t low = readMemory(_address, ram, rom);
|
|
|
|
|
uint8_t high = readMemory((uint8_t)(_address + 1), ram, rom);
|
|
|
|
|
// Get value
|
|
|
|
|
uint8_t value = readMemory(COMBINE(high, low), ram, rom);
|
|
|
|
|
|
|
|
|
|
doSBC(cpu, value);
|
|
|
|
|
|
|
|
|
|
return 6;
|
|
|
|
|
}
|
|
|
|
|
case CPX_Z: {
|
|
|
|
|
// Get offset
|
|
|
|
@@ -1580,10 +1769,28 @@ useconds_t runCycle(CPU *cpu, uint8_t *ram, uint8_t *rom) {
|
|
|
|
|
return 3;
|
|
|
|
|
}
|
|
|
|
|
case SBC_Z: {
|
|
|
|
|
break;
|
|
|
|
|
// Get offset
|
|
|
|
|
uint8_t offset = readMemory(cpu->ProgrammeCounter++, ram, rom);
|
|
|
|
|
// Get value
|
|
|
|
|
uint8_t value = readMemory(offset, ram, rom);
|
|
|
|
|
|
|
|
|
|
doSBC(cpu, value);
|
|
|
|
|
|
|
|
|
|
return 3;
|
|
|
|
|
}
|
|
|
|
|
case INC_Z: {
|
|
|
|
|
break;
|
|
|
|
|
// Get offset
|
|
|
|
|
uint8_t offset = readMemory(cpu->ProgrammeCounter++, ram, rom);
|
|
|
|
|
// Get value
|
|
|
|
|
uint8_t value = readMemory(offset, ram, rom);
|
|
|
|
|
// Increment, set flags
|
|
|
|
|
value++;
|
|
|
|
|
cpu->Flags.ZeroFlag = value == 0;
|
|
|
|
|
cpu->Flags.NegativeFlag = (value & 0x80) != 0;
|
|
|
|
|
// Store at address
|
|
|
|
|
writeMemory(offset, value, ram, rom);
|
|
|
|
|
|
|
|
|
|
return 5;
|
|
|
|
|
}
|
|
|
|
|
case INX: {
|
|
|
|
|
// Increment, set flags
|
|
|
|
@@ -1594,7 +1801,12 @@ useconds_t runCycle(CPU *cpu, uint8_t *ram, uint8_t *rom) {
|
|
|
|
|
return 2;
|
|
|
|
|
}
|
|
|
|
|
case SBC_I: {
|
|
|
|
|
break;
|
|
|
|
|
// Get value
|
|
|
|
|
uint8_t value = readMemory(cpu->ProgrammeCounter++, ram, rom);
|
|
|
|
|
|
|
|
|
|
doSBC(cpu, value);
|
|
|
|
|
|
|
|
|
|
return 2;
|
|
|
|
|
}
|
|
|
|
|
case NOP: {
|
|
|
|
|
return 2;
|
|
|
|
@@ -1615,14 +1827,34 @@ useconds_t runCycle(CPU *cpu, uint8_t *ram, uint8_t *rom) {
|
|
|
|
|
return 4;
|
|
|
|
|
}
|
|
|
|
|
case SBC_A: {
|
|
|
|
|
break;
|
|
|
|
|
// Load address
|
|
|
|
|
uint8_t low = readMemory(cpu->ProgrammeCounter++, ram, rom);
|
|
|
|
|
uint8_t high = readMemory(cpu->ProgrammeCounter++, ram, rom);
|
|
|
|
|
// Get value
|
|
|
|
|
uint8_t value = readMemory(COMBINE(high, low), ram, rom);
|
|
|
|
|
|
|
|
|
|
doSBC(cpu, value);
|
|
|
|
|
|
|
|
|
|
return 4;
|
|
|
|
|
}
|
|
|
|
|
case INC_A: {
|
|
|
|
|
break;
|
|
|
|
|
// Load address
|
|
|
|
|
uint8_t low = readMemory(cpu->ProgrammeCounter++, ram, rom);
|
|
|
|
|
uint8_t high = readMemory(cpu->ProgrammeCounter++, ram, rom);
|
|
|
|
|
// Get value
|
|
|
|
|
uint8_t value = readMemory(COMBINE(high, low), ram, rom);
|
|
|
|
|
// Increment, set flags
|
|
|
|
|
value++;
|
|
|
|
|
cpu->Flags.ZeroFlag = value == 0;
|
|
|
|
|
cpu->Flags.NegativeFlag = (value & 0x80) != 0;
|
|
|
|
|
// Store at address
|
|
|
|
|
writeMemory(COMBINE(high, low), value, ram, rom);
|
|
|
|
|
|
|
|
|
|
return 6;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
case BEQ: {
|
|
|
|
|
useconds_t cycles = 2;
|
|
|
|
|
uint8_t cycles = 2;
|
|
|
|
|
|
|
|
|
|
// Get offset
|
|
|
|
|
int8_t offset = (int8_t)readMemory(cpu->ProgrammeCounter++, ram, rom);
|
|
|
|
@@ -1640,13 +1872,43 @@ useconds_t runCycle(CPU *cpu, uint8_t *ram, uint8_t *rom) {
|
|
|
|
|
return cycles;
|
|
|
|
|
}
|
|
|
|
|
case SBC_ZiY: {
|
|
|
|
|
break;
|
|
|
|
|
// Get _address
|
|
|
|
|
uint8_t _address = readMemory(cpu->ProgrammeCounter++, ram, rom);
|
|
|
|
|
// Get offset
|
|
|
|
|
uint8_t low = readMemory(_address, ram, rom);
|
|
|
|
|
uint8_t high = readMemory((uint8_t)(_address + 1), ram, rom);
|
|
|
|
|
// Get address
|
|
|
|
|
uint16_t address = cpu->Y + COMBINE(high, low);
|
|
|
|
|
// Get value
|
|
|
|
|
uint8_t value = readMemory(address, ram, rom);
|
|
|
|
|
|
|
|
|
|
doSBC(cpu, value);
|
|
|
|
|
|
|
|
|
|
return 5 + (((uint16_t)low + cpu->Y) > 0xFF);
|
|
|
|
|
}
|
|
|
|
|
case SBC_XZ: {
|
|
|
|
|
break;
|
|
|
|
|
// Get offset
|
|
|
|
|
uint8_t offset = readMemory(cpu->ProgrammeCounter++, ram, rom);
|
|
|
|
|
// Get value
|
|
|
|
|
uint8_t value = readMemory((uint8_t)(cpu->X + offset), ram, rom);
|
|
|
|
|
|
|
|
|
|
doSBC(cpu, value);
|
|
|
|
|
|
|
|
|
|
return 4;
|
|
|
|
|
}
|
|
|
|
|
case INC_XZ: {
|
|
|
|
|
break;
|
|
|
|
|
// Get offset
|
|
|
|
|
uint8_t offset = readMemory(cpu->ProgrammeCounter++, ram, rom);
|
|
|
|
|
// Get value
|
|
|
|
|
uint8_t value = readMemory((uint8_t)(cpu->X + offset), ram, rom);
|
|
|
|
|
// Increment, set flags
|
|
|
|
|
value++;
|
|
|
|
|
cpu->Flags.ZeroFlag = value == 0;
|
|
|
|
|
cpu->Flags.NegativeFlag = (value & 0x80) != 0;
|
|
|
|
|
// Store at address
|
|
|
|
|
writeMemory((uint8_t)(cpu->X + offset), value, ram, rom);
|
|
|
|
|
|
|
|
|
|
return 6;
|
|
|
|
|
}
|
|
|
|
|
case SED: {
|
|
|
|
|
cpu->Flags.DecimalMode = 1;
|
|
|
|
@@ -1654,13 +1916,41 @@ useconds_t runCycle(CPU *cpu, uint8_t *ram, uint8_t *rom) {
|
|
|
|
|
return 2;
|
|
|
|
|
}
|
|
|
|
|
case SBC_YA: {
|
|
|
|
|
break;
|
|
|
|
|
// Get address
|
|
|
|
|
uint8_t low = readMemory(cpu->ProgrammeCounter++, ram, rom);
|
|
|
|
|
uint8_t high = readMemory(cpu->ProgrammeCounter++, ram, rom);
|
|
|
|
|
// Get value
|
|
|
|
|
uint8_t value = readMemory(cpu->Y + COMBINE(high, low), ram, rom);
|
|
|
|
|
|
|
|
|
|
doSBC(cpu, value);
|
|
|
|
|
|
|
|
|
|
return 4 + (((uint16_t)low + cpu->Y) > 0xFF);
|
|
|
|
|
}
|
|
|
|
|
case SBC_XA: {
|
|
|
|
|
break;
|
|
|
|
|
// Get address
|
|
|
|
|
uint8_t low = readMemory(cpu->ProgrammeCounter++, ram, rom);
|
|
|
|
|
uint8_t high = readMemory(cpu->ProgrammeCounter++, ram, rom);
|
|
|
|
|
// Get value
|
|
|
|
|
uint8_t value = readMemory(cpu->X + COMBINE(high, low), ram, rom);
|
|
|
|
|
|
|
|
|
|
doSBC(cpu, value);
|
|
|
|
|
|
|
|
|
|
return 4 + (((uint16_t)low + cpu->X) > 0xFF);
|
|
|
|
|
}
|
|
|
|
|
case INC_XA: {
|
|
|
|
|
break;
|
|
|
|
|
// Get address
|
|
|
|
|
uint8_t low = readMemory(cpu->ProgrammeCounter++, ram, rom);
|
|
|
|
|
uint8_t high = readMemory(cpu->ProgrammeCounter++, ram, rom);
|
|
|
|
|
// Get value
|
|
|
|
|
uint8_t value = readMemory(cpu->X + COMBINE(high, low), ram, rom);
|
|
|
|
|
// Increment, set flags
|
|
|
|
|
value++;
|
|
|
|
|
cpu->Flags.ZeroFlag = value == 0;
|
|
|
|
|
cpu->Flags.NegativeFlag = (value & 0x80) != 0;
|
|
|
|
|
// Store at address
|
|
|
|
|
writeMemory(cpu->X + COMBINE(high, low), value, ram, rom);
|
|
|
|
|
|
|
|
|
|
return 7;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
default:
|
|
|
|
|