Last active
December 16, 2021 03:30
-
-
Save arpruss/c714dd7682d7c7bd7aa8263709d4501e to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
GRAPHICS = True # uses cv2 to display board | |
import z80 # pip3 --install z80, but modified to make af visible | |
import binascii | |
import time | |
if GRAPHICS: | |
import cv2 | |
import numpy as np | |
zoom = 5 | |
MINIMUM_COMPUTE_TIME_PER_FRAME = 1. / 5 | |
def getch(): | |
return chr(cv2.waitKey(0)) | |
blocks = [] | |
for block in range(64): | |
data = np.zeros((3,2),dtype=np.uint8) | |
a = 1 | |
for j in range(3): | |
for i in range(2): | |
data[j,i] = 0 if (block & a) else 255 | |
a <<= 1 | |
blocks.append(cv2.resize(data, (2*zoom,3*zoom), interpolation = cv2.INTER_NEAREST)) | |
else: | |
from getch import getch # pip3 --install py-getch | |
FILE = "zout/sargon-z80.hex" | |
ORG = 0x0000 | |
START = ORG+0x1a00 | |
BLINKER = ORG+0x204C | |
def hexToMemory(filename,startAddress=0,length=-1,fill=0): | |
memory = [None] * 0x10000 | |
last = 0 | |
with open(filename,"r") as f: | |
for line in f: | |
line = line.strip() | |
if line[0] == ':': | |
data = binascii.unhexlify(line[1:]) | |
if data[3] == 1: | |
break | |
elif data[3] == 0: | |
count = data[0] | |
address = (data[1] << 8) | data[2] | |
for i in range(count): | |
a = address+i-startAddress | |
if memory[a] is not None: | |
print("Overlap at %04x" % a) | |
#raise Exception("overlap") | |
memory[a] = data[4+i] | |
last = max(last, a+1) | |
for i in range(0x10000): | |
if memory[i] is None: | |
memory[i] = fill | |
if length < 0: | |
return bytes(memory[:last]) | |
else: | |
return bytes(memory) | |
def getWord(address): | |
return z.memory[address] | (z.memory[(address+1) & 0xFFFF] << 8) | |
def setWord(address,data): | |
z.memory[address] = data & 0xFF | |
z.memory[(address+1) & 0xFFFF] = data >> 8 | |
def getBytes(address,count): | |
data = bytearray(count) | |
for i in range(count): | |
data[i] = z.memory[(address+i)&0xFFFF] | |
return data | |
def handle38(): | |
addr = getWord(z.sp) | |
function1 = z.memory[addr] | |
addr = (addr+1) & 0xFFFF | |
function2 = z.memory[addr] | |
addr = (addr+1) & 0xFFFF | |
if (function1 == 0xb2 or function1 == 0xb3) and function2 == 0x1a: | |
msg = getWord(addr) | |
addr = (addr+2) & 0xFFFF | |
length = getWord(addr) | |
addr = (addr+2) & 0xFFFF | |
data = getBytes(msg,length).decode('ascii', 'ignore') | |
if function1 == 0xb2: | |
print(data) | |
else: | |
print(data,end='',flush=True) | |
elif function1 == 0x92 and function2 == 0x1a: | |
addr = (addr+2) & 0xFFFF | |
print() | |
elif function1 == 0x81 and function2 == 0x00: | |
z.af = (z.af & 0xFF) | (ord(getch()) << 8) | |
elif function1 == 0x81 and function2 == 0x1A: | |
data = bytearray((z.af>>8,)) | |
print(data.decode('ascii', 'ignore'), end='', flush=True) | |
elif function1 == 0x1F: | |
print("[done]") | |
return True | |
else: | |
print("Unknown function 0x%02x from 0x%04x" % (function1,addr-4)) | |
z.sp += 2 | |
z.pc = addr | |
return False | |
z = z80.Z80Machine() | |
z.set_memory_block(0, hexToMemory(FILE)) | |
z.set_breakpoint(0x38) | |
z.set_breakpoint(0x00) | |
if GRAPHICS: z.set_breakpoint(BLINKER) # blinker | |
z.pc = START | |
def getImage(): | |
jupiterWidth = 64 | |
jupiterHeight = 32 | |
data = np.zeros((jupiterHeight*3*zoom,jupiterWidth*2*zoom),dtype=np.uint8) | |
for x in range(jupiterWidth): | |
for y in range(jupiterHeight): | |
block = z.memory[0xC000 + y * jupiterWidth + x] | |
if 0x80 <= block and block < 0x80+64: | |
x1 = x*2*zoom | |
y1 = y*3*zoom | |
data[y1:y1+3*zoom, x1:x1+2*zoom] = blocks[block & 0x7F] | |
return data | |
def handleBreakpoints(): | |
if z.pc == 0x00: | |
print("[reset]") | |
return true | |
elif z.pc == 0x38: | |
return handle38() | |
else: | |
return False | |
if GRAPHICS: | |
lastFrame = 0 | |
while True: | |
z.ticks_to_stop = 200000 | |
events = z.run() | |
if (events & z._BREAKPOINT_HIT) or time.time() >= lastFrame + MINIMUM_COMPUTE_TIME_PER_FRAME: | |
image = getImage() | |
cv2.imshow("Sargon", image) | |
if handleBreakpoints(): | |
break | |
cv2.waitKey(1) | |
lastFrame = time.time() | |
else: | |
while True: | |
events = z.run() | |
if handleBreakpoints(): | |
break | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment