From b863d5e51aaa8bb98db2c38bc1979e63b39cd39a Mon Sep 17 00:00:00 2001 From: Mike Naberezny Date: Tue, 1 Jul 2008 16:47:47 +0000 Subject: [PATCH] Appropriately change "CPU" to "MPU". --- mpu.py | 1234 +++++++++++++++++++ mpu_test.py | 3251 +++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 4485 insertions(+) create mode 100644 mpu.py create mode 100644 mpu_test.py diff --git a/mpu.py b/mpu.py new file mode 100644 index 0000000..9942e4d --- /dev/null +++ b/mpu.py @@ -0,0 +1,1234 @@ +class MPU: + # vectors + ResetTo = 0xfffc + IrqTo = 0xfffe + NMITo = 0xfffa + + # processor flags + NEGATIVE = 128 + OVERFLOW = 64 + BREAK = 16 + DECIMAL = 8 + INTERRUPT = 4 + ZERO = 2 + CARRY = 1 + + def __init__(self): + # config + self.debug = False + self.externalLoop = True + self.stopOnIterrupt = True + + # vm status + self.breakFlag = False + self.excycles = 0 + self.addcycles = False + self.processorCycles = 0; + self.internalCycleDelay=0; + + # init + self.clearMemory() + self.reset() + + def __repr__(self): + out = '<6502: A=%02x, X=%02x, Y=%02x, Flags=%02x, SP=%02x, PC=%04x>' + return out % (self.a, self.x, self.y, + self.flags, self.sp, self.pc) + + def step(self): + breakFlag = False + instructCode = self.ImmediateByte() + self.pc +=1 + self.pc &=0xffff + self.excycles = 0 + self.addcycles = self.extracycles[instructCode] + self.instruct[instructCode](self) + self.processorCycles += self.cycletime[instructCode]+self.excycles + self.pc &=0xffff + return self + + def reset(self): + self.pc=0 + self.sp=255 + self.a=self.x=self.y=0 + self.flags=32 + self.breakFlag=False + self.processorCycles=0 + + def clearMemory(self, start=0x0000, end=0xFFFF): + self.memory = self.RAM = [] + for addr in range(start, end + 1): + self.memory.insert(addr, 0x00) + + + def ByteAt(self, addr): + return self.memory[addr] + + def WordAt(self, addr): + return self.ByteAt(addr) + self.ByteAt(0xffff&(addr+1))*256 + + def ImmediateByte(self): + return self.ByteAt(self.pc) + + def ZeroPageAddr(self): + return self.ByteAt(self.pc) + + def ZeroPageXAddr(self): + return 255 & (self.x + self.ByteAt(self.pc)) + + def ZeroPageYAddr(self): + return 255 & (self.y + self.ByteAt(self.pc)) + + def IndirectXAddr(self): + return self.WordAt( 255 & (self.ByteAt(self.pc) + self.x)) + + def IndirectYAddr(self): + if self.addcycles: + a1 = self.WordAt(self.ByteAt(self.pc)) + a2 = (a1+self.y)&0xffff + if ((a1&0xff00) != (a2&0xff00)): + self.extracyles += 1 + return a2 + else: + return (self.WordAt(self.ByteAt(self.pc))+self.y)&0xffff + + def AbsoluteAddr(self): + return self.WordAt(self.pc) + + def AbsoluteXAddr(self): + if self.addcycles: + a1 = self.WordAt(self.pc) + a2 = (a1+self.x)&0xffff + if ((a1&0xff00)!=(a2&0xff00)): + self.extracyles += 1; + return a2 + else: + return (self.WordAt(self.pc)+self.x)&0xffff + + def AbsoluteYAddr(self): + if self.addcycles: + a1 = self.WordAt(self.pc) + a2=(a1+self.y)&0xffff + if ((a1&0xff00)!=(a2&0xff00)): + self.extracyles += 1; + return a2 + else: + return (self.WordAt(self.pc)+self.y)&0xffff + + def BranchRelAddr(self): + self.excycles += 1 + addr = self.ImmediateByte() + self.pc += 1 + + if addr & 128: + addr = self.pc - (addr ^ 0xFF) + 1 + else: + addr = self.pc + addr + + if (self.pc & 0xff00) != (addr & 0xff00): + self.excycles += 1 + + self.pc = addr & 0xffff + + # stack + + def stPush(self,z): + self.RAM[self.sp+256] = z&255; + self.sp -= 1; + self.sp &= 255 + + def stPop(self): + self.sp += 1 + self.sp &= 255 + return self.ByteAt(self.sp+256) + + def stPushWord(self, z): + self.stPush((z>>8)&255) + self.stPush(z&255) + + def stPopWord(self): + z = self.stPop() + z += 256*self.stPop() + return z + + # operations + + def FlagsNZ(self, z): + self.flags &= ~(self.ZERO + self.NEGATIVE) + if z == 0: + self.flags |= self.ZERO + else: + self.flags |= z & 128 + + def opORA(self, x): + self.a |= self.ByteAt(x()) + self.FlagsNZ(self.a) + + def opASL(self, x): + addr = x() + tbyte = self.ByteAt(addr); + self.flags &= ~(self.CARRY + self.NEGATIVE + self.ZERO) + + if (tbyte&128): + self.flags |= self.CARRY + + tbyte = (tbyte << 1) & 0xFF + + if (tbyte): + self.flags |= tbyte & 128 + else: + self.flags |= self.ZERO + + self.RAM[addr] = tbyte + + def opLSR(self, x): + addr = x() + tbyte = self.ByteAt(addr) + self.flags &=~(self.CARRY+self.NEGATIVE+self.ZERO) + self.flags |=tbyte&1 + + tbyte=tbyte>>1 + if (tbyte): + pass # {} + else: + self.flags |= self.ZERO + self.RAM[addr]=tbyte + + def opBCL(self, x): + if self.flags & x: + self.pc += 1 + else: + self.BranchRelAddr() + + def opBST(self, x): + if (self.flags&x): + self.BranchRelAddr() + else: + self.pc+=1 + + def opCLR(self, x): + self.flags &=~x + + def opSET(self, x): + self.flags |= x + + def opAND(self, x): + self.a &= self.ByteAt(x()) + self.FlagsNZ(self.a) + + def opBIT(self, x): + tbyte = self.ByteAt(x()) + self.flags &=~(self.ZERO+self.NEGATIVE+self.OVERFLOW) + if ((self.a&tbyte)==0): + self.flags |=self.ZERO; + self.flags |=tbyte&(128+64) + + def opROL(self, x): + addr = x(); + tbyte = self.ByteAt(addr) + if self.flags & self.CARRY: + if tbyte & 128: + pass + else: + self.flags &= ~self.CARRY + tbyte = (tbyte << 1) | 1 + else: + if tbyte & 128: + self.flags |= self.CARRY + tbyte = tbyte << 1 + self.FlagsNZ(tbyte) + self.RAM[addr] = tbyte & 0xFF + + def opEOR(self, x): + self.a^=self.ByteAt(x()) + self.FlagsNZ(a) + + def opADC(self, x): + data=self.ByteAt(x()) + if (self.flags&self.DECIMAL): + if (self.flags&self.CARRY): + tmp = 1 + else: + tmp = 0 + data = self.bcd2dec[data]+self.bcd2dec[self.a]+tmp + self.flags &= ~(self.CARRY+self.OVERFLOW+self.NEGATIVE+self.ZERO) + if (data>99): + self.flags|=self.CARRY+self.OVERFLOW; + data -=100 + + if (data==0): + self.flags|=self.ZERO + else: + self.flags |=data&128 + self.a=self.dec2bcd[data] + else: + if self.flags & self.CARRY: + tmp = 1 + else: + tmp = 0 + data += self.a + tmp; + self.flags &= ~(self.CARRY+self.OVERFLOW+self.NEGATIVE+self.ZERO) + if data > 255: + self.flags|=self.OVERFLOW+self.CARRY + data &=255 + if data == 0: + self.flags |= self.ZERO + else: + self.flags |= data&128; + self.a = data + + def opROR(self, x): + addr=x() + tbyte=self.ByteAt(addr) + if (self.flags&self.CARRY): + if (tbyte&1): + pass # {} + else: + self.flags &=~ self.CARRY + tbyte=(tbyte>>1)|128 + else: + if (tbyte&1): + self.flags |= self.CARRY + tbyte=tbyte>>1 + self.FlagsNZ(tbyte) + self.RAM[addr]=tbyte + + def opSTA(self, x): + self.RAM[x()] = self.a + + def opSTY(self, x): + self.RAM[x()] = self.y + + def opSTX(self, y): + self.RAM[y()] = self.x + + def opCPY(self, x): + tbyte=self.ByteAt(x()); + self.flags &=~(self.CARRY+self.ZERO+self.NEGATIVE) + if (self.y==tbyte): + self.flags |= self.CARRY + self.ZERO + elif (self.y>tbyte): + self.flags |= self.CARRY + else: + self.flags |= self.NEGATIVE; + + def opCPX(self, y): + tbyte=self.ByteAt(y()) + self.flags &=~(self.CARRY+self.ZERO+self.NEGATIVE) + if (self.x==tbyte): + self.flags |= self.CARRY + self.ZERO + elif (self.x>tbyte): + self.flags |= self.CARRY + else: + self.flags |= self.NEGATIVE + + def opCMP(self, x): + tbyte = self.ByteAt(x()) + self.flags &=~(self.CARRY+self.ZERO+self.NEGATIVE) + if (self.a==tbyte): + self.flags |= self.CARRY + self.ZERO + elif (self.a>tbyte): + self.flags |= self.CARRY + else: + self.flags |= self.NEGATIVE + + def opSBC(self, x): + data = self.ByteAt(x()) + if (self.flags & self.DECIMAL): + if (self.flags & self.CARRY): + tmp = 0 + else: + tmp = 1 + + data = self.bcd2dec[a] - self.bcd2dec[data] - tmp + self.flags &= ~(self.CARRY + self.ZERO + self.NEGATIVE + self.OVERFLOW) + if (data==0): + self.flags |= self.ZERO + self.CARRY + elif (data>0): + self.flags |= self.CARRY + else: + self.flags |= self.NEGATIVE + data +=100 + self.a = self.dec2bcd[data] + else: + if (self.flags & self.CARRY): + tmp = 0 + else: + tmp = 1 + + data = self.a - data - tmp + self.flags &=~(self.CARRY + self.ZERO + self.OVERFLOW + self.NEGATIVE) + if (data==0): + self.flags |= self.ZERO + self.CARRY + elif (data>0): + self.flags |= self.CARRY + else: + self.flags |= self.OVERFLOW + self.flags |= data&128 + self.a = data&255 + + def opDECR(self, x): + addr=x(); + tbyte = self.ByteAt(addr) + self.flags &=~(self.ZERO+self.NEGATIVE) + tbyte -= 1 + if tbyte: + self.flags |= self.tbyte&128 + else: + self.flags |= self.ZERO; + self.RAM[addr] = tbyte + + def opINCR(self, x): + addr=x(); + tbyte = self.ByteAt(addr) + self.flags &=~(self.ZERO + self.NEGATIVE) + tbyte += 1 + if (tbyte): + self.flags |= tbyte&128 + else: + self.flags |= fZER; + self.RAM[addr]=tbyte + + def opLDA(self, x): + self.a = self.ByteAt(x()) + self.FlagsNZ(self.a) + + def opLDY(self, x): + self.y = self.ByteAt(x()) + self.FlagsNZ(self.y) + + def opLDX(self, y): + self.x = self.ByteAt(y()) + self.FlagsNZ(self.x) + + # instructions + + def i00(self): + pc = (self.pc + 2) & 0xFFFF + self.stPushWord(pc) + + self.flags |= self.BREAK + self.stPush(self.flags) + + self.flags |= self.INTERRUPT + self.pc = self.WordAt(self.IrqTo) + + self.breakFlag = True + + def i01(self): + self.opORA(self.IndirectXAddr) + self.pc += 1 + + def i05(self): + self.opORA(self.ZeroPageAddr) + self.pc += 1 + + def i06(self): + self.opASL(self.ZeroPageAddr) + self.pc += 1 + + def i08(self): + self.stPush(self.flags) + + def i09(self): + self.a |= self.ImmediateByte() + self.FlagsNZ(self.a) + self.pc += 1 + + def i0a(self): + if (self.a&128): + self.flags |= self.CARRY + else: + self.flags &= ~self.CARRY; + self.a = self.a << 1; + self.FlagsNZ(self.a); + self.a &= 255 + + def i0d(self): + self.opORA(self.AbsoluteAddr) + self.pc += 2 + + def i0e(self): + self.opASL(self.AbsoluteAddr) + self.pc += 2 + + def i10(self): + self.opBCL(self.NEGATIVE) + + def i11(self): + self.opORA(self.IndirectYAddr) + self.pc += 1 + + def i15(self): + self.opORA(self.ZeroPageXAddr) + self.pc += 1 + + def i16(self): + self.opASL(self.ZeroPageXAddr) + self.pc += 1 + + def i18(self): + self.opCLR(self.CARRY) + + def i19(self): + self.opORA(self.AbsoluteYAddr) + self.pc += 2 + + def i1d(self): + self.opORA(self.AbsoluteXAddr) + self.pc += 2 + + def i1e(self): + self.opASL(self.AbsoluteXAddr) + self.pc += 2 + + def i20(self): + self.stPushWord((self.pc+1)&0xffff) + self.pc=self.WordAt(self.pc) + + def i21(self): + self.opAND(self.IndirectXAddr) + self.pc += 1 + + def i24(self): + self.opBIT(self.ZeroPageAddr) + self.pc += 1 + + def i25(self): + self.opAND(self.ZeroPageAddr) + self.pc += 1 + + def i26(self): + self.opROL(self.ZeroPageAddr) + self.pc += 1 + + def i28(self): + self.flags = self.stPop() + + def i29(self): + self.a &= self.ImmediateByte() + self.FlagsNZ(self.a) + self.pc += 1 + + def i2a(self): + if (self.flags & self.CARRY): + if ((self.a & 128)==0): + self.flags &=~self.CARRY; + self.a=(self.a<<1)|1 + else: + if (self.a&128): + self.flags|=self.CARRY; + self.a=self.a<<1 + self.FlagsNZ(self.a); + self.a&=255 + + def i2c(self): + self.opBIT(self.AbsoluteAddr) + self.pc+=2 + + def i2d(self): + self.opAND(self.AbsoluteAddr) + self.pc+=2 + + def i2e(self): + self.opROL(self.AbsoluteAddr) + self.pc += 2 + + def i30(self): + self.opBST(self.NEGATIVE) + + def i31(self): + self.opAND(self.IndirectYAddr) + self.pc += 1 + + def i35(self): + self.opAND(self.ZeroPageXAddr) + self.pc += 1 + + def i36(self): + self.opROL(self.ZeroPageXAddr) + self.pc += 1 + + def i38(self): + self.opSET(self.CARRY) + + def i39(self): + self.opAND(self.AbsoluteYAddr) + self.pc+=2 + + def i3d(self): + self.opAND(self.AbsoluteXAddr) + self.pc += 2 + + def i3e(self): + self.opROL(self.AbsoluteXAddr) + self.pc+=2 + + def i40(self): + self.flags = self.stPop() + self.pc = self.stPopWord() + + def i41(self): + self.opEOR(self.IndirectXAddr) + self.pc+=1 + + def i45(self): + self.opEOR(self.ZeroPageAddr) + self.pc+=1 + + def i46(self): + self.opLSR(self.ZeroPageAddr) + self.pc+=1 + + def i48(self): + self.stPush(self.a) + + def i49(self): + self.a ^= self.ImmediateByte() + self.FlagsNZ(self.a) + self.pc+=1 + + def i4a(self): + self.flags &=~(self.CARRY+self.NEGATIVE+self.ZERO); + if (self.a&1): + self.flags |= self.CARRY + + self.a=self.a>>1 + if (self.a): + pass # {} + else: + self.flags |= self.ZERO + self.a&=255 + + def i4c(self): + self.pc=self.WordAt(self.pc) + + def i4d(self): + self.opEOR(self.AbsoluteAddr) + self.pc+=2 + + def i4e(self): + self.opLSR(self.AbsoluteAddr) + self.pc += 2 + + def i50(self): + self.opBCL(self.OVERFLOW) + + def i51(self): + self.opEOR(self.IndirectYAddr) + self.pc+=1 + + def i55(self): + self.opEOR(self.ZeroPageXAddr) + self.pc+=1 + + def i56(self): + self.opLSR(self.ZeroPageXAddr) + self.pc+=1 + + def i58(self): + self.opCLR(self.INTERRUPT) + + def i59(self): + self.opEOR(self.AbsoluteYAddr) + self.pc +=2 + + def i5d(self): + self.opEOR(self.AbsoluteXAddr) + self.pc+=2 + + def i5e(self): + self.opLSR(self.AbsoluteXAddr) + self.pc+=2 + + def i60(self): + self.pc=self.stPopWord() + self.pc+=1 + + def i61(self): + self.opADC(self.IndirectXAddr) + self.pc+=1 + + def i65(self): + self.opADC(self.ZeroPageAddr) + self.pc+=1 + + def i66(self): + self.opROR(self.ZeroPageAddr) + self.pc+=1 + + def i68(self): + self.a = self.stPop() + self.FlagsNZ(self.a) + + def i69(self): + data = self.ImmediateByte() + + if (self.flags & self.CARRY): + tmp = 1 + else: + tmp = 0 + + if (self.flags & self.DECIMAL): + data = self.bcd2dec[data] + self.bcd2dec[a] + tmp + self.flags &= ~(self.CARRY+self.OVERFLOW+self.NEGATIVE+self.ZERO) + if (data>99): + self.flags|=self.CARRY+self.OVERFLOW + data -=100 + if (data==0): + self.flags |= self.ZERO + else: + self.flags |= self.data&128 + self.a = self.dec2bcd[data] + else: + if (self.flags & self.CARRY): + tmp = 1 + else: + tmp = 0 + data += self.a + tmp + self.flags &= ~(self.CARRY+self.OVERFLOW+self.NEGATIVE+self.ZERO) + if (data>255): + self.flags |= self.OVERFLOW + self.CARRY + data &=255 + if (data==0): + self.flags |= self.ZERO + else: + self.flags |= data&128 + self.a=data + self.pc += 1 + + def i6a(self): + if self.flags & self.CARRY: + if (self.a & 1) == 0: + self.flags &= ~self.CARRY + self.a = (self.a >> 1) | 128 + else: + if self.a & 1: + self.flags |= self.CARRY + self.a = self.a >> 1 + self.FlagsNZ(self.a) + self.a &= 255 + + def i6c(self): + ta = self.WordAt(self.pc) + self.pc = self.WordAt(ta) + + def i6d(self): + self.opADC(self.AbsoluteAddr) + self.pc +=2 + + def i6e(self): + self.opROR(self.AbsoluteAddr) + self.pc+=2 + + def i70(self): + self.opBST(self.OVERFLOW) + + def i71(self): + self.opADC(self.IndirectYAddr) + self.pc+=1 + + def i75(self): + self.opADC(self.ZeroPageXAddr) + self.pc+=1 + + def i76(self): + self.opROR(self.ZeroPageXAddr) + self.pc+=1 + + def i78(self): + self.opSET(self.INTERRUPT) + + def i79(self): + self.opADC(self.AbsoluteYAddr) + self.pc+=2 + + def i7d(self): + self.opADC(self.AbsoluteXAddr) + self.pc+=2 + + def i7e(self): + self.opROR(self.AbsoluteXAddr) + self.pc+=2 + + def i81(self): + self.opSTA(self.IndirectXAddr) + self.pc+=1 + + def i84(self): + self.opSTY(self.ZeroPageAddr) + self.pc+=1 + + def i85(self): + self.opSTA(self.ZeroPageAddr) + self.pc+=1 + + def i86(self): + self.opSTX(self.ZeroPageAddr) + self.pc+=1 + + def i88(self): + self.y -= 1 + self.y&=255 + self.FlagsNZ(self.y) + + def i8a(self): + self.a=self.x + self.FlagsNZ(self.a) + + def i8c(self): + self.opSTY(self.AbsoluteAddr) + self.pc+=2 + + def i8d(self): + self.opSTA(self.AbsoluteAddr) + self.pc+=2 + + def i8e(self): + self.opSTX(self.AbsoluteAddr) + self.pc+=2 + + def i90(self): + self.opBCL(self.CARRY) + + def i91(self): + self.opSTA(self.IndirectYAddr) + self.pc+=1 + + def i94(self): + self.opSTY(self.ZeroPageXAddr) + self.pc+=1 + + def i95(self): + self.opSTA(self.ZeroPageXAddr) + self.pc+=1 + + def i96(self): + self.opSTX(self.ZeroPageYAddr) + self.pc+=1 + + def i98(self): + self.a = self.y + self.FlagsNZ(self.a) + + def i99(self): + self.opSTA(self.AbsoluteYAddr) + self.pc+=2 + + def i9a(self): + self.sp=self.x + + def i9d(self): + self.opSTA(self.AbsoluteXAddr) + self.pc+=2 + + def ia0(self): + self.y=self.ImmediateByte() + self.FlagsNZ(self.y) + self.pc+=1 + + def ia1(self): + self.opLDA(self.IndirectXAddr) + self.pc+=1 + + def ia2(self): + self.x=self.ImmediateByte() + self.FlagsNZ(self.x) + self.pc+=1 + + def ia4(self): + self.opLDY(self.ZeroPageAddr) + self.pc+=1 + + def ia5(self): + self.opLDA(self.ZeroPageAddr) + self.pc+=1 + + def ia6(self): + self.opLDX(self.ZeroPageAddr) + self.pc+=1 + + def ia8(self): + self.y = self.a + self.FlagsNZ(self.y) + + def ia9(self): + self.a = self.ImmediateByte() + self.FlagsNZ(self.a) + self.pc += 1 + + def iaa(self): + self.x = self.a + self.FlagsNZ(self.x) + + def iac(self): + self.opLDY(self.AbsoluteAddr) + self.pc += 2 + + def iad(self): + self.opLDA(self.AbsoluteAddr) + self.pc += 2 + + def iae(self): + self.opLDX(self.AbsoluteAddr) + self.pc += 2 + + def ib0(self): + self.opBST(self.CARRY) + + def ib1(self): + self.opLDA(self.IndirectYAddr) + self.pc+=1 + + def ib4(self): + self.opLDY(self.ZeroPageXAddr) + self.pc+=1 + + def ib5(self): + self.opLDA(self.ZeroPageXAddr) + self.pc+=1 + + def ib6(self): + self.opLDX(self.ZeroPageYAddr) + self.pc+=1 + + def ib8(self): + self.opCLR(self.OVERFLOW) + + def ib9(self): + self.opLDA(self.AbsoluteYAddr) + self.pc+=2 + + def iba(self): + self.x = self.sp + self.FlagsNZ(self.x) + + def ibc(self): + self.opLDY(self.AbsoluteXAddr) + self.pc+=2 + + def ibd(self): + self.opLDA(self.AbsoluteXAddr) + self.pc+=2 + + def ibe(self): + self.opLDX(self.AbsoluteYAddr) + self.pc+=2 + + def ic0(self): + tbyte = self.ImmediateByte() + self.flags &=~(self.CARRY+self.ZERO+self.NEGATIVE); + if (y==tbyte): + self.flags |= self.CARRY+self.ZERO + elif (y>tbyte): + self.flags |= self.CARRY + else: + self.flags |= self.NEGATIVE; + self.pc += 1 + + def ic1(self): + self.opCMP(self.IndirectXAddr) + self.pc+=1 + + def ic4(self): + self.opCPY(self.ZeroPageAddr) + self.pc += 1 + + def ic5(self): + self.opCMP(self.ZeroPageAddr) + self.pc += 1 + + def ic6(self): + self.opDECR(self.ZeroPageAddr) + self.pc += 1 + + def ic8(self): + self.y += 1 + self.y &= 255 + self.FlagsNZ(self.y) + + def ic9(self): + tbyte = self.ImmediateByte() + self.flags &=~(self.CARRY+self.ZERO+self.NEGATIVE) + if (self.a==tbyte): + self.flags |= self.CARRY + self.ZERO + elif (a>tbyte): + self.flags |= self.CARRY + else: + self.flags |= self.NEGATIVE + self.pc +=1 + + def ica(self): + self.x -= 1 + self.x &= 255 + self.FlagsNZ(self.x) + + def icc(self): + self.opCPY(self.AbsoluteAddr) + self.pc += 2 + + def icd(self): + self.opCMP(self.AbsoluteAddr) + self.pc += 2 + + def ice(self): + self.opDECR(self.AbsoluteAddr) + self.pc += 2 + + def id0(self): + self.opBCL(self.ZERO) + + def id1(self): + self.opCMP(self.IndirectYAddr) + self.pc+=1 + + def id5(self): + self.opCMP(self.ZeroPageXAddr) + self.pc+=1 + + def id6(self): + self.opDECR(self.ZeroPageXAddr) + self.pc+=1 + + def id8(self): + self.opCLR(self.DECIMAL) + + def id9(self): + self.opCMP(self.AbsoluteYAddr) + self.pc+=2 + + def idd(self): + self.opCMP(self.AbsoluteXAddr) + self.pc+=2 + + def ide(self): + self.opDECR(AbsoluteXAddr) + self.pc+=2 + + def ie0(self): + tbyte = self.ImmediateByte() + self.flags &=~(self.CARRY+self.ZERO+self.NEGATIVE) + if (self.x==tbyte): + self.flags |= self.CARRY + self.ZERO + elif (self.x>tbyte): + self.flags |= self.CARRY + else: + self.flags |= self.NEGATIVE; + self.pc += 1 + + def ie1(self): + self.opSBC(self.IndirectXAddr) + self.pc+=1 + + def ie4(self): + self.opCPX(self.ZeroPageAddr) + self.pc+=1 + + def ie5(self): + self.opSBC(self.ZeroPageAddr) + self.pc+=1 + + def ie6(self): + self.opINCR(ZeroPageAddr) + self.pc+=1 + + def ie8(self): + self.x+=1 + self.x&=255 + self.FlagsNZ(self.x) + + def ie9(self): + data=self.ImmediateByte() + + if (self.flags & self.DECIMAL): + if (self.flags & self.CARRY): + tmp = 0 + else: + tmp = 1 + data = self.bcd2dec[a] - self.bcd2dec[data] - tmp + self.flags &= ~(self.CARRY+self.ZERO+self.NEGATIVE+self.OVERFLOW) + if (data==0): + self.flags |= self.ZERO + self.CARRY + elif (data>0): + self.flags |= self.CARRY + else: + self.flags |= self.NEGATIVE; + data +=100 + self.a = self.dec2bcd[data] + else: + if (self.flags & self.CARRY): + tmp = 0 + else: + tmp = 1 + data = self.a - data - tmp + self.flags &=~(self.CARRY+self.ZERO+self.OVERFLOW+self.NEGATIVE) + if (data==0): + self.flags |= self.ZERO + self.CARRY + elif (data>0): + self.flags |= self.CARRY + else: + self.flags |= self.OVERFLOW + data &= 255; + self.flags |= data&128; + self.a=data + self.pc+=1 + + def iea(self): + pass + + def iec(self): + self.opCPX(self.AbsoluteAddr) + self.pc+=2 + + def ied(self): + self.opSBC(self.AbsoluteAddr) + self.pc+=2 + + def iee(self): + self.opINCR(self.AbsoluteAddr) + self.pc+=2 + + def if0(self): + self.opBST(self.ZERO) + + def if1(self): + self.opSBC(self.IndirectYAddr) + self.pc+=1 + + def if5(self): + self.opSBC(self.ZeroPageXAddr) + self.pc+=1 + + def if6(self): + self.opINCR(self.ZeroPageXAddr) + self.pc+=1 + + def if8(self): + self.opSET(self.DECIMAL) + + def if9(self): + self.opSBC(self.AbsoluteYAddr) + self.pc+=2 + + def ifd(self): + self.opSBC(self.AbsoluteXAddr) + self.pc+=2 + + def ife(self): + self.opINCR(self.AbsoluteXAddr) + self.pc+=2 + + def ini(self): + if self.debug: + raise NotImplementedError + self.pc+=1 + + + # code pages + + instruct = [ + i00, i01, ini, ini, ini, i05, i06, ini, + i08, i09, i0a, ini, ini, i0d, i0e, ini, + i10, i11, ini, ini, ini, i15, i16, ini, + i18, i19, ini, ini, ini, i1d, i1e, ini, + i20, i21, ini, ini, i24, i25, i26, ini, + i28, i29, i2a, ini, i2c, i2d, i2e, ini, + i30, i31, ini, ini, ini, i35, i36, ini, + i38, i39, ini, ini, ini, i3d, i3e, ini, + i40, i41, ini, ini, ini, i45, i46, ini, + i48, i49, i4a, ini, i4c, i4d, i4e, ini, + i50, i51, ini, ini, ini, i55, i56, ini, + i58, i59, ini, ini, ini, i5d, i5e, ini, + i60, i61, ini, ini, ini, i65, i66, ini, + i68, i69, i6a, ini, i6c, i6d, i6e, ini, + i70, i71, ini, ini, ini, i75, i76, ini, + i78, i79, ini, ini, ini, i7d, i7e, ini, + ini, i81, ini, ini, i84, i85, i86, ini, + i88, ini, i8a, ini, i8c, i8d, i8e, ini, + i90, i91, ini, ini, i94, i95, i96, ini, + i98, i99, i9a, ini, ini, i9d, ini, ini, + ia0, ia1, ia2, ini, ia4, ia5, ia6, ini, + ia8, ia9, iaa, ini, iac, iad, iae, ini, + ib0, ib1, ini, ini, ib4, ib5, ib6, ini, + ib8, ib9, iba, ini, ibc, ibd, ibe, ini, + ic0, ic1, ini, ini, ic4, ic5, ic6, ini, + ic8, ic9, ica, ini, icc, icd, ice, ini, + id0, id1, ini, ini, ini, id5, id6, ini, + id8, id9, ini, ini, ini, idd, ide, ini, + ie0, ie1, ini, ini, ie4, ie5, ie6, ini, + ie8, ie9, iea, ini, iec, ied, iee, ini, + if0, if1, ini, ini, ini, if5, if6, ini, + if8, if9, ini, ini, ini, ifd, ife, ini + ] + + cycletime = [ + 7, 6, 0, 0, 0, 3, 5, 0, 3, 2, 2, 0, 0, 4, 6, 0, # 00 + 2, 5, 0, 0, 0, 4, 6, 0, 2, 4, 0, 0, 0, 4, 7, 0, # 10 + 6, 6, 0, 0, 3, 3, 5, 0, 4, 2, 2, 0, 4, 4, 6, 0, # 20 + 2, 5, 0, 0, 0, 4, 6, 0, 2, 4, 0, 0, 0, 4, 7, 0, # 30 + 6, 6, 0, 0, 0, 3, 5, 0, 3, 2, 2, 0, 3, 4, 6, 0, # 40 + 2, 5, 0, 0, 0, 4, 6, 0, 2, 4, 0, 0, 0, 4, 7, 0, # 50 + 6, 6, 0, 0, 0, 3, 5, 0, 4, 2, 2, 0, 5, 4, 6, 0, # 60 + 2, 5, 0, 0, 0, 4, 6, 0, 2, 4, 0, 0, 0, 4, 7, 0, # 70 + 0, 6, 0, 0, 3, 3, 3, 0, 2, 0, 2, 0, 4, 4, 4, 0, # 80 + 2, 6, 0, 0, 4, 4, 4, 0, 2, 5, 2, 0, 0, 5, 0, 0, # 90 + 2, 6, 2, 0, 3, 3, 3, 0, 2, 2, 2, 0, 4, 4, 4, 0, # A0 + 2, 5, 0, 0, 4, 4, 4, 0, 2, 4, 2, 0, 4, 4, 4, 0, # B0 + 2, 6, 0, 0, 3, 3, 5, 0, 2, 2, 2, 0, 4, 4, 3, 0, # C0 + 2, 5, 0, 0, 0, 4, 6, 0, 2, 4, 0, 0, 0, 4, 7, 0, # D0 + 2, 6, 0, 0, 3, 3, 5, 0, 2, 2, 2, 0, 4, 4, 6, 0, # E0 + 2, 5, 0, 0, 0, 4, 6, 0, 2, 4, 0, 0, 0, 4, 7, 0 # F0 + ] + + extracycles= [ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, # 00 + 2, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, # 10 + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, # 20 + 2, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, # 30 + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, # 40 + 2, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, # 50 + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, # 60 + 2, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, # 70 + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, # 80 + 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, # 90 + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, # A0 + 2, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 1, 1, 0, # B0 + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, # C0 + 2, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, # D0 + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, # E0 + 2, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0 # F0 + ] + + # lookup tables for opBCD math. + bcd2dec = [ + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, # 0x00 + 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, # 0x10 + 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, # 0x20 + 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, # 0x30 + 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, # 0x40 + 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, # 0x50 + 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, # 0x60 + 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, # 0x70 + 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, # 0x80 + 90, 91, 92, 93, 94, 95, 96, 97, 98, 99,100,101,102,103,104,105, # 0x90 + 100,101,102,103,104,105,106,107,108,109,110,111,112,113,114,115, # 0xA0 + 110,111,112,113,114,115,116,117,118,119,120,121,122,123,124,125, # 0xB0 + 120,121,122,123,124,125,126,127,128,129,130,131,132,133,134,135, # 0xC0 + 130,131,132,133,134,135,136,137,138,139,140,141,142,143,144,145, # 0xD0 + 140,141,142,143,144,145,146,147,148,149,150,151,152,153,154,155, # 0xE0 + 150,151,152,153,154,155,156,157,158,159,160,161,162,163,164,165 # 0xF0 + ] + + dec2bcd= [ + 0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09, + 0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17,0x18,0x19, + 0x20,0x21,0x22,0x23,0x24,0x25,0x26,0x27,0x28,0x29, + 0x30,0x31,0x32,0x33,0x34,0x35,0x36,0x37,0x38,0x39, + 0x40,0x41,0x42,0x43,0x44,0x45,0x46,0x47,0x48,0x49, + 0x50,0x51,0x52,0x53,0x54,0x55,0x56,0x57,0x58,0x59, + 0x60,0x61,0x62,0x63,0x64,0x65,0x66,0x67,0x68,0x69, + 0x70,0x71,0x72,0x73,0x74,0x75,0x76,0x77,0x78,0x79, + 0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89, + 0x90,0x91,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99 + ] + diff --git a/mpu_test.py b/mpu_test.py new file mode 100644 index 0000000..4fa250d --- /dev/null +++ b/mpu_test.py @@ -0,0 +1,3251 @@ +import unittest +import sys +from mpu import MPU + +class MPUTests(unittest.TestCase): + + # ADC Absolute + + def test_adc_bcd_off_absolute_carry_clear_in_accumulator_zeroes(self): + cpu = MPU() + cpu.a = 0 + cpu.memory[0x0000:0x0002] = (0x6D, 0x00, 0xC0) #=> $0000 ADC $C000 + cpu.memory[0xC000] = 0x00 + cpu.step() + self.assertEquals(0x0003, cpu.pc) + self.assertEquals(0x00, cpu.a) + self.assertEquals(0, cpu.flags & cpu.CARRY) + self.assertEquals(0, cpu.flags & cpu.NEGATIVE) + self.assertEquals(cpu.ZERO, cpu.flags & cpu.ZERO) + + def test_adc_bcd_off_absolute_carry_set_in_accumulator_zero(self): + cpu = MPU() + cpu.a = 0 + cpu.flags |= cpu.CARRY + cpu.memory[0x0000:0x0002] = (0x6D, 0x00, 0xC0) #=> $0000 ADC $C000 + cpu.memory[0xC000] = 0x00 + cpu.step() + self.assertEquals(0x0003, cpu.pc) + self.assertEquals(0x01, cpu.a) + self.assertEquals(0, cpu.flags & cpu.NEGATIVE) + self.assertEquals(0, cpu.flags & cpu.ZERO) + self.assertNotEquals(cpu.CARRY, cpu.flags & cpu.CARRY) + + def test_adc_bcd_off_absolute_carry_clear_in_no_carry_clear_out(self): + cpu = MPU() + cpu.a = 0x01 + cpu.memory[0x0000:0x0002] = (0x6D, 0x00, 0xC0) #=> $0000 ADC $C000 + cpu.memory[0xC000] = 0xFE + cpu.step() + self.assertEquals(0x0003, cpu.pc) + self.assertEquals(0xFF, cpu.a) + self.assertEquals(cpu.NEGATIVE, cpu.flags & cpu.NEGATIVE) + self.assertEquals(0, cpu.flags & cpu.CARRY) + self.assertEquals(0, cpu.flags & cpu.ZERO) + + def test_adc_bcd_off_absolute_carry_clear_in_carry_set_out(self): + cpu = MPU() + cpu.a = 0x02 + cpu.memory[0x0000:0x0002] = (0x6D, 0x00, 0xC0) #=> $0000 ADC $C000 + cpu.memory[0xC000] = 0xFF + cpu.step() + self.assertEquals(0x0003, cpu.pc) + self.assertEquals(0x01, cpu.a) + self.assertEquals(cpu.CARRY, cpu.flags & cpu.CARRY) + self.assertEquals(0, cpu.flags & cpu.NEGATIVE) + self.assertEquals(0, cpu.flags & cpu.ZERO) + + def test_adc_bcd_off_absolute_overflow(self): + cpu = MPU() + cpu.a = 0xFF + cpu.memory[0x0000:0x0002] = (0x6D, 0x00, 0xC0) #=> $0000 ADC $C000 + cpu.memory[0xC000] = 0xFF + cpu.step() + self.assertEquals(0x0003, cpu.pc) + self.assertEquals(0xFE, cpu.a) + self.assertEquals(cpu.NEGATIVE, cpu.flags & cpu.NEGATIVE) + self.assertEquals(cpu.OVERFLOW, cpu.flags & cpu.OVERFLOW) + self.assertEquals(0, cpu.flags & cpu.ZERO) + + # ADC Zero Page + + def test_adc_bcd_off_zp_carry_clear_in_accumulator_zeroes(self): + cpu = MPU() + cpu.a = 0 + cpu.memory[0x0000:0x0001] = (0x65, 0xB0) #=> $0000 ADC $00B0 + cpu.memory[0x00B0] = 0x00 + cpu.step() + self.assertEquals(0x0002, cpu.pc) + self.assertEquals(0x00, cpu.a) + self.assertEquals(0, cpu.flags & cpu.CARRY) + self.assertEquals(0, cpu.flags & cpu.NEGATIVE) + self.assertEquals(cpu.ZERO, cpu.flags & cpu.ZERO) + + def test_adc_bcd_off_absolute_carry_set_in_accumulator_zero(self): + cpu = MPU() + cpu.a = 0 + cpu.flags |= cpu.CARRY + cpu.memory[0x0000:0x0001] = (0x65, 0xB0) #=> $0000 ADC $00B0 + cpu.memory[0x00B0] = 0x00 + cpu.step() + self.assertEquals(0x0002, cpu.pc) + self.assertEquals(0x01, cpu.a) + self.assertEquals(0, cpu.flags & cpu.NEGATIVE) + self.assertEquals(0, cpu.flags & cpu.ZERO) + self.assertNotEquals(cpu.CARRY, cpu.flags & cpu.CARRY) + + def test_adc_bcd_off_absolute_carry_clear_in_no_carry_clear_out(self): + cpu = MPU() + cpu.a = 0x01 + cpu.memory[0x0000:0x0001] = (0x65, 0xB0) #=> $0000 ADC $00B0 + cpu.memory[0x00B0] = 0xFE + cpu.step() + self.assertEquals(0x0002, cpu.pc) + self.assertEquals(0xFF, cpu.a) + self.assertEquals(cpu.NEGATIVE, cpu.flags & cpu.NEGATIVE) + self.assertEquals(0, cpu.flags & cpu.CARRY) + self.assertEquals(0, cpu.flags & cpu.ZERO) + + def test_adc_bcd_off_absolute_carry_clear_in_carry_set_out(self): + cpu = MPU() + cpu.a = 0x02 + cpu.memory[0x0000:0x0001] = (0x65, 0xB0) #=> $0000 ADC $00B0 + cpu.memory[0x00B0] = 0xFF + cpu.step() + self.assertEquals(0x0002, cpu.pc) + self.assertEquals(0x01, cpu.a) + self.assertEquals(cpu.CARRY, cpu.flags & cpu.CARRY) + self.assertEquals(0, cpu.flags & cpu.NEGATIVE) + self.assertEquals(0, cpu.flags & cpu.ZERO) + + def test_adc_bcd_off_absolute_overflow(self): + cpu = MPU() + cpu.a = 0xFF + cpu.memory[0x0000:0x0002] = (0x65, 0xB0) #=> $0000 ADC $00B0 + cpu.memory[0x00B0] = 0xFF + cpu.step() + self.assertEquals(0x0002, cpu.pc) + self.assertEquals(0xFE, cpu.a) + self.assertEquals(cpu.NEGATIVE, cpu.flags & cpu.NEGATIVE) + self.assertEquals(cpu.OVERFLOW, cpu.flags & cpu.OVERFLOW) + self.assertEquals(0, cpu.flags & cpu.ZERO) + + # ADC Immediate + + def test_adc_bcd_off_immediate_carry_clear_in_accumulator_zeroes(self): + cpu = MPU() + cpu.a = 0 + cpu.memory[0x0000:0x0001] = (0x69, 0x00) #=> $0000 ADC #$00 + cpu.step() + self.assertEquals(0x0002, cpu.pc) + self.assertEquals(0x00, cpu.a) + self.assertEquals(0, cpu.flags & cpu.CARRY) + self.assertEquals(0, cpu.flags & cpu.NEGATIVE) + self.assertEquals(cpu.ZERO, cpu.flags & cpu.ZERO) + + def test_adc_bcd_off_immediate_carry_set_in_accumulator_zero(self): + cpu = MPU() + cpu.a = 0 + cpu.flags |= cpu.CARRY + cpu.memory[0x0000:0x0001] = (0x69, 0x00) #=> $0000 ADC #$00 + cpu.step() + self.assertEquals(0x0002, cpu.pc) + self.assertEquals(0x01, cpu.a) + self.assertEquals(0, cpu.flags & cpu.NEGATIVE) + self.assertEquals(0, cpu.flags & cpu.ZERO) + self.assertNotEquals(cpu.CARRY, cpu.flags & cpu.CARRY) + + def test_adc_bcd_off_immediate_carry_clear_in_no_carry_clear_out(self): + cpu = MPU() + cpu.a = 0x01 + cpu.memory[0x0000:0x0001] = (0x69, 0xFE) #=> $0000 ADC #$FE + cpu.step() + self.assertEquals(0x0002, cpu.pc) + self.assertEquals(0xFF, cpu.a) + self.assertEquals(cpu.NEGATIVE, cpu.flags & cpu.NEGATIVE) + self.assertEquals(0, cpu.flags & cpu.CARRY) + self.assertEquals(0, cpu.flags & cpu.ZERO) + + def test_adc_bcd_off_immediate_carry_clear_in_carry_set_out(self): + cpu = MPU() + cpu.a = 0x02 + cpu.memory[0x0000:0x0001] = (0x69, 0xFF) #=> $0000 ADC #$FF + cpu.step() + self.assertEquals(0x0002, cpu.pc) + self.assertEquals(0x01, cpu.a) + self.assertEquals(cpu.CARRY, cpu.flags & cpu.CARRY) + self.assertEquals(0, cpu.flags & cpu.NEGATIVE) + self.assertEquals(0, cpu.flags & cpu.ZERO) + + def test_adc_bcd_off_immediate_overflow(self): + cpu = MPU() + cpu.a = 0xFF + cpu.memory[0x0000:0x0001] = (0x69, 0xFF) #=> $0000 ADC #$FF + cpu.step() + self.assertEquals(0x0002, cpu.pc) + self.assertEquals(0xFE, cpu.a) + self.assertEquals(cpu.NEGATIVE, cpu.flags & cpu.NEGATIVE) + self.assertEquals(cpu.OVERFLOW, cpu.flags & cpu.OVERFLOW) + self.assertEquals(0, cpu.flags & cpu.ZERO) + + # ADC Absolute, X-Indexed + + def test_adc_bcd_off_abs_x_carry_clear_in_accumulator_zeroes(self): + cpu = MPU() + cpu.a = 0x00 + cpu.x = 0x03 + cpu.memory[0x0000:0x0002] = (0x7D, 0x00, 0xC0) #=> $0000 ADC $C000,X + cpu.memory[0xC000 + cpu.x] = 0x00 + cpu.step() + self.assertEquals(0x0003, cpu.pc) + self.assertEquals(0x00, cpu.a) + self.assertEquals(0, cpu.flags & cpu.CARRY) + self.assertEquals(0, cpu.flags & cpu.NEGATIVE) + self.assertEquals(cpu.ZERO, cpu.flags & cpu.ZERO) + + def test_adc_bcd_off_abs_x_carry_set_in_accumulator_zero(self): + cpu = MPU() + cpu.a = 0 + cpu.x = 0x03 + cpu.flags |= cpu.CARRY + cpu.memory[0x0000:0x0002] = (0x7D, 0x00, 0xC0) #=> $0000 ADC $C000,X + cpu.memory[0xC000 + cpu.x] = 0x00 + cpu.step() + self.assertEquals(0x0003, cpu.pc) + self.assertEquals(0x01, cpu.a) + self.assertEquals(0, cpu.flags & cpu.NEGATIVE) + self.assertEquals(0, cpu.flags & cpu.ZERO) + self.assertNotEquals(cpu.CARRY, cpu.flags & cpu.CARRY) + + def test_adc_bcd_off_abs_x_carry_clear_in_no_carry_clear_out(self): + cpu = MPU() + cpu.a = 0x01 + cpu.x = 0x03 + cpu.memory[0x0000:0x0002] = (0x7D, 0x00, 0xC0) #=> $0000 ADC $C000,X + cpu.memory[0xC000 + cpu.x] = 0xFE + cpu.step() + self.assertEquals(0x0003, cpu.pc) + self.assertEquals(0xFF, cpu.a) + self.assertEquals(cpu.NEGATIVE, cpu.flags & cpu.NEGATIVE) + self.assertEquals(0, cpu.flags & cpu.CARRY) + self.assertEquals(0, cpu.flags & cpu.ZERO) + + def test_adc_bcd_off_abs_x_carry_clear_in_carry_set_out(self): + cpu = MPU() + cpu.a = 0x02 + cpu.x = 0x03 + cpu.memory[0x0000:0x0002] = (0x7D, 0x00, 0xC0) #=> $0000 ADC $C000,X + cpu.memory[0xC000 + cpu.x] = 0xFF + cpu.step() + self.assertEquals(0x0003, cpu.pc) + self.assertEquals(0x01, cpu.a) + self.assertEquals(cpu.CARRY, cpu.flags & cpu.CARRY) + self.assertEquals(0, cpu.flags & cpu.NEGATIVE) + self.assertEquals(0, cpu.flags & cpu.ZERO) + + def test_adc_bcd_off_abs_x_overflow(self): + cpu = MPU() + cpu.a = 0xFF + cpu.x = 0x03 + cpu.memory[0x0000:0x0002] = (0x7D, 0x00, 0xC0) #=> $0000 ADC $C000,X + cpu.memory[0xC000 + cpu.x] = 0xFF + cpu.step() + self.assertEquals(0x0003, cpu.pc) + self.assertEquals(0xFE, cpu.a) + self.assertEquals(cpu.NEGATIVE, cpu.flags & cpu.NEGATIVE) + self.assertEquals(cpu.OVERFLOW, cpu.flags & cpu.OVERFLOW) + self.assertEquals(0, cpu.flags & cpu.ZERO) + + # ADC Absolute, Y-Indexed + + def test_adc_bcd_off_abs_y_carry_clear_in_accumulator_zeroes(self): + cpu = MPU() + cpu.a = 0x00 + cpu.y = 0x03 + cpu.memory[0x0000:0x0002] = (0x79, 0x00, 0xC0) #=> $0000 ADC $C000,Y + cpu.memory[0xC000 + cpu.y] = 0x00 + cpu.step() + self.assertEquals(0x0003, cpu.pc) + self.assertEquals(0x00, cpu.a) + self.assertEquals(0, cpu.flags & cpu.CARRY) + self.assertEquals(0, cpu.flags & cpu.NEGATIVE) + self.assertEquals(cpu.ZERO, cpu.flags & cpu.ZERO) + + def test_adc_bcd_off_abs_y_carry_set_in_accumulator_zero(self): + cpu = MPU() + cpu.a = 0 + cpu.y = 0x03 + cpu.flags |= cpu.CARRY + cpu.memory[0x0000:0x0002] = (0x7D, 0x00, 0xC0) #=> $0000 ADC $C000,Y + cpu.memory[0xC000 + cpu.y] = 0x00 + cpu.step() + self.assertEquals(0x0003, cpu.pc) + self.assertEquals(0x01, cpu.a) + self.assertEquals(0, cpu.flags & cpu.NEGATIVE) + self.assertEquals(0, cpu.flags & cpu.ZERO) + self.assertNotEquals(cpu.CARRY, cpu.flags & cpu.CARRY) + + def test_adc_bcd_off_abs_y_carry_clear_in_no_carry_clear_out(self): + cpu = MPU() + cpu.a = 0x01 + cpu.y = 0x03 + cpu.memory[0x0000:0x0002] = (0x79, 0x00, 0xC0) #=> $0000 ADC $C000,Y + cpu.memory[0xC000 + cpu.y] = 0xFE + cpu.step() + self.assertEquals(0x0003, cpu.pc) + self.assertEquals(0xFF, cpu.a) + self.assertEquals(cpu.NEGATIVE, cpu.flags & cpu.NEGATIVE) + self.assertEquals(0, cpu.flags & cpu.CARRY) + self.assertEquals(0, cpu.flags & cpu.ZERO) + + def test_adc_bcd_off_abs_y_carry_clear_in_carry_set_out(self): + cpu = MPU() + cpu.a = 0x02 + cpu.y = 0x03 + cpu.memory[0x0000:0x0002] = (0x79, 0x00, 0xC0) #=> $0000 ADC $C000,Y + cpu.memory[0xC000 + cpu.y] = 0xFF + cpu.step() + self.assertEquals(0x0003, cpu.pc) + self.assertEquals(0x01, cpu.a) + self.assertEquals(cpu.CARRY, cpu.flags & cpu.CARRY) + self.assertEquals(0, cpu.flags & cpu.NEGATIVE) + self.assertEquals(0, cpu.flags & cpu.ZERO) + + def test_adc_bcd_off_abs_y_overflow(self): + cpu = MPU() + cpu.a = 0xFF + cpu.y = 0x03 + cpu.memory[0x0000:0x0002] = (0x79, 0x00, 0xC0) #=> $0000 ADC $C000,Y + cpu.memory[0xC000 + cpu.y] = 0xFF + cpu.step() + self.assertEquals(0x0003, cpu.pc) + self.assertEquals(0xFE, cpu.a) + self.assertEquals(cpu.NEGATIVE, cpu.flags & cpu.NEGATIVE) + self.assertEquals(cpu.OVERFLOW, cpu.flags & cpu.OVERFLOW) + self.assertEquals(0, cpu.flags & cpu.ZERO) + + # ADC Zero Page, X-Indexed + + def test_adc_bcd_off_zp_x_carry_clear_in_accumulator_zeroes(self): + cpu = MPU() + cpu.a = 0x00 + cpu.x = 0x03 + cpu.memory[0x0000:0x0001] = (0x75, 0x10) #=> $0000 ADC $0010,X + cpu.memory[0x0010 + cpu.x] = 0x00 + cpu.step() + self.assertEquals(0x0002, cpu.pc) + self.assertEquals(0x00, cpu.a) + self.assertEquals(0, cpu.flags & cpu.CARRY) + self.assertEquals(0, cpu.flags & cpu.NEGATIVE) + self.assertEquals(cpu.ZERO, cpu.flags & cpu.ZERO) + + def test_adc_bcd_off_zp_x_carry_set_in_accumulator_zero(self): + cpu = MPU() + cpu.a = 0 + cpu.x = 0x03 + cpu.flags |= cpu.CARRY + cpu.memory[0x0000:0x0001] = (0x75, 0x10) #=> $0000 ADC $0010,X + cpu.memory[0x0010 + cpu.x] = 0x00 + cpu.step() + self.assertEquals(0x0002, cpu.pc) + self.assertEquals(0x01, cpu.a) + self.assertEquals(0, cpu.flags & cpu.NEGATIVE) + self.assertEquals(0, cpu.flags & cpu.ZERO) + self.assertNotEquals(cpu.CARRY, cpu.flags & cpu.CARRY) + + def test_adc_bcd_off_zp_x_carry_clear_in_no_carry_clear_out(self): + cpu = MPU() + cpu.a = 0x01 + cpu.x = 0x03 + cpu.memory[0x0000:0x0001] = (0x75, 0x10) #=> $0000 ADC $0010,X + cpu.memory[0x0010 + cpu.x] = 0xFE + cpu.step() + self.assertEquals(0x0002, cpu.pc) + self.assertEquals(0xFF, cpu.a) + self.assertEquals(cpu.NEGATIVE, cpu.flags & cpu.NEGATIVE) + self.assertEquals(0, cpu.flags & cpu.CARRY) + self.assertEquals(0, cpu.flags & cpu.ZERO) + + def test_adc_bcd_off_zp_x_carry_clear_in_carry_set_out(self): + cpu = MPU() + cpu.a = 0x02 + cpu.x = 0x03 + cpu.memory[0x0000:0x0001] = (0x75, 0x10) #=> $0000 ADC $0010,X + cpu.memory[0x0010 + cpu.x] = 0xFF + cpu.step() + self.assertEquals(0x0002, cpu.pc) + self.assertEquals(0x01, cpu.a) + self.assertEquals(cpu.CARRY, cpu.flags & cpu.CARRY) + self.assertEquals(0, cpu.flags & cpu.NEGATIVE) + self.assertEquals(0, cpu.flags & cpu.ZERO) + + def test_adc_bcd_off_zp_x_overflow(self): + cpu = MPU() + cpu.a = 0xFF + cpu.x = 0x03 + cpu.memory[0x0000:0x0001] = (0x75, 0x10) #=> $0000 ADC $0010,X + cpu.memory[0x0010 + cpu.x] = 0xFF + cpu.step() + self.assertEquals(0x0002, cpu.pc) + self.assertEquals(0xFE, cpu.a) + self.assertEquals(cpu.NEGATIVE, cpu.flags & cpu.NEGATIVE) + self.assertEquals(cpu.OVERFLOW, cpu.flags & cpu.OVERFLOW) + self.assertEquals(0, cpu.flags & cpu.ZERO) + + # ADC Indirect, Indexed (X) + + def test_adc_bcd_off_indirect_indexed_carry_clear_in_accumulator_zeroes(self): + cpu = MPU() + cpu.a = 0x00 + cpu.x = 0x03 + cpu.memory[0x0000:0x0001] = (0x61, 0x10) #=> $0000 ADC ($0010,X) + cpu.memory[0x0013:0x0014] = (0xCD, 0xAB) #=> Vector to $ABCD + cpu.memory[0xABCD] = 0x00 + cpu.step() + self.assertEquals(0x0002, cpu.pc) + self.assertEquals(0x00, cpu.a) + self.assertEquals(0, cpu.flags & cpu.CARRY) + self.assertEquals(0, cpu.flags & cpu.NEGATIVE) + self.assertEquals(cpu.ZERO, cpu.flags & cpu.ZERO) + + def test_adc_bcd_off_indirect_indexed_carry_set_in_accumulator_zero(self): + cpu = MPU() + cpu.a = 0 + cpu.x = 0x03 + cpu.flags |= cpu.CARRY + cpu.memory[0x0000:0x0001] = (0x61, 0x10) #=> $0000 ADC ($0010,X) + cpu.memory[0x0013:0x0014] = (0xCD, 0xAB) #=> Vector to $ABCD + cpu.memory[0xABCD] = 0x00 + cpu.step() + self.assertEquals(0x0002, cpu.pc) + self.assertEquals(0x01, cpu.a) + self.assertEquals(0, cpu.flags & cpu.NEGATIVE) + self.assertEquals(0, cpu.flags & cpu.ZERO) + self.assertNotEquals(cpu.CARRY, cpu.flags & cpu.CARRY) + + def test_adc_bcd_off_indirect_indexed_carry_clear_in_no_carry_clear_out(self): + cpu = MPU() + cpu.a = 0x01 + cpu.x = 0x03 + cpu.memory[0x0000:0x0001] = (0x61, 0x10) #=> $0000 ADC ($0010,X) + cpu.memory[0x0013:0x0014] = (0xCD, 0xAB) #=> Vector to $ABCD + cpu.memory[0xABCD] = 0xFE + cpu.step() + self.assertEquals(0x0002, cpu.pc) + self.assertEquals(0xFF, cpu.a) + self.assertEquals(cpu.NEGATIVE, cpu.flags & cpu.NEGATIVE) + self.assertEquals(0, cpu.flags & cpu.CARRY) + self.assertEquals(0, cpu.flags & cpu.ZERO) + + def test_adc_bcd_off_indirect_indexed_carry_clear_in_carry_set_out(self): + cpu = MPU() + cpu.a = 0x02 + cpu.x = 0x03 + cpu.memory[0x0000:0x0001] = (0x61, 0x10) #=> $0000 ADC ($0010,X) + cpu.memory[0x0013:0x0014] = (0xCD, 0xAB) #=> Vector to $ABCD + cpu.memory[0xABCD] = 0xFF + cpu.step() + self.assertEquals(0x0002, cpu.pc) + self.assertEquals(0x01, cpu.a) + self.assertEquals(cpu.CARRY, cpu.flags & cpu.CARRY) + self.assertEquals(0, cpu.flags & cpu.NEGATIVE) + self.assertEquals(0, cpu.flags & cpu.ZERO) + + def test_adc_bcd_off_indirect_indexed_overflow(self): + cpu = MPU() + cpu.a = 0xFF + cpu.x = 0x03 + cpu.memory[0x0000:0x0001] = (0x61, 0x10) #=> $0000 ADC ($0010,X) + cpu.memory[0x0013:0x0014] = (0xCD, 0xAB) #=> Vector to $ABCD + cpu.memory[0xABCD] = 0xFF + cpu.step() + self.assertEquals(0x0002, cpu.pc) + self.assertEquals(0xFE, cpu.a) + self.assertEquals(cpu.NEGATIVE, cpu.flags & cpu.NEGATIVE) + self.assertEquals(cpu.OVERFLOW, cpu.flags & cpu.OVERFLOW) + self.assertEquals(0, cpu.flags & cpu.ZERO) + + # ADC Indexed, Indirect (Y) + + def test_adc_bcd_off_indexed_indirect_carry_clear_in_accumulator_zeroes(self): + cpu = MPU() + cpu.a = 0x00 + cpu.y = 0x03 + cpu.memory[0x0000:0x0001] = (0x71, 0x10) #=> $0000 ADC ($0010),Y + cpu.memory[0x0010:0x0011] = (0xCD, 0xAB) #=> Vector to $ABCD + cpu.memory[0xABCD + cpu.y] = 0x00 + cpu.step() + self.assertEquals(0x0002, cpu.pc) + self.assertEquals(0x00, cpu.a) + self.assertEquals(0, cpu.flags & cpu.CARRY) + self.assertEquals(0, cpu.flags & cpu.NEGATIVE) + self.assertEquals(cpu.ZERO, cpu.flags & cpu.ZERO) + + def test_adc_bcd_off_indexed_indirect_carry_set_in_accumulator_zero(self): + cpu = MPU() + cpu.a = 0 + cpu.y = 0x03 + cpu.flags |= cpu.CARRY + cpu.memory[0x0000:0x0001] = (0x71, 0x10) #=> $0000 ADC ($0010),Y + cpu.memory[0x0010:0x0011] = (0xCD, 0xAB) #=> Vector to $ABCD + cpu.memory[0xABCD + cpu.y] = 0x00 + cpu.step() + self.assertEquals(0x0002, cpu.pc) + self.assertEquals(0x01, cpu.a) + self.assertEquals(0, cpu.flags & cpu.NEGATIVE) + self.assertEquals(0, cpu.flags & cpu.ZERO) + self.assertNotEquals(cpu.CARRY, cpu.flags & cpu.CARRY) + + def test_adc_bcd_off_indexed_indirect_carry_clear_in_no_carry_clear_out(self): + cpu = MPU() + cpu.a = 0x01 + cpu.y = 0x03 + cpu.memory[0x0000:0x0001] = (0x71, 0x10) #=> $0000 ADC ($0010),Y + cpu.memory[0x0010:0x0011] = (0xCD, 0xAB) #=> Vector to $ABCD + cpu.memory[0xABCD + cpu.y] = 0xFE + cpu.step() + self.assertEquals(0x0002, cpu.pc) + self.assertEquals(0xFF, cpu.a) + self.assertEquals(cpu.NEGATIVE, cpu.flags & cpu.NEGATIVE) + self.assertEquals(0, cpu.flags & cpu.CARRY) + self.assertEquals(0, cpu.flags & cpu.ZERO) + + def test_adc_bcd_off_indexed_indirect_carry_clear_in_carry_set_out(self): + cpu = MPU() + cpu.a = 0x02 + cpu.y = 0x03 + cpu.memory[0x0000:0x0001] = (0x71, 0x10) #=> $0000 ADC ($0010),Y + cpu.memory[0x0010:0x0011] = (0xCD, 0xAB) #=> Vector to $ABCD + cpu.memory[0xABCD + cpu.y] = 0xFF + cpu.step() + self.assertEquals(0x0002, cpu.pc) + self.assertEquals(0x01, cpu.a) + self.assertEquals(cpu.CARRY, cpu.flags & cpu.CARRY) + self.assertEquals(0, cpu.flags & cpu.NEGATIVE) + self.assertEquals(0, cpu.flags & cpu.ZERO) + + def test_adc_bcd_off_indexed_indirect_indexed_overflow(self): + cpu = MPU() + cpu.a = 0xFF + cpu.x = 0x03 + cpu.memory[0x0000:0x0001] = (0x61, 0x10) #=> $0000 ADC ($0010,X) + cpu.memory[0x0013:0x0014] = (0xCD, 0xAB) #=> Vector to $ABCD + cpu.memory[0xABCD] = 0xFF + cpu.step() + self.assertEquals(0x0002, cpu.pc) + self.assertEquals(0xFE, cpu.a) + self.assertEquals(cpu.NEGATIVE, cpu.flags & cpu.NEGATIVE) + self.assertEquals(cpu.OVERFLOW, cpu.flags & cpu.OVERFLOW) + self.assertEquals(0, cpu.flags & cpu.ZERO) + + # AND (Absolute) + + def test_and_absolute_all_zeros_setting_zero_flag(self): + cpu = MPU() + cpu.a = 0xFF + cpu.memory[0x0000:0x0002] = (0x2D, 0xCD, 0xAB) #=> AND $ABCD + cpu.memory[0xABCD] = 0x00 + cpu.step() + self.assertEquals(0x0003, cpu.pc) + self.assertEquals(0x00, cpu.a) + self.assertEquals(cpu.ZERO, cpu.flags & cpu.ZERO) + self.assertEquals(0, cpu.flags & cpu.NEGATIVE) + + def test_and_absolute_zeros_and_ones_setting_negative_flag(self): + cpu = MPU() + cpu.a = 0xFF + cpu.memory[0x0000:0x0002] = (0x2D, 0xCD, 0xAB) #=> AND $ABCD + cpu.memory[0xABCD] = 0xAA + cpu.step() + self.assertEquals(0x0003, cpu.pc) + self.assertEquals(0xAA, cpu.a) + self.assertEquals(cpu.NEGATIVE, cpu.flags & cpu.NEGATIVE) + self.assertEquals(0, cpu.flags & cpu.ZERO) + + # AND (Absolute) + + def test_and_zp_all_zeros_setting_zero_flag(self): + cpu = MPU() + cpu.a = 0xFF + cpu.memory[0x0000:0x0001] = (0x25, 0x10) #=> AND $0010 + cpu.memory[0x0010] = 0x00 + cpu.step() + self.assertEquals(0x0002, cpu.pc) + self.assertEquals(0x00, cpu.a) + self.assertEquals(cpu.ZERO, cpu.flags & cpu.ZERO) + self.assertEquals(0, cpu.flags & cpu.NEGATIVE) + + def test_and_zp_zeros_and_ones_setting_negative_flag(self): + cpu = MPU() + cpu.a = 0xFF + cpu.memory[0x0000:0x0001] = (0x25, 0x10) #=> AND $0010 + cpu.memory[0x0010] = 0xAA + cpu.step() + self.assertEquals(0x0002, cpu.pc) + self.assertEquals(0xAA, cpu.a) + self.assertEquals(cpu.NEGATIVE, cpu.flags & cpu.NEGATIVE) + self.assertEquals(0, cpu.flags & cpu.ZERO) + + # AND (Immediate) + + def test_and_immediate_all_zeros_setting_zero_flag(self): + cpu = MPU() + cpu.a = 0xFF + cpu.memory[0x0000:0x0001] = (0x29, 0x00) #=> AND #$00 + cpu.step() + self.assertEquals(0x0002, cpu.pc) + self.assertEquals(0x00, cpu.a) + self.assertEquals(cpu.ZERO, cpu.flags & cpu.ZERO) + self.assertEquals(0, cpu.flags & cpu.NEGATIVE) + + def test_and_immediate_zeros_and_ones_setting_negative_flag(self): + cpu = MPU() + cpu.a = 0xFF + cpu.memory[0x0000:0x0001] = (0x29, 0xAA) #=> AND #$AA + cpu.step() + self.assertEquals(0x0002, cpu.pc) + self.assertEquals(0xAA, cpu.a) + self.assertEquals(cpu.NEGATIVE, cpu.flags & cpu.NEGATIVE) + self.assertEquals(0, cpu.flags & cpu.ZERO) + + # AND (Absolute, X-Indexed) + + def test_and_abs_x_all_zeros_setting_zero_flag(self): + cpu = MPU() + cpu.a = 0xFF + cpu.x = 0x03 + cpu.memory[0x0000:0x0002] = (0x3d, 0xCD, 0xAB) #=> AND $ABCD,X + cpu.memory[0xABCD + cpu.x] = 0x00 + cpu.step() + self.assertEquals(0x0003, cpu.pc) + self.assertEquals(0x00, cpu.a) + self.assertEquals(cpu.ZERO, cpu.flags & cpu.ZERO) + self.assertEquals(0, cpu.flags & cpu.NEGATIVE) + + def test_and_abs_x_zeros_and_ones_setting_negative_flag(self): + cpu = MPU() + cpu.a = 0xFF + cpu.x = 0x03 + cpu.memory[0x0000:0x0002] = (0x3d, 0xCD, 0xAB) #=> AND $ABCD,X + cpu.memory[0xABCD + cpu.x] = 0xAA + cpu.step() + self.assertEquals(0x0003, cpu.pc) + self.assertEquals(0xAA, cpu.a) + self.assertEquals(cpu.NEGATIVE, cpu.flags & cpu.NEGATIVE) + self.assertEquals(0, cpu.flags & cpu.ZERO) + + # AND (Absolute, Y-Indexed) + + def test_and_abs_y_all_zeros_setting_zero_flag(self): + cpu = MPU() + cpu.a = 0xFF + cpu.y = 0x03 + cpu.memory[0x0000:0x0002] = (0x39, 0xCD, 0xAB) #=> AND $ABCD,X + cpu.memory[0xABCD + cpu.y] = 0x00 + cpu.step() + self.assertEquals(0x0003, cpu.pc) + self.assertEquals(0x00, cpu.a) + self.assertEquals(cpu.ZERO, cpu.flags & cpu.ZERO) + self.assertEquals(0, cpu.flags & cpu.NEGATIVE) + + def test_and_abs_y_zeros_and_ones_setting_negative_flag(self): + cpu = MPU() + cpu.a = 0xFF + cpu.y = 0x03 + cpu.memory[0x0000:0x0002] = (0x39, 0xCD, 0xAB) #=> AND $ABCD,X + cpu.memory[0xABCD + cpu.y] = 0xAA + cpu.step() + self.assertEquals(0x0003, cpu.pc) + self.assertEquals(0xAA, cpu.a) + self.assertEquals(cpu.NEGATIVE, cpu.flags & cpu.NEGATIVE) + self.assertEquals(0, cpu.flags & cpu.ZERO) + + # AND Indirect, Indexed (X) + + def test_and_indirect_indexed_x_all_zeros_setting_zero_flag(self): + cpu = MPU() + cpu.a = 0xFF + cpu.x = 0x03 + cpu.memory[0x0000:0x0001] = (0x21, 0x10) #=> AND ($0010,X) + cpu.memory[0x0013:0x0014] = (0xCD, 0xAB) #=> Vector to $ABCD + cpu.memory[0xABCD] = 0x00 + cpu.step() + self.assertEquals(0x0002, cpu.pc) + self.assertEquals(0x00, cpu.a) + self.assertEquals(cpu.ZERO, cpu.flags & cpu.ZERO) + self.assertEquals(0, cpu.flags & cpu.NEGATIVE) + + def test_and_indirect_indexed_x_zeros_and_ones_setting_negative_flag(self): + cpu = MPU() + cpu.a = 0xFF + cpu.x = 0x03 + cpu.memory[0x0000:0x0001] = (0x21, 0x10) #=> AND ($0010,X) + cpu.memory[0x0013:0x0014] = (0xCD, 0xAB) #=> Vector to $ABCD + cpu.memory[0xABCD] = 0xAA + cpu.step() + self.assertEquals(0x0002, cpu.pc) + self.assertEquals(0xAA, cpu.a) + self.assertEquals(cpu.NEGATIVE, cpu.flags & cpu.NEGATIVE) + self.assertEquals(0, cpu.flags & cpu.ZERO) + + # AND Indexed, Indirect (Y) + + def test_and_indexed_indirect_y_all_zeros_setting_zero_flag(self): + cpu = MPU() + cpu.a = 0xFF + cpu.y = 0x03 + cpu.memory[0x0000:0x0001] = (0x31, 0x10) #=> AND ($0010),Y + cpu.memory[0x0010:0x0011] = (0xCD, 0xAB) #=> Vector to $ABCD + cpu.memory[0xABCD + cpu.y] = 0x00 + cpu.step() + self.assertEquals(0x0002, cpu.pc) + self.assertEquals(0x00, cpu.a) + self.assertEquals(cpu.ZERO, cpu.flags & cpu.ZERO) + self.assertEquals(0, cpu.flags & cpu.NEGATIVE) + + def test_and_indexed_indirect_y_zeros_and_ones_setting_negative_flag(self): + cpu = MPU() + cpu.a = 0xFF + cpu.y = 0x03 + cpu.memory[0x0000:0x0001] = (0x31, 0x10) #=> AND ($0010),Y + cpu.memory[0x0010:0x0011] = (0xCD, 0xAB) #=> Vector to $ABCD + cpu.memory[0xABCD + cpu.y] = 0xAA + cpu.step() + self.assertEquals(0x0002, cpu.pc) + self.assertEquals(0xAA, cpu.a) + self.assertEquals(cpu.NEGATIVE, cpu.flags & cpu.NEGATIVE) + self.assertEquals(0, cpu.flags & cpu.ZERO) + + # AND Zero Page, X-Indexed + + def test_and_zp_x_all_zeros_setting_zero_flag(self): + cpu = MPU() + cpu.a = 0xFF + cpu.x = 0x03 + cpu.memory[0x0000:0x0001] = (0x35, 0x10) #=> AND $0010,X + cpu.memory[0x0010 + cpu.x] = 0x00 + cpu.step() + self.assertEquals(0x0002, cpu.pc) + self.assertEquals(0x00, cpu.a) + self.assertEquals(cpu.ZERO, cpu.flags & cpu.ZERO) + self.assertEquals(0, cpu.flags & cpu.NEGATIVE) + + def test_and_zp_x_all_zeros_and_ones_setting_negative_flag(self): + cpu = MPU() + cpu.a = 0xFF + cpu.x = 0x03 + cpu.memory[0x0000:0x0001] = (0x35, 0x10) #=> AND $0010,X + cpu.memory[0x0010 + cpu.x] = 0xAA + cpu.step() + self.assertEquals(0x0002, cpu.pc) + self.assertEquals(0xAA, cpu.a) + self.assertEquals(cpu.NEGATIVE, cpu.flags & cpu.NEGATIVE) + self.assertEquals(0, cpu.flags & cpu.ZERO) + + # ASL Accumulator + + def test_asl_accumulator_sets_z_flag(self): + cpu = MPU() + cpu.a = 0x00 + cpu.memory[0x0000] = 0x0A #=> ASL A + cpu.step() + self.assertEquals(0x0001, cpu.pc) + self.assertEquals(0x00, cpu.a) + self.assertEquals(cpu.ZERO, cpu.flags & cpu.ZERO) + self.assertEquals(0, cpu.flags & cpu.NEGATIVE) + + def test_asl_accumulator_sets_n_flag(self): + cpu = MPU() + cpu.a = 0x40 + cpu.memory[0x0000] = 0x0A #=> ASL A + cpu.step() + self.assertEquals(0x0001, cpu.pc) + self.assertEquals(0x80, cpu.a) + self.assertEquals(cpu.NEGATIVE, cpu.flags & cpu.NEGATIVE) + self.assertEquals(0, cpu.flags & cpu.ZERO) + + def test_asl_accumulator_shifts_out_zero(self): + cpu = MPU() + cpu.a = 0x7F + cpu.memory[0x0000] = 0x0A #=> ASL A + cpu.step() + self.assertEquals(0x0001, cpu.pc) + self.assertEquals(0xFE, cpu.a) + self.assertEquals(0, cpu.flags & cpu.CARRY) + + def test_asl_accumulator_shifts_out_one(self): + cpu = MPU() + cpu.a = 0xFF + cpu.memory[0x0000] = 0x0A #=> ASL A + cpu.step() + self.assertEquals(0x0001, cpu.pc) + self.assertEquals(0xFE, cpu.a) + self.assertEquals(cpu.CARRY, cpu.flags & cpu.CARRY) + + # ASL Absolute + + def test_asl_absolute_sets_z_flag(self): + cpu = MPU() + cpu.memory[0x0000:0x0002] = (0x0E, 0xCD, 0xAB) #=> ASL $ABCD + cpu.memory[0xABCD] = 0x00 + cpu.step() + self.assertEquals(0x0003, cpu.pc) + self.assertEquals(0x00, cpu.memory[0xABCD]) + self.assertEquals(cpu.ZERO, cpu.flags & cpu.ZERO) + self.assertEquals(0, cpu.flags & cpu.NEGATIVE) + + def test_asl_absolute_sets_n_flag(self): + cpu = MPU() + cpu.memory[0x0000:0x0002] = (0x0E, 0xCD, 0xAB) #=> ASL $ABCD + cpu.memory[0xABCD] = 0x40 + cpu.step() + self.assertEquals(0x0003, cpu.pc) + self.assertEquals(0x80, cpu.memory[0xABCD]) + self.assertEquals(cpu.NEGATIVE, cpu.flags & cpu.NEGATIVE) + self.assertEquals(0, cpu.flags & cpu.ZERO) + + def test_asl_absolute_shifts_out_zero(self): + cpu = MPU() + cpu.a = 0xAA + cpu.memory[0x0000:0x0002] = (0x0E, 0xCD, 0xAB) #=> ASL $ABCD + cpu.memory[0xABCD] = 0x7F + cpu.step() + self.assertEquals(0x0003, cpu.pc) + self.assertEquals(0xAA, cpu.a) + self.assertEquals(0xFE, cpu.memory[0xABCD]) + self.assertEquals(0, cpu.flags & cpu.CARRY) + + def test_asl_absolute_shifts_out_one(self): + cpu = MPU() + cpu.a = 0xAA + cpu.memory[0x0000:0x0002] = (0x0E, 0xCD, 0xAB) #=> ASL $ABCD + cpu.memory[0xABCD] = 0xFF + cpu.step() + self.assertEquals(0x0003, cpu.pc) + self.assertEquals(0xAA, cpu.a) + self.assertEquals(0xFE, cpu.memory[0xABCD]) + self.assertEquals(cpu.CARRY, cpu.flags & cpu.CARRY) + + # ASL Zero Page + + def test_asl_zp_sets_z_flag(self): + cpu = MPU() + cpu.memory[0x0000:0x0001] = (0x06, 0x10) #=> ASL $0010 + cpu.memory[0x0010] = 0x00 + cpu.step() + self.assertEquals(0x0002, cpu.pc) + self.assertEquals(0x00, cpu.memory[0x0010]) + self.assertEquals(cpu.ZERO, cpu.flags & cpu.ZERO) + self.assertEquals(0, cpu.flags & cpu.NEGATIVE) + + def test_asl_zp_sets_n_flag(self): + cpu = MPU() + cpu.memory[0x0000:0x0001] = (0x06, 0x10) #=> ASL $0010 + cpu.memory[0x0010] = 0x40 + cpu.step() + self.assertEquals(0x0002, cpu.pc) + self.assertEquals(0x80, cpu.memory[0x0010]) + self.assertEquals(cpu.NEGATIVE, cpu.flags & cpu.NEGATIVE) + self.assertEquals(0, cpu.flags & cpu.ZERO) + + def test_asl_zp_shifts_out_zero(self): + cpu = MPU() + cpu.a = 0xAA + cpu.memory[0x0000:0x0001] = (0x06, 0x10) #=> ASL $0010 + cpu.memory[0x0010] = 0x7F + cpu.step() + self.assertEquals(0x0002, cpu.pc) + self.assertEquals(0xAA, cpu.a) + self.assertEquals(0xFE, cpu.memory[0x0010]) + self.assertEquals(0, cpu.flags & cpu.CARRY) + + def test_asl_zp_shifts_out_one(self): + cpu = MPU() + cpu.a = 0xAA + cpu.memory[0x0000:0x0001] = (0x06, 0x10) #=> ASL $0010 + cpu.memory[0x0010] = 0xFF + cpu.step() + self.assertEquals(0x0002, cpu.pc) + self.assertEquals(0xAA, cpu.a) + self.assertEquals(0xFE, cpu.memory[0x0010]) + self.assertEquals(cpu.CARRY, cpu.flags & cpu.CARRY) + + # ASL Absolute, X-Indexed + + def test_asl_absolute_x_indexed_sets_z_flag(self): + cpu = MPU() + cpu.x = 0x03 + cpu.memory[0x0000:0x0002] = (0x1E, 0xCD, 0xAB) #=> ASL $ABCD,X + cpu.memory[0xABCD + cpu.x] = 0x00 + cpu.step() + self.assertEquals(0x0003, cpu.pc) + self.assertEquals(0x00, cpu.memory[0xABCD + cpu.x]) + self.assertEquals(cpu.ZERO, cpu.flags & cpu.ZERO) + self.assertEquals(0, cpu.flags & cpu.NEGATIVE) + + def test_asl_absolute_x_indexed_sets_n_flag(self): + cpu = MPU() + cpu.x = 0x03 + cpu.memory[0x0000:0x0002] = (0x1E, 0xCD, 0xAB) #=> ASL $ABCD,X + cpu.memory[0xABCD + cpu.x] = 0x40 + cpu.step() + self.assertEquals(0x0003, cpu.pc) + self.assertEquals(0x80, cpu.memory[0xABCD + cpu.x]) + self.assertEquals(cpu.NEGATIVE, cpu.flags & cpu.NEGATIVE) + self.assertEquals(0, cpu.flags & cpu.ZERO) + + def test_asl_absolute_x_indexed_shifts_out_zero(self): + cpu = MPU() + cpu.a = 0xAA + cpu.x = 0x03 + cpu.memory[0x0000:0x0002] = (0x1E, 0xCD, 0xAB) #=> ASL $ABCD,X + cpu.memory[0xABCD + cpu.x] = 0x7F + cpu.step() + self.assertEquals(0x0003, cpu.pc) + self.assertEquals(0xAA, cpu.a) + self.assertEquals(0xFE, cpu.memory[0xABCD + cpu.x]) + self.assertEquals(0, cpu.flags & cpu.CARRY) + + def test_asl_absolute_x_indexed_shifts_out_one(self): + cpu = MPU() + cpu.a = 0xAA + cpu.x = 0x03 + cpu.memory[0x0000:0x0002] = (0x1E, 0xCD, 0xAB) #=> ASL $ABCD,X + cpu.memory[0xABCD + cpu.x] = 0xFF + cpu.step() + self.assertEquals(0x0003, cpu.pc) + self.assertEquals(0xAA, cpu.a) + self.assertEquals(0xFE, cpu.memory[0xABCD + cpu.x]) + self.assertEquals(cpu.CARRY, cpu.flags & cpu.CARRY) + + # ASL Zero Page, X-Indexed + + def test_asl_zp_x_indexed_sets_z_flag(self): + cpu = MPU() + cpu.x = 0x03 + cpu.memory[0x0000:0x0001] = (0x16, 0x10) #=> ASL $0010,X + cpu.memory[0x0010 + cpu.x] = 0x00 + cpu.step() + self.assertEquals(0x0002, cpu.pc) + self.assertEquals(0x00, cpu.memory[0x0010 + cpu.x]) + self.assertEquals(cpu.ZERO, cpu.flags & cpu.ZERO) + self.assertEquals(0, cpu.flags & cpu.NEGATIVE) + + def test_asl_zp_x_indexed_sets_n_flag(self): + cpu = MPU() + cpu.x = 0x03 + cpu.memory[0x0000:0x0001] = (0x16, 0x10) #=> ASL $0010,X + cpu.memory[0x0010 + cpu.x] = 0x40 + cpu.step() + self.assertEquals(0x0002, cpu.pc) + self.assertEquals(0x80, cpu.memory[0x0010 + cpu.x]) + self.assertEquals(cpu.NEGATIVE, cpu.flags & cpu.NEGATIVE) + self.assertEquals(0, cpu.flags & cpu.ZERO) + + def test_asl_zp_x_indexed_shifts_out_zero(self): + cpu = MPU() + cpu.x = 0x03 + cpu.a = 0xAA + cpu.memory[0x0000:0x0001] = (0x16, 0x10) #=> ASL $0010,X + cpu.memory[0x0010 + cpu.x] = 0x7F + cpu.step() + self.assertEquals(0x0002, cpu.pc) + self.assertEquals(0xAA, cpu.a) + self.assertEquals(0xFE, cpu.memory[0x0010 + cpu.x]) + self.assertEquals(0, cpu.flags & cpu.CARRY) + + def test_asl_zp_x_indexed_shifts_out_one(self): + cpu = MPU() + cpu.x = 0x03 + cpu.a = 0xAA + cpu.memory[0x0000:0x0001] = (0x16, 0x10) #=> ASL $0010,X + cpu.memory[0x0010 + cpu.x] = 0xFF + cpu.step() + self.assertEquals(0x0002, cpu.pc) + self.assertEquals(0xAA, cpu.a) + self.assertEquals(0xFE, cpu.memory[0x0010 + cpu.x]) + self.assertEquals(cpu.CARRY, cpu.flags & cpu.CARRY) + + # BCC + + def test_bcc_carry_clear_branches_relative_forward(self): + cpu = MPU() + cpu.flags &= ~(cpu.CARRY) + cpu.memory[0x0000:0x0001] = (0x90, 0x06) #=> BCC +6 + cpu.step() + self.assertEquals(0x0002 + 0x06, cpu.pc) + + def test_bcc_carry_clear_branches_relative_backward(self): + cpu = MPU() + cpu.flags &= ~(cpu.CARRY) + cpu.pc = 0x0050 + rel = (0x06^0xFF + 1) # two's complement of 6 + cpu.memory[0x0050:0x0051] = (0x90, rel) #=> BCC -6 + cpu.step() + self.assertEquals(0x0052 + rel, cpu.pc) + + def test_bcc_carry_set_does_not_branch(self): + cpu = MPU() + cpu.flags |= cpu.CARRY + cpu.memory[0x0000:0x0001] = (0x90, 0x06) #=> BCC +6 + cpu.step() + self.assertEquals(0x0002, cpu.pc) + + # BCS + + def test_bcs_carry_set_branches_relative_forward(self): + cpu = MPU() + cpu.flags |= cpu.CARRY + cpu.memory[0x0000:0x0001] = (0xB0, 0x06) #=> BCS +6 + cpu.step() + self.assertEquals(0x0002 + 0x06, cpu.pc) + + def test_bcs_carry_set_branches_relative_backward(self): + cpu = MPU() + cpu.flags |= cpu.CARRY + cpu.pc = 0x0050 + rel = (0x06^0xFF + 1) # two's complement of 6 + cpu.memory[0x0050:0x0051] = (0xB0, rel) #=> BCS -6 + cpu.step() + self.assertEquals(0x0052 + rel, cpu.pc) + + def test_bcs_carry_clear_does_not_branch(self): + cpu = MPU() + cpu.flags &= ~(cpu.CARRY) + cpu.memory[0x0000:0x0001] = (0xB0, 0x06) #=> BCS +6 + cpu.step() + self.assertEquals(0x0002, cpu.pc) + + # BEQ + + def test_beq_zero_set_branches_relative_forward(self): + cpu = MPU() + cpu.flags |= cpu.ZERO + cpu.memory[0x0000:0x0001] = (0xF0, 0x06) #=> BEQ +6 + cpu.step() + self.assertEquals(0x0002 + 0x06, cpu.pc) + + def test_beq_zero_set_branches_relative_backward(self): + cpu = MPU() + cpu.flags |= cpu.ZERO + cpu.pc = 0x0050 + rel = (0x06^0xFF + 1) # two's complement of 6 + cpu.memory[0x0050:0x0051] = (0xF0, rel) #=> BEQ -6 + cpu.step() + self.assertEquals(0x0052 + rel, cpu.pc) + + def test_beq_zero_clear_does_not_branch(self): + cpu = MPU() + cpu.flags &= ~(cpu.ZERO) + cpu.memory[0x0000:0x0001] = (0xF0, 0x06) #=> BEQ +6 + cpu.step() + self.assertEquals(0x0002, cpu.pc) + + # BMI + + def test_bmi_negative_set_branches_relative_forward(self): + cpu = MPU() + cpu.flags |= cpu.NEGATIVE + cpu.memory[0x0000:0x0001] = (0x30, 0x06) #=> BMI +06 + cpu.step() + self.assertEquals(0x0002 + 0x06, cpu.pc) + + def test_bmi_negative_set_branches_relative_backward(self): + cpu = MPU() + cpu.flags |= cpu.NEGATIVE + cpu.pc = 0x0050 + rel = (0x06^0xFF + 1) # two's complement of 6 + cpu.memory[0x0050:0x0051] = (0x30, rel) #=> BMI -6 + cpu.step() + self.assertEquals(0x0052 + rel, cpu.pc) + + def test_bmi_negative_clear_does_not_branch(self): + cpu = MPU() + cpu.flags &= ~(cpu.NEGATIVE) + cpu.memory[0x0000:0x0001] = (0x30, 0x06) #=> BEQ +6 + cpu.step() + self.assertEquals(0x0002, cpu.pc) + + # BNE + + def test_bne_zero_clear_branches_relative_forward(self): + cpu = MPU() + cpu.flags &= ~(cpu.ZERO) + cpu.memory[0x0000:0x0001] = (0xD0, 0x06) #=> BNE +6 + cpu.step() + self.assertEquals(0x0002 + 0x06, cpu.pc) + + def test_bne_zero_clear_branches_relative_backward(self): + cpu = MPU() + cpu.flags &= ~(cpu.ZERO) + cpu.pc = 0x0050 + rel = (0x06^0xFF + 1) # two's complement of 6 + cpu.memory[0x0050:0x0051] = (0xD0, rel) #=> BNE -6 + cpu.step() + self.assertEquals(0x0052 + rel, cpu.pc) + + def test_bne_zero_set_does_not_branch(self): + cpu = MPU() + cpu.flags |= cpu.ZERO + cpu.memory[0x0000:0x0001] = (0xD0, 0x06) #=> BNE +6 + cpu.step() + self.assertEquals(0x0002, cpu.pc) + + # BPL + + def test_bpl_negative_clear_branches_relative_forward(self): + cpu = MPU() + cpu.flags &= ~(cpu.NEGATIVE) + cpu.memory[0x0000:0x0001] = (0x10, 0x06) #=> BPL +06 + cpu.step() + self.assertEquals(0x0002 + 0x06, cpu.pc) + + def test_bpl_negative_clear_branches_relative_backward(self): + cpu = MPU() + cpu.flags &= ~(cpu.NEGATIVE) + cpu.pc = 0x0050 + rel = (0x06^0xFF + 1) # two's complement of 6 + cpu.memory[0x0050:0x0051] = (0x10, rel) #=> BPL -6 + cpu.step() + self.assertEquals(0x0052 + rel, cpu.pc) + + def test_bpl_negative_set_does_not_branch(self): + cpu = MPU() + cpu.flags |= cpu.NEGATIVE + cpu.memory[0x0000:0x0001] = (0x10, 0x06) #=> BPL +6 + cpu.step() + self.assertEquals(0x0002, cpu.pc) + + # BRK + + def test_brk_pushes_pc_plus_2_and_status_then_sets_pc_to_irq_vector(self): + cpu = MPU() + cpu.flags = 0x00 + cpu.memory[0xFFFE:0xFFFF] = (0xCD, 0xAB) + cpu.memory[0xC000] = 0x00 #=> BRK + cpu.pc = 0xC000 + cpu.step() + self.assertEquals(0xABCD, cpu.pc) + + self.assertEquals(0xC0, cpu.memory[0x1FF]) # PCH + self.assertEquals(0x03, cpu.memory[0x1FE]) # PCL + self.assertEquals(cpu.BREAK, cpu.memory[0x1FD]) # Status (P) + self.assertEquals(0xFC, cpu.sp) + + self.assertEquals(cpu.BREAK | cpu.INTERRUPT, cpu.flags) + + # BVC + + def test_bvc_overflow_clear_branches_relative_forward(self): + cpu = MPU() + cpu.flags &= ~(cpu.OVERFLOW) + cpu.memory[0x0000:0x0001] = (0x50, 0x06) #=> BVC +6 + cpu.step() + self.assertEquals(0x0002 + 0x06, cpu.pc) + + def test_bvc_overflow_clear_branches_relative_backward(self): + cpu = MPU() + cpu.flags &= ~(cpu.OVERFLOW) + cpu.pc = 0x0050 + rel = (0x06^0xFF + 1) # two's complement of 6 + cpu.memory[0x0050:0x0051] = (0x50, rel) #=> BVC -6 + cpu.step() + self.assertEquals(0x0052 + rel, cpu.pc) + + def test_bvc_overflow_set_does_not_branch(self): + cpu = MPU() + cpu.flags |= cpu.OVERFLOW + cpu.memory[0x0000:0x0001] = (0x50, 0x06) #=> BVC +6 + cpu.step() + self.assertEquals(0x0002, cpu.pc) + + # BVS + + def test_bvs_overflow_set_branches_relative_forward(self): + cpu = MPU() + cpu.flags |= cpu.OVERFLOW + cpu.memory[0x0000:0x0001] = (0x70, 0x06) #=> BVS +6 + cpu.step() + self.assertEquals(0x0002 + 0x06, cpu.pc) + + def test_bvs_overflow_set_branches_relative_backward(self): + cpu = MPU() + cpu.flags |= cpu.OVERFLOW + cpu.pc = 0x0050 + rel = (0x06^0xFF + 1) # two's complement of 6 + cpu.memory[0x0050:0x0051] = (0x70, rel) #=> BVS -6 + cpu.step() + self.assertEquals(0x0052 + rel, cpu.pc) + + def test_bvs_overflow_clear_does_not_branch(self): + cpu = MPU() + cpu.flags &= ~(cpu.OVERFLOW) + cpu.memory[0x0000:0x0001] = (0x70, 0x06) #=> BVS +6 + cpu.step() + self.assertEquals(0x0002, cpu.pc) + + # CLC + + def test_clc_clears_carry_flag(self): + cpu = MPU() + cpu.flags |= cpu.CARRY + cpu.memory[0x0000] = 0x18 #=> CLC + cpu.step() + self.assertEquals(0x0001, cpu.pc) + self.assertEquals(0, cpu.flags & cpu.CARRY) + + # CLD + + def test_cld_clears_decimal_flag(self): + cpu = MPU() + cpu.flags |= cpu.DECIMAL + cpu.memory[0x0000] = 0xD8 #=> CLD + cpu.step() + self.assertEquals(0x0001, cpu.pc) + self.assertEquals(0, cpu.flags & cpu.DECIMAL) + + # CLI + + def test_cli_clears_interrupt_mask_flag(self): + cpu = MPU() + cpu.flags |= cpu.INTERRUPT + cpu.memory[0x0000] = 0x58 #=> CLI + cpu.step() + self.assertEquals(0x0001, cpu.pc) + self.assertEquals(0, cpu.flags & cpu.INTERRUPT) + + # CLV + + def test_clv_clears_overflow_flag(self): + cpu = MPU() + cpu.flags |= cpu.OVERFLOW + cpu.memory[0x0000] = 0xB8 #=> CLV + cpu.step() + self.assertEquals(0x0001, cpu.pc) + self.assertEquals(0, cpu.flags & cpu.OVERFLOW) + + # DEX + + def test_dex_decrements_x(self): + cpu = MPU() + cpu.x = 0x10 + cpu.memory[0x0000] = 0xCA #=> DEX + cpu.step() + self.assertEquals(0x0001, cpu.pc) + self.assertEquals(0x0F, cpu.x) + + def test_dex_below_00_rolls_over_and_sets_negative_flag(self): + cpu = MPU() + cpu.x = 0x00 + cpu.memory[0x0000] = 0xCA #=> DEX + cpu.step() + self.assertEquals(0x0001, cpu.pc) + self.assertEquals(0xFF, cpu.x) + self.assertEquals(cpu.NEGATIVE, cpu.flags & cpu.NEGATIVE) + + def test_dex_sets_zero_flag_when_decrementing_to_zero(self): + cpu = MPU() + cpu.x = 0x01 + cpu.memory[0x0000] = 0xCA #=> DEX + cpu.step() + self.assertEquals(0x0001, cpu.pc) + self.assertEquals(0x00, cpu.x) + self.assertEquals(cpu.ZERO, cpu.flags & cpu.ZERO) + + # DEY + + def test_dey_decrements_y(self): + cpu = MPU() + cpu.y = 0x10 + cpu.memory[0x0000] = 0x88 #=> DEY + cpu.step() + self.assertEquals(0x0001, cpu.pc) + self.assertEquals(0x0F, cpu.y) + + def test_dey_below_00_rolls_over_and_sets_negative_flag(self): + cpu = MPU() + cpu.y = 0x00 + cpu.memory[0x0000] = 0x88 #=> DEY + cpu.step() + self.assertEquals(0x0001, cpu.pc) + self.assertEquals(0xFF, cpu.y) + self.assertEquals(cpu.NEGATIVE, cpu.flags & cpu.NEGATIVE) + + def test_dey_sets_zero_flag_when_decrementing_to_zero(self): + cpu = MPU() + cpu.y = 0x01 + cpu.memory[0x0000] = 0x88 #=> DEY + cpu.step() + self.assertEquals(0x0001, cpu.pc) + self.assertEquals(0x00, cpu.y) + self.assertEquals(cpu.ZERO, cpu.flags & cpu.ZERO) + + # INX + + def test_inx_increments_x(self): + cpu = MPU() + cpu.x = 0x09 + cpu.memory[0x0000] = 0xE8 #=> INX + cpu.step() + self.assertEquals(0x0001, cpu.pc) + self.assertEquals(0x0A, cpu.x) + + def test_inx_above_FF_rolls_over_and_sets_zero_flag(self): + cpu = MPU() + cpu.x = 0xFF + cpu.memory[0x0000] = 0xE8 #=> INX + cpu.step() + self.assertEquals(0x0001, cpu.pc) + self.assertEquals(0x00, cpu.x) + self.assertEquals(cpu.ZERO, cpu.flags & cpu.ZERO) + + def test_inx_sets_negative_flag_when_incrementing_above_7F(self): + cpu = MPU() + cpu.x = 0x7f + cpu.memory[0x0000] = 0xE8 #=> INX + cpu.step() + self.assertEquals(0x0001, cpu.pc) + self.assertEquals(0x80, cpu.x) + self.assertEquals(cpu.NEGATIVE, cpu.flags & cpu.NEGATIVE) + + # INY + + def test_iny_increments_y(self): + cpu = MPU() + cpu.y = 0x09 + cpu.memory[0x0000] = 0xC8 #=> INY + cpu.step() + self.assertEquals(0x0001, cpu.pc) + self.assertEquals(0x0A, cpu.y) + + def test_iny_above_FF_rolls_over_and_sets_zero_flag(self): + cpu = MPU() + cpu.y = 0xFF + cpu.memory[0x0000] = 0xC8 #=> INY + cpu.step() + self.assertEquals(0x0001, cpu.pc) + self.assertEquals(0x00, cpu.y) + self.assertEquals(cpu.ZERO, cpu.flags & cpu.ZERO) + + def test_iny_sets_negative_flag_when_incrementing_above_7F(self): + cpu = MPU() + cpu.y = 0x7f + cpu.memory[0x0000] = 0xC8 #=> INY + cpu.step() + self.assertEquals(0x0001, cpu.pc) + self.assertEquals(0x80, cpu.y) + self.assertEquals(cpu.NEGATIVE, cpu.flags & cpu.NEGATIVE) + + # JMP + + def test_jmp_jumps_to_absolute_address(self): + cpu = MPU() + cpu.memory[0x0000:0x0002] = (0x4C, 0xCD, 0xAB) #=> JMP $ABCD + cpu.step() + self.assertEquals(0xABCD, cpu.pc) + + def test_jmp_jumps_to_indirect_address(self): + cpu = MPU() + cpu.memory[0x0000:0x0002] = (0x6C, 0x00, 0x02) #=> JMP ($ABCD) + cpu.memory[0x0200:0x0201] = (0xCD, 0xAB) + cpu.step() + self.assertEquals(0xABCD, cpu.pc) + + # JSR + + def test_jsr_pushes_pc_plus_2_and_sets_pc(self): + cpu = MPU() + cpu.memory[0xC000:0xC002] = (0x20, 0xD2, 0xFF) #=> JSR $FFD2 + cpu.pc = 0xC000 + cpu.step() + self.assertEquals(0xFFD2, cpu.pc) + self.assertEquals(0xFD, cpu.sp) + self.assertEquals(0xC0, cpu.memory[0x01FF]) # PCH + self.assertEquals(0x02, cpu.memory[0x01FE]) # PCL+2 + + # LDA Absolute + + def test_lda_absolute_loads_a_sets_n_flag(self): + cpu = MPU() + cpu.a = 0x00 + cpu.memory[0x0000:0x0002] = (0xAD, 0xCD, 0xAB) #=> LDA $ABCD + cpu.memory[0xABCD] = 0x80 + cpu.step() + self.assertEquals(0x0003, cpu.pc) + self.assertEquals(0x80, cpu.a) + self.assertEquals(cpu.NEGATIVE, cpu.flags & cpu.NEGATIVE) + self.assertEquals(0, cpu.flags & cpu.ZERO) + + def test_lda_absolute_loads_a_sets_z_flag(self): + cpu = MPU() + cpu.a = 0xFF + cpu.memory[0x0000:0x0002] = (0xAD, 0xCD, 0xAB) #=> LDA $ABCD + cpu.memory[0xABCD] = 0x00 + cpu.step() + self.assertEquals(0x0003, cpu.pc) + self.assertEquals(0x00, cpu.a) + self.assertEquals(cpu.ZERO, cpu.flags & cpu.ZERO) + self.assertEquals(0, cpu.flags & cpu.NEGATIVE) + + # LDA Absolute + + def test_lda_absolute_loads_a_sets_n_flag(self): + cpu = MPU() + cpu.a = 0x00 + cpu.memory[0x0000:0x0002] = (0xAD, 0xCD, 0xAB) #=> LDA $ABCD + cpu.memory[0xABCD] = 0x80 + cpu.step() + self.assertEquals(0x0003, cpu.pc) + self.assertEquals(0x80, cpu.a) + self.assertEquals(cpu.NEGATIVE, cpu.flags & cpu.NEGATIVE) + self.assertEquals(0, cpu.flags & cpu.ZERO) + + def test_lda_absolute_loads_a_sets_z_flag(self): + cpu = MPU() + cpu.a = 0xFF + cpu.memory[0x0000:0x0002] = (0xAD, 0xCD, 0xAB) #=> LDA $ABCD + cpu.memory[0xABCD] = 0x00 + cpu.step() + self.assertEquals(0x0003, cpu.pc) + self.assertEquals(0x00, cpu.a) + self.assertEquals(cpu.ZERO, cpu.flags & cpu.ZERO) + self.assertEquals(0, cpu.flags & cpu.NEGATIVE) + + # LDA Zero Page + + def test_lda_zp_loads_a_sets_n_flag(self): + cpu = MPU() + cpu.a = 0x00 + cpu.memory[0x0000:0x0002] = (0xA5, 0x10) #=> LDA $0010 + cpu.memory[0x0010] = 0x80 + cpu.step() + self.assertEquals(0x0002, cpu.pc) + self.assertEquals(0x80, cpu.a) + self.assertEquals(cpu.NEGATIVE, cpu.flags & cpu.NEGATIVE) + self.assertEquals(0, cpu.flags & cpu.ZERO) + + def test_lda_zp_loads_a_sets_z_flag(self): + cpu = MPU() + cpu.a = 0xFF + cpu.memory[0x0000:0x0002] = (0xA5, 0x10) #=> LDA $0010 + cpu.memory[0x0010] = 0x00 + cpu.step() + self.assertEquals(0x0002, cpu.pc) + self.assertEquals(0x00, cpu.a) + self.assertEquals(cpu.ZERO, cpu.flags & cpu.ZERO) + self.assertEquals(0, cpu.flags & cpu.NEGATIVE) + + # LDA Immediate + + def test_lda_immediate_loads_a_sets_n_flag(self): + cpu = MPU() + cpu.a = 0x00 + cpu.memory[0x0000:0x0002] = (0xA9, 0x80) #=> LDA #$80 + cpu.step() + self.assertEquals(0x0002, cpu.pc) + self.assertEquals(0x80, cpu.a) + self.assertEquals(cpu.NEGATIVE, cpu.flags & cpu.NEGATIVE) + self.assertEquals(0, cpu.flags & cpu.ZERO) + + def test_ldx_immediate_loads_x_sets_z_flag(self): + cpu = MPU() + cpu.a = 0xFF + cpu.memory[0x0000:0x0002] = (0xA2, 0x00) #=> LDA #$00 + cpu.step() + self.assertEquals(0x0002, cpu.pc) + self.assertEquals(0x00, cpu.a) + self.assertEquals(cpu.ZERO, cpu.flags & cpu.ZERO) + self.assertEquals(0, cpu.flags & cpu.NEGATIVE) + + # LDA Absolute, X-Indexed + + def test_lda_absolute_x_indexed_loads_a_sets_n_flag(self): + cpu = MPU() + cpu.a = 0x00 + cpu.x = 0x03 + cpu.memory[0x0000:0x0002] = (0xBD, 0xCD, 0xAB) #=> LDA $ABCD,X + cpu.memory[0xABCD + cpu.x] = 0x80 + cpu.step() + self.assertEquals(0x0003, cpu.pc) + self.assertEquals(0x80, cpu.a) + self.assertEquals(cpu.NEGATIVE, cpu.flags & cpu.NEGATIVE) + self.assertEquals(0, cpu.flags & cpu.ZERO) + + def test_lda_absolute_x_indexed_loads_x_sets_z_flag(self): + cpu = MPU() + cpu.a = 0xFF + cpu.x = 0x03 + cpu.memory[0x0000:0x0002] = (0xBD, 0xCD, 0xAB) #=> LDA $ABCD,X + cpu.memory[0xABCD + cpu.y] = 0x00 + cpu.step() + self.assertEquals(0x0003, cpu.pc) + self.assertEquals(0x00, cpu.a) + self.assertEquals(cpu.ZERO, cpu.flags & cpu.ZERO) + self.assertEquals(0, cpu.flags & cpu.NEGATIVE) + + # LDA Absolute, Y-Indexed + + def test_lda_absolute_y_indexed_loads_a_sets_n_flag(self): + cpu = MPU() + cpu.a = 0x00 + cpu.y = 0x03 + cpu.memory[0x0000:0x0002] = (0xB9, 0xCD, 0xAB) #=> LDA $ABCD,Y + cpu.memory[0xABCD + cpu.y] = 0x80 + cpu.step() + self.assertEquals(0x0003, cpu.pc) + self.assertEquals(0x80, cpu.a) + self.assertEquals(cpu.NEGATIVE, cpu.flags & cpu.NEGATIVE) + self.assertEquals(0, cpu.flags & cpu.ZERO) + + def test_lda_absolute_y_indexed_loads_a_sets_z_flag(self): + cpu = MPU() + cpu.a = 0xFF + cpu.y = 0x03 + cpu.memory[0x0000:0x0002] = (0xB9, 0xCD, 0xAB) #=> LDA $ABCD,Y + cpu.memory[0xABCD + cpu.y] = 0x00 + cpu.step() + self.assertEquals(0x0003, cpu.pc) + self.assertEquals(0x00, cpu.a) + self.assertEquals(cpu.ZERO, cpu.flags & cpu.ZERO) + self.assertEquals(0, cpu.flags & cpu.NEGATIVE) + + # LDA Indirect, Indexed (X) + + def test_lda_indirect_indexed_x_loads_a_sets_n_flag(self): + cpu = MPU() + cpu.a = 0x00 + cpu.x = 0x03 + cpu.memory[0x0000:0x0002] = (0xA1, 0x10) #=> LDA ($0010,X) + cpu.memory[0x0013:0x0014] = (0xCD, 0xAB) #=> Vector to $ABCD + cpu.memory[0xABCD] = 0x80 + cpu.step() + self.assertEquals(0x0002, cpu.pc) + self.assertEquals(0x80, cpu.a) + self.assertEquals(cpu.NEGATIVE, cpu.flags & cpu.NEGATIVE) + self.assertEquals(0, cpu.flags & cpu.ZERO) + + def test_lda_indirect_indexed_x_loads_a_sets_z_flag(self): + cpu = MPU() + cpu.a = 0x00 + cpu.x = 0x03 + cpu.memory[0x0000:0x0002] = (0xA1, 0x10) #=> LDA ($0010,X) + cpu.memory[0x0013:0x0014] = (0xCD, 0xAB) #=> Vector to $ABCD + cpu.memory[0xABCD] = 0x00 + cpu.step() + self.assertEquals(0x0002, cpu.pc) + self.assertEquals(0x00, cpu.a) + self.assertEquals(cpu.ZERO, cpu.flags & cpu.ZERO) + self.assertEquals(0, cpu.flags & cpu.NEGATIVE) + + # LDA Indexed, Indirect (Y) + + def test_lda_indexed_indirect_y_loads_a_sets_n_flag(self): + cpu = MPU() + cpu.a = 0x00 + cpu.y = 0x03 + cpu.memory[0x0000:0x0002] = (0xB1, 0x10) #=> LDA ($0010),Y + cpu.memory[0x0010:0x0011] = (0xCD, 0xAB) #=> Vector to $ABCD + cpu.memory[0xABCD + cpu.y] = 0x80 + cpu.step() + self.assertEquals(0x0002, cpu.pc) + self.assertEquals(0x80, cpu.a) + self.assertEquals(cpu.NEGATIVE, cpu.flags & cpu.NEGATIVE) + self.assertEquals(0, cpu.flags & cpu.ZERO) + + def test_lda_indexed_indirect_y_loads_a_sets_z_flag(self): + cpu = MPU() + cpu.a = 0x00 + cpu.y = 0x03 + cpu.memory[0x0000:0x0002] = (0xB1, 0x10) #=> LDA ($0010),Y + cpu.memory[0x0010:0x0011] = (0xCD, 0xAB) #=> Vector to $ABCD + cpu.memory[0xABCD + cpu.y] = 0x00 + cpu.step() + self.assertEquals(0x0002, cpu.pc) + self.assertEquals(0x00, cpu.a) + self.assertEquals(cpu.ZERO, cpu.flags & cpu.ZERO) + self.assertEquals(0, cpu.flags & cpu.NEGATIVE) + + # LDA Zero Page, X-Indexed + + def test_lda_zp_x_indexed_loads_x_sets_n_flag(self): + cpu = MPU() + cpu.a = 0x00 + cpu.x = 0x03 + cpu.memory[0x0000:0x0001] = (0xB5, 0x10) #=> LDA $0010,X + cpu.memory[0x0010 + cpu.x] = 0x80 + cpu.step() + self.assertEquals(0x0002, cpu.pc) + self.assertEquals(0x80, cpu.a) + self.assertEquals(cpu.NEGATIVE, cpu.flags & cpu.NEGATIVE) + self.assertEquals(0, cpu.flags & cpu.ZERO) + + def test_lda_zp_x_indexed_loads_x_sets_z_flag(self): + cpu = MPU() + cpu.a = 0xFF + cpu.x = 0x03 + cpu.memory[0x0000:0x0002] = (0xB5, 0x10) #=> LDA $0010,X + cpu.memory[0x0010 + cpu.x] = 0x00 + cpu.step() + self.assertEquals(0x0002, cpu.pc) + self.assertEquals(0x00, cpu.a) + self.assertEquals(cpu.ZERO, cpu.flags & cpu.ZERO) + self.assertEquals(0, cpu.flags & cpu.NEGATIVE) + + # LDX Absolute + + def test_ldx_absolute_loads_x_sets_n_flag(self): + cpu = MPU() + cpu.x = 0x00 + cpu.memory[0x0000:0x0002] = (0xAE, 0xCD, 0xAB) #=> LDX $ABCD + cpu.memory[0xABCD] = 0x80 + cpu.step() + self.assertEquals(0x0003, cpu.pc) + self.assertEquals(0x80, cpu.x) + self.assertEquals(cpu.NEGATIVE, cpu.flags & cpu.NEGATIVE) + self.assertEquals(0, cpu.flags & cpu.ZERO) + + def test_ldx_absolute_loads_x_sets_z_flag(self): + cpu = MPU() + cpu.x = 0xFF + cpu.memory[0x0000:0x0002] = (0xAE, 0xCD, 0xAB) #=> LDX $ABCD + cpu.memory[0xABCD] = 0x00 + cpu.step() + self.assertEquals(0x0003, cpu.pc) + self.assertEquals(0x00, cpu.x) + self.assertEquals(cpu.ZERO, cpu.flags & cpu.ZERO) + self.assertEquals(0, cpu.flags & cpu.NEGATIVE) + + # LDX Zero Page + + def test_ldx_zp_loads_x_sets_n_flag(self): + cpu = MPU() + cpu.x = 0x00 + cpu.memory[0x0000:0x0002] = (0xA6, 0x10) #=> LDX $0010 + cpu.memory[0x0010] = 0x80 + cpu.step() + self.assertEquals(0x0002, cpu.pc) + self.assertEquals(0x80, cpu.x) + self.assertEquals(cpu.NEGATIVE, cpu.flags & cpu.NEGATIVE) + self.assertEquals(0, cpu.flags & cpu.ZERO) + + def test_ldx_zp_loads_x_sets_z_flag(self): + cpu = MPU() + cpu.x = 0xFF + cpu.memory[0x0000:0x0002] = (0xA6, 0x10) #=> LDX $0010 + cpu.memory[0x0010] = 0x00 + cpu.step() + self.assertEquals(0x0002, cpu.pc) + self.assertEquals(0x00, cpu.x) + self.assertEquals(cpu.ZERO, cpu.flags & cpu.ZERO) + self.assertEquals(0, cpu.flags & cpu.NEGATIVE) + + # LDX Immediate + + def test_ldx_immediate_loads_x_sets_n_flag(self): + cpu = MPU() + cpu.x = 0x00 + cpu.memory[0x0000:0x0002] = (0xA2, 0x80) #=> LDX #$80 + cpu.step() + self.assertEquals(0x0002, cpu.pc) + self.assertEquals(0x80, cpu.x) + self.assertEquals(cpu.NEGATIVE, cpu.flags & cpu.NEGATIVE) + self.assertEquals(0, cpu.flags & cpu.ZERO) + + def test_ldx_immediate_loads_x_sets_z_flag(self): + cpu = MPU() + cpu.x = 0xFF + cpu.memory[0x0000:0x0002] = (0xA2, 0x00) #=> LDX #$00 + cpu.step() + self.assertEquals(0x0002, cpu.pc) + self.assertEquals(0x00, cpu.x) + self.assertEquals(cpu.ZERO, cpu.flags & cpu.ZERO) + self.assertEquals(0, cpu.flags & cpu.NEGATIVE) + + # LDX Absolute, Y-Indexed + + def test_ldx_absolute_y_indexed_loads_x_sets_n_flag(self): + cpu = MPU() + cpu.x = 0x00 + cpu.y = 0x03 + cpu.memory[0x0000:0x0002] = (0xBE, 0xCD, 0xAB) #=> LDX $ABCD,Y + cpu.memory[0xABCD + cpu.y] = 0x80 + cpu.step() + self.assertEquals(0x0003, cpu.pc) + self.assertEquals(0x80, cpu.x) + self.assertEquals(cpu.NEGATIVE, cpu.flags & cpu.NEGATIVE) + self.assertEquals(0, cpu.flags & cpu.ZERO) + + def test_ldx_absolute_y_indexed_loads_x_sets_z_flag(self): + cpu = MPU() + cpu.x = 0xFF + cpu.y = 0x03 + cpu.memory[0x0000:0x0002] = (0xBE, 0xCD, 0xAB) #=> LDX $ABCD,Y + cpu.memory[0xABCD + cpu.y] = 0x00 + cpu.step() + self.assertEquals(0x0003, cpu.pc) + self.assertEquals(0x00, cpu.x) + self.assertEquals(cpu.ZERO, cpu.flags & cpu.ZERO) + self.assertEquals(0, cpu.flags & cpu.NEGATIVE) + + # LDX Zero Page, Y-Indexed + + def test_ldx_zp_y_indexed_loads_x_sets_n_flag(self): + cpu = MPU() + cpu.x = 0x00 + cpu.y = 0x03 + cpu.memory[0x0000:0x0001] = (0xB6, 0x10) #=> LDX $0010,Y + cpu.memory[0x0010 + cpu.y] = 0x80 + cpu.step() + self.assertEquals(0x0002, cpu.pc) + self.assertEquals(0x80, cpu.x) + self.assertEquals(cpu.NEGATIVE, cpu.flags & cpu.NEGATIVE) + self.assertEquals(0, cpu.flags & cpu.ZERO) + + def test_ldx_zp_y_indexed_loads_x_sets_z_flag(self): + cpu = MPU() + cpu.x = 0xFF + cpu.y = 0x03 + cpu.memory[0x0000:0x0002] = (0xB6, 0x10) #=> LDX $0010,Y + cpu.memory[0x0010 + cpu.y] = 0x00 + cpu.step() + self.assertEquals(0x0002, cpu.pc) + self.assertEquals(0x00, cpu.x) + self.assertEquals(cpu.ZERO, cpu.flags & cpu.ZERO) + self.assertEquals(0, cpu.flags & cpu.NEGATIVE) + + # LDY Absolute + + def test_ldy_absolute_loads_y_sets_n_flag(self): + cpu = MPU() + cpu.y = 0x00 + cpu.memory[0x0000:0x0002] = (0xAC, 0xCD, 0xAB) #=> LDY $ABCD + cpu.memory[0xABCD] = 0x80 + cpu.step() + self.assertEquals(0x0003, cpu.pc) + self.assertEquals(0x80, cpu.y) + self.assertEquals(cpu.NEGATIVE, cpu.flags & cpu.NEGATIVE) + self.assertEquals(0, cpu.flags & cpu.ZERO) + + def test_ldy_absolute_loads_y_sets_z_flag(self): + cpu = MPU() + cpu.y = 0xFF + cpu.memory[0x0000:0x0002] = (0xAC, 0xCD, 0xAB) #=> LDY $ABCD + cpu.memory[0xABCD] = 0x00 + cpu.step() + self.assertEquals(0x0003, cpu.pc) + self.assertEquals(0x00, cpu.y) + self.assertEquals(cpu.ZERO, cpu.flags & cpu.ZERO) + self.assertEquals(0, cpu.flags & cpu.NEGATIVE) + + # LDY Zero Page + + def test_ldy_zp_loads_y_sets_n_flag(self): + cpu = MPU() + cpu.y = 0x00 + cpu.memory[0x0000:0x0002] = (0xA4, 0x10) #=> LDY $0010 + cpu.memory[0x0010] = 0x80 + cpu.step() + self.assertEquals(0x0002, cpu.pc) + self.assertEquals(0x80, cpu.y) + self.assertEquals(cpu.NEGATIVE, cpu.flags & cpu.NEGATIVE) + self.assertEquals(0, cpu.flags & cpu.ZERO) + + def test_ldy_zp_loads_y_sets_z_flag(self): + cpu = MPU() + cpu.y = 0xFF + cpu.memory[0x0000:0x0002] = (0xA4, 0x10) #=> LDY $0010 + cpu.memory[0x0010] = 0x00 + cpu.step() + self.assertEquals(0x0002, cpu.pc) + self.assertEquals(0x00, cpu.y) + self.assertEquals(cpu.ZERO, cpu.flags & cpu.ZERO) + self.assertEquals(0, cpu.flags & cpu.NEGATIVE) + + # LDY Immediate + + def test_ldy_immediate_loads_y_sets_n_flag(self): + cpu = MPU() + cpu.y = 0x00 + cpu.memory[0x0000:0x0002] = (0xA0, 0x80) #=> LDY #$80 + cpu.step() + self.assertEquals(0x0002, cpu.pc) + self.assertEquals(0x80, cpu.y) + self.assertEquals(cpu.NEGATIVE, cpu.flags & cpu.NEGATIVE) + self.assertEquals(0, cpu.flags & cpu.ZERO) + + def test_ldy_immediate_loads_y_sets_z_flag(self): + cpu = MPU() + cpu.y = 0xFF + cpu.memory[0x0000:0x0002] = (0xA0, 0x00) #=> LDY #$00 + cpu.step() + self.assertEquals(0x0002, cpu.pc) + self.assertEquals(0x00, cpu.y) + self.assertEquals(cpu.ZERO, cpu.flags & cpu.ZERO) + self.assertEquals(0, cpu.flags & cpu.NEGATIVE) + + # LDY Absolute, X-Indexed + + def test_ldy_absolute_x_indexed_loads_x_sets_n_flag(self): + cpu = MPU() + cpu.y = 0x00 + cpu.x = 0x03 + cpu.memory[0x0000:0x0002] = (0xBC, 0xCD, 0xAB) #=> LDY $ABCD,X + cpu.memory[0xABCD + cpu.x] = 0x80 + cpu.step() + self.assertEquals(0x0003, cpu.pc) + self.assertEquals(0x80, cpu.y) + self.assertEquals(cpu.NEGATIVE, cpu.flags & cpu.NEGATIVE) + self.assertEquals(0, cpu.flags & cpu.ZERO) + + def test_ldy_absolute_x_indexed_loads_x_sets_z_flag(self): + cpu = MPU() + cpu.y = 0xFF + cpu.x = 0x03 + cpu.memory[0x0000:0x0002] = (0xBC, 0xCD, 0xAB) #=> LDY $ABCD,X + cpu.memory[0xABCD + cpu.x] = 0x00 + cpu.step() + self.assertEquals(0x0003, cpu.pc) + self.assertEquals(0x00, cpu.y) + self.assertEquals(cpu.ZERO, cpu.flags & cpu.ZERO) + self.assertEquals(0, cpu.flags & cpu.NEGATIVE) + + # LDY Zero Page, X-Indexed + + def test_ldy_zp_x_indexed_loads_x_sets_n_flag(self): + cpu = MPU() + cpu.y = 0x00 + cpu.x = 0x03 + cpu.memory[0x0000:0x0001] = (0xB4, 0x10) #=> LDY $0010,X + cpu.memory[0x0010 + cpu.x] = 0x80 + cpu.step() + self.assertEquals(0x0002, cpu.pc) + self.assertEquals(0x80, cpu.y) + self.assertEquals(cpu.NEGATIVE, cpu.flags & cpu.NEGATIVE) + self.assertEquals(0, cpu.flags & cpu.ZERO) + + def test_ldy_zp_x_indexed_loads_x_sets_z_flag(self): + cpu = MPU() + cpu.y = 0xFF + cpu.x = 0x03 + cpu.memory[0x0000:0x0002] = (0xB4, 0x10) #=> LDY $0010,X + cpu.memory[0x0010 + cpu.x] = 0x00 + cpu.step() + self.assertEquals(0x0002, cpu.pc) + self.assertEquals(0x00, cpu.y) + self.assertEquals(cpu.ZERO, cpu.flags & cpu.ZERO) + self.assertEquals(0, cpu.flags & cpu.NEGATIVE) + + # NOP + + def test_nop_does_nothing(self): + cpu = MPU() + cpu.memory[0x0000] = 0xEA #=> NOP + cpu.step() + self.assertEquals(0x0001, cpu.pc) + + # ORA Absolute + + def test_ora_absolute_zeroes_or_zeros_sets_z_flag(self): + cpu = MPU() + cpu.flags &= ~(cpu.ZERO) + cpu.a = 0x00 + cpu.memory[0x0000:0x0001] = (0x0D, 0xCD, 0xAB) #=> ORA $ABCD + cpu.memory[0xABCD] = 0x00 + cpu.step() + self.assertEquals(0x0003, cpu.pc) + self.assertEquals(0x00, cpu.a) + self.assertEquals(cpu.ZERO, cpu.flags & cpu.ZERO) + + def test_ora_absolute_turns_bits_on_sets_n_flag(self): + cpu = MPU() + cpu.flags &= ~(cpu.NEGATIVE) + cpu.a = 0x03 + cpu.memory[0x0000:0x0001] = (0x0D, 0xCD, 0xAB) #=> ORA $ABCD + cpu.memory[0xABCD] = 0x82 + cpu.step() + self.assertEquals(0x0003, cpu.pc) + self.assertEquals(0x83, cpu.a) + self.assertEquals(cpu.NEGATIVE, cpu.flags & cpu.NEGATIVE) + self.assertEquals(0, cpu.flags & cpu.ZERO) + + # ORA Zero Page + + def test_ora_zp_zeroes_or_zeros_sets_z_flag(self): + cpu = MPU() + cpu.flags &= ~(cpu.ZERO) + cpu.a = 0x00 + cpu.memory[0x0000:0x0001] = (0x05, 0x10) #=> ORA $0010 + cpu.memory[0x0010] = 0x00 + cpu.step() + self.assertEquals(0x0002, cpu.pc) + self.assertEquals(0x00, cpu.a) + self.assertEquals(cpu.ZERO, cpu.flags & cpu.ZERO) + + def test_ora_zp_turns_bits_on_sets_n_flag(self): + cpu = MPU() + cpu.flags &= ~(cpu.NEGATIVE) + cpu.a = 0x03 + cpu.memory[0x0000:0x0001] = (0x05, 0x10) #=> ORA $0010 + cpu.memory[0x0010] = 0x82 + cpu.step() + self.assertEquals(0x0002, cpu.pc) + self.assertEquals(0x83, cpu.a) + self.assertEquals(cpu.NEGATIVE, cpu.flags & cpu.NEGATIVE) + self.assertEquals(0, cpu.flags & cpu.ZERO) + + # ORA Immediate + + def test_ora_immediate_zeroes_or_zeros_sets_z_flag(self): + cpu = MPU() + cpu.flags &= ~(cpu.ZERO) + cpu.a = 0x00 + cpu.memory[0x0000:0x0001] = (0x09, 0x00) #=> ORA #$00 + cpu.step() + self.assertEquals(0x0002, cpu.pc) + self.assertEquals(0x00, cpu.a) + self.assertEquals(cpu.ZERO, cpu.flags & cpu.ZERO) + + def test_ora_immediate_turns_bits_on_sets_n_flag(self): + cpu = MPU() + cpu.flags &= ~(cpu.NEGATIVE) + cpu.a = 0x03 + cpu.memory[0x0000:0x0001] = (0x09, 0x82) #=> ORA #$82 + cpu.step() + self.assertEquals(0x0002, cpu.pc) + self.assertEquals(0x83, cpu.a) + self.assertEquals(cpu.NEGATIVE, cpu.flags & cpu.NEGATIVE) + self.assertEquals(0, cpu.flags & cpu.ZERO) + + # ORA Absolute, X + + def test_ora_absolute_x_indexed_zeroes_or_zeros_sets_z_flag(self): + cpu = MPU() + cpu.flags &= ~(cpu.ZERO) + cpu.a = 0x00 + cpu.x = 0x03 + cpu.memory[0x0000:0x0002] = (0x1D, 0xCD, 0xAB) #=> ORA $ABCD,X + cpu.memory[0xABCD + cpu.x] = 0x00 + cpu.step() + self.assertEquals(0x0003, cpu.pc) + self.assertEquals(0x00, cpu.a) + self.assertEquals(cpu.ZERO, cpu.flags & cpu.ZERO) + + def test_ora_absolute_x_indexed_turns_bits_on_sets_n_flag(self): + cpu = MPU() + cpu.flags &= ~(cpu.NEGATIVE) + cpu.a = 0x03 + cpu.x = 0x03 + cpu.memory[0x0000:0x0002] = (0x1D, 0xCD, 0xAB) #=> ORA $ABCD,X + cpu.memory[0xABCD + cpu.x] = 0x82 + cpu.step() + self.assertEquals(0x0003, cpu.pc) + self.assertEquals(0x83, cpu.a) + self.assertEquals(cpu.NEGATIVE, cpu.flags & cpu.NEGATIVE) + self.assertEquals(0, cpu.flags & cpu.ZERO) + + # ORA Absolute, Y + + def test_ora_absolute_y_indexed_zeroes_or_zeros_sets_z_flag(self): + cpu = MPU() + cpu.flags &= ~(cpu.ZERO) + cpu.a = 0x00 + cpu.y = 0x03 + cpu.memory[0x0000:0x0002] = (0x19, 0xCD, 0xAB) #=> ORA $ABCD,Y + cpu.memory[0xABCD + cpu.y] = 0x00 + cpu.step() + self.assertEquals(0x0003, cpu.pc) + self.assertEquals(0x00, cpu.a) + self.assertEquals(cpu.ZERO, cpu.flags & cpu.ZERO) + + def test_ora_absolute_y_indexed_turns_bits_on_sets_n_flag(self): + cpu = MPU() + cpu.flags &= ~(cpu.NEGATIVE) + cpu.a = 0x03 + cpu.y = 0x03 + cpu.memory[0x0000:0x0002] = (0x19, 0xCD, 0xAB) #=> ORA $ABCD,Y + cpu.memory[0xABCD + cpu.y] = 0x82 + cpu.step() + self.assertEquals(0x0003, cpu.pc) + self.assertEquals(0x83, cpu.a) + self.assertEquals(cpu.NEGATIVE, cpu.flags & cpu.NEGATIVE) + self.assertEquals(0, cpu.flags & cpu.ZERO) + + # ORA Indirect, Indexed (X) + + def test_ora_indirect_indexed_x_zeroes_or_zeros_sets_z_flag(self): + cpu = MPU() + cpu.flags &= ~(cpu.ZERO) + cpu.a = 0x00 + cpu.x = 0x03 + cpu.memory[0x0000:0x0001] = (0x01, 0x10) #=> ORA ($0010,X) + cpu.memory[0x0013:0x0014] = (0xCD, 0xAB) #=> Vector to $ABCD + cpu.memory[0xABCD] = 0x00 + cpu.step() + self.assertEquals(0x0002, cpu.pc) + self.assertEquals(0x00, cpu.a) + self.assertEquals(cpu.ZERO, cpu.flags & cpu.ZERO) + + def test_ora_indirect_indexed_x_turns_bits_on_sets_n_flag(self): + cpu = MPU() + cpu.flags &= ~(cpu.NEGATIVE) + cpu.a = 0x03 + cpu.x = 0x03 + cpu.memory[0x0000:0x0001] = (0x01, 0x10) #=> ORA ($ABCD,X) + cpu.memory[0x0013:0x0014] = (0xCD, 0xAB) #=> Vector to $ABCD + cpu.memory[0xABCD] = 0x82 + cpu.step() + self.assertEquals(0x0002, cpu.pc) + self.assertEquals(0x83, cpu.a) + self.assertEquals(cpu.NEGATIVE, cpu.flags & cpu.NEGATIVE) + self.assertEquals(0, cpu.flags & cpu.ZERO) + + # ORA Indexed, Indirect (Y) + + def test_ora_indexed_indirect_y_zeroes_or_zeros_sets_z_flag(self): + cpu = MPU() + cpu.flags &= ~(cpu.ZERO) + cpu.a = 0x00 + cpu.y = 0x03 + cpu.memory[0x0000:0x0001] = (0x11, 0x10) #=> ORA ($0010),Y + cpu.memory[0x0010:0x0011] = (0xCD, 0xAB) #=> Vector to $ABCD + cpu.memory[0xABCD + cpu.y] = 0x00 + cpu.step() + self.assertEquals(0x0002, cpu.pc) + self.assertEquals(0x00, cpu.a) + self.assertEquals(cpu.ZERO, cpu.flags & cpu.ZERO) + + def test_ora_indexed_indirect_y_turns_bits_on_sets_n_flag(self): + cpu = MPU() + cpu.flags &= ~(cpu.NEGATIVE) + cpu.a = 0x03 + cpu.y = 0x03 + cpu.memory[0x0000:0x0001] = (0x11, 0x10) #=> ORA ($0010),Y + cpu.memory[0x0010:0x0011] = (0xCD, 0xAB) #=> Vector to $ABCD + cpu.memory[0xABCD + cpu.y] = 0x82 + cpu.step() + self.assertEquals(0x0002, cpu.pc) + self.assertEquals(0x83, cpu.a) + self.assertEquals(cpu.NEGATIVE, cpu.flags & cpu.NEGATIVE) + self.assertEquals(0, cpu.flags & cpu.ZERO) + + # ORA Zero Page, X + + def test_ora_zp_x_indexed_zeroes_or_zeros_sets_z_flag(self): + cpu = MPU() + cpu.flags &= ~(cpu.ZERO) + cpu.a = 0x00 + cpu.x = 0x03 + cpu.memory[0x0000:0x0001] = (0x15, 0x10) #=> ORA $0010,X + cpu.memory[0x0010 + cpu.x] = 0x00 + cpu.step() + self.assertEquals(0x0002, cpu.pc) + self.assertEquals(0x00, cpu.a) + self.assertEquals(cpu.ZERO, cpu.flags & cpu.ZERO) + + def test_ora_zp_x_indexed_turns_bits_on_sets_n_flag(self): + cpu = MPU() + cpu.flags &= ~(cpu.NEGATIVE) + cpu.a = 0x03 + cpu.x = 0x03 + cpu.memory[0x0000:0x0001] = (0x15, 0x10) #=> ORA $0010,X + cpu.memory[0x0010 + cpu.x] = 0x82 + cpu.step() + self.assertEquals(0x0002, cpu.pc) + self.assertEquals(0x83, cpu.a) + self.assertEquals(cpu.NEGATIVE, cpu.flags & cpu.NEGATIVE) + self.assertEquals(0, cpu.flags & cpu.ZERO) + + # PHA + + def test_pha_pushes_a_and_updates_sp(self): + cpu = MPU() + cpu.a = 0xAB + cpu.memory[0x0000] = 0x48 #=> PHA + cpu.step() + self.assertEquals(0x0001, cpu.pc) + self.assertEquals(0xAB, cpu.a) + self.assertEquals(0xAB, cpu.memory[0x01FF]) + self.assertEquals(0xFE, cpu.sp) + + # PHP + + def test_php_pushes_processor_status_and_updates_sp(self): + cpu = MPU() + flags = (cpu.NEGATIVE | cpu.OVERFLOW | cpu.DECIMAL | cpu.ZERO | cpu.CARRY) + cpu.flags = flags + cpu.memory[0x0000] = 0x08 #=> PHP + cpu.step() + self.assertEquals(0x0001, cpu.pc) + self.assertEquals(flags, cpu.memory[0x1FF]) + self.assertEquals(0xFE, cpu.sp) + + # PLA + + def test_pla_pulls_top_byte_from_stack_into_a_and_updates_sp(self): + cpu = MPU() + cpu.memory[0x0000] = 0x68 #=> PLA + cpu.memory[0x01FF] = 0xAB + cpu.sp = 0xFE + cpu.step() + self.assertEquals(0x0001, cpu.pc) + self.assertEquals(0xAB, cpu.a) + self.assertEquals(0xFF, cpu.sp) + + # PLP + + def test_plp_pulls_top_byte_from_stack_into_flags_and_updates_sp(self): + cpu = MPU() + cpu.memory[0x0000] = 0x28 #=> PLP + cpu.memory[0x01FF] = 0xAB + cpu.sp = 0xFE + cpu.step() + self.assertEquals(0x0001, cpu.pc) + self.assertEquals(0xAB, cpu.flags) + self.assertEquals(0xFF, cpu.sp) + + # ROL Accumulator + + def test_rol_accumulator_zero_and_carry_zero_sets_z_flag(self): + cpu = MPU() + cpu.a = 0x00 + cpu.flags &= ~(cpu.CARRY) + cpu.memory[0x0000] = 0x2A #=> ROL A + cpu.step() + self.assertEquals(0x0001, cpu.pc) + self.assertEquals(0x00, cpu.a) + self.assertEquals(cpu.ZERO, cpu.flags & cpu.ZERO) + self.assertEquals(0, cpu.flags & cpu.NEGATIVE) + + def test_rol_accumulator_zero_and_carry_one_clears_z_flag(self): + cpu = MPU() + cpu.a = 0x00 + cpu.flags |= cpu.CARRY + cpu.memory[0x0000] = 0x2A #=> ROL A + cpu.step() + self.assertEquals(0x0001, cpu.pc) + self.assertEquals(0x01, cpu.a) + self.assertEquals(0, cpu.flags & cpu.ZERO) + self.assertEquals(0, cpu.flags & cpu.NEGATIVE) + + def test_rol_accumulator_sets_n_flag(self): + cpu = MPU() + cpu.a = 0x40 + cpu.flags |= cpu.CARRY + cpu.memory[0x0000] = 0x2A #=> ROL A + cpu.step() + self.assertEquals(0x0001, cpu.pc) + self.assertEquals(0x81, cpu.a) + self.assertEquals(cpu.NEGATIVE, cpu.flags & cpu.NEGATIVE) + self.assertEquals(0, cpu.flags & cpu.ZERO) + + def test_rol_accumulator_shifts_out_zero(self): + cpu = MPU() + cpu.a = 0x7F + cpu.flags &= ~(cpu.CARRY) + cpu.memory[0x0000] = 0x0A #=> ROL A + cpu.step() + self.assertEquals(0x0001, cpu.pc) + self.assertEquals(0xFE, cpu.a) + self.assertEquals(0, cpu.flags & cpu.CARRY) + + def test_rol_accumulator_shifts_out_one(self): + cpu = MPU() + cpu.a = 0xFF + cpu.flags &= ~(cpu.CARRY) + cpu.memory[0x0000] = 0x2A #=> ROL A + cpu.step() + self.assertEquals(0x0001, cpu.pc) + self.assertEquals(0xFE, cpu.a) + self.assertEquals(cpu.CARRY, cpu.flags & cpu.CARRY) + + # ROL Absolute + + def test_rol_absolute_zero_and_carry_zero_sets_z_flag(self): + cpu = MPU() + cpu.flags &= ~(cpu.CARRY) + cpu.memory[0x0000:0x0002] = (0x2E, 0xCD, 0xAB) #=> ROL $ABCD + cpu.memory[0xABCD] = 0x00 + cpu.step() + self.assertEquals(0x0003, cpu.pc) + self.assertEquals(0x00, cpu.memory[0xABCD]) + self.assertEquals(cpu.ZERO, cpu.flags & cpu.ZERO) + self.assertEquals(0, cpu.flags & cpu.NEGATIVE) + + def test_rol_absolute_zero_and_carry_one_clears_z_flag(self): + cpu = MPU() + cpu.a = 0x00 + cpu.flags |= cpu.CARRY + cpu.memory[0x0000:0x0002] = (0x2E, 0xCD, 0xAB) #=> ROL $ABCD + cpu.memory[0xABCD] = 0x00 + cpu.step() + self.assertEquals(0x0003, cpu.pc) + self.assertEquals(0x01, cpu.memory[0xABCD]) + self.assertEquals(0, cpu.flags & cpu.ZERO) + self.assertEquals(0, cpu.flags & cpu.NEGATIVE) + + def test_rol_absolute_sets_n_flag(self): + cpu = MPU() + cpu.flags |= cpu.CARRY + cpu.memory[0x0000:0x0002] = (0x2E, 0xCD, 0xAB) #=> ROL $ABCD + cpu.memory[0xABCD] = 0x40 + cpu.step() + self.assertEquals(0x0003, cpu.pc) + self.assertEquals(0x81, cpu.memory[0xABCD]) + self.assertEquals(cpu.NEGATIVE, cpu.flags & cpu.NEGATIVE) + self.assertEquals(0, cpu.flags & cpu.ZERO) + + def test_rol_absolute_shifts_out_zero(self): + cpu = MPU() + cpu.flags &= ~(cpu.CARRY) + cpu.memory[0x0000:0x0002] = (0x2E, 0xCD, 0xAB) #=> ROL $ABCD + cpu.memory[0xABCD] = 0x7F + cpu.step() + self.assertEquals(0x0003, cpu.pc) + self.assertEquals(0xFE, cpu.memory[0xABCD]) + self.assertEquals(0, cpu.flags & cpu.CARRY) + + def test_rol_absolute_shifts_out_one(self): + cpu = MPU() + cpu.flags &= ~(cpu.CARRY) + cpu.memory[0x0000:0x0002] = (0x2E, 0xCD, 0xAB) #=> ROL $ABCD + cpu.memory[0xABCD] = 0xFF + cpu.step() + self.assertEquals(0x0003, cpu.pc) + self.assertEquals(0xFE, cpu.memory[0xABCD]) + self.assertEquals(cpu.CARRY, cpu.flags & cpu.CARRY) + + # ROL Zero Page + + def test_rol_zp_zero_and_carry_zero_sets_z_flag(self): + cpu = MPU() + cpu.flags &= ~(cpu.CARRY) + cpu.memory[0x0000:0x0001] = (0x26, 0x10) #=> ROL $0010 + cpu.memory[0x0010] = 0x00 + cpu.step() + self.assertEquals(0x0002, cpu.pc) + self.assertEquals(0x00, cpu.memory[0x0010]) + self.assertEquals(cpu.ZERO, cpu.flags & cpu.ZERO) + self.assertEquals(0, cpu.flags & cpu.NEGATIVE) + + def test_rol_zp_zero_and_carry_one_clears_z_flag(self): + cpu = MPU() + cpu.a = 0x00 + cpu.flags |= cpu.CARRY + cpu.memory[0x0000:0x0001] = (0x26, 0x10) #=> ROL $0010 + cpu.memory[0x0010] = 0x00 + cpu.step() + self.assertEquals(0x0002, cpu.pc) + self.assertEquals(0x01, cpu.memory[0x0010]) + self.assertEquals(0, cpu.flags & cpu.ZERO) + self.assertEquals(0, cpu.flags & cpu.NEGATIVE) + + def test_rol_zp_sets_n_flag(self): + cpu = MPU() + cpu.flags |= cpu.CARRY + cpu.memory[0x0000:0x0001] = (0x26, 0x10) #=> ROL $0010 + cpu.memory[0x0010] = 0x40 + cpu.step() + self.assertEquals(0x0002, cpu.pc) + self.assertEquals(0x81, cpu.memory[0x0010]) + self.assertEquals(cpu.NEGATIVE, cpu.flags & cpu.NEGATIVE) + self.assertEquals(0, cpu.flags & cpu.ZERO) + + def test_rol_zp_shifts_out_zero(self): + cpu = MPU() + cpu.flags &= ~(cpu.CARRY) + cpu.memory[0x0000:0x0001] = (0x26, 0x10) #=> ROL $0010 + cpu.memory[0x0010] = 0x7F + cpu.step() + self.assertEquals(0x0002, cpu.pc) + self.assertEquals(0xFE, cpu.memory[0x0010]) + self.assertEquals(0, cpu.flags & cpu.CARRY) + + def test_rol_zp_shifts_out_one(self): + cpu = MPU() + cpu.flags &= ~(cpu.CARRY) + cpu.memory[0x0000:0x0001] = (0x26, 0x10) #=> ROL $0010 + cpu.memory[0x0010] = 0xFF + cpu.step() + self.assertEquals(0x0002, cpu.pc) + self.assertEquals(0xFE, cpu.memory[0x0010]) + self.assertEquals(cpu.CARRY, cpu.flags & cpu.CARRY) + + # ROL Absolute, X-Indexed + + def test_rol_absolute_x_indexed_zero_and_carry_zero_sets_z_flag(self): + cpu = MPU() + cpu.flags &= ~(cpu.CARRY) + cpu.x = 0x03 + cpu.memory[0x0000:0x0002] = (0x3E, 0xCD, 0xAB) #=> ROL $ABCD,X + cpu.memory[0xABCD + cpu.x] = 0x00 + cpu.step() + self.assertEquals(0x0003, cpu.pc) + self.assertEquals(0x00, cpu.memory[0xABCD + cpu.x]) + self.assertEquals(cpu.ZERO, cpu.flags & cpu.ZERO) + self.assertEquals(0, cpu.flags & cpu.NEGATIVE) + + def test_rol_absolute_x_indexed_zero_and_carry_one_clears_z_flag(self): + cpu = MPU() + cpu.x = 0x03 + cpu.flags |= cpu.CARRY + cpu.memory[0x0000:0x0002] = (0x3E, 0xCD, 0xAB) #=> ROL $ABCD,X + cpu.memory[0xABCD + cpu.x] = 0x00 + cpu.step() + self.assertEquals(0x0003, cpu.pc) + self.assertEquals(0x01, cpu.memory[0xABCD + cpu.x]) + self.assertEquals(0, cpu.flags & cpu.ZERO) + self.assertEquals(0, cpu.flags & cpu.NEGATIVE) + + def test_rol_absolute_x_indexed_sets_n_flag(self): + cpu = MPU() + cpu.x = 0x03 + cpu.flags |= cpu.CARRY + cpu.memory[0x0000:0x0002] = (0x3E, 0xCD, 0xAB) #=> ROL $ABCD,X + cpu.memory[0xABCD + cpu.x] = 0x40 + cpu.step() + self.assertEquals(0x0003, cpu.pc) + self.assertEquals(0x81, cpu.memory[0xABCD + cpu.x]) + self.assertEquals(cpu.NEGATIVE, cpu.flags & cpu.NEGATIVE) + self.assertEquals(0, cpu.flags & cpu.ZERO) + + def test_rol_absolute_x_indexed_shifts_out_zero(self): + cpu = MPU() + cpu.x = 0x03 + cpu.flags &= ~(cpu.CARRY) + cpu.memory[0x0000:0x0002] = (0x3E, 0xCD, 0xAB) #=> ROL $ABCD,X + cpu.memory[0xABCD + cpu.x] = 0x7F + cpu.step() + self.assertEquals(0x0003, cpu.pc) + self.assertEquals(0xFE, cpu.memory[0xABCD + cpu.x]) + self.assertEquals(0, cpu.flags & cpu.CARRY) + + def test_rol_absolute_x_indexed_shifts_out_one(self): + cpu = MPU() + cpu.x = 0x03 + cpu.flags &= ~(cpu.CARRY) + cpu.memory[0x0000:0x0002] = (0x3E, 0xCD, 0xAB) #=> ROL $ABCD,X + cpu.memory[0xABCD + cpu.x] = 0xFF + cpu.step() + self.assertEquals(0x0003, cpu.pc) + self.assertEquals(0xFE, cpu.memory[0xABCD + cpu.x]) + self.assertEquals(cpu.CARRY, cpu.flags & cpu.CARRY) + + # ROL Zero Page, X-Indexed + + def test_rol_zp_x_indexed_zero_and_carry_zero_sets_z_flag(self): + cpu = MPU() + cpu.flags &= ~(cpu.CARRY) + cpu.x = 0x03 + cpu.memory[0x0000:0x0001] = (0x36, 0x10) #=> ROL $0010,X + cpu.memory[0x0010 + cpu.x] = 0x00 + cpu.step() + self.assertEquals(0x0002, cpu.pc) + self.assertEquals(0x00, cpu.memory[0x0010 + cpu.x]) + self.assertEquals(cpu.ZERO, cpu.flags & cpu.ZERO) + self.assertEquals(0, cpu.flags & cpu.NEGATIVE) + + def test_rol_zp_x_indexed_zero_and_carry_one_clears_z_flag(self): + cpu = MPU() + cpu.x = 0x03 + cpu.flags |= cpu.CARRY + cpu.memory[0x0000:0x0001] = (0x36, 0x10) #=> ROL $0010,X + cpu.memory[0x0010 + cpu.x] = 0x00 + cpu.step() + self.assertEquals(0x0002, cpu.pc) + self.assertEquals(0x01, cpu.memory[0x0010 + cpu.x]) + self.assertEquals(0, cpu.flags & cpu.ZERO) + self.assertEquals(0, cpu.flags & cpu.NEGATIVE) + + def test_rol_zp_x_indexed_sets_n_flag(self): + cpu = MPU() + cpu.x = 0x03 + cpu.flags |= cpu.CARRY + cpu.memory[0x0000:0x0001] = (0x36, 0x10) #=> ROL $0010,X + cpu.memory[0x0010 + cpu.x] = 0x40 + cpu.step() + self.assertEquals(0x0002, cpu.pc) + self.assertEquals(0x81, cpu.memory[0x0010 + cpu.x]) + self.assertEquals(cpu.NEGATIVE, cpu.flags & cpu.NEGATIVE) + self.assertEquals(0, cpu.flags & cpu.ZERO) + + def test_rol_zp_x_indexed_shifts_out_zero(self): + cpu = MPU() + cpu.x = 0x03 + cpu.flags &= ~(cpu.CARRY) + cpu.memory[0x0000:0x0001] = (0x36, 0x10) #=> ROL $0010,X + cpu.memory[0x0010 + cpu.x] = 0x7F + cpu.step() + self.assertEquals(0x0002, cpu.pc) + self.assertEquals(0xFE, cpu.memory[0x0010 + cpu.x]) + self.assertEquals(0, cpu.flags & cpu.CARRY) + + def test_rol_zp_x_indexed_shifts_out_one(self): + cpu = MPU() + cpu.x = 0x03 + cpu.flags &= ~(cpu.CARRY) + cpu.memory[0x0000:0x0001] = (0x36, 0x10) #=> ROL $0010,X + cpu.memory[0x0010 + cpu.x] = 0xFF + cpu.step() + self.assertEquals(0x0002, cpu.pc) + self.assertEquals(0xFE, cpu.memory[0x0010 + cpu.x]) + self.assertEquals(cpu.CARRY, cpu.flags & cpu.CARRY) + + # ROR Accumulator + + def test_ror_accumulator_zero_and_carry_zero_sets_z_flag(self): + cpu = MPU() + cpu.a = 0x00 + cpu.flags &= ~(cpu.CARRY) + cpu.memory[0x0000] = 0x6A #=> ROR A + cpu.step() + self.assertEquals(0x0001, cpu.pc) + self.assertEquals(0x00, cpu.a) + self.assertEquals(cpu.ZERO, cpu.flags & cpu.ZERO) + self.assertEquals(0, cpu.flags & cpu.NEGATIVE) + + def test_ror_accumulator_zero_and_carry_one_rotates_in_sets_n_flags(self): + cpu = MPU() + cpu.a = 0x00 + cpu.flags |= cpu.CARRY + cpu.memory[0x0000] = 0x6A #=> ROR A + cpu.step() + self.assertEquals(0x0001, cpu.pc) + self.assertEquals(0x80, cpu.a) + self.assertEquals(0, cpu.flags & cpu.ZERO) + self.assertEquals(cpu.NEGATIVE, cpu.flags & cpu.NEGATIVE) + + def test_ror_accumulator_shifts_out_zero(self): + cpu = MPU() + cpu.a = 0x02 + cpu.flags |= cpu.CARRY + cpu.memory[0x0000] = 0x6A #=> ROR A + cpu.step() + self.assertEquals(0x0001, cpu.pc) + self.assertEquals(0x81, cpu.a) + self.assertEquals(0, cpu.flags & cpu.CARRY) + + def test_ror_accumulator_shifts_out_one(self): + cpu = MPU() + cpu.a = 0x03 + cpu.flags |= cpu.CARRY + cpu.memory[0x0000] = 0x6A #=> ROR A + cpu.step() + self.assertEquals(0x0001, cpu.pc) + self.assertEquals(0x81, cpu.a) + self.assertEquals(cpu.CARRY, cpu.flags & cpu.CARRY) + + # ROR Absolute + + def test_ror_absolute_zero_and_carry_zero_sets_z_flag(self): + cpu = MPU() + cpu.flags &= ~(cpu.CARRY) + cpu.memory[0x0000:0x0002] = (0x6E, 0xCD, 0xAB) #=> ROR $ABCD + cpu.memory[0xABCD] = 0x00 + cpu.step() + self.assertEquals(0x0003, cpu.pc) + self.assertEquals(0x00, cpu.memory[0xABCD]) + self.assertEquals(cpu.ZERO, cpu.flags & cpu.ZERO) + self.assertEquals(0, cpu.flags & cpu.NEGATIVE) + + def test_ror_absolute_zero_and_carry_one_rotates_in_sets_n_flags(self): + cpu = MPU() + cpu.flags |= cpu.CARRY + cpu.memory[0x0000:0x0002] = (0x6E, 0xCD, 0xAB) #=> ROR $ABCD + cpu.memory[0xABCD] = 0x00 + cpu.step() + self.assertEquals(0x0003, cpu.pc) + self.assertEquals(0x80, cpu.memory[0xABCD]) + self.assertEquals(0, cpu.flags & cpu.ZERO) + self.assertEquals(cpu.NEGATIVE, cpu.flags & cpu.NEGATIVE) + + def test_ror_absolute_shifts_out_zero(self): + cpu = MPU() + cpu.flags |= cpu.CARRY + cpu.memory[0x0000:0x0002] = (0x6E, 0xCD, 0xAB) #=> ROR $ABCD + cpu.memory[0xABCD] = 0x02 + cpu.step() + self.assertEquals(0x0003, cpu.pc) + self.assertEquals(0x81, cpu.memory[0xABCD]) + self.assertEquals(0, cpu.flags & cpu.CARRY) + + def test_ror_absolute_shifts_out_one(self): + cpu = MPU() + cpu.flags |= cpu.CARRY + cpu.memory[0x0000:0x0002] = (0x6E, 0xCD, 0xAB) #=> ROR $ABCD + cpu.memory[0xABCD] = 0x03 + cpu.step() + self.assertEquals(0x0003, cpu.pc) + self.assertEquals(0x81, cpu.memory[0xABCD]) + self.assertEquals(cpu.CARRY, cpu.flags & cpu.CARRY) + + # ROR Zero Page + + def test_ror_zp_zero_and_carry_zero_sets_z_flag(self): + cpu = MPU() + cpu.flags &= ~(cpu.CARRY) + cpu.memory[0x0000:0x0001] = (0x66, 0x10) #=> ROR $0010 + cpu.memory[0x0010] = 0x00 + cpu.step() + self.assertEquals(0x0002, cpu.pc) + self.assertEquals(0x00, cpu.memory[0x0010]) + self.assertEquals(cpu.ZERO, cpu.flags & cpu.ZERO) + self.assertEquals(0, cpu.flags & cpu.NEGATIVE) + + def test_ror_zp_zero_and_carry_one_rotates_in_sets_n_flags(self): + cpu = MPU() + cpu.flags |= cpu.CARRY + cpu.memory[0x0000:0x0001] = (0x66, 0x10) #=> ROR $0010 + cpu.memory[0x0010] = 0x00 + cpu.step() + self.assertEquals(0x0002, cpu.pc) + self.assertEquals(0x80, cpu.memory[0x0010]) + self.assertEquals(0, cpu.flags & cpu.ZERO) + self.assertEquals(cpu.NEGATIVE, cpu.flags & cpu.NEGATIVE) + + def test_ror_zp_zero_absolute_shifts_out_zero(self): + cpu = MPU() + cpu.flags |= cpu.CARRY + cpu.memory[0x0000:0x0001] = (0x66, 0x10) #=> ROR $0010 + cpu.memory[0x0010] = 0x02 + cpu.step() + self.assertEquals(0x0002, cpu.pc) + self.assertEquals(0x81, cpu.memory[0x0010]) + self.assertEquals(0, cpu.flags & cpu.CARRY) + + def test_ror_zp_shifts_out_one(self): + cpu = MPU() + cpu.flags |= cpu.CARRY + cpu.memory[0x0000:0x0001] = (0x66, 0x10) #=> ROR $0010 + cpu.memory[0x0010] = 0x03 + cpu.step() + self.assertEquals(0x0002, cpu.pc) + self.assertEquals(0x81, cpu.memory[0x0010]) + self.assertEquals(cpu.CARRY, cpu.flags & cpu.CARRY) + + # ROR Absolute, X-Indexed + + def test_ror_absolute_x_indexed_zero_and_carry_zero_sets_z_flag(self): + cpu = MPU() + cpu.x = 0x03 + cpu.flags &= ~(cpu.CARRY) + cpu.memory[0x0000:0x0002] = (0x7E, 0xCD, 0xAB) #=> ROR $ABCD,X + cpu.memory[0xABCD + cpu.x] = 0x00 + cpu.step() + self.assertEquals(0x0003, cpu.pc) + self.assertEquals(0x00, cpu.memory[0xABCD + cpu.x]) + self.assertEquals(cpu.ZERO, cpu.flags & cpu.ZERO) + self.assertEquals(0, cpu.flags & cpu.NEGATIVE) + + def test_ror_absolute_x_indexed_zero_and_carry_one_rotates_in_sets_n_flags(self): + cpu = MPU() + cpu.x = 0x03 + cpu.flags |= cpu.CARRY + cpu.memory[0x0000:0x0002] = (0x7E, 0xCD, 0xAB) #=> ROR $ABCD,X + cpu.memory[0xABCD + cpu.x] = 0x00 + cpu.step() + self.assertEquals(0x0003, cpu.pc) + self.assertEquals(0x80, cpu.memory[0xABCD + cpu.x]) + self.assertEquals(0, cpu.flags & cpu.ZERO) + self.assertEquals(cpu.NEGATIVE, cpu.flags & cpu.NEGATIVE) + + def test_ror_absolute_x_indexed_shifts_out_zero(self): + cpu = MPU() + cpu.x = 0x03 + cpu.flags |= cpu.CARRY + cpu.memory[0x0000:0x0002] = (0x7E, 0xCD, 0xAB) #=> ROR $ABCD,X + cpu.memory[0xABCD + cpu.x] = 0x02 + cpu.step() + self.assertEquals(0x0003, cpu.pc) + self.assertEquals(0x81, cpu.memory[0xABCD + cpu.x]) + self.assertEquals(0, cpu.flags & cpu.CARRY) + + def test_ror_absolute_x_indexed_shifts_out_one(self): + cpu = MPU() + cpu.x = 0x03 + cpu.flags |= cpu.CARRY + cpu.memory[0x0000:0x0002] = (0x7E, 0xCD, 0xAB) #=> ROR $ABCD,X + cpu.memory[0xABCD + cpu.x] = 0x03 + cpu.step() + self.assertEquals(0x0003, cpu.pc) + self.assertEquals(0x81, cpu.memory[0xABCD + cpu.x]) + self.assertEquals(cpu.CARRY, cpu.flags & cpu.CARRY) + + # ROR Zero Page, X-Indexed + + def test_ror_zp_x_indexed_zero_and_carry_zero_sets_z_flag(self): + cpu = MPU() + cpu.x = 0x03 + cpu.flags &= ~(cpu.CARRY) + cpu.memory[0x0000:0x0001] = (0x76, 0x10) #=> ROR $0010,X + cpu.memory[0x0010 + cpu.x] = 0x00 + cpu.step() + self.assertEquals(0x0002, cpu.pc) + self.assertEquals(0x00, cpu.memory[0x0010 + cpu.x]) + self.assertEquals(cpu.ZERO, cpu.flags & cpu.ZERO) + self.assertEquals(0, cpu.flags & cpu.NEGATIVE) + + def test_ror_zp_x_indexed_zero_and_carry_one_rotates_in_sets_n_flags(self): + cpu = MPU() + cpu.x = 0x03 + cpu.flags |= cpu.CARRY + cpu.memory[0x0000:0x0001] = (0x76, 0x10) #=> ROR $0010,X + cpu.memory[0x0010 + cpu.x] = 0x00 + cpu.step() + self.assertEquals(0x0002, cpu.pc) + self.assertEquals(0x80, cpu.memory[0x0010 + cpu.x]) + self.assertEquals(0, cpu.flags & cpu.ZERO) + self.assertEquals(cpu.NEGATIVE, cpu.flags & cpu.NEGATIVE) + + def test_ror_zp_x_indexed_zero_absolute_shifts_out_zero(self): + cpu = MPU() + cpu.x = 0x03 + cpu.flags |= cpu.CARRY + cpu.memory[0x0000:0x0001] = (0x76, 0x10) #=> ROR $0010,X + cpu.memory[0x0010 + cpu.x] = 0x02 + cpu.step() + self.assertEquals(0x0002, cpu.pc) + self.assertEquals(0x81, cpu.memory[0x0010 + cpu.x]) + self.assertEquals(0, cpu.flags & cpu.CARRY) + + def test_ror_zp_x_indexed_shifts_out_one(self): + cpu = MPU() + cpu.x = 0x03 + cpu.flags |= cpu.CARRY + cpu.memory[0x0000:0x0001] = (0x76, 0x10) #=> ROR $0010,X + cpu.memory[0x0010 + cpu.x] = 0x03 + cpu.step() + self.assertEquals(0x0002, cpu.pc) + self.assertEquals(0x81, cpu.memory[0x0010 + cpu.x]) + self.assertEquals(cpu.CARRY, cpu.flags & cpu.CARRY) + + # RTI + + def test_rti_restores_status_register_and_program_counter_and_updates_sp(self): + cpu = MPU() + cpu.memory[0x0000] = 0x40 #=> RTI + cpu.memory[0x01FD:0x01FF] = (0xAB, 0x03, 0xC0) # Status (P), PCL, PCH + cpu.sp = 0xFC + + cpu.step() + self.assertEquals(0xC003, cpu.pc) + self.assertEquals(0xAB, cpu.flags) + self.assertEquals(0xFF, cpu.sp) + + # RTS + + def test_rts_restores_program_counter_and_increments_then_updates_sp(self): + cpu = MPU() + cpu.memory[0x0000] = 0x60 #=> RTS + cpu.memory[0x01FE:0x01FF] = (0x03, 0xC0) # PCL, PCH + cpu.sp = 0xFD + + cpu.step() + self.assertEquals(0xC004, cpu.pc) + self.assertEquals(0xFF, cpu.sp) + + # SEC + + def test_sec_sets_carry_flag(self): + cpu = MPU() + cpu.flags &= ~(cpu.CARRY) + cpu.memory[0x0000] = 0x038 #=> SEC + cpu.step() + self.assertEquals(0x0001, cpu.pc) + self.assertEquals(cpu.CARRY, cpu.flags & cpu.CARRY) + + # SED + + def test_sed_sets_decimal_mode_flag(self): + cpu = MPU() + cpu.flags &= ~(cpu.DECIMAL) + cpu.memory[0x0000] = 0xF8 #=> SED + cpu.step() + self.assertEquals(0x0001, cpu.pc) + self.assertEquals(cpu.DECIMAL, cpu.flags & cpu.DECIMAL) + + # SEI + + def test_sei_sets_interrupt_disable_flag(self): + cpu = MPU() + cpu.flags &= ~(cpu.INTERRUPT) + cpu.memory[0x0000] = 0x78 #=> SEI + cpu.step() + self.assertEquals(0x0001, cpu.pc) + self.assertEquals(cpu.INTERRUPT, cpu.flags & cpu.INTERRUPT) + + # STA Absolute + + def test_sta_absolute_stores_a_leaves_a_and_n_flag_unchanged(self): + cpu = MPU() + cpu.flags = flags = 0xFF & ~(cpu.NEGATIVE) + cpu.a = 0xFF + cpu.memory[0x0000:0x0002] = (0x8D, 0xCD, 0xAB) #=> STA $ABCD + cpu.memory[0xABCD] = 0x00 + cpu.step() + self.assertEquals(0x0003, cpu.pc) + self.assertEquals(0xFF, cpu.memory[0xABCD]) + self.assertEquals(0xFF, cpu.a) + self.assertEquals(flags, cpu.flags) + + def test_sta_absolute_stores_a_leaves_a_and_z_flag_unchanged(self): + cpu = MPU() + cpu.flags = flags = 0xFF & ~(cpu.ZERO) + cpu.a = 0x00 + cpu.memory[0x0000:0x0002] = (0x8D, 0xCD, 0xAB) #=> STA $ABCD + cpu.memory[0xABCD] = 0xFF + cpu.step() + self.assertEquals(0x0003, cpu.pc) + self.assertEquals(0x00, cpu.memory[0xABCD]) + self.assertEquals(0x00, cpu.a) + self.assertEquals(flags, cpu.flags) + + # STA Zero Page + + def test_sta_zp_stores_a_leaves_a_and_n_flag_unchanged(self): + cpu = MPU() + cpu.flags = flags = 0xFF & ~(cpu.NEGATIVE) + cpu.a = 0xFF + cpu.memory[0x0000:0x0001] = (0x85, 0x10) #=> STA $0010 + cpu.memory[0x0010] = 0x00 + cpu.step() + self.assertEquals(0x0002, cpu.pc) + self.assertEquals(0xFF, cpu.memory[0x0010]) + self.assertEquals(0xFF, cpu.a) + self.assertEquals(flags, cpu.flags) + + def test_sta_zp_stores_a_leaves_a_and_z_flag_unchanged(self): + cpu = MPU() + cpu.flags = flags = 0xFF & ~(cpu.ZERO) + cpu.a = 0x00 + cpu.memory[0x0000:0x0001] = (0x85, 0x10) #=> STA $0010 + cpu.memory[0x0010] = 0xFF + cpu.step() + self.assertEquals(0x0002, cpu.pc) + self.assertEquals(0x00, cpu.memory[0x0010]) + self.assertEquals(0x00, cpu.a) + self.assertEquals(flags, cpu.flags) + + # STA Absolute, X-Indexed + + def test_sta_absolute_x_indexed_stores_a_leaves_a_and_n_flag_unchanged(self): + cpu = MPU() + cpu.flags = flags = 0xFF & ~(cpu.NEGATIVE) + cpu.a = 0xFF + cpu.x = 0x03 + cpu.memory[0x0000:0x0002] = (0x9D, 0xCD, 0xAB) #=> STA $ABCD,X + cpu.memory[0xABCD + cpu.x] = 0x00 + cpu.step() + self.assertEquals(0x0003, cpu.pc) + self.assertEquals(0xFF, cpu.memory[0xABCD + cpu.x]) + self.assertEquals(0xFF, cpu.a) + self.assertEquals(flags, cpu.flags) + + def test_sta_absolute_x_indexed_stores_a_leaves_a_and_z_flag_unchanged(self): + cpu = MPU() + cpu.flags = flags = 0xFF & ~(cpu.ZERO) + cpu.a = 0x00 + cpu.x = 0x03 + cpu.memory[0x0000:0x0002] = (0x9D, 0xCD, 0xAB) #=> STA $ABCD,X + cpu.memory[0xABCD + cpu.x] = 0xFF + cpu.step() + self.assertEquals(0x0003, cpu.pc) + self.assertEquals(0x00, cpu.memory[0xABCD + cpu.x]) + self.assertEquals(0x00, cpu.a) + self.assertEquals(flags, cpu.flags) + + # STA Absolute, Y-Indexed + + def test_sta_absolute_y_indexed_stores_a_leaves_a_and_n_flag_unchanged(self): + cpu = MPU() + cpu.flags = flags = 0xFF & ~(cpu.NEGATIVE) + cpu.a = 0xFF + cpu.y = 0x03 + cpu.memory[0x0000:0x0002] = (0x99, 0xCD, 0xAB) #=> STA $ABCD,Y + cpu.memory[0xABCD + cpu.y] = 0x00 + cpu.step() + self.assertEquals(0x0003, cpu.pc) + self.assertEquals(0xFF, cpu.memory[0xABCD + cpu.y]) + self.assertEquals(0xFF, cpu.a) + self.assertEquals(flags, cpu.flags) + + def test_sta_absolute_y_indexed_stores_a_leaves_a_and_z_flag_unchanged(self): + cpu = MPU() + cpu.flags = flags = 0xFF & ~(cpu.ZERO) + cpu.a = 0x00 + cpu.y = 0x03 + cpu.memory[0x0000:0x0002] = (0x99, 0xCD, 0xAB) #=> STA $ABCD,Y + cpu.memory[0xABCD + cpu.y] = 0xFF + cpu.step() + self.assertEquals(0x0003, cpu.pc) + self.assertEquals(0x00, cpu.memory[0xABCD + cpu.y]) + self.assertEquals(0x00, cpu.a) + self.assertEquals(flags, cpu.flags) + + # STA Indirect, Indexed (X) + + def test_sta_indirect_indexed_x_stores_a_leaves_a_and_n_flag_unchanged(self): + cpu = MPU() + cpu.flags = flags = 0xFF & ~(cpu.NEGATIVE) + cpu.a = 0xFF + cpu.x = 0x03 + cpu.memory[0x0000:0x0001] = (0x81, 0x10) #=> STA ($0010,X) + cpu.memory[0x0013:0x0014] = (0xED, 0xFE) #=> Vector to $FEED + cpu.memory[0xFEED] = 0x00 + cpu.step() + self.assertEquals(0x0002, cpu.pc) + self.assertEquals(0xFF, cpu.memory[0xFEED]) + self.assertEquals(0xFF, cpu.a) + self.assertEquals(flags, cpu.flags) + + def test_sta_indirect_indexed_x_stores_a_leaves_a_and_z_flag_unchanged(self): + cpu = MPU() + cpu.flags = flags = 0xFF & ~(cpu.ZERO) + cpu.a = 0x00 + cpu.x = 0x03 + cpu.memory[0x0000:0x0001] = (0x81, 0x10) #=> STA ($0010,X) + cpu.memory[0x0013:0x0014] = (0xED, 0xFE) #=> Vector to $FEED + cpu.memory[0xFEED] = 0xFF + cpu.step() + self.assertEquals(0x0002, cpu.pc) + self.assertEquals(0x00, cpu.memory[0xFEED]) + self.assertEquals(0x00, cpu.a) + self.assertEquals(flags, cpu.flags) + + # STA Indexed, Indirect (Y) + + def test_sta_indexed_indirect_y_stores_a_leaves_a_and_n_flag_unchanged(self): + cpu = MPU() + cpu.flags = flags = 0xFF & ~(cpu.NEGATIVE) + cpu.a = 0xFF + cpu.y = 0x03 + cpu.memory[0x0000:0x0001] = (0x91, 0x10) #=> STA ($0010),Y + cpu.memory[0x0010:0x0011] = (0xED, 0xFE) #=> Vector to $FEED + cpu.memory[0xFEED + cpu.y] = 0x00 + cpu.step() + self.assertEquals(0x0002, cpu.pc) + self.assertEquals(0xFF, cpu.memory[0xFEED + cpu.y]) + self.assertEquals(0xFF, cpu.a) + self.assertEquals(flags, cpu.flags) + + def test_sta_indexed_indirect_y_stores_a_leaves_a_and_z_flag_unchanged(self): + cpu = MPU() + cpu.flags = flags = 0xFF & ~(cpu.ZERO) + cpu.a = 0x00 + cpu.y = 0x03 + cpu.memory[0x0000:0x0001] = (0x91, 0x10) #=> STA ($0010),Y + cpu.memory[0x0010:0x0011] = (0xED, 0xFE) #=> Vector to $FEED + cpu.memory[0xFEED + cpu.y] = 0xFF + cpu.step() + self.assertEquals(0x0002, cpu.pc) + self.assertEquals(0x00, cpu.memory[0xFEED + cpu.y]) + self.assertEquals(0x00, cpu.a) + self.assertEquals(flags, cpu.flags) + + # STA Zero Page, X-Indexed + + def test_sta_zp_x_indexed_stores_a_leaves_a_and_n_flag_unchanged(self): + cpu = MPU() + cpu.flags = flags = 0xFF & ~(cpu.NEGATIVE) + cpu.a = 0xFF + cpu.x = 0x03 + cpu.memory[0x0000:0x0002] = (0x95, 0x10) #=> STA $0010,X + cpu.memory[0x0010 + cpu.x] = 0x00 + cpu.step() + self.assertEquals(0x0002, cpu.pc) + self.assertEquals(0xFF, cpu.memory[0x0010 + cpu.x]) + self.assertEquals(0xFF, cpu.a) + self.assertEquals(flags, cpu.flags) + + def test_sta_zp_x_indexed_stores_a_leaves_a_and_z_flag_unchanged(self): + cpu = MPU() + cpu.flags = flags = 0xFF & ~(cpu.ZERO) + cpu.a = 0x00 + cpu.x = 0x03 + cpu.memory[0x0000:0x0002] = (0x95, 0x10) #=> STA $0010,X + cpu.memory[0x0010 + cpu.x] = 0xFF + cpu.step() + self.assertEquals(0x0002, cpu.pc) + self.assertEquals(0x00, cpu.memory[0x0010 + cpu.x]) + self.assertEquals(0x00, cpu.a) + self.assertEquals(flags, cpu.flags) + + # STX Absolute + + def test_stx_absolute_stores_x_leaves_x_and_n_flag_unchanged(self): + cpu = MPU() + cpu.flags = flags = 0xFF & ~(cpu.NEGATIVE) + cpu.x = 0xFF + cpu.memory[0x0000:0x0002] = (0x8E, 0xCD, 0xAB) #=> STX $ABCD + cpu.memory[0xABCD] = 0x00 + cpu.step() + self.assertEquals(0x0003, cpu.pc) + self.assertEquals(0xFF, cpu.memory[0xABCD]) + self.assertEquals(0xFF, cpu.x) + self.assertEquals(flags, cpu.flags) + + def test_stx_absolute_stores_x_leaves_x_and_z_flag_unchanged(self): + cpu = MPU() + cpu.flags = flags = 0xFF & ~(cpu.ZERO) + cpu.x = 0x00 + cpu.memory[0x0000:0x0002] = (0x8E, 0xCD, 0xAB) #=> STX $ABCD + cpu.memory[0xABCD] = 0xFF + cpu.step() + self.assertEquals(0x0003, cpu.pc) + self.assertEquals(0x00, cpu.memory[0xABCD]) + self.assertEquals(0x00, cpu.x) + self.assertEquals(flags, cpu.flags) + + # STX Zero Page + + def test_stx_zp_stores_x_leaves_x_and_n_flag_unchanged(self): + cpu = MPU() + cpu.flags = flags = 0xFF & ~(cpu.NEGATIVE) + cpu.x = 0xFF + cpu.memory[0x0000:0x0001] = (0x86, 0x10) #=> STX $0010 + cpu.memory[0x0010] = 0x00 + cpu.step() + self.assertEquals(0x0002, cpu.pc) + self.assertEquals(0xFF, cpu.memory[0x0010]) + self.assertEquals(0xFF, cpu.x) + self.assertEquals(flags, cpu.flags) + + def test_stx_zp_stores_x_leaves_x_and_z_flag_unchanged(self): + cpu = MPU() + cpu.flags = flags = 0xFF & ~(cpu.ZERO) + cpu.x = 0x00 + cpu.memory[0x0000:0x0001] = (0x86, 0x10) #=> STX $0010 + cpu.memory[0x0010] = 0xFF + cpu.step() + self.assertEquals(0x0002, cpu.pc) + self.assertEquals(0x00, cpu.memory[0x0010]) + self.assertEquals(0x00, cpu.x) + self.assertEquals(flags, cpu.flags) + + # STX Zero Page, Y-Indexed + + def test_stx_zp_y_indexed_stores_x_leaves_x_and_n_flag_unchanged(self): + cpu = MPU() + cpu.flags = flags = 0xFF & ~(cpu.NEGATIVE) + cpu.x = 0xFF + cpu.y = 0x03 + cpu.memory[0x0000:0x0001] = (0x96, 0x10) #=> STX $0010,Y + cpu.memory[0x0010 + cpu.y] = 0x00 + cpu.step() + self.assertEquals(0x0002, cpu.pc) + self.assertEquals(0xFF, cpu.memory[0x0010 + cpu.y]) + self.assertEquals(0xFF, cpu.x) + self.assertEquals(flags, cpu.flags) + + def test_stx_zp_y_indexed_stores_x_leaves_x_and_z_flag_unchanged(self): + cpu = MPU() + cpu.flags = flags = 0xFF & ~(cpu.ZERO) + cpu.x = 0x00 + cpu.y = 0x03 + cpu.memory[0x0000:0x0001] = (0x96, 0x10) #=> STX $0010,Y + cpu.memory[0x0010 + cpu.y] = 0xFF + cpu.step() + self.assertEquals(0x0002, cpu.pc) + self.assertEquals(0x00, cpu.memory[0x0010 + cpu.y]) + self.assertEquals(0x00, cpu.x) + self.assertEquals(flags, cpu.flags) + + # STY Absolute + + def test_sty_absolute_stores_y_leaves_y_and_n_flag_unchanged(self): + cpu = MPU() + cpu.flags = flags = 0xFF & ~(cpu.NEGATIVE) + cpu.y = 0xFF + cpu.memory[0x0000:0x0002] = (0x8C, 0xCD, 0xAB) #=> STY $ABCD + cpu.memory[0xABCD] = 0x00 + cpu.step() + self.assertEquals(0x0003, cpu.pc) + self.assertEquals(0xFF, cpu.memory[0xABCD]) + self.assertEquals(0xFF, cpu.y) + self.assertEquals(flags, cpu.flags) + + def test_sty_absolute_stores_y_leaves_y_and_z_flag_unchanged(self): + cpu = MPU() + cpu.flags = flags = 0xFF & ~(cpu.ZERO) + cpu.y = 0x00 + cpu.memory[0x0000:0x0002] = (0x8C, 0xCD, 0xAB) #=> STY $ABCD + cpu.memory[0xABCD] = 0xFF + cpu.step() + self.assertEquals(0x0003, cpu.pc) + self.assertEquals(0x00, cpu.memory[0xABCD]) + self.assertEquals(0x00, cpu.y) + self.assertEquals(flags, cpu.flags) + + # STY Zero Page + + def test_sty_zp_stores_y_leaves_y_and_n_flag_unchanged(self): + cpu = MPU() + cpu.flags = flags = 0xFF & ~(cpu.NEGATIVE) + cpu.y = 0xFF + cpu.memory[0x0000:0x0001] = (0x84, 0x10) #=> STY $0010 + cpu.memory[0x0010] = 0x00 + cpu.step() + self.assertEquals(0x0002, cpu.pc) + self.assertEquals(0xFF, cpu.memory[0x0010]) + self.assertEquals(0xFF, cpu.y) + self.assertEquals(flags, cpu.flags) + + def test_sty_zp_stores_y_leaves_y_and_z_flag_unchanged(self): + cpu = MPU() + cpu.flags = flags = 0xFF & ~(cpu.ZERO) + cpu.y = 0x00 + cpu.memory[0x0000:0x0001] = (0x84, 0x10) #=> STY $0010 + cpu.memory[0x0010] = 0xFF + cpu.step() + self.assertEquals(0x0002, cpu.pc) + self.assertEquals(0x00, cpu.memory[0x0010]) + self.assertEquals(0x00, cpu.y) + self.assertEquals(flags, cpu.flags) + + # STY Zero Page, X-Indexed + + def test_sty_zp_x_indexed_stores_y_leaves_y_and_n_flag_unchanged(self): + cpu = MPU() + cpu.flags = flags = 0xFF & ~(cpu.NEGATIVE) + cpu.y = 0xFF + cpu.x = 0x03 + cpu.memory[0x0000:0x0001] = (0x94, 0x10) #=> STY $0010,X + cpu.memory[0x0010 + cpu.x] = 0x00 + cpu.step() + self.assertEquals(0x0002, cpu.pc) + self.assertEquals(0xFF, cpu.memory[0x0010 + cpu.x]) + self.assertEquals(0xFF, cpu.y) + self.assertEquals(flags, cpu.flags) + + def test_sty_zp_x_indexed_stores_y_leaves_y_and_z_flag_unchanged(self): + cpu = MPU() + cpu.flags = flags = 0xFF & ~(cpu.ZERO) + cpu.y = 0x00 + cpu.x = 0x03 + cpu.memory[0x0000:0x0001] = (0x94, 0x10) #=> STY $0010,X + cpu.memory[0x0010 + cpu.x] = 0xFF + cpu.step() + self.assertEquals(0x0002, cpu.pc) + self.assertEquals(0x00, cpu.memory[0x0010 + cpu.x]) + self.assertEquals(0x00, cpu.y) + self.assertEquals(flags, cpu.flags) + + # TAX + + def test_tax_transfers_accumulator_into_x(self): + cpu = MPU() + cpu.a = 0xAB + cpu.x = 0x00 + cpu.memory[0x0000] = 0xAA #=> TAX + cpu.step() + self.assertEquals(0x0001, cpu.pc) + self.assertEquals(0xAB, cpu.a) + self.assertEquals(0xAB, cpu.x) + + def test_tax_sets_negative_flag(self): + cpu = MPU() + cpu.flags &= ~(cpu.NEGATIVE) + cpu.a = 0x80 + cpu.x = 0x00 + cpu.memory[0x0000] = 0xAA #=> TAX + cpu.step() + self.assertEquals(0x0001, cpu.pc) + self.assertEquals(0x80, cpu.a) + self.assertEquals(0x80, cpu.x) + self.assertEquals(cpu.NEGATIVE, cpu.flags & cpu.NEGATIVE) + + def test_tax_sets_zero_flag(self): + cpu = MPU() + cpu.flags &= ~(cpu.ZERO) + cpu.a = 0x00 + cpu.x = 0xFF + cpu.memory[0x0000] = 0xAA #=> TAX + cpu.step() + self.assertEquals(0x0001, cpu.pc) + self.assertEquals(0x00, cpu.a) + self.assertEquals(0x00, cpu.x) + self.assertEquals(cpu.ZERO, cpu.flags & cpu.ZERO) + + # TAY + + def test_tay_transfers_accumulator_into_y(self): + cpu = MPU() + cpu.a = 0xAB + cpu.y = 0x00 + cpu.memory[0x0000] = 0xA8 #=> TAY + cpu.step() + self.assertEquals(0x0001, cpu.pc) + self.assertEquals(0xAB, cpu.a) + self.assertEquals(0xAB, cpu.y) + + def test_tay_sets_negative_flag(self): + cpu = MPU() + cpu.flags &= ~(cpu.NEGATIVE) + cpu.a = 0x80 + cpu.y = 0x00 + cpu.memory[0x0000] = 0xA8 #=> TAY + cpu.step() + self.assertEquals(0x0001, cpu.pc) + self.assertEquals(0x80, cpu.a) + self.assertEquals(0x80, cpu.y) + self.assertEquals(cpu.NEGATIVE, cpu.flags & cpu.NEGATIVE) + + def test_tay_sets_zero_flag(self): + cpu = MPU() + cpu.flags &= ~(cpu.ZERO) + cpu.a = 0x00 + cpu.y = 0xFF + cpu.memory[0x0000] = 0xA8 #=> TAY + cpu.step() + self.assertEquals(0x0001, cpu.pc) + self.assertEquals(0x00, cpu.a) + self.assertEquals(0x00, cpu.y) + self.assertEquals(cpu.ZERO, cpu.flags & cpu.ZERO) + + # TSX + + def test_tsx_transfers_stack_pointer_into_x(self): + cpu = MPU() + cpu.sp = 0xAB + cpu.x = 0x00 + cpu.memory[0x0000] = 0xBA #=> TSX + cpu.step() + self.assertEquals(0x0001, cpu.pc) + self.assertEquals(0xAB, cpu.sp) + self.assertEquals(0xAB, cpu.x) + + def test_tsx_sets_negative_flag(self): + cpu = MPU() + cpu.flags &= ~(cpu.NEGATIVE) + cpu.sp = 0x80 + cpu.x = 0x00 + cpu.memory[0x0000] = 0xBA #=> TSX + cpu.step() + self.assertEquals(0x0001, cpu.pc) + self.assertEquals(0x80, cpu.sp) + self.assertEquals(0x80, cpu.x) + self.assertEquals(cpu.NEGATIVE, cpu.flags & cpu.NEGATIVE) + + def test_tsx_sets_zero_flag(self): + cpu = MPU() + cpu.flags &= ~(cpu.ZERO) + cpu.sp = 0x00 + cpu.y = 0xFF + cpu.memory[0x0000] = 0xBA #=> TSX + cpu.step() + self.assertEquals(0x0001, cpu.pc) + self.assertEquals(0x00, cpu.sp) + self.assertEquals(0x00, cpu.x) + self.assertEquals(cpu.ZERO, cpu.flags & cpu.ZERO) + + # TXA + + def test_txa_transfers_x_into_a(self): + cpu = MPU() + cpu.x = 0xAB + cpu.a = 0x00 + cpu.memory[0x0000] = 0x8A #=> TXA + cpu.step() + self.assertEquals(0x0001, cpu.pc) + self.assertEquals(0xAB, cpu.a) + self.assertEquals(0xAB, cpu.x) + + def test_txa_sets_negative_flag(self): + cpu = MPU() + cpu.flags &= ~(cpu.NEGATIVE) + cpu.x = 0x80 + cpu.a = 0x00 + cpu.memory[0x0000] = 0x8A #=> TXA + cpu.step() + self.assertEquals(0x0001, cpu.pc) + self.assertEquals(0x80, cpu.a) + self.assertEquals(0x80, cpu.x) + self.assertEquals(cpu.NEGATIVE, cpu.flags & cpu.NEGATIVE) + + def test_txa_sets_zero_flag(self): + cpu = MPU() + cpu.flags &= ~(cpu.ZERO) + cpu.x = 0x00 + cpu.a = 0xFF + cpu.memory[0x0000] = 0x8A #=> TXA + cpu.step() + self.assertEquals(0x0001, cpu.pc) + self.assertEquals(0x00, cpu.a) + self.assertEquals(0x00, cpu.x) + self.assertEquals(cpu.ZERO, cpu.flags & cpu.ZERO) + + # TXS + + def test_txs_transfers_x_into_stack_pointer(self): + cpu = MPU() + cpu.x = 0xAB + cpu.memory[0x0000] = 0x9A #=> TXS + cpu.step() + self.assertEquals(0x0001, cpu.pc) + self.assertEquals(0xAB, cpu.sp) + self.assertEquals(0xAB, cpu.x) + + def test_txs_does_not_set_negative_flag(self): + cpu = MPU() + cpu.flags &= ~(cpu.NEGATIVE) + cpu.x = 0x80 + cpu.memory[0x0000] = 0x9A #=> TXS + cpu.step() + self.assertEquals(0x0001, cpu.pc) + self.assertEquals(0x80, cpu.sp) + self.assertEquals(0x80, cpu.x) + self.assertEquals(0, cpu.flags & cpu.NEGATIVE) + + def test_txs_does_not_set_zero_flag(self): + cpu = MPU() + cpu.flags &= ~(cpu.ZERO) + cpu.x = 0x00 + cpu.memory[0x0000] = 0x9A #=> TXS + cpu.step() + self.assertEquals(0x0001, cpu.pc) + self.assertEquals(0x00, cpu.sp) + self.assertEquals(0x00, cpu.x) + self.assertEquals(0, cpu.flags & cpu.ZERO) + + # TYA + + def test_tya_transfers_y_into_a(self): + cpu = MPU() + cpu.y = 0xAB + cpu.a = 0x00 + cpu.memory[0x0000] = 0x98 #=> TYA + cpu.step() + self.assertEquals(0x0001, cpu.pc) + self.assertEquals(0xAB, cpu.a) + self.assertEquals(0xAB, cpu.y) + + def test_tya_sets_negative_flag(self): + cpu = MPU() + cpu.flags &= ~(cpu.NEGATIVE) + cpu.y = 0x80 + cpu.a = 0x00 + cpu.memory[0x0000] = 0x98 #=> TYA + cpu.step() + self.assertEquals(0x0001, cpu.pc) + self.assertEquals(0x80, cpu.a) + self.assertEquals(0x80, cpu.y) + self.assertEquals(cpu.NEGATIVE, cpu.flags & cpu.NEGATIVE) + + def test_tya_sets_zero_flag(self): + cpu = MPU() + cpu.flags &= ~(cpu.ZERO) + cpu.y = 0x00 + cpu.a = 0xFF + cpu.memory[0x0000] = 0x98 #=> TYA + cpu.step() + self.assertEquals(0x00, cpu.a) + self.assertEquals(0x00, cpu.y) + self.assertEquals(cpu.ZERO, cpu.flags & cpu.ZERO) + self.assertEquals(0x0001, cpu.pc) + + + +def test_suite(): + return unittest.findTestCases(sys.modules[__name__]) + +if __name__ == '__main__': + unittest.main(defaultTest='test_suite')