diff --git a/6502_65C02_functional_tests/6502_decimal_test.a65 b/6502_65C02_functional_tests/6502_decimal_test.a65 index 7a76ad1..3a15610 100644 --- a/6502_65C02_functional_tests/6502_decimal_test.a65 +++ b/6502_65C02_functional_tests/6502_decimal_test.a65 @@ -118,6 +118,15 @@ NEXT2 inc N2 ; [6] see text lda #0 ; test passed, so store 0 in ERROR sta ERROR DONE + lda #1 + cmp ERROR + beq _E + lda #'P' + sta $dc00 + jmp _E2 +_E lda #'F' + sta $dc00 +_E2 end_of_test ; Calculate the actual decimal mode accumulator and flags, the accumulator diff --git a/6502_65C02_functional_tests/6502_functional_test.a65 b/6502_65C02_functional_tests/6502_functional_test.a65 index 0c7ce35..02533b2 100644 --- a/6502_65C02_functional_tests/6502_functional_test.a65 +++ b/6502_65C02_functional_tests/6502_functional_test.a65 @@ -128,7 +128,7 @@ ram_top = -1 ;disable test decimal mode ADC & SBC, 0=enable, 1=disable, ;2=disable including decimal flag in processor status -disable_decimal = 1 +disable_decimal = 0 noopt ;do not take shortcuts diff --git a/6502_65C02_functional_tests/report.i65 b/6502_65C02_functional_tests/report.i65 index cefc1c4..4e8d0e3 100644 --- a/6502_65C02_functional_tests/report.i65 +++ b/6502_65C02_functional_tests/report.i65 @@ -50,7 +50,6 @@ rstack jsr rspace inx bne rstack jsr rcrlf ;new line - jmp rend ; Skip BS ;show zero page workspace lda #0 jsr rhex @@ -64,6 +63,7 @@ rzp jsr rspace cpx #zp_bss bne rzp jsr rcrlf + jmp rend ; Skip Workspace since 65k is large ;show absolute workspace lda #hi(data_segment) jsr rhex diff --git a/inc/cpu.h b/inc/cpu.h index 06f877b..595019f 100644 --- a/inc/cpu.h +++ b/inc/cpu.h @@ -2,7 +2,6 @@ #define CPU_H #include -#include typedef struct { uint16_t ProgrammeCounter; @@ -29,6 +28,6 @@ typedef struct { void initCPU(CPU *cpu); void resetCPU(CPU *cpu, uint8_t *rom); -useconds_t runCycle(CPU *cpu, uint8_t *ram, uint8_t *rom); +uint8_t runCycle(CPU *cpu, uint8_t *ram, uint8_t *rom); #endif // CPU_H \ No newline at end of file diff --git a/inc/opcodes.h b/inc/opcodes.h index f159d40..5e08cf6 100644 --- a/inc/opcodes.h +++ b/inc/opcodes.h @@ -123,7 +123,7 @@ #define CLV 0xb8 // Clear overflow flag #define LDA_YA 0xb9 // Load A from memory, Y-indexed absolute #define TSX 0xba // Transfer stack pointer to X -#define LDY_XA 0xbb // Load Y from memory, X-indexed absolute +#define LDY_XA 0xbc // Load Y from memory, X-indexed absolute #define LDA_XA 0xbd // Load A from memory, X-indexed absolute #define LDX_YA 0xbe // Load X from memory, Y-indexed absolute /* 113 */ diff --git a/src/cpu.c b/src/cpu.c index 793b549..af10589 100644 --- a/src/cpu.c +++ b/src/cpu.c @@ -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: diff --git a/src/main.c b/src/main.c index 08ed31d..d707c17 100644 --- a/src/main.c +++ b/src/main.c @@ -6,9 +6,13 @@ #include #include #include +#include #include +#define MACHINE_SPEED_HZ 1e6 // 1 MHz; + static struct termios orig_termios; +static struct timespec sleepTime; void restore_terminal(void) { tcsetattr(STDIN_FILENO, TCSANOW, &orig_termios); } @@ -44,7 +48,8 @@ int main(void) { /* DEBUG */ - FILE *fp = fopen("/Users/Kili2/Documents/Projekte/6502pc/6502_65C02_functional_tests/6502_functional_test.bin", "rb"); + //FILE *fp = fopen("/Users/Kili2/Documents/Projekte/6502pc/6502_65C02_functional_tests/6502_functional_test.bin", "rb"); + FILE *fp = fopen("/Users/Kili2/Documents/Projekte/6502pc/6502_65C02_functional_tests/6502_decimal_test.bin", "rb"); if (!fp) { perror("fopen"); return 1; @@ -65,14 +70,15 @@ int main(void) { resetCPU(&cpu, rom); while (1) { - //printf("\tPC: 0x%x\tOP: 0x%x\n", cpu.ProgrammeCounter, ram[cpu.ProgrammeCounter]); - useconds_t sleep = runCycle(&cpu, ram, rom); + // printf("\tPC: 0x%x\tOP: 0x%x\n", cpu.ProgrammeCounter, ram[cpu.ProgrammeCounter]); + uint8_t sleep = runCycle(&cpu, ram, rom); if (sleep == 1) { printf("opcode missing: 0x%X\n", ram[cpu.ProgrammeCounter - 1]); return 1; } - fflush(stdout); - usleep(sleep); + sleepTime.tv_sec = 0; + sleepTime.tv_nsec = sleep * (1000 / MACHINE_SPEED_HZ); + nanosleep(&sleepTime, NULL); } /* CPU WORK */ diff --git a/src/rom.c b/src/rom.c index 91b6051..7457b1d 100644 --- a/src/rom.c +++ b/src/rom.c @@ -3,6 +3,8 @@ uint8_t rom[ROM_SIZE] = {0}; void initRom(uint8_t *rom) { + + rom[0] = 0xa9, // LDA rom[1] = 'H', // H literal rom[2] = 0x8d, // STA @@ -11,7 +13,7 @@ void initRom(uint8_t *rom) { rom[6] = /* Reset Vector */ rom[0xFFFC - ROM_BASE] = 0x00, // Lower byte base of ROM - rom[0xFFFD - ROM_BASE] = 0x04, // Upper byte of base of ROM + rom[0xFFFD - ROM_BASE] = 0x02, // Upper byte of base of ROM rom[0xFFFE - ROM_BASE] = 0x00, // Lower byte base of ROM rom[0xFFFF - ROM_BASE] = 0x00; // Upper byte of base of ROM } \ No newline at end of file