planckforth/others/planck.py

297 lines
6.5 KiB
Python
Raw Permalink Normal View History

2021-01-04 14:16:12 +01:00
#!/usr/bin/env python3
2021-01-03 15:59:45 +01:00
# planck -
# Copyright (C) 2021 nineties
#
2021-01-05 18:12:47 +01:00
import os
2021-01-03 15:59:45 +01:00
import sys
2021-01-05 07:55:29 +01:00
import operator
from ctypes import c_uint32
2021-01-10 17:24:43 +01:00
import platform
from struct import pack_into, unpack_from
2021-01-10 17:24:43 +01:00
RUNTIME_NAME = "Python {}".format(platform.python_version())
COPYRIGHT = "Copyright (c) 2021 Koichi Nakamura <koichi@idein.jp>"
VERSION = "{}:{}".format(RUNTIME_NAME, COPYRIGHT)
2021-01-05 13:06:03 +01:00
MEMORY_SIZE = 0x40000
memory = bytearray(MEMORY_SIZE)
CELL = 4
STACK_SIZE = 0x400
RSTACK_SIZE = 0x400
2021-01-05 13:06:03 +01:00
HERE_CELL = 0
LATEST_CELL = CELL
2021-01-03 15:59:45 +01:00
sp = MEMORY_SIZE
rp = MEMORY_SIZE - STACK_SIZE
2021-01-03 15:59:45 +01:00
ip = 0
2021-01-05 07:55:29 +01:00
np = 0
2021-01-03 15:59:45 +01:00
2021-12-06 18:11:46 +01:00
ALIGN_MASK = ~(CELL - 1)
2021-01-05 06:22:10 +01:00
def aligned(n):
return (n + CELL - 1) & ALIGN_MASK
2021-01-05 06:22:10 +01:00
2021-01-05 07:55:29 +01:00
def align():
write(HERE_CELL, aligned(read(HERE_CELL)))
def readi(addr):
return unpack_from('<i', memory, addr)[0]
def read(addr):
return unpack_from('<I', memory, addr)[0]
2021-01-03 15:59:45 +01:00
def write(addr, v):
pack_into('<I', memory, addr, c_uint32(v).value)
2021-01-03 15:59:45 +01:00
def comma(v, signed=False):
2021-01-05 07:55:29 +01:00
here = read(HERE_CELL)
write(here, v)
write(HERE_CELL, here + CELL)
2021-01-05 07:55:29 +01:00
2021-01-03 15:59:45 +01:00
def read_byte(addr):
return memory[addr]
2021-01-05 13:06:03 +01:00
def write_byte(addr, c):
memory[addr] = c
2021-01-03 15:59:45 +01:00
2021-01-05 07:55:29 +01:00
def comma_byte(v):
2021-01-03 15:59:45 +01:00
here = read(HERE_CELL)
2021-01-05 13:06:03 +01:00
write_byte(here, v)
2021-01-05 07:55:29 +01:00
write(HERE_CELL, here + 1)
2021-01-03 15:59:45 +01:00
2021-01-05 07:55:29 +01:00
def comma_string(s):
2021-01-05 13:06:03 +01:00
for c in s:
comma_byte(ord(c))
comma_byte(0)
2021-01-03 15:59:45 +01:00
2021-01-05 19:22:01 +01:00
def write_string(addr, s):
for c in s:
write_byte(addr, c)
addr += 1
2021-01-05 18:12:47 +01:00
def read_string(addr):
s = ""
while True:
c = read_byte(addr)
if c == 0: break
s += chr(c)
addr += 1
return s
2021-01-05 19:22:01 +01:00
def read_bytes(addr, n):
data = []
for i in range(n):
data.append(read_byte(addr))
addr += 1
return bytes(data)
2021-01-03 15:59:45 +01:00
def find(c):
it = read(LATEST_CELL)
while it != 0:
n = read_byte(it + CELL)
C = chr(read_byte(it + CELL + 1))
2021-01-03 15:59:45 +01:00
if (c == C and n == 1):
return it + 2*CELL
2021-01-03 15:59:45 +01:00
it = read(it)
raise Exception('Unknown word: {}'.format(c))
def push(v):
global sp
sp -= CELL
2021-01-03 15:59:45 +01:00
write(sp, v)
def pop():
global sp
v = readi(sp)
sp += CELL
2021-01-03 15:59:45 +01:00
return v
def rpush(v):
global rp
rp -= CELL
2021-01-03 15:59:45 +01:00
write(rp, v)
def rpop():
global rp
v = readi(rp)
rp += CELL
2021-01-03 15:59:45 +01:00
return v
2021-01-05 07:55:29 +01:00
operators = []
def add_operator(name, func):
funcid = len(operators)
here = read(HERE_CELL)
latest = read(LATEST_CELL)
write(LATEST_CELL, here)
comma(latest)
comma_byte(len(name))
comma_string(name)
align()
comma(funcid)
operators.append(func)
return funcid
def next(np):
return read(np), np + CELL
2021-01-05 07:55:29 +01:00
def add_simple_operator(name, func):
def func_(ip, np):
func()
return next(np)
return add_operator(name, func_)
def add_uint_operator(name, op):
def func():
b = c_uint32(pop()).value
a = c_uint32(pop()).value
push(op(a, b))
return add_simple_operator(name, func)
def add_int_operator(name, op):
2021-01-05 07:55:29 +01:00
def func():
b = pop()
a = pop()
push(op(a, b))
2021-01-05 07:55:29 +01:00
return add_simple_operator(name, func)
write(HERE_CELL, 2*CELL)
2021-01-03 15:59:45 +01:00
write(LATEST_CELL, 0)
2021-01-05 08:05:07 +01:00
# Store command line arguments
argv_addrs = []
for arg in sys.argv:
argv_addrs.append(read(HERE_CELL))
2021-01-05 08:05:07 +01:00
comma_string(arg)
align()
ARGV_ADDR = read(HERE_CELL)
for addr in argv_addrs:
comma(addr)
2021-01-09 15:39:29 +01:00
# Version String
2021-01-10 12:44:50 +01:00
VERSION_ADDR = read(HERE_CELL)
comma_string(VERSION)
2021-01-09 15:39:29 +01:00
align()
2021-01-05 07:55:29 +01:00
def docol(ip, np):
rpush(np)
return next(ip + CELL)
2021-01-05 07:55:29 +01:00
DOCOL_ID = add_operator('', docol)
2021-01-11 06:20:48 +01:00
add_simple_operator('Q', lambda: exit(pop()))
add_simple_operator('C', lambda: push(CELL))
2021-01-05 07:55:29 +01:00
add_simple_operator('h', lambda: push(HERE_CELL))
add_simple_operator('l', lambda: push(LATEST_CELL))
2021-01-05 08:05:18 +01:00
def key():
c = sys.stdin.read(1)
if c:
push(ord(c))
else:
exit(0)
add_simple_operator('k', key)
2021-01-05 07:55:29 +01:00
add_simple_operator('t', lambda: sys.stdout.write(chr(pop())))
add_operator('j', lambda ip,np: next(np + readi(np)))
add_operator('J', lambda ip,np: next(np + (CELL if pop() else readi(np))))
2021-01-05 07:55:29 +01:00
add_simple_operator('f', lambda: push(find(chr(pop()))))
add_operator('x', lambda ip,np: (pop(), np))
add_simple_operator('@', lambda: push(readi(pop())))
2021-01-05 07:55:29 +01:00
# NB: Python evaluates expressions from left to right
# https://docs.python.org/3/reference/expressions.html#evaluation-order
add_simple_operator('!', lambda: write(pop(), pop()))
add_simple_operator('?', lambda: push(read_byte(pop())))
add_simple_operator('$', lambda: write_byte(pop(), pop()))
add_simple_operator('d', lambda: push(sp))
def set_sp():
global sp
sp = pop()
add_simple_operator('D', set_sp)
add_simple_operator('r', lambda: push(rp))
def set_rp():
global rp
rp = pop()
add_simple_operator('R', set_rp)
add_simple_operator('i', lambda: push(DOCOL_ID))
add_operator('e', lambda ip,np: next(rpop()))
def lit(ip, np):
push(readi(np))
return next(np + CELL)
2021-01-05 07:55:29 +01:00
add_operator('L', lit)
def litstring(ip, np):
push(np + CELL)
return next(np + CELL + read(np))
2021-01-05 07:55:29 +01:00
add_operator('S', litstring)
def divmod():
b = c_uint32(pop()).value
a = c_uint32(pop()).value
push(a%b)
push(a//b)
add_simple_operator('/', divmod)
add_int_operator('+', operator.add)
add_int_operator('-', operator.sub)
add_int_operator('*', operator.mul)
add_uint_operator('&', operator.and_)
add_uint_operator('|', operator.or_)
add_uint_operator('^', operator.xor)
add_int_operator('<', operator.lt)
add_uint_operator('u', operator.lt)
add_uint_operator('=', operator.eq)
2021-01-11 04:50:24 +01:00
add_uint_operator('(', operator.lshift)
add_uint_operator(')', operator.rshift)
add_int_operator('%', operator.rshift)
2021-01-05 08:05:07 +01:00
def argv():
push(ARGV_ADDR)
push(len(sys.argv))
add_simple_operator('v', argv)
2021-01-10 12:44:50 +01:00
add_simple_operator('V', lambda: push(VERSION_ADDR))
2021-01-05 19:22:01 +01:00
2021-01-05 18:12:47 +01:00
def openfile():
flag = pop()
name = read_string(pop())
fd = os.open(name, flag)
push(fd)
def closefile():
fd = pop()
os.close(fd)
2021-01-09 09:21:58 +01:00
push(0)
2021-01-05 19:22:01 +01:00
def readfile():
fd = pop()
size = pop()
addr = pop()
s = os.read(fd, size)
write_string(addr, s)
push(len(s))
def writefile():
fd = pop()
size = pop()
addr = pop()
n = os.write(fd, read_bytes(addr, size))
2021-01-09 09:21:58 +01:00
push(n)
add_simple_operator('(open)', openfile)
add_simple_operator('(close)', closefile)
add_simple_operator('(write)', writefile)
add_simple_operator('(read)', readfile)
2021-01-05 22:07:08 +01:00
def allocate():
size = pop()
addr = len(memory)
memory.extend([0]*size)
2021-01-05 22:07:08 +01:00
push(addr)
2021-01-17 12:14:42 +01:00
def free():
pop() # Bootstrap version do nothing
2021-01-09 09:21:58 +01:00
add_simple_operator('(allocate)', allocate)
2021-01-17 12:14:42 +01:00
add_simple_operator('(free)', free)
2021-01-05 07:55:29 +01:00
start = read(HERE_CELL)
comma(find('k'))
comma(find('f'))
comma(find('x'))
comma(find('j'))
comma(-4*CELL)
2021-01-05 07:55:29 +01:00
ip, np = next(start)
2021-01-03 15:59:45 +01:00
while True:
2021-01-05 07:55:29 +01:00
ip, np = operators[read(ip)](ip, np)