FInal opcodes

This commit is contained in:
2026-08-30 23:02:24 +02:00
parent 1f4390a42b
commit f5672ee9c3
8 changed files with 452 additions and 146 deletions
@@ -118,6 +118,15 @@ NEXT2 inc N2 ; [6] see text
lda #0 ; test passed, so store 0 in ERROR lda #0 ; test passed, so store 0 in ERROR
sta ERROR sta ERROR
DONE DONE
lda #1
cmp ERROR
beq _E
lda #'P'
sta $dc00
jmp _E2
_E lda #'F'
sta $dc00
_E2
end_of_test end_of_test
; Calculate the actual decimal mode accumulator and flags, the accumulator ; Calculate the actual decimal mode accumulator and flags, the accumulator
@@ -128,7 +128,7 @@ ram_top = -1
;disable test decimal mode ADC & SBC, 0=enable, 1=disable, ;disable test decimal mode ADC & SBC, 0=enable, 1=disable,
;2=disable including decimal flag in processor status ;2=disable including decimal flag in processor status
disable_decimal = 1 disable_decimal = 0
noopt ;do not take shortcuts noopt ;do not take shortcuts
+1 -1
View File
@@ -50,7 +50,6 @@ rstack jsr rspace
inx inx
bne rstack bne rstack
jsr rcrlf ;new line jsr rcrlf ;new line
jmp rend ; Skip BS
;show zero page workspace ;show zero page workspace
lda #0 lda #0
jsr rhex jsr rhex
@@ -64,6 +63,7 @@ rzp jsr rspace
cpx #zp_bss cpx #zp_bss
bne rzp bne rzp
jsr rcrlf jsr rcrlf
jmp rend ; Skip Workspace since 65k is large
;show absolute workspace ;show absolute workspace
lda #hi(data_segment) lda #hi(data_segment)
jsr rhex jsr rhex
+1 -2
View File
@@ -2,7 +2,6 @@
#define CPU_H #define CPU_H
#include <stdint.h> #include <stdint.h>
#include <unistd.h>
typedef struct { typedef struct {
uint16_t ProgrammeCounter; uint16_t ProgrammeCounter;
@@ -29,6 +28,6 @@ typedef struct {
void initCPU(CPU *cpu); void initCPU(CPU *cpu);
void resetCPU(CPU *cpu, uint8_t *rom); 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 #endif // CPU_H
+1 -1
View File
@@ -123,7 +123,7 @@
#define CLV 0xb8 // Clear overflow flag #define CLV 0xb8 // Clear overflow flag
#define LDA_YA 0xb9 // Load A from memory, Y-indexed absolute #define LDA_YA 0xb9 // Load A from memory, Y-indexed absolute
#define TSX 0xba // Transfer stack pointer to X #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 LDA_XA 0xbd // Load A from memory, X-indexed absolute
#define LDX_YA 0xbe // Load X from memory, Y-indexed absolute #define LDX_YA 0xbe // Load X from memory, Y-indexed absolute
/* 113 */ /* 113 */
+425 -135
View File
@@ -7,6 +7,55 @@
#define LO_BYTE(x) ((uint8_t)((x) & 0xFF)) #define LO_BYTE(x) ((uint8_t)((x) & 0xFF))
#define HI_BYTE(x) ((uint8_t)(((x) >> 8) & 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) { void initCPU(CPU *cpu) {
#pragma clang diagnostic push #pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wmissing-field-initializers" #pragma clang diagnostic ignored "-Wmissing-field-initializers"
@@ -20,7 +69,7 @@ void resetCPU(CPU *cpu, uint8_t *rom) {
cpu->ProgrammeCounter = COMBINE(high, low); 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 // Fetch opcode
uint8_t opcode = readMemory(cpu->ProgrammeCounter++, ram, rom); 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: { case BPL: {
useconds_t cycles = 2; uint8_t cycles = 2;
// Get offset // Get offset
int8_t offset = (int8_t)readMemory(cpu->ProgrammeCounter++, ram, rom); 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: { case BMI: {
useconds_t cycles = 2; uint8_t cycles = 2;
// Get offset // Get offset
int8_t offset = (int8_t)readMemory(cpu->ProgrammeCounter++, ram, rom); 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 // Perform shift
cpu->Flags.CarryFlag = (value & 0x01) != 0; cpu->Flags.CarryFlag = (value & 0x01) != 0;
value = (uint8_t)(value >> 1); value = (uint8_t)(value >> 1);
// Set flags, write to memory // Set flags and write to memory
cpu->Flags.ZeroFlag = value == 0; cpu->Flags.ZeroFlag = value == 0;
cpu->Flags.NegativeFlag = 0; cpu->Flags.NegativeFlag = 0;
writeMemory(offset, value, ram, rom); writeMemory(offset, value, ram, rom);
@@ -604,7 +653,17 @@ useconds_t runCycle(CPU *cpu, uint8_t *ram, uint8_t *rom) {
return 3; return 3;
} }
case EOR_A: { 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: { case LSR_A: {
// Load address // Load address
@@ -615,7 +674,7 @@ useconds_t runCycle(CPU *cpu, uint8_t *ram, uint8_t *rom) {
// Perform shift // Perform shift
cpu->Flags.CarryFlag = (value & 0x01) != 0; cpu->Flags.CarryFlag = (value & 0x01) != 0;
value = (uint8_t)(value >> 1); value = (uint8_t)(value >> 1);
// Set flags, write to memory // Set flags and write to memory
cpu->Flags.ZeroFlag = value == 0; cpu->Flags.ZeroFlag = value == 0;
cpu->Flags.NegativeFlag = 0; cpu->Flags.NegativeFlag = 0;
writeMemory(COMBINE(high, low), value, ram, rom); writeMemory(COMBINE(high, low), value, ram, rom);
@@ -624,7 +683,7 @@ useconds_t runCycle(CPU *cpu, uint8_t *ram, uint8_t *rom) {
} }
case BVC: { case BVC: {
useconds_t cycles = 2; uint8_t cycles = 2;
// Get offset // Get offset
int8_t offset = (int8_t)readMemory(cpu->ProgrammeCounter++, ram, rom); 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 // Perform shift
cpu->Flags.CarryFlag = (value & 0x01) != 0; cpu->Flags.CarryFlag = (value & 0x01) != 0;
value = (uint8_t)(value >> 1); value = (uint8_t)(value >> 1);
// Set flags, write to memory // Set flags and write to memory
cpu->Flags.ZeroFlag = value == 0; cpu->Flags.ZeroFlag = value == 0;
cpu->Flags.NegativeFlag = 0; cpu->Flags.NegativeFlag = 0;
writeMemory((uint8_t)(cpu->X + offset), value, ram, rom); 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 // Perform shift
cpu->Flags.CarryFlag = (value & 0x01) != 0; cpu->Flags.CarryFlag = (value & 0x01) != 0;
value = (uint8_t)(value >> 1); value = (uint8_t)(value >> 1);
// Set flags, write to memory // Set flags and write to memory
cpu->Flags.ZeroFlag = value == 0; cpu->Flags.ZeroFlag = value == 0;
cpu->Flags.NegativeFlag = 0; cpu->Flags.NegativeFlag = 0;
writeMemory(cpu->X + COMBINE(high, low), value, ram, rom); 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); uint8_t high = readMemory((uint8_t)(_address + 1), ram, rom);
// Get value // Get value
uint8_t value = readMemory(COMBINE(high, low), ram, rom); uint8_t value = readMemory(COMBINE(high, low), ram, rom);
// BCD
if (cpu->Flags.DecimalMode == 1) { doADC(cpu, value);
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;
}
return 6; 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); uint8_t offset = readMemory(cpu->ProgrammeCounter++, ram, rom);
// Get value // Get value
uint8_t value = readMemory(offset, ram, rom); uint8_t value = readMemory(offset, ram, rom);
// BCD
if (cpu->Flags.DecimalMode == 1) { doADC(cpu, value);
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;
}
return 3; return 3;
} }
case ROR_Z: { 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: { case PLA: {
// Pull from stack // Pull from stack
@@ -799,22 +855,22 @@ useconds_t runCycle(CPU *cpu, uint8_t *ram, uint8_t *rom) {
case ADC_I: { case ADC_I: {
// Get value // Get value
uint8_t value = readMemory(cpu->ProgrammeCounter++, ram, rom); uint8_t value = readMemory(cpu->ProgrammeCounter++, ram, rom);
// BCD
if (cpu->Flags.DecimalMode == 1) { doADC(cpu, value);
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;
}
return 2; return 2;
} }
case ROR: { 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: { case JMP_Ai: {
// Load pointer address // Load pointer address
@@ -836,26 +892,32 @@ useconds_t runCycle(CPU *cpu, uint8_t *ram, uint8_t *rom) {
// Get value // Get value
uint8_t value = readMemory(COMBINE(high, low), ram, rom); uint8_t value = readMemory(COMBINE(high, low), ram, rom);
// BCD doADC(cpu, value);
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;
}
return 4; return 4;
} }
case ROR_A: { 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: { case BVS: {
useconds_t cycles = 2; uint8_t cycles = 2;
// Get offset // Get offset
int8_t offset = (int8_t)readMemory(cpu->ProgrammeCounter++, ram, rom); 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); uint16_t address = cpu->Y + COMBINE(high, low);
// Get value // Get value
uint8_t value = readMemory(address, ram, rom); uint8_t value = readMemory(address, ram, rom);
// BCD
if (cpu->Flags.DecimalMode == 1) { doADC(cpu, value);
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;
}
return 5 + (((uint16_t)low + cpu->Y) > 0xFF); 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); uint8_t offset = readMemory(cpu->ProgrammeCounter++, ram, rom);
// Get value // Get value
uint8_t value = readMemory((uint8_t)(cpu->X + offset), ram, rom); uint8_t value = readMemory((uint8_t)(cpu->X + offset), ram, rom);
// BCD
if (cpu->Flags.DecimalMode == 1) { doADC(cpu, value);
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;
}
return 4; return 4;
} }
case ROR_XZ: { 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: { case SEI: {
cpu->Flags.InterruptDisable = 1; 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); uint8_t high = readMemory(cpu->ProgrammeCounter++, ram, rom);
// Get value // Get value
uint8_t value = readMemory(cpu->Y + COMBINE(high, low), ram, rom); uint8_t value = readMemory(cpu->Y + COMBINE(high, low), ram, rom);
// BCD
if (cpu->Flags.DecimalMode == 1) { doADC(cpu, value);
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;
}
return 4 + (((uint16_t)low + cpu->Y) > 0xFF); 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); uint8_t high = readMemory(cpu->ProgrammeCounter++, ram, rom);
// Get value // Get value
uint8_t value = readMemory(cpu->X + COMBINE(high, low), ram, rom); uint8_t value = readMemory(cpu->X + COMBINE(high, low), ram, rom);
// BCD
if (cpu->Flags.DecimalMode == 1) { doADC(cpu, value);
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;
}
return 4 + (((uint16_t)low + cpu->X) > 0xFF); return 4 + (((uint16_t)low + cpu->X) > 0xFF);
} }
case ROR_XA: { 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: { 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: { 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: { 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: { 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: { case DEY: {
// Decrement, set flags // Decrement, set flags
@@ -996,7 +1078,13 @@ useconds_t runCycle(CPU *cpu, uint8_t *ram, uint8_t *rom) {
return 2; return 2;
} }
case STY_A: { 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: { case STA_A: {
// Load address // Load address
@@ -1008,11 +1096,17 @@ useconds_t runCycle(CPU *cpu, uint8_t *ram, uint8_t *rom) {
return 4; return 4;
} }
case STX_A: { 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: { case BCC: {
useconds_t cycles = 2; uint8_t cycles = 2;
// Get offset // Get offset
int8_t offset = (int8_t)readMemory(cpu->ProgrammeCounter++, ram, rom); 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; return cycles;
} }
case STA_ZiY: { 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: { 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: { 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: { 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: { case TYA: {
cpu->Accumulator = cpu->Y; cpu->Accumulator = cpu->Y;
@@ -1050,7 +1169,13 @@ useconds_t runCycle(CPU *cpu, uint8_t *ram, uint8_t *rom) {
return 2; return 2;
} }
case STA_YA: { 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: { case TXS: {
cpu->StackPointer = cpu->X; cpu->StackPointer = cpu->X;
@@ -1058,7 +1183,13 @@ useconds_t runCycle(CPU *cpu, uint8_t *ram, uint8_t *rom) {
return 2; return 2;
} }
case STA_XA: { 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: { case LDY_I: {
@@ -1201,7 +1332,7 @@ useconds_t runCycle(CPU *cpu, uint8_t *ram, uint8_t *rom) {
} }
case BCS: { case BCS: {
useconds_t cycles = 2; uint8_t cycles = 2;
// Get offset // Get offset
int8_t offset = (int8_t)readMemory(cpu->ProgrammeCounter++, ram, rom); 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; return 3;
} }
case DEC_Z: { 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: { case INY: {
// Increment, set flags // Increment, set flags
@@ -1454,11 +1596,23 @@ useconds_t runCycle(CPU *cpu, uint8_t *ram, uint8_t *rom) {
return 4; return 4;
} }
case DEC_A: { 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: { case BNE: {
useconds_t cycles = 2; uint8_t cycles = 2;
// Get offset // Get offset
int8_t offset = (int8_t)readMemory(cpu->ProgrammeCounter++, ram, rom); 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; return 4;
} }
case DEC_XZ: { 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: { case CLD: {
cpu->Flags.DecimalMode = 0; 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); return 4 + (((uint16_t)low + cpu->X) > 0xFF);
} }
case DEC_XA: { 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: { case CPX_I: {
@@ -1563,7 +1740,19 @@ useconds_t runCycle(CPU *cpu, uint8_t *ram, uint8_t *rom) {
return 2; return 2;
} }
case SBC_XZi: { 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: { case CPX_Z: {
// Get offset // Get offset
@@ -1580,10 +1769,28 @@ useconds_t runCycle(CPU *cpu, uint8_t *ram, uint8_t *rom) {
return 3; return 3;
} }
case SBC_Z: { 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: { 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: { case INX: {
// Increment, set flags // Increment, set flags
@@ -1594,7 +1801,12 @@ useconds_t runCycle(CPU *cpu, uint8_t *ram, uint8_t *rom) {
return 2; return 2;
} }
case SBC_I: { case SBC_I: {
break; // Get value
uint8_t value = readMemory(cpu->ProgrammeCounter++, ram, rom);
doSBC(cpu, value);
return 2;
} }
case NOP: { case NOP: {
return 2; return 2;
@@ -1615,14 +1827,34 @@ useconds_t runCycle(CPU *cpu, uint8_t *ram, uint8_t *rom) {
return 4; return 4;
} }
case SBC_A: { 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: { 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: { case BEQ: {
useconds_t cycles = 2; uint8_t cycles = 2;
// Get offset // Get offset
int8_t offset = (int8_t)readMemory(cpu->ProgrammeCounter++, ram, rom); 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; return cycles;
} }
case SBC_ZiY: { 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: { 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: { 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: { case SED: {
cpu->Flags.DecimalMode = 1; cpu->Flags.DecimalMode = 1;
@@ -1654,13 +1916,41 @@ useconds_t runCycle(CPU *cpu, uint8_t *ram, uint8_t *rom) {
return 2; return 2;
} }
case SBC_YA: { 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: { 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: { 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: default:
+11 -5
View File
@@ -6,9 +6,13 @@
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <termios.h> #include <termios.h>
#include <time.h>
#include <unistd.h> #include <unistd.h>
#define MACHINE_SPEED_HZ 1e6 // 1 MHz;
static struct termios orig_termios; static struct termios orig_termios;
static struct timespec sleepTime;
void restore_terminal(void) { tcsetattr(STDIN_FILENO, TCSANOW, &orig_termios); } void restore_terminal(void) { tcsetattr(STDIN_FILENO, TCSANOW, &orig_termios); }
@@ -44,7 +48,8 @@ int main(void) {
/* DEBUG */ /* 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) { if (!fp) {
perror("fopen"); perror("fopen");
return 1; return 1;
@@ -65,14 +70,15 @@ int main(void) {
resetCPU(&cpu, rom); resetCPU(&cpu, rom);
while (1) { while (1) {
//printf("\tPC: 0x%x\tOP: 0x%x\n", cpu.ProgrammeCounter, ram[cpu.ProgrammeCounter]); // printf("\tPC: 0x%x\tOP: 0x%x\n", cpu.ProgrammeCounter, ram[cpu.ProgrammeCounter]);
useconds_t sleep = runCycle(&cpu, ram, rom); uint8_t sleep = runCycle(&cpu, ram, rom);
if (sleep == 1) { if (sleep == 1) {
printf("opcode missing: 0x%X\n", ram[cpu.ProgrammeCounter - 1]); printf("opcode missing: 0x%X\n", ram[cpu.ProgrammeCounter - 1]);
return 1; return 1;
} }
fflush(stdout); sleepTime.tv_sec = 0;
usleep(sleep); sleepTime.tv_nsec = sleep * (1000 / MACHINE_SPEED_HZ);
nanosleep(&sleepTime, NULL);
} }
/* CPU WORK */ /* CPU WORK */
+3 -1
View File
@@ -3,6 +3,8 @@
uint8_t rom[ROM_SIZE] = {0}; uint8_t rom[ROM_SIZE] = {0};
void initRom(uint8_t *rom) { void initRom(uint8_t *rom) {
rom[0] = 0xa9, // LDA rom[0] = 0xa9, // LDA
rom[1] = 'H', // H literal rom[1] = 'H', // H literal
rom[2] = 0x8d, // STA rom[2] = 0x8d, // STA
@@ -11,7 +13,7 @@ void initRom(uint8_t *rom) {
rom[6] = rom[6] =
/* Reset Vector */ /* Reset Vector */
rom[0xFFFC - ROM_BASE] = 0x00, // Lower byte base of ROM 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[0xFFFE - ROM_BASE] = 0x00, // Lower byte base of ROM
rom[0xFFFF - ROM_BASE] = 0x00; // Upper byte of base of ROM rom[0xFFFF - ROM_BASE] = 0x00; // Upper byte of base of ROM
} }