From 0245f2a195612b4c53b0b27c4bdf1da722d02260 Mon Sep 17 00:00:00 2001 From: Mike Naberezny Date: Tue, 1 Jul 2008 00:24:18 +0000 Subject: [PATCH] Initial import. --- TODO.txt | 10 + cpu.py | 1234 +++++++++++++++++++ cpu.pyc | Bin 0 -> 42069 bytes cpu_test.py | 3251 +++++++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 4495 insertions(+) create mode 100644 TODO.txt create mode 100644 cpu.py create mode 100644 cpu.pyc create mode 100644 cpu_test.py diff --git a/TODO.txt b/TODO.txt new file mode 100644 index 0000000..2a53bbf --- /dev/null +++ b/TODO.txt @@ -0,0 +1,10 @@ +Instructions needing unit tests: + bit + cmp + cpx + cpy + dec + eor + inc + lsr + sbc diff --git a/cpu.py b/cpu.py new file mode 100644 index 0000000..afb94f5 --- /dev/null +++ b/cpu.py @@ -0,0 +1,1234 @@ +class CPU: + # 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/cpu.pyc b/cpu.pyc new file mode 100644 index 0000000000000000000000000000000000000000..f15593a288284edffc57119b6b17c8a572628570 GIT binary patch literal 42069 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 literal 0 HcmV?d00001 diff --git a/cpu_test.py b/cpu_test.py new file mode 100644 index 0000000..67fbf4c --- /dev/null +++ b/cpu_test.py @@ -0,0 +1,3251 @@ +import unittest +import sys +from cpu import CPU + +class CPUTests(unittest.TestCase): + + # ADC Absolute + + def test_adc_bcd_off_absolute_carry_clear_in_accumulator_zeroes(self): + cpu = CPU() + 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 = CPU() + 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 = CPU() + 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 = CPU() + 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 = CPU() + 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 = CPU() + 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 = CPU() + 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 = CPU() + 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 = CPU() + 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 = CPU() + 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 = CPU() + 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 = CPU() + 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 = CPU() + 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 = CPU() + 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 = CPU() + 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 = CPU() + 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 = CPU() + 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 = CPU() + 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 = CPU() + 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 = CPU() + 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 = CPU() + 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 = CPU() + 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 = CPU() + 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 = CPU() + 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 = CPU() + 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 = CPU() + 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 = CPU() + 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 = CPU() + 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 = CPU() + 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 = CPU() + 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 = CPU() + 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 = CPU() + 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 = CPU() + 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 = CPU() + 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 = CPU() + 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 = CPU() + 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 = CPU() + 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 = CPU() + 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 = CPU() + 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 = CPU() + 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 = CPU() + 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 = CPU() + 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 = CPU() + 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 = CPU() + 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 = CPU() + 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 = CPU() + 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 = CPU() + 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 = CPU() + 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 = CPU() + 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 = CPU() + 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 = CPU() + 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 = CPU() + 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 = CPU() + 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 = CPU() + 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 = CPU() + 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 = CPU() + 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 = CPU() + 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 = CPU() + 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 = CPU() + 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 = CPU() + 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 = CPU() + 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 = CPU() + 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 = CPU() + 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 = CPU() + 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 = CPU() + 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 = CPU() + 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 = CPU() + 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 = CPU() + 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 = CPU() + 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 = CPU() + 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 = CPU() + 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 = CPU() + 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 = CPU() + 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 = CPU() + 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 = CPU() + 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 = CPU() + 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 = CPU() + 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 = CPU() + 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 = CPU() + 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 = CPU() + 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 = CPU() + 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 = CPU() + 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 = CPU() + 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 = CPU() + 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 = CPU() + 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 = CPU() + 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 = CPU() + 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 = CPU() + 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 = CPU() + 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 = CPU() + 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 = CPU() + 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 = CPU() + 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 = CPU() + 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 = CPU() + 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 = CPU() + 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 = CPU() + 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 = CPU() + 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 = CPU() + 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 = CPU() + 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 = CPU() + 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 = CPU() + 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 = CPU() + 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 = CPU() + 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 = CPU() + 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 = CPU() + 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 = CPU() + 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 = CPU() + 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 = CPU() + 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 = CPU() + 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 = CPU() + 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 = CPU() + 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 = CPU() + 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 = CPU() + 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 = CPU() + 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 = CPU() + 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 = CPU() + 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 = CPU() + 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 = CPU() + 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 = CPU() + 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 = CPU() + 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 = CPU() + 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 = CPU() + 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 = CPU() + 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 = CPU() + 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 = CPU() + 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 = CPU() + 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 = CPU() + 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 = CPU() + 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 = CPU() + 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 = CPU() + 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 = CPU() + 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 = CPU() + 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 = CPU() + 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 = CPU() + 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 = CPU() + 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 = CPU() + 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 = CPU() + 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 = CPU() + 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 = CPU() + 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 = CPU() + 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 = CPU() + 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 = CPU() + 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 = CPU() + 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 = CPU() + 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 = CPU() + 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 = CPU() + 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 = CPU() + 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 = CPU() + 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 = CPU() + 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 = CPU() + 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 = CPU() + 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 = CPU() + 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 = CPU() + 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 = CPU() + 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 = CPU() + 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 = CPU() + 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 = CPU() + 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 = CPU() + 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 = CPU() + 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 = CPU() + 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 = CPU() + 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 = CPU() + 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 = CPU() + 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 = CPU() + 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 = CPU() + 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 = CPU() + 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 = CPU() + 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 = CPU() + 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 = CPU() + 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 = CPU() + 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 = CPU() + 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 = CPU() + 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 = CPU() + 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 = CPU() + 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 = CPU() + 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 = CPU() + 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 = CPU() + 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 = CPU() + 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 = CPU() + 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 = CPU() + 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 = CPU() + 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 = CPU() + 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 = CPU() + 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 = CPU() + 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 = CPU() + 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 = CPU() + 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 = CPU() + 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 = CPU() + 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 = CPU() + 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 = CPU() + 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 = CPU() + 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 = CPU() + 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 = CPU() + 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 = CPU() + 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 = CPU() + 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 = CPU() + 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 = CPU() + 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 = CPU() + 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 = CPU() + 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 = CPU() + 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 = CPU() + 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 = CPU() + 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 = CPU() + 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 = CPU() + 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 = CPU() + 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 = CPU() + 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 = CPU() + 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 = CPU() + 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 = CPU() + 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 = CPU() + 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 = CPU() + 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 = CPU() + 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 = CPU() + 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 = CPU() + 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 = CPU() + 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 = CPU() + 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 = CPU() + 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 = CPU() + 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 = CPU() + 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 = CPU() + 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 = CPU() + 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 = CPU() + 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 = CPU() + 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 = CPU() + 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 = CPU() + 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 = CPU() + 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 = CPU() + 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 = CPU() + 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 = CPU() + 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 = CPU() + 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 = CPU() + 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 = CPU() + 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 = CPU() + 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 = CPU() + 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 = CPU() + 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 = CPU() + 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 = CPU() + 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 = CPU() + 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 = CPU() + 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 = CPU() + 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 = CPU() + 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 = CPU() + 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 = CPU() + 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 = CPU() + 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 = CPU() + 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 = CPU() + 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 = CPU() + 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 = CPU() + 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 = CPU() + 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 = CPU() + 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 = CPU() + 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 = CPU() + 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 = CPU() + 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 = CPU() + 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 = CPU() + 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 = CPU() + 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 = CPU() + 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 = CPU() + 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 = CPU() + 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 = CPU() + 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 = CPU() + 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 = CPU() + 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 = CPU() + 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 = CPU() + 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 = CPU() + 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 = CPU() + 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 = CPU() + 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 = CPU() + 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 = CPU() + 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 = CPU() + 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 = CPU() + 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 = CPU() + 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 = CPU() + 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')