OSDN Git Service

adc bug fixed!!!!
[motonesemu/motonesemu.git] / emulator / 6502core.c
index e36fd80..4e9ecf3 100644 (file)
@@ -2,17 +2,23 @@
 #include <string.h>
 #include <libio.h>
 #include "tools.h"
+#include "6502core.h"
 
+/*
+ * 6502 little endian
+ * hi bit > low bit order
+ * but gcc generates low > hi order for bit field
+ * */
 struct status_reg {
-    unsigned int negative       :1;
-    unsigned int overflow       :1;
-    unsigned int researved      :1;
-    unsigned int break_mode     :1;
-    unsigned int decimal        :1;
-    unsigned int irq_disable    :1;
-    unsigned int zero           :1;
     unsigned int carry          :1;
-};
+    unsigned int zero           :1;
+    unsigned int irq_disable    :1;
+    unsigned int decimal        :1;
+    unsigned int break_mode     :1;
+    unsigned int researved      :1;
+    unsigned int overflow       :1;
+    unsigned int negative       :1;
+} __attribute__ ((packed));
 
 struct cpu_6502 {
     unsigned char acc;
@@ -45,21 +51,20 @@ typedef int (handler_6502_t) (void);
  * 
  **/
 
-#define ADDR_MODE_ZP        0
-#define ADDR_MODE_ZP_X      1
-#define ADDR_MODE_ZP_Y      2
-#define ADDR_MODE_ABS       3
-#define ADDR_MODE_ABS_X     4
-#define ADDR_MODE_ABS_Y     5
-#define ADDR_MODE_IND       6
-#define ADDR_MODE_IMP       7
-#define ADDR_MODE_ACC       8
-#define ADDR_MODE_IMM       9
-#define ADDR_MODE_REL       10
-#define ADDR_MODE_INDEX_INDIR       11
-#define ADDR_MODE_INDIR_INDEX       12
-
 #define N_BIT      0x80
+#define V_BIT      0x40
+
+//stack pointer base address
+#define STACK_BASE  0x100
+
+
+/* cycle check must be cleared on release  */
+#define cycle_check
+
+
+#define NMI_VECTOR        0xFFFA
+#define RESET_VECTOR      0xFFFC
+#define IRQ_VECTOR        0xFFFE
 
 struct opcode_map {
     unsigned char   opcode;
@@ -73,8 +78,13 @@ struct opcode_map {
 
 static struct cpu_6502 cpu_reg;
 static struct opcode_map *current_inst;
+
+//exec index is the cycle consumed for execution only.
+//cpu total cycle is current_exec_index + 1 because 
+//fetch cycle uses 1 cycle prior to the execution.
 static int current_exec_index;
 static int exec_done;
+static int intr_done;
 
 unsigned char load_memory(unsigned short addr);
 unsigned short load_addr(unsigned short addr, int cycle);
@@ -84,6 +94,7 @@ unsigned char get_cpu_data_buf(void);
 void set_cpu_data_buf(unsigned char data);
 unsigned short get_cpu_addr_buf(void);
 void set_cpu_addr_buf(unsigned short addr);
+int get_clock_cnt(void);
 
 int func_ADC(void);
 int func_AND(void);
@@ -157,6 +168,8 @@ struct opcode_map opcode_list [255] = {
 /*
  * load from memory in various addressing mode.
  * cpu_data_buf has the output value.
+ *
+ *
  * */
 static int load_addr_mode(int *done) {
     switch (current_inst->addr_mode) {
@@ -189,6 +202,14 @@ static int load_addr_mode(int *done) {
             }
             break;
 
+            /*
+             * Indexed zero page
+             * Wraparound is used when performing the addition so 
+             * the address of the data will always be
+             * in zero page. For example, if the operand is $FF and 
+             * the X register contains $01 the address
+             * of the data will be $0000, not $0100.
+             * */
         case ADDR_MODE_ZP_X:
             //zp indexed with x takes three cycles.
             if (current_exec_index == 0) {
@@ -202,7 +223,7 @@ static int load_addr_mode(int *done) {
                 return TRUE;
             }
             else if (current_exec_index == 2) {
-                unsigned short zp = get_cpu_data_buf();
+                unsigned char zp = get_cpu_data_buf();
                 load_memory(zp);
                 goto addr_mode_done;
             }
@@ -221,7 +242,7 @@ static int load_addr_mode(int *done) {
                 return TRUE;
             }
             else if (current_exec_index == 2) {
-                unsigned short zp = get_cpu_data_buf();
+                unsigned char zp = get_cpu_data_buf();
                 load_memory(zp);
                 goto addr_mode_done;
             }
@@ -264,9 +285,9 @@ static int load_addr_mode(int *done) {
                     unsigned short addr = get_cpu_addr_buf();
                     unsigned short hi_8, added_hi_8;
 
-                    hi_8 = addr >> 8;
+                    hi_8 = (addr >> 8);
                     addr += cpu_reg.x;
-                    added_hi_8 = addr >> 8;
+                    added_hi_8 = (addr >> 8);
 
                     if (hi_8 == added_hi_8) {
                         load_memory(addr);
@@ -274,7 +295,7 @@ static int load_addr_mode(int *done) {
                     }
 
                     //load value in the next cycle.
-                    set_cpu_data_buf(addr);
+                    set_cpu_addr_buf(addr);
                     return TRUE;
                 }
                 else {
@@ -286,7 +307,7 @@ static int load_addr_mode(int *done) {
             }
             else if (current_exec_index == 3) {
                 if (current_inst->cycle_aux) {
-                    unsigned short addr = get_cpu_data_buf();
+                    unsigned short addr = get_cpu_addr_buf();
                     load_memory(addr);
                     goto addr_mode_done;
                 }
@@ -312,9 +333,9 @@ static int load_addr_mode(int *done) {
                     unsigned short addr = get_cpu_addr_buf();
                     unsigned short hi_8, added_hi_8;
 
-                    hi_8 = addr >> 8;
+                    hi_8 = (addr >> 8);
                     addr += cpu_reg.y;
-                    added_hi_8 = addr >> 8;
+                    added_hi_8 = (addr >> 8);
 
                     if (hi_8 == added_hi_8) {
                         load_memory(addr);
@@ -322,7 +343,7 @@ static int load_addr_mode(int *done) {
                     }
 
                     //load value in the next cycle.
-                    set_cpu_data_buf(addr);
+                    set_cpu_addr_buf(addr);
                     return TRUE;
                 }
                 else {
@@ -334,7 +355,7 @@ static int load_addr_mode(int *done) {
             }
             else if (current_exec_index == 3) {
                 if (current_inst->cycle_aux) {
-                    unsigned short addr = get_cpu_data_buf();
+                    unsigned short addr = get_cpu_addr_buf();
                     load_memory(addr);
                     goto addr_mode_done;
                 }
@@ -355,12 +376,14 @@ static int load_addr_mode(int *done) {
                 return TRUE;
             }
             else if (current_exec_index == 2) {
-                unsigned short addr = get_cpu_data_buf();
+                unsigned char addr = get_cpu_data_buf();
                 load_addr(addr, 1);
+                //save addr in the temporary buffer.
+                set_cpu_data_buf(addr);
                 return TRUE;
             }
             else if (current_exec_index == 3) {
-                unsigned short addr = get_cpu_data_buf();
+                unsigned char addr = get_cpu_data_buf();
                 load_addr(addr + 1, 2);
                 return TRUE;
             }
@@ -378,24 +401,26 @@ static int load_addr_mode(int *done) {
                 return TRUE;
             }
             else if (current_exec_index == 1) {
-                unsigned short addr = get_cpu_data_buf();
+                unsigned char addr = get_cpu_data_buf();
                 load_addr(addr, 1);
+                //save addr in the temporary buffer.
+                set_cpu_data_buf(addr);
                 return TRUE;
             }
             else if (current_exec_index == 2) {
-                unsigned short addr = get_cpu_data_buf();
+                unsigned char addr = get_cpu_data_buf();
                 load_addr(addr + 1, 2);
                 return TRUE;
             }
             else if (current_exec_index == 3) {
                 if (current_inst->cycle_aux) {
                     //Add one cycle if indexing across page boundary
-                    unsigned short addr = get_cpu_data_buf();
+                    unsigned short addr = get_cpu_addr_buf();
                     unsigned short hi_8, added_hi_8;
 
-                    hi_8 = addr >> 8;
+                    hi_8 = (addr >> 8);
                     addr += cpu_reg.y;
-                    added_hi_8 = addr >> 8;
+                    added_hi_8 = (addr >> 8);
 
                     if (hi_8 == added_hi_8) {
                         load_memory(addr);
@@ -403,11 +428,11 @@ static int load_addr_mode(int *done) {
                     }
 
                     //load value in the next cycle.
-                    set_cpu_data_buf(addr);
+                    set_cpu_addr_buf(addr);
                     return TRUE;
                 }
                 else {
-                    unsigned short addr = get_cpu_data_buf();
+                    unsigned short addr = get_cpu_addr_buf();
                     addr += cpu_reg.y;
                     load_memory(addr);
                     goto addr_mode_done;
@@ -415,7 +440,7 @@ static int load_addr_mode(int *done) {
             }
             else if (current_exec_index == 4) {
                 if (current_inst->cycle_aux) {
-                    unsigned short addr = get_cpu_data_buf();
+                    unsigned short addr = get_cpu_addr_buf();
                     load_memory(addr);
                     goto addr_mode_done;
                 }
@@ -471,7 +496,7 @@ static int store_addr_mode(unsigned char data, int *done) {
                 return TRUE;
             }
             else if (current_exec_index == 2) {
-                unsigned short zp = get_cpu_data_buf();
+                unsigned char zp = get_cpu_data_buf();
                 store_memory(zp, data);
                 goto addr_mode_done;
             }
@@ -490,7 +515,7 @@ static int store_addr_mode(unsigned char data, int *done) {
                 return TRUE;
             }
             else if (current_exec_index == 2) {
-                unsigned short zp = get_cpu_data_buf();
+                unsigned char zp = get_cpu_data_buf();
                 store_memory(zp, data);
                 goto addr_mode_done;
             }
@@ -530,11 +555,11 @@ static int store_addr_mode(unsigned char data, int *done) {
             else if (current_exec_index == 2) {
                 unsigned short addr = get_cpu_addr_buf();
                 addr += cpu_reg.x;
-                set_cpu_data_buf(addr);
+                set_cpu_addr_buf(addr);
                 return TRUE;
             }
             else if (current_exec_index == 3) {
-                unsigned short addr = get_cpu_data_buf();
+                unsigned short addr = get_cpu_addr_buf();
                 store_memory(addr, data);
                 goto addr_mode_done;
             }
@@ -554,11 +579,11 @@ static int store_addr_mode(unsigned char data, int *done) {
             else if (current_exec_index == 2) {
                 unsigned short addr = get_cpu_addr_buf();
                 addr += cpu_reg.y;
-                set_cpu_data_buf(addr);
+                set_cpu_addr_buf(addr);
                 return TRUE;
             }
             else if (current_exec_index == 3) {
-                unsigned short addr = get_cpu_data_buf();
+                unsigned short addr = get_cpu_addr_buf();
                 store_memory(addr, data);
                 goto addr_mode_done;
             }
@@ -578,12 +603,14 @@ static int store_addr_mode(unsigned char data, int *done) {
                 return TRUE;
             }
             else if (current_exec_index == 2) {
-                unsigned short addr = get_cpu_data_buf();
+                unsigned char addr = get_cpu_data_buf();
                 load_addr(addr, 1);
+                //save addr in the temporary buffer.
+                set_cpu_data_buf(addr);
                 return TRUE;
             }
             else if (current_exec_index == 3) {
-                unsigned short addr = get_cpu_data_buf();
+                unsigned char addr = get_cpu_data_buf();
                 load_addr(addr + 1, 2);
                 return TRUE;
             }
@@ -601,23 +628,25 @@ static int store_addr_mode(unsigned char data, int *done) {
                 return TRUE;
             }
             else if (current_exec_index == 1) {
-                unsigned short addr = get_cpu_data_buf();
+                unsigned char addr = get_cpu_data_buf();
                 load_addr(addr, 1);
+                //save addr in the temporary buffer.
+                set_cpu_data_buf(addr);
                 return TRUE;
             }
             else if (current_exec_index == 2) {
-                unsigned short addr = get_cpu_data_buf();
+                unsigned char addr = get_cpu_data_buf();
                 load_addr(addr + 1, 2);
                 return TRUE;
             }
             else if (current_exec_index == 3) {
-                unsigned short addr = get_cpu_data_buf();
+                unsigned short addr = get_cpu_addr_buf();
                 addr += cpu_reg.y;
-                set_cpu_data_buf(addr);
+                set_cpu_addr_buf(addr);
                 return TRUE;
             }
             else if (current_exec_index == 4) {
-                unsigned short addr = get_cpu_data_buf();
+                unsigned short addr = get_cpu_addr_buf();
                 store_memory(addr, data);
                 goto addr_mode_done;
             }
@@ -633,6 +662,158 @@ addr_mode_done:
     return TRUE;
 }
 
+/*
+ * for inc/dec/shift operation
+ * */
+static int memory_to_memory(int *do_operation, int *done) {
+    switch (current_inst->addr_mode) {
+        case ADDR_MODE_ACC:
+        case ADDR_MODE_IMP:
+        case ADDR_MODE_IMM:
+        case ADDR_MODE_REL:
+        case ADDR_MODE_ZP_Y:
+        case ADDR_MODE_ABS_Y:
+        case ADDR_MODE_INDEX_INDIR:
+        case ADDR_MODE_INDIR_INDEX:
+            //not supported.
+            return FALSE;
+
+        case ADDR_MODE_ZP:
+            //zp takes 4 cycles.
+            if (current_exec_index == 0) {
+                load_memory(cpu_reg.pc);
+                cpu_reg.pc++;
+                return TRUE;
+            }
+            else if (current_exec_index == 1) {
+                unsigned short zp = get_cpu_data_buf();
+                load_memory(zp);
+                set_cpu_addr_buf(zp);
+                return TRUE;
+            }
+            else if (current_exec_index == 2) {
+                //arithmetic operation here!!
+                //result is set in cpu_data_buf
+                *do_operation = TRUE;
+                return TRUE;
+            }
+            else if (current_exec_index == 3) {
+                unsigned short zp = get_cpu_addr_buf();
+                unsigned short data = get_cpu_data_buf();
+                store_memory(zp, data);
+                goto mm_done;
+            }
+            break;
+
+        case ADDR_MODE_ZP_X:
+            //zp indexed with x takes 5 cycles.
+            if (current_exec_index == 0) {
+                load_memory(cpu_reg.pc);
+                cpu_reg.pc++;
+                return TRUE;
+            }
+            else if (current_exec_index == 1) {
+                unsigned char imm = get_cpu_data_buf();
+                set_cpu_data_buf(imm + cpu_reg.x);
+                return TRUE;
+            }
+            else if (current_exec_index == 2) {
+                unsigned char zp = get_cpu_data_buf();
+                load_memory(zp);
+                set_cpu_addr_buf(zp);
+                return TRUE;
+            }
+            else if (current_exec_index == 3) {
+                //arithmetic operation here!!
+                //result is set in cpu_data_buf
+                *do_operation = TRUE;
+                return TRUE;
+            }
+            else if (current_exec_index == 4) {
+                unsigned char zp = get_cpu_addr_buf();
+                unsigned short data = get_cpu_data_buf();
+                store_memory(zp, data);
+                goto mm_done;
+            }
+            break;
+
+        case ADDR_MODE_ABS:
+            //takes 5 cycles.
+            if (current_exec_index == 0) {
+                load_addr(cpu_reg.pc, 1);
+                cpu_reg.pc++;
+                return TRUE;
+            }
+            else if (current_exec_index == 1) {
+                load_addr(cpu_reg.pc, 2);
+                cpu_reg.pc++;
+                return TRUE;
+            }
+            else if (current_exec_index == 2) {
+                unsigned short addr = get_cpu_addr_buf();
+                load_memory(addr);
+                return TRUE;
+            }
+            else if (current_exec_index == 3) {
+                //arithmetic operation here!!
+                //result is set in cpu_data_buf
+                *do_operation = TRUE;
+                return TRUE;
+            }
+            else if (current_exec_index == 4) {
+                unsigned short addr = get_cpu_addr_buf();
+                unsigned short data = get_cpu_data_buf();
+                store_memory(addr, data);
+                goto mm_done;
+            }
+            break;
+
+        case ADDR_MODE_ABS_X:
+            //abs indexed with x takes 6 cycles.
+            if (current_exec_index == 0) {
+                load_addr(cpu_reg.pc, 1);
+                cpu_reg.pc++;
+                return TRUE;
+            }
+            else if (current_exec_index == 1) {
+                load_addr(cpu_reg.pc, 2);
+                cpu_reg.pc++;
+                return TRUE;
+            }
+            else if (current_exec_index == 2) {
+                unsigned short abs = get_cpu_addr_buf();
+                set_cpu_addr_buf(abs + cpu_reg.x);
+                return TRUE;
+            }
+            else if (current_exec_index == 3) {
+                unsigned short addr = get_cpu_addr_buf();
+                load_memory(addr);
+                return TRUE;
+            }
+            else if (current_exec_index == 4) {
+                //arithmetic operation here!!
+                //result is set in cpu_data_buf
+                *do_operation = TRUE;
+                return TRUE;
+            }
+            else if (current_exec_index == 5) {
+                unsigned short addr = get_cpu_addr_buf();
+                unsigned short data = get_cpu_data_buf();
+                store_memory(addr, data);
+                goto mm_done;
+            }
+            break;
+
+        default:
+            return FALSE;
+    }
+    return FALSE;
+
+mm_done:
+    *done = TRUE;
+    return TRUE;
+}
+
 
 /*-------------   flag operation..  ---------------------*/
 
@@ -650,19 +831,194 @@ static void set_negative(unsigned char data) {
         cpu_reg.status.negative = 0;
 }
 
+static void set_CMP_carry(unsigned char data, unsigned char cmp) {
+    if (data >= cmp)
+        cpu_reg.status.carry = 1;
+    else
+        cpu_reg.status.carry = 0;
+}
+
+static void set_BIT_overflow(unsigned char data) {
+    if (data & V_BIT)
+        cpu_reg.status.overflow = 1;
+    else
+        cpu_reg.status.overflow = 0;
+}
+
+/*
+ * c Set if unsigned overflow; cleared if valid unsigned result.
+ * */
+static void set_ADD_carry(unsigned char d1, unsigned char d2, unsigned char d3) {
+    unsigned short d1_short = d1;
+    unsigned short d2_short = d2;
+    unsigned short d3_short = d3;
+    if (d1_short + d2_short + d3_short > 0xff)
+        cpu_reg.status.carry = 1;
+    else
+        cpu_reg.status.carry = 0;
+}
+
+/*
+ * v Set if signed overflow; cleared if valid signed result.
+ * */
+static void set_ADD_overflow(char d1, char d2, char d3) {
+    short d1_short = d1;
+    short d2_short = d2;
+    short d3_short = d3;
+    if (d1_short + d2_short + d3_short > +127 || d1_short + d2_short + d3_short < -128 )
+        cpu_reg.status.overflow = 1;
+    else
+        cpu_reg.status.overflow = 0;
+}
+
+/*
+ * c Set if unsigned borrow not required; cleared if unsigned borrow.
+ * */
+static void set_SUB_carry(unsigned char d1, unsigned char d2, unsigned char d3) {
+    unsigned short d1_short = d1;
+    unsigned short d2_short = d2;
+    unsigned short d3_short = d3;
+
+    if (d1_short >=  d2_short + d3_short)
+        cpu_reg.status.carry = 1;
+    else
+        cpu_reg.status.carry = 0;
+}
+
+/*
+ * v Set if signed borrow not required; cleared if signed borrow.
+ * */
+static void set_SUB_overflow(char d1, char d2, char d3) {
+    short d1_short = d1;
+    short d2_short = d2;
+    short d3_short = d3;
+    if (d1_short >= d2_short + d3_short)
+        cpu_reg.status.overflow = 1;
+    else
+        cpu_reg.status.overflow = 0;
+}
+
+/*-------------   stack operation..  ---------------------*/
+//stack operation takes two cycles.
+static void push(unsigned char data) {
+    store_memory(STACK_BASE + cpu_reg.sp, data);
+    cpu_reg.sp--;
+}
+
+static unsigned char pop(void) {
+    cpu_reg.sp++;
+    return load_memory(STACK_BASE + cpu_reg.sp);
+}
 
 /*---------- instruction implementations.   -----------------*/
 
+/*
+ * Add Memory to Accumulator with Carry: ADC
+ * A + M + C -> A
+ * Flags: N, V, Z, C
+ * */
 int func_ADC(void) {
-    return FALSE;
+    int done = FALSE;
+    int ret;
+    unsigned char data;
+    unsigned char old_carry;
+
+    ret = load_addr_mode(&done);
+    if (!ret)
+        return FALSE;
+
+    if (!done) 
+        return TRUE;
+
+    data = get_cpu_data_buf();
+    old_carry = cpu_reg.status.carry;
+    //signed, unsigned overflow check.
+    set_ADD_carry(cpu_reg.acc, cpu_reg.status.carry, data);
+    set_ADD_overflow(cpu_reg.acc, cpu_reg.status.carry, data);
+    //add data with carry to accumurator.
+    cpu_reg.acc += data + old_carry;
+
+    // N/Z flags set.
+    set_negative(cpu_reg.acc);
+    set_zero(cpu_reg.acc);
+
+    exec_done = TRUE;
+    return TRUE;
 }
 
+/*
+ * AND Memory with Accumulator: AND
+ * A & M -> A
+ * Flags: N, Z
+ * */
 int func_AND(void) {
-    return FALSE;
+    int done = FALSE;
+    int ret;
+    unsigned char data;
+
+    ret = load_addr_mode(&done);
+    if (!ret)
+        return FALSE;
+
+    if (!done) 
+        return TRUE;
+
+    data = get_cpu_data_buf();
+    cpu_reg.acc = cpu_reg.acc & data;
+    //N/Z flags set.
+    set_negative(cpu_reg.acc);
+    set_zero(cpu_reg.acc);
+
+    exec_done = TRUE;
+    return TRUE;
 }
 
+/*
+ * Arithmetic Shift Left One Bit: ASL
+ * C <- 7 6 5 4 3 2 1 0 <- 0
+ * Flags: N, Z, C
+ * */
 int func_ASL(void) {
-    return FALSE;
+    int done = FALSE;
+    int operation = FALSE;
+    unsigned char data;
+    int ret;
+
+    if (current_inst->addr_mode == ADDR_MODE_ACC) {
+        unsigned char op_data = cpu_reg.acc;
+        //set carry flag from the pre-opration value.
+        cpu_reg.status.carry = ((op_data & 0x80) != 0);
+        cpu_reg.acc = (op_data << 1);
+        set_negative(cpu_reg.acc);
+        set_zero(cpu_reg.acc);
+        goto acc_done;
+    }
+    else {
+        ret = memory_to_memory(&operation, &done);
+        if (!ret)
+            return FALSE;
+
+        if (operation) {
+            unsigned char op_data = get_cpu_data_buf();
+            //set carry flag from the pre-opration value.
+            cpu_reg.status.carry = ((op_data & 0x80) != 0);
+            op_data = (op_data << 1);
+            set_cpu_data_buf(op_data);
+            return TRUE;
+        }
+    }
+
+    if (!done) 
+        return TRUE;
+
+    // N/Z flags set.
+    data = get_cpu_data_buf();
+    set_negative(data);
+    set_zero(data);
+
+acc_done:
+    exec_done = TRUE;
+    return TRUE;
 }
 
 static int branch(unsigned char condition) {
@@ -685,7 +1041,7 @@ static int branch(unsigned char condition) {
         unsigned short addr = cpu_reg.pc;
         unsigned short br_addr = cpu_reg.pc + rel;
 
-        if (addr >> 8 == br_addr >> 8) {
+        if ((addr >> 8) == (br_addr >> 8)) {
             //in page branch.
             cpu_reg.pc = br_addr;
             exec_done = TRUE;
@@ -733,8 +1089,51 @@ int func_BEQ(void) {
     return branch(cpu_reg.status.zero == 1);
 }
 
-int func_BIT(void) {
-    return FALSE;
+/*
+ * Test Bits in Memory with Accumulator: BIT
+ * A & M
+ * Flags: N = M7, V = M6, Z
+ * */
+int func_BIT(void) {
+    int done = FALSE;
+    int ret;
+    unsigned char cmp;
+
+    ret = load_addr_mode(&done);
+    if (!ret)
+        return FALSE;
+
+    if (!done) 
+        return TRUE;
+
+    cmp = get_cpu_data_buf();
+    //cmp N/V/Z flags set.
+    /*
+     * The BIT instruction really performs two distinct operations.
+     * First, it directly transfers the highest and next to highest 
+     * bits of the memory operand (that is, seven and six if m
+     * = 1, or fifteen and fourteen if m = 0) to the n and v flags. 
+     * It does this without modifying the value in the
+     * accumulator, making it useful for testing the sign of a value 
+     * in memory without loading it into one of the
+     * registers. An exception to this is the case where the immediate 
+     * addressing mode is used with the BIT
+     * instruction: since it serves no purpose to test the bits of a 
+     * constant value, the n and v flags are left unchanged in
+     * this one case.
+     * BITs second operation is to logically AND the value of the 
+     * memory operand with the value in the
+     * accumulator, conditioning the z flag in the status register to 
+     * reflect whether or not the result of the ANDing was
+     * zero or not, but without storing the result in the accumulator
+     * */
+    //6502 core supports zp and abs only
+    set_negative(cmp);
+    set_BIT_overflow(cmp);
+    set_zero(cpu_reg.acc & cmp);
+
+    exec_done = TRUE;
+    return TRUE;
 }
 
 /*
@@ -786,36 +1185,175 @@ int func_BVS(void) {
     return branch(cpu_reg.status.overflow == 1);
 }
 
+/*
+ * Clear Carry Flag: CLC
+ * 0 -> C
+ * Flags: C = 0
+ * */
 int func_CLC(void) {
-    return FALSE;
+    cpu_reg.status.carry = 0;
+    exec_done = TRUE;
+    return TRUE;
 }
 
+/*
+ * Clear Decimal Mode: CLD
+ * 0 -> D
+ * Flags: D = 0
+ *
+ * NOTE: Decimal mode is not implemented on NES core.
+ * */
 int func_CLD(void) {
-    return FALSE;
+    cpu_reg.status.decimal = 0;
+    exec_done = TRUE;
+    return TRUE;
 }
 
+/*
+ * Clear Interrupt Disable Status: CLI
+ * 0 -> I
+ * Flags: I = 0
+ * */
 int func_CLI(void) {
-    return FALSE;
+    cpu_reg.status.irq_disable = 0;
+    exec_done = TRUE;
+    return TRUE;
 }
 
+/*
+ * Clear Overflow Flag: CLV
+ * 0 -> V
+ * Flags: V = 0
+ * */
 int func_CLV(void) {
-    return FALSE;
+    cpu_reg.status.overflow = 0;
+    exec_done = TRUE;
+    return TRUE;
 }
 
+/*
+ * Compare Memory and Accumulator: CMP
+ * A - M
+ * Flags: N, Z, C
+ * */
 int func_CMP(void) {
-    return FALSE;
+    int done = FALSE;
+    int ret;
+    unsigned char cmp;
+
+    ret = load_addr_mode(&done);
+    if (!ret)
+        return FALSE;
+
+    if (!done) 
+        return TRUE;
+
+    cmp = get_cpu_data_buf();
+    //cmp C/N/Z flags set.
+    set_CMP_carry(cpu_reg.acc, cmp);
+    set_negative(cpu_reg.acc - cmp);
+    set_zero(cpu_reg.acc - cmp);
+
+    exec_done = TRUE;
+    return TRUE;
 }
 
+/*
+ * Compare Memory and Index X: CPX
+ * X - M
+ * Flags: N, Z, C
+ * */
 int func_CPX(void) {
-    return FALSE;
+    int done = FALSE;
+    int ret;
+    unsigned char cmp;
+
+    ret = load_addr_mode(&done);
+    if (!ret)
+        return FALSE;
+
+    if (!done) 
+        return TRUE;
+
+    cmp = get_cpu_data_buf();
+    //cmp C/N/Z flags set.
+    set_CMP_carry(cpu_reg.x, cmp);
+    set_negative(cpu_reg.x - cmp);
+    set_zero(cpu_reg.x - cmp);
+
+    exec_done = TRUE;
+    return TRUE;
 }
 
+/*
+ * Compare Memory with Index Y: CPY
+ * Y - M
+ * Flags: N, Z, C
+ * */
 int func_CPY(void) {
-    return FALSE;
+    int done = FALSE;
+    int ret;
+    unsigned char cmp;
+
+    ret = load_addr_mode(&done);
+    if (!ret)
+        return FALSE;
+
+    if (!done) 
+        return TRUE;
+
+    cmp = get_cpu_data_buf();
+    //cmp C/N/Z flags set.
+
+/*
+ * Subtract the data located at the effective address specified 
+ * by the operand from the contents of the Y
+ * register, setting the carry, zero, and negative flags based 
+ * on the result, but without altering the contents of either
+ * the memory location or the register. The comparison is of 
+ * unsigned values only (expect for signed comparison
+ * for equality).
+ * */
+    set_CMP_carry(cpu_reg.y, cmp);
+    set_negative(cpu_reg.y - cmp);
+    set_zero(cpu_reg.y - cmp);
+
+    exec_done = TRUE;
+    return TRUE;
 }
 
+/*
+ * Decrement Memory by One: DEC
+ * M - 1 -> M
+ * Flags: N, Z
+ * */
 int func_DEC(void) {
-    return FALSE;
+    int done = FALSE;
+    int operation = FALSE;
+    unsigned char data;
+    int ret;
+
+    ret = memory_to_memory(&operation, &done);
+    if (!ret)
+        return FALSE;
+
+    if (operation) {
+        unsigned char op_data = get_cpu_data_buf();
+        op_data--;
+        set_cpu_data_buf(op_data);
+        return TRUE;
+    }
+
+    if (!done) 
+        return TRUE;
+
+    // N/Z flags set.
+    data = get_cpu_data_buf();
+    set_negative(data);
+    set_zero(data);
+
+    exec_done = TRUE;
+    return TRUE;
 }
 
 /*
@@ -850,12 +1388,65 @@ int func_DEY(void) {
     return TRUE;
 }
 
+/*
+ * Exclusive-OR Memory with Accumulator: EOR
+ * A ^ M -> A
+ * Flags: N, Z
+ * */
 int func_EOR(void) {
-    return FALSE;
+    int done = FALSE;
+    int ret;
+    unsigned char data;
+
+    ret = load_addr_mode(&done);
+    if (!ret)
+        return FALSE;
+
+    if (!done) 
+        return TRUE;
+
+    data = get_cpu_data_buf();
+    cpu_reg.acc = cpu_reg.acc ^ data;
+    //N/Z flags set.
+    set_negative(cpu_reg.acc);
+    set_zero(cpu_reg.acc);
+
+    exec_done = TRUE;
+    return TRUE;
 }
 
+/*
+ * Increment Memory by One: INC
+ * M + 1 -> M
+ * Flags: N, Z
+ * */
 int func_INC(void) {
-    return FALSE;
+    int done = FALSE;
+    int operation = FALSE;
+    unsigned char data;
+    int ret;
+
+    ret = memory_to_memory(&operation, &done);
+    if (!ret)
+        return FALSE;
+
+    if (operation) {
+        unsigned char op_data = get_cpu_data_buf();
+        op_data++;
+        set_cpu_data_buf(op_data);
+        return TRUE;
+    }
+
+    if (!done) 
+        return TRUE;
+
+    // N/Z flags set.
+    data = get_cpu_data_buf();
+    set_negative(data);
+    set_zero(data);
+
+    exec_done = TRUE;
+    return TRUE;
 }
 
 /*
@@ -885,11 +1476,110 @@ int func_INY(void) {
     return TRUE;
 }
 
-int func_JMP(void) {
+static int jmp(int cycle, int *done) {
+    switch (current_inst->addr_mode) {
+        case ADDR_MODE_ABS:
+            //takes 2 cycles.
+            if (cycle == 0) {
+                load_addr(cpu_reg.pc, 1);
+                cpu_reg.pc++;
+                return TRUE;
+            }
+            else if (cycle == 1) {
+                load_addr(cpu_reg.pc, 2);
+                cpu_reg.pc++;
+                *done = TRUE;
+                return TRUE;
+            }
+            break;
+
+        case ADDR_MODE_IND:
+            //takes 4 cycles.
+            if (cycle == 0) {
+                load_addr(cpu_reg.pc, 1);
+                cpu_reg.pc++;
+                return TRUE;
+            }
+            else if (cycle == 1) {
+                load_addr(cpu_reg.pc, 2);
+                cpu_reg.pc++;
+                return TRUE;
+            }
+            else if (cycle == 2) {
+                load_memory(get_cpu_addr_buf());
+                return TRUE;
+            }
+            else if (cycle == 3) {
+                unsigned char low, hi;
+                unsigned short addr;
+                low = get_cpu_data_buf();
+                hi = load_memory(get_cpu_addr_buf() + 1);
+                addr = (hi << 8) | low;
+                set_cpu_addr_buf(addr);
+                *done = TRUE;
+                return TRUE;
+            }
+            break;
+
+        default:
+            return FALSE;
+    }
     return FALSE;
 }
 
+/*
+ * Jump to New Location: JMP
+ * Jump to new location
+ * Flags: none
+ * */
+int func_JMP(void) {
+    int done = FALSE;
+    int ret;
+
+    ret = jmp(current_exec_index, &done);
+    if (!ret)
+        return FALSE;
+
+    if (!done) 
+        return TRUE;
+
+    cpu_reg.pc = get_cpu_addr_buf();
+
+    exec_done = TRUE;
+    return TRUE;
+}
+
+/*
+ * Jump to New Location Saving Return Address: JSR
+ * Jump to Subroutine
+ * Flags: none
+ * */
 int func_JSR(void) {
+    int done = FALSE;
+
+    //cycle 1
+    if (current_exec_index == 0) {
+        //save return addr(-1) hi.
+        //pc + 1 => jsr abslo abshi - 1
+        push((cpu_reg.pc + 1) >> 8);
+        return TRUE;
+    }
+    //cycle 2
+    else if (current_exec_index == 1) {
+        //save return addr(-1) low.
+        push(cpu_reg.pc + 1);
+        return TRUE;
+    }
+    //cycle 3,4
+    else if (current_exec_index < 4) {
+        return jmp(current_exec_index - 2, &done);
+    }
+    //cycle 5
+    else if (current_exec_index == 4) {
+        cpu_reg.pc = get_cpu_addr_buf();
+        exec_done = TRUE;
+        return TRUE;
+    }
     return FALSE;
 }
 
@@ -968,59 +1658,433 @@ int func_LDY(void) {
     return TRUE;
 }
 
+/*
+ * Logical Shift Right One Bit: LSR
+ * 0 -> 7 6 5 4 3 2 1 0 -> C
+ * Flags: N, Z, C
+ * */
 int func_LSR(void) {
-    return FALSE;
+    int done = FALSE;
+    int operation = FALSE;
+    unsigned char data;
+    int ret;
+
+    if (current_inst->addr_mode == ADDR_MODE_ACC) {
+        unsigned char op_data = cpu_reg.acc;
+        //set carry flag from the pre-opration value.
+        cpu_reg.status.carry = (op_data & 0x01);
+        cpu_reg.acc = (op_data >> 1);
+        set_negative(cpu_reg.acc);
+        set_zero(cpu_reg.acc);
+        goto acc_done;
+    }
+    else {
+        ret = memory_to_memory(&operation, &done);
+        if (!ret)
+            return FALSE;
+
+        if (operation) {
+            unsigned char op_data = get_cpu_data_buf();
+            //set carry flag from the pre-opration value.
+            cpu_reg.status.carry = (op_data & 0x01);
+            op_data = (op_data >> 1);
+            set_cpu_data_buf(op_data);
+            return TRUE;
+        }
+    }
+
+    if (!done) 
+        return TRUE;
+
+    // N/Z flags set.
+    data = get_cpu_data_buf();
+    set_negative(data);
+    set_zero(data);
+
+acc_done:
+    exec_done = TRUE;
+    return TRUE;
 }
 
 int func_NOP(void) {
     return FALSE;
 }
 
+/*
+ * OR Memory with Accumulator: ORA
+ * A | M -> A
+ * Flags: N, Z
+ * */
 int func_ORA(void) {
+    int done = FALSE;
+    int ret;
+    unsigned char data;
+
+    ret = load_addr_mode(&done);
+    if (!ret)
+        return FALSE;
+
+    if (!done) 
+        return TRUE;
+
+    data = get_cpu_data_buf();
+    cpu_reg.acc = cpu_reg.acc | data;
+    //N/Z flags set.
+    set_negative(cpu_reg.acc);
+    set_zero(cpu_reg.acc);
+
+    exec_done = TRUE;
+    return TRUE;
+}
+
+/*
+ * push takes 2 cycles.
+ * */
+static int push_op(unsigned char data, int *done) {
+    //cycle 1
+    if (current_exec_index == 0) {
+        push(data);
+        return TRUE;
+    }
+    //cycle 2
+    else if (current_exec_index == 1) {
+        //cycle 2 doesn't do enything.
+        *done = TRUE;
+        return TRUE;
+    }
     return FALSE;
 }
 
+/*
+ * Push Accumulator on Stack: PHA
+ * A -> S
+ * Flags: none
+ * */
 int func_PHA(void) {
-    return FALSE;
+    int ret;
+    int done = FALSE;
+    ret = push_op(cpu_reg.acc, &done);
+    exec_done = done;
+    return ret;
 }
 
 int func_PHP(void) {
     return FALSE;
 }
 
-int func_PLA(void) {
+/*
+ * pull takes 3 cycles.
+ * */
+static int pull_op(int *done) {
+    //cycle 1
+    if (current_exec_index == 0) {
+        pop();
+        return TRUE;
+    }
+    //cycle 2
+    else if (current_exec_index == 1) {
+        //cycle 2 doesn't do enything.
+        return TRUE;
+    }
+    //cycle 3
+    else if (current_exec_index == 2) {
+        //cycle 3 caller must xfer data from cpu data buf
+        *done = TRUE;
+        return TRUE;
+    }
     return FALSE;
 }
 
+/*
+ * Pull Accumulator from Stack: PLA
+ * S -> A
+ * Flags: N, Z
+ * */
+int func_PLA(void) {
+    int ret;
+    int done = FALSE;
+    ret = pull_op(&done);
+    if (done) {
+        cpu_reg.acc = get_cpu_data_buf();
+        set_negative(cpu_reg.acc);
+        set_zero(cpu_reg.acc);
+    }
+    exec_done = done;
+    return ret;
+}
+
 int func_PLP(void) {
     return FALSE;
 }
 
+/*
+ * Rotate Left One Bit: ROL
+ * C <- 7 6 5 4 3 2 1 0 <- C
+ * Flags: N, Z, C
+ * */
 int func_ROL(void) {
-    return FALSE;
+    int done = FALSE;
+    int operation = FALSE;
+    unsigned char data;
+    int ret;
+
+    if (current_inst->addr_mode == ADDR_MODE_ACC) {
+        unsigned char op_data = cpu_reg.acc;
+        unsigned char old_carry = cpu_reg.status.carry;
+
+        //set carry flag from the pre-opration value.
+        cpu_reg.status.carry = ((op_data & 0x80) != 0);
+        cpu_reg.acc = (op_data << 1);
+        if (old_carry)
+            cpu_reg.acc |= 0x01;
+        set_negative(cpu_reg.acc);
+        set_zero(cpu_reg.acc);
+        goto acc_done;
+    }
+    else {
+        ret = memory_to_memory(&operation, &done);
+        if (!ret)
+            return FALSE;
+
+        if (operation) {
+            unsigned char op_data = get_cpu_data_buf();
+            unsigned char old_carry = cpu_reg.status.carry;
+
+            //set carry flag from the pre-opration value.
+            cpu_reg.status.carry = ((op_data & 0x80) != 0);
+            op_data = (op_data << 1);
+            if (old_carry)
+                op_data |= 0x01;
+            set_cpu_data_buf(op_data);
+            return TRUE;
+        }
+    }
+
+    if (!done) 
+        return TRUE;
+
+    // N/Z flags set.
+    data = get_cpu_data_buf();
+    set_negative(data);
+    set_zero(data);
+
+acc_done:
+    exec_done = TRUE;
+    return TRUE;
 }
 
+/*
+ * Rotate Right One Bit: ROR
+ * C -> 7 6 5 4 3 2 1 0 -> C
+ * Flags: N, Z, C
+ * */
 int func_ROR(void) {
-    return FALSE;
+    int done = FALSE;
+    int operation = FALSE;
+    unsigned char data;
+    int ret;
+
+    if (current_inst->addr_mode == ADDR_MODE_ACC) {
+        unsigned char op_data = cpu_reg.acc;
+        unsigned char old_carry = cpu_reg.status.carry;
+
+        //set carry flag from the pre-opration value.
+        cpu_reg.status.carry = (op_data & 0x01);
+        cpu_reg.acc = (op_data >> 1);
+        if (old_carry)
+            cpu_reg.acc |= 0x80;
+        set_negative(cpu_reg.acc);
+        set_zero(cpu_reg.acc);
+        goto acc_done;
+    }
+    else {
+        ret = memory_to_memory(&operation, &done);
+        if (!ret)
+            return FALSE;
+
+        if (operation) {
+            unsigned char op_data = get_cpu_data_buf();
+            unsigned char old_carry = cpu_reg.status.carry;
+
+            //set carry flag from the pre-opration value.
+            cpu_reg.status.carry = (op_data & 0x01);
+            op_data = (op_data >> 1);
+            if (old_carry)
+                op_data |= 0x80;
+            set_cpu_data_buf(op_data);
+            return TRUE;
+        }
+    }
+
+    if (!done) 
+        return TRUE;
+
+    // N/Z flags set.
+    data = get_cpu_data_buf();
+    set_negative(data);
+    set_zero(data);
+
+acc_done:
+    exec_done = TRUE;
+    return TRUE;
 }
 
+/*
+ * Return from Interrupt: RTI
+ * Return from Interrupt
+ * Flags: all
+ * */
 int func_RTI(void) {
+    //cycle 1
+    if (current_exec_index == 0) {
+        //pop statu reg.
+        pop();
+        return TRUE;
+    }
+    //cycle 2 
+    else if (current_exec_index == 1) {
+        unsigned char data;
+        //set status reg
+        data = get_cpu_data_buf();
+        memcpy(&cpu_reg.status, &data, sizeof(data));
+        //pop return addr low.
+        pop();
+        return TRUE;
+    }
+    //cycle 3
+    else if (current_exec_index == 2) {
+        //set return addr low.
+        set_cpu_addr_buf(get_cpu_data_buf());
+        //pop return addr hi.
+        pop();
+        return TRUE;
+    }
+    //cycle 4
+    else if (current_exec_index == 3) {
+        unsigned char hi, lo;
+        unsigned short addr;
+
+        //set return addr hi
+        lo = get_cpu_addr_buf();
+        hi = get_cpu_data_buf();
+        addr = (hi << 8) | lo;
+        set_cpu_addr_buf(addr);
+        return TRUE;
+    }
+    //cycle 5
+    else if (current_exec_index == 4) {
+        //set pc = addr
+        cpu_reg.pc = get_cpu_addr_buf();
+        exec_done = TRUE;
+        return TRUE;
+    }
     return FALSE;
 }
 
+/*
+ * Return from Subroutine: RTS
+ * Return from Subroutine
+ * Flags: none
+ * */
 int func_RTS(void) {
+
+    //cycle 1
+    if (current_exec_index == 0) {
+        //pop return addr low.
+        pop();
+        return TRUE;
+    }
+    //cycle 2 
+    else if (current_exec_index == 1) {
+        //set return addr low.
+        set_cpu_addr_buf(get_cpu_data_buf());
+        return TRUE;
+    }
+    //cycle 3
+    else if (current_exec_index == 2) {
+        //pop return addr hi.
+        pop();
+        return TRUE;
+    }
+    //cycle 4
+    else if (current_exec_index == 3) {
+        unsigned char hi, lo;
+        unsigned short addr;
+
+        //set return addr hi
+        lo = get_cpu_addr_buf();
+        hi = get_cpu_data_buf();
+        addr = (hi << 8) | lo;
+        set_cpu_addr_buf(addr);
+        return TRUE;
+    }
+    //cycle 5
+    else if (current_exec_index == 4) {
+        //set pc = addr + 1
+        cpu_reg.pc = get_cpu_addr_buf() + 1;
+        exec_done = TRUE;
+        return TRUE;
+    }
     return FALSE;
 }
 
+/*
+ * Subtract Memory from Accumulator with Borrow: SBC
+ * A - M - ~C -> A
+ * Flags: N, V, Z, C
+ * */
 int func_SBC(void) {
-    return FALSE;
+    int done = FALSE;
+    int ret;
+    unsigned char data;
+    unsigned char c_comp;
+
+    ret = load_addr_mode(&done);
+    if (!ret)
+        return FALSE;
+
+    if (!done) 
+        return TRUE;
+
+    data = get_cpu_data_buf();
+    c_comp = (cpu_reg.status.carry == 0 ? 1 : 0);
+
+    //signed, unsigned overflow check.
+    set_SUB_carry(cpu_reg.acc, data, c_comp);
+    set_SUB_overflow(cpu_reg.acc, data, c_comp);
+
+    //subtract data with carry to accumurator.
+    cpu_reg.acc = cpu_reg.acc - data - c_comp;
+
+    // N/Z flags set.
+    set_negative(cpu_reg.acc);
+    set_zero(cpu_reg.acc);
+
+    exec_done = TRUE;
+    return TRUE;
 }
 
+/*
+ * Set Carry Flag: SEC
+ * 1 -> C
+ * Flags: C = 1
+ * */
 int func_SEC(void) {
-    return FALSE;
+    cpu_reg.status.carry = 1;
+    exec_done = TRUE;
+    return TRUE;
 }
 
+/*
+ * Set Decimal Mode: SED
+ * 1 -> D
+ * Flags: D = 1
+ *
+ * NOTE: decimal mode is not supported on NES core
+ * */
 int func_SED(void) {
+    cpu_reg.status.decimal = 1;
+    fprintf(stderr, "decimal mode is not supported!!!\n");
     return FALSE;
 }
 
@@ -1183,6 +2247,8 @@ int func_TYA(void) {
     return TRUE;
 }
 
+/* ------------------     6502 execution..      ------------------- */
+
 /*
  * decode6502:
  * return execution cycle count
@@ -1194,11 +2260,11 @@ int decode6502(unsigned char inst) {
         return FALSE;
     }
 
-    dprint("decode inst: %02x > %s, %d cycle, %d len\n", 
+    /*dprint("decode inst: %02x > %s, %d cycle, %d len\n", 
             inst, omap->mnemonic, omap->cycle, omap->inst_len);
+*/
 
     current_inst = omap;
-    current_exec_index = 0;
 
     return TRUE;
 }
@@ -1206,8 +2272,10 @@ int decode6502(unsigned char inst) {
 int test_and_set_exec(void) {
     int ret;
     ret = exec_done;
-    if (exec_done)
+    if (exec_done) {
         exec_done = FALSE;
+        current_exec_index = 0;
+    }
     return ret;
 }
 
@@ -1215,6 +2283,107 @@ int execute6502(void) {
     int ret;
     ret = current_inst->func();
     current_exec_index++;
+
+#ifdef cycle_check
+    if (exec_done && (current_inst->cycle - 1 != current_exec_index)) {
+        if (current_inst->cycle_aux && (
+                    current_inst->addr_mode == ADDR_MODE_ABS_X ||
+                    current_inst->addr_mode == ADDR_MODE_ABS_Y ||
+                    current_inst->addr_mode == ADDR_MODE_INDIR_INDEX ) && 
+                (current_inst->cycle == current_exec_index)) {
+            ;
+        }
+        else if ((current_inst->addr_mode == ADDR_MODE_REL) && 
+                ((current_inst->cycle == current_exec_index) ||
+                (current_inst->cycle + 1 == current_exec_index ))) {
+            ;
+        }
+        else {
+            fprintf(stderr, "instruction cycle check error!!\n");
+            return FALSE;
+        }
+    }
+#endif
+
+    return ret;
+}
+
+int reset_exec6502(void) {
+    switch (current_exec_index++) {
+        case 0:
+            //step 1: load intvec low.
+            load_addr(RESET_VECTOR, 1);
+            return TRUE;
+        case 1:
+            //step 2: load intvec hi.
+            load_addr(RESET_VECTOR + 1, 2);
+            return TRUE;
+        case 2:
+            //step 3: set pc
+            cpu_reg.pc = get_cpu_addr_buf();
+            //set status flag
+            cpu_reg.status.decimal = 0;
+            cpu_reg.status.irq_disable = 1;
+            intr_done = TRUE;
+            return TRUE;
+    }
+    return FALSE;
+}
+
+int reset6502(void) {
+    current_exec_index = 0;
+    return reset_exec6502();
+}
+
+int nmi6502(void) {
+    dprint("nmi...\n");
+
+    //nmi6502 is always called when current instruction execution is done.
+    switch (current_exec_index++) {
+        case 0:
+            //first: push pc hi.
+            push(cpu_reg.pc >> 8);
+            return TRUE;
+        case 1:
+            //second: push pc low.
+            push(cpu_reg.pc);
+            return TRUE;
+        case 2:
+            {
+                //step 3, push status_reg
+                unsigned char stat;
+                memcpy(&stat, &cpu_reg.status, sizeof(stat));
+                push(stat);
+                return TRUE;
+            }
+        case 3:
+            //step 4: load intvec low.
+            load_addr(NMI_VECTOR, 1);
+            return TRUE;
+        case 4:
+            //step 5: load intvec hi.
+            load_addr(NMI_VECTOR + 1, 2);
+            return TRUE;
+        case 5:
+            //step 6: set pc
+            cpu_reg.pc = get_cpu_addr_buf();
+            //set status flag
+            cpu_reg.status.decimal = 0;
+            cpu_reg.status.irq_disable = 1;
+
+            intr_done = TRUE;
+            return TRUE;
+    }
+    return FALSE;
+}
+
+int test_and_set_intr(void) {
+    int ret;
+    ret = intr_done;
+    if (ret) {
+        current_exec_index = 0;
+        intr_done = FALSE;
+    }
     return ret;
 }
 
@@ -1230,35 +2399,57 @@ void pc_move(int offset) {
     cpu_reg.pc += offset;
 }
 
+int init_6502core(void) {
+    memset(&cpu_reg, 0, sizeof(struct cpu_6502));
+    current_inst = NULL;
+    current_exec_index = 0;
+    exec_done = FALSE;
+    intr_done = FALSE;
+    return TRUE;
+}
+
+/* for debug.c */
+
 void dump_6502(int full) {
+    printf("\nclock: %09d\n", get_clock_cnt());
     if (full) 
         printf("6502 CPU registers:\n");
 
-    printf("pc:     %04x\n", cpu_reg.pc);
+    printf(" pc:     %04x\n", cpu_reg.pc);
     if (full) {
-        printf("acc:    %02x\n", cpu_reg.acc);
-        printf("x:      %02x\n", cpu_reg.x);
-        printf("y:      %02x\n", cpu_reg.y);
-        printf("sp:     %02x\n", cpu_reg.sp);
-        printf("status:\n");
-        printf(" negative:   %d\n", cpu_reg.status.negative);
-        printf(" overflow:   %d\n", cpu_reg.status.overflow);
-        printf(" break:      %d\n", cpu_reg.status.break_mode);
-        printf(" decimal:    %d\n", cpu_reg.status.decimal);
-        printf(" irq:        %d\n", cpu_reg.status.irq_disable);
-        printf(" zero:       %d\n", cpu_reg.status.zero);
-        printf(" carry:      %d\n", cpu_reg.status.carry);
+        printf(" acc:    %02x\n", cpu_reg.acc);
+        printf(" x:      %02x\n", cpu_reg.x);
+        printf(" y:      %02x\n", cpu_reg.y);
+        printf(" sp:     %02x\n", cpu_reg.sp);
+        printf(" status:\n");
+        printf("  negative:   %d\n", cpu_reg.status.negative);
+        printf("  overflow:   %d\n", cpu_reg.status.overflow);
+        printf("  break:      %d\n", cpu_reg.status.break_mode);
+        printf("  decimal:    %d\n", cpu_reg.status.decimal);
+        printf("  irq:        %d\n", cpu_reg.status.irq_disable);
+        printf("  zero:       %d\n", cpu_reg.status.zero);
+        printf("  carry:      %d\n", cpu_reg.status.carry);
         printf("-------------------\n");
     }
     //printf("data:     %02x\n", cpu_data_buffer);
 }
 
 
-int init_6502core(void) {
-    memset(&cpu_reg, 0, sizeof(struct cpu_6502));
-    current_inst = NULL;
-    current_exec_index = 0;
-    exec_done = FALSE;
-    return TRUE;
+int disas_inst(unsigned short addr) {
+    unsigned char inst;
+    unsigned char dbg_get_byte(unsigned short addr);
+    void disasm(const char* mnemonic, int addr_mode, unsigned short pc);
+
+    inst = dbg_get_byte(addr);
+    struct opcode_map * omap = &opcode_list[inst];
+    
+    disasm(omap->mnemonic, omap->addr_mode, addr);
+    return omap->inst_len;
+}
+
+void report_exec_err(void) {
+    fprintf(stderr, "cpu execute instruction failure @0x%04x.\n", pc_get());
+    fprintf(stderr, "error instruction: %s, cycle:%d\n", 
+            current_inst->mnemonic, current_exec_index - 1);
 }