mirror of
https://github.com/lloeki/python-dcpu_16.git
synced 2025-12-06 09:54:39 +01:00
since it's more advanced, using test.py
This commit is contained in:
parent
ff63a59cac
commit
e78f4b8af8
2 changed files with 343 additions and 479 deletions
458
dcpu_16.py
458
dcpu_16.py
|
|
@ -1,136 +1,364 @@
|
||||||
# System width
|
from __future__ import print_function, division
|
||||||
|
|
||||||
|
def log(string):
|
||||||
|
print(" << %s" % string)
|
||||||
|
|
||||||
|
#http://0x10c.com/doc/dcpu-16.txt
|
||||||
|
spec = '1.1'
|
||||||
|
|
||||||
w = 16
|
w = 16
|
||||||
wmask = 2**16-1
|
wmask = 2**w-1
|
||||||
|
|
||||||
|
literals = [l for l in xrange(0, 0x20)]
|
||||||
|
|
||||||
|
opcode_map = {}
|
||||||
|
valcode_map = {}
|
||||||
|
|
||||||
|
|
||||||
|
class opcode(object):
|
||||||
|
def __init__(self, *opcode):
|
||||||
|
self.opcode = opcode
|
||||||
|
|
||||||
|
def __call__(self, f):
|
||||||
|
_opcode_f = f
|
||||||
|
_opcode_f.opcode = self.opcode
|
||||||
|
opcode_map[self.opcode] = _opcode_f
|
||||||
|
return _opcode_f
|
||||||
|
|
||||||
|
|
||||||
|
class valcode(object):
|
||||||
|
def __init__(self, valcode):
|
||||||
|
self.valcode = valcode
|
||||||
|
|
||||||
|
def __call__(self, f):
|
||||||
|
_valcode_f = f
|
||||||
|
_valcode_f.valcode = self.valcode
|
||||||
|
try:
|
||||||
|
for code in self.valcode:
|
||||||
|
# currify with (bound) code
|
||||||
|
valcode_map[code] = lambda c, code=code: _valcode_f(c, code)
|
||||||
|
valcode_map[code].__name__ = '%s(code=0x%02X)' % (_valcode_f.__name__, code)
|
||||||
|
except TypeError:
|
||||||
|
valcode_map[self.valcode] = _valcode_f
|
||||||
|
return _valcode_f
|
||||||
|
|
||||||
|
|
||||||
|
@opcode(0x0, 0x01)
|
||||||
|
def JSR(c, a):
|
||||||
|
"""pushes the address of the next instruction to the stack, then sets PC to a"""
|
||||||
|
#pushnext
|
||||||
|
c.pc = c[a]
|
||||||
|
|
||||||
|
@opcode(0x1)
|
||||||
|
def SET(c, a, b):
|
||||||
|
"""sets a to b"""
|
||||||
|
c[a] = c[b]
|
||||||
|
|
||||||
|
@opcode(0x2)
|
||||||
|
def ADD(c, a, b):
|
||||||
|
"""sets a to a+b, sets O to 0x0001 if there's an overflow"""
|
||||||
|
res = (c[a] + c[b])
|
||||||
|
if res > wmask:
|
||||||
|
c.o = 0x0001
|
||||||
|
res = res & wmask
|
||||||
|
c[a] = res
|
||||||
|
|
||||||
|
@opcode(0x3)
|
||||||
|
def SUB(c, a, b):
|
||||||
|
"""sets a to a-b, sets O to 0xFFFF if there's an underflow"""
|
||||||
|
res = (c[a] - c[b])
|
||||||
|
if res & (wmask+1):
|
||||||
|
c.o = 0xFFFF
|
||||||
|
res = res & wmask
|
||||||
|
c[a] = res
|
||||||
|
|
||||||
|
@opcode(0x4)
|
||||||
|
def MUL(c, a, b):
|
||||||
|
"""sets a to a*b, sets O to ((a*b)>>16)&0xFFFF"""
|
||||||
|
res = (c[a] * c[b])
|
||||||
|
c.o = ((c[a] * c[b]) >> w) & wmask
|
||||||
|
res = res & wmask
|
||||||
|
c[a] = res
|
||||||
|
|
||||||
|
@opcode(0x5)
|
||||||
|
def DIV(c, a, b):
|
||||||
|
"""sets a to a/b, sets O to ((a<<16)/b)&0xFFFF"""
|
||||||
|
res = c[a] / c[b]
|
||||||
|
c.o = ((c[a] << w) / c[b]) & wmask
|
||||||
|
c[a] = res
|
||||||
|
|
||||||
|
@opcode(0x6)
|
||||||
|
def MOD(c, a, b):
|
||||||
|
"""sets a to a%b. if b==0, sets a to 0 instead"""
|
||||||
|
if c[b]==0:
|
||||||
|
res = 0
|
||||||
|
else:
|
||||||
|
res = c[a] % c[b]
|
||||||
|
c[a] = res
|
||||||
|
|
||||||
|
@opcode(0x7)
|
||||||
|
def SHL(c, a, b):
|
||||||
|
"""sets a to a<<b. sets O to ((a<<b)>>16)&0xFFFF"""
|
||||||
|
res = (c[a] << c[b])
|
||||||
|
c.o = ((c[a] << c[b]) >> w) & wmask
|
||||||
|
res = res & wmask
|
||||||
|
c[a] = res
|
||||||
|
|
||||||
|
@opcode(0x8)
|
||||||
|
def SHR(c, a, b):
|
||||||
|
"""sets a to a>>b. sets O to ((a>>16)>>b)&0xFFFF"""
|
||||||
|
res = (c[a] >> c[b])
|
||||||
|
c.o = ((c[a] >> w) >> c[b]) & wmask
|
||||||
|
res = res & wmask
|
||||||
|
c[a] = res
|
||||||
|
|
||||||
|
@opcode(0x9)
|
||||||
|
def AND(c, a, b):
|
||||||
|
"""sets a to a&b"""
|
||||||
|
res = c[a] & c[b]
|
||||||
|
c[a] = res
|
||||||
|
|
||||||
|
@opcode(0xA)
|
||||||
|
def BOR(c, a, b):
|
||||||
|
"""sets a to a|b"""
|
||||||
|
res = c[a] | c[b]
|
||||||
|
c[a] = res
|
||||||
|
|
||||||
|
@opcode(0xB)
|
||||||
|
def XOR(c, a, b):
|
||||||
|
"""sets a to a^b"""
|
||||||
|
res = c[a] ^ c[b]
|
||||||
|
c[a] = res
|
||||||
|
|
||||||
|
@opcode(0xC)
|
||||||
|
def IFE(c, a, b):
|
||||||
|
"""performs next instruction only if a==b"""
|
||||||
|
if c[a] == c[b]:
|
||||||
|
c.skip = True
|
||||||
|
|
||||||
|
@opcode(0xD)
|
||||||
|
def IFN(c, a, b):
|
||||||
|
"""performs next instruction only if a!=b"""
|
||||||
|
if c[a] != c[b]:
|
||||||
|
c.skip = True
|
||||||
|
|
||||||
|
@opcode(0xE)
|
||||||
|
def IFG(c, a, b):
|
||||||
|
"""performs next instruction only if a>b"""
|
||||||
|
if c[a] > c[b]:
|
||||||
|
c.skip = True
|
||||||
|
|
||||||
|
@opcode(0xF)
|
||||||
|
def IFB(c, a, b):
|
||||||
|
"""performs next instruction only if (a&b)!=0"""
|
||||||
|
if (c[a] & c[b]) != 0:
|
||||||
|
c.skip = True
|
||||||
|
|
||||||
|
|
||||||
|
def make_pointer(c, codestr):
|
||||||
|
"""creates a pointer func that evaluates codestr"""
|
||||||
|
def getter(c=c):
|
||||||
|
return eval("%s" % codestr)
|
||||||
|
def setter(data, c=c):
|
||||||
|
exec("%s = %r" % (codestr, data)) in {}, {'c': c, 'data': data}
|
||||||
|
pointer = getter
|
||||||
|
pointer.codestr = codestr
|
||||||
|
pointer.set = setter
|
||||||
|
return pointer
|
||||||
|
|
||||||
|
def pointerize(f):
|
||||||
|
"""wraps a function that generates a codestr to create a pointer"""
|
||||||
|
if f.func_code.co_argcount == 1:
|
||||||
|
ptrz = lambda c: make_pointer(c, f(c))
|
||||||
|
elif f.func_code.co_argcount == 2:
|
||||||
|
ptrz = lambda c, code: make_pointer(c, f(c, code))
|
||||||
|
else:
|
||||||
|
raise Exception('%s has too many arguments' % f.__name__)
|
||||||
|
ptrz.__name__ = 'ptr_to_%s' % f.__name__
|
||||||
|
ptrz.__doc__ = f.__doc__
|
||||||
|
return ptrz
|
||||||
|
|
||||||
|
@valcode(range(0x00, 0x08))
|
||||||
|
@pointerize
|
||||||
|
def register(c, code):
|
||||||
|
"""register"""
|
||||||
|
v = "c.r[%r]" % code
|
||||||
|
log(v)
|
||||||
|
return v
|
||||||
|
|
||||||
|
@valcode(range(0x08, 0x10))
|
||||||
|
@pointerize
|
||||||
|
def register_value(c, code):
|
||||||
|
"""[register]"""
|
||||||
|
v = "c.m[c.r[%r-0x07]]" % code
|
||||||
|
log(v)
|
||||||
|
return v
|
||||||
|
|
||||||
|
@valcode(range(0x10, 0x18))
|
||||||
|
@pointerize
|
||||||
|
def next_word_plus_register_value(c, code):
|
||||||
|
"""[next word + register]"""
|
||||||
|
v = "c.m[%r + %r-0x0f]" % (c.m[c.pc], code)
|
||||||
|
log(v)
|
||||||
|
c.pc += 1
|
||||||
|
return v
|
||||||
|
|
||||||
|
@valcode(0x18)
|
||||||
|
@pointerize
|
||||||
|
def pop(c):
|
||||||
|
"""POP / [SP++]"""
|
||||||
|
v = "c.m[%r]" % c.sp
|
||||||
|
log(v)
|
||||||
|
c.sp += 1
|
||||||
|
return v
|
||||||
|
|
||||||
|
@valcode(0x19)
|
||||||
|
@pointerize
|
||||||
|
def peek(c):
|
||||||
|
"""PEEK / [SP]"""
|
||||||
|
v = "c.m[%r]" % c.sp
|
||||||
|
log(v)
|
||||||
|
return v
|
||||||
|
|
||||||
|
@valcode(0x1A)
|
||||||
|
@pointerize
|
||||||
|
def push(c):
|
||||||
|
"""PUSH / [--SP]"""
|
||||||
|
c.sp -= 1
|
||||||
|
v = "c.m[%r]" % c.sp
|
||||||
|
log(v)
|
||||||
|
return v
|
||||||
|
|
||||||
|
@valcode(0x1B)
|
||||||
|
@pointerize
|
||||||
|
def stack_pointer(c):
|
||||||
|
"""stack pointer"""
|
||||||
|
v = "c.sp"
|
||||||
|
log(v)
|
||||||
|
return v
|
||||||
|
|
||||||
|
@valcode(0x1C)
|
||||||
|
@pointerize
|
||||||
|
def program_counter(c):
|
||||||
|
"""program counter"""
|
||||||
|
v = "c.pc"
|
||||||
|
log(v)
|
||||||
|
return v
|
||||||
|
|
||||||
|
@valcode(0x1D)
|
||||||
|
@pointerize
|
||||||
|
def overflow(c):
|
||||||
|
"""overflow"""
|
||||||
|
v = "c.o"
|
||||||
|
log(v)
|
||||||
|
return v
|
||||||
|
|
||||||
|
@valcode(0x1E)
|
||||||
|
@pointerize
|
||||||
|
def next_word_value(c):
|
||||||
|
"""[next_word]"""
|
||||||
|
v = "c.m[%r]" % c.m[c.pc]
|
||||||
|
c.pc += 1
|
||||||
|
log(v)
|
||||||
|
return v
|
||||||
|
|
||||||
|
@valcode(0x1F)
|
||||||
|
@pointerize
|
||||||
|
def next_word(c):
|
||||||
|
"""next_word (literal)"""
|
||||||
|
v = "c.m[%r]" % c.pc
|
||||||
|
c.pc += 1
|
||||||
|
log(v)
|
||||||
|
return v
|
||||||
|
|
||||||
|
@valcode(range(0x20, 0x40))
|
||||||
|
@pointerize
|
||||||
|
def literal(c, code):
|
||||||
|
"""literal value 0x00-0x1F (literal)"""
|
||||||
|
v = "%r" % (code - 0x20)
|
||||||
|
log(v)
|
||||||
|
return v
|
||||||
|
|
||||||
# Literal values
|
|
||||||
literal = xrange(0x00, 0x20)
|
|
||||||
|
|
||||||
opcodes = [
|
|
||||||
'nbi',
|
|
||||||
'SET',
|
|
||||||
'ADD',
|
|
||||||
'SUB',
|
|
||||||
'MUL',
|
|
||||||
'DIV',
|
|
||||||
'MOD',
|
|
||||||
'SHL',
|
|
||||||
'SHR',
|
|
||||||
'AND',
|
|
||||||
'BOR',
|
|
||||||
'XOR',
|
|
||||||
'IFE',
|
|
||||||
'IFN',
|
|
||||||
'IFG',
|
|
||||||
'IFB',
|
|
||||||
]
|
|
||||||
|
|
||||||
class CPU(object):
|
class CPU(object):
|
||||||
|
def __init__(c, debug=False):
|
||||||
class Ops(object):
|
|
||||||
def SET(c, a, b):
|
|
||||||
return None
|
|
||||||
def ADD(c, a, b):
|
|
||||||
return None
|
|
||||||
def SUB(c, a, b):
|
|
||||||
return None
|
|
||||||
def MUL(c, a, b):
|
|
||||||
return None
|
|
||||||
def DIV(c, a, b):
|
|
||||||
return None
|
|
||||||
def MOD(c, a, b):
|
|
||||||
return None
|
|
||||||
def SHL(c, a, b):
|
|
||||||
return (a << b) & wmask
|
|
||||||
def SHR(c, a, b):
|
|
||||||
return (a >> b)
|
|
||||||
def AND(c, a, b):
|
|
||||||
return a & b
|
|
||||||
def BOR(c, a, b):
|
|
||||||
return a | b
|
|
||||||
def XOR(c, a, b):
|
|
||||||
return a ^ b
|
|
||||||
def IFE(c, a, b):
|
|
||||||
return a == b
|
|
||||||
def IFN(c, a, b):
|
|
||||||
return a != b
|
|
||||||
def IFG(c, a, b):
|
|
||||||
return a > b
|
|
||||||
def IFB(c, a, b):
|
|
||||||
return (a & b) != 0
|
|
||||||
|
|
||||||
def __init__(c):
|
|
||||||
c.reset()
|
|
||||||
c.clear()
|
c.clear()
|
||||||
|
c.reset()
|
||||||
|
c.debug = debug
|
||||||
|
|
||||||
def reset(c):
|
def reset(c):
|
||||||
"""Reset CPU"""
|
"""reset CPU"""
|
||||||
c.r = [0 for _ in xrange(0, w)]
|
c.r = [0 for _ in xrange(0, 8)]
|
||||||
c.pc = 0
|
c.pc = 0x0000
|
||||||
c.sp = 0
|
c.sp = 0x0000
|
||||||
c.o = False
|
c.o = 0x0000
|
||||||
c.skip = False
|
c.skip = False
|
||||||
|
|
||||||
def clear(c):
|
def clear(c):
|
||||||
"""Clear memory"""
|
"""clear memory"""
|
||||||
c.m = [0 for _ in xrange(0, 2**w)]
|
c.m = [0 for _ in xrange(0, 2**w)]
|
||||||
|
|
||||||
def __getitem__(c, addr):
|
def _pointer(c, code):
|
||||||
"""Read value at memory address"""
|
"""get pointer to value code"""
|
||||||
return c.m[addr]
|
try:
|
||||||
|
return valcode_map[code](c)
|
||||||
|
except KeyError:
|
||||||
|
raise Exception("Invalid value code")
|
||||||
|
|
||||||
def __setitem__(c, addr, value):
|
def __getitem__(c, code):
|
||||||
"""Write value at memory address"""
|
"""get pointer to value"""
|
||||||
c.m[addr] = value
|
return c._pointer(code)()
|
||||||
|
|
||||||
def next_word(c):
|
def __setitem__(c, code, value):
|
||||||
val = c[c.pc]
|
"""set value at pointer"""
|
||||||
|
c._pointer(code).set(value)
|
||||||
|
|
||||||
|
def step(c):
|
||||||
|
"""start handling [PC]"""
|
||||||
|
word = c.m[c.pc]
|
||||||
c.pc += 1
|
c.pc += 1
|
||||||
return val
|
opcode = word & 0xF
|
||||||
|
try:
|
||||||
def dispatch_op(c):
|
op = opcode_map[(opcode,)]
|
||||||
|
log(op.__name__)
|
||||||
def get_opcode(word):
|
except KeyError:
|
||||||
return word & 0xF
|
raise Exception('Invalid opcode %01X at PC=%04X' % (opcode, c.pc))
|
||||||
def get_a(word):
|
a = word >> 4 & 0x3F
|
||||||
return (word >> 4) & 0x3F
|
b = word >> 10 & 0x3F
|
||||||
def get_b(word):
|
|
||||||
return (word >> 10) & 0x3F
|
|
||||||
|
|
||||||
def get_op(word):
|
|
||||||
getattr(CPU.Ops, opcodes[get_opcode(word)])
|
|
||||||
|
|
||||||
def is_nbi(opcode):
|
|
||||||
return opcode == 0x0
|
|
||||||
def is_set(opcode):
|
|
||||||
return 0x0 < opcode <= 0xb
|
|
||||||
def is_skip(opcode):
|
|
||||||
return 0xb < opcode <= 0xf
|
|
||||||
def set_a(value):
|
|
||||||
pass
|
|
||||||
|
|
||||||
word = c.next_word()
|
|
||||||
if c.skip:
|
if c.skip:
|
||||||
c.skip = False
|
c.skip = False
|
||||||
return
|
|
||||||
|
|
||||||
opcode = get_opcode(word)
|
|
||||||
if is_nbi(opcode):
|
|
||||||
pass
|
|
||||||
elif is_set(opcode):
|
|
||||||
set_a(get_op(opcode)())
|
|
||||||
elif is_skip(opcode):
|
|
||||||
if not get_op(opcode)():
|
|
||||||
c.skip = True
|
|
||||||
else:
|
else:
|
||||||
raise OpcodeError(c.pc, opcode)
|
op(c, a, b)
|
||||||
|
if c.debug:
|
||||||
|
log(c.dump_r())
|
||||||
|
|
||||||
|
def dump_r(c):
|
||||||
|
"""human-readable register status"""
|
||||||
|
return " ".join( "%s=%04X" %
|
||||||
|
(["A", "B", "C",
|
||||||
|
"X", "Y", "Z",
|
||||||
|
"I", "J",
|
||||||
|
"PC", "SP", "O",
|
||||||
|
][i],
|
||||||
|
(c.r + [c.pc, c.sp, c.o])[i])
|
||||||
|
for i in range(11))
|
||||||
|
|
||||||
|
def load_m(c, io=None):
|
||||||
|
"""load data in memory"""
|
||||||
|
# TODO: load from io object
|
||||||
|
data = [
|
||||||
|
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,
|
||||||
|
]
|
||||||
|
for i in xrange(len(data)):
|
||||||
|
c.m[i] = data[i]
|
||||||
|
|
||||||
|
def dump_m(c, io):
|
||||||
|
"""dump memory data"""
|
||||||
|
# TODO: save to io object
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
class OpcodeError(Exception):
|
|
||||||
def __init__(self, addr, data):
|
|
||||||
self.addr = addr
|
|
||||||
self.data = data
|
|
||||||
|
|
||||||
def __str__(self):
|
|
||||||
return "Invalid opcode at %s: '%s'" % (self.addr, self.data)
|
|
||||||
|
|
||||||
|
|
|
||||||
364
test.py
364
test.py
|
|
@ -1,364 +0,0 @@
|
||||||
from __future__ import print_function, division
|
|
||||||
|
|
||||||
def log(string):
|
|
||||||
print(" << %s" % string)
|
|
||||||
|
|
||||||
#http://0x10c.com/doc/dcpu-16.txt
|
|
||||||
spec = '1.1'
|
|
||||||
|
|
||||||
w = 16
|
|
||||||
wmask = 2**w-1
|
|
||||||
|
|
||||||
literals = [l for l in xrange(0, 0x20)]
|
|
||||||
|
|
||||||
opcode_map = {}
|
|
||||||
valcode_map = {}
|
|
||||||
|
|
||||||
|
|
||||||
class opcode(object):
|
|
||||||
def __init__(self, *opcode):
|
|
||||||
self.opcode = opcode
|
|
||||||
|
|
||||||
def __call__(self, f):
|
|
||||||
_opcode_f = f
|
|
||||||
_opcode_f.opcode = self.opcode
|
|
||||||
opcode_map[self.opcode] = _opcode_f
|
|
||||||
return _opcode_f
|
|
||||||
|
|
||||||
|
|
||||||
class valcode(object):
|
|
||||||
def __init__(self, valcode):
|
|
||||||
self.valcode = valcode
|
|
||||||
|
|
||||||
def __call__(self, f):
|
|
||||||
_valcode_f = f
|
|
||||||
_valcode_f.valcode = self.valcode
|
|
||||||
try:
|
|
||||||
for code in self.valcode:
|
|
||||||
# currify with (bound) code
|
|
||||||
valcode_map[code] = lambda c, code=code: _valcode_f(c, code)
|
|
||||||
valcode_map[code].__name__ = '%s(code=0x%02X)' % (_valcode_f.__name__, code)
|
|
||||||
except TypeError:
|
|
||||||
valcode_map[self.valcode] = _valcode_f
|
|
||||||
return _valcode_f
|
|
||||||
|
|
||||||
|
|
||||||
@opcode(0x0, 0x01)
|
|
||||||
def JSR(c, a):
|
|
||||||
"""pushes the address of the next instruction to the stack, then sets PC to a"""
|
|
||||||
#pushnext
|
|
||||||
c.pc = c[a]
|
|
||||||
|
|
||||||
@opcode(0x1)
|
|
||||||
def SET(c, a, b):
|
|
||||||
"""sets a to b"""
|
|
||||||
c[a] = c[b]
|
|
||||||
|
|
||||||
@opcode(0x2)
|
|
||||||
def ADD(c, a, b):
|
|
||||||
"""sets a to a+b, sets O to 0x0001 if there's an overflow"""
|
|
||||||
res = (c[a] + c[b])
|
|
||||||
if res > wmask:
|
|
||||||
c.o = 0x0001
|
|
||||||
res = res & wmask
|
|
||||||
c[a] = res
|
|
||||||
|
|
||||||
@opcode(0x3)
|
|
||||||
def SUB(c, a, b):
|
|
||||||
"""sets a to a-b, sets O to 0xFFFF if there's an underflow"""
|
|
||||||
res = (c[a] - c[b])
|
|
||||||
if res & (wmask+1):
|
|
||||||
c.o = 0xFFFF
|
|
||||||
res = res & wmask
|
|
||||||
c[a] = res
|
|
||||||
|
|
||||||
@opcode(0x4)
|
|
||||||
def MUL(c, a, b):
|
|
||||||
"""sets a to a*b, sets O to ((a*b)>>16)&0xFFFF"""
|
|
||||||
res = (c[a] * c[b])
|
|
||||||
c.o = ((c[a] * c[b]) >> w) & wmask
|
|
||||||
res = res & wmask
|
|
||||||
c[a] = res
|
|
||||||
|
|
||||||
@opcode(0x5)
|
|
||||||
def DIV(c, a, b):
|
|
||||||
"""sets a to a/b, sets O to ((a<<16)/b)&0xFFFF"""
|
|
||||||
res = c[a] / c[b]
|
|
||||||
c.o = ((c[a] << w) / c[b]) & wmask
|
|
||||||
c[a] = res
|
|
||||||
|
|
||||||
@opcode(0x6)
|
|
||||||
def MOD(c, a, b):
|
|
||||||
"""sets a to a%b. if b==0, sets a to 0 instead"""
|
|
||||||
if c[b]==0:
|
|
||||||
res = 0
|
|
||||||
else:
|
|
||||||
res = c[a] % c[b]
|
|
||||||
c[a] = res
|
|
||||||
|
|
||||||
@opcode(0x7)
|
|
||||||
def SHL(c, a, b):
|
|
||||||
"""sets a to a<<b. sets O to ((a<<b)>>16)&0xFFFF"""
|
|
||||||
res = (c[a] << c[b])
|
|
||||||
c.o = ((c[a] << c[b]) >> w) & wmask
|
|
||||||
res = res & wmask
|
|
||||||
c[a] = res
|
|
||||||
|
|
||||||
@opcode(0x8)
|
|
||||||
def SHR(c, a, b):
|
|
||||||
"""sets a to a>>b. sets O to ((a>>16)>>b)&0xFFFF"""
|
|
||||||
res = (c[a] >> c[b])
|
|
||||||
c.o = ((c[a] >> w) >> c[b]) & wmask
|
|
||||||
res = res & wmask
|
|
||||||
c[a] = res
|
|
||||||
|
|
||||||
@opcode(0x9)
|
|
||||||
def AND(c, a, b):
|
|
||||||
"""sets a to a&b"""
|
|
||||||
res = c[a] & c[b]
|
|
||||||
c[a] = res
|
|
||||||
|
|
||||||
@opcode(0xA)
|
|
||||||
def BOR(c, a, b):
|
|
||||||
"""sets a to a|b"""
|
|
||||||
res = c[a] | c[b]
|
|
||||||
c[a] = res
|
|
||||||
|
|
||||||
@opcode(0xB)
|
|
||||||
def XOR(c, a, b):
|
|
||||||
"""sets a to a^b"""
|
|
||||||
res = c[a] ^ c[b]
|
|
||||||
c[a] = res
|
|
||||||
|
|
||||||
@opcode(0xC)
|
|
||||||
def IFE(c, a, b):
|
|
||||||
"""performs next instruction only if a==b"""
|
|
||||||
if c[a] == c[b]:
|
|
||||||
c.skip = True
|
|
||||||
|
|
||||||
@opcode(0xD)
|
|
||||||
def IFN(c, a, b):
|
|
||||||
"""performs next instruction only if a!=b"""
|
|
||||||
if c[a] != c[b]:
|
|
||||||
c.skip = True
|
|
||||||
|
|
||||||
@opcode(0xE)
|
|
||||||
def IFG(c, a, b):
|
|
||||||
"""performs next instruction only if a>b"""
|
|
||||||
if c[a] > c[b]:
|
|
||||||
c.skip = True
|
|
||||||
|
|
||||||
@opcode(0xF)
|
|
||||||
def IFB(c, a, b):
|
|
||||||
"""performs next instruction only if (a&b)!=0"""
|
|
||||||
if (c[a] & c[b]) != 0:
|
|
||||||
c.skip = True
|
|
||||||
|
|
||||||
|
|
||||||
def make_pointer(c, codestr):
|
|
||||||
"""creates a pointer func that evaluates codestr"""
|
|
||||||
def getter(c=c):
|
|
||||||
return eval("%s" % codestr)
|
|
||||||
def setter(data, c=c):
|
|
||||||
exec("%s = %r" % (codestr, data)) in {}, {'c': c, 'data': data}
|
|
||||||
pointer = getter
|
|
||||||
pointer.codestr = codestr
|
|
||||||
pointer.set = setter
|
|
||||||
return pointer
|
|
||||||
|
|
||||||
def pointerize(f):
|
|
||||||
"""wraps a function that generates a codestr to create a pointer"""
|
|
||||||
if f.func_code.co_argcount == 1:
|
|
||||||
ptrz = lambda c: make_pointer(c, f(c))
|
|
||||||
elif f.func_code.co_argcount == 2:
|
|
||||||
ptrz = lambda c, code: make_pointer(c, f(c, code))
|
|
||||||
else:
|
|
||||||
raise Exception('%s has too many arguments' % f.__name__)
|
|
||||||
ptrz.__name__ = 'ptr_to_%s' % f.__name__
|
|
||||||
ptrz.__doc__ = f.__doc__
|
|
||||||
return ptrz
|
|
||||||
|
|
||||||
@valcode(range(0x00, 0x08))
|
|
||||||
@pointerize
|
|
||||||
def register(c, code):
|
|
||||||
"""register"""
|
|
||||||
v = "c.r[%r]" % code
|
|
||||||
log(v)
|
|
||||||
return v
|
|
||||||
|
|
||||||
@valcode(range(0x08, 0x10))
|
|
||||||
@pointerize
|
|
||||||
def register_value(c, code):
|
|
||||||
"""[register]"""
|
|
||||||
v = "c.m[c.r[%r-0x07]]" % code
|
|
||||||
log(v)
|
|
||||||
return v
|
|
||||||
|
|
||||||
@valcode(range(0x10, 0x18))
|
|
||||||
@pointerize
|
|
||||||
def next_word_plus_register_value(c, code):
|
|
||||||
"""[next word + register]"""
|
|
||||||
v = "c.m[%r + %r-0x0f]" % (c.m[c.pc], code)
|
|
||||||
log(v)
|
|
||||||
c.pc += 1
|
|
||||||
return v
|
|
||||||
|
|
||||||
@valcode(0x18)
|
|
||||||
@pointerize
|
|
||||||
def pop(c):
|
|
||||||
"""POP / [SP++]"""
|
|
||||||
v = "c.m[%r]" % c.sp
|
|
||||||
log(v)
|
|
||||||
c.sp += 1
|
|
||||||
return v
|
|
||||||
|
|
||||||
@valcode(0x19)
|
|
||||||
@pointerize
|
|
||||||
def peek(c):
|
|
||||||
"""PEEK / [SP]"""
|
|
||||||
v = "c.m[%r]" % c.sp
|
|
||||||
log(v)
|
|
||||||
return v
|
|
||||||
|
|
||||||
@valcode(0x1A)
|
|
||||||
@pointerize
|
|
||||||
def push(c):
|
|
||||||
"""PUSH / [--SP]"""
|
|
||||||
c.sp -= 1
|
|
||||||
v = "c.m[%r]" % c.sp
|
|
||||||
log(v)
|
|
||||||
return v
|
|
||||||
|
|
||||||
@valcode(0x1B)
|
|
||||||
@pointerize
|
|
||||||
def stack_pointer(c):
|
|
||||||
"""stack pointer"""
|
|
||||||
v = "c.sp"
|
|
||||||
log(v)
|
|
||||||
return v
|
|
||||||
|
|
||||||
@valcode(0x1C)
|
|
||||||
@pointerize
|
|
||||||
def program_counter(c):
|
|
||||||
"""program counter"""
|
|
||||||
v = "c.pc"
|
|
||||||
log(v)
|
|
||||||
return v
|
|
||||||
|
|
||||||
@valcode(0x1D)
|
|
||||||
@pointerize
|
|
||||||
def overflow(c):
|
|
||||||
"""overflow"""
|
|
||||||
v = "c.o"
|
|
||||||
log(v)
|
|
||||||
return v
|
|
||||||
|
|
||||||
@valcode(0x1E)
|
|
||||||
@pointerize
|
|
||||||
def next_word_value(c):
|
|
||||||
"""[next_word]"""
|
|
||||||
v = "c.m[%r]" % c.m[c.pc]
|
|
||||||
c.pc += 1
|
|
||||||
log(v)
|
|
||||||
return v
|
|
||||||
|
|
||||||
@valcode(0x1F)
|
|
||||||
@pointerize
|
|
||||||
def next_word(c):
|
|
||||||
"""next_word (literal)"""
|
|
||||||
v = "c.m[%r]" % c.pc
|
|
||||||
c.pc += 1
|
|
||||||
log(v)
|
|
||||||
return v
|
|
||||||
|
|
||||||
@valcode(range(0x20, 0x40))
|
|
||||||
@pointerize
|
|
||||||
def literal(c, code):
|
|
||||||
"""literal value 0x00-0x1F (literal)"""
|
|
||||||
v = "%r" % (code - 0x20)
|
|
||||||
log(v)
|
|
||||||
return v
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
class CPU(object):
|
|
||||||
def __init__(c, debug=False):
|
|
||||||
c.clear()
|
|
||||||
c.reset()
|
|
||||||
c.debug = debug
|
|
||||||
|
|
||||||
def reset(c):
|
|
||||||
"""reset CPU"""
|
|
||||||
c.r = [0 for _ in xrange(0, 8)]
|
|
||||||
c.pc = 0x0000
|
|
||||||
c.sp = 0x0000
|
|
||||||
c.o = 0x0000
|
|
||||||
c.skip = False
|
|
||||||
|
|
||||||
def clear(c):
|
|
||||||
"""clear memory"""
|
|
||||||
c.m = [0 for _ in xrange(0, 2**w)]
|
|
||||||
|
|
||||||
def _pointer(c, code):
|
|
||||||
"""get pointer to value code"""
|
|
||||||
try:
|
|
||||||
return valcode_map[code](c)
|
|
||||||
except KeyError:
|
|
||||||
raise Exception("Invalid value code")
|
|
||||||
|
|
||||||
def __getitem__(c, code):
|
|
||||||
"""get pointer to value"""
|
|
||||||
return c._pointer(code)()
|
|
||||||
|
|
||||||
def __setitem__(c, code, value):
|
|
||||||
"""set value at pointer"""
|
|
||||||
c._pointer(code).set(value)
|
|
||||||
|
|
||||||
def step(c):
|
|
||||||
"""start handling [PC]"""
|
|
||||||
word = c.m[c.pc]
|
|
||||||
c.pc += 1
|
|
||||||
opcode = word & 0xF
|
|
||||||
try:
|
|
||||||
op = opcode_map[(opcode,)]
|
|
||||||
log(op.__name__)
|
|
||||||
except KeyError:
|
|
||||||
raise Exception('Invalid opcode %01X at PC=%04X' % (opcode, c.pc))
|
|
||||||
a = word >> 4 & 0x3F
|
|
||||||
b = word >> 10 & 0x3F
|
|
||||||
if c.skip:
|
|
||||||
c.skip = False
|
|
||||||
else:
|
|
||||||
op(c, a, b)
|
|
||||||
if c.debug:
|
|
||||||
log(c.dump_r())
|
|
||||||
|
|
||||||
def dump_r(c):
|
|
||||||
"""human-readable register status"""
|
|
||||||
return " ".join( "%s=%04X" %
|
|
||||||
(["A", "B", "C",
|
|
||||||
"X", "Y", "Z",
|
|
||||||
"I", "J",
|
|
||||||
"PC", "SP", "O",
|
|
||||||
][i],
|
|
||||||
(c.r + [c.pc, c.sp, c.o])[i])
|
|
||||||
for i in range(11))
|
|
||||||
|
|
||||||
def load_m(c, io=None):
|
|
||||||
"""load data in memory"""
|
|
||||||
# TODO: load from io object
|
|
||||||
data = [
|
|
||||||
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,
|
|
||||||
]
|
|
||||||
for i in xrange(len(data)):
|
|
||||||
c.m[i] = data[i]
|
|
||||||
|
|
||||||
def dump_m(c, io):
|
|
||||||
"""dump memory data"""
|
|
||||||
# TODO: save to io object
|
|
||||||
pass
|
|
||||||
|
|
||||||
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue