Skip to content

Instantly share code, notes, and snippets.

@pervognsen
Last active September 22, 2018 19:40
Show Gist options
  • Save pervognsen/435f6ebde3b790a676559ecf14b49112 to your computer and use it in GitHub Desktop.
Save pervognsen/435f6ebde3b790a676559ecf14b49112 to your computer and use it in GitHub Desktop.
pc = 0
mem = [0] * 2**16
def load(addr):
if addr < io_base:
return mem[addr]
else:
return io_read(addr)
def store(addr, data):
if addr < io_base:
mem[addr] = data
else:
io_write(addr, data)
def load_word(addr):
return mem[addr] | (mem[(addr + 1) & 0xFFFF] << 4) | (mem[(addr + 2) & 0xFFFF] << 8) | (mem[(addr + 3) & 0xFFFF] << 12)
def step():
global pc
dest, src, pc = load_word(pc), load_word(pc + 4), load_word(pc + 8)
store(dest, load(src))
class HaltException(Exception):
def __init__(self, data):
super().__init__()
self.data = data
class BreakException(Exception):
def __init__(self, data):
super().__init__()
self.data = data
io_base = 0xFF00
IO_GET, IO_PUT, IO_HALT, IO_BREAK = range(io_base, io_base + 4)
def io_read(addr):
if addr == IO_GET:
while True:
try:
x = int(input("> "), 16)
if 0 <= x <= 0xFF:
return x
except ValueError:
pass
print("Error: Expected hex digit")
def io_write(addr, data):
if addr == IO_PUT:
print("%x" % data)
elif addr == IO_HALT:
raise HaltException(data)
elif addr == IO_BREAK:
raise BreakException(data)
here = 0
segs = {'code': 0, 'data': 0x4000}
seg = 'code'
def set_seg(new_seg):
global seg, here
segs[seg] = here
seg = new_seg
here = segs[seg]
def code_seg():
set_seg('code')
def data_seg():
set_seg('data')
def align(n):
global here
here = ((here + n - 1) // n) * n
return here
def nibble(x):
global here
assert 0 <= x <= 0xF
addr = here
mem[here] = x
here += 1
return addr
def byte(x):
assert 0 <= x <= 0xFF
addr = nibble(x & 0xF)
nibble((x >> 4) & 0xF)
return addr
def word(x):
assert 0 <= x <= 0xFFFF
addr = byte(x & 0xFF)
byte((x >> 8) & 0xFF)
return addr
def move_jump(dest, src, next):
addr = word(dest)
word(src)
word(next)
return addr
def move(dest, src):
return move_jump(dest, src, here + 12)
def jump(next):
return move_jump(0, 0, next)
def nop():
return move(0, 0)
def unary_lookup(dest, src, table):
move(here + 12 + 4, src)
move(dest, table)
def binary_lookup(dest, src1, src2, table):
move(here + 24 + 4, src1)
move(here + 12 + 5, src2)
move(dest, table)
def unary(op):
table = align(16)
for x in range(16):
nibble(op(x) & 0xF)
return lambda dest, src: unary_lookup(dest, src, table)
def binary(op):
table = align(16 * 16)
for y in range(16):
for x in range(16):
nibble(op(x, y) & 0xF)
return lambda dest, src1, src2: binary_lookup(dest, src1, src2, table)
def conditional_constant(dest, flag, true_value, false_value):
data_seg()
op = unary(lambda x: true_value if x else false_value)
code_seg()
op(dest, flag)
def conditional_jump(flag, true_target, false_target=None):
end = here + 4*24 + 12
if false_target is None:
false_target = end
for i in range(4):
conditional_constant(end - 4 + i, flag, true_target >> (4 * i), false_target >> (4 * i))
jump(false_target)
data_seg()
op_add = binary(lambda x, y: x + y)
op_not = unary(lambda x: ~x)
a, b, c, d = [nibble(0) for i in range(4)]
code_seg()
start = here
move(a, IO_GET)
op_not(b, a)
move(IO_PUT, b)
move(a, IO_GET)
move(b, IO_GET)
op_add(c, a, b)
move(IO_PUT, c)
move(a, IO_GET)
conditional_jump(a, start)
move(IO_HALT, 0)
try:
while True:
step()
except HaltException:
print("Halted")
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment