+#include <stdio.h>
+#include <string.h>
+#include <libio.h>
#include "tools.h"
+#include "6502core.h"
/*
- * instruction consists of following format.
- * aaabbbcc
- * aaa and cc determins opcode
- * bbb determins addr mode.
- *
- * ref:
- * http://www.llx.com/~nparker/a2/opcodes.html
- *
+ * 6502 little endian
+ * hi bit > low bit order
+ * but gcc generates low > hi order for bit field
* */
-struct mem_opcode_fmt {
- unsigned int aaa:3;
- unsigned int bbb:3;
- unsigned int cc:2;
+struct status_reg {
+ 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;
+ unsigned char x;
+ unsigned char y;
+ unsigned char sp;
+ struct status_reg status;
+ unsigned short pc;
};
-struct cond_br_opcode_fmt {
- unsigned int xx:2;
- unsigned int y:1;
- unsigned int one:5;
+
+typedef int (handler_6502_t) (void);
+
+/*
+ * 6502 instructions
+ * adressing mode instruction length
+ * 0:Zero Page 2
+ * 1:Zero Page, X 2
+ * 2:Zero Page, Y 2
+ * 3:Absolute 3
+ * 4:Absolute, X 3
+ * 5:Absolute, Y 3
+ * 6:Indirect 3
+ * 7:Implied 1
+ * 8:Accumulator 1
+ * 9:Immediate 2
+ * 10:Relative 2
+ * 11:(Indirect, X) 2
+ * 12:(Indirect), Y 2
+ *
+ **/
+
+#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;
+ char mnemonic[4];
+ handler_6502_t *func;
+ int addr_mode;
+ int cycle;
+ int cycle_aux; /*Add one cycle if indexing across page boundary*/
+ int inst_len;
};
-struct single_opcode_fmt {
- unsigned int aaaa:4;
- unsigned int eight:4;
+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);
+void store_memory(unsigned short addr, unsigned char data);
+
+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);
+int func_ASL(void);
+int func_BCC(void);
+int func_BCS(void);
+int func_BEQ(void);
+int func_BIT(void);
+int func_BMI(void);
+int func_BNE(void);
+int func_BPL(void);
+int func_BRK(void);
+int func_BVC(void);
+int func_BVS(void);
+int func_CLC(void);
+int func_CLD(void);
+int func_CLI(void);
+int func_CLV(void);
+int func_CMP(void);
+int func_CPX(void);
+int func_CPY(void);
+int func_DEC(void);
+int func_DEX(void);
+int func_DEY(void);
+int func_EOR(void);
+int func_INC(void);
+int func_INX(void);
+int func_INY(void);
+int func_JMP(void);
+int func_JSR(void);
+int func_LDA(void);
+int func_LDX(void);
+int func_LDY(void);
+int func_LSR(void);
+int func_NOP(void);
+int func_ORA(void);
+int func_PHA(void);
+int func_PHP(void);
+int func_PLA(void);
+int func_PLP(void);
+int func_ROL(void);
+int func_ROR(void);
+int func_RTI(void);
+int func_RTS(void);
+int func_SBC(void);
+int func_SEC(void);
+int func_SED(void);
+int func_SEI(void);
+int func_STA(void);
+int func_STX(void);
+int func_STY(void);
+int func_TAX(void);
+int func_TAY(void);
+int func_TSX(void);
+int func_TXA(void);
+int func_TXS(void);
+int func_TYA(void);
+
+struct opcode_map opcode_list [255] = {
+#include "opcode"
};
+
/*
- * addressing mode for group 1 instruction
- * addressing mode:
+ * awk '{print "int func_" $2 "(void) {\n\n}"}' < opcode-6502 | sort | uniq
*
- * Zero Page
- * Zero Page, X
- * Zero Page, Y
- * Absolute
- * Absolute, X
- * Absolute, Y
- * Indirect
- * Implied
- * Accumulator
- * Immediate
- * Relative
- * (Indirect, X)
- * (Indirect), Y
- * */
-
-/*(zero page, x)*/
-#define AM_GP1_INDR_INDX 0
-
-#define AM_GP1_ZP 1
-#define AM_GP1_IMM 2
-#define AM_GP1_ABS 3
-
-/*(zero page), y*/
-#define AM_GP1_INDX_INDR 4
-
-#define AM_GP1_ZP_X 5
-#define AM_GP1_ABS_X 6
-#define AM_GP1_ABS_Y 7
-
-#define AM_GP2_IMM 0
-#define AM_GP2_ZP 1
-#define AM_GP2_ACC 2
-#define AM_GP2_ABS 3
-#define AM_GP2_ZP_X 5
-#define AM_GP2_ABS_X 7
-
-#define AM_GP3_IMM 0
-#define AM_GP3_ZP 1
-#define AM_GP3_ABS 3
-#define AM_GP3_ZP_X 5
-#define AM_GP3_ABS_X 7
-
-static int decode_gp1(struct mem_opcode_fmt fmt, int *cycle, int *len) {
-
- *cycle = 0;
- switch (fmt.aaa) {
- case 0:
- dprint("ORA\n");
- break;
-
- case 1:
- dprint("AND\n");
- break;
-
- case 2:
- dprint("EOR\n");
- break;
+ * */
- case 3:
- dprint("ADC\n");
- break;
- case 4:
- dprint("STA\n");
- break;
- case 5:
- dprint("LDA\n");
- break;
+/*
+ * 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) {
+ case ADDR_MODE_ACC:
+ case ADDR_MODE_IMP:
+ //not supported.
+ return FALSE;
- case 6:
- dprint("CMP\n");
+ case ADDR_MODE_IMM:
+ case ADDR_MODE_REL:
+ //load immediate/relative value takes 1 cycle.
+ if (current_exec_index == 0) {
+ load_memory(cpu_reg.pc);
+ cpu_reg.pc++;
+ goto addr_mode_done;
+ }
+ break;
+
+ case ADDR_MODE_ZP:
+ //zp takes two 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);
+ goto addr_mode_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) {
+ 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);
+ goto addr_mode_done;
+ }
+ break;
+
+ case ADDR_MODE_ZP_Y:
+ //zp indexed with y takes three 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.y);
+ return TRUE;
+ }
+ else if (current_exec_index == 2) {
+ unsigned char zp = get_cpu_data_buf();
+ load_memory(zp);
+ goto addr_mode_done;
+ }
+ break;
+
+ case ADDR_MODE_ABS:
+ //takes three 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);
+ goto addr_mode_done;
+ }
+ break;
+
+ case ADDR_MODE_ABS_X:
+ //abs indexed with x takes three 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) {
+ if (current_inst->cycle_aux) {
+ //Add one cycle if indexing across page boundary
+ unsigned short addr = get_cpu_addr_buf();
+ unsigned short hi_8, added_hi_8;
+
+ hi_8 = (addr >> 8);
+ addr += cpu_reg.x;
+ added_hi_8 = (addr >> 8);
+
+ if (hi_8 == added_hi_8) {
+ load_memory(addr);
+ goto addr_mode_done;
+ }
+
+ //load value in the next cycle.
+ set_cpu_addr_buf(addr);
+ return TRUE;
+ }
+ else {
+ unsigned short addr = get_cpu_addr_buf();
+ addr += cpu_reg.x;
+ load_memory(addr);
+ goto addr_mode_done;
+ }
+ }
+ else if (current_exec_index == 3) {
+ if (current_inst->cycle_aux) {
+ unsigned short addr = get_cpu_addr_buf();
+ load_memory(addr);
+ goto addr_mode_done;
+ }
+ }
+
+ break;
+
+ case ADDR_MODE_ABS_Y:
+ //abs indexed with y takes three 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) {
+ if (current_inst->cycle_aux) {
+ //Add one cycle if indexing across page boundary
+ unsigned short addr = get_cpu_addr_buf();
+ unsigned short hi_8, added_hi_8;
+
+ hi_8 = (addr >> 8);
+ addr += cpu_reg.y;
+ added_hi_8 = (addr >> 8);
+
+ if (hi_8 == added_hi_8) {
+ load_memory(addr);
+ goto addr_mode_done;
+ }
+
+ //load value in the next cycle.
+ set_cpu_addr_buf(addr);
+ return TRUE;
+ }
+ else {
+ unsigned short addr = get_cpu_addr_buf();
+ addr += cpu_reg.y;
+ load_memory(addr);
+ goto addr_mode_done;
+ }
+ }
+ else if (current_exec_index == 3) {
+ if (current_inst->cycle_aux) {
+ unsigned short addr = get_cpu_addr_buf();
+ load_memory(addr);
+ goto addr_mode_done;
+ }
+ }
+ break;
+
+ case ADDR_MODE_INDEX_INDIR:
+ //Zero Page Indexed Indirect: (zp,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 zp = get_cpu_data_buf();
+ zp += cpu_reg.x;
+ set_cpu_data_buf(zp);
+ return TRUE;
+ }
+ else if (current_exec_index == 2) {
+ 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 char addr = get_cpu_data_buf();
+ load_addr(addr + 1, 2);
+ return TRUE;
+ }
+ else if (current_exec_index == 4) {
+ load_memory(get_cpu_addr_buf());
+ goto addr_mode_done;
+ }
+ break;
+
+ case ADDR_MODE_INDIR_INDEX:
+ //Zero Page Indirect Indexed with Y: (zp),y 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 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 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_addr_buf();
+ unsigned short hi_8, added_hi_8;
+
+ hi_8 = (addr >> 8);
+ addr += cpu_reg.y;
+ added_hi_8 = (addr >> 8);
+
+ if (hi_8 == added_hi_8) {
+ load_memory(addr);
+ goto addr_mode_done;
+ }
+
+ //load value in the next cycle.
+ set_cpu_addr_buf(addr);
+ return TRUE;
+ }
+ else {
+ unsigned short addr = get_cpu_addr_buf();
+ addr += cpu_reg.y;
+ load_memory(addr);
+ goto addr_mode_done;
+ }
+ }
+ else if (current_exec_index == 4) {
+ if (current_inst->cycle_aux) {
+ unsigned short addr = get_cpu_addr_buf();
+ load_memory(addr);
+ goto addr_mode_done;
+ }
+ }
break;
- case 7:
- dprint("SBC\n");
default:
- break;
+ return FALSE;
}
+ return FALSE;
- *len = 2;
- switch (fmt.bbb) {
- case AM_GP1_ZP:
- *cycle = 3;
- break;
+addr_mode_done:
+ *done = TRUE;
+ return TRUE;
+}
- case AM_GP1_IMM:
- *cycle = 2;
- break;
+/*
+ * store into memory in various addressing mode.
+ * */
+static int store_addr_mode(unsigned char data, int *done) {
+ switch (current_inst->addr_mode) {
+ case ADDR_MODE_ACC:
+ case ADDR_MODE_IMP:
+ case ADDR_MODE_IMM:
+ case ADDR_MODE_REL:
+ //not supported.
+ return FALSE;
- case AM_GP1_ABS :
- *len = 3;
- case AM_GP1_ZP_X:
- *cycle = 4;
+ case ADDR_MODE_ZP:
+ //zp takes two 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();
+ store_memory(zp, data);
+ goto addr_mode_done;
+ }
+ break;
+
+ case ADDR_MODE_ZP_X:
+ //zp indexed with x takes three 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();
+ store_memory(zp, data);
+ goto addr_mode_done;
+ }
+ break;
+
+ case ADDR_MODE_ZP_Y:
+ //zp indexed with y takes three 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.y);
+ return TRUE;
+ }
+ else if (current_exec_index == 2) {
+ unsigned char zp = get_cpu_data_buf();
+ store_memory(zp, data);
+ goto addr_mode_done;
+ }
+ break;
+
+ case ADDR_MODE_ABS:
+ //takes three 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();
+ store_memory(addr, data);
+ goto addr_mode_done;
+ }
+ break;
+
+ case ADDR_MODE_ABS_X:
+ //abs indexed with x takes 4 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();
+ addr += cpu_reg.x;
+ set_cpu_addr_buf(addr);
+ return TRUE;
+ }
+ else if (current_exec_index == 3) {
+ unsigned short addr = get_cpu_addr_buf();
+ store_memory(addr, data);
+ goto addr_mode_done;
+ }
+ break;
+
+ case ADDR_MODE_ABS_Y:
+ 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();
+ addr += cpu_reg.y;
+ set_cpu_addr_buf(addr);
+ return TRUE;
+ }
+ else if (current_exec_index == 3) {
+ unsigned short addr = get_cpu_addr_buf();
+ store_memory(addr, data);
+ goto addr_mode_done;
+ }
+ break;
+
+ case ADDR_MODE_INDEX_INDIR:
+ //Zero Page Indexed Indirect: (zp,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 zp = get_cpu_data_buf();
+ zp += cpu_reg.x;
+ set_cpu_data_buf(zp);
+ return TRUE;
+ }
+ else if (current_exec_index == 2) {
+ 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 char addr = get_cpu_data_buf();
+ load_addr(addr + 1, 2);
+ return TRUE;
+ }
+ else if (current_exec_index == 4) {
+ store_memory(get_cpu_addr_buf(), data);
+ goto addr_mode_done;
+ }
+ break;
+
+ case ADDR_MODE_INDIR_INDEX:
+ //Zero Page Indirect Indexed with Y: (zp),y 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 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 char addr = get_cpu_data_buf();
+ load_addr(addr + 1, 2);
+ return TRUE;
+ }
+ else if (current_exec_index == 3) {
+ unsigned short addr = get_cpu_addr_buf();
+ addr += cpu_reg.y;
+ set_cpu_addr_buf(addr);
+ return TRUE;
+ }
+ else if (current_exec_index == 4) {
+ unsigned short addr = get_cpu_addr_buf();
+ store_memory(addr, data);
+ goto addr_mode_done;
+ }
break;
- case AM_GP1_ABS_X:
- case AM_GP1_ABS_Y:
- *cycle = 7;
- *len = 3;
- break;
+ default:
+ return FALSE;
+ }
+ return FALSE;
- case AM_GP1_INDR_INDX:
- *cycle = 6;
- break;
+addr_mode_done:
+ *done = TRUE;
+ 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 AM_GP1_INDX_INDR :
- *cycle = 5;
+ 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;
}
-static int decode_gp2(struct mem_opcode_fmt fmt, int *cycle, int *len) {
- *cycle = 0;
- switch (fmt.aaa) {
- case 0:
- dprint("ASL\n");
- break;
- case 1:
- dprint("ROL\n");
- break;
+/*------------- flag operation.. ---------------------*/
- case 2:
- dprint("LSR\n");
- break;
+static void set_zero(unsigned char data) {
+ if (data == 0)
+ cpu_reg.status.zero = 1;
+ else
+ cpu_reg.status.zero = 0;
+}
- case 3:
- dprint("ROR\n");
- break;
+static void set_negative(unsigned char data) {
+ if (data & N_BIT)
+ cpu_reg.status.negative = 1;
+ else
+ cpu_reg.status.negative = 0;
+}
- case 4:
- dprint("STX\n");
- break;
+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;
+}
- case 5:
- dprint("LDX\n");
- break;
+static void set_BIT_overflow(unsigned char data) {
+ if (data & V_BIT)
+ cpu_reg.status.overflow = 1;
+ else
+ cpu_reg.status.overflow = 0;
+}
- case 6:
- dprint("DEC\n");
- break;
+/*
+ * 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;
+}
- case 7:
- dprint("INC\n");
- default:
- break;
+/*
+ * 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) {
+ 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) {
+ 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) {
+ 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;
- *len = 2;
- switch (fmt.bbb) {
- case AM_GP2_ZP:
- *cycle = 3;
- break;
+ 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;
+ }
+ }
- case AM_GP2_ACC:
- *len = 1;
- case AM_GP2_IMM:
- *cycle = 2;
- break;
+ if (!done)
+ return TRUE;
- case AM_GP2_ABS :
- *len = 3;
- case AM_GP2_ZP_X:
- *cycle = 4;
- break;
+ // N/Z flags set.
+ data = get_cpu_data_buf();
+ set_negative(data);
+ set_zero(data);
- case AM_GP2_ABS_X:
- *len = 3;
- *cycle = 7;
- break;
+acc_done:
+ exec_done = TRUE;
+ return TRUE;
+}
- default:
+static int branch(unsigned char condition) {
+
+ if (current_exec_index == 0) {
+ int done = FALSE;
+ int ret;
+ ret = load_addr_mode(&done);
+ if (!ret)
return FALSE;
+
+ if (!condition) {
+ exec_done = TRUE;
+ }
+ return TRUE;
}
+ else if (current_exec_index == 1) {
+ //case branch
+ char rel = get_cpu_data_buf();
+ unsigned short addr = cpu_reg.pc;
+ unsigned short br_addr = cpu_reg.pc + rel;
+
+ if ((addr >> 8) == (br_addr >> 8)) {
+ //in page branch.
+ cpu_reg.pc = br_addr;
+ exec_done = TRUE;
+ }
+ else {
+ set_cpu_addr_buf(br_addr);
+ }
+ return TRUE;
+ }
+ else if (current_exec_index == 2) {
+ //cross page branch.
+ unsigned short br_addr = get_cpu_addr_buf();
+ cpu_reg.pc = br_addr;
+ exec_done = TRUE;
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+/*
+ * Branch on Carry Clear: BCC
+ * Branch if C = 0
+ * Flags: none
+ * */
+int func_BCC(void) {
+ return branch(cpu_reg.status.carry == 0);
+}
+
+/*
+ * Branch on Carry Set: BCS
+ * Branch if C = 1
+ * Flags: none
+ * */
+int func_BCS(void) {
+ return branch(cpu_reg.status.carry == 1);
+}
+
+/*
+ * Branch on Result Zero: BEQ
+ * Branch if Z = 1
+ * Flags: none
+ * */
+int func_BEQ(void) {
+ return branch(cpu_reg.status.zero == 1);
+}
+/*
+ * 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;
}
-static int decode_gp3(struct mem_opcode_fmt fmt, int *cycle, int *len) {
- *cycle = 0;
- switch (fmt.aaa) {
- case 1:
- dprint("BIT\n");
- break;
+/*
+ * Branch on Result Minus: BMI
+ * Branch if N = 1
+ * Flags: none
+ * */
+int func_BMI(void) {
+ return branch(cpu_reg.status.negative == 1);
+}
- case 2:
- dprint("JMP\n");
- break;
+/*
+ * Branch on Result not Zero: BNE
+ * Branch if Z = 0
+ * Flags: none
+ * */
+int func_BNE(void) {
+ return branch(cpu_reg.status.zero == 0);
+}
- case 3:
- dprint("JMP(abs)\n");
- break;
+/*
+ * Branch on Result Plus: BPL
+ * Branch if N = 0
+ * Flags: none
+ * */
+int func_BPL(void) {
+ return branch(cpu_reg.status.negative == 0);
+}
- case 4:
- dprint("STY\n");
- break;
+int func_BRK(void) {
+ return FALSE;
+}
- case 5:
- dprint("LDY\n");
- break;
+/*
+ * Branch on Overflow Clear: BVC
+ * Branch if V = 0
+ * Flags: none
+ * */
+int func_BVC(void) {
+ return branch(cpu_reg.status.overflow == 0);
+}
- case 6:
- dprint("CPY\n");
- break;
+/*
+ * Branch on Overflow Set: BVS
+ * Branch if V = 1
+ * Flags: none
+ * */
+int func_BVS(void) {
+ return branch(cpu_reg.status.overflow == 1);
+}
- case 7:
- dprint("CPX\n");
- break;
+/*
+ * Clear Carry Flag: CLC
+ * 0 -> C
+ * Flags: C = 0
+ * */
+int func_CLC(void) {
+ cpu_reg.status.carry = 0;
+ exec_done = TRUE;
+ return TRUE;
+}
- case 0:
- default:
- return FALSE;
- }
+/*
+ * Clear Decimal Mode: CLD
+ * 0 -> D
+ * Flags: D = 0
+ *
+ * NOTE: Decimal mode is not implemented on NES core.
+ * */
+int func_CLD(void) {
+ cpu_reg.status.decimal = 0;
+ exec_done = TRUE;
+ return TRUE;
+}
- *len = 2;
- switch (fmt.bbb) {
- case AM_GP3_ZP:
- *cycle = 3;
- break;
+/*
+ * Clear Interrupt Disable Status: CLI
+ * 0 -> I
+ * Flags: I = 0
+ * */
+int func_CLI(void) {
+ cpu_reg.status.irq_disable = 0;
+ exec_done = TRUE;
+ return TRUE;
+}
- case AM_GP3_IMM:
- *cycle = 2;
- break;
+/*
+ * Clear Overflow Flag: CLV
+ * 0 -> V
+ * Flags: V = 0
+ * */
+int func_CLV(void) {
+ cpu_reg.status.overflow = 0;
+ exec_done = TRUE;
+ return TRUE;
+}
- case AM_GP3_ABS :
- *len = 3;
- case AM_GP3_ZP_X:
- *cycle = 4;
- break;
+/*
+ * Compare Memory and Accumulator: CMP
+ * A - M
+ * Flags: N, Z, C
+ * */
+int func_CMP(void) {
+ int done = FALSE;
+ int ret;
+ unsigned char cmp;
- case AM_GP3_ABS_X:
- *cycle = 7;
- *len = 3;
- break;
+ ret = load_addr_mode(&done);
+ if (!ret)
+ return FALSE;
- default:
- 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;
}
-static int decode_cond_br(unsigned char inst, int *cycle, int *len) {
- *cycle = 2;
- *len = 2;
- switch (inst) {
- case 0x10:
- dprint("BPL\n");
- break;
- case 0x30:
- dprint("BMI\n");
- break;
- case 0x50:
- dprint("BVC\n");
- break;
- case 0x70:
- dprint("BVS\n");
- break;
- case 0x90:
- dprint("BCC\n");
- break;
- case 0xB0:
- dprint("BCS\n");
- break;
- case 0xD0:
- dprint("BNE\n");
- break;
- case 0xF0:
- dprint("BEQ\n");
- break;
- case 0x00:
- dprint("BRK\n");
- *cycle = 7;
- *len = 1;
- break;
- case 0x20:
- dprint("JSR abs\n");
- *cycle = 6;
- *len = 3;
- break;
- case 0x40:
- dprint("RTI\n");
- *cycle = 6;
- *len = 1;
- break;
- case 0x60:
- dprint("RTS\n");
- *cycle = 6;
- *len = 1;
- break;
- default:
- return FALSE;
- }
+/*
+ * Compare Memory and Index X: CPX
+ * X - M
+ * Flags: N, Z, C
+ * */
+int func_CPX(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 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;
}
-static int decode_single(unsigned char inst, int *cycle, int *len) {
- *cycle = 2;
- *len = 1;
- switch (inst) {
- case 0x08:
- dprint("PHP\n");
- *cycle = 3;
- break;
- case 0x28:
- dprint("PLP\n");
- *cycle = 4;
- break;
- case 0x48:
- dprint("PHA\n");
- *cycle = 3;
- break;
- case 0x68:
- dprint("PLA\n");
- *cycle = 4;
- break;
- case 0x88:
- dprint("DEY\n");
- break;
- case 0xA8:
- dprint("TAY\n");
- break;
- case 0xC8:
- dprint("INY\n");
- break;
- case 0xE8:
- dprint("INX\n");
- break;
- case 0x18:
- dprint("CLC\n");
- break;
- case 0x38:
- dprint("SEC\n");
- break;
- case 0x58:
- dprint("CLI\n");
- break;
- case 0x78:
- dprint("SEI\n");
- break;
- case 0x98:
- dprint("TYA\n");
- break;
- case 0xb8:
- dprint("CLV\n");
- break;
- case 0xD8:
- dprint("CLD\n");
- break;
- case 0xF8:
- dprint("SED\n");
- break;
- case 0x8A:
- dprint("TXA\n");
- break;
- case 0x9A:
- dprint("TXS\n");
- break;
- case 0xAA:
- dprint("TAX\n");
- break;
- case 0xBA:
- dprint("TSX\n");
- break;
- case 0xCA:
- dprint("DEX\n");
- break;
- case 0xEA:
- dprint("NOP\n");
- break;
- default:
- return FALSE;
+/*
+ * Compare Memory with Index Y: CPY
+ * Y - M
+ * Flags: N, Z, C
+ * */
+int func_CPY(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 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) {
+ 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;
}
/*
- * decode6502:
- * return execution cycle count
+ * Decrement Index X by One: DEX
+ * X - 1 -> X
+ * Flags: N, Z
* */
-int decode6502(unsigned char inst, int *cycle_cnt, int *inst_len) {
- int ret = FALSE;
- struct mem_opcode_fmt* m_fmt = (struct mem_opcode_fmt*)&inst;
- struct cond_br_opcode_fmt* c_fmt = (struct cond_br_opcode_fmt*)&inst;
- struct single_opcode_fmt* s_fmt = (struct single_opcode_fmt*)&inst;
+int func_DEX(void) {
+ cpu_reg.x--;
+ //ldx N/Z flags set.
+ set_negative(cpu_reg.x);
+ set_zero(cpu_reg.x);
- if (m_fmt->cc == 1)
- ret = decode_gp1(*m_fmt, cycle_cnt, inst_len);
- else if (m_fmt->cc == 2)
- ret = decode_gp2(*m_fmt, cycle_cnt, inst_len);
- else if (m_fmt->cc == 0)
- ret = decode_gp3(*m_fmt, cycle_cnt, inst_len);
+ exec_done = TRUE;
+ return TRUE;
+}
- /*conditional branc group*/
- else if (c_fmt->one == 0x10)
- ret = decode_cond_br(inst, cycle_cnt, inst_len);
+/*
+ * Decrement Index Y by One: DEY
+ * Y - 1 -> Y
+ * Flags: N, Z
+ * */
+int func_DEY(void) {
+ cpu_reg.y--;
- /*single byte inst group*/
- else if (s_fmt->eight == 0x08 || s_fmt->eight == 0x0a)
- ret = decode_single(inst, cycle_cnt, inst_len);
+ //ldx N/Z flags set.
+ set_negative(cpu_reg.y);
+ set_zero(cpu_reg.y);
- return ret;
+ exec_done = TRUE;
+ return TRUE;
+}
+
+/*
+ * Exclusive-OR Memory with Accumulator: EOR
+ * A ^ M -> A
+ * Flags: N, Z
+ * */
+int func_EOR(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;
+}
+
+/*
+ * Increment Memory by One: INC
+ * M + 1 -> M
+ * Flags: N, Z
+ * */
+int func_INC(void) {
+ 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;
+}
+
+/*
+ * Increment Index X by One: INX
+ * X + 1 -> X
+ * Flags: N, Z
+ * */
+int func_INX(void) {
+ cpu_reg.x++;
+
+ //ldx N/Z flags set.
+ set_negative(cpu_reg.x);
+ set_zero(cpu_reg.x);
+
+ exec_done = TRUE;
+ return TRUE;
+}
+
+int func_INY(void) {
+ cpu_reg.y++;
+
+ //ldx N/Z flags set.
+ set_negative(cpu_reg.y);
+ set_zero(cpu_reg.y);
+
+ exec_done = TRUE;
+ return TRUE;
+}
+
+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;
+}
+
+/*
+ * Load Accumulator with Memory: LDA
+ * M -> A
+ * Flags: N, Z
+ * */
+int func_LDA(void) {
+ int done = FALSE;
+ int ret;
+
+ ret = load_addr_mode(&done);
+ if (!ret)
+ return FALSE;
+
+ if (!done)
+ return TRUE;
+
+ cpu_reg.acc = get_cpu_data_buf();
+ //ldx N/Z flags set.
+ set_negative(cpu_reg.acc);
+ set_zero(cpu_reg.acc);
+
+ exec_done = TRUE;
+ return TRUE;
+}
+
+/*
+ * Load Index X with Memory: LDX
+ * M -> X
+ * Flags: N, Z
+ * */
+int func_LDX(void) {
+ int done = FALSE;
+ int ret;
+
+ ret = load_addr_mode(&done);
+ if (!ret)
+ return FALSE;
+
+ if (!done)
+ return TRUE;
+
+ cpu_reg.x = get_cpu_data_buf();
+ //ldx N/Z flags set.
+ set_negative(cpu_reg.x);
+ set_zero(cpu_reg.x);
+
+ exec_done = TRUE;
+ return TRUE;
+}
+
+/*
+ * Load Index Y with Memory: LDY
+ * M -> Y
+ * Flags: N, Z
+ * */
+int func_LDY(void) {
+ int done = FALSE;
+ int ret;
+
+ ret = load_addr_mode(&done);
+ if (!ret)
+ return FALSE;
+
+ if (!done)
+ return TRUE;
+
+ cpu_reg.y = get_cpu_data_buf();
+ //ldx N/Z flags set.
+ set_negative(cpu_reg.y);
+ set_zero(cpu_reg.y);
+
+ exec_done = TRUE;
+ 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) {
+ 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) {
+ int ret;
+ int done = FALSE;
+ ret = push_op(cpu_reg.acc, &done);
+ exec_done = done;
+ return ret;
+}
+
+int func_PHP(void) {
+ return FALSE;
+}
+
+/*
+ * 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) {
+ 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) {
+ 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) {
+ 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) {
+ 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;
+}
+
+/*
+ * set interrupt disable.
+ * */
+int func_SEI(void) {
+ cpu_reg.status.irq_disable = 1;
+ exec_done = TRUE;
+ return TRUE;
+}
+
+/*
+ * Store Accumulator in Memory: STA
+ * A -> M
+ * Flags: none
+ * */
+int func_STA(void) {
+ int done = FALSE;
+ int ret;
+
+ ret = store_addr_mode(cpu_reg.acc, &done);
+ if (!ret)
+ return FALSE;
+
+ if (!done)
+ return TRUE;
+
+ exec_done = TRUE;
+ return TRUE;
+}
+
+/*
+ * Store Index X in Memory: STX
+ * X -> M
+ * Flags: none
+ * */
+int func_STX(void) {
+ int done = FALSE;
+ int ret;
+
+ ret = store_addr_mode(cpu_reg.x, &done);
+ if (!ret)
+ return FALSE;
+
+ if (!done)
+ return TRUE;
+
+ exec_done = TRUE;
+ return TRUE;
+}
+
+/*
+ * Store Index Y in Memory: STY
+ * Y -> M
+ * Flags: none
+ * */
+int func_STY(void) {
+ int done = FALSE;
+ int ret;
+
+ ret = store_addr_mode(cpu_reg.y, &done);
+ if (!ret)
+ return FALSE;
+
+ if (!done)
+ return TRUE;
+
+ exec_done = TRUE;
+ return TRUE;
+}
+
+/*
+ * Transfer Accumulator to Index X: TAX
+ * A -> X
+ * Flags: N, Z
+ * */
+int func_TAX(void) {
+ cpu_reg.x = cpu_reg.acc;
+
+ set_negative(cpu_reg.x);
+ set_zero(cpu_reg.x);
+
+ exec_done = TRUE;
+ return TRUE;
+}
+
+/*
+ * Transfer Accumulator to Index Y: TAY
+ * A -> Y
+ * Flags: N, Z
+ * */
+int func_TAY(void) {
+ cpu_reg.y = cpu_reg.acc;
+
+ set_negative(cpu_reg.y);
+ set_zero(cpu_reg.y);
+
+ exec_done = TRUE;
+ return TRUE;
+}
+
+/*
+ * Transfer Stack Pointer to Index X: TSX
+ * S -> X
+ * Flags: N, Z
+ * */
+int func_TSX(void) {
+ cpu_reg.x = cpu_reg.sp;
+
+ set_negative(cpu_reg.x);
+ set_zero(cpu_reg.x);
+
+ exec_done = TRUE;
+ return TRUE;
+}
+
+/*
+ * Transfer Index X to Accumulator: TXA
+ * X -> A
+ * Flags: N, Z
+ * */
+int func_TXA(void) {
+ cpu_reg.acc = cpu_reg.x;
+
+ set_negative(cpu_reg.acc);
+ set_zero(cpu_reg.acc);
+
+ exec_done = TRUE;
+ return TRUE;
+}
+
+/*
+ * Transfer Index X to Stack Pointer: TXS
+ * X -> S
+ * Flags: N, Z
+ * */
+int func_TXS(void) {
+ cpu_reg.sp = cpu_reg.x;
+
+ set_negative(cpu_reg.sp);
+ set_zero(cpu_reg.sp);
+
+ exec_done = TRUE;
+ return TRUE;
+}
+
+/*
+ * Transfer Index Y to Accumulator: TYA
+ * Y -> A
+ * Flags: N, Z
+ * */
+int func_TYA(void) {
+ cpu_reg.acc = cpu_reg.y;
+
+ set_negative(cpu_reg.y);
+ set_zero(cpu_reg.y);
+
+ exec_done = TRUE;
+ return TRUE;
+}
+
+/* ------------------ 6502 execution.. ------------------- */
+
+/*
+ * decode6502:
+ * return execution cycle count
+ * */
+int decode6502(unsigned char inst) {
+
+ struct opcode_map * omap = &opcode_list[inst];
+ if (omap->func == NULL) {
+ return FALSE;
+ }
+
+ /*dprint("decode inst: %02x > %s, %d cycle, %d len\n",
+ inst, omap->mnemonic, omap->cycle, omap->inst_len);
+*/
+
+ current_inst = omap;
+
+ return TRUE;
+}
+
+int test_and_set_exec(void) {
+ int ret;
+ ret = exec_done;
+ if (exec_done) {
+ exec_done = FALSE;
+ current_exec_index = 0;
+ }
+ return ret;
+}
+
+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;
+}
+
+void pc_set(unsigned short addr) {
+ cpu_reg.pc = addr;
+}
+
+unsigned short pc_get(void) {
+ return cpu_reg.pc;
+}
+
+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);
+ 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("-------------------\n");
+ }
+ //printf("data: %02x\n", cpu_data_buffer);
+}
+
+
+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);
}