mirror of
https://git.sr.ht/~crc_/retroforth
synced 2024-11-16 19:48:56 +01:00
toolchain: implement retro-extend in Python
FossilOrigin-Name: 5d9d03c34cf2b4365681cfdd3d5211f352d2038e430669dffb9007873fbcadcd
This commit is contained in:
parent
9c69997d23
commit
bac77af47e
1 changed files with 413 additions and 0 deletions
413
tools/retro-extend.py
Executable file
413
tools/retro-extend.py
Executable file
|
@ -0,0 +1,413 @@
|
|||
#!/usr/bin/env python3
|
||||
|
||||
# retro-extend is a tool to load additional code into an image file. It
|
||||
# takes the name of an image file and one or more source files to load
|
||||
# into the image. After completion the image file will be updated with
|
||||
# the changes.
|
||||
#
|
||||
# Copyright (c) 2010 - 2020, Charles Childers
|
||||
# Optimizations and process() rewrite by Greg Copeland
|
||||
|
||||
import os, sys, math, time, struct
|
||||
from struct import pack, unpack
|
||||
|
||||
ip = 0
|
||||
stack = [] * 128
|
||||
address = []
|
||||
memory = []
|
||||
Interpreter = 0
|
||||
|
||||
|
||||
def rxDivMod(a, b):
|
||||
x = abs(a)
|
||||
y = abs(b)
|
||||
q, r = divmod(x, y)
|
||||
if a < 0 and b < 0:
|
||||
r *= -1
|
||||
elif a > 0 and b < 0:
|
||||
q *= -1
|
||||
elif a < 0 and b > 0:
|
||||
r *= -1
|
||||
q *= -1
|
||||
return q, r
|
||||
|
||||
|
||||
def findEntry(named):
|
||||
header = memory[2]
|
||||
Done = False
|
||||
while header != 0 and not Done:
|
||||
if named == extractString(header + 3):
|
||||
Done = True
|
||||
else:
|
||||
header = memory[header]
|
||||
return header
|
||||
|
||||
|
||||
def rxGetInput():
|
||||
return ord(sys.stdin.read(1))
|
||||
|
||||
|
||||
def rxDisplayCharacter():
|
||||
global stack
|
||||
if stack[-1] > 0 and stack[-1] < 128:
|
||||
if stack[-1] == 8:
|
||||
sys.stdout.write(chr(stack.pop()))
|
||||
sys.stdout.write(chr(32))
|
||||
sys.stdout.write(chr(8))
|
||||
else:
|
||||
sys.stdout.write(chr(stack.pop()))
|
||||
else:
|
||||
sys.stdout.write("\033[2J\033[1;1H")
|
||||
stack.pop()
|
||||
sys.stdout.flush()
|
||||
|
||||
|
||||
def i_no():
|
||||
pass
|
||||
|
||||
|
||||
def i_li():
|
||||
global ip, memory, stack, address
|
||||
ip += 1
|
||||
stack.append(memory[ip])
|
||||
|
||||
|
||||
def i_du():
|
||||
global ip, memory, stack, address
|
||||
stack.append(stack[-1])
|
||||
|
||||
|
||||
def i_dr():
|
||||
global ip, memory, stack, address
|
||||
stack.pop()
|
||||
|
||||
|
||||
def i_sw():
|
||||
global ip, memory, stack, address
|
||||
a = stack[-2]
|
||||
stack[-2] = stack[-1]
|
||||
stack[-1] = a
|
||||
|
||||
|
||||
def i_pu():
|
||||
global ip, memory, stack, address
|
||||
address.append(stack.pop())
|
||||
|
||||
|
||||
def i_po():
|
||||
global ip, memory, stack, address
|
||||
stack.append(address.pop())
|
||||
|
||||
|
||||
def i_ju():
|
||||
global ip, memory, stack, address
|
||||
ip = stack.pop() - 1
|
||||
|
||||
|
||||
def i_ca():
|
||||
global ip, memory, stack, address
|
||||
address.append(ip)
|
||||
ip = stack.pop() - 1
|
||||
|
||||
|
||||
def i_cc():
|
||||
global ip, memory, stack, address
|
||||
target = stack.pop()
|
||||
if stack.pop() != 0:
|
||||
address.append(ip)
|
||||
ip = target - 1
|
||||
|
||||
|
||||
def i_re():
|
||||
global ip, memory, stack, address
|
||||
ip = address.pop()
|
||||
|
||||
|
||||
def i_eq():
|
||||
global ip, memory, stack, address
|
||||
a = stack.pop()
|
||||
b = stack.pop()
|
||||
if b == a:
|
||||
stack.append(-1)
|
||||
else:
|
||||
stack.append(0)
|
||||
|
||||
|
||||
def i_ne():
|
||||
global ip, memory, stack, address
|
||||
a = stack.pop()
|
||||
b = stack.pop()
|
||||
if b != a:
|
||||
stack.append(-1)
|
||||
else:
|
||||
stack.append(0)
|
||||
|
||||
|
||||
def i_lt():
|
||||
global ip, memory, stack, address
|
||||
a = stack.pop()
|
||||
b = stack.pop()
|
||||
if b < a:
|
||||
stack.append(-1)
|
||||
else:
|
||||
stack.append(0)
|
||||
|
||||
|
||||
def i_gt():
|
||||
global ip, memory, stack, address
|
||||
a = stack.pop()
|
||||
b = stack.pop()
|
||||
if b > a:
|
||||
stack.append(-1)
|
||||
else:
|
||||
stack.append(0)
|
||||
|
||||
|
||||
def i_fe():
|
||||
global ip, memory, stack, address
|
||||
if stack[-1] == -1:
|
||||
stack[-1] = len(stack) - 1
|
||||
elif stack[-1] == -2:
|
||||
stack[-1] = len(address)
|
||||
elif stack[-1] == -3:
|
||||
stack[-1] = len(memory)
|
||||
elif stack[-1] == -4:
|
||||
stack[-1] = -2147483648
|
||||
elif stack[-1] == -5:
|
||||
stack[-1] = 2147483647
|
||||
else:
|
||||
stack[-1] = memory[stack[-1]]
|
||||
|
||||
|
||||
def i_st():
|
||||
global ip, memory, stack, address
|
||||
mi = stack.pop()
|
||||
memory[mi] = stack.pop()
|
||||
|
||||
|
||||
def i_ad():
|
||||
global ip, memory, stack, address
|
||||
t = stack.pop()
|
||||
stack[-1] += t
|
||||
stack[-1] = unpack("=l", pack("=L", stack[-1] & 0xFFFFFFFF))[0]
|
||||
|
||||
|
||||
def i_su():
|
||||
global ip, memory, stack, address
|
||||
t = stack.pop()
|
||||
stack[-1] -= t
|
||||
stack[-1] = unpack("=l", pack("=L", stack[-1] & 0xFFFFFFFF))[0]
|
||||
|
||||
|
||||
def i_mu():
|
||||
global ip, memory, stack, address
|
||||
t = stack.pop()
|
||||
stack[-1] *= t
|
||||
stack[-1] = unpack("=l", pack("=L", stack[-1] & 0xFFFFFFFF))[0]
|
||||
|
||||
|
||||
def i_di():
|
||||
global ip, memory, stack, address
|
||||
a = stack[-1]
|
||||
b = stack[-2]
|
||||
stack[-1], stack[-2] = rxDivMod(b, a)
|
||||
stack[-1] = unpack("=l", pack("=L", stack[-1] & 0xFFFFFFFF))[0]
|
||||
stack[-2] = unpack("=l", pack("=L", stack[-2] & 0xFFFFFFFF))[0]
|
||||
|
||||
|
||||
def i_an():
|
||||
global ip, memory, stack, address
|
||||
t = stack.pop()
|
||||
stack[-1] &= t
|
||||
|
||||
|
||||
def i_or():
|
||||
global ip, memory, stack, address
|
||||
t = stack.pop()
|
||||
stack[-1] |= t
|
||||
|
||||
|
||||
def i_xo():
|
||||
global ip, memory, stack, address
|
||||
t = stack.pop()
|
||||
stack[-1] ^= t
|
||||
|
||||
|
||||
def i_sh():
|
||||
global ip, memory, stack, address
|
||||
t = stack.pop()
|
||||
if t < 0:
|
||||
stack[-1] <<= t * -1
|
||||
else:
|
||||
stack[-1] >>= t
|
||||
|
||||
|
||||
def i_zr():
|
||||
global ip, memory, stack, address
|
||||
if stack[-1] == 0:
|
||||
stack.pop()
|
||||
ip = address.pop()
|
||||
|
||||
|
||||
def i_ha():
|
||||
global ip, memory, stack, address
|
||||
ip = 9000000
|
||||
|
||||
|
||||
def i_ie():
|
||||
stack.push(1)
|
||||
|
||||
|
||||
def i_iq():
|
||||
stack.pop()
|
||||
stack.push(0)
|
||||
stack.push(0)
|
||||
|
||||
|
||||
def i_ii():
|
||||
stack.pop()
|
||||
rxDisplayCharacter()
|
||||
|
||||
|
||||
instructions = [
|
||||
i_no,
|
||||
i_li,
|
||||
i_du,
|
||||
i_dr,
|
||||
i_sw,
|
||||
i_pu,
|
||||
i_po,
|
||||
i_ju,
|
||||
i_ca,
|
||||
i_cc,
|
||||
i_re,
|
||||
i_eq,
|
||||
i_ne,
|
||||
i_lt,
|
||||
i_gt,
|
||||
i_fe,
|
||||
i_st,
|
||||
i_ad,
|
||||
i_su,
|
||||
i_mu,
|
||||
i_di,
|
||||
i_an,
|
||||
i_or,
|
||||
i_xo,
|
||||
i_sh,
|
||||
i_zr,
|
||||
i_ha,
|
||||
i_ie,
|
||||
i_iq,
|
||||
i_ii,
|
||||
]
|
||||
|
||||
|
||||
def validateOpcode(opcode):
|
||||
I0 = opcode & 0xFF
|
||||
I1 = (opcode >> 8) & 0xFF
|
||||
I2 = (opcode >> 16) & 0xFF
|
||||
I3 = (opcode >> 24) & 0xFF
|
||||
if (
|
||||
(I0 >= 0 and I0 <= 29)
|
||||
and (I1 >= 0 and I1 <= 29)
|
||||
and (I2 >= 0 and I2 <= 29)
|
||||
and (I3 >= 0 and I3 <= 29)
|
||||
):
|
||||
return True
|
||||
else:
|
||||
return False
|
||||
|
||||
|
||||
def extractString(at):
|
||||
i = at
|
||||
s = ""
|
||||
while memory[i] != 0:
|
||||
s = s + chr(memory[i])
|
||||
i = i + 1
|
||||
return s
|
||||
|
||||
|
||||
def injectString(s, to):
|
||||
global memory
|
||||
i = to
|
||||
for c in s:
|
||||
memory[i] = ord(c)
|
||||
i = i + 1
|
||||
memory[i] = 0
|
||||
|
||||
|
||||
def execute(word, output="console"):
|
||||
global ip, memory, stack, address
|
||||
ip = word
|
||||
address.append(0)
|
||||
notfound = memory[findEntry("err:notfound") + 1]
|
||||
while ip < 100000 and len(address) > 0:
|
||||
if ip == notfound:
|
||||
print("ERROR: word not found!:", extractString(1024))
|
||||
opcode = memory[ip]
|
||||
if validateOpcode(opcode):
|
||||
I0 = opcode & 0xFF
|
||||
I1 = (opcode >> 8) & 0xFF
|
||||
I2 = (opcode >> 16) & 0xFF
|
||||
I3 = (opcode >> 24) & 0xFF
|
||||
if I0 != 0:
|
||||
instructions[I0]()
|
||||
if I1 != 0:
|
||||
instructions[I1]()
|
||||
if I2 != 0:
|
||||
instructions[I2]()
|
||||
if I3 != 0:
|
||||
instructions[I3]()
|
||||
else:
|
||||
print("Invalid Bytecode", opcode, ip)
|
||||
ip = 2000000
|
||||
ip = ip + 1
|
||||
return
|
||||
|
||||
|
||||
def load_image():
|
||||
global memory
|
||||
cells = int(os.path.getsize("ngaImage") / 4)
|
||||
f = open("ngaImage", "rb")
|
||||
memory = list(struct.unpack(cells * "i", f.read()))
|
||||
f.close()
|
||||
remaining = 1000000 - cells
|
||||
memory.extend([0] * remaining)
|
||||
|
||||
|
||||
def process(line):
|
||||
for Token in line.split(" "):
|
||||
if Token != "":
|
||||
injectString(Token, 1024)
|
||||
stack.append(1024)
|
||||
execute(Interpreter)
|
||||
|
||||
|
||||
def run():
|
||||
import sys
|
||||
|
||||
f = sys.argv[1]
|
||||
in_block = False
|
||||
with open(f, "r") as source:
|
||||
for line in source.readlines():
|
||||
if line.rstrip() == "~~~":
|
||||
in_block = not in_block
|
||||
elif in_block:
|
||||
process(line.strip())
|
||||
Lines += 1
|
||||
|
||||
|
||||
def save_image():
|
||||
with open("ngaImage", "wb") as file:
|
||||
j = 0
|
||||
while j < memory[3]:
|
||||
file.write(struct.pack("i", memory[j]))
|
||||
j = j + 1
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
load_image()
|
||||
Interpreter = memory[findEntry("interpret") + 1]
|
||||
run()
|
||||
save_image()
|
Loading…
Reference in a new issue