6502

minimal 6502 emulator written in C
Index Commits Files Refs README LICENSE
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:
M6502.c | 431+++++++++++++++++++++++++++++++++++++++++++++++++++++--------------------------
M6502.h | 8++++----
Mmain.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;