WIP working towards 1.5

This commit is contained in:
Loic Nageleisen 2012-04-27 17:07:05 +02:00
parent a714a9d71a
commit 13adbbf68c
2 changed files with 350 additions and 170 deletions

View file

@ -5,12 +5,19 @@ Spec: http://0x10c.com/doc/dcpu-16.txt
See LICENSE for licensing information. See LICENSE for licensing information.
""" """
# TODO: cycle count management
# branching opcodes take one cycle longer to perform if the test fails
# when they skip an if instruction, they will skip an additional instruction
# TODO: signed functions
# signed numbers are represented using two's complement
# TODO: interrupts
# TODO: hardware
from __future__ import print_function, division from __future__ import print_function, division
# DCPU-16 spec version # DCPU-16 spec version
spec = '1.1' spec = '1.5'
# log tool # log tool
@ -100,131 +107,247 @@ def pointerize(f):
return ptrz return ptrz
@opcode(0x0, 0x01) @opcode(0x00, 0x01)
def JSR(c, a): def JSR(c, a):
"""pushes the address of the next instruction to the stack, then sets PC to a""" """pushes the address of the next instruction to the stack, then sets PC to a"""
c.sp -= 1 c.sp -= 1
c.m[c.sp] = c.pc c.m[c.sp] = c.pc
c.pc = a() c.pc = a()
@opcode(0x1) @opcode(0x00, 0x07)
def SET(c, a, b): def HCF(c, a):
"""sets a to b""" """use sparingly"""
a.set(b()) pass
@opcode(0x2) @opcode(0x00, 0x08)
def ADD(c, a, b): def INT(c, a):
"""sets a to a+b, sets O to 0x0001 if there's an overflow""" """triggers a software interrupt with message a"""
res = (a() + b()) pass
@opcode(0x00, 0x09)
def IAG(c, a):
"""sets a to IA"""
pass
@opcode(0x00, 0x0A)
def IAS(c, a):
"""sets IA to a"""
pass
@opcode(0x00, 0x0B)
def IAP(c, a):
"""if IA is 0, does nothing, otherwise pushes IA to the stack, then sets IA to a"""
pass
@opcode(0x00, 0x0C)
def IAQ(c, a):
"""if a is nonzero, interrupts will be added to the queue instead of triggered. if a is zero, interrupts will be triggered as nomral again"""
pass
@opcode(0x00, 0x10)
def HWN(c, a):
"""sets a to number of connected hardware devices"""
pass
@opcode(0x00, 0x11)
def HWQ(c, a):
"""sets A, B, C,X, Y registers to information about hardware a
A+(B<<16) is a 32 bit word identifying the hardware id
C is the hardware version
X+(Y<<16) is a 32 bit word identifying the manufacturer
"""
pass
@opcode(0x00, 0x12)
def HWI(c, a):
"""sends an interrupt to hardware a"""
pass
@opcode(0x01)
def SET(c, b, a):
"""sets b to a"""
b.set(a())
@opcode(0x02)
def ADD(c, b, a):
"""sets b to b+a, sets EX to 0x0001 if there's an overflow, 0x0 otherwise"""
res = (b() + a())
if res > wmask: if res > wmask:
c.o = 0x0001 c.ex = 0x0001
res = res & wmask res = res & wmask
a.set(res) b.set(res)
@opcode(0x3) @opcode(0x03)
def SUB(c, a, b): def SUB(c, b, a):
"""sets a to a-b, sets O to 0xFFFF if there's an underflow""" """sets b to b-a, sets EX to 0xFFFF if there's an underflow, 0x0 otherwise"""
res = (a() - b()) res = (b() - a())
if res & (wmask+1): if res & (wmask+1):
c.o = 0xFFFF c.ex = 0xFFFF
res = res & wmask res = res & wmask
a.set(res) b.set(res)
@opcode(0x4) @opcode(0x04)
def MUL(c, a, b): def MUL(c, b, a):
"""sets a to a*b, sets O to ((a*b)>>16)&0xFFFF""" """sets b to b*a, sets EX to ((b*a)>>16)&0xFFFF (treats b, a as unsigned)"""
res = (a() * b()) res = (b() * a())
c.o = ((a() * b()) >> w) & wmask c.ex = ((b() * a()) >> w) & wmask
res = res & wmask res = res & wmask
a.set(res) b.set(res)
@opcode(0x5) @opcode(0x05)
def DIV(c, a, b): def MLI(c, b, a):
"""sets a to a/b, sets O to ((a<<16)/b)&0xFFFF""" """like MUL, but treats b, a as signed"""
res = a() // b() pass
c.o = ((a() << w) // b()) & wmask
a.set(res)
@opcode(0x6) @opcode(0x06)
def MOD(c, a, b): def DIV(c, b, a):
"""sets a to a%b. if b==0, sets a to 0 instead""" """sets b to b/a, sets EX to ((b<<16)/a)&0xFFFF. if a==0, sets b and EX to 0 instead. (treats b, a as unsigned)"""
if b()==0: res = b() // a()
c.ex = ((b() << w) // a()) & wmask
b.set(res)
@opcode(0x07)
def DVI(c, b, a):
"""like DIV, but treats b, a as signed. Rounds towards 0"""
pass
@opcode(0x08)
def MOD(c, b, a):
"""sets b to b%a. if a==0 sets b to 0 instead"""
if a()==0:
res = 0 res = 0
else: else:
res = a() % b() res = b() % a()
a.set(res) b.set(res)
@opcode(0x7) @opcode(0x09)
def SHL(c, a, b): def MDI(c, b, a):
"""sets a to a<<b. sets O to ((a<<b)>>16)&0xFFFF""" """like MOD, but treat b, a as signed. Rounds towards 0"""
res = (a() << b()) pass
c.o = ((a() << b()) >> w) & wmask
@opcode(0x0A)
def AND(c, b, a):
"""sets b to b&a"""
res = b() & a()
b.set(res)
@opcode(0x0B)
def BOR(c, b, a):
"""sets b to b|a"""
res = b() | a()
b.set(res)
@opcode(0x0C)
def XOR(c, b, a):
"""sets b to b^a"""
res = b() ^ a()
b.set(res)
@opcode(0x0D)
def SHR(c, b, a):
"""sets b to b>>>a. sets EX to ((b<<16)>>a)&0xFFFF (logical shift)"""
res = (b() >> a())
c.ex = ((b() << w) >> a()) & wmask
res = res & wmask res = res & wmask
a.set(res) b.set(res)
@opcode(0x8) @opcode(0x0E)
def SHR(c, a, b): def ASR(c, b, a):
"""sets a to a>>b. sets O to ((a>>16)>>b)&0xFFFF""" """sets b to b>>a. sets EX to ((b<<16)>>>a)&0xFFFF (arithmetic shift) (treats b as signed)"""
res = (a() >> b()) pass
c.o = ((a() >> w) >> b()) & wmask
@opcode(0x0F)
def SHL(c, b, a):
"""sets b to b<<a. sets EX to ((b<<a)>>16)&0xFFFF"""
res = (b() << a())
c.ex = ((b() << a()) >> w) & wmask
res = res & wmask res = res & wmask
a.set(res) b.set(res)
@opcode(0x9) @opcode(0x10)
def AND(c, a, b): def IFB(c, b, a):
"""sets a to a&b""" """performs next instruction only if (b&a)!=0"""
res = a() & b() if (b() & a()) != 0:
a.set(res)
@opcode(0xA)
def BOR(c, a, b):
"""sets a to a|b"""
res = a() | b()
a.set(res)
@opcode(0xB)
def XOR(c, a, b):
"""sets a to a^b"""
res = a() ^ b()
a.set(res)
@opcode(0xC)
def IFE(c, a, b):
"""performs next instruction only if a==b"""
if a() == b():
c.skip = False c.skip = False
else: else:
c.skip = True c.skip = True
@opcode(0xD) @opcode(0x11)
def IFN(c, a, b): def IFC(c, b, a):
"""performs next instruction only if a!=b""" """performs next instruction only if (b&a)==0"""
if a() != b(): if (b() & a()) == 0:
c.skip = False c.skip = False
else: else:
c.skip = True c.skip = True
@opcode(0xE) @opcode(0x12)
def IFG(c, a, b): def IFE(c, b, a):
"""performs next instruction only if a>b""" """performs next instruction only if b==a"""
if a() > b(): if b() == a():
c.skip = False c.skip = False
else: else:
c.skip = True c.skip = True
@opcode(0xF) @opcode(0x13)
def IFB(c, a, b): def IFN(c, b, a):
"""performs next instruction only if (a&b)!=0""" """performs next instruction only if b!=a"""
if (a() & b()) != 0: if b() != a():
c.skip = False c.skip = False
else: else:
c.skip = True c.skip = True
@opcode(0x14)
def IFG(c, b, a):
"""performs next instruction only if b>a"""
if b() > a():
c.skip = False
else:
c.skip = True
@opcode(0x15)
def IFA(c, b, a):
"""performs next instruction only if b>a (signed)"""
pass
@opcode(0x16)
def IFL(c, b, a):
"""performs next instruction only if b<a"""
if b() < a():
c.skip = False
else:
c.skip = True
@opcode(0x17)
def IFU(c, b, a):
"""performs next instruction only if b<a (signed)"""
pass
@opcode(0x1A)
def ADX(c, b, a):
"""sets b to b+a+EX, sets EX to 0x0001 if there is an overflow, 0x0 otherwise"""
pass
@opcode(0x1B)
def SBX(c, b, a):
"""sets b to b-a+EX, sets EX to 0xFFFF if there is an underflow, 0x0 otherwise"""
pass
@opcode(0x1E)
def STI(c, b, a):
"""sets b to a, then increases I and J by 1"""
pass
@opcode(0x1F)
def STD(c, b, a):
"""sets b to a, then decreases I and J by 1"""
pass
@valcode(range(0x00, 0x08)) @valcode(range(0x00, 0x08))
@pointerize @pointerize
def register(c, code): def register(c, code):
"""register""" """register (A, B, C, X, Y, Z, I, J, in that order)"""
v = "c.r[0x%01X]" % code v = "c.r[0x%01X]" % code
return v return v
@ -245,8 +368,16 @@ def next_word_plus_register_value(c, code):
@valcode(0x18) @valcode(0x18)
@pointerize @pointerize
def push_pop(c):
"""(PUSH / [--SP]) if in b, or (POP / [SP++]) if in a"""
pass
def push(c):
"""[--SP] / PUSH"""
c.sp -= 1
v = "c.m[0x%04X]" % c.sp
return v
def pop(c): def pop(c):
"""POP / [SP++]""" """[SP++] / POP"""
v = "c.m[0x%04X]" % c.sp v = "c.m[0x%04X]" % c.sp
c.sp += 1 c.sp += 1
return v return v
@ -254,37 +385,35 @@ def pop(c):
@valcode(0x19) @valcode(0x19)
@pointerize @pointerize
def peek(c): def peek(c):
"""PEEK / [SP]""" """[SP] / PEEK"""
v = "c.m[0x%04X]" % c.sp v = "c.m[0x%04X]" % c.sp
return v return v
@valcode(0x1A) @valcode(0x1A)
@pointerize @pointerize
def push(c): def pick(c):
"""PUSH / [--SP]""" """[SP + next word] / PICK n"""
c.sp -= 1 pass
v = "c.m[0x%04X]" % c.sp
return v
@valcode(0x1B) @valcode(0x1B)
@pointerize @pointerize
def stack_pointer(c): def stack_pointer(c):
"""stack pointer""" """SP"""
v = "c.sp" v = "c.sp"
return v return v
@valcode(0x1C) @valcode(0x1C)
@pointerize @pointerize
def program_counter(c): def program_counter(c):
"""program counter""" """PC"""
v = "c.pc" v = "c.pc"
return v return v
@valcode(0x1D) @valcode(0x1D)
@pointerize @pointerize
def overflow(c): def excess(c):
"""overflow""" """EX"""
v = "c.o" v = "c.ex"
return v return v
@valcode(0x1E) @valcode(0x1E)
@ -306,8 +435,8 @@ def next_word(c):
@valcode(range(0x20, 0x40)) @valcode(range(0x20, 0x40))
@pointerize @pointerize
def literal(c, code): def literal(c, code):
"""literal value 0x00-0x1F (literal)""" """literal value 0xFFFF-0x1E (-1..30) (literal) (only for a)"""
v = "0x%04X" % (code - 0x20) v = "0x%04X" % ((code - 0x20 - 1) & 0xFFFF)
return v return v
@ -345,7 +474,7 @@ class CPU(object):
c.r = [0 for _ in xrange(0, 8)] c.r = [0 for _ in xrange(0, 8)]
c.pc = 0x0000 c.pc = 0x0000
c.sp = 0x0000 c.sp = 0x0000
c.o = 0x0000 c.ex = 0x0000
c.skip = False c.skip = False
def clear(c): def clear(c):
@ -362,22 +491,22 @@ class CPU(object):
j = Register(0x7) j = Register(0x7)
pc = Register() pc = Register()
sp = Register() sp = Register()
o = Register() ex = Register()
def _op(c, word): def _op(c, word):
"""dispatch word to op and args""" """dispatch word to op and args"""
opcode = word & 0xF opcode = word & 0x1F
a_code = word >> 4 & 0x3F b_code = word >> 5 & 0x1F
b_code = word >> 10 & 0x3F a_code = word >> 10 & 0x3F
try: try:
op = _opcode_map[opcode] op = _opcode_map[opcode]
try: try:
op = op[a_code] op = op[a_code]
except TypeError: except TypeError:
args = (c._pointer(a_code), args = (c._pointer(b_code),
c._pointer(b_code)) c._pointer(a_code))
else: else:
args = (c._pointer(b_code),) args = (c._pointer(a_code),)
finally: finally:
if c.debug: if c.debug:
log(' '.join([op.__name__] + [arg.codestr for arg in args])) log(' '.join([op.__name__] + [arg.codestr for arg in args]))
@ -428,9 +557,9 @@ class CPU(object):
(["A", "B", "C", (["A", "B", "C",
"X", "Y", "Z", "X", "Y", "Z",
"I", "J", "I", "J",
"PC", "SP", "O", "PC", "SP", "EX",
][i], ][i],
(c.r + [c.pc, c.sp, c.o])[i]) (c.r + [c.pc, c.sp, c.ex])[i])
for i in range(11)) for i in range(11))
def load_m(c, data=None, io=None): def load_m(c, data=None, io=None):
@ -446,8 +575,25 @@ class CPU(object):
spec_demo = [ spec_demo = [
0x7c01, 0x0030, 0x7de1, 0x1000, 0x0020, 0x7803, 0x1000, 0xc00d, # TODO: hand-reassembled for 1.5, but still some bugs
0x7dc1, 0x001a, 0xa861, 0x7c01, 0x2000, 0x2161, 0x2000, 0x8463, 0x7c01, 0x0030, # SET A, 0x30
0x806d, 0x7dc1, 0x000d, 0x9031, 0x7c10, 0x0018, 0x7dc1, 0x001a, 0x7fc1, 0x1000, 0x0020, # SET [0x1000], 0x20
0x9037, 0x61c1, 0x7dc1, 0x001a, 0x0000, 0x0000, 0x0000, 0x0000, 0x7803, 0x1000, # SUB A, [0X1000]
0xc012, # 0xc013 # IFE A, 0xF
0x7f81, 0x001a, # SET PC, crash
0x90c1, # 0xacc1 # SET I, 10
0x7c01, 0x2000, # SET A, 0x2000
# :loop
0x22C1, 0x2000, # SET [I + 0x2000], [A]
0x88C3, # SUB I, 1
0x84D3, # IFN I, 0
0x7f81, 0x000d, # SET PC, loop
0x9461, # SET X, 4
0x7c20, 0x0018, # JSR testsub
0x7f81, 0x001a, # SET PC, crash
# :testsub
0x946f, # SHL X, 4
0x6381, # SET PC, POP
# :crash
0x7f81, 0x001a, # SET PC, crash
] ]

152
test.py
View file

@ -10,7 +10,7 @@ class TestInstructions(unittest.TestCase):
pass pass
def test_SET(self): def test_SET(self):
dcpu_16.SET.opcode = (0x1,) self.assertEqual(dcpu_16.SET.opcode, (0x01,))
c = CPU() c = CPU()
c.a = 0x0 c.a = 0x0
c.b = 0x42 c.b = 0x42
@ -19,107 +19,161 @@ class TestInstructions(unittest.TestCase):
self.assertEqual(c.b, 0x42) self.assertEqual(c.b, 0x42)
def test_ADD(self): def test_ADD(self):
dcpu_16.SET.opcode = (0x2,) self.assertEqual(dcpu_16.ADD.opcode, (0x02,))
c = CPU() c = CPU()
c.a = 0x17 c.a = 0x17
c.b = 0x42 c.b = 0x42
dcpu_16.ADD(c, c._pointer(0x0), c._pointer(0x1)) dcpu_16.ADD(c, c._pointer(0x0), c._pointer(0x1))
self.assertEqual(c.a, 0x17+0x42) self.assertEqual(c.a, 0x17+0x42)
self.assertEqual(c.b, 0x42) self.assertEqual(c.b, 0x42)
self.assertEqual(c.o, 0x0) self.assertEqual(c.ex, 0x0)
def test_SUB(self): def test_SUB(self):
dcpu_16.SET.opcode = (0x3,) self.assertEqual(dcpu_16.SUB.opcode, (0x03,))
c = CPU() c = CPU()
c.a = 0x42 c.a = 0x42
c.b = 0x17 c.b = 0x17
dcpu_16.SUB(c, c._pointer(0x0), c._pointer(0x1)) dcpu_16.SUB(c, c._pointer(0x0), c._pointer(0x1))
self.assertEqual(c.a, 0x42-0x17) self.assertEqual(c.a, 0x42-0x17)
self.assertEqual(c.b, 0x17) self.assertEqual(c.b, 0x17)
self.assertEqual(c.o, 0x0) self.assertEqual(c.ex, 0x0)
def test_MUL(self): def test_MUL(self):
dcpu_16.SET.opcode = (0x4,) self.assertEqual(dcpu_16.MUL.opcode, (0x04,))
c = CPU() c = CPU()
c.a = 0x17 c.a = 0x17
c.b = 0x42 c.b = 0x42
dcpu_16.MUL(c, c._pointer(0x0), c._pointer(0x1)) dcpu_16.MUL(c, c._pointer(0x0), c._pointer(0x1))
self.assertEqual(c.a, 0x17*0x42) self.assertEqual(c.a, 0x17*0x42)
self.assertEqual(c.b, 0x42) self.assertEqual(c.b, 0x42)
self.assertEqual(c.o, 0x0) 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): def test_DIV(self):
dcpu_16.SET.opcode = (0x5,) self.assertEqual(dcpu_16.DIV.opcode, (0x06,))
c = CPU() c = CPU()
c.a = 0x17 c.a = 0x17
c.b = 0x42 c.b = 0x42
dcpu_16.DIV(c, c._pointer(0x0), c._pointer(0x1)) dcpu_16.DIV(c, c._pointer(0x0), c._pointer(0x1))
self.assertEqual(c.a, 0x17/0x42) self.assertEqual(c.a, 0x17/0x42)
self.assertEqual(c.b, 0x42) self.assertEqual(c.b, 0x42)
self.assertEqual(c.o, ((0x17<<16)/0x42)&0xFFFF) 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): def test_MOD(self):
dcpu_16.SET.opcode = (0x6,) self.assertEqual(dcpu_16.MOD.opcode, (0x08,))
c = CPU() c = CPU()
c.a = 0x17 c.a = 0x17
c.b = 0x42 c.b = 0x42
dcpu_16.MOD(c, c._pointer(0x0), c._pointer(0x1)) dcpu_16.MOD(c, c._pointer(0x0), c._pointer(0x1))
self.assertEqual(c.a, 0x17%0x42) self.assertEqual(c.a, 0x17%0x42)
self.assertEqual(c.b, 0x42) self.assertEqual(c.b, 0x42)
self.assertEqual(c.o, 0x0) self.assertEqual(c.ex, 0x0)
def test_SHL(self): def test_MDI(self):
dcpu_16.SET.opcode = (0x7,) self.assertEqual(dcpu_16.MDI.opcode, (0x09,))
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.o, 0x0)
def test_SHR(self):
dcpu_16.SET.opcode = (0x8,)
c = CPU() c = CPU()
c.a = 0x17 c.a = 0x17
c.b = 0x42 c.b = 0x42
dcpu_16.SHR(c, c._pointer(0x0), c._pointer(0x1)) dcpu_16.MOD(c, c._pointer(0x0), c._pointer(0x1))
self.assertEqual(c.a, 0x17>>0x42) self.assertEqual(c.a, 0x17%0x42)
self.assertEqual(c.b, 0x42) self.assertEqual(c.b, 0x42)
self.assertEqual(c.o, 0x0) self.assertEqual(c.ex, 0x0)
def test_AND(self): def test_AND(self):
dcpu_16.SET.opcode = (0x9,) self.assertEqual(dcpu_16.AND.opcode, (0x0A,))
c = CPU() c = CPU()
c.a = 0x17 c.a = 0x17
c.b = 0x42 c.b = 0x42
dcpu_16.AND(c, c._pointer(0x0), c._pointer(0x1)) dcpu_16.AND(c, c._pointer(0x0), c._pointer(0x1))
self.assertEqual(c.a, 0x17&0x42) self.assertEqual(c.a, 0x17&0x42)
self.assertEqual(c.b, 0x42) self.assertEqual(c.b, 0x42)
self.assertEqual(c.o, 0x0) self.assertEqual(c.ex, 0x0)
def test_BOR(self): def test_BOR(self):
dcpu_16.SET.opcode = (0xA,) self.assertEqual(dcpu_16.BOR.opcode, (0x0B,))
c = CPU() c = CPU()
c.a = 0x17 c.a = 0x17
c.b = 0x42 c.b = 0x42
dcpu_16.BOR(c, c._pointer(0x0), c._pointer(0x1)) dcpu_16.BOR(c, c._pointer(0x0), c._pointer(0x1))
self.assertEqual(c.a, 0x17|0x42) self.assertEqual(c.a, 0x17|0x42)
self.assertEqual(c.b, 0x42) self.assertEqual(c.b, 0x42)
self.assertEqual(c.o, 0x0) self.assertEqual(c.ex, 0x0)
def test_XOR(self): def test_XOR(self):
dcpu_16.SET.opcode = (0xB,) self.assertEqual(dcpu_16.XOR.opcode, (0x0C,))
c = CPU() c = CPU()
c.a = 0x17 c.a = 0x17
c.b = 0x42 c.b = 0x42
dcpu_16.XOR(c, c._pointer(0x0), c._pointer(0x1)) dcpu_16.XOR(c, c._pointer(0x0), c._pointer(0x1))
self.assertEqual(c.a, 0x17^0x42) self.assertEqual(c.a, 0x17^0x42)
self.assertEqual(c.b, 0x42) self.assertEqual(c.b, 0x42)
self.assertEqual(c.o, 0x0) 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): def test_IFE(self):
dcpu_16.SET.opcode = (0xC,) self.assertEqual(dcpu_16.IFE.opcode, (0x12,))
c = CPU() c = CPU()
c.a = 0x17 c.a = 0x17
@ -133,7 +187,7 @@ class TestInstructions(unittest.TestCase):
self.assertEqual(c.skip, False) self.assertEqual(c.skip, False)
def test_IFN(self): def test_IFN(self):
dcpu_16.SET.opcode = (0xD,) self.assertEqual(dcpu_16.IFN.opcode, (0x13,))
c = CPU() c = CPU()
c.a = 0x17 c.a = 0x17
@ -147,7 +201,7 @@ class TestInstructions(unittest.TestCase):
self.assertEqual(c.skip, True) self.assertEqual(c.skip, True)
def test_IFG(self): def test_IFG(self):
dcpu_16.SET.opcode = (0xE,) self.assertEqual(dcpu_16.IFG.opcode, (0x14,))
c = CPU() c = CPU()
c.a = 0x41 c.a = 0x41
@ -165,22 +219,8 @@ class TestInstructions(unittest.TestCase):
dcpu_16.IFG(c, c._pointer(0x0), c._pointer(0x1)) dcpu_16.IFG(c, c._pointer(0x0), c._pointer(0x1))
self.assertEqual(c.skip, False) self.assertEqual(c.skip, False)
def test_IFB(self):
dcpu_16.SET.opcode = (0xF,)
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_JSR(self): def test_JSR(self):
dcpu_16.JSR.opcode = (0x0, 0x1) self.assertEqual(dcpu_16.JSR.opcode, (0x00, 0x01))
c = CPU() c = CPU()
c.a = 0xDEAD c.a = 0xDEAD
@ -203,7 +243,7 @@ class TestCPU(unittest.TestCase):
for r in c.r: for r in c.r:
self.assertEqual(r, 0) self.assertEqual(r, 0)
self.assertEqual(c.pc, 0) self.assertEqual(c.pc, 0)
self.assertEqual(c.o, 0) self.assertEqual(c.ex, 0)
self.assertEqual(c.sp, 0) self.assertEqual(c.sp, 0)
self.assertEqual(c.skip, False) self.assertEqual(c.skip, False)
self.assertEqual(c.pc, 0) self.assertEqual(c.pc, 0)
@ -219,7 +259,7 @@ class TestCPU(unittest.TestCase):
for r in c.r: for r in c.r:
self.assertEqual(r, 0) self.assertEqual(r, 0)
self.assertEqual(c.pc, 0) self.assertEqual(c.pc, 0)
self.assertEqual(c.o, 0) self.assertEqual(c.ex, 0)
self.assertEqual(c.sp, 0) self.assertEqual(c.sp, 0)
self.assertEqual(c.skip, False) self.assertEqual(c.skip, False)
self.assertEqual(c.pc, 0) self.assertEqual(c.pc, 0)
@ -239,13 +279,7 @@ class TestCPUWithPrograms(unittest.TestCase):
def test_spec_demo(self): def test_spec_demo(self):
c = CPU() c = CPU()
data = [ c.load_m(data=dcpu_16.spec_demo)
0x7c01, 0x0030, 0x7de1, 0x1000, 0x0020, 0x7803, 0x1000, 0xc00d,
0x7dc1, 0x001a, 0xa861, 0x7c01, 0x2000, 0x2161, 0x2000, 0x8463,
0x806d, 0x7dc1, 0x000d, 0x9031, 0x7c10, 0x0018, 0x7dc1, 0x001a,
0x9037, 0x61c1, 0x7dc1, 0x001a, 0x0000, 0x0000, 0x0000, 0x0000,
]
c.load_m(data=data)
self.assertEqual(c.pc, 0) self.assertEqual(c.pc, 0)
c.step() # SET A, 0x30 c.step() # SET A, 0x30