commit 00eaf1aa34f6299038873f7dcae4e0f2292809f3
parent 7d77f4257759213bca1e96419be11ac7e84d687f
Author: mjkloeckner <martin.cachari@gmail.com>
Date: Tue, 12 Jul 2022 19:22:05 -0300
CPU instructions implementation plus clock simulation and CPU reset fix
Added CPU instructions implementation, mostly conditionals like BEQ,
BNE, etc.
The CPU_exec function now has a loop that simulates the clock of the
CPU; CPU_reset function also gets a loop, because it caused a BUG in
the CPU_exec function, since CPU_exec only executes a instruction if the clock
is set at zero, before the modification CPU_reset leaved the clock at 8
cycles since that is how long the real CPU takes to reset, but it never
decremented it, so in the first call to CPU_exec the instruction would never
be executed.
Diffstat:
M | 6502.c | | | 431 | +++++++++++++++++++++++++++++++++++++++++++++++++++++-------------------------- |
M | 6502.h | | | 8 | ++++---- |
M | main.c | | | 24 | ++++++++++++++++++------ |
3 files changed, 313 insertions(+), 150 deletions(-)
diff --git a/6502.c b/6502.c
@@ -8,14 +8,14 @@ static MEM mem; /* 8 bit word */
static uint8_t cyc;
static uint8_t opc;
-static uint8_t fch;
+static uint8_t tmp;
static uint16_t addr_abs;
static uint16_t addr_rel;
-INS lookup[0x100];
+INS decode[0x100];
-static uint8_t ST_FLAG_MASK[] = {
+static uint8_t ST_FLAG_MASK[] = {
(1 << 0), /* Carry */
(1 << 1), /* Zero */
(1 << 2), /* Disable interrupts */
@@ -30,39 +30,56 @@ static uint8_t ST_FLAG_MASK[] = {
/* Cpu methods */
void CPU_init(void) {
cpu.ac = cpu.x = cpu.y = cpu.sp = cpu.st = 0;
+ cyc = opc = tmp = 0;
}
void CPU_reset(void) {
- cpu.sp = 0xFF; /* first page */
- cpu.st = 0x00 | ST_FLAG_MASK[U];
+ /* simulate 8 cycles needed to reset the cpu */
+ do {
+ if(cyc == 0) {
+ cpu.sp = 0xFF; /* first page */
+ cpu.st = 0x00 | ST_FLAG_MASK[U];
- /* little endian */
- uint16_t lo = MEM_fetch(0xFFFC);
- uint16_t hi = MEM_fetch(0xFFFD);
+ /* little endian */
+ uint16_t lo = MEM_read(0xFFFC);
+ uint16_t hi = MEM_read(0xFFFD);
- cpu.pc = (hi << 8) | lo;
+ cpu.pc = (hi << 8) | lo;
- addr_abs = addr_rel = opc = 0x0000;
+ addr_abs = addr_rel = opc = 0x0000;
- cyc = 8;
-}
-
-void CPU_clock(void) {
+ cyc = 8;
+ }
+ cyc--;
+ } while(cyc != 0);
}
void CPU_fetch(INS *ins) {
- *ins = lookup[MEM_fetch(cpu.pc++)];
+ *ins = decode[MEM_read(cpu.pc)];
}
-void CPU_exec(const INS ins) {
- addr_abs = 0x0000;
- ins.mode();
- ins.op();
+void CPU_exec(INS ins) {
+ /* simulate instructions cycles */
+ do {
+ if(cyc == 0) {
+ cpu.pc++;
+
+ cyc = ins.cycles;
+
+ uint8_t add_cyc_0 = ins.mode();
+ uint8_t add_cyc_1 = ins.op();
+
+ cyc += add_cyc_0 & add_cyc_1;
+ }
+ cyc--;
+ } while(cyc != 0);
}
+/* interrupt request */
void CPU_irq(void) {
}
+/* non maskeable interrupt request */
void CPU_nm_irq(void) {
}
@@ -84,14 +101,14 @@ void print_reg(uint8_t reg) {
}
void CPU_dump(void) {
- printf("N O - B D I Z C\n");
+ INS aux = decode[MEM_read(cpu.pc)];
+
+ printf(" a: %02X (%3d) N V - B D I Z C\n", cpu.ac, cpu.ac);
+ printf(" x: %02X (%3d) ", cpu.x, cpu.x);
print_reg(cpu.st);
- printf(" a: %02X\n", cpu.ac);
- printf(" x: %02X\n", cpu.x);
- printf(" y: %02X\n", cpu.y);
- printf(" sp: %02X\n", cpu.sp);
- printf(" pc: %04X\n", cpu.pc);
- printf("ram[%04X]: %02X\n", cpu.pc, mem.ram[cpu.pc]);
+ printf(" y: %02X (%3d)\n", cpu.y, cpu.y);
+ printf(" sp: %02X\n", cpu.sp);
+ printf(" pc: %04X -> %02X (%s)(%s)\n", cpu.pc, mem.ram[cpu.pc], aux.name, CPU_mode_name(aux.mode));
}
/* Memory methods */
@@ -99,6 +116,7 @@ void MEM_init(void) {
for(uint16_t i = 0; i < 0xFFFF; i++)
mem.ram[i] = 0;
+ /* First address that pc reads */
mem.ram[0xFFFC] = 0x00;
mem.ram[0xFFFD] = 0x80;
}
@@ -116,7 +134,7 @@ void MEM_load_from_file(char *path) {
fclose(fp);
}
-uint8_t MEM_fetch(uint16_t addr) {
+uint8_t MEM_read(uint16_t addr) {
return mem.ram[addr];
}
@@ -125,14 +143,24 @@ uint8_t MEM_write(uint16_t addr, uint8_t val) {
return 0;
}
-void MEM_dump(void) {
+void MEM_dump() {
for(uint16_t i = 0; i < 0xF; i++)
printf("%02X ", mem.ram[i]);
putchar('\n');
}
-char *mode_to_str(uint8_t (*mode)(void)) {
+void MEM_dump_page(uint16_t page) {
+ uint16_t j = 1;
+
+ printf("Page %04X:\n", page);
+ for(uint16_t i = page; i < (page + 0x3C); i++, j++)
+ printf("%02X %s", mem.ram[i], (j % 0xF) ? "" : "\n");
+
+ putchar('\n');
+}
+
+char *CPU_mode_name(uint8_t (*mode)(void)) {
if(mode == &IMM) return "IMM";
else if(mode == &ABS) return "ABS";
else if(mode == &ABX) return "ABX";
@@ -149,101 +177,10 @@ char *mode_to_str(uint8_t (*mode)(void)) {
return "NUL";
}
-/* Lookup table */
-INS lookup[0x100] = {
- {"BRK", &BRK, &IMM, 7}, {"ORA", &ORA, &IZX, 6}, {"???", &NUL, &IMP, 2},
- {"???", &NUL, &IMP, 8}, {"???", &NOP, &IMP, 3}, {"ORA", &ORA, &ZP0, 3},
- {"ASL", &ASL, &ZP0, 5}, {"???", &NUL, &IMP, 5}, {"PHP", &PHP, &IMP, 3},
- {"ORA", &ORA, &IMM, 2}, {"ASL", &ASL, &IMP, 2}, {"???", &NUL, &IMP, 2},
- {"???", &NOP, &IMP, 4}, {"ORA", &ORA, &ABS, 4}, {"ASL", &ASL, &ABS, 6},
- {"???", &NUL, &IMP, 6}, {"BPL", &BPL, &REL, 2}, {"ORA", &ORA, &IZY, 5},
- {"???", &NUL, &IMP, 2}, {"???", &NUL, &IMP, 8}, {"???", &NOP, &IMP, 4},
- {"ORA", &ORA, &ZPX, 4}, {"ASL", &ASL, &ZPX, 6}, {"???", &NUL, &IMP, 6},
- {"CLC", &CLC, &IMP, 2}, {"ORA", &ORA, &ABY, 4}, {"???", &NOP, &IMP, 2},
- {"???", &NUL, &IMP, 7}, {"???", &NOP, &IMP, 4}, {"ORA", &ORA, &ABX, 4},
- {"ASL", &ASL, &ABX, 7}, {"???", &NUL, &IMP, 7}, {"JSR", &JSR, &ABS, 6},
- {"AND", &AND, &IZX, 6}, {"???", &NUL, &IMP, 2}, {"???", &NUL, &IMP, 8},
- {"BIT", &BIT, &ZP0, 3}, {"AND", &AND, &ZP0, 3}, {"ROL", &ROL, &ZP0, 5},
- {"???", &NUL, &IMP, 5}, {"PLP", &PLP, &IMP, 4}, {"AND", &AND, &IMM, 2},
- {"ROL", &ROL, &IMP, 2}, {"???", &NUL, &IMP, 2}, {"BIT", &BIT, &ABS, 4},
- {"AND", &AND, &ABS, 4}, {"ROL", &ROL, &ABS, 6}, {"???", &NUL, &IMP, 6},
- {"BMI", &BMI, &REL, 2}, {"AND", &AND, &IZY, 5}, {"???", &NUL, &IMP, 2},
- {"???", &NUL, &IMP, 8}, {"???", &NOP, &IMP, 4}, {"AND", &AND, &ZPX, 4},
- {"ROL", &ROL, &ZPX, 6}, {"???", &NUL, &IMP, 6}, {"SEC", &SEC, &IMP, 2},
- {"AND", &AND, &ABY, 4}, {"???", &NOP, &IMP, 2}, {"???", &NUL, &IMP, 7},
- {"???", &NOP, &IMP, 4}, {"AND", &AND, &ABX, 4}, {"ROL", &ROL, &ABX, 7},
- {"???", &NUL, &IMP, 7}, {"RTI", &RTI, &IMP, 6}, {"EOR", &EOR, &IZX, 6},
- {"???", &NUL, &IMP, 2}, {"???", &NUL, &IMP, 8}, {"???", &NOP, &IMP, 3},
- {"EOR", &EOR, &ZP0, 3}, {"LSR", &LSR, &ZP0, 5}, {"???", &NUL, &IMP, 5},
- {"PHA", &PHA, &IMP, 3}, {"EOR", &EOR, &IMM, 2}, {"LSR", &LSR, &IMP, 2},
- {"???", &NUL, &IMP, 2}, {"JMP", &JMP, &ABS, 3}, {"EOR", &EOR, &ABS, 4},
- {"LSR", &LSR, &ABS, 6}, {"???", &NUL, &IMP, 6}, {"BVC", &BVC, &REL, 2},
- {"EOR", &EOR, &IZY, 5}, {"???", &NUL, &IMP, 2}, {"???", &NUL, &IMP, 8},
- {"???", &NOP, &IMP, 4}, {"EOR", &EOR, &ZPX, 4}, {"LSR", &LSR, &ZPX, 6},
- {"???", &NUL, &IMP, 6}, {"CLI", &CLI, &IMP, 2}, {"EOR", &EOR, &ABY, 4},
- {"???", &NOP, &IMP, 2}, {"???", &NUL, &IMP, 7}, {"???", &NOP, &IMP, 4},
- {"EOR", &EOR, &ABX, 4}, {"LSR", &LSR, &ABX, 7}, {"???", &NUL, &IMP, 7},
- {"RTS", &RTS, &IMP, 6}, {"ADC", &ADC, &IZX, 6}, {"???", &NUL, &IMP, 2},
- {"???", &NUL, &IMP, 8}, {"???", &NOP, &IMP, 3}, {"ADC", &ADC, &ZP0, 3},
- {"ROR", &ROR, &ZP0, 5}, {"???", &NUL, &IMP, 5}, {"PLA", &PLA, &IMP, 4},
- {"ADC", &ADC, &IMM, 2}, {"ROR", &ROR, &IMP, 2}, {"???", &NUL, &IMP, 2},
- {"JMP", &JMP, &IND, 5}, {"ADC", &ADC, &ABS, 4}, {"ROR", &ROR, &ABS, 6},
- {"???", &NUL, &IMP, 6}, {"BVS", &BVS, &REL, 2}, {"ADC", &ADC, &IZY, 5},
- {"???", &NUL, &IMP, 2}, {"???", &NUL, &IMP, 8}, {"???", &NOP, &IMP, 4},
- {"ADC", &ADC, &ZPX, 4}, {"ROR", &ROR, &ZPX, 6}, {"???", &NUL, &IMP, 6},
- {"SEI", &SEI, &IMP, 2}, {"ADC", &ADC, &ABY, 4}, {"???", &NOP, &IMP, 2},
- {"???", &NUL, &IMP, 7}, {"???", &NOP, &IMP, 4}, {"ADC", &ADC, &ABX, 4},
- {"ROR", &ROR, &ABX, 7}, {"???", &NUL, &IMP, 7}, {"???", &NOP, &IMP, 2},
- {"STA", &STA, &IZX, 6}, {"???", &NOP, &IMP, 2}, {"???", &NUL, &IMP, 6},
- {"STY", &STY, &ZP0, 3}, {"STA", &STA, &ZP0, 3}, {"STX", &STX, &ZP0, 3},
- {"???", &NUL, &IMP, 3}, {"DEY", &DEY, &IMP, 2}, {"???", &NOP, &IMP, 2},
- {"TXA", &TXA, &IMP, 2}, {"???", &NUL, &IMP, 2}, {"STY", &STY, &ABS, 4},
- {"STA", &STA, &ABS, 4}, {"STX", &STX, &ABS, 4}, {"???", &NUL, &IMP, 4},
- {"BCC", &BCC, &REL, 2}, {"STA", &STA, &IZY, 6}, {"???", &NUL, &IMP, 2},
- {"???", &NUL, &IMP, 6}, {"STY", &STY, &ZPX, 4}, {"STA", &STA, &ZPX, 4},
- {"STX", &STX, &ZPY, 4}, {"???", &NUL, &IMP, 4}, {"TYA", &TYA, &IMP, 2},
- {"STA", &STA, &ABY, 5}, {"TXS", &TXS, &IMP, 2}, {"???", &NUL, &IMP, 5},
- {"???", &NOP, &IMP, 5}, {"STA", &STA, &ABX, 5}, {"???", &NUL, &IMP, 5},
- {"???", &NUL, &IMP, 5}, {"LDY", &LDY, &IMM, 2}, {"LDA", &LDA, &IZX, 6},
- {"LDX", &LDX, &IMM, 2}, {"???", &NUL, &IMP, 6}, {"LDY", &LDY, &ZP0, 3},
- {"LDA", &LDA, &ZP0, 3}, {"LDX", &LDX, &ZP0, 3}, {"???", &NUL, &IMP, 3},
- {"TAY", &TAY, &IMP, 2}, {"LDA", &LDA, &IMM, 2}, {"TAX", &TAX, &IMP, 2},
- {"???", &NUL, &IMP, 2}, {"LDY", &LDY, &ABS, 4}, {"LDA", &LDA, &ABS, 4},
- {"LDX", &LDX, &ABS, 4}, {"???", &NUL, &IMP, 4}, {"BCS", &BCS, &REL, 2},
- {"LDA", &LDA, &IZY, 5}, {"???", &NUL, &IMP, 2}, {"???", &NUL, &IMP, 5},
- {"LDY", &LDY, &ZPX, 4}, {"LDA", &LDA, &ZPX, 4}, {"LDX", &LDX, &ZPY, 4},
- {"???", &NUL, &IMP, 4}, {"CLV", &CLV, &IMP, 2}, {"LDA", &LDA, &ABY, 4},
- {"TSX", &TSX, &IMP, 2}, {"???", &NUL, &IMP, 4}, {"LDY", &LDY, &ABX, 4},
- {"LDA", &LDA, &ABX, 4}, {"LDX", &LDX, &ABY, 4}, {"???", &NUL, &IMP, 4},
- {"CPY", &CPY, &IMM, 2}, {"CMP", &CMP, &IZX, 6}, {"???", &NOP, &IMP, 2},
- {"???", &NUL, &IMP, 8}, {"CPY", &CPY, &ZP0, 3}, {"CMP", &CMP, &ZP0, 3},
- {"DEC", &DEC, &ZP0, 5}, {"???", &NUL, &IMP, 5}, {"INY", &INY, &IMP, 2},
- {"CMP", &CMP, &IMM, 2}, {"DEX", &DEX, &IMP, 2}, {"???", &NUL, &IMP, 2},
- {"CPY", &CPY, &ABS, 4}, {"CMP", &CMP, &ABS, 4}, {"DEC", &DEC, &ABS, 6},
- {"???", &NUL, &IMP, 6}, {"BNE", &BNE, &REL, 2}, {"CMP", &CMP, &IZY, 5},
- {"???", &NUL, &IMP, 2}, {"???", &NUL, &IMP, 8}, {"???", &NOP, &IMP, 4},
- {"CMP", &CMP, &ZPX, 4}, {"DEC", &DEC, &ZPX, 6}, {"???", &NUL, &IMP, 6},
- {"CLD", &CLD, &IMP, 2}, {"CMP", &CMP, &ABY, 4}, {"NOP", &NOP, &IMP, 2},
- {"???", &NUL, &IMP, 7}, {"???", &NOP, &IMP, 4}, {"CMP", &CMP, &ABX, 4},
- {"DEC", &DEC, &ABX, 7}, {"???", &NUL, &IMP, 7}, {"CPX", &CPX, &IMM, 2},
- {"SBC", &SBC, &IZX, 6}, {"???", &NOP, &IMP, 2}, {"???", &NUL, &IMP, 8},
- {"CPX", &CPX, &ZP0, 3}, {"SBC", &SBC, &ZP0, 3}, {"INC", &INC, &ZP0, 5},
- {"???", &NUL, &IMP, 5}, {"INX", &INX, &IMP, 2}, {"SBC", &SBC, &IMM, 2},
- {"NOP", &NOP, &IMP, 2}, {"???", &SBC, &IMP, 2}, {"CPX", &CPX, &ABS, 4},
- {"SBC", &SBC, &ABS, 4}, {"INC", &INC, &ABS, 6}, {"???", &NUL, &IMP, 6},
- {"BEQ", &BEQ, &REL, 2}, {"SBC", &SBC, &IZY, 5}, {"???", &NUL, &IMP, 2},
- {"???", &NUL, &IMP, 8}, {"???", &NOP, &IMP, 4}, {"SBC", &SBC, &ZPX, 4},
- {"INC", &INC, &ZPX, 6}, {"???", &NUL, &IMP, 6}, {"SED", &SED, &IMP, 2},
- {"SBC", &SBC, &ABY, 4}, {"NOP", &NOP, &IMP, 2}, {"???", &NUL, &IMP, 7},
- {"???", &NOP, &IMP, 4}, {"SBC", &SBC, &ABX, 4}, {"INC", &INC, &ABX, 7},
- {"???", &NUL, &IMP, 7}
-};
-
-
/* Addressing modes */
uint8_t ABS(void) {
- uint8_t lo = MEM_fetch(cpu.pc++);
- uint8_t hi = MEM_fetch(cpu.pc++);
+ uint16_t lo = MEM_read(cpu.pc++);
+ uint16_t hi = MEM_read(cpu.pc++);
addr_abs = (hi << 8) | lo;
return 0;
@@ -263,7 +200,7 @@ uint8_t IMM(void) {
}
uint8_t IMP(void) {
- fch = cpu.ac;
+ tmp = cpu.ac;
return 0;
}
@@ -280,7 +217,7 @@ uint8_t IZY(void) {
}
uint8_t REL(void) {
- addr_rel = MEM_fetch(cpu.pc++);
+ addr_rel = MEM_read(cpu.pc++);
if(addr_rel & (1 << 7))
addr_rel |= 0xFF00;
@@ -303,35 +240,70 @@ uint8_t ZPY(void) {
/* Instructions */
uint8_t ADC(void) {
- uint8_t data = MEM_fetch(addr_abs);
+ uint8_t data = MEM_read(addr_abs);
cpu.ac += (data + CPU_get_flag(C));
CPU_set_flag(Z, cpu.ac == 0);
CPU_set_flag(N, cpu.ac & (1 << 7));
- CPU_set_flag(O, ((cpu.ac^data) & ~(cpu.ac^data)) & (1 << 7));
+ CPU_set_flag(V, ((cpu.ac^data) & ~(cpu.ac^data)) & (1 << 7));
return 1;
}
uint8_t AND(void) {
- return 0;
+ cpu.ac &= MEM_read(addr_abs);
+
+ CPU_set_flag(Z, cpu.ac == 0);
+ CPU_set_flag(N, cpu.ac & (1 << 7));
+
+ return 1;
}
uint8_t ASL(void) {
-
+
return 0;
}
uint8_t BCC(void) {
+ if(!CPU_get_flag(C)) {
+ addr_abs = cpu.pc + addr_rel;
+
+ /* if address changes page */
+ if((addr_abs & (1 << 7)) != (cpu.pc & (1 << 7)))
+ cyc++;
+
+ cpu.pc = addr_abs;
+ }
+
return 0;
}
uint8_t BCS(void) {
+ if(CPU_get_flag(C)) {
+ addr_abs = cpu.pc + addr_rel;
+
+ /* if address changes page */
+ if((addr_abs & (1 << 7)) != (cpu.pc & (1 << 7)))
+ cyc++;
+
+ cpu.pc = addr_abs;
+ }
+
return 0;
}
uint8_t BEQ(void) {
+ if(CPU_get_flag(Z)) {
+ addr_abs = cpu.pc + addr_rel;
+
+ /* if address changes page */
+ if((addr_abs & (1 << 7)) != (cpu.pc & (1 << 7)))
+ cyc++;
+
+ cpu.pc = addr_abs;
+ }
+
return 0;
}
@@ -340,29 +312,77 @@ uint8_t BIT(void) {
}
uint8_t BMI(void) {
+ if(CPU_get_flag(N)) {
+ addr_abs = cpu.pc + addr_rel;
+
+ /* if address changes page */
+ if((addr_abs & (1 << 7)) != (cpu.pc & (1 << 7)))
+ cyc++;
+
+ cpu.pc = addr_abs;
+ }
+
return 0;
}
uint8_t BNE(void) {
- if(!CPU_get_flag(Z))
- cpu.pc += addr_rel;
+ if(!CPU_get_flag(Z)) {
+ addr_abs = cpu.pc + addr_rel;
+
+ /* if address changes page */
+ if((addr_abs & (1 << 7)) != (cpu.pc & (1 << 7)))
+ cyc++;
+
+ cpu.pc = addr_abs;
+ }
return 0;
}
uint8_t BPL(void) {
+ if(!CPU_get_flag(N)) {
+ addr_abs = cpu.pc + addr_rel;
+
+ /* if address changes page */
+ if((addr_abs & (1 << 7)) != (cpu.pc & (1 << 7)))
+ cyc++;
+
+ cpu.pc = addr_abs;
+ }
+
return 0;
}
uint8_t BRK(void) {
+
return 0;
}
uint8_t BVC(void) {
+ if(!CPU_get_flag(V)) {
+ addr_abs = cpu.pc + addr_rel;
+
+ /* if address changes page */
+ if((addr_abs & (1 << 7)) != (cpu.pc & (1 << 7)))
+ cyc++;
+
+ cpu.pc = addr_abs;
+ }
+
return 0;
}
uint8_t BVS(void) {
+ if(CPU_get_flag(V)) {
+ addr_abs = cpu.pc + addr_rel;
+
+ /* if address changes page */
+ if((addr_abs & (1 << 7)) != (cpu.pc & (1 << 7)))
+ cyc++;
+
+ cpu.pc = addr_abs;
+ }
+
return 0;
}
@@ -372,14 +392,17 @@ uint8_t CLC(void) {
}
uint8_t CLD(void) {
+ CPU_set_flag(D, 0);
return 0;
}
uint8_t CLI(void) {
+ CPU_set_flag(I, 0);
return 0;
}
uint8_t CLV(void) {
+ CPU_set_flag(V, 0);
return 0;
}
@@ -396,9 +419,16 @@ uint8_t CPY(void) {
}
uint8_t DEC(void) {
+ tmp = (MEM_read(addr_abs) - 1) & 0x00FF;
+ MEM_write(addr_abs, tmp);
+
+ CPU_set_flag(Z, tmp == 0);
+ CPU_set_flag(N, tmp & 0xFF);
+
return 0;
}
+/* Decrements X register */
uint8_t DEX(void) {
cpu.x -= 1;
@@ -408,7 +438,7 @@ uint8_t DEX(void) {
return 0;
}
-/* Subtracts one from the Y register */
+/* Decrements Y register */
uint8_t DEY(void) {
cpu.y -= 1;
@@ -419,18 +449,40 @@ uint8_t DEY(void) {
}
uint8_t EOR(void) {
- return 0;
+ cpu.ac ^= MEM_read(addr_abs);
+
+ CPU_set_flag(Z, cpu.ac == 0);
+ CPU_set_flag(N, cpu.ac & (1 << 7));
+
+ return 1;
}
uint8_t INC(void) {
+ tmp = MEM_read(addr_abs + 1);
+
+ MEM_write(addr_abs, tmp);
+
+ CPU_set_flag(Z, tmp == 0);
+ CPU_set_flag(N, tmp & (1 << 7));
+
return 0;
}
uint8_t INX(void) {
+ cpu.x += 1;
+
+ CPU_set_flag(Z, cpu.x == 0);
+ CPU_set_flag(N, cpu.x & (1 << 7));
+
return 0;
}
uint8_t INY(void) {
+ cpu.y += 1;
+
+ CPU_set_flag(Z, cpu.y == 0);
+ CPU_set_flag(N, cpu.y & (1 << 7));
+
return 0;
}
@@ -443,30 +495,30 @@ uint8_t JSR(void) {
}
uint8_t LDA(void) {
- cpu.ac = MEM_fetch(addr_abs);
+ cpu.ac = MEM_read(addr_abs);
CPU_set_flag(Z, cpu.ac == 0);
CPU_set_flag(N, cpu.ac & (1 << 7));
- return 0;
+ return 1;
}
uint8_t LDX(void) {
- cpu.x = MEM_fetch(addr_abs);
+ cpu.x = MEM_read(addr_abs);
CPU_set_flag(Z, cpu.x == 0);
CPU_set_flag(N, cpu.x & (1 << 7));
- return 0;
+ return 1;
}
uint8_t LDY(void) {
- cpu.y = MEM_fetch(addr_abs);
+ cpu.y = MEM_read(addr_abs);
CPU_set_flag(Z, cpu.y == 0);
CPU_set_flag(N, cpu.y & (1 << 7));
- return 0;
+ return 1;
}
uint8_t LSR(void) {
@@ -478,7 +530,12 @@ uint8_t NOP(void) {
}
uint8_t ORA(void) {
- return 0;
+ cpu.ac |= MEM_read(addr_abs);
+
+ CPU_set_flag(Z, cpu.ac == 0);
+ CPU_set_flag(N, cpu.ac & (1 << 7));
+
+ return 1;
}
uint8_t PHA(void) {
@@ -518,14 +575,17 @@ uint8_t SBC(void) {
}
uint8_t SEC(void) {
+ CPU_set_flag(C, 1);
return 0;
}
uint8_t SED(void) {
+ CPU_set_flag(D, 1);
return 0;
}
uint8_t SEI(void) {
+ CPU_set_flag(I, 1);
return 0;
}
@@ -540,6 +600,7 @@ uint8_t STX(void) {
}
uint8_t STY(void) {
+ MEM_write(addr_abs, cpu.y);
return 0;
}
@@ -567,7 +628,97 @@ uint8_t TYA(void) {
return 0;
}
-
uint8_t NUL(void) {
return 0;
}
+
+/* Lookup table */
+INS decode[0x100] = {
+ {"BRK", &BRK, &IMM, 7}, {"ORA", &ORA, &IZX, 6}, {"???", &NUL, &IMP, 2},
+ {"???", &NUL, &IMP, 8}, {"???", &NOP, &IMP, 3}, {"ORA", &ORA, &ZP0, 3},
+ {"ASL", &ASL, &ZP0, 5}, {"???", &NUL, &IMP, 5}, {"PHP", &PHP, &IMP, 3},
+ {"ORA", &ORA, &IMM, 2}, {"ASL", &ASL, &IMP, 2}, {"???", &NUL, &IMP, 2},
+ {"???", &NOP, &IMP, 4}, {"ORA", &ORA, &ABS, 4}, {"ASL", &ASL, &ABS, 6},
+ {"???", &NUL, &IMP, 6}, {"BPL", &BPL, &REL, 2}, {"ORA", &ORA, &IZY, 5},
+ {"???", &NUL, &IMP, 2}, {"???", &NUL, &IMP, 8}, {"???", &NOP, &IMP, 4},
+ {"ORA", &ORA, &ZPX, 4}, {"ASL", &ASL, &ZPX, 6}, {"???", &NUL, &IMP, 6},
+ {"CLC", &CLC, &IMP, 2}, {"ORA", &ORA, &ABY, 4}, {"???", &NOP, &IMP, 2},
+ {"???", &NUL, &IMP, 7}, {"???", &NOP, &IMP, 4}, {"ORA", &ORA, &ABX, 4},
+ {"ASL", &ASL, &ABX, 7}, {"???", &NUL, &IMP, 7}, {"JSR", &JSR, &ABS, 6},
+ {"AND", &AND, &IZX, 6}, {"???", &NUL, &IMP, 2}, {"???", &NUL, &IMP, 8},
+ {"BIT", &BIT, &ZP0, 3}, {"AND", &AND, &ZP0, 3}, {"ROL", &ROL, &ZP0, 5},
+ {"???", &NUL, &IMP, 5}, {"PLP", &PLP, &IMP, 4}, {"AND", &AND, &IMM, 2},
+ {"ROL", &ROL, &IMP, 2}, {"???", &NUL, &IMP, 2}, {"BIT", &BIT, &ABS, 4},
+ {"AND", &AND, &ABS, 4}, {"ROL", &ROL, &ABS, 6}, {"???", &NUL, &IMP, 6},
+ {"BMI", &BMI, &REL, 2}, {"AND", &AND, &IZY, 5}, {"???", &NUL, &IMP, 2},
+ {"???", &NUL, &IMP, 8}, {"???", &NOP, &IMP, 4}, {"AND", &AND, &ZPX, 4},
+ {"ROL", &ROL, &ZPX, 6}, {"???", &NUL, &IMP, 6}, {"SEC", &SEC, &IMP, 2},
+ {"AND", &AND, &ABY, 4}, {"???", &NOP, &IMP, 2}, {"???", &NUL, &IMP, 7},
+ {"???", &NOP, &IMP, 4}, {"AND", &AND, &ABX, 4}, {"ROL", &ROL, &ABX, 7},
+ {"???", &NUL, &IMP, 7}, {"RTI", &RTI, &IMP, 6}, {"EOR", &EOR, &IZX, 6},
+ {"???", &NUL, &IMP, 2}, {"???", &NUL, &IMP, 8}, {"???", &NOP, &IMP, 3},
+ {"EOR", &EOR, &ZP0, 3}, {"LSR", &LSR, &ZP0, 5}, {"???", &NUL, &IMP, 5},
+ {"PHA", &PHA, &IMP, 3}, {"EOR", &EOR, &IMM, 2}, {"LSR", &LSR, &IMP, 2},
+ {"???", &NUL, &IMP, 2}, {"JMP", &JMP, &ABS, 3}, {"EOR", &EOR, &ABS, 4},
+ {"LSR", &LSR, &ABS, 6}, {"???", &NUL, &IMP, 6}, {"BVC", &BVC, &REL, 2},
+ {"EOR", &EOR, &IZY, 5}, {"???", &NUL, &IMP, 2}, {"???", &NUL, &IMP, 8},
+ {"???", &NOP, &IMP, 4}, {"EOR", &EOR, &ZPX, 4}, {"LSR", &LSR, &ZPX, 6},
+ {"???", &NUL, &IMP, 6}, {"CLI", &CLI, &IMP, 2}, {"EOR", &EOR, &ABY, 4},
+ {"???", &NOP, &IMP, 2}, {"???", &NUL, &IMP, 7}, {"???", &NOP, &IMP, 4},
+ {"EOR", &EOR, &ABX, 4}, {"LSR", &LSR, &ABX, 7}, {"???", &NUL, &IMP, 7},
+ {"RTS", &RTS, &IMP, 6}, {"ADC", &ADC, &IZX, 6}, {"???", &NUL, &IMP, 2},
+ {"???", &NUL, &IMP, 8}, {"???", &NOP, &IMP, 3}, {"ADC", &ADC, &ZP0, 3},
+ {"ROR", &ROR, &ZP0, 5}, {"???", &NUL, &IMP, 5}, {"PLA", &PLA, &IMP, 4},
+ {"ADC", &ADC, &IMM, 2}, {"ROR", &ROR, &IMP, 2}, {"???", &NUL, &IMP, 2},
+ {"JMP", &JMP, &IND, 5}, {"ADC", &ADC, &ABS, 4}, {"ROR", &ROR, &ABS, 6},
+ {"???", &NUL, &IMP, 6}, {"BVS", &BVS, &REL, 2}, {"ADC", &ADC, &IZY, 5},
+ {"???", &NUL, &IMP, 2}, {"???", &NUL, &IMP, 8}, {"???", &NOP, &IMP, 4},
+ {"ADC", &ADC, &ZPX, 4}, {"ROR", &ROR, &ZPX, 6}, {"???", &NUL, &IMP, 6},
+ {"SEI", &SEI, &IMP, 2}, {"ADC", &ADC, &ABY, 4}, {"???", &NOP, &IMP, 2},
+ {"???", &NUL, &IMP, 7}, {"???", &NOP, &IMP, 4}, {"ADC", &ADC, &ABX, 4},
+ {"ROR", &ROR, &ABX, 7}, {"???", &NUL, &IMP, 7}, {"???", &NOP, &IMP, 2},
+ {"STA", &STA, &IZX, 6}, {"???", &NOP, &IMP, 2}, {"???", &NUL, &IMP, 6},
+ {"STY", &STY, &ZP0, 3}, {"STA", &STA, &ZP0, 3}, {"STX", &STX, &ZP0, 3},
+ {"???", &NUL, &IMP, 3}, {"DEY", &DEY, &IMP, 2}, {"???", &NOP, &IMP, 2},
+ {"TXA", &TXA, &IMP, 2}, {"???", &NUL, &IMP, 2}, {"STY", &STY, &ABS, 4},
+ {"STA", &STA, &ABS, 4}, {"STX", &STX, &ABS, 4}, {"???", &NUL, &IMP, 4},
+ {"BCC", &BCC, &REL, 2}, {"STA", &STA, &IZY, 6}, {"???", &NUL, &IMP, 2},
+ {"???", &NUL, &IMP, 6}, {"STY", &STY, &ZPX, 4}, {"STA", &STA, &ZPX, 4},
+ {"STX", &STX, &ZPY, 4}, {"???", &NUL, &IMP, 4}, {"TYA", &TYA, &IMP, 2},
+ {"STA", &STA, &ABY, 5}, {"TXS", &TXS, &IMP, 2}, {"???", &NUL, &IMP, 5},
+ {"???", &NOP, &IMP, 5}, {"STA", &STA, &ABX, 5}, {"???", &NUL, &IMP, 5},
+ {"???", &NUL, &IMP, 5}, {"LDY", &LDY, &IMM, 2}, {"LDA", &LDA, &IZX, 6},
+ {"LDX", &LDX, &IMM, 2}, {"???", &NUL, &IMP, 6}, {"LDY", &LDY, &ZP0, 3},
+ {"LDA", &LDA, &ZP0, 3}, {"LDX", &LDX, &ZP0, 3}, {"???", &NUL, &IMP, 3},
+ {"TAY", &TAY, &IMP, 2}, {"LDA", &LDA, &IMM, 2}, {"TAX", &TAX, &IMP, 2},
+ {"???", &NUL, &IMP, 2}, {"LDY", &LDY, &ABS, 4}, {"LDA", &LDA, &ABS, 4},
+ {"LDX", &LDX, &ABS, 4}, {"???", &NUL, &IMP, 4}, {"BCS", &BCS, &REL, 2},
+ {"LDA", &LDA, &IZY, 5}, {"???", &NUL, &IMP, 2}, {"???", &NUL, &IMP, 5},
+ {"LDY", &LDY, &ZPX, 4}, {"LDA", &LDA, &ZPX, 4}, {"LDX", &LDX, &ZPY, 4},
+ {"???", &NUL, &IMP, 4}, {"CLV", &CLV, &IMP, 2}, {"LDA", &LDA, &ABY, 4},
+ {"TSX", &TSX, &IMP, 2}, {"???", &NUL, &IMP, 4}, {"LDY", &LDY, &ABX, 4},
+ {"LDA", &LDA, &ABX, 4}, {"LDX", &LDX, &ABY, 4}, {"???", &NUL, &IMP, 4},
+ {"CPY", &CPY, &IMM, 2}, {"CMP", &CMP, &IZX, 6}, {"???", &NOP, &IMP, 2},
+ {"???", &NUL, &IMP, 8}, {"CPY", &CPY, &ZP0, 3}, {"CMP", &CMP, &ZP0, 3},
+ {"DEC", &DEC, &ZP0, 5}, {"???", &NUL, &IMP, 5}, {"INY", &INY, &IMP, 2},
+ {"CMP", &CMP, &IMM, 2}, {"DEX", &DEX, &IMP, 2}, {"???", &NUL, &IMP, 2},
+ {"CPY", &CPY, &ABS, 4}, {"CMP", &CMP, &ABS, 4}, {"DEC", &DEC, &ABS, 6},
+ {"???", &NUL, &IMP, 6}, {"BNE", &BNE, &REL, 2}, {"CMP", &CMP, &IZY, 5},
+ {"???", &NUL, &IMP, 2}, {"???", &NUL, &IMP, 8}, {"???", &NOP, &IMP, 4},
+ {"CMP", &CMP, &ZPX, 4}, {"DEC", &DEC, &ZPX, 6}, {"???", &NUL, &IMP, 6},
+ {"CLD", &CLD, &IMP, 2}, {"CMP", &CMP, &ABY, 4}, {"NOP", &NOP, &IMP, 2},
+ {"???", &NUL, &IMP, 7}, {"???", &NOP, &IMP, 4}, {"CMP", &CMP, &ABX, 4},
+ {"DEC", &DEC, &ABX, 7}, {"???", &NUL, &IMP, 7}, {"CPX", &CPX, &IMM, 2},
+ {"SBC", &SBC, &IZX, 6}, {"???", &NOP, &IMP, 2}, {"???", &NUL, &IMP, 8},
+ {"CPX", &CPX, &ZP0, 3}, {"SBC", &SBC, &ZP0, 3}, {"INC", &INC, &ZP0, 5},
+ {"???", &NUL, &IMP, 5}, {"INX", &INX, &IMP, 2}, {"SBC", &SBC, &IMM, 2},
+ {"NOP", &NOP, &IMP, 2}, {"???", &SBC, &IMP, 2}, {"CPX", &CPX, &ABS, 4},
+ {"SBC", &SBC, &ABS, 4}, {"INC", &INC, &ABS, 6}, {"???", &NUL, &IMP, 6},
+ {"BEQ", &BEQ, &REL, 2}, {"SBC", &SBC, &IZY, 5}, {"???", &NUL, &IMP, 2},
+ {"???", &NUL, &IMP, 8}, {"???", &NOP, &IMP, 4}, {"SBC", &SBC, &ZPX, 4},
+ {"INC", &INC, &ZPX, 6}, {"???", &NUL, &IMP, 6}, {"SED", &SED, &IMP, 2},
+ {"SBC", &SBC, &ABY, 4}, {"NOP", &NOP, &IMP, 2}, {"???", &NUL, &IMP, 7},
+ {"???", &NOP, &IMP, 4}, {"SBC", &SBC, &ABX, 4}, {"INC", &INC, &ABX, 7},
+ {"???", &NUL, &IMP, 7}
+};
+
diff --git a/6502.h b/6502.h
@@ -29,13 +29,12 @@ typedef enum {
D, /* Decimal mode */
B, /* Break */
U, /* Unused */
- O, /* Overflow */
+ V, /* Overflow */
N /* Negative */
} ST_FLAG;
void CPU_init(void);
void CPU_reset(void);
-void CPU_clock(void);
void CPU_fetch(INS *ins);
void CPU_exec(INS ins);
@@ -46,15 +45,16 @@ void CPU_set_flag(ST_FLAG flag, uint8_t val);
uint8_t CPU_get_flag(ST_FLAG flag);
void CPU_dump(void);
+char *CPU_mode_name(uint8_t (*mode)(void));
void MEM_init(void);
void MEM_dump(void);
+void MEM_dump_page(uint16_t page);
void MEM_load_from_file(char *fp);
-uint8_t MEM_fetch(uint16_t addr);
+uint8_t MEM_read(uint16_t addr);
uint8_t MEM_write(uint16_t addr, uint8_t val);
-char *mode_to_str(uint8_t (*mode)(void));
/* Addresing modes */
uint8_t ABS(void);
diff --git a/main.c b/main.c
@@ -3,27 +3,39 @@
#include <stdio.h>
#include <stdbool.h>
-#define INPUT_FILE_PATH "example.bin"
+#define INPUT_FILE_PATH "10times3.bin"
+
+/* TODO: Finish with CPU instructions implementation */
+/* TODO: add support for command line arguments */
+/* TODO: add proper system monitor (memory dump, cpu registers) */
int main (void) {
INS ins;
+ /* Initialize memory to 0 */
MEM_init();
+
+ /* Load program to memory */
MEM_load_from_file(INPUT_FILE_PATH);
+ /* Initialize registers to 0 */
CPU_init();
CPU_reset();
do {
- CPU_dump();
+ /* Fetch an instruction and increment pc */
CPU_fetch(&ins);
- CPU_exec(ins);
- printf("ins: %s (%s)(%d)\n", ins.name, mode_to_str(ins.mode), ins.cycles);
+ CPU_dump();
+
+ putchar('\n');
- CPU_clock();
+ MEM_dump_page(0x0000);
+ MEM_dump_page(0x8000);
+
+ /* Execute instruction */
+ CPU_exec(ins);
- MEM_dump();
} while(getchar() != 'q');
return 0;