mirror of
https://github.com/mnaberez/py65.git
synced 2024-10-31 22:06:12 +00:00
Test cases pass except for devices/65C02_extended_opcodes_test_modified.bin
This commit is contained in:
parent
8b9cf7db69
commit
254b2fb167
@ -1,3 +1,5 @@
|
||||
import sys
|
||||
|
||||
from py65.utils.conversions import itoa
|
||||
from py65.utils.devices import make_instruction_decorator
|
||||
from py65 import disassembler
|
||||
@ -60,8 +62,9 @@ class MPU:
|
||||
def step(self, trace=False):
|
||||
instructCode = self.memory[self.pc]
|
||||
if trace:
|
||||
print self, "$%04X: %s" % (
|
||||
out = str(self) + " $%04X: %s" % (
|
||||
self.pc, self.disassembler.instruction_at(self.pc)[1])
|
||||
print >> sys.stderr, "\n".join(out.split('\n'))
|
||||
self.pc = (self.pc + 1) & self.addrMask
|
||||
self.excycles = 0
|
||||
self.addcycles = self.extracycles[instructCode]
|
||||
@ -296,6 +299,9 @@ class MPU:
|
||||
self.FlagsNZ(self.a)
|
||||
|
||||
def opADC(self, x):
|
||||
return self._opADC(x, flags_use_adjusted_result=False)
|
||||
|
||||
def _opADC(self, x, flags_use_adjusted_result):
|
||||
data = self.ByteAt(x())
|
||||
|
||||
if self.p & self.DECIMAL:
|
||||
@ -315,24 +321,35 @@ class MPU:
|
||||
# the ALU outputs are not decimally adjusted
|
||||
nibble0 = nibble0 & 0xf
|
||||
nibble1 = nibble1 & 0xf
|
||||
aluresult = (nibble1 << 4) + nibble0
|
||||
|
||||
# the final A contents will be decimally adjusted
|
||||
nibble0 = (nibble0 + adjust0) & 0xf
|
||||
nibble1 = (nibble1 + adjust1) & 0xf
|
||||
adjresult = (nibble1 << 4) + nibble0
|
||||
|
||||
# Update result for use in setting flags below
|
||||
aluresult = (nibble1 << 4) + nibble0
|
||||
|
||||
self.p &= ~(self.CARRY | self.OVERFLOW | self.NEGATIVE | self.ZERO)
|
||||
if aluresult == 0:
|
||||
self.p |= self.ZERO
|
||||
|
||||
if flags_use_adjusted_result: # 65C02 and 65816
|
||||
if adjresult == 0:
|
||||
self.p |= self.ZERO
|
||||
else:
|
||||
self.p |= adjresult & self.NEGATIVE
|
||||
if decimalcarry == 1:
|
||||
self.p |= self.CARRY
|
||||
if (~(self.a ^ data) & (self.a ^ aluresult)) & self.NEGATIVE:
|
||||
self.p |= self.OVERFLOW
|
||||
else:
|
||||
self.p |= aluresult & self.NEGATIVE
|
||||
if decimalcarry == 1:
|
||||
self.p |= self.CARRY
|
||||
if (~(self.a ^ data) & (self.a ^ aluresult)) & self.NEGATIVE:
|
||||
self.p |= self.OVERFLOW
|
||||
self.a = (nibble1 << 4) + nibble0
|
||||
if aluresult == 0:
|
||||
self.p |= self.ZERO
|
||||
else:
|
||||
self.p |= aluresult & self.NEGATIVE
|
||||
if decimalcarry == 1:
|
||||
self.p |= self.CARRY
|
||||
if (~(self.a ^ data) & (self.a ^ aluresult)) & self.NEGATIVE:
|
||||
self.p |= self.OVERFLOW
|
||||
|
||||
self.a = adjresult
|
||||
else:
|
||||
if self.p & self.CARRY:
|
||||
tmp = 1
|
||||
@ -395,59 +412,70 @@ class MPU:
|
||||
self.p |= (register_value - tbyte) & self.NEGATIVE
|
||||
|
||||
def opSBC(self, x):
|
||||
if self.p & self.DECIMAL:
|
||||
self._opSBCDecimal(x)
|
||||
return
|
||||
|
||||
data = self.ByteAt(x())
|
||||
|
||||
if self.p & self.DECIMAL:
|
||||
halfcarry = 1
|
||||
decimalcarry = 0
|
||||
adjust0 = 0
|
||||
adjust1 = 0
|
||||
result = self.a + (~data & self.byteMask) + (self.p & self.CARRY)
|
||||
self.p &= ~(self.CARRY | self.ZERO | self.OVERFLOW | self.NEGATIVE)
|
||||
if ((self.a ^ data) & (self.a ^ result)) & self.NEGATIVE:
|
||||
self.p |= self.OVERFLOW
|
||||
data = result & self.byteMask
|
||||
if data == 0:
|
||||
self.p |= self.ZERO
|
||||
if result > self.byteMask:
|
||||
self.p |= self.CARRY
|
||||
self.p |= data & self.NEGATIVE
|
||||
self.a = data
|
||||
|
||||
nibble0 = (self.a & 0xf) + (~data & 0xf) + (self.p & self.CARRY)
|
||||
if nibble0 <= 0xf:
|
||||
halfcarry = 0
|
||||
adjust0 = 10
|
||||
nibble1 = ((self.a >> 4) & 0xf) + ((~data >> 4) & 0xf) + halfcarry
|
||||
if nibble1 <= 0xf:
|
||||
adjust1 = 10 << 4
|
||||
def _opSBCDecimal(self, x):
|
||||
"""SBC opcode in BCD mode.
|
||||
|
||||
# the ALU outputs are not decimally adjusted
|
||||
aluresult = self.a + (~data & self.byteMask) + \
|
||||
(self.p & self.CARRY)
|
||||
This is sufficiently different on 6502 and 65C02 to warrant a separate
|
||||
implementation, see e.g. http://6502.org/tutorials/decimal_mode.html#A
|
||||
"""
|
||||
data = self.ByteAt(x())
|
||||
|
||||
if aluresult > self.byteMask:
|
||||
decimalcarry = 1
|
||||
aluresult &= self.byteMask
|
||||
halfcarry = 1
|
||||
decimalcarry = 0
|
||||
adjust0 = 0
|
||||
adjust1 = 0
|
||||
|
||||
# but the final result will be adjusted
|
||||
nibble0 = (aluresult + adjust0) & 0xf
|
||||
nibble1 = ((aluresult + adjust1) >> 4) & 0xf
|
||||
nibble0 = (self.a & 0xf) + (~data & 0xf) + (self.p & self.CARRY)
|
||||
if nibble0 <= 0xf:
|
||||
halfcarry = 0
|
||||
adjust0 = 10
|
||||
nibble1 = ((self.a >> 4) & 0xf) + ((~data >> 4) & 0xf) + halfcarry
|
||||
if nibble1 <= 0xf:
|
||||
adjust1 = 10 << 4
|
||||
|
||||
# Update result for use in setting flags below
|
||||
aluresult = (nibble1 << 4) + nibble0
|
||||
# the ALU outputs are not decimally adjusted
|
||||
aluresult = self.a + (~data & self.byteMask) + \
|
||||
(self.p & self.CARRY)
|
||||
|
||||
self.p &= ~(self.CARRY | self.ZERO | self.NEGATIVE | self.OVERFLOW)
|
||||
if aluresult == 0:
|
||||
self.p |= self.ZERO
|
||||
else:
|
||||
self.p |= aluresult & self.NEGATIVE
|
||||
if decimalcarry == 1:
|
||||
self.p |= self.CARRY
|
||||
if ((self.a ^ data) & (self.a ^ aluresult)) & self.NEGATIVE:
|
||||
self.p |= self.OVERFLOW
|
||||
self.a = (nibble1 << 4) + nibble0
|
||||
if aluresult > self.byteMask:
|
||||
decimalcarry = 1
|
||||
aluresult &= self.byteMask
|
||||
|
||||
# but the final result will be adjusted
|
||||
nibble0 = (aluresult + adjust0) & 0xf
|
||||
nibble1 = ((aluresult + adjust1) >> 4) & 0xf
|
||||
|
||||
# Update result for use in setting flags below
|
||||
adjresult = (nibble1 << 4) + nibble0
|
||||
|
||||
self.p &= ~(self.CARRY | self.ZERO | self.NEGATIVE | self.OVERFLOW)
|
||||
if aluresult == 0:
|
||||
self.p |= self.ZERO
|
||||
else:
|
||||
result = self.a + (~data & self.byteMask) + (self.p & self.CARRY)
|
||||
self.p &= ~(self.CARRY | self.ZERO | self.OVERFLOW | self.NEGATIVE)
|
||||
if ((self.a ^ data) & (self.a ^ result)) & self.NEGATIVE:
|
||||
self.p |= self.OVERFLOW
|
||||
data = result & self.byteMask
|
||||
if data == 0:
|
||||
self.p |= self.ZERO
|
||||
if result > self.byteMask:
|
||||
self.p |= self.CARRY
|
||||
self.p |= data & self.NEGATIVE
|
||||
self.a = data
|
||||
self.p |= aluresult & self.NEGATIVE
|
||||
if decimalcarry == 1:
|
||||
self.p |= self.CARRY
|
||||
if ((self.a ^ data) & (self.a ^ aluresult)) & self.NEGATIVE:
|
||||
self.p |= self.OVERFLOW
|
||||
self.a = adjresult
|
||||
|
||||
def opDECR(self, x):
|
||||
if x is None:
|
||||
|
@ -63,6 +63,77 @@ class MPU(mpu6502.MPU):
|
||||
self.p |= self.ZERO
|
||||
self.memory[address] = m & ~self.a
|
||||
|
||||
def opADC(self, x):
|
||||
return self._opADC(x, flags_use_adjusted_result=True)
|
||||
|
||||
def _opSBCDecimal(self, x):
|
||||
"""SBC opcode in binary mode (non-BCD)"""
|
||||
|
||||
data = self.ByteAt(x())
|
||||
|
||||
decimalcarry = 0
|
||||
#adjust0 = 0
|
||||
#adjust1 = 0
|
||||
|
||||
#nibble0 = (self.a & 0xf) + (~data & 0xf) + (self.p & self.CARRY)
|
||||
#if nibble0 <= 0xf:
|
||||
#halfcarry = 0
|
||||
#adjust0 = 10 # 0xa = -0x6
|
||||
#nibble1 = ((self.a >> 4) & 0xf) + ((~data >> 4) & 0xf) + halfcarry
|
||||
#if nibble1 <= 0xf:
|
||||
#adjust1 = 10 << 4 # -0x60
|
||||
|
||||
# the ALU outputs are not decimally adjusted
|
||||
aluresult = self.a + (~data & self.byteMask) + \
|
||||
(self.p & self.CARRY)
|
||||
|
||||
if aluresult > self.byteMask:
|
||||
decimalcarry = 1
|
||||
aluresult &= self.byteMask
|
||||
|
||||
#A2 = (self.a + ~data + (self.p & self.CARRY))
|
||||
#print "A = %02X, %02X, A2 = %02X, a=%02X, data=%02X, alu=%02X" % (A, (A & self.byteMask), A2, self.a, data, aluresult)
|
||||
#assert A == A2
|
||||
|
||||
# but the final result will be adjusted
|
||||
#nibble0 = (aluresult + adjust0) & 0xf
|
||||
#nibble1 = ((aluresult + adjust1) >> 4) & 0xf
|
||||
|
||||
# Update result for use in setting flags below
|
||||
#adjresult = (nibble1 << 4) + nibble0
|
||||
|
||||
A = self.a - data + (self.p & self.CARRY) - 1
|
||||
AL = (self.a & 0xf) - (data & 0xf) + (self.p & self.CARRY) - 1
|
||||
assert (A & self.byteMask) == aluresult
|
||||
|
||||
# XXX
|
||||
if A < 0:
|
||||
#print A, A2
|
||||
#assert adjust1, (A, adjust1)
|
||||
A -= 0x60
|
||||
|
||||
if AL < 0:
|
||||
#assert adjust0, (AL, adjust0)
|
||||
A -= 0x6
|
||||
|
||||
#if (A & self.byteMask) != adjresult:
|
||||
# print "a=%02X data=%02X carry=%02X, res=%02X, adj=%02X" % (
|
||||
# self.a, data, self.p & self.CARRY, A & self.byteMask, adjresult)
|
||||
#assert False
|
||||
|
||||
adjresult = A & self.byteMask
|
||||
|
||||
self.p &= ~(self.CARRY | self.ZERO | self.NEGATIVE | self.OVERFLOW)
|
||||
if adjresult == 0:
|
||||
self.p |= self.ZERO
|
||||
else:
|
||||
self.p |= adjresult & self.NEGATIVE
|
||||
if decimalcarry == 1:
|
||||
self.p |= self.CARRY
|
||||
if ((self.a ^ data) & (self.a ^ aluresult)) & self.NEGATIVE:
|
||||
self.p |= self.OVERFLOW
|
||||
self.a = adjresult
|
||||
|
||||
# instructions
|
||||
|
||||
@instruction(name="BRK", mode="imp", cycles=7)
|
||||
|
@ -25,27 +25,13 @@ class KlausDormannTests(unittest.TestCase):
|
||||
mpu, mpu.memory[0xb], mpu.memory[0xc], mpu.memory[0xd], mpu.memory[0xf])
|
||||
|
||||
def test6502FunctionalTest(self):
|
||||
self.klausTestCase("6502_functional_test.bin", 0x0, 0x400, 0x3399)
|
||||
self.klausTestCase("devices/6502_functional_test.bin", 0x0, 0x400, 0x3399)
|
||||
|
||||
def test65C02ExtendedOpcodesTest(self):
|
||||
# XXX fails
|
||||
def Xtest65C02ExtendedOpcodesTest(self):
|
||||
tracer = lambda pc: (0x1484 <= pc <= 0x16cc)
|
||||
self.klausTestCase("65C02_extended_opcodes_test_modified.bin", 0xa, 0x400, 0x24a8, tracer)
|
||||
|
||||
def test6502DecimalTest(self):
|
||||
mpu = self._make_mpu()
|
||||
mpu.pc = 0x1000
|
||||
|
||||
object_code = bytearray(open("6502_decimal_test.bin", "r").read())
|
||||
self._write(mpu.memory, 0x200, object_code)
|
||||
|
||||
# $1000: JSR $0200
|
||||
self._write(mpu.memory, 0x1000, [0x20, 0x00, 0x02])
|
||||
|
||||
while True:
|
||||
mpu.step()
|
||||
if mpu.pc == 0x1003:
|
||||
break
|
||||
assert mpu.memory[0x0b] == 0
|
||||
self.klausTestCase("devices/65C02_extended_opcodes_test_modified.bin"
|
||||
"", 0xa, 0x400, 0x24a8) #, tracer)
|
||||
|
||||
# Test Helpers
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user