retroforth/tools/retro-extend.py
crc de6c62d5f2 toolchain: retro-extend.py now handles multiple inputs, passing image name on command line
FossilOrigin-Name: ba4fc1a5e2b043520ccdd82c01b9a56616c95a80416db7e125434f4cf7f2529e
2020-09-22 15:34:05 +00:00

417 lines
7.9 KiB
Python
Executable file

#!/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
#
# Usage:
#
# retro-extend.py image filename [filenames]
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 process_files():
for f in sys.argv[2:]:
print(f)
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())
def save_image():
print("Writing {0} cells to {1}".format(memory[3], sys.argv[1]))
with open(sys.argv[1], "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]
process_files()
save_image()