Last active
December 23, 2015 06:49
-
-
Save jedie/6595991 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env python | |
""" | |
DragonPy - Dragon 32 emulator in Python | |
======================================= | |
6809 is Big-Endian | |
Based on XRoar emulator by Ciaran Anscomb (GPL license) more info, see README | |
:copyleft: 2013 by the DragonPy team, see AUTHORS for more details. | |
:license: GNU GPL v3 or above, see LICENSE for more details. | |
""" | |
import logging | |
log = logging.getLogger("DragonPy") | |
def signed8(x): | |
""" convert to signed 8-bit """ | |
if x > 0x7f: # 0x7f == 2**7-1 == 127 | |
x = x - 0x100 # 0x100 == 2**8 == 256 | |
return x | |
def signed16(x): | |
""" convert to signed 16-bit """ | |
if x > 0x7fff: # 0x7fff == 2**15-1 == 32767 | |
x = x - 0x10000 # 0x100 == 2**16 == 65536 | |
return x | |
def _register_bit(key): | |
def set_flag(self, value): | |
assert value in (0, 1) | |
self._register[key] = value | |
def get_flag(self): | |
return self._register[key] | |
return property(get_flag, set_flag) | |
class ConditionCodeRegister(object): | |
""" CC - 8 bit condition code register bits """ | |
def __init__(self, *args, **kwargs): | |
self._register = {} | |
self.status_from_byte(0x0) # create all keys in dict with value 0 | |
E = _register_bit("E") # E - 0x80 - bit 7 - Entire register state stacked | |
F = _register_bit("F") # F - 0x40 - bit 6 - FIRQ interrupt masked | |
H = _register_bit("H") # H - 0x20 - bit 5 - Half-Carry | |
I = _register_bit("I") # I - 0x10 - bit 4 - IRQ interrupt masked | |
N = _register_bit("N") # N - 0x08 - bit 3 - Negative result (twos complement) | |
Z = _register_bit("Z") # Z - 0x04 - bit 2 - Zero result | |
V = _register_bit("V") # V - 0x02 - bit 1 - Overflow | |
C = _register_bit("C") # C - 0x01 - bit 0 - Carry (or borrow) | |
#### | |
def status_from_byte(self, status): | |
self.E, self.F, self.H, self.I, self.N, self.Z, self.V, self.C = \ | |
[0 if status & x == 0 else 1 for x in (128, 64, 32, 16, 8, 4, 2, 1)] | |
def status_as_byte(self): | |
return self.C | \ | |
self.V << 1 | \ | |
self.Z << 2 | \ | |
self.N << 3 | \ | |
self.I << 4 | \ | |
self.H << 5 | \ | |
self.F << 6 | \ | |
self.E << 7 | |
#### | |
def set_Z8(self, r): | |
self.Z = 1 if r & 0xff == 0 else 0 | |
def set_Z16(self, r): | |
self.Z = 1 if r & 0xffff == 0 else 0 | |
def set_N8(self, r): | |
self.N = 1 if signed8(r) < 0 else 0 | |
def set_N16(self, r): | |
self.N = 1 if signed16(r) < 0 else 0 | |
def set_H(self, a, b, r): # TODO: Add tests | |
self.H = 1 if (a ^ b ^ r) & 0x10 else 0 | |
def set_C8(self, r): | |
self.C = 1 if r & 0x100 else 0 | |
def set_C16(self, r): | |
self.C = 1 if r & 0x10000 else 0 | |
def set_V8(self, a, b, r): # FIXME | |
self.V = 1 if (a ^ b ^ r ^ (r >> 1)) & 0x80 else 0 | |
def set_V16(self, a, b, r): # FIXME | |
self.V = 1 if (a ^ b ^ r ^ (r >> 1)) & 0x8000 else 0 | |
#### | |
def set_NZ8(self, r): | |
self.set_N8(r) | |
self.set_Z8(r) | |
def set_NZ16(self, r): | |
self.set_N16(r) | |
self.set_Z16(r) | |
def set_NZC8(self, r): | |
self.set_N8(r) | |
self.set_Z8(r) | |
self.set_C8(r) | |
def set_NZVC8(self, a, b, r): # FIXME | |
self.set_N8(r) | |
self.set_Z8(r) | |
self.set_V8(a, b, r) | |
self.set_C8(r) | |
def set_NZVC16(self, a, b, r): # FIXME | |
self.set_N16(r) | |
self.set_Z16(r) | |
self.set_V16(a, b, r) | |
self.set_C16(r) | |
class Accumulators(object): | |
def __init__(self, cpu): | |
self.cpu = cpu | |
self._A = 0 # A - 8 bit accumulator | |
self._B = 0 # B - 8 bit accumulator | |
# D - 16 bit concatenated reg. (A + B) | |
def _check(self, value): | |
if value > 0xff: | |
self.cpu.cc.V = 1 # set Overflow flag | |
value = value & 0xff | |
return value | |
def get_A(self): | |
return self._A | |
def set_A(self, value): | |
self._A = self._check(value) | |
A = property(get_A, set_A) | |
def get_B(self): | |
return self._B | |
def set_B(self, value): | |
self._B = self._check(value) | |
B = property(get_B, set_B) | |
def get_D(self): | |
return self._A * 256 + self._B | |
def set_D(self, value): | |
self.set_A(value >> 8) | |
self.set_B(value & 0xff) | |
if value > 0xffff: | |
self.cpu.cc.V = 1 # set Overflow flag | |
value = value & 0xffff | |
D = property(get_D, set_D) | |
#------------------------------------------------------------------------------ | |
# TODO: move into separate test.py: | |
import unittest | |
class TestCPU(object): | |
def __init__(self): | |
self.accu = Accumulators(self) | |
self.cc = ConditionCodeRegister() | |
class BaseTestCase(unittest.TestCase): | |
def assertEqualHex(self, hex1, hex2, msg=None): | |
first = "$%x" % hex1 | |
second = "$%x" % hex2 | |
self.assertEqual(first, second, msg) | |
class CC_AccumulatorTestCase(BaseTestCase): | |
def setUp(self): | |
self.cpu = TestCPU() | |
def test_A01(self): | |
self.cpu.accu.A = 0xff | |
self.assertEqualHex(self.cpu.accu.A, 0xff) | |
self.assertEqual(self.cpu.cc.V, 0) | |
self.cpu.accu.A = 0xff + 1 | |
self.assertEqual(self.cpu.cc.V, 1) | |
self.assertEqualHex(self.cpu.accu.A, 0x0) # XXX | |
def test_B01(self): | |
self.cpu.accu.B = 0x5a | |
self.assertEqualHex(self.cpu.accu.B, 0x5a) | |
self.assertEqual(self.cpu.cc.V, 0) | |
self.cpu.accu.B = 0xff + 10 | |
self.assertEqual(self.cpu.cc.V, 1) | |
self.assertEqualHex(self.cpu.accu.B, 0x9) # XXX | |
def test_D01(self): | |
self.cpu.accu.A = 0x12 | |
self.cpu.accu.B = 0xab | |
self.assertEqualHex(self.cpu.accu.D, 0x12ab) | |
self.assertEqual(self.cpu.cc.V, 0) | |
def test_D02(self): | |
self.cpu.accu.D = 0xfd89 | |
self.assertEqualHex(self.cpu.accu.A, 0xfd) | |
self.assertEqualHex(self.cpu.accu.B, 0x89) | |
self.assertEqual(self.cpu.cc.V, 0) | |
def test_D03(self): | |
self.cpu.accu.D = 0xffff + 1 | |
self.assertEqualHex(self.cpu.accu.A, 0x0) # XXX | |
self.assertEqualHex(self.cpu.accu.B, 0x0) # XXX | |
self.assertEqual(self.cpu.cc.V, 1) | |
class CCTestCase(unittest.TestCase): | |
def setUp(self): | |
self.cc = ConditionCodeRegister() | |
def test_status_from_byte_to_byte(self): | |
for i in xrange(256): | |
self.cc.status_from_byte(i) | |
status_byte = self.cc.status_as_byte() | |
self.assertEqual(status_byte, i) | |
def test_set_NZ8(self): | |
self.cc.set_NZ8(r=0x12) | |
self.assertEqual(self.cc.N, 0) | |
self.assertEqual(self.cc.Z, 0) | |
self.cc.set_NZ8(r=0x0) | |
self.assertEqual(self.cc.N, 0) | |
self.assertEqual(self.cc.Z, 1) | |
self.cc.set_NZ8(r=0x80) | |
self.assertEqual(self.cc.N, 1) | |
self.assertEqual(self.cc.Z, 0) | |
def test_set_NZ16(self): | |
self.cc.set_NZ16(r=0x7fff) # 0x7fff == 32767 | |
self.assertEqual(self.cc.N, 0) | |
self.assertEqual(self.cc.Z, 0) | |
self.cc.set_NZ16(r=0x00) | |
self.assertEqual(self.cc.N, 0) | |
self.assertEqual(self.cc.Z, 1) | |
self.cc.set_NZ16(r=0x8000) # signed 0x8000 == -32768 | |
self.assertEqual(self.cc.N, 1) | |
self.assertEqual(self.cc.Z, 0) | |
def test_set_NZC8(self): # FIXME: C ??? | |
self.cc.set_NZC8(0x7f) | |
self.assertEqual(self.cc.N, 0) | |
self.assertEqual(self.cc.Z, 0) | |
self.assertEqual(self.cc.C, 0) | |
self.cc.set_NZC8(0x100) | |
self.assertEqual(self.cc.N, 0) | |
self.assertEqual(self.cc.Z, 1) | |
self.assertEqual(self.cc.C, 1) | |
def test_set_NZVC8(self): | |
a = 1 | |
b = 2 | |
r = a + b | |
self.cc.set_NZVC8(a, b, r) | |
self.assertEqual(self.cc.N, 0) | |
self.assertEqual(self.cc.Z, 0) | |
self.assertEqual(self.cc.V, 0) | |
self.assertEqual(self.cc.C, 0) | |
a = 0xff | |
b = 1 | |
r = a + b | |
self.cc.set_NZVC8(a, b, r) | |
self.assertEqual(self.cc.N, 0) | |
self.assertEqual(self.cc.Z, 1) | |
self.assertEqual(self.cc.V, 1) # FIXME | |
self.assertEqual(self.cc.C, 0) | |
if __name__ == '__main__': | |
unittest.main(verbosity=2) | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment