1 #include "6502.h" 2 3 #include <stdio.h> 4 5 /* included for debugging purposes */ 6 #include <string.h> 7 8 static CPU cpu; 9 static MEM mem; /* 8 bit word */ 10 11 static uint8_t cyc; 12 static uint8_t opc; 13 14 static uint16_t tmp; 15 static uint16_t addr_abs; 16 static uint16_t addr_rel; 17 18 INS decode[0x100]; 19 static INS prev_ins; 20 21 /* Cpu methods */ 22 void CPU_init(void) { 23 cpu.ac = cpu.x = cpu.y = cpu.sp = cpu.st = 0; 24 cyc = opc = tmp = 0; 25 prev_ins = (INS) {"???", &NUL, &IMP, 7}; 26 } 27 28 void CPU_reset(void) { 29 cpu.sp = 0xFF; 30 cpu.st = 0x00; 31 32 /* little endian */ 33 uint16_t lo = MEM_read(0xFFFC); 34 uint16_t hi = MEM_read(0xFFFD); 35 36 cpu.pc = (hi << 8) | lo; 37 38 addr_abs = addr_rel = opc = 0x0000; 39 40 /* simulate 8 cycles needed to reset the cpu */ 41 cyc = 8; 42 } 43 44 void CPU_fetch(INS *ins) { 45 *ins = decode[opc = MEM_read(cpu.pc)]; 46 } 47 48 uint8_t CPU_exec(INS ins) { 49 /* simulate instructions cycles */ 50 do { 51 if (cyc == 0) { 52 if (!strcmp(ins.name, "???")) { 53 /* printf("EXEC: invalid instruction reached\n"); */ 54 return 1; 55 } else if (!strcmp(ins.name, "BNE") && !(strcmp(prev_ins.name, "BNE"))) { 56 /* printf("EXEC: consecutive BNE reached\n"); */ 57 return 1; 58 } 59 60 cpu.pc++; 61 cyc = ins.cycles; 62 63 uint8_t add_cyc_0 = ins.mode(); 64 uint8_t add_cyc_1 = ins.op(); 65 66 prev_ins = ins; 67 cyc += add_cyc_0 & add_cyc_1; 68 } 69 } while(--cyc); 70 71 return 0; 72 } 73 74 /* interrupt request */ 75 void CPU_irq(void) { 76 if(!CPU_get_flag(I)) { 77 /* save pc */ 78 MEM_write(0x100 + cpu.sp--, (cpu.pc >> 8) & 0x00FF); 79 MEM_write(0x100 + cpu.sp--, cpu.pc & 0x00FF); 80 81 /* save st */ 82 MEM_write(0x100 + cpu.sp--, cpu.st | (1 << 4) | (1 << 5)); 83 84 CPU_set_flag(I, 1); 85 86 uint16_t lo = MEM_read(0xFFFE); 87 uint16_t hi = MEM_read(0xFFFF); 88 89 cpu.pc = ((hi << 8) & 0xFF00) | (lo & 0x00FF); 90 91 cyc = 8; 92 } 93 } 94 95 /* non maskeable interrupt request */ 96 void CPU_nm_irq(void) { 97 /* save program counter to stack */ 98 MEM_write(0x100 + cpu.sp--, (cpu.pc >> 8) & 0x00FF); 99 MEM_write(0x100 + cpu.sp--, cpu.pc & 0x00FF); 100 101 /* save cpu status to stack */ 102 MEM_write(0x100 + cpu.sp--, cpu.st | (1 << 4) | (1 << 5)); 103 CPU_set_flag(I, 1); 104 105 addr_abs = 0xFFFA; 106 uint16_t lo = MEM_read(addr_abs + 0); 107 uint16_t hi = MEM_read(addr_abs + 1); 108 109 cpu.pc = (hi << 8) | lo; 110 111 cyc = 8; 112 } 113 114 void CPU_branch(void) { 115 cyc++; 116 addr_abs = cpu.pc + addr_rel; 117 118 /* if address changes page */ 119 if((addr_abs & 0xFF00) != (cpu.pc & 0xFF00)) 120 cyc++; 121 122 cpu.pc = addr_abs; 123 } 124 125 void CPU_set_flag(ST_FLAG flag, uint8_t val) { 126 cpu.st = val ? cpu.st | (1 << flag) : cpu.st & ~(1 << flag); 127 } 128 129 uint8_t CPU_get_flag(ST_FLAG flag) { 130 return (cpu.st & (1 << flag)) >> flag; 131 } 132 133 void print_reg(uint8_t reg) { 134 for(unsigned long i = ((sizeof(reg) * 8)); i > 0; i--) { 135 putchar((reg & (0x01 << (i - 1))) ? '1' : '0'); 136 putchar(' '); 137 } 138 putchar('\n'); 139 } 140 141 void CPU_dump(void) { 142 INS aux = decode[MEM_read(cpu.pc)]; 143 144 printf(" a: %02X (%3d) N V - B D I Z C\n" 145 " x: %02X (%3d) ", cpu.ac, cpu.ac, cpu.x, cpu.x); 146 print_reg(cpu.st); 147 printf(" y: %02X (%3d)\n" 148 " sp: %02X\n" 149 " pc: %04X -> %02X (%s)(%s)\n" 150 "\033[5A", cpu.y, cpu.y, cpu.sp, cpu.pc, mem.ram[cpu.pc], aux.name, 151 CPU_mode_name(aux.mode)); 152 } 153 154 uint16_t CPU_get_pc(void) { 155 return cpu.pc; 156 } 157 158 /* Memory methods */ 159 void MEM_init(void) { 160 for(uint16_t i = 0; i < 0xFFFF; i++) 161 mem.ram[i] = 0; 162 } 163 164 void MEM_set_pc_start(uint16_t addr) { 165 mem.ram[0xFFFC] = (addr & 0x00FF); 166 mem.ram[0xFFFD] = ((addr & 0xFF00) >> 8); 167 } 168 169 int MEM_load_from_file(char *path) { 170 FILE *fp; 171 172 if(path == NULL) { 173 return 1; 174 } 175 176 fp = fopen(path, "rb"); 177 if(fp == NULL) { 178 fprintf(stderr, "ERROR: file \"%s\" not found.\n", path); 179 return 2; 180 } 181 182 fread(mem.ram, 1, sizeof(mem.ram), fp); 183 /* fread(mem.ram + 0x8000, 1, 0x7FFF - 0x6, fp); */ 184 185 fclose(fp); 186 return 0; 187 } 188 189 uint8_t MEM_read(uint16_t addr) { 190 return mem.ram[addr]; 191 } 192 193 uint8_t MEM_write(uint16_t addr, uint8_t val) { 194 mem.ram[addr] = val; 195 return val; 196 } 197 198 void MEM_dump() { 199 for(uint16_t i = 0; i < 0xF; i++) 200 printf("%02X ", mem.ram[i]); 201 202 putchar('\n'); 203 } 204 205 void MEM_dump_page(uint16_t page) { 206 uint16_t j = 1; 207 208 printf("Page %04X:\n", page); 209 for(uint16_t i = page; i <= (page + 0xFF); i++, j++) 210 printf("%02X %s", mem.ram[i], (j % 0x1E) ? "" : "\n"); 211 212 putchar('\n'); 213 } 214 215 void MEM_dump_last_six(void) { 216 printf("Last six:\n"); 217 for(size_t i = 0xFFFA; i <= 0xFFFF; i++) 218 printf("%02X ", mem.ram[i]); 219 220 putchar('\n'); 221 } 222 223 char *CPU_mode_name(uint8_t (*mode)(void)) { 224 if(mode == &IMM) return "IMM"; 225 else if(mode == &ABS) return "ABS"; 226 else if(mode == &ABX) return "ABX"; 227 else if(mode == &ABY) return "ABY"; 228 else if(mode == &IMP) return "IMP"; 229 else if(mode == &IND) return "IND"; 230 else if(mode == &IZX) return "IZX"; 231 else if(mode == &IZY) return "IZY"; 232 else if(mode == &REL) return "REL"; 233 else if(mode == &ZP0) return "ZP0"; 234 else if(mode == &ZPX) return "ZPX"; 235 else if(mode == &ZPY) return "ZPY"; 236 237 return "NUL"; 238 } 239 240 /* Addressing modes */ 241 uint8_t ABS(void) { 242 uint16_t lo = MEM_read(cpu.pc++); 243 uint16_t hi = MEM_read(cpu.pc++); 244 245 addr_abs = (hi << 8) | lo; 246 247 /* printf("Address: %04X -> (%02X)\n", addr_abs, MEM_read(addr_abs)); */ 248 return 0; 249 } 250 251 uint8_t ABX(void) { 252 uint16_t lo = MEM_read(cpu.pc++); 253 uint16_t hi = MEM_read(cpu.pc++); 254 255 addr_abs = (hi << 8) | lo; 256 257 /* printf("address fetched: %04X\nx register: %02X\nend address: %04X (%02X)\n", addr_abs, cpu.x, addr_abs + cpu.x, MEM_read(addr_abs + cpu.x)); */ 258 259 addr_abs += cpu.x; 260 /* printf("Address: %04X -> (%02X)\n", addr_abs, MEM_read(addr_abs)); */ 261 262 return ((addr_abs & 0x00FF) != (hi << 8)) ? 1 : 0; 263 } 264 265 uint8_t ABY(void) { 266 uint16_t lo = MEM_read(cpu.pc++); 267 uint16_t hi = MEM_read(cpu.pc++); 268 269 addr_abs = (hi << 8) | lo; 270 271 /* printf("address fetched: %04X\ny register: %02X\nend address: %04X (%02X)\n", addr_abs, cpu.y, addr_abs + cpu.y, MEM_read(addr_abs + cpu.y)); */ 272 273 addr_abs += cpu.y; 274 /* printf("Address: %04X -> (%02X)\n", addr_abs, MEM_read(addr_abs)); */ 275 return ((addr_abs & 0x00FF) != (hi << 8)) ? 1 : 0; 276 } 277 278 uint8_t IMM(void) { 279 addr_abs = cpu.pc++; 280 /* printf("Address: %04X -> (%02X)\n", addr_abs, MEM_read(addr_abs)); */ 281 return 0; 282 } 283 284 uint8_t IMP(void) { 285 tmp = cpu.ac; 286 return 0; 287 } 288 289 uint8_t IND(void) { 290 /* get a direction from memory */ 291 uint16_t lo = MEM_read(cpu.pc++); 292 uint16_t hi = MEM_read(cpu.pc++); 293 294 /* assign the direction to ptr */ 295 uint16_t p = (hi << 8) | lo; 296 297 /* get the address pointed by p 298 * and simulate page boundary hardware bug */ 299 addr_abs = (MEM_read((lo == 0xFF) ? (p & 0xFF00) : p + 1) << 8) | MEM_read(p); 300 301 /* printf("Address: %04X -> (%02X)\n", addr_abs, MEM_read(addr_abs)); */ 302 return 0; 303 } 304 305 uint8_t IZX(void) { 306 uint8_t addr = MEM_read(cpu.pc++); 307 308 /* get a direction from memory */ 309 uint16_t lo = MEM_read((addr + cpu.x) & 0xFF); 310 uint16_t hi = MEM_read((addr + cpu.x + 1) & 0xFF); 311 312 addr_abs = ((hi << 8) & 0xFF00) | lo; 313 314 /* printf("Address: %04X -> (%02X)\n", addr_abs, MEM_read(addr_abs)); */ 315 316 return 0; 317 } 318 319 uint8_t IZY(void) { 320 uint8_t addr = MEM_read(cpu.pc++); 321 322 /* get a direction from memory */ 323 uint16_t lo = MEM_read(addr); 324 uint16_t hi = MEM_read(addr + 1); 325 326 addr_abs = ((hi << 8) & 0xFF00) | lo; 327 addr_abs += cpu.y; 328 329 /* printf("Address: %04X -> (%02X)\n", addr_abs, MEM_read(addr_abs)); */ 330 331 return ((addr_abs & 0xFF00) != (hi << 8)) ? 1 : 0; 332 } 333 334 uint8_t REL(void) { 335 addr_rel = (MEM_read(cpu.pc++) & 0x00FF); 336 /* printf("REL: offset: %02X (%d)\n", addr_rel, (int8_t)addr_rel); */ 337 338 /* signed byte */ 339 if (addr_rel & (1 << 7)) 340 addr_rel |= 0xFF00; 341 342 return 0; 343 } 344 345 /* read only the offset of the zero page */ 346 uint8_t ZP0(void) { 347 addr_abs = (MEM_read(cpu.pc++) & 0x00FF); 348 349 /* printf("Address: %04X -> (%02X)\n", addr_abs, MEM_read(addr_abs)); */ 350 return 0; 351 } 352 353 uint8_t ZPX(void) { 354 addr_abs = (MEM_read(cpu.pc++) + cpu.x) & 0x00FF; 355 356 /* printf("Address: %04X -> (%02X)\n", addr_abs, MEM_read(addr_abs)); */ 357 return 0; 358 } 359 360 uint8_t ZPY(void) { 361 addr_abs = (MEM_read(cpu.pc++) + cpu.y) & 0x00FF; 362 363 /* printf("Address: %04X -> (%02X)\n", addr_abs, MEM_read(addr_abs)); */ 364 return 0; 365 } 366 367 368 /* Instructions */ 369 uint8_t ADC(void) { 370 uint16_t data = MEM_read(addr_abs); 371 uint16_t res = (cpu.ac + data + (uint16_t)CPU_get_flag(C)); 372 373 CPU_set_flag(N, res & (1 << 7)); 374 CPU_set_flag(Z, (res & 0x00FF) == 0); 375 CPU_set_flag(C, ((res & 0xFF00) >> 7)); 376 CPU_set_flag(V, ((cpu.ac^res) & ~(cpu.ac^data)) & (1 << 7)); 377 378 cpu.ac = (uint8_t)(res & 0x00FF); 379 380 return 1; 381 } 382 383 uint8_t AND(void) { 384 cpu.ac &= MEM_read(addr_abs); 385 386 CPU_set_flag(Z, cpu.ac == 0); 387 CPU_set_flag(N, cpu.ac & (1 << 7)); 388 389 return 1; 390 } 391 392 uint8_t ASL(void) { 393 if(decode[opc].mode == &IMP) { 394 tmp = cpu.ac << 1; 395 CPU_set_flag(C, (cpu.ac & (1 << 7))); 396 cpu.ac = (tmp & 0x00FF); 397 } 398 else { 399 tmp = MEM_read(addr_abs) << 1; 400 CPU_set_flag(C, MEM_read(addr_abs) & (1 << 7)); 401 MEM_write(addr_abs, tmp & 0x00FF); 402 } 403 404 CPU_set_flag(Z, tmp == 0); 405 CPU_set_flag(N, tmp & (1 << 7)); 406 407 return 0; 408 } 409 410 uint8_t BCC(void) { 411 if(!CPU_get_flag(C)) 412 CPU_branch(); 413 414 return 0; 415 } 416 417 uint8_t BCS(void) { 418 if(CPU_get_flag(C)) 419 CPU_branch(); 420 421 return 0; 422 } 423 424 uint8_t BEQ(void) { 425 if(CPU_get_flag(Z)) 426 CPU_branch(); 427 428 return 0; 429 } 430 431 uint8_t BIT(void) { 432 tmp = (MEM_read(addr_abs) & 0x00FF); 433 434 CPU_set_flag(Z, (cpu.ac & tmp) == 0); 435 CPU_set_flag(V, tmp & (1 << 6)); 436 CPU_set_flag(N, tmp & (1 << 7)); 437 438 return 0; 439 } 440 441 uint8_t BMI(void) { 442 if(CPU_get_flag(N)) 443 CPU_branch(); 444 445 return 0; 446 } 447 448 uint8_t BNE(void) { 449 if(!CPU_get_flag(Z)) 450 CPU_branch(); 451 452 return 0; 453 } 454 455 uint8_t BPL(void) { 456 if(!CPU_get_flag(N)) 457 CPU_branch(); 458 459 return 0; 460 } 461 462 uint8_t BRK(void) { 463 /* save program counter to stack */ 464 MEM_write(0x100 + cpu.sp--, (cpu.pc >> 8) & 0x00FF); 465 MEM_write(0x100 + cpu.sp--, cpu.pc & 0x00FF); 466 467 /* save cpu status to stack */ 468 MEM_write(0x100 + cpu.sp--, cpu.st | (1 << 4) | (1 << 5)); 469 CPU_set_flag(I, 1); 470 471 uint16_t lo = MEM_read(0xFFFE); 472 uint16_t hi = MEM_read(0xFFFF); 473 474 cpu.pc = (hi << 8) | lo; 475 476 return 0; 477 } 478 479 uint8_t BVC(void) { 480 if(!CPU_get_flag(V)) 481 CPU_branch(); 482 483 return 0; 484 } 485 486 uint8_t BVS(void) { 487 if(CPU_get_flag(V)) 488 CPU_branch(); 489 490 return 0; 491 } 492 493 uint8_t CLC(void) { 494 CPU_set_flag(C, 0); 495 return 0; 496 } 497 498 uint8_t CLD(void) { 499 CPU_set_flag(D, 0); 500 return 0; 501 } 502 503 uint8_t CLI(void) { 504 CPU_set_flag(I, 0); 505 return 0; 506 } 507 508 uint8_t CLV(void) { 509 CPU_set_flag(V, 0); 510 return 0; 511 } 512 513 uint8_t CMP(void) { 514 tmp = (MEM_read(addr_abs) & 0x00FF); 515 516 /* printf("cmp: %d, acc: %d\n", tmp, cpu.ac); */ 517 518 CPU_set_flag(C, cpu.ac >= tmp); 519 CPU_set_flag(Z, cpu.ac == tmp); 520 CPU_set_flag(N, (cpu.ac - tmp) & (1<<7)); 521 522 return 0; 523 } 524 525 uint8_t CPX(void) { 526 tmp = (MEM_read(addr_abs) & 0x00FF); 527 528 CPU_set_flag(C, cpu.x >= tmp); 529 CPU_set_flag(Z, cpu.x == tmp); 530 CPU_set_flag(N, (cpu.x - tmp) & (1<<7)); 531 532 return 0; 533 } 534 535 uint8_t CPY(void) { 536 tmp = (MEM_read(addr_abs) & 0x00FF); 537 538 CPU_set_flag(C, cpu.y >= tmp); 539 CPU_set_flag(Z, cpu.y == tmp); 540 CPU_set_flag(N, (cpu.y - tmp) & (1<<7)); 541 542 return 0; 543 } 544 545 uint8_t DEC(void) { 546 tmp = MEM_write(addr_abs, MEM_read(addr_abs) - 1) & 0x00FF; 547 548 CPU_set_flag(Z, tmp == 0); 549 CPU_set_flag(N, tmp & (1 << 7)); 550 551 return 0; 552 } 553 554 /* Decrements X register */ 555 uint8_t DEX(void) { 556 cpu.x -= 1; 557 558 CPU_set_flag(Z, cpu.x == 0); 559 CPU_set_flag(N, cpu.x & (1 << 7)); 560 561 return 0; 562 } 563 564 /* Decrements Y register */ 565 uint8_t DEY(void) { 566 cpu.y -= 1; 567 568 CPU_set_flag(Z, cpu.y == 0); 569 CPU_set_flag(N, cpu.y & (1 << 7)); 570 571 return 0; 572 } 573 574 uint8_t EOR(void) { 575 cpu.ac ^= MEM_read(addr_abs); 576 577 CPU_set_flag(Z, cpu.ac == 0); 578 CPU_set_flag(N, cpu.ac & (1 << 7)); 579 580 return 1; 581 } 582 583 uint8_t INC(void) { 584 tmp = MEM_write(addr_abs, MEM_read(addr_abs) + 1) & 0x00FF; 585 586 CPU_set_flag(Z, tmp == 0); 587 CPU_set_flag(N, tmp & (1 << 7)); 588 589 return 0; 590 } 591 592 uint8_t INX(void) { 593 cpu.x += 1; 594 595 CPU_set_flag(Z, cpu.x == 0); 596 CPU_set_flag(N, cpu.x & (1 << 7)); 597 598 return 0; 599 } 600 601 uint8_t INY(void) { 602 cpu.y += 1; 603 604 CPU_set_flag(Z, cpu.y == 0); 605 CPU_set_flag(N, cpu.y & (1 << 7)); 606 607 return 0; 608 } 609 610 uint8_t JMP(void) { 611 cpu.pc = addr_abs; 612 return 0; 613 } 614 615 uint8_t JSR(void) { 616 cpu.pc--; 617 618 MEM_write(0x100 + cpu.sp--, (cpu.pc & 0xFF00) >> 8); 619 MEM_write(0x100 + cpu.sp--, (cpu.pc & 0x00FF)); 620 621 cpu.pc = addr_abs; 622 623 return 0; 624 } 625 626 uint8_t LDA(void) { 627 cpu.ac = MEM_read(addr_abs); 628 629 CPU_set_flag(Z, cpu.ac == 0); 630 CPU_set_flag(N, cpu.ac & (1 << 7)); 631 632 return 1; 633 } 634 635 uint8_t LDX(void) { 636 cpu.x = MEM_read(addr_abs); 637 638 CPU_set_flag(Z, cpu.x == 0); 639 CPU_set_flag(N, cpu.x & (1 << 7)); 640 641 return 1; 642 } 643 644 uint8_t LDY(void) { 645 cpu.y = MEM_read(addr_abs); 646 647 CPU_set_flag(Z, cpu.y == 0); 648 CPU_set_flag(N, cpu.y & (1 << 7)); 649 650 return 1; 651 } 652 653 uint8_t LSR(void) { 654 if(decode[opc].mode == &IMP) { 655 tmp = (cpu.ac >> 1); 656 CPU_set_flag(C, cpu.ac & 0x01); 657 cpu.ac = (tmp & 0x00FF); 658 } 659 else { 660 tmp = (MEM_read(addr_abs) >> 1); 661 CPU_set_flag(C, MEM_read(addr_abs) & 0x01); 662 MEM_write(addr_abs, tmp & 0x00FF); 663 } 664 665 CPU_set_flag(Z, tmp == 0); 666 CPU_set_flag(N, tmp & (1 << 7)); 667 668 return 0; 669 } 670 671 uint8_t NOP(void) { 672 return 0; 673 } 674 675 uint8_t ORA(void) { 676 cpu.ac |= MEM_read(addr_abs); 677 678 CPU_set_flag(Z, cpu.ac == 0); 679 CPU_set_flag(N, cpu.ac & (1 << 7)); 680 681 return 1; 682 } 683 684 uint8_t PHA(void) { 685 MEM_write(0x100 + cpu.sp--, cpu.ac); 686 687 return 0; 688 } 689 690 uint8_t PHP(void) { 691 MEM_write(0x100 + cpu.sp--, cpu.st | (1 << 4) | (1 << 5)); 692 693 return 0; 694 } 695 696 uint8_t PLA(void) { 697 cpu.ac = MEM_read(0x100 + ++cpu.sp); 698 699 CPU_set_flag(Z, (cpu.ac == 0)); 700 CPU_set_flag(N, cpu.ac & (1 << 7)); 701 702 return 0; 703 } 704 705 uint8_t PLP(void) { 706 uint8_t B_is_set = CPU_get_flag(B); 707 uint8_t U_is_set = CPU_get_flag(U); 708 709 /* restore status */ 710 cpu.st = MEM_read(0x100 + ++cpu.sp); 711 712 /* This two flags stay the same as before */ 713 CPU_set_flag(B, B_is_set); 714 CPU_set_flag(U, U_is_set); 715 716 return 0; 717 } 718 719 uint8_t ROL(void) { 720 if(decode[opc].mode == &IMP) { 721 tmp = (cpu.ac << 1) & 0xFE; 722 tmp |= CPU_get_flag(C); 723 724 CPU_set_flag(C, cpu.ac & (1 << 7)); 725 cpu.ac = (tmp & 0x00FF); 726 } 727 else { 728 tmp = (MEM_read(addr_abs) << 1) & 0xFE; 729 tmp |= CPU_get_flag(C); 730 731 CPU_set_flag(C, MEM_read(addr_abs) & (1 << 7)); 732 MEM_write(addr_abs, tmp & 0x00FF); 733 } 734 735 CPU_set_flag(Z, tmp == 0); 736 CPU_set_flag(N, tmp & (1 << 7)); 737 738 return 0; 739 } 740 741 uint8_t ROR(void) { 742 if(decode[opc].mode == &IMP) { 743 tmp = (cpu.ac >> 1) & 0x7F; 744 tmp |= (CPU_get_flag(C) << 7); 745 746 CPU_set_flag(C, cpu.ac & 0x01); 747 748 cpu.ac = (tmp & 0x00FF); 749 } 750 else { 751 tmp = (MEM_read(addr_abs) >> 1) & 0x7F; 752 tmp |= (CPU_get_flag(C) << 7); 753 754 CPU_set_flag(C, MEM_read(addr_abs) & 1); 755 MEM_write(addr_abs, tmp & 0x00FF); 756 } 757 758 CPU_set_flag(Z, tmp == 0); 759 CPU_set_flag(N, tmp & (1 << 7)); 760 761 return 0; 762 } 763 764 uint8_t RTI(void) { 765 uint8_t B_is_set = CPU_get_flag(B); 766 uint8_t U_is_set = CPU_get_flag(U); 767 768 /* restore status */ 769 cpu.st = MEM_read(0x100 + ++cpu.sp); 770 771 /* This two flags stay the same as before */ 772 CPU_set_flag(B, B_is_set); 773 CPU_set_flag(U, U_is_set); 774 775 /* restore pc */ 776 cpu.pc = MEM_read(0x100 + ++cpu.sp); 777 cpu.pc |= (MEM_read(0x100 + ++cpu.sp) << 8); 778 779 return 0; 780 } 781 782 uint8_t RTS(void) { 783 cpu.pc = MEM_read(0x100 + ++cpu.sp); 784 cpu.pc |= (MEM_read(0x100 + ++cpu.sp) << 8); 785 786 CPU_set_flag(B, 0); 787 788 cpu.pc++; 789 790 return 0; 791 } 792 793 uint8_t SBC(void) { 794 uint16_t data = MEM_read(addr_abs) ^ 0xFF; 795 uint16_t res = (cpu.ac + data + (uint16_t)CPU_get_flag(C)); 796 797 CPU_set_flag(N, res & (1 << 7)); 798 CPU_set_flag(Z, (res & 0x00FF) == 0); 799 CPU_set_flag(C, ((res & 0xFF00) >> 7)); 800 CPU_set_flag(V, ((cpu.ac^res) & ~(cpu.ac^data)) & (1 << 7)); 801 802 cpu.ac = (uint8_t)(res & 0x00FF); 803 804 return 1; 805 } 806 807 uint8_t SEC(void) { 808 CPU_set_flag(C, 1); 809 return 0; 810 } 811 812 uint8_t SED(void) { 813 CPU_set_flag(D, 1); 814 return 0; 815 } 816 817 uint8_t SEI(void) { 818 CPU_set_flag(I, 1); 819 return 0; 820 } 821 822 uint8_t STA(void) { 823 MEM_write(addr_abs, cpu.ac); 824 return 0; 825 } 826 827 uint8_t STX(void) { 828 MEM_write(addr_abs, cpu.x); 829 return 0; 830 } 831 832 uint8_t STY(void) { 833 MEM_write(addr_abs, cpu.y); 834 return 0; 835 } 836 837 uint8_t TAX(void) { 838 cpu.x = cpu.ac; 839 840 CPU_set_flag(Z, cpu.x == 0); 841 CPU_set_flag(N, cpu.x & (1 << 7)); 842 843 return 0; 844 } 845 846 uint8_t TAY(void) { 847 cpu.y = cpu.ac; 848 849 CPU_set_flag(Z, cpu.y == 0); 850 CPU_set_flag(N, cpu.y & (1 << 7)); 851 852 return 0; 853 } 854 855 uint8_t TSX(void) { 856 cpu.x = cpu.sp; 857 858 CPU_set_flag(Z, cpu.x == 0); 859 CPU_set_flag(N, cpu.x & (1 << 7)); 860 861 return 0; 862 } 863 864 uint8_t TXA(void) { 865 cpu.ac = cpu.x; 866 867 CPU_set_flag(Z, cpu.ac == 0); 868 CPU_set_flag(N, cpu.ac & (1 << 7)); 869 870 return 0; 871 } 872 873 uint8_t TXS(void) { 874 cpu.sp = cpu.x; 875 876 return 0; 877 } 878 879 uint8_t TYA(void) { 880 cpu.ac = cpu.y; 881 882 CPU_set_flag(Z, cpu.ac == 0); 883 CPU_set_flag(N, cpu.ac & (1 << 7)); 884 885 return 0; 886 } 887 888 uint8_t NUL(void) { 889 return 0; 890 } 891 892 /* Lookup table */ 893 INS decode[0x100] = { 894 {"BRK", &BRK, &IMM, 7}, {"ORA", &ORA, &IZX, 6}, {"???", &NUL, &IMP, 2}, 895 {"???", &NUL, &IMP, 8}, {"???", &NOP, &IMP, 3}, {"ORA", &ORA, &ZP0, 3}, 896 {"ASL", &ASL, &ZP0, 5}, {"???", &NUL, &IMP, 5}, {"PHP", &PHP, &IMP, 3}, 897 {"ORA", &ORA, &IMM, 2}, {"ASL", &ASL, &IMP, 2}, {"???", &NUL, &IMP, 2}, 898 {"???", &NOP, &IMP, 4}, {"ORA", &ORA, &ABS, 4}, {"ASL", &ASL, &ABS, 6}, 899 {"???", &NUL, &IMP, 6}, {"BPL", &BPL, &REL, 2}, {"ORA", &ORA, &IZY, 5}, 900 {"???", &NUL, &IMP, 2}, {"???", &NUL, &IMP, 8}, {"???", &NOP, &IMP, 4}, 901 {"ORA", &ORA, &ZPX, 4}, {"ASL", &ASL, &ZPX, 6}, {"???", &NUL, &IMP, 6}, 902 {"CLC", &CLC, &IMP, 2}, {"ORA", &ORA, &ABY, 4}, {"???", &NOP, &IMP, 2}, 903 {"???", &NUL, &IMP, 7}, {"???", &NOP, &IMP, 4}, {"ORA", &ORA, &ABX, 4}, 904 {"ASL", &ASL, &ABX, 7}, {"???", &NUL, &IMP, 7}, {"JSR", &JSR, &ABS, 6}, 905 {"AND", &AND, &IZX, 6}, {"???", &NUL, &IMP, 2}, {"???", &NUL, &IMP, 8}, 906 {"BIT", &BIT, &ZP0, 3}, {"AND", &AND, &ZP0, 3}, {"ROL", &ROL, &ZP0, 5}, 907 {"???", &NUL, &IMP, 5}, {"PLP", &PLP, &IMP, 4}, {"AND", &AND, &IMM, 2}, 908 {"ROL", &ROL, &IMP, 2}, {"???", &NUL, &IMP, 2}, {"BIT", &BIT, &ABS, 4}, 909 {"AND", &AND, &ABS, 4}, {"ROL", &ROL, &ABS, 6}, {"???", &NUL, &IMP, 6}, 910 {"BMI", &BMI, &REL, 2}, {"AND", &AND, &IZY, 5}, {"???", &NUL, &IMP, 2}, 911 {"???", &NUL, &IMP, 8}, {"???", &NOP, &IMP, 4}, {"AND", &AND, &ZPX, 4}, 912 {"ROL", &ROL, &ZPX, 6}, {"???", &NUL, &IMP, 6}, {"SEC", &SEC, &IMP, 2}, 913 {"AND", &AND, &ABY, 4}, {"???", &NOP, &IMP, 2}, {"???", &NUL, &IMP, 7}, 914 {"???", &NOP, &IMP, 4}, {"AND", &AND, &ABX, 4}, {"ROL", &ROL, &ABX, 7}, 915 {"???", &NUL, &IMP, 7}, {"RTI", &RTI, &IMP, 6}, {"EOR", &EOR, &IZX, 6}, 916 {"???", &NUL, &IMP, 2}, {"???", &NUL, &IMP, 8}, {"???", &NOP, &IMP, 3}, 917 {"EOR", &EOR, &ZP0, 3}, {"LSR", &LSR, &ZP0, 5}, {"???", &NUL, &IMP, 5}, 918 {"PHA", &PHA, &IMP, 3}, {"EOR", &EOR, &IMM, 2}, {"LSR", &LSR, &IMP, 2}, 919 {"???", &NUL, &IMP, 2}, {"JMP", &JMP, &ABS, 3}, {"EOR", &EOR, &ABS, 4}, 920 {"LSR", &LSR, &ABS, 6}, {"???", &NUL, &IMP, 6}, {"BVC", &BVC, &REL, 2}, 921 {"EOR", &EOR, &IZY, 5}, {"???", &NUL, &IMP, 2}, {"???", &NUL, &IMP, 8}, 922 {"???", &NOP, &IMP, 4}, {"EOR", &EOR, &ZPX, 4}, {"LSR", &LSR, &ZPX, 6}, 923 {"???", &NUL, &IMP, 6}, {"CLI", &CLI, &IMP, 2}, {"EOR", &EOR, &ABY, 4}, 924 {"???", &NOP, &IMP, 2}, {"???", &NUL, &IMP, 7}, {"???", &NOP, &IMP, 4}, 925 {"EOR", &EOR, &ABX, 4}, {"LSR", &LSR, &ABX, 7}, {"???", &NUL, &IMP, 7}, 926 {"RTS", &RTS, &IMP, 6}, {"ADC", &ADC, &IZX, 6}, {"???", &NUL, &IMP, 2}, 927 {"???", &NUL, &IMP, 8}, {"???", &NOP, &IMP, 3}, {"ADC", &ADC, &ZP0, 3}, 928 {"ROR", &ROR, &ZP0, 5}, {"???", &NUL, &IMP, 5}, {"PLA", &PLA, &IMP, 4}, 929 {"ADC", &ADC, &IMM, 2}, {"ROR", &ROR, &IMP, 2}, {"???", &NUL, &IMP, 2}, 930 {"JMP", &JMP, &IND, 5}, {"ADC", &ADC, &ABS, 4}, {"ROR", &ROR, &ABS, 6}, 931 {"???", &NUL, &IMP, 6}, {"BVS", &BVS, &REL, 2}, {"ADC", &ADC, &IZY, 5}, 932 {"???", &NUL, &IMP, 2}, {"???", &NUL, &IMP, 8}, {"???", &NOP, &IMP, 4}, 933 {"ADC", &ADC, &ZPX, 4}, {"ROR", &ROR, &ZPX, 6}, {"???", &NUL, &IMP, 6}, 934 {"SEI", &SEI, &IMP, 2}, {"ADC", &ADC, &ABY, 4}, {"???", &NOP, &IMP, 2}, 935 {"???", &NUL, &IMP, 7}, {"???", &NOP, &IMP, 4}, {"ADC", &ADC, &ABX, 4}, 936 {"ROR", &ROR, &ABX, 7}, {"???", &NUL, &IMP, 7}, {"???", &NOP, &IMP, 2}, 937 {"STA", &STA, &IZX, 6}, {"???", &NOP, &IMP, 2}, {"???", &NUL, &IMP, 6}, 938 {"STY", &STY, &ZP0, 3}, {"STA", &STA, &ZP0, 3}, {"STX", &STX, &ZP0, 3}, 939 {"???", &NUL, &IMP, 3}, {"DEY", &DEY, &IMP, 2}, {"???", &NOP, &IMP, 2}, 940 {"TXA", &TXA, &IMP, 2}, {"???", &NUL, &IMP, 2}, {"STY", &STY, &ABS, 4}, 941 {"STA", &STA, &ABS, 4}, {"STX", &STX, &ABS, 4}, {"???", &NUL, &IMP, 4}, 942 {"BCC", &BCC, &REL, 2}, {"STA", &STA, &IZY, 6}, {"???", &NUL, &IMP, 2}, 943 {"???", &NUL, &IMP, 6}, {"STY", &STY, &ZPX, 4}, {"STA", &STA, &ZPX, 4}, 944 {"STX", &STX, &ZPY, 4}, {"???", &NUL, &IMP, 4}, {"TYA", &TYA, &IMP, 2}, 945 {"STA", &STA, &ABY, 5}, {"TXS", &TXS, &IMP, 2}, {"???", &NUL, &IMP, 5}, 946 {"???", &NOP, &IMP, 5}, {"STA", &STA, &ABX, 5}, {"???", &NUL, &IMP, 5}, 947 {"???", &NUL, &IMP, 5}, {"LDY", &LDY, &IMM, 2}, {"LDA", &LDA, &IZX, 6}, 948 {"LDX", &LDX, &IMM, 2}, {"???", &NUL, &IMP, 6}, {"LDY", &LDY, &ZP0, 3}, 949 {"LDA", &LDA, &ZP0, 3}, {"LDX", &LDX, &ZP0, 3}, {"???", &NUL, &IMP, 3}, 950 {"TAY", &TAY, &IMP, 2}, {"LDA", &LDA, &IMM, 2}, {"TAX", &TAX, &IMP, 2}, 951 {"???", &NUL, &IMP, 2}, {"LDY", &LDY, &ABS, 4}, {"LDA", &LDA, &ABS, 4}, 952 {"LDX", &LDX, &ABS, 4}, {"???", &NUL, &IMP, 4}, {"BCS", &BCS, &REL, 2}, 953 {"LDA", &LDA, &IZY, 5}, {"???", &NUL, &IMP, 2}, {"???", &NUL, &IMP, 5}, 954 {"LDY", &LDY, &ZPX, 4}, {"LDA", &LDA, &ZPX, 4}, {"LDX", &LDX, &ZPY, 4}, 955 {"???", &NUL, &IMP, 4}, {"CLV", &CLV, &IMP, 2}, {"LDA", &LDA, &ABY, 4}, 956 {"TSX", &TSX, &IMP, 2}, {"???", &NUL, &IMP, 4}, {"LDY", &LDY, &ABX, 4}, 957 {"LDA", &LDA, &ABX, 4}, {"LDX", &LDX, &ABY, 4}, {"???", &NUL, &IMP, 4}, 958 {"CPY", &CPY, &IMM, 2}, {"CMP", &CMP, &IZX, 6}, {"???", &NOP, &IMP, 2}, 959 {"???", &NUL, &IMP, 8}, {"CPY", &CPY, &ZP0, 3}, {"CMP", &CMP, &ZP0, 3}, 960 {"DEC", &DEC, &ZP0, 5}, {"???", &NUL, &IMP, 5}, {"INY", &INY, &IMP, 2}, 961 {"CMP", &CMP, &IMM, 2}, {"DEX", &DEX, &IMP, 2}, {"???", &NUL, &IMP, 2}, 962 {"CPY", &CPY, &ABS, 4}, {"CMP", &CMP, &ABS, 4}, {"DEC", &DEC, &ABS, 6}, 963 {"???", &NUL, &IMP, 6}, {"BNE", &BNE, &REL, 2}, {"CMP", &CMP, &IZY, 5}, 964 {"???", &NUL, &IMP, 2}, {"???", &NUL, &IMP, 8}, {"???", &NOP, &IMP, 4}, 965 {"CMP", &CMP, &ZPX, 4}, {"DEC", &DEC, &ZPX, 6}, {"???", &NUL, &IMP, 6}, 966 {"CLD", &CLD, &IMP, 2}, {"CMP", &CMP, &ABY, 4}, {"NOP", &NOP, &IMP, 2}, 967 {"???", &NUL, &IMP, 7}, {"???", &NOP, &IMP, 4}, {"CMP", &CMP, &ABX, 4}, 968 {"DEC", &DEC, &ABX, 7}, {"???", &NUL, &IMP, 7}, {"CPX", &CPX, &IMM, 2}, 969 {"SBC", &SBC, &IZX, 6}, {"???", &NOP, &IMP, 2}, {"???", &NUL, &IMP, 8}, 970 {"CPX", &CPX, &ZP0, 3}, {"SBC", &SBC, &ZP0, 3}, {"INC", &INC, &ZP0, 5}, 971 {"???", &NUL, &IMP, 5}, {"INX", &INX, &IMP, 2}, {"SBC", &SBC, &IMM, 2}, 972 {"NOP", &NOP, &IMP, 2}, {"???", &SBC, &IMP, 2}, {"CPX", &CPX, &ABS, 4}, 973 {"SBC", &SBC, &ABS, 4}, {"INC", &INC, &ABS, 6}, {"???", &NUL, &IMP, 6}, 974 {"BEQ", &BEQ, &REL, 2}, {"SBC", &SBC, &IZY, 5}, {"???", &NUL, &IMP, 2}, 975 {"???", &NUL, &IMP, 8}, {"???", &NOP, &IMP, 4}, {"SBC", &SBC, &ZPX, 4}, 976 {"INC", &INC, &ZPX, 6}, {"???", &NUL, &IMP, 6}, {"SED", &SED, &IMP, 2}, 977 {"SBC", &SBC, &ABY, 4}, {"NOP", &NOP, &IMP, 2}, {"???", &NUL, &IMP, 7}, 978 {"???", &NOP, &IMP, 4}, {"SBC", &SBC, &ABX, 4}, {"INC", &INC, &ABX, 7}, 979 {"???", &NUL, &IMP, 7} 980 }; 981