Last active
September 12, 2017 19:37
-
-
Save stanleykerr/cf4d0ed93221af2f5a73292456c0c3ec to your computer and use it in GitHub Desktop.
lol i'm never gonna finish this
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| package com.stanley.nesemu; | |
| import java.util.Arrays; | |
| import java.util.HashMap; | |
| import java.util.List; | |
| import java.util.Map; | |
| public class CPU { | |
| private Rom rom; | |
| private Ram ramObj; | |
| private PPU ppu; | |
| private APU apu; | |
| public CPURam ram; | |
| public int pc, x, y, a, s, pb; // pb = 1 if goes past page boundary | |
| private Status statusReg; | |
| private boolean running; | |
| private final byte[] CPI = {7,6,1,8,3,3,5,5,3,2,2,2,4,4,6,6,3,5,1,8,4,4,6,6,2,4,2,7,4,4,7,7,6,6,1,8,3,3,5,5,4,2,2,2,4,4,6,6,2,5,1,8,4,4,6,6,2,4,2,7,4,4,7,7,6,6,1,8,3,3,5,5,3,2,2,2,3,4,6,6,3,5,1,8,4,4,6,6,2,4,2,7,4,4,7,7,6,6,1,8,3,3,5,5,4,2,2,2,5,4,6,6,2,5,1,8,4,4,6,6,2,4,2,7,4,4,7,7,2,6,2,6,3,3,3,3,2,2,2,2,4,4,4,4,3,6,1,6,4,4,4,4,2,5,2,5,5,5,5,5,2,6,2,6,3,3,3,3,2,2,2,2,4,4,4,4,2,5,1,5,4,4,4,4,2,4,2,4,4,4,4,4,2,6,2,8,3,3,5,5,2,2,2,2,4,4,6,6,3,5,1,8,4,4,6,6,2,4,2,7,4,4,7,7,2,6,2,8,3,3,5,5,2,2,2,2,4,4,6,6,2,5,1,8,4,4,6,6,2,4,2,7,4,4,7,7}; | |
| private int cycles; | |
| public CPU(Ram ram, PPU ppu, APU apu, Rom rom) { | |
| this.ramObj = ram; | |
| this.ppu = ppu; | |
| this.rom = rom; | |
| this.running = false; | |
| this.ram = new CPURam(rom, ppu, ram, apu); | |
| } | |
| public void startup() { | |
| this.statusReg = new Status(); | |
| // TODO: Implement memory sets | |
| for(int i = 0; i < 0x800; ++i) | |
| ram.write(i, 0xFF); | |
| ram.write(0x0008, 0xF7); | |
| ram.write(0x0009, 0xEF); | |
| ram.write(0x000A, 0xDF); | |
| ram.write(0x000F, 0xBF); | |
| for(int i = 0x4000; i <= 0x400F; ++i) | |
| ram.write(i, 0x00); | |
| a = 0; | |
| x = 0; | |
| y = 0; | |
| s = 0xFD; | |
| pc = ram.read(0xFFFD) * 256 + ram.read(0xFFFC); | |
| } | |
| public void runRom(Rom rom) { | |
| // Load rom | |
| this.rom = rom; | |
| // Program counter stores current execution point | |
| this.pc = Rom.HEADER_SIZE; | |
| // Run program | |
| this.running = true; | |
| while(this.running) { | |
| runCycle(); | |
| } | |
| } | |
| private static enum Modifier { | |
| INDX(0x01, 0x03, 0x21, 0x23, 0x41, 0x43, 0x61, 0x63, 0x81, 0x83, 0xA1, 0xA2, 0xA3, 0xC1, 0xC3, 0xE1, 0xE3), | |
| IMM(0x09, 0x0B, 0x29, 0x2B, 0x49, 0x4B, 0x69, 0x6B, 0x80, 0x82, 0x89, 0xA0, 0xA2, 0xA9, 0xAB, 0xAB, 0xC0, 0xC2, 0xC9, 0xCB, 0xE0, 0xE2, 0xE9, 0xEB), | |
| ZPG_PLAIN(0x04, 0x05, 0x06, 0x07, 0x24, 0x25 ,0x26, 0x27, 0x44, 0x45, 0x46, 0x47, 0x64, 0x65, 0x66, 0x67, 0x84, 0x85, 0x86, 0x87, 0xA4, 0xA5, 0xA6, 0xA7, 0xC4, 0xC5, 0xC6, 0xC7, 0xE4, 0xE5, 0xE6, 0xE7), | |
| ZPG_X(0x14, 0x15, 0x16, 0x17, 0x34, 0x35, 0x36, 0x37, 0x54, 0x55, 0x56, 0x57, 0x74, 0x75, 0x76, 0x77, 0x94, 0x95, 0xB4, 0xB5, 0xD4, 0xD5, 0xD6, 0xD7, 0xF4, 0xF5, 0xF6, 0xF7), | |
| ZPG_Y(0xB7, 0xB6, 0x97, 0x96), | |
| ABS_PLAIN(0x0C, 0x0D, 0x0E, 0x0F, 0x20, 0x2C, 0x2D, 0x2E, 0x2F, 0x4D, 0x4E, 0x4F, 0x6D, 0x6E, 0x6F, 0x8C, 0x8D, 0x8E, 0x8F, 0xAC, 0xAD, 0xAE, 0xAF, 0xCC, 0xCD, 0xCE, 0xCF, 0xEC, 0xED, 0xEE, 0xEF), | |
| ABSX_ONCARRY(0x1C, 0x1D, 0x3C, 0x3D, 0x5C, 0x5D, 0x7C, 0x7D, 0xBC, 0xBD, 0xDC, 0xDD, 0xFC, 0xFD), | |
| ABSX_ALWAYS(0x1E, 0x1F, 0x3E, 0x3F, 0x5E, 0x5F, 0x7E, 0x7F, 0x9C, 0x9D, 0xDE, 0xDF, 0xFE, 0xFF), | |
| ABSY_ONCARRY(0x19, 0x39, 0x59, 0x79, 0xB9, 0xBB, 0xBE, 0xBF, 0xD9, 0xF9), | |
| ABSY_ALWAYS(0x1B, 0x3B, 0x5B, 0x7B, 0x99, 0x9B, 0x9E, 0x9F, 0xDB, 0xFB), | |
| INDY_ONCARRY(0x11, 0x31, 0x51, 0x71, 0xB1, 0xB3, 0xD1, 0xF1), | |
| INDY_ALWAYS(0x13, 0x33, 0x53, 0x73, 0x91, 0x93, 0xD3, 0xF3), | |
| NONE; | |
| private Map<Integer> addressMap = new HashMap<>(); | |
| private Modifier(int... addresses) { | |
| for(int addr : addresses) | |
| addressMap.put(addr, this); | |
| } | |
| public static int get(int addr) { | |
| Modifier modifier = addressMap.getOrDefault(addr, NONE); | |
| switch(modifier) { | |
| case INDX: return indX(); | |
| case IMM: return imm(); | |
| case ZPG_PLAIN: return zpg(); | |
| case ZPG_X: return zpg(x); | |
| case ZPG_Y: return zpg(y); | |
| case ABS_PLAIN: return abs(); | |
| case ABS_XONCARRY: return abs(x, Dummy.ONCARRY); | |
| case ABS_XALWAYS: return abs(x, Dummy.ALWAYS); | |
| case ABS_YONCARRY: return abs(y, Dummy.ONCARRY); | |
| case ABS_YALWAYS: return abs(y, Dummy.ALWAYS); | |
| case INDY_ONCARRY: return indY(Dummy.ONCARRY); | |
| case INDY_ALWAYS: return indY(Dummy.ALWAYS); | |
| case NONE: | |
| default: return -1; | |
| } | |
| } | |
| } | |
| private static enum IType { | |
| ADC(0x69, 0x65, 0x75, 0x6D, 0x7D, 0x79, 0x61, 0x71), AND(0x29, 0x25, 0x35, 0x2D, 0x3D, 0x39, 0x21, 0x31), ASL(0x0A, 0x06, 0x16, 0x0E, 0x1E), | |
| BCC(0x90), BCS(0xB0), BEQ(0xF0), BIT(0x24, 0x2C), BMI(0x30), BNE(0xD0), BPL(0x10), BRK(0x00), BVC(0x50), BVS(0x70), | |
| CLC(0x18), CLD(0xD8), CLI(0x58), CLV(0xB8), CMP(0xC1, 0xC5, 0xC9, 0xCD, 0xD1, 0xD5, 0xD9, 0xDD), CPX(0xE0, 0xE4, 0xEC), CPY(0xC0, 0xC4, 0xCC), | |
| DEC(0xC6, 0xD6, 0xCE, 0xDE), DEX(0xCA), DEY(0x88), | |
| EOR(0x49, 0x45, 0x55, 0x4D, 0x5D, 0x59, 0x41, 0x51), | |
| INC(0xE6, 0xF6, 0xEE, 0xFE), INX(0xE8), INY(0xC8), | |
| JMP(0x4C, 0x6C), JSR(0x20), | |
| LDA(0xA9, 0xA5, 0xB5, 0xAD, 0xBD, 0xB9, 0xA1, 0xB1), LDX(0xA2, 0xA6, 0xB6, 0xAE, 0xBE), LDY(0xA0, 0xA4, 0xB4, 0xAC, 0xBC), LSR(0x4A, 0x46, 0x56, 0x4E, 0x5E), | |
| NOP(0x1A, 0x3a, 0x5a, 0x7a, 0xda, 0xea, 0xfa, 0x80, 0x82, 0xc2, 0xe2, 0x89, 0x04, 0x44, 0x64, 0x14, 0x34, 0x54, 0x74, 0xd4, 0xf4, 0x0C, 0x1c, 0xc3, 0x5c, 0x7c, 0xdc, 0xfc), | |
| ORA(0x09, 0x05, 0x15, 0x15, 0x0d, 0x1d, 0x19, 0x01, 0x11), | |
| PHA(0x48), PHP(0x08), PLA(0x68), PLP(0x28), | |
| ROL(0x2A, 0x26, 0x36, 0x2E, 0x3E), ROR(0x6A, 0x66, 0x76, 0x6E, 0x7E), RTI(0x40), RTS(0x60), | |
| SBC(0xE9, 0xE5, 0xF5, 0xED, 0xFD, 0xF9, 0xE1, 0xF1), SEC(0x38), SED(0xF8), SEI(0x78), SLO(0x03, 0x07, 0x0f, 0x13, 0x17, 0x1b, 0x1f), STA(0x85, 0x95, 0x8D, 0x9D, 0x99, 0x81, 0x91), STX(0x86, 0x96, 0x8E), STY(0x84, 0x94, 0x8C), | |
| TAX(0xAA), TAY(0xA8), TSX(0xBA), TXA(0x8A), TXS(0x9A), TYA(0x98), | |
| UNREGISTERED; | |
| private static Map<Integer, IType> addressMap = new HashMap<>(); | |
| private IType(int... addresses) { | |
| for(int addr : addresses) | |
| addressMap.put(addr, this); | |
| } | |
| public static IType get(int addr) { | |
| return addressMap.getOrDefault(addr, UNREGISTERED); | |
| } | |
| } | |
| private static enum Dummy { | |
| ONCARRY, ALWAYS; | |
| } | |
| private int interrupt = 0; | |
| public void runCycle() { | |
| if(cycles-- > 0) return; | |
| if(interrupt > 0) { | |
| if(!statusReg.isInterrupt() && !interruptDelay) { | |
| interrupt(); | |
| cycles += 7; | |
| return; | |
| } else if(interruptDelay) { | |
| interruptDelay = false; | |
| if(!previntflag) { | |
| interrupt(); | |
| cycles += 7; | |
| return; | |
| } | |
| } | |
| } else { | |
| interruptDelay = false; | |
| } | |
| int instr = this.rom.read(this.pc++); | |
| IType type = IType.get(instr); | |
| int toUse = Modifier.get(instr); | |
| /* DEBUG OUTPUT: String op = String.format(Util.opcodes()[instr], | |
| ram.read(pc), | |
| ram.read(pc + 1), | |
| pc + (byte) (ram.read(pc)) + 1); | |
| System.out.println(Util.toHex(pc - 1) + " " + Util.toHex(instr) | |
| + String.format(" %-14s ", op));*/ | |
| switch(type) { | |
| case ADC: | |
| adc(toUse); | |
| break; | |
| case AND: | |
| and(toUse); | |
| break; | |
| case ASL: | |
| if(instr == 0x0A) aslA(); | |
| else asl(toUse); | |
| break; | |
| case BCC: | |
| branch(!statusReg.isCarry()); | |
| break; | |
| case BCS: | |
| branch(statusReg.isCarry()); | |
| break; | |
| case BEQ: | |
| branch(statusReg.isZero()); | |
| break; | |
| case BIT: | |
| bit(toUse); | |
| break; | |
| case BMI: | |
| branch(statusReg.isNegative()); | |
| break; | |
| case BNE: | |
| branch(!statusReg.isZero()); | |
| break; | |
| case BPL: | |
| branch(!statusReg.isNegative()); | |
| break; | |
| case BRK: | |
| breakinterrupt(); | |
| break; | |
| case BVC: | |
| branch(!statusReg.isOverflow()); | |
| break; | |
| case BVS: | |
| branch(statusReg.isOverflow()); | |
| break; | |
| case CLC: | |
| statusReg.setCarry(false); | |
| break; | |
| case CLD: | |
| statusReg.setDecimal(false); | |
| break; | |
| case CLI: | |
| delayInterrupt(); | |
| statusReg.setInterrupt(false); | |
| break; | |
| case CLV: | |
| statusReg.setOverflow(false); | |
| break; | |
| case CMP: | |
| cmp(a, toUse); | |
| break; | |
| case CPX: | |
| cmp(x, toUse); | |
| break; | |
| case CPY: | |
| cmp(y, toUse); | |
| break; | |
| case DEC: | |
| dec(toUse); | |
| break; | |
| case DEX: | |
| x--; | |
| x &= 0xFF; | |
| setflags(x); | |
| break; | |
| case DEY: | |
| y--; | |
| y &= 0xFF; | |
| setflags(y); | |
| break; | |
| case EOR: | |
| eor(toUse); | |
| break; | |
| case INC: | |
| inc(toUse); | |
| break; | |
| case INX: | |
| x++; | |
| x &= 0xff; | |
| setflags(x); | |
| break; | |
| case INY: | |
| y++; | |
| y &= 0xff; | |
| setflags(y); | |
| break; | |
| case JMP: | |
| int tempPC = pc; | |
| pc = instr == 0x4cc ? abs() : ind(); | |
| if(pc == (tempPC - 1)) | |
| // TODO: idle = true; | |
| break; | |
| case JSR: | |
| jsr(toUse); | |
| break; | |
| case LDA: | |
| ld(toUse, a); | |
| break; | |
| case LDX: | |
| ld(toUse, x); | |
| break; | |
| case LDY: | |
| ld(toUse, y); | |
| break; | |
| case LSR: | |
| if(instr == 0x4A) lsrA(); | |
| else lsr(toUse); | |
| break; | |
| case NOP: | |
| break; | |
| case ORA: | |
| ora(toUse); | |
| break; | |
| case PHA: | |
| ram.read(pc + 1); //dummy fetch | |
| push(a); | |
| break; | |
| case PHP: | |
| ram.read(pc + 1); //dummy fetch | |
| push(flagstobyte() | 16); | |
| break; | |
| case PLA: | |
| ram.read(pc + 1); //dummy fetch | |
| a = pop(); | |
| setflags(a); | |
| break; | |
| case PLP: | |
| delayInterrupt(); | |
| ram.read(pc + 1); //dummy fetch | |
| bytetoflags(pop()); | |
| break; | |
| case ROL: | |
| if(instr == 0x2A) rolA(); | |
| else rol(toUse); | |
| break; | |
| case ROR: | |
| if(instr == 0x6A) rorA(); | |
| else ror(toUse); | |
| break; | |
| case RTI: | |
| rti(); | |
| break; | |
| case RTS: | |
| rts(); | |
| break; | |
| case SBC: | |
| sbc(toUse); | |
| break; | |
| case SEC: | |
| statusReg.setCarry(true); | |
| break; | |
| case SED: | |
| statusReg.setDecimal(true); | |
| break; | |
| case SEI: | |
| delayInterrupt(); | |
| statusReg.setInterrupt(true); | |
| break; | |
| case SLO: | |
| slo(toUse); | |
| break; | |
| case STA: | |
| st(toUse, a); | |
| break; | |
| case STX: | |
| st(toUse, x); | |
| break; | |
| case STY: | |
| st(toUse, y); | |
| break; | |
| case TAX: | |
| x = a; | |
| setflags(a); | |
| break; | |
| case TAY: | |
| y = a; | |
| setflags(a); | |
| break; | |
| case TSX: | |
| s = x; | |
| setflags(x); | |
| break; | |
| case TXA: | |
| a = x; | |
| setflags(a); | |
| break; | |
| case TXS: | |
| s = x; | |
| break; | |
| case TYA: | |
| a = y; | |
| setflags(a); | |
| break; | |
| case UNREGISTERED: | |
| default: | |
| System.err.println("Instruction not found! (" + Util.toHex(instr) + ")"); | |
| System.exit(1); | |
| break; | |
| } | |
| cycles += CPI[instr]; | |
| } | |
| private boolean interruptDelay, previntflag; | |
| private void delayInterrupt() { | |
| interruptDelay = true; | |
| previntflag = statusReg.isInterrupt(); | |
| } | |
| private void rol(final int addr) { | |
| int data = ram.read(addr); | |
| ram.write(addr, data); | |
| data = (data << 1) | (statusReg.isCarry() ? 1 : 0); | |
| statusReg.setCarry((data & 256) != 0); | |
| data &= 0xFF; | |
| setflags(data); | |
| ram.write(addr, data); | |
| } | |
| private void rolA() { | |
| a = a << 1 | (statusReg.isCarry() ? 1 : 0); | |
| statusReg.setCarry((a & 256) != 0); | |
| a &= 0xff; | |
| setflags(a); | |
| } | |
| private void ror(final int addr) { | |
| int data = ram.read(addr); | |
| ram.write(addr, data); | |
| final boolean tmp = statusReg.isCarry(); | |
| statusReg.setCarry((data & 1) != 0); | |
| data = ((data >> 1) & 0x7F) | (tmp ? 0x80 : 0); | |
| setflags(data); | |
| ram.write(addr, data); | |
| } | |
| private void rorA() { | |
| final boolean tmp = statusReg.isCarry(); | |
| statusReg.setCarry((a & 1) != 0); | |
| a >>= 1; | |
| a &= 0x7F; | |
| a |= (tmp ? 128 : 0); | |
| setflags(a); | |
| } | |
| private void rts() { | |
| ram.read(pc++); | |
| pc = (pop() & 0xff) | (pop() << 8); | |
| pc++; | |
| } | |
| private void rti() { | |
| ram.read(pc++); | |
| bytetoflags(pop()); | |
| pc = (pop() & 0xff) | (pop() << 8); | |
| } | |
| private int pop() { | |
| ++s; | |
| s &= 0xff; | |
| return ram.read(0x100 + s); | |
| } | |
| public void push(final int byteToPush) { | |
| ram.write((0x100 + (s & 0xff)), byteToPush); | |
| --s; | |
| s &= 0xff; | |
| } | |
| private void branch(final boolean isTaken) { | |
| if(!isTaken) { | |
| rel(); | |
| return; | |
| } | |
| final int pcprev = pc + 1; // previous pc | |
| pc = rel(); | |
| // page boundary penalty | |
| if((pcprev & 0xff00) != (pc & 0xff00)) | |
| pb = 2; | |
| //else cycles++; | |
| //if((pcprev - 2) == pc) | |
| //idle = true; | |
| } | |
| private void interrupt() { | |
| push(pc >> 8); | |
| push(pc & 0xFF); | |
| push(flagstobyte() & ~16); | |
| pc = ram.read(0xFFFE) + (ram.read(0xFFFF) << 8); | |
| statusReg.setInterrupt(true); | |
| } | |
| private void breakinterrupt() { | |
| // same as interrupt but BRK flag is turned on | |
| ram.read(pc++); // dummy fetch | |
| push(pc >> 8); // high bit 1st | |
| push(pc & 0xFF); // check that this pushes right address | |
| push(flagstobyte() | 16 | 32); // push byte w/bits 4+5 set | |
| pc = ram.read(0xFFFE) + (ram.read(0xFFFF) << 8); | |
| statusReg.setInterrupt(true); | |
| } | |
| private void lsr(final int addr) { | |
| int data = ram.read(addr); | |
| ram.write(addr, data); | |
| statusReg.setCarry((data & 1) != 0); | |
| data >>= 1; | |
| data &= 0x7F; | |
| ram.write(addr, data); | |
| setflags(data); | |
| } | |
| private void lsrA() { | |
| statusReg.setCarry((a & 1) != 0); | |
| a >>= 1; | |
| a &= 0x7F; | |
| setflags(a); | |
| } | |
| private boolean decimalModeEnable = false; | |
| private void ld(final int addr, int v) { | |
| v = ram.read(addr); | |
| setflags(v); | |
| } | |
| private void st(final int addr, int v) { | |
| ram.write(addr, v); | |
| } | |
| private void setflags(final int result) { | |
| statusReg.setZero(result == 0); | |
| statusReg.setNegative((result & 128) != 0); | |
| } | |
| private void inc(final int addr) { | |
| int tmp = ram.read(addr); | |
| ram.write(addr, tmp); | |
| ++tmp; | |
| tmp &= 0xff; | |
| ram.write(addr, tmp); | |
| setflags(tmp); | |
| } | |
| private void dec(final int addr) { | |
| int tmp = ram.read(addr); | |
| ram.write(addr, tmp); | |
| --tmp; | |
| tmp &= 0xff; | |
| ram.write(addr, tmp); | |
| setflags(tmp); | |
| } | |
| private void adc(final int addr) { | |
| final int value = ram.read(addr); | |
| int result; | |
| if(statusReg.isDecimal() && decimalModeEnable) { | |
| int al = (a & 0xF) + (value & 0xF) + (statusReg.isCarry() ? 1 : 0); | |
| if(al >= 0x0A) | |
| al = ((al + 0x6) & 0xF) + 0x10; | |
| result = (a & 0xF0) + (value & 0xF0) + al; | |
| if(result >= 0xA0) | |
| result += 0x60; | |
| } else result = value + a + (statusReg.isCarry() ? 1 : 0); | |
| statusReg.setCarry(result >> 8 != 0); | |
| statusReg.setOverflow(((a ^ value) & 0x80) == 0 && (((a ^ result) & 0x80)) != 0); | |
| a = result & 0xff; | |
| setflags(a); | |
| } | |
| private void sbc(final int addr) { | |
| final int value = ram.read(addr); | |
| int result; | |
| if(statusReg.isDecimal() && decimalModeEnable) { | |
| int al = (a & 0xF) - (value & 0xF) + (statusReg.isCarry() ? 1 : 0); | |
| if(al < 0) | |
| al = ((al - 0x6) & 0xF) - 0x10; | |
| result = (a & 0xF0) + (value & 0xF0) + al; | |
| if(result < 0) | |
| result -= 0x60; | |
| } else result = a - value - (statusReg.isCarry() ? 0 : 1); | |
| statusReg.setCarry(result >> 8 == 0); | |
| statusReg.setOverflow((((a ^ value) & 0x80) != 0) && (((a ^ result) & 0x80) != 0)); | |
| a = result & 0xff; | |
| setflags(a); | |
| } | |
| private void and(final int addr) { | |
| a &= ram.read(addr); | |
| setflags(a); | |
| } | |
| private void asl(final int addr) { | |
| int data = ram.read(addr); | |
| ram.write(addr, data); | |
| statusReg.setCarry((data & 128) != 0); | |
| data <<= 1; | |
| data &= 0xff; | |
| setflags(data); | |
| ram.write(addr, data); | |
| } | |
| private void aslA() { | |
| statusReg.setCarry((a & 128) != 0); | |
| a <<= 1; | |
| a &= 0xff; | |
| setflags(a); | |
| } | |
| private void cmp(final int regVal, final int addr) { | |
| final int result = regVal - ram.read(addr); | |
| statusReg.setNegative(result == 0 ? false : (result & 128) != 0); | |
| statusReg.setCarry(result >= 0); | |
| statusReg.setZero(result == 0); | |
| } | |
| private void eor(final int addr) { | |
| a ^= ram.read(addr); | |
| a &= 0xff; | |
| setflags(a); | |
| } | |
| private void ora(final int addr) { | |
| a |= ram.read(addr); | |
| a &= 0xff; | |
| setflags(a); | |
| } | |
| private void bit(final int addr) { | |
| final int data = ram.read(addr); | |
| statusReg.setZero((data & a) == 0); | |
| statusReg.setNegative((data & 128) != 0); | |
| statusReg.setOverflow((data & 64) != 0); | |
| } | |
| private void jsr(final int addr) { | |
| pc--; | |
| ram.read(pc); | |
| push(pc >> 8); | |
| push(pc & 0xFF); | |
| pc = addr; | |
| } | |
| private int imm() { | |
| return pc++; | |
| } | |
| // Zero page mode | |
| private int zpg() { | |
| return ram.read(pc++); | |
| } | |
| // Zero page added to register (modulus page boundary) | |
| private int zpg(final int reg) { | |
| return (ram.read(pc++) + reg) & 0xff; | |
| } | |
| // Returns actual value of PC, not memory location to look at | |
| // because only branches use this | |
| private int rel() { | |
| return ((byte) ram.read(pc++)) + pc; | |
| } | |
| // Absolute mode | |
| private int abs() { | |
| return ram.read(pc++) + (ram.read(pc++) << 8); | |
| } | |
| // Absolute + value from register | |
| private int abs(final int reg, final Dummy dummy) { | |
| final int addr = (ram.read(pc++) | (ram.read(pc++) << 8)); | |
| if(addr >> 8 != (addr + reg) >> 8) pb = 1; | |
| if(((addr & 0xFF00) != ((addr + reg) & 0xFF00) && dummy == Dummy.ONCARRY) || dummy == Dummy.ALWAYS) | |
| ram.read((addr & 0xFF00) | ((addr + reg) & 0xFF)); | |
| return (addr + reg) & 0xFFFF; | |
| } | |
| /* [ Only used by JMP ] | |
| * If reading from the last byte in a page, high bit of address | |
| * Taken from first byte on the page, not first byte on NEXT page. | |
| */ | |
| private int ind() { | |
| final int addr = abs(); | |
| return ram.read(addr) + (ram.read(((addr & 0xff) == 0xff) ? addr - 0xff : addr + 1) << 8); | |
| } | |
| // Indirect mode | |
| // (Doesn't suffer from same bug as jump indirect) | |
| private int indX() { | |
| final int arg = ram.read(pc++); | |
| return ram.read((arg + x) & 0xff) + (ram.read((arg + 1 + x) & 0xff) << 8); | |
| } | |
| private void slo(int addr) { | |
| asl(addr); | |
| ora(addr); | |
| } | |
| private int indY(final Dummy dummy) { | |
| final int arg = ram.read(pc++); | |
| final int addr = (ram.read((arg) & 0xff) | (ram.read((arg + 1) & 0xff) << 8)); | |
| if(addr >> 8 != (addr + y) >> 8) pb = 1; | |
| if(((addr & 0xFF00) != ((addr + y) & 0xFF00) && dummy == Dummy.ONCARRY) || dummy == Dummy.ALWAYS) | |
| ram.read((addr & 0xFF00) | ((addr + y) & 0xFF)); | |
| return (addr + y) & 0xffff; | |
| } | |
| public final int flagstobyte() { | |
| return ((statusReg.isNegative() ? 128 : 0) | (statusReg.isOverflow() ? 64 : 0) | 32 | |
| | (statusReg.isDecimal() ? 8 : 0) | (statusReg.isInterrupt() ? 4 : 0) | |
| | (statusReg.isZero() ? 2 : 0) | (statusReg.isCarry() ? 1 : 0)); | |
| } | |
| private void bytetoflags(final int sb) { | |
| statusReg.setNegative((sb & 128) != 0); | |
| statusReg.setOverflow((sb & 64) != 0); | |
| statusReg.setDecimal((sb & 8) != 0); | |
| statusReg.setInterrupt((sb & 4) != 0); | |
| statusReg.setZero((sb & 2) != 0); | |
| statusReg.setCarry((sb & 1) != 0); | |
| } | |
| public Status getStatusReg() { | |
| return statusReg; | |
| } | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment