Skip to content

Instantly share code, notes, and snippets.

@arpruss
Last active December 16, 2021 03:30
Show Gist options
  • Save arpruss/c714dd7682d7c7bd7aa8263709d4501e to your computer and use it in GitHub Desktop.
Save arpruss/c714dd7682d7c7bd7aa8263709d4501e to your computer and use it in GitHub Desktop.
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