repos/6502

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