7 unsigned int negative :1;
8 unsigned int overflow :1;
9 unsigned int researved :1;
10 unsigned int break_mode :1;
11 unsigned int decimal :1;
12 unsigned int irq_disable :1;
14 unsigned int carry :1;
22 struct status_reg status;
27 typedef int (handler_6502_t) (void);
31 * adressing mode instruction length
48 #define ADDR_MODE_ZP 0
49 #define ADDR_MODE_ZP_X 1
50 #define ADDR_MODE_ZP_Y 2
51 #define ADDR_MODE_ABS 3
52 #define ADDR_MODE_ABS_X 4
53 #define ADDR_MODE_ABS_Y 5
54 #define ADDR_MODE_IND 6
55 #define ADDR_MODE_IMP 7
56 #define ADDR_MODE_ACC 8
57 #define ADDR_MODE_IMM 9
58 #define ADDR_MODE_REL 10
59 #define ADDR_MODE_INDEX_INDIR 11
60 #define ADDR_MODE_INDIR_INDEX 12
63 #define N_BIT16 0x8000
71 int cycle_aux; /*Add one cycle if indexing across page boundary*/
75 static struct cpu_6502 cpu_reg;
76 static struct opcode_map *current_inst;
77 static int current_exec_index;
80 unsigned char load_memory(unsigned short addr);
81 unsigned short load_addr(unsigned short addr, int cycle);
83 unsigned char get_cpu_data_buf(void);
84 void set_cpu_data_buf(unsigned char data);
85 unsigned short get_cpu_addr_buf(void);
86 void set_cpu_addr_buf(unsigned short addr);
145 struct opcode_map opcode_list [255] = {
151 * awk '{print "int func_" $2 "(void) {\n\n}"}' < opcode-6502 | sort | uniq
157 static int addr_mode_exec(int *done) {
158 switch (current_inst->addr_mode) {
161 //accumulator/implied doesn't need memory operation.
166 //load immediate/relative value takes 1 cycle.
167 if (current_exec_index == 0) {
168 load_memory(cpu_reg.pc);
175 //zp takes two cycles.
176 if (current_exec_index == 0) {
177 load_memory(cpu_reg.pc);
181 else if (current_exec_index == 1) {
182 unsigned short zp = get_cpu_data_buf();
189 //zp indexed with x takes three cycles.
190 if (current_exec_index == 0) {
191 load_memory(cpu_reg.pc);
195 else if (current_exec_index == 1) {
196 unsigned char imm = get_cpu_data_buf();
197 set_cpu_data_buf(imm + cpu_reg.x);
200 else if (current_exec_index == 2) {
201 unsigned short zp = get_cpu_data_buf();
208 //zp indexed with y takes three cycles.
209 if (current_exec_index == 0) {
210 load_memory(cpu_reg.pc);
214 else if (current_exec_index == 1) {
215 unsigned char imm = get_cpu_data_buf();
216 set_cpu_data_buf(imm + cpu_reg.y);
219 else if (current_exec_index == 2) {
220 unsigned short zp = get_cpu_data_buf();
227 //takes three cycles.
228 if (current_exec_index == 0) {
229 load_addr(cpu_reg.pc, 1);
233 else if (current_exec_index == 1) {
234 load_addr(cpu_reg.pc, 2);
238 else if (current_exec_index == 2) {
239 unsigned short addr = get_cpu_addr_buf();
245 case ADDR_MODE_ABS_X:
246 //abs indexed with x takes three cycles.
247 if (current_exec_index == 0) {
248 load_addr(cpu_reg.pc, 1);
252 else if (current_exec_index == 1) {
253 load_addr(cpu_reg.pc, 2);
257 else if (current_exec_index == 2) {
258 if (current_inst->cycle_aux) {
259 //Add one cycle if indexing across page boundary
260 unsigned short addr = get_cpu_addr_buf();
261 unsigned short hi_8, added_hi_8;
265 added_hi_8 = addr >> 8;
267 if (hi_8 == added_hi_8) {
272 //load value in the next cycle.
273 set_cpu_data_buf(addr);
277 unsigned short addr = get_cpu_addr_buf();
283 else if (current_exec_index == 3) {
284 if (current_inst->cycle_aux) {
285 unsigned short addr = get_cpu_data_buf();
293 case ADDR_MODE_ABS_Y:
294 //abs indexed with y takes three cycles.
295 if (current_exec_index == 0) {
296 load_addr(cpu_reg.pc, 1);
300 else if (current_exec_index == 1) {
301 load_addr(cpu_reg.pc, 2);
305 else if (current_exec_index == 2) {
306 if (current_inst->cycle_aux) {
307 //Add one cycle if indexing across page boundary
308 unsigned short addr = get_cpu_addr_buf();
309 unsigned short hi_8, added_hi_8;
313 added_hi_8 = addr >> 8;
315 if (hi_8 == added_hi_8) {
320 //load value in the next cycle.
321 set_cpu_data_buf(addr);
325 unsigned short addr = get_cpu_addr_buf();
331 else if (current_exec_index == 3) {
332 if (current_inst->cycle_aux) {
333 unsigned short addr = get_cpu_data_buf();
340 case ADDR_MODE_INDEX_INDIR:
341 case ADDR_MODE_INDIR_INDEX:
342 #warning zp indexed indirect, zp indirect indexed must be reworked!!
471 * Load Accumulator with Memory: LDA
480 * Load Index X with Memory: LDX
488 ret = addr_mode_exec(&done);
495 cpu_reg.x = get_cpu_data_buf();
498 cpu_reg.status.zero = 1;
499 if (cpu_reg.x & N_BIT8)
500 cpu_reg.status.negative = 1;
506 * Load Index Y with Memory: LDY
514 ret = addr_mode_exec(&done);
521 cpu_reg.y = get_cpu_data_buf();
524 cpu_reg.status.zero = 1;
525 if (cpu_reg.y & N_BIT8)
526 cpu_reg.status.negative = 1;
588 * set interrupt disable.
591 cpu_reg.status.irq_disable = 1;
617 * Transfer Stack Pointer to Index X: TSX
622 cpu_reg.x = cpu_reg.sp;
624 if (cpu_reg.x & N_BIT8)
625 cpu_reg.status.negative = 1;
627 cpu_reg.status.zero = 1;
638 * Transfer Index X to Stack Pointer: TXS
643 cpu_reg.sp = cpu_reg.x;
645 if (cpu_reg.sp & N_BIT8)
646 cpu_reg.status.negative = 1;
648 cpu_reg.status.zero = 1;
660 * return execution cycle count
662 int decode6502(unsigned char inst) {
664 struct opcode_map * omap = &opcode_list[inst];
665 if (omap->func == NULL) {
669 dprint("decode inst: %02x > %s, %d cycle, %d len\n",
670 inst, omap->mnemonic, omap->cycle, omap->inst_len);
673 current_exec_index = 0;
677 int test_and_set_exec(void) {
685 int execute6502(void) {
687 ret = current_inst->func();
688 current_exec_index++;
692 void pc_set(unsigned short addr) {
696 unsigned short pc_get(void) {
700 void pc_move(int offset) {
701 cpu_reg.pc += offset;
704 void dump_6502(int full) {
706 printf("6502 CPU registers:\n");
708 printf("pc: %04x\n", cpu_reg.pc);
710 printf("acc: %02x\n", cpu_reg.acc);
711 printf("x: %02x\n", cpu_reg.x);
712 printf("y: %02x\n", cpu_reg.y);
713 printf("sp: %02x\n", cpu_reg.sp);
715 printf(" negative: %d\n", cpu_reg.status.negative);
716 printf(" overflow: %d\n", cpu_reg.status.overflow);
717 printf(" break: %d\n", cpu_reg.status.break_mode);
718 printf(" decimal: %d\n", cpu_reg.status.decimal);
719 printf(" irq: %d\n", cpu_reg.status.irq_disable);
720 printf(" zero: %d\n", cpu_reg.status.zero);
721 printf(" carry: %d\n", cpu_reg.status.carry);
722 printf("-------------------\n");
724 //printf("data: %02x\n", cpu_data_buffer);
728 int init_6502core(void) {
729 memset(&cpu_reg, 0, sizeof(struct cpu_6502));
731 current_exec_index = 0;