HW_PB2: 0,
}
pdl_value = [255 for i in range(4)]
+gr_on = False
def init():
global termios_attr, pcm
addr = bascalc(low_mem[ZP_CV])
low_mem[ZP_BASL] = addr & 0xff
low_mem[ZP_BASH] = addr >> 8
- low_mem[addr + low_mem[ZP_CH]] = (ord(ch) & 0x7f) | 0x80
+ i = ord(ch)
+ data = (
+ (i & 0x3f) ^ 0x60
+ if invflg == INVFLG_FLASH else
+ (i & 0x3f) ^ 0x20
+ if invflg == INVFLG_INVERSE else
+ i | 0x80
+ )
+ low_mem[addr + low_mem[ZP_CH]] = data
- write(ch)
+ if gr_on and low_mem[ZP_CV] < 20:
+ write(gr_encode([data])[0] + invflg())
+ else:
+ write(ch)
low_mem[ZP_CH] += 1
if low_mem[ZP_CH] >= low_mem[ZP_WNDLFT] + low_mem[ZP_WNDWTH]:
crlf()
write('\x1b[J')
def home():
- write(f'\x1b[2J\x1b[{low_mem[ZP_WNDLFT] + 1:d};{low_mem[ZP_WNDTOP] + 1:d}H')
+ # move cursor home, clear to end of screen
+ # just approximates proper behaviour of clearing the window rectangle
+ write(
+ f'\x1b[{low_mem[ZP_WNDTOP] + 1:d};{low_mem[ZP_WNDLFT] + 1:d}H\x1b[J'
+ )
low_mem[ZP_CH] = low_mem[ZP_WNDLFT]
low_mem[ZP_CV] = low_mem[ZP_WNDTOP]
+ for i in range(low_mem[ZP_WNDTOP], 24):
+ addr = bascalc(i)
+ low_mem[addr:addr + 40] = [0xa0] * 40
def invflg():
- write(
+ return (
'\x1b[0;7;5m'
if low_mem[ZP_INVFLG] == INVFLG_FLASH else
'\x1b[0;7m'
def normal():
if low_mem[ZP_INVFLG] != INVFLG_NORMAL:
low_mem[ZP_INVFLG] = INVFLG_NORMAL
- invflg()
+ write(invflg())
def inverse():
if low_mem[ZP_INVFLG] != INVFLG_INVERSE:
low_mem[ZP_INVFLG] = INVFLG_INVERSE
- invflg()
+ write(invflg())
def flash():
if low_mem[ZP_INVFLG] != INVFLG_FLASH:
low_mem[ZP_INVFLG] = INVFLG_FLASH
- invflg()
+ write(invflg())
def tone(freq, dur): # Hz, s
if beep_style == BEEP_STYLE_VT100:
data &= 0xff
if addr < 0x800:
low_mem[addr] = data
- if addr == ZP_WNDTOP or addr == ZP_WNDBTM:
+ if addr >= 0x400:
+ y = ((addr >> 7) & 7) | (((addr & 0x7f) // 40) << 3)
+ if y < 24:
+ x = (addr & 0x7f) % 40
+ gr_update(x, y, x + 1, y + 1)
+ elif addr == ZP_WNDTOP or addr == ZP_WNDBTM:
# save cursor, set scrolling region, restore cursor
write(
f'\x1b[s\x1b[{low_mem[ZP_WNDTOP] + 1:d};{low_mem[ZP_WNDBTM]:d}r\x1b[u'
addr &= 0xffff
if addr == NICK_REST or addr == NICK_TONE:
- # for lemonade_patched, see test/lemonade_tone_nick.py
- if addr == NICK_REST:
- low_mem[NICK_FREQL] = 0
- low_mem[NICK_FREQH] = 0
- frequency_incr = low_mem[NICK_FREQL] + (low_mem[NICK_FREQH] << 8)
- duration_count = -(low_mem[NICK_DURL] + (low_mem[NICK_DURH] << 8))
- duration_count = ((duration_count - 1) & 0xffff) + 1
- duration = 3.58309497e-10 + duration_count * (
- 2.34821712e-05 + frequency_incr * 4.47591203e-11
- )
- if frequency_incr:
- period = 0x1fffe * (2.34821712e-05 / frequency_incr + 4.47591203e-11)
- tone(1. / period, duration)
- else:
- time.sleep(duration)
+ pass
+ ## for lemonade_patched, see test/lemonade_tone_nick.py
+ #if addr == NICK_REST:
+ # low_mem[NICK_FREQL] = 0
+ # low_mem[NICK_FREQH] = 0
+ #frequency_incr = low_mem[NICK_FREQL] + (low_mem[NICK_FREQH] << 8)
+ #duration_count = -(low_mem[NICK_DURL] + (low_mem[NICK_DURH] << 8))
+ #duration_count = ((duration_count - 1) & 0xffff) + 1
+ #duration = 3.58309497e-10 + duration_count * (
+ # 2.34821712e-05 + frequency_incr * 4.47591203e-11
+ #)
+ #if frequency_incr:
+ # period = 0x1fffe * (2.34821712e-05 / frequency_incr + 4.47591203e-11)
+ # tone(1. / period, duration)
+ #else:
+ # time.sleep(duration)
elif addr == TONE_TONE or addr == TONE_TONE1:
# for lemonade, see test/lemonade_tone_patched.py
period_count = ((low_mem[TONE_PERIOD] - 1) & 0xff) + 1
return 0x400 | ((y & 7) << 7) | ((y >> 3) * 40)
def text():
+ global gr_on
+
# save cursor, set scrolling region, restore cursor
write('\x1b[s\x1b1;24r\x1b[u')
low_mem[ZP_WNDLFT] = 0
low_mem[ZP_WNDWTH] = 40
low_mem[ZP_WNDTOP] = 0
low_mem[ZP_WNDBTM] = 24
+ gr_on = False
def gr():
+ global gr_on
+
# clear screen, set scrolling region (homes cursor)
+ #write(f'\x1b[2J\x1b[21;24r\x1b[1;21H')
write(f'\x1b[2J\x1b[21;24r')
low_mem[ZP_WNDLFT] = 0
low_mem[ZP_WNDWTH] = 40
for i in range(20):
addr = bascalc(i)
low_mem[addr:addr + 40] = [0] * 40
+ gr_on = True
# takes memory encoded with upper pixel in bits 0-3, lower in bits 4-7
# returns a stream of unicode characters with attribute-setting escapes
# attribute-setting can be optimized by passing in a previous attribute
-def gr_encode(_in, attr = (-1, -1, -1)):
+def gr_encode(_in, attr = (-1, -1, -1, -1, -1)):
out = []
for i in _in:
background = colors[i & 0xf]
else:
background = 0
ch = '█'
- new_attr = (background & 7, foreground & 7, foreground >> 3)
+ new_attr = (background & 7, foreground & 7, foreground >> 3, -1, -1)
if new_attr != attr:
out.append(
'\x1b[0;{0:d};{1:d}{2:s}m'.format(
- new_attr[0] + 40,
- new_attr[1] + 30,
- ';1' if new_attr[2] else ''
+ new_attr[0] + 40, # foreground
+ new_attr[1] + 30, # background
+ ';1' if new_attr[2] else '' # intense
)
)
attr = new_attr
out.append(ch)
return ''.join(out), attr
+# similar to gr_encode(), but for the text portion of screen (lines 21-24)
+# decodes hi bits of characters into attributes interleaved with characters
+text_hibits = [
+ (0x40, (-1, -1, -1, 1, 0)), # inverse @ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_
+ (0x20, (-1, -1, -1, 1, 0)), # inverse !"#$%&'()*+,-./0123456789:;<=>?
+ (0x40, (-1, -1, -1, 1, 1)), # blink @ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_
+ (0x20, (-1, -1, -1, 1, 1)), # blink !"#$%&'()*+,-./0123456789:;<=>?
+ (0x40, (-1, -1, -1, 0, 0)), # normal @ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_
+ (0x20, (-1, -1, -1, 0, 0)), # normal !"#$%&'()*+,-./0123456789:;<=>?
+ (0x40, (-1, -1, -1, 0, 0)), # normal @ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_
+ (0x60, (-1, -1, -1, 0, 0)), # normal `abcdefghijklmnopqrstuvwxyz{|}~del
+]
+def text_encode(_in, attr = (-1, -1, -1, -1, -1)):
+ out = []
+ for i in _in:
+ base, new_attr = text_hibits[i >> 5]
+ if new_attr != attr:
+ out.append(
+ '\x1b[0{0:s}{1:s}m'.format(
+ ';7' if new_attr[3] else '', # reverse video
+ ';5' if new_attr[4] else '' # blink
+ )
+ )
+ attr = new_attr
+ out.append(chr(base | (i & 0x1f)))
+ return ''.join(out), attr
+
def gr_update(x0, y0, x1, y1):
write('\x1b[s') # save cursor
- attr = (-1, -1, -1)
+ attr = (-1, -1, -1, -1, -1)
for i in range(y0, y1):
addr = bascalc(i)
- data, attr = gr_encode(low_mem[addr + x0:addr + x1], attr)
+ data, attr = (
+ gr_encode(low_mem[addr + x0:addr + x1], attr)
+ if gr_on and i < 20 else
+ text_encode(low_mem[addr + x0:addr + x1], attr)
+ )
write(f'\x1b[{i + 1:d};{x0 + 1:d}H{data:s}')
- write('\x1b[u') # restore cursor
- invflg() # restore normal/inverse/flash
+ write('\x1b[u' + invflg()) # restore cursor and normal/inverse/flash
def color(n):
low_mem[ZP_COLOR] = n