ch_in = ''
poll_in = select.poll()
poll_in.register(fd_in, select.POLLIN)
+
+# following values were taken from a 48K Apple after normal boot and NEW
+low_mem = [0] * 0x800
+#low_mem[ZP_WNDLFT] = 0
+low_mem[ZP_WNDWTH] = 40
+#low_mem[ZP_WNDTOP] = 0
+low_mem[ZP_WNDBTM] = 24
+#low_mem[ZP_CH] = 0
+low_mem[ZP_CV] = 23 # likely value (depends on previous terminal activity)
+#low_mem[ZP_COLOR] = 0
+low_mem[ZP_LOMEM] = 4
+low_mem[ZP_LOMEM + 1] = 8
+#low_mem[ZP_HIMEM] = 0
+low_mem[ZP_HIMEM + 1] = 150
+
mem = {
- # following values were taken from a 48K Apple after normal boot and NEW
- ZP_WNDLFT: 0,
- ZP_WNDWTH: 40,
- ZP_WNDTOP: 0,
- ZP_WNDBTM: 24,
- ZP_CH: 0,
- ZP_CV: 23, # just a likely value (depends on previous terminal activity)
- ZP_COLOR: 0,
- ZP_LOMEM: 4,
- ZP_LOMEM + 1: 8,
- ZP_HIMEM: 0,
- ZP_HIMEM + 1: 150,
- TONE_PERIOD: 0,
- TONE_DUR: 0,
- NICK_DURL: 0,
- NICK_DURH: 0,
- NICK_FREQL: 0,
- NICK_FREQH: 0,
HW_IOADR: 0,
HW_PB0: 0,
HW_PB1: 0,
HW_PB2: 0,
}
-gr_mem = [[0 for j in range(40)] for i in range(48)]
pdl_value = [255 for i in range(4)]
def init():
def crlf():
write(
- '\r\n' + (f'\x1b[{mem[ZP_WNDLFT]:d}C' if mem[ZP_WNDLFT] else '')
+ '\r\n' + (f'\x1b[{low_mem[ZP_WNDLFT]:d}C' if low_mem[ZP_WNDLFT] else '')
)
- mem[ZP_CV] += 1
- if mem[ZP_CV] >= mem[ZP_WNDBTM]:
- mem[ZP_CV] = mem[ZP_WNDBTM] - 1
- mem[ZP_CH] = mem[ZP_WNDLFT]
+ low_mem[ZP_CV] += 1
+ if low_mem[ZP_CV] >= low_mem[ZP_WNDBTM]:
+ low_mem[ZP_CV] = low_mem[ZP_WNDBTM] - 1
+ low_mem[ZP_CH] = low_mem[ZP_WNDLFT]
def _print(data):
for ch in data:
if ch == '\a':
tone(1000., .1) # 1 kHz for .1 sec
elif ch == '\b':
- if mem[ZP_CH] > mem[ZP_WNDLFT]:
+ if low_mem[ZP_CH] > low_mem[ZP_WNDLFT]:
write('\b')
- mem[ZP_CH] -= 1
+ low_mem[ZP_CH] -= 1
elif ch == '\n':
write('\n')
- mem[ZP_CV] += 1
- if mem[ZP_CV] >= mem[ZP_WNDBTM]:
- mem[ZP_CV] = mem[ZP_WNDBTM] - 1
+ low_mem[ZP_CV] += 1
+ if low_mem[ZP_CV] >= low_mem[ZP_WNDBTM]:
+ low_mem[ZP_CV] = low_mem[ZP_WNDBTM] - 1
elif ch == '\r':
# apple treats \r as \r\n, so if you write e.g. \r\n you'll get \r\n\n
crlf()
elif ord(ch) >= 0x20:
# some applications expect BASL, BASH = base address of current line
- addr = bascalc(mem[ZP_CV])
- mem[ZP_BASL] = addr & 0xff
- mem[ZP_BASH] = addr >> 8
- mem[addr + mem[ZP_CH]] = (ord(ch) & 0x7f) | 0x80
+ 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
write(ch)
- mem[ZP_CH] += 1
- if mem[ZP_CH] >= mem[ZP_WNDLFT] + mem[ZP_WNDWTH]:
+ low_mem[ZP_CH] += 1
+ if low_mem[ZP_CH] >= low_mem[ZP_WNDLFT] + low_mem[ZP_WNDWTH]:
crlf()
def get_internal():
if len(line):
_print('\b')
line = line[:-1]
- elif mem[ZP_CH] > mem[ZP_WNDLFT]:
+ elif low_mem[ZP_CH] > low_mem[ZP_WNDLFT]:
_print('\r')
else:
_print(ch)
def htab(x):
write(f'\x1b[{x:d}G')
- mem[ZP_CH] = x - 1
+ low_mem[ZP_CH] = x - 1
def vtab(y):
write(f'\x1b[{y:d}d')
- mem[ZP_CV] = y - 1
+ low_mem[ZP_CV] = y - 1
def cleol():
write('\x1b[K')
write('\x1b[J')
def home():
- write(f'\x1b[2J\x1b[{mem[ZP_WNDLFT] + 1:d};{mem[ZP_WNDTOP] + 1:d}H')
- mem[ZP_CH] = mem[ZP_WNDLFT]
- mem[ZP_CV] = mem[ZP_WNDTOP]
+ write(f'\x1b[2J\x1b[{low_mem[ZP_WNDLFT] + 1:d};{low_mem[ZP_WNDTOP] + 1:d}H')
+ low_mem[ZP_CH] = low_mem[ZP_WNDLFT]
+ low_mem[ZP_CV] = low_mem[ZP_WNDTOP]
def normal():
write('\x1b[0m')
def himem(addr):
addr &= 0xffff
- mem[ZP_HIMEM] = addr & 0xff
- mem[ZP_HIMEM + 1] = addr >> 8
+ low_mem[ZP_HIMEM] = addr & 0xff
+ low_mem[ZP_HIMEM + 1] = addr >> 8
def lomem(addr):
addr &= 0xffff
- mem[ZP_LOMEM] = addr & 0xff
- mem[ZP_LOMEM + 1] = addr >> 8
+ low_mem[ZP_LOMEM] = addr & 0xff
+ low_mem[ZP_LOMEM + 1] = addr >> 8
def peek(addr):
addr &= 0xffff
#if len(ch_in) == 0 and len(poll_in.poll(POLL_TIMEOUT_MS)):
if len(poll_in.poll(POLL_TIMEOUT_MS)):
get_internal()
- return mem.get(addr, 0)
+ return low_mem[addr] if addr < 0x800 else mem.get(addr, 0)
def poke(addr, data):
global ch_in
mem[HW_IOADR] &= 0x7f
else:
data &= 0xff
- mem[addr] = data
- if addr == ZP_WNDTOP or addr == ZP_WNDBTM:
- # save cursor, set scrolling region, restore cursor
- write(f'\x1b[s\x1b[{mem[ZP_WNDTOP] + 1:d};{mem[ZP_WNDBTM]:d}r\x1b[u')
+ if addr < 0x800:
+ low_mem[addr] = data
+ if 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'
+ )
+ else:
+ mem[addr] = data
def call(addr):
global flash_color0
if addr == NICK_REST or addr == NICK_TONE:
# for lemonade_patched, see test/lemonade_tone_nick.py
if addr == NICK_REST:
- mem[NICK_FREQL] = 0
- mem[NICK_FREQH] = 0
- frequency_incr = mem[NICK_FREQL] + (mem[NICK_FREQH] << 8)
- duration_count = -(mem[NICK_DURL] + (mem[NICK_DURH] << 8))
+ 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
time.sleep(duration)
elif addr == TONE_TONE or addr == TONE_TONE1:
# for lemonade, see test/lemonade_tone_patched.py
- period_count = ((mem[TONE_PERIOD] - 1) & 0xff) + 1
- duration_count = ((mem[TONE_DUR] - 1) & 0xff) + 1
+ period_count = ((low_mem[TONE_PERIOD] - 1) & 0xff) + 1
+ duration_count = ((low_mem[TONE_DUR] - 1) & 0xff) + 1
cycles = 1.37788799e-02 + duration_count * (
-4.21513128e-06 + 1.27999925e+02 / period_count
)
tone(cycles / duration, duration)
elif addr == FLASH_INIT or addr == FLASH_INIT_PATCHED:
# for lemonade, lighting (init)
- flash_color0 = mem[ZP_COLOR]
+ flash_color0 = low_mem[ZP_COLOR] & 0xf
elif addr == FLASH_EXECUTE or addr == FLASH_EXECUTE_PATCHED:
# for lemonade, lightning (execute)
time.sleep(.02)
- flash_color1 = mem[ZP_COLOR]
+ flash_color1 = low_mem[ZP_COLOR] & 0xf
for i in range(20):
x0 = 40
x1 = 0
+ addr = bascalc(i)
for j in range(40):
- if gr_mem[i * 2][j] == flash_color0:
- gr_mem[i * 2][j] = flash_color1
+ if (low_mem[addr + j] & 0xf) == flash_color0:
+ low_mem[addr + j] = (low_mem[addr + j] & 0xf0) | flash_color1
if j < x0:
x0 = j
x1 = j + 1
- if gr_mem[i * 2 + 1][j] == flash_color0:
- gr_mem[i * 2 + 1][j] = flash_color1
+ if (low_mem[addr + j] >> 4) == flash_color0:
+ low_mem[addr + j] = (low_mem[addr + j] & 0xf) | (flash_color1 << 4)
if j < x0:
x0 = j
x1 = j + 1
def text():
# save cursor, set scrolling region, restore cursor
write('\x1b[s\x1b1;24r\x1b[u')
- mem[ZP_WNDLFT] = 0
- mem[ZP_WNDWTH] = 40
- mem[ZP_WNDTOP] = 0
- mem[ZP_WNDBTM] = 24
+ low_mem[ZP_WNDLFT] = 0
+ low_mem[ZP_WNDWTH] = 40
+ low_mem[ZP_WNDTOP] = 0
+ low_mem[ZP_WNDBTM] = 24
def gr():
# clear screen, set scrolling region (homes cursor)
write(f'\x1b[2J\x1b[21;24r')
- mem[ZP_WNDLFT] = 0
- mem[ZP_WNDWTH] = 40
- mem[ZP_WNDTOP] = 20
- mem[ZP_WNDBTM] = 24
- mem[ZP_CH] = 0
- mem[ZP_CV] = 20
- for i in range(40):
- gr_mem[i][:] = [0 for j in range(40)]
+ low_mem[ZP_WNDLFT] = 0
+ low_mem[ZP_WNDWTH] = 40
+ low_mem[ZP_WNDTOP] = 20
+ low_mem[ZP_WNDBTM] = 24
+ low_mem[ZP_CH] = 0
+ low_mem[ZP_CV] = 20
+ for i in range(20):
+ addr = bascalc(i)
+ low_mem[addr:addr + 40] = [0] * 40
def gr_update(x0, y0, x1, y1):
write(f'\x1b7') # save all attributes (in case in INVERSE/FLASH mode)
br = -1
for i in range(y0, y1):
write(f'\x1b[{i + 1:d};{x0 * gr_width + 1:d}H')
+ addr = bascalc(i)
for j in range(x0, x1):
- new_bg = colors[gr_mem[i * 2][j]]
- new_fg = colors[gr_mem[i * 2 + 1][j]]
+ new_bg = colors[low_mem[addr + j] & 0xf]
+ new_fg = colors[low_mem[addr + j] >> 4]
# 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:
write(f'\x1b8') # restore all attributes (in case in INVERSE/FLASH mode)
def color(n):
- mem[ZP_COLOR] = n
+ low_mem[ZP_COLOR] = n
def plot(x, y):
- gr_mem[y][x] = mem[ZP_COLOR]
- y >>= 1
- gr_update(x, y, x + 1, y + 1)
+ color = low_mem[ZP_COLOR] & 0xf
+ i = y & 1
+ j = y >> 1
+ addr = bascalc(j)
+ if i == 0:
+ low_mem[addr + x] = (low_mem[addr + x] & 0xf0) | color
+ else:
+ low_mem[addr + x] = (low_mem[addr + x] & 0xf) | (color << 4)
+ gr_update(x, j, x + 1, j + 1)
def hlin(x0, x1, y):
+ color = low_mem[ZP_COLOR] & 0xf
if x1 < x0:
x0, x1 = x1, x0
- for x in range(x0, x1 + 1):
- gr_mem[y][x] = mem[ZP_COLOR]
- y >>= 1
- gr_update(x0, y, x1 + 1, y + 1)
+ i = y & 1
+ j = y >> 1
+ addr = bascalc(j)
+ if i == 0:
+ for x in range(x0, x1 + 1):
+ low_mem[addr + x] = (low_mem[addr + x] & 0xf0) | color
+ else:
+ for x in range(x0, x1 + 1):
+ low_mem[addr + x] = (low_mem[addr + x] & 0xf) | (color << 4)
+ gr_update(x0, j, x1 + 1, j + 1)
def vlin(y0, y1, x):
+ color = low_mem[ZP_COLOR] & 0xf
if y1 < y0:
y0, y1 = y1, y0
for y in range(y0, y1 + 1):
- gr_mem[y][x] = mem[ZP_COLOR]
+ i = y & 1
+ j = y >> 1
+ addr = bascalc(j)
+ if i == 0:
+ low_mem[addr + x] = (low_mem[addr + x] & 0xf0) | color
+ else:
+ low_mem[addr + x] = (low_mem[addr + x] & 0xf) | (color << 4)
gr_update(x, y0 >> 1, x + 1, (y1 >> 1) + 1)
def usr(n):
return 0
def scrn(x, y):
- return gr_mem[y][x]
+ i = y & 1
+ j = y >> 1
+ addr = bascalc(j)
+ return low_mem[addr + x] & 0xf if i == 0 else low_mem[addr + x] >> 4
def pdl(n):
return pdl_value[n]
def pos():
- return mem[ZP_CH]
+ return low_mem[ZP_CH]