mirror of
https://github.com/lloeki/python-dcpu_16.git
synced 2025-12-06 09:54:39 +01:00
361 lines
9.9 KiB
Python
361 lines
9.9 KiB
Python
import unittest
|
|
import random
|
|
import dcpu_16
|
|
from dcpu_16 import CPU
|
|
|
|
class TestInstructions(unittest.TestCase):
|
|
"""Instruction set"""
|
|
|
|
def setUp(self):
|
|
pass
|
|
|
|
def test_SET(self):
|
|
self.assertEqual(dcpu_16.SET.opcode, (0x01,))
|
|
c = CPU()
|
|
c.a = 0x0
|
|
c.b = 0x42
|
|
dcpu_16.SET(c, c._pointer(0x0), c._pointer(0x1))
|
|
self.assertEqual(c.a, 0x42)
|
|
self.assertEqual(c.b, 0x42)
|
|
|
|
def test_ADD(self):
|
|
self.assertEqual(dcpu_16.ADD.opcode, (0x02,))
|
|
c = CPU()
|
|
c.a = 0x17
|
|
c.b = 0x42
|
|
dcpu_16.ADD(c, c._pointer(0x0), c._pointer(0x1))
|
|
self.assertEqual(c.a, 0x17+0x42)
|
|
self.assertEqual(c.b, 0x42)
|
|
self.assertEqual(c.ex, 0x0)
|
|
|
|
def test_SUB(self):
|
|
self.assertEqual(dcpu_16.SUB.opcode, (0x03,))
|
|
c = CPU()
|
|
c.a = 0x42
|
|
c.b = 0x17
|
|
dcpu_16.SUB(c, c._pointer(0x0), c._pointer(0x1))
|
|
self.assertEqual(c.a, 0x42-0x17)
|
|
self.assertEqual(c.b, 0x17)
|
|
self.assertEqual(c.ex, 0x0)
|
|
|
|
def test_MUL(self):
|
|
self.assertEqual(dcpu_16.MUL.opcode, (0x04,))
|
|
c = CPU()
|
|
c.a = 0x17
|
|
c.b = 0x42
|
|
dcpu_16.MUL(c, c._pointer(0x0), c._pointer(0x1))
|
|
self.assertEqual(c.a, 0x17*0x42)
|
|
self.assertEqual(c.b, 0x42)
|
|
self.assertEqual(c.ex, 0x0)
|
|
|
|
def test_MLI(self):
|
|
self.assertEqual(dcpu_16.MLI.opcode, (0x05,))
|
|
c = CPU()
|
|
c.a = 0x17
|
|
c.b = 0x42
|
|
dcpu_16.MLI(c, c._pointer(0x0), c._pointer(0x1))
|
|
self.assertEqual(c.a, 0x17*0x42)
|
|
self.assertEqual(c.b, 0x42)
|
|
self.assertEqual(c.ex, 0x0)
|
|
|
|
def test_DIV(self):
|
|
self.assertEqual(dcpu_16.DIV.opcode, (0x06,))
|
|
c = CPU()
|
|
c.a = 0x17
|
|
c.b = 0x42
|
|
dcpu_16.DIV(c, c._pointer(0x0), c._pointer(0x1))
|
|
self.assertEqual(c.a, 0x17/0x42)
|
|
self.assertEqual(c.b, 0x42)
|
|
self.assertEqual(c.ex, ((0x17<<16)/0x42)&0xFFFF)
|
|
|
|
def test_DVI(self):
|
|
self.assertEqual(dcpu_16.DVI.opcode, (0x07,))
|
|
c = CPU()
|
|
c.a = 0x17
|
|
c.b = 0x42
|
|
dcpu_16.DIV(c, c._pointer(0x0), c._pointer(0x1))
|
|
self.assertEqual(c.a, 0x17/0x42)
|
|
self.assertEqual(c.b, 0x42)
|
|
self.assertEqual(c.ex, ((0x17<<16)/0x42)&0xFFFF)
|
|
|
|
def test_MOD(self):
|
|
self.assertEqual(dcpu_16.MOD.opcode, (0x08,))
|
|
c = CPU()
|
|
c.a = 0x17
|
|
c.b = 0x42
|
|
dcpu_16.MOD(c, c._pointer(0x0), c._pointer(0x1))
|
|
self.assertEqual(c.a, 0x17%0x42)
|
|
self.assertEqual(c.b, 0x42)
|
|
self.assertEqual(c.ex, 0x0)
|
|
|
|
def test_MDI(self):
|
|
self.assertEqual(dcpu_16.MDI.opcode, (0x09,))
|
|
c = CPU()
|
|
c.a = 0x17
|
|
c.b = 0x42
|
|
dcpu_16.MOD(c, c._pointer(0x0), c._pointer(0x1))
|
|
self.assertEqual(c.a, 0x17%0x42)
|
|
self.assertEqual(c.b, 0x42)
|
|
self.assertEqual(c.ex, 0x0)
|
|
|
|
def test_AND(self):
|
|
self.assertEqual(dcpu_16.AND.opcode, (0x0A,))
|
|
c = CPU()
|
|
c.a = 0x17
|
|
c.b = 0x42
|
|
dcpu_16.AND(c, c._pointer(0x0), c._pointer(0x1))
|
|
self.assertEqual(c.a, 0x17&0x42)
|
|
self.assertEqual(c.b, 0x42)
|
|
self.assertEqual(c.ex, 0x0)
|
|
|
|
def test_BOR(self):
|
|
self.assertEqual(dcpu_16.BOR.opcode, (0x0B,))
|
|
c = CPU()
|
|
c.a = 0x17
|
|
c.b = 0x42
|
|
dcpu_16.BOR(c, c._pointer(0x0), c._pointer(0x1))
|
|
self.assertEqual(c.a, 0x17|0x42)
|
|
self.assertEqual(c.b, 0x42)
|
|
self.assertEqual(c.ex, 0x0)
|
|
|
|
def test_XOR(self):
|
|
self.assertEqual(dcpu_16.XOR.opcode, (0x0C,))
|
|
c = CPU()
|
|
c.a = 0x17
|
|
c.b = 0x42
|
|
dcpu_16.XOR(c, c._pointer(0x0), c._pointer(0x1))
|
|
self.assertEqual(c.a, 0x17^0x42)
|
|
self.assertEqual(c.b, 0x42)
|
|
self.assertEqual(c.ex, 0x0)
|
|
|
|
def test_SHR(self):
|
|
self.assertEqual(dcpu_16.SHR.opcode, (0x0D,))
|
|
c = CPU()
|
|
c.a = 0x17
|
|
c.b = 0x42
|
|
dcpu_16.SHR(c, c._pointer(0x0), c._pointer(0x1))
|
|
self.assertEqual(c.a, 0x17>>0x42)
|
|
self.assertEqual(c.b, 0x42)
|
|
self.assertEqual(c.ex, 0x0)
|
|
|
|
def test_ASR(self):
|
|
self.assertEqual(dcpu_16.ASR.opcode, (0x0E,))
|
|
c = CPU()
|
|
c.a = 0x17
|
|
c.b = 0x42
|
|
dcpu_16.ASR(c, c._pointer(0x0), c._pointer(0x1))
|
|
self.assertEqual(c.a, 0x17>>0x42)
|
|
self.assertEqual(c.b, 0x42)
|
|
self.assertEqual(c.ex, 0x0)
|
|
|
|
def test_SHL(self):
|
|
self.assertEqual(dcpu_16.SHL.opcode, (0x0F,))
|
|
c = CPU()
|
|
c.a = 0x17
|
|
c.b = 0x4
|
|
dcpu_16.SHL(c, c._pointer(0x0), c._pointer(0x1))
|
|
self.assertEqual(c.a, 0x17<<0x4 & dcpu_16.wmask)
|
|
self.assertEqual(c.b, 0x4)
|
|
self.assertEqual(c.ex, 0x0)
|
|
|
|
def test_IFB(self):
|
|
self.assertEqual(dcpu_16.IFB.opcode, (0x10,))
|
|
c = CPU()
|
|
|
|
c.a = 0xF0F0
|
|
c.b = 0x0F0F
|
|
dcpu_16.IFB(c, c._pointer(0x0), c._pointer(0x1))
|
|
self.assertEqual(c.skip, True)
|
|
|
|
c.a = 0xF1F0
|
|
c.b = 0x0F0F
|
|
dcpu_16.IFB(c, c._pointer(0x0), c._pointer(0x1))
|
|
self.assertEqual(c.skip, False)
|
|
|
|
def test_IFE(self):
|
|
self.assertEqual(dcpu_16.IFE.opcode, (0x12,))
|
|
c = CPU()
|
|
|
|
c.a = 0x17
|
|
c.b = 0x42
|
|
dcpu_16.IFE(c, c._pointer(0x0), c._pointer(0x1))
|
|
self.assertEqual(c.skip, True)
|
|
|
|
c.a = 0x42
|
|
c.b = 0x42
|
|
dcpu_16.IFE(c, c._pointer(0x0), c._pointer(0x1))
|
|
self.assertEqual(c.skip, False)
|
|
|
|
def test_IFN(self):
|
|
self.assertEqual(dcpu_16.IFN.opcode, (0x13,))
|
|
c = CPU()
|
|
|
|
c.a = 0x17
|
|
c.b = 0x42
|
|
dcpu_16.IFN(c, c._pointer(0x0), c._pointer(0x1))
|
|
self.assertEqual(c.skip, False)
|
|
|
|
c.a = 0x42
|
|
c.b = 0x42
|
|
dcpu_16.IFN(c, c._pointer(0x0), c._pointer(0x1))
|
|
self.assertEqual(c.skip, True)
|
|
|
|
def test_IFG(self):
|
|
self.assertEqual(dcpu_16.IFG.opcode, (0x14,))
|
|
c = CPU()
|
|
|
|
c.a = 0x41
|
|
c.b = 0x42
|
|
dcpu_16.IFG(c, c._pointer(0x0), c._pointer(0x1))
|
|
self.assertEqual(c.skip, True)
|
|
|
|
c.a = 0x42
|
|
c.b = 0x42
|
|
dcpu_16.IFG(c, c._pointer(0x0), c._pointer(0x1))
|
|
self.assertEqual(c.skip, True)
|
|
|
|
c.a = 0x42
|
|
c.b = 0x41
|
|
dcpu_16.IFG(c, c._pointer(0x0), c._pointer(0x1))
|
|
self.assertEqual(c.skip, False)
|
|
|
|
def test_JSR(self):
|
|
self.assertEqual(dcpu_16.JSR.opcode, (0x00, 0x01))
|
|
c = CPU()
|
|
|
|
c.a = 0xDEAD
|
|
c.pc = 0xBEEF
|
|
dcpu_16.JSR(c, c._pointer(0x0))
|
|
self.assertEqual(c.pc, 0xDEAD)
|
|
self.assertEqual(c.sp, 0xFFFF)
|
|
self.assertEqual(c.m[0xFFFF], 0xBEEF)
|
|
|
|
|
|
class TestCPU(unittest.TestCase):
|
|
"""CPU behavior"""
|
|
|
|
def setUp(self):
|
|
pass
|
|
|
|
def test_initial_state(self):
|
|
"""Initial state shall be all zero"""
|
|
c = CPU()
|
|
for r in c.r:
|
|
self.assertEqual(r, 0)
|
|
self.assertEqual(c.pc, 0)
|
|
self.assertEqual(c.ex, 0)
|
|
self.assertEqual(c.sp, 0)
|
|
self.assertEqual(c.skip, False)
|
|
self.assertEqual(c.pc, 0)
|
|
for r in c.m:
|
|
self.assertEqual(r, 0)
|
|
|
|
def test_reset(self):
|
|
"""Reset shall bring CPU register state to initial"""
|
|
c = CPU()
|
|
for i in xrange(0x8):
|
|
c.r[i] = random.randrange(0x10000)
|
|
c.reset()
|
|
for r in c.r:
|
|
self.assertEqual(r, 0)
|
|
self.assertEqual(c.pc, 0)
|
|
self.assertEqual(c.ex, 0)
|
|
self.assertEqual(c.sp, 0)
|
|
self.assertEqual(c.skip, False)
|
|
self.assertEqual(c.pc, 0)
|
|
|
|
def test_clear(self):
|
|
"""Clear shall zero memory"""
|
|
c = CPU()
|
|
for i in xrange(0x10000):
|
|
c.m[i] = random.randrange(0x10000)
|
|
c.clear()
|
|
for r in c.m:
|
|
self.assertEqual(r, 0)
|
|
|
|
class TestCPUWithPrograms(unittest.TestCase):
|
|
def setUP(self):
|
|
pass
|
|
|
|
def test_spec_demo(self):
|
|
c = CPU()
|
|
c.load_m(data=dcpu_16.spec_demo)
|
|
|
|
self.assertEqual(c.pc, 0)
|
|
c.step() # SET A, 0x30
|
|
self.assertEqual(c.a, 0x30)
|
|
|
|
self.assertEqual(c.pc, 2)
|
|
c.step() # SET [0x1000], 0x20
|
|
self.assertEqual(c.m[0x1000], 0x20)
|
|
|
|
self.assertEqual(c.pc, 5)
|
|
c.step() # SUB A, [0x1000]
|
|
self.assertEqual(c.a, 0x10)
|
|
|
|
self.assertEqual(c.pc, 7)
|
|
c.step() # IFN A, 0x10
|
|
self.assertEqual(c.pc, 8)
|
|
self.assertEqual(c.skip, True)
|
|
|
|
c.step() # skip SET PC, crash
|
|
self.assertEqual(c.skip, False)
|
|
|
|
self.assertEqual(c.pc, 10)
|
|
c.step() # SET I, 10
|
|
self.assertEqual(c.i, 0x0A)
|
|
|
|
self.assertEqual(c.pc, 11)
|
|
c.step() # SET A, 0x2000
|
|
self.assertEqual(c.a, 0x2000)
|
|
|
|
for i in range(10, 0, -1):
|
|
self.assertEqual(c.pc, 13)
|
|
c.step() # SET [0x2000+I], [A]
|
|
self.assertEqual(c.m[0x2000+i], 0x0)
|
|
|
|
self.assertEqual(c.pc, 15)
|
|
c.step() # SUB I, 1
|
|
self.assertEqual(c.i, i-1)
|
|
|
|
self.assertEqual(c.pc, 16)
|
|
c.step() # IFN I, 0
|
|
self.assertEqual(c.skip, i-1==0)
|
|
|
|
self.assertEqual(c.pc, 17)
|
|
c.step() # SET PC, loop (with skip if c.i==0)
|
|
|
|
self.assertEqual(c.pc, 19)
|
|
c.step() # SET X, 0x4
|
|
self.assertEqual(c.x, 0x4)
|
|
|
|
self.assertEqual(c.pc, 20)
|
|
c.step() # JSR testsub
|
|
self.assertEqual(c.sp, 0xFFFF)
|
|
self.assertEqual(c.m[0xFFFF], 22)
|
|
|
|
self.assertEqual(c.pc, 24)
|
|
c.step() # SHL X, 4
|
|
self.assertEqual(c.x, 0x40)
|
|
|
|
self.assertEqual(c.pc, 25)
|
|
c.step() # SET PC, POP
|
|
|
|
self.assertEqual(c.pc, 22)
|
|
c.step() # SET PC, crash
|
|
|
|
self.assertEqual(c.pc, 26)
|
|
c.step() # SET PC, crash
|
|
|
|
self.assertEqual(c.pc, 26)
|
|
# endless loop
|
|
|
|
|
|
if __name__ == '__main__':
|
|
cases = [
|
|
'test.TestInstructions',
|
|
'test.TestCPU',
|
|
'test.TestCPUWithPrograms'
|
|
]
|
|
suite = unittest.TestLoader().loadTestsFromNames(cases)
|
|
unittest.TextTestRunner(verbosity=2).run(suite)
|