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;
15 } __attribute__ ((packed));
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
65 /* cycle check must be cleared on release */
74 int cycle_aux; /*Add one cycle if indexing across page boundary*/
78 static struct cpu_6502 cpu_reg;
79 static struct opcode_map *current_inst;
80 static int current_exec_index;
83 unsigned char load_memory(unsigned short addr);
84 unsigned short load_addr(unsigned short addr, int cycle);
85 void store_memory(unsigned short addr, unsigned char data);
87 unsigned char get_cpu_data_buf(void);
88 void set_cpu_data_buf(unsigned char data);
89 unsigned short get_cpu_addr_buf(void);
90 void set_cpu_addr_buf(unsigned short addr);
149 struct opcode_map opcode_list [255] = {
155 * awk '{print "int func_" $2 "(void) {\n\n}"}' < opcode-6502 | sort | uniq
162 * load from memory in various addressing mode.
163 * cpu_data_buf has the output value.
165 static int load_addr_mode(int *done) {
166 switch (current_inst->addr_mode) {
174 //load immediate/relative value takes 1 cycle.
175 if (current_exec_index == 0) {
176 load_memory(cpu_reg.pc);
183 //zp takes two cycles.
184 if (current_exec_index == 0) {
185 load_memory(cpu_reg.pc);
189 else if (current_exec_index == 1) {
190 unsigned short zp = get_cpu_data_buf();
197 //zp indexed with x takes three cycles.
198 if (current_exec_index == 0) {
199 load_memory(cpu_reg.pc);
203 else if (current_exec_index == 1) {
204 unsigned char imm = get_cpu_data_buf();
205 set_cpu_data_buf(imm + cpu_reg.x);
208 else if (current_exec_index == 2) {
209 unsigned short zp = get_cpu_data_buf();
216 //zp indexed with y takes three cycles.
217 if (current_exec_index == 0) {
218 load_memory(cpu_reg.pc);
222 else if (current_exec_index == 1) {
223 unsigned char imm = get_cpu_data_buf();
224 set_cpu_data_buf(imm + cpu_reg.y);
227 else if (current_exec_index == 2) {
228 unsigned short zp = get_cpu_data_buf();
235 //takes three cycles.
236 if (current_exec_index == 0) {
237 load_addr(cpu_reg.pc, 1);
241 else if (current_exec_index == 1) {
242 load_addr(cpu_reg.pc, 2);
246 else if (current_exec_index == 2) {
247 unsigned short addr = get_cpu_addr_buf();
253 case ADDR_MODE_ABS_X:
254 //abs indexed with x takes three cycles.
255 if (current_exec_index == 0) {
256 load_addr(cpu_reg.pc, 1);
260 else if (current_exec_index == 1) {
261 load_addr(cpu_reg.pc, 2);
265 else if (current_exec_index == 2) {
266 if (current_inst->cycle_aux) {
267 //Add one cycle if indexing across page boundary
268 unsigned short addr = get_cpu_addr_buf();
269 unsigned short hi_8, added_hi_8;
273 added_hi_8 = addr >> 8;
275 if (hi_8 == added_hi_8) {
280 //load value in the next cycle.
281 set_cpu_data_buf(addr);
285 unsigned short addr = get_cpu_addr_buf();
291 else if (current_exec_index == 3) {
292 if (current_inst->cycle_aux) {
293 unsigned short addr = get_cpu_data_buf();
301 case ADDR_MODE_ABS_Y:
302 //abs indexed with y takes three cycles.
303 if (current_exec_index == 0) {
304 load_addr(cpu_reg.pc, 1);
308 else if (current_exec_index == 1) {
309 load_addr(cpu_reg.pc, 2);
313 else if (current_exec_index == 2) {
314 if (current_inst->cycle_aux) {
315 //Add one cycle if indexing across page boundary
316 unsigned short addr = get_cpu_addr_buf();
317 unsigned short hi_8, added_hi_8;
321 added_hi_8 = addr >> 8;
323 if (hi_8 == added_hi_8) {
328 //load value in the next cycle.
329 set_cpu_data_buf(addr);
333 unsigned short addr = get_cpu_addr_buf();
339 else if (current_exec_index == 3) {
340 if (current_inst->cycle_aux) {
341 unsigned short addr = get_cpu_data_buf();
348 case ADDR_MODE_INDEX_INDIR:
349 //Zero Page Indexed Indirect: (zp,x) takes 5 cycles
350 if (current_exec_index == 0) {
351 load_memory(cpu_reg.pc);
355 else if (current_exec_index == 1) {
356 unsigned char zp = get_cpu_data_buf();
358 set_cpu_data_buf(zp);
361 else if (current_exec_index == 2) {
362 unsigned short addr = get_cpu_data_buf();
366 else if (current_exec_index == 3) {
367 unsigned short addr = get_cpu_data_buf();
368 load_addr(addr + 1, 2);
371 else if (current_exec_index == 4) {
372 load_memory(get_cpu_addr_buf());
377 case ADDR_MODE_INDIR_INDEX:
378 //Zero Page Indirect Indexed with Y: (zp),y takes 4 cycles.
379 if (current_exec_index == 0) {
380 load_memory(cpu_reg.pc);
384 else if (current_exec_index == 1) {
385 unsigned short addr = get_cpu_data_buf();
389 else if (current_exec_index == 2) {
390 unsigned short addr = get_cpu_data_buf();
391 load_addr(addr + 1, 2);
394 else if (current_exec_index == 3) {
395 if (current_inst->cycle_aux) {
396 //Add one cycle if indexing across page boundary
397 unsigned short addr = get_cpu_data_buf();
398 unsigned short hi_8, added_hi_8;
402 added_hi_8 = addr >> 8;
404 if (hi_8 == added_hi_8) {
409 //load value in the next cycle.
410 set_cpu_data_buf(addr);
414 unsigned short addr = get_cpu_data_buf();
420 else if (current_exec_index == 4) {
421 if (current_inst->cycle_aux) {
422 unsigned short addr = get_cpu_data_buf();
440 * store into memory in various addressing mode.
442 static int store_addr_mode(unsigned char data, int *done) {
443 switch (current_inst->addr_mode) {
452 //zp takes two cycles.
453 if (current_exec_index == 0) {
454 load_memory(cpu_reg.pc);
458 else if (current_exec_index == 1) {
459 unsigned short zp = get_cpu_data_buf();
460 store_memory(zp, data);
466 //zp indexed with x takes three cycles.
467 if (current_exec_index == 0) {
468 load_memory(cpu_reg.pc);
472 else if (current_exec_index == 1) {
473 unsigned char imm = get_cpu_data_buf();
474 set_cpu_data_buf(imm + cpu_reg.x);
477 else if (current_exec_index == 2) {
478 unsigned short zp = get_cpu_data_buf();
479 store_memory(zp, data);
485 //zp indexed with y takes three cycles.
486 if (current_exec_index == 0) {
487 load_memory(cpu_reg.pc);
491 else if (current_exec_index == 1) {
492 unsigned char imm = get_cpu_data_buf();
493 set_cpu_data_buf(imm + cpu_reg.y);
496 else if (current_exec_index == 2) {
497 unsigned short zp = get_cpu_data_buf();
498 store_memory(zp, data);
504 //takes three cycles.
505 if (current_exec_index == 0) {
506 load_addr(cpu_reg.pc, 1);
510 else if (current_exec_index == 1) {
511 load_addr(cpu_reg.pc, 2);
515 else if (current_exec_index == 2) {
516 unsigned short addr = get_cpu_addr_buf();
517 store_memory(addr, data);
522 case ADDR_MODE_ABS_X:
523 //abs indexed with x takes 4 cycles.
524 if (current_exec_index == 0) {
525 load_addr(cpu_reg.pc, 1);
529 else if (current_exec_index == 1) {
530 load_addr(cpu_reg.pc, 2);
534 else if (current_exec_index == 2) {
535 unsigned short addr = get_cpu_addr_buf();
537 set_cpu_data_buf(addr);
540 else if (current_exec_index == 3) {
541 unsigned short addr = get_cpu_data_buf();
542 store_memory(addr, data);
547 case ADDR_MODE_ABS_Y:
548 if (current_exec_index == 0) {
549 load_addr(cpu_reg.pc, 1);
553 else if (current_exec_index == 1) {
554 load_addr(cpu_reg.pc, 2);
558 else if (current_exec_index == 2) {
559 unsigned short addr = get_cpu_addr_buf();
561 set_cpu_data_buf(addr);
564 else if (current_exec_index == 3) {
565 unsigned short addr = get_cpu_data_buf();
566 store_memory(addr, data);
571 case ADDR_MODE_INDEX_INDIR:
572 //Zero Page Indexed Indirect: (zp,x) takes 5 cycles
573 if (current_exec_index == 0) {
574 load_memory(cpu_reg.pc);
578 else if (current_exec_index == 1) {
579 unsigned char zp = get_cpu_data_buf();
581 set_cpu_data_buf(zp);
584 else if (current_exec_index == 2) {
585 unsigned short addr = get_cpu_data_buf();
589 else if (current_exec_index == 3) {
590 unsigned short addr = get_cpu_data_buf();
591 load_addr(addr + 1, 2);
594 else if (current_exec_index == 4) {
595 store_memory(get_cpu_addr_buf(), data);
600 case ADDR_MODE_INDIR_INDEX:
601 //Zero Page Indirect Indexed with Y: (zp),y takes 5 cycles.
602 if (current_exec_index == 0) {
603 load_memory(cpu_reg.pc);
607 else if (current_exec_index == 1) {
608 unsigned short addr = get_cpu_data_buf();
612 else if (current_exec_index == 2) {
613 unsigned short addr = get_cpu_data_buf();
614 load_addr(addr + 1, 2);
617 else if (current_exec_index == 3) {
618 unsigned short addr = get_cpu_data_buf();
620 set_cpu_data_buf(addr);
623 else if (current_exec_index == 4) {
624 unsigned short addr = get_cpu_data_buf();
625 store_memory(addr, data);
641 /*------------- flag operation.. ---------------------*/
643 static void set_zero(unsigned char data) {
645 cpu_reg.status.zero = 1;
647 cpu_reg.status.zero = 0;
650 static void set_negative(unsigned char data) {
652 cpu_reg.status.negative = 1;
654 cpu_reg.status.negative = 0;
657 /*------------- stack operation.. ---------------------*/
658 //stack operation takes two cycles.
659 static void push(unsigned char data) {
660 store_memory(cpu_reg.sp--, data);
663 static unsigned char pop(void) {
664 return load_memory(--cpu_reg.sp);
667 /*---------- instruction implementations. -----------------*/
681 static int branch(unsigned char condition) {
683 if (current_exec_index == 0) {
686 ret = load_addr_mode(&done);
695 else if (current_exec_index == 1) {
697 char rel = get_cpu_data_buf();
698 unsigned short addr = cpu_reg.pc;
699 unsigned short br_addr = cpu_reg.pc + rel;
701 if (addr >> 8 == br_addr >> 8) {
703 cpu_reg.pc = br_addr;
707 set_cpu_addr_buf(br_addr);
711 else if (current_exec_index == 2) {
713 unsigned short br_addr = get_cpu_addr_buf();
714 cpu_reg.pc = br_addr;
723 * Branch on Carry Clear: BCC
728 return branch(cpu_reg.status.carry == 0);
732 * Branch on Carry Set: BCS
737 return branch(cpu_reg.status.carry == 1);
741 * Branch on Result Zero: BEQ
746 return branch(cpu_reg.status.zero == 1);
754 * Branch on Result Minus: BMI
759 return branch(cpu_reg.status.negative == 1);
763 * Branch on Result not Zero: BNE
768 return branch(cpu_reg.status.zero == 0);
772 * Branch on Result Plus: BPL
777 return branch(cpu_reg.status.negative == 0);
785 * Branch on Overflow Clear: BVC
790 return branch(cpu_reg.status.overflow == 0);
794 * Branch on Overflow Set: BVS
799 return branch(cpu_reg.status.overflow == 1);
835 * Decrement Index X by One: DEX
843 set_negative(cpu_reg.x);
851 * Decrement Index Y by One: DEY
859 set_negative(cpu_reg.y);
875 * Increment Index X by One: INX
883 set_negative(cpu_reg.x);
894 set_negative(cpu_reg.y);
901 static int jmp(int cycle, int *done) {
902 switch (current_inst->addr_mode) {
906 load_addr(cpu_reg.pc, 1);
910 else if (cycle == 1) {
911 load_addr(cpu_reg.pc, 2);
921 load_addr(cpu_reg.pc, 1);
925 else if (cycle == 1) {
926 load_addr(cpu_reg.pc, 2);
930 else if (cycle == 2) {
931 load_memory(get_cpu_addr_buf());
934 else if (cycle == 3) {
935 unsigned char low, hi;
937 low = get_cpu_data_buf();
938 hi = load_memory(get_cpu_addr_buf() + 1);
939 addr = (hi << 8) | low;
940 set_cpu_addr_buf(addr);
953 * Jump to New Location: JMP
954 * Jump to new location
961 ret = jmp(current_exec_index, &done);
968 cpu_reg.pc = get_cpu_addr_buf();
975 * Jump to New Location Saving Return Address: JSR
983 if (current_exec_index < 2) {
984 return jmp(current_exec_index, &done);
987 else if (current_exec_index == 3) {
988 //save return addr(-1) hi.
989 push((cpu_reg.pc - 1) >> 8);
993 else if (current_exec_index == 4) {
994 //save return addr(-1) low.
995 push(cpu_reg.pc - 1);
999 else if (current_exec_index == 5) {
1000 cpu_reg.pc = get_cpu_addr_buf();
1008 * Load Accumulator with Memory: LDA
1012 int func_LDA(void) {
1016 ret = load_addr_mode(&done);
1023 cpu_reg.acc = get_cpu_data_buf();
1024 //ldx N/Z flags set.
1025 set_negative(cpu_reg.acc);
1026 set_zero(cpu_reg.acc);
1033 * Load Index X with Memory: LDX
1037 int func_LDX(void) {
1041 ret = load_addr_mode(&done);
1048 cpu_reg.x = get_cpu_data_buf();
1049 //ldx N/Z flags set.
1050 set_negative(cpu_reg.x);
1051 set_zero(cpu_reg.x);
1058 * Load Index Y with Memory: LDY
1062 int func_LDY(void) {
1066 ret = load_addr_mode(&done);
1073 cpu_reg.y = get_cpu_data_buf();
1074 //ldx N/Z flags set.
1075 set_negative(cpu_reg.y);
1076 set_zero(cpu_reg.y);
1082 int func_LSR(void) {
1086 int func_NOP(void) {
1090 int func_ORA(void) {
1094 int func_PHA(void) {
1098 int func_PHP(void) {
1102 int func_PLA(void) {
1106 int func_PLP(void) {
1110 int func_ROL(void) {
1114 int func_ROR(void) {
1118 int func_RTI(void) {
1123 * Return from Subroutine: RTS
1124 * Return from Subroutine
1127 int func_RTS(void) {
1130 if (current_exec_index == 0) {
1131 //pop return addr low.
1136 if (current_exec_index == 0) {
1137 //set return addr low.
1138 set_cpu_addr_buf(get_cpu_data_buf());
1142 else if (current_exec_index == 1) {
1143 //pop return addr hi.
1148 else if (current_exec_index == 1) {
1149 unsigned char hi, lo;
1150 unsigned short addr;
1152 //set return addr hi
1153 lo = get_cpu_addr_buf();
1154 hi = get_cpu_data_buf();
1155 addr = (hi << 8) | lo;
1156 set_cpu_addr_buf(addr);
1160 else if (current_exec_index == 2) {
1162 cpu_reg.pc = get_cpu_addr_buf() + 1;
1169 int func_SBC(void) {
1173 int func_SEC(void) {
1177 int func_SED(void) {
1182 * set interrupt disable.
1184 int func_SEI(void) {
1185 cpu_reg.status.irq_disable = 1;
1191 * Store Accumulator in Memory: STA
1195 int func_STA(void) {
1199 ret = store_addr_mode(cpu_reg.acc, &done);
1211 * Store Index X in Memory: STX
1215 int func_STX(void) {
1219 ret = store_addr_mode(cpu_reg.x, &done);
1231 * Store Index Y in Memory: STY
1235 int func_STY(void) {
1239 ret = store_addr_mode(cpu_reg.y, &done);
1251 * Transfer Accumulator to Index X: TAX
1255 int func_TAX(void) {
1256 cpu_reg.x = cpu_reg.acc;
1258 set_negative(cpu_reg.x);
1259 set_zero(cpu_reg.x);
1266 * Transfer Accumulator to Index Y: TAY
1270 int func_TAY(void) {
1271 cpu_reg.y = cpu_reg.acc;
1273 set_negative(cpu_reg.y);
1274 set_zero(cpu_reg.y);
1281 * Transfer Stack Pointer to Index X: TSX
1285 int func_TSX(void) {
1286 cpu_reg.x = cpu_reg.sp;
1288 set_negative(cpu_reg.x);
1289 set_zero(cpu_reg.x);
1296 * Transfer Index X to Accumulator: TXA
1300 int func_TXA(void) {
1301 cpu_reg.acc = cpu_reg.x;
1303 set_negative(cpu_reg.acc);
1304 set_zero(cpu_reg.acc);
1311 * Transfer Index X to Stack Pointer: TXS
1315 int func_TXS(void) {
1316 cpu_reg.sp = cpu_reg.x;
1318 set_negative(cpu_reg.sp);
1319 set_zero(cpu_reg.sp);
1326 * Transfer Index Y to Accumulator: TYA
1330 int func_TYA(void) {
1331 cpu_reg.acc = cpu_reg.y;
1333 set_negative(cpu_reg.y);
1334 set_zero(cpu_reg.y);
1342 * return execution cycle count
1344 int decode6502(unsigned char inst) {
1346 struct opcode_map * omap = &opcode_list[inst];
1347 if (omap->func == NULL) {
1351 dprint("decode inst: %02x > %s, %d cycle, %d len\n",
1352 inst, omap->mnemonic, omap->cycle, omap->inst_len);
1354 current_inst = omap;
1355 current_exec_index = 0;
1360 int test_and_set_exec(void) {
1368 int execute6502(void) {
1370 ret = current_inst->func();
1371 current_exec_index++;
1374 if (exec_done && (current_inst->cycle - 1 != current_exec_index)) {
1375 if (current_inst->cycle_aux && (
1376 current_inst->addr_mode == ADDR_MODE_ABS_X ||
1377 current_inst->addr_mode == ADDR_MODE_ABS_Y ||
1378 current_inst->addr_mode == ADDR_MODE_INDIR_INDEX ) &&
1379 (current_inst->cycle == current_exec_index)) {
1382 else if ((current_inst->addr_mode == ADDR_MODE_REL) &&
1383 ((current_inst->cycle == current_exec_index) ||
1384 (current_inst->cycle + 1 == current_exec_index ))) {
1388 fprintf(stderr, "instruction cycle check error!!\n");
1398 void pc_set(unsigned short addr) {
1402 unsigned short pc_get(void) {
1406 void pc_move(int offset) {
1407 cpu_reg.pc += offset;
1410 void dump_6502(int full) {
1412 printf("6502 CPU registers:\n");
1414 printf("pc: %04x\n", cpu_reg.pc);
1416 printf("acc: %02x\n", cpu_reg.acc);
1417 printf("x: %02x\n", cpu_reg.x);
1418 printf("y: %02x\n", cpu_reg.y);
1419 printf("sp: %02x\n", cpu_reg.sp);
1420 printf("status:\n");
1421 printf(" negative: %d\n", cpu_reg.status.negative);
1422 printf(" overflow: %d\n", cpu_reg.status.overflow);
1423 printf(" break: %d\n", cpu_reg.status.break_mode);
1424 printf(" decimal: %d\n", cpu_reg.status.decimal);
1425 printf(" irq: %d\n", cpu_reg.status.irq_disable);
1426 printf(" zero: %d\n", cpu_reg.status.zero);
1427 printf(" carry: %d\n", cpu_reg.status.carry);
1428 printf("-------------------\n");
1430 //printf("data: %02x\n", cpu_data_buffer);
1434 int init_6502core(void) {
1435 memset(&cpu_reg, 0, sizeof(struct cpu_6502));
1436 current_inst = NULL;
1437 current_exec_index = 0;