import select
import sys
import termios
+import time
import tty
# see https://www.tinaja.com/ebooks/tearing_rework.pdf
ROM_OLDRST = 0xFF59 # Old reset entry, no autostart
ROM_MON = 0xFF65 # Enter monitor and beep spkr
+# colors (map 15 apple colors to 16 VT100 colours, some duplicate or unused)
+colors = [
+ 0x0, # black -> black
+ 0x5, # dark pink -> magenta
+ 0x1, # dark blue -> blue
+ 0x5, # dark purple -> magenta
+ 0x2, # dark green -> green
+ 0x7, # grey 1 -> white
+ 0x9, # light blue -> intense blue
+ 0xd, # light purple -> intense magenta
+ 0x6, # dark yellow -> yellow
+ 0xe, # orange -> intense yellow
+ 0x7, # grey 2 -> white
+ 0xc, # pink -> intense red
+ 0xa, # light green -> intense green
+ 0xe, # light yellow -> intense yellow
+ 0xb, # light cyan -> intense cyan
+ 0xf, # white -> intense white
+]
+
# global state
attr = None
fd_in = sys.stdin.fileno()
0x300: 0, # tone freq
0x301: 0, # tone dur
}
+gr_color = 0
+gr_mem = [[0 for j in range(40)] for i in range(40)]
def init():
global attr
return len(poll_in.poll(1)) != 0
def read(n):
- return str(os.read(fd_in, 1), 'ascii')
+ return str(os.read(fd_in, 1), 'utf-8')
def write(data):
- os.write(fd_out, bytes(data, 'ascii'))
+ os.write(fd_out, bytes(data, 'utf-8'))
def _print(data):
for ch in data:
write('\x1b[J')
def home():
- write('\x1b[H\x1b[2J')
+ write('\x1b[2J\x1b[H')
mem[ZP_CH] = 0
mem[ZP_CV] = 0
def tone(freq, dur): # Hz, ms
# doesn't seem to work on any linux console on my laptop
- write(f'\x1b7\x1b[10;{freq:d}]\x1b[11;{dur:d}]\x07\x1b8')
+ #write(f'\x1b7\x1b[10;{freq:d}]\x1b[11;{dur:d}]\x07\x1b8')
+ time.sleep(dur * .001)
def himem(addr):
pass
pass
def gr():
- pass
+ write('\x1b[2J\x1b[21H')
+ mem[ZP_CH] = 0
+ mem[ZP_CV] = 20
+ for i in range(40):
+ gr_mem[i][:] = [0 for j in range(40)]
+
+def gr_update(x0, y0, x1, y1):
+ write('\x1b[s') # save cursor
+ bg = -1
+ fg = -1
+ br = -1
+ for i in range(y0, y1):
+ write(f'\x1b[{i + 1:d};{x0 * 2 + 1:d}H')
+ for j in range(x0, x1):
+ new_bg = colors[gr_mem[i * 2][j]]
+ new_fg = colors[gr_mem[i * 2 + 1][j]]
+ # we cannot draw two different intense colours in same block,
+ # so just do the best we can (the greater colour gets priority)
+ if new_bg < new_fg:
+ ch = '▄'
+ elif new_bg > new_fg:
+ new_bg, new_fg = new_fg, new_bg
+ ch = '▀'
+ elif new_bg < 8:
+ # we try to draw not-intense pixels using background, it
+ # might play nicer with terminals that use black-on-white
+ new_fg = 0
+ ch = ' '
+ else:
+ new_bg = 0
+ ch = '█'
+ new_br = new_fg >= 8
+ new_bg &= 7
+ new_fg &= 7
+ if new_bg != bg or new_fg != fg or new_br != br:
+ write(
+ '\x1b[0{0:s}{1:s}{2:s}m'.format(
+ f';4{new_bg:d}' if new_bg else '',
+ f';3{new_fg:d}' if new_fg else '',
+ ';1' if new_br else ''
+ )
+ )
+ bg = new_bg
+ fg = new_fg
+ br = new_br
+ write(ch * 2)
+ write('\x1b[u\x1b[0m') # restore cursor and attrs
+ time.sleep(.1)
def color(n):
- pass
+ global gr_color
+ gr_color = n
def plot(x, y):
- pass
+ gr_mem[y][x] = gr_color
+ y >>= 1
+ gr_update(x, y, x + 1, y + 1)
def hlin(x0, x1, y):
- pass
+ if x1 < x0:
+ x0, x1 = x1, x0
+ for x in range(x0, x1 + 1):
+ gr_mem[y][x] = gr_color
+ y >>= 1
+ gr_update(x0, y, x1 + 1, y + 1)
def vlin(y0, y1, x):
- pass
+ if y1 < y0:
+ y0, y1 = y1, y0
+ for y in range(y0, y1 + 1):
+ gr_mem[y][x] = gr_color
+ gr_update(x, y0 >> 1, x + 1, (y1 >> 1) + 1)
def usr(n):
return 0
def scrn(x, y):
- return 0
+ return gr_mem[y][x]
def pdl(n):
return 127