From 9220ec85db467298dfd20b3fe3c414dbf470a1f4 Mon Sep 17 00:00:00 2001 From: James Tauber Date: Sat, 13 Aug 2011 03:52:07 -0400 Subject: [PATCH 01/11] ported to pygame and added bit-accurate characters --- applepy.py | 209 ++++++++++++++++++++++++++++++++++------------------- 1 file changed, 134 insertions(+), 75 deletions(-) diff --git a/applepy.py b/applepy.py index efa08f0..59bafb5 100644 --- a/applepy.py +++ b/applepy.py @@ -3,7 +3,8 @@ # originally written 2001, updated 2011 -import curses +import pygame + def signed(x): if x > 0x7F: @@ -11,6 +12,113 @@ def signed(x): return x +class Display: + + characters = [ + [0b00000, 0b01110, 0b10001, 0b10101, 0b10111, 0b10110, 0b10000, 0b01111], + [0b00000, 0b00100, 0b01010, 0b10001, 0b10001, 0b11111, 0b10001, 0b10001], + [0b00000, 0b11110, 0b10001, 0b10001, 0b11110, 0b10001, 0b10001, 0b11110], + [0b00000, 0b01110, 0b10001, 0b10000, 0b10000, 0b10000, 0b10001, 0b01110], + [0b00000, 0b11110, 0b10001, 0b10001, 0b10001, 0b10001, 0b10001, 0b11110], + [0b00000, 0b11111, 0b10000, 0b10000, 0b11110, 0b10000, 0b10000, 0b11111], + [0b00000, 0b11111, 0b10000, 0b10000, 0b11110, 0b10000, 0b10000, 0b10000], + [0b00000, 0b01111, 0b10000, 0b10000, 0b10000, 0b10011, 0b10001, 0b01111], + [0b00000, 0b10001, 0b10001, 0b10001, 0b11111, 0b10001, 0b10001, 0b10001], + [0b00000, 0b01110, 0b00100, 0b00100, 0b00100, 0b00100, 0b00100, 0b01110], + [0b00000, 0b00001, 0b00001, 0b00001, 0b00001, 0b00001, 0b10001, 0b01110], + [0b00000, 0b10001, 0b10010, 0b10100, 0b11000, 0b10100, 0b10010, 0b10001], + [0b00000, 0b10000, 0b10000, 0b10000, 0b10000, 0b10000, 0b10000, 0b11111], + [0b00000, 0b10001, 0b11011, 0b10101, 0b10101, 0b10001, 0b10001, 0b10001], + [0b00000, 0b10001, 0b10001, 0b11001, 0b10101, 0b10011, 0b10001, 0b10001], + [0b00000, 0b01110, 0b10001, 0b10001, 0b10001, 0b10001, 0b10001, 0b01110], + [0b00000, 0b11110, 0b10001, 0b10001, 0b11110, 0b10000, 0b10000, 0b10000], + [0b00000, 0b01110, 0b10001, 0b10001, 0b10001, 0b10101, 0b10010, 0b01101], + [0b00000, 0b11110, 0b10001, 0b10001, 0b11110, 0b10100, 0b10010, 0b10001], + [0b00000, 0b01110, 0b10001, 0b10000, 0b01110, 0b00001, 0b10001, 0b01110], + [0b00000, 0b11111, 0b00100, 0b00100, 0b00100, 0b00100, 0b00100, 0b00100], + [0b00000, 0b10001, 0b10001, 0b10001, 0b10001, 0b10001, 0b10001, 0b01110], + [0b00000, 0b10001, 0b10001, 0b10001, 0b10001, 0b10001, 0b01010, 0b00100], + [0b00000, 0b10001, 0b10001, 0b10001, 0b10101, 0b10101, 0b11011, 0b10001], + [0b00000, 0b10001, 0b10001, 0b01010, 0b00100, 0b01010, 0b10001, 0b10001], + [0b00000, 0b10001, 0b10001, 0b01010, 0b00100, 0b00100, 0b00100, 0b00100], + [0b00000, 0b11111, 0b00001, 0b00010, 0b00100, 0b01000, 0b10000, 0b11111], + [0b00000, 0b11111, 0b11000, 0b11000, 0b11000, 0b11000, 0b11000, 0b11111], + [0b00000, 0b00000, 0b10000, 0b01000, 0b00100, 0b00010, 0b00001, 0b00000], + [0b00000, 0b11111, 0b00011, 0b00011, 0b00011, 0b00011, 0b00011, 0b11111], + [0b00000, 0b00000, 0b00000, 0b00100, 0b01010, 0b10001, 0b00000, 0b00000], + [0b00000, 0b00000, 0b00000, 0b00000, 0b00000, 0b00000, 0b00000, 0b11111], + [0b00000, 0b00000, 0b00000, 0b00000, 0b00000, 0b00000, 0b00000, 0b00000], + [0b00000, 0b00100, 0b00100, 0b00100, 0b00100, 0b00100, 0b00000, 0b00100], + [0b00000, 0b01010, 0b01010, 0b00000, 0b00000, 0b00000, 0b00000, 0b00000], + [0b00000, 0b01010, 0b01010, 0b11111, 0b01010, 0b11111, 0b01010, 0b01010], + [0b00000, 0b00100, 0b01111, 0b10100, 0b01110, 0b00101, 0b11110, 0b00100], + [0b00000, 0b11000, 0b11001, 0b00010, 0b00100, 0b01000, 0b10011, 0b00011], + [0b00000, 0b01000, 0b10100, 0b10100, 0b01000, 0b10101, 0b10010, 0b01101], + [0b00000, 0b00100, 0b00100, 0b00000, 0b00000, 0b00000, 0b00000, 0b00000], + [0b00000, 0b00100, 0b01000, 0b10000, 0b10000, 0b10000, 0b01000, 0b00100], + [0b00000, 0b00100, 0b00010, 0b00001, 0b00001, 0b00001, 0b00010, 0b00100], + [0b00000, 0b00100, 0b10101, 0b01110, 0b00100, 0b01110, 0b10101, 0b00100], + [0b00000, 0b00000, 0b00100, 0b00100, 0b11111, 0b00100, 0b00100, 0b00000], + [0b00000, 0b00000, 0b00000, 0b00000, 0b00000, 0b00100, 0b00100, 0b01000], + [0b00000, 0b00000, 0b00000, 0b00000, 0b11111, 0b00000, 0b00000, 0b00000], + [0b00000, 0b00000, 0b00000, 0b00000, 0b00000, 0b00000, 0b00000, 0b00100], + [0b00000, 0b00000, 0b00001, 0b00010, 0b00100, 0b01000, 0b10000, 0b00000], + [0b00000, 0b01110, 0b10001, 0b10011, 0b10101, 0b11001, 0b10001, 0b01110], + [0b00000, 0b00100, 0b01100, 0b00100, 0b00100, 0b00100, 0b00100, 0b01110], + [0b00000, 0b01110, 0b10001, 0b00001, 0b00110, 0b01000, 0b10000, 0b11111], + [0b00000, 0b11111, 0b00001, 0b00010, 0b00110, 0b00001, 0b10001, 0b01110], + [0b00000, 0b00010, 0b00110, 0b01010, 0b10010, 0b11111, 0b00010, 0b00010], + [0b00000, 0b11111, 0b10000, 0b11110, 0b00001, 0b00001, 0b10001, 0b01110], + [0b00000, 0b00111, 0b01000, 0b10000, 0b11110, 0b10001, 0b10001, 0b01110], + [0b00000, 0b11111, 0b00001, 0b00010, 0b00100, 0b01000, 0b01000, 0b01000], + [0b00000, 0b01110, 0b10001, 0b10001, 0b01110, 0b10001, 0b10001, 0b01110], + [0b00000, 0b01110, 0b10001, 0b10001, 0b01111, 0b00001, 0b00010, 0b11100], + [0b00000, 0b00000, 0b00000, 0b00100, 0b00000, 0b00100, 0b00000, 0b00000], + [0b00000, 0b00000, 0b00000, 0b00100, 0b00000, 0b00100, 0b00100, 0b01000], + [0b00000, 0b00010, 0b00100, 0b01000, 0b10000, 0b01000, 0b00100, 0b00010], + [0b00000, 0b00000, 0b00000, 0b11111, 0b00000, 0b11111, 0b00000, 0b00000], + [0b00000, 0b01000, 0b00100, 0b00010, 0b00001, 0b00010, 0b00100, 0b01000], + [0b00000, 0b01110, 0b10001, 0b00010, 0b00100, 0b00100, 0b00000, 0b00100] + ] + + def __init__(self): + self.screen = pygame.display.set_mode((560, 432)) + pygame.display.set_caption("ApplePy") + + def update(self, address, value): + base = address - 0x400 + hi, lo = divmod(base, 0x80) + row_group, column = divmod(lo, 0x28) + row = hi + 8 * row_group + + # skip if writing to row group 3 + if row_group == 3: + return + + mode, ch = divmod(value, 0x40) + + if mode == 0: # inverse + on = (0, 0, 0) + off = (0, 200, 0) + elif mode == 1: # flash + on = (0, 0, 0) + off = (0, 200, 0) + else: # normal + on = (0, 200, 0) + off = (0, 0, 0) + + pixels = pygame.PixelArray(self.screen) + for line in range(8): + b = self.characters[ch][line] + for i in range(5): + x = 2 * (column * 7 + (5 - i)) + y = 2 * (row * 9 + line) + bit = (b >> i) % 2 + pixels[x][y] = on if bit else off + pixels[x + 1][y] = on if bit else off + del pixels + + class RAM: def __init__(self, start, size): @@ -63,7 +171,8 @@ class ROM: class Memory: - def __init__(self): + def __init__(self, display): + self.display = display self.rom = ROM(0xD000, 0x3000) # available from http://www.easy68k.com/paulrsm/6502/index.html @@ -93,33 +202,7 @@ class Memory: if address < 0xC000: self.ram.write_byte(address, value) if 0x400 <= address < 0x800: - self.write_screen(address, value) - - def write_screen(self, address, value): - base = address - 0x400 - hi, lo = divmod(base, 0x80) - row_group, column = divmod(lo, 0x28) - row = hi + 8 * row_group - - # skip if writing to row group 3 - if row_group == 3: - return - - c = chr(0x20 + ((value + 0x20) % 0x40)) - - if value < 0x40: - attr = curses.A_DIM - elif value < 0x80: - attr = curses.A_REVERSE - elif value < 0xA0: - attr = curses.A_UNDERLINE - else: - attr = curses.A_DIM - - try: - self.win.addch(row, column, c, attr) - except curses.error: - pass + self.display.update(address, value) class Disassemble: @@ -523,41 +606,13 @@ class CPU: def reset(self): self.program_counter = self.memory.read_word(self.RESET_VECTOR) - def dump(self, win, op): - win.move(10, 50) - win.clrtoeol() - win.addstr(10, 50, self.disassemble.disasm(self.program_counter - 1)) - win.addstr(14, 50, "BUFFER:" + - " ".join("%02X" % self.memory.read_byte(m) for m in range(0x200, 0x210)) - ) - win.addstr(11, 50, "A=%02X X=%02X Y=%02X S=%02X V=%02X B=%02X D=%02X I=%02X Z=%02X C=%02X PC=%04X S=%02X" % ( - self.accumulator, - self.x_index, - self.y_index, - self.sign_flag, - self.overflow_flag, - self.break_flag, - self.decimal_mode_flag, - self.interrupt_disable_flag, - self.zero_flag, - self.carry_flag, - self.program_counter - 1, - self.stack_pointer)) - win.addstr(12, 50, "STACK:" + - " ".join("%02X" % self.memory.read_byte(self.STACK_PAGE + i) for i in range(255, self.stack_pointer, -1)) - ) - - def run(self, win): - self.memory.win = win - win.clear() - curses.noecho() - win.nodelay(True) - while True: + def run(self): + update_cycle = 0 + quit = False + while not quit: op = self.read_pc_byte() - # self.dump(win, op) func = self.ops[op] if func is None: - curses.endwin() print "UNKNOWN OP" print hex(self.program_counter - 1) print hex(op) @@ -565,18 +620,21 @@ class CPU: else: self.ops[op]() - try: - key = ord(win.getkey()) - if key == 0xA: - key = 0xD - elif key == 0x7F: - key = 0x8 - # win.addstr(15, 50, hex(key)) - self.memory.softswitches.kbd = 0x80 + key - except curses.error: - pass - except TypeError: - pass + for event in pygame.event.get(): + if event.type == pygame.QUIT: + quit = True + + if event.type == pygame.KEYDOWN: + if event.unicode: + key = ord(event.unicode) + if key == 0x7F: + key = 0x08 + self.memory.softswitches.kbd = 0x80 + key + + update_cycle += 1 + if update_cycle >= 1024: + pygame.display.flip() + update_cycle = 0 #### @@ -959,7 +1017,8 @@ class CPU: if __name__ == "__main__": - mem = Memory() + display = Display() + mem = Memory(display) cpu = CPU(mem) - curses.wrapper(cpu.run) + cpu.run() From 4267732d7f96dcff4709ab95f433c9b426d3cb6b Mon Sep 17 00:00:00 2001 From: James Tauber Date: Sat, 13 Aug 2011 04:02:43 -0400 Subject: [PATCH 02/11] make display optional (for testing) --- applepy.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/applepy.py b/applepy.py index ae5a390..4f0c67a 100644 --- a/applepy.py +++ b/applepy.py @@ -175,7 +175,7 @@ class ROM: class Memory: - def __init__(self, display): + def __init__(self, display=None): self.display = display self.rom = ROM(0xD000, 0x3000) @@ -209,7 +209,7 @@ class Memory: def write_byte(self, address, value): if address < 0xC000: self.ram.write_byte(address, value) - if 0x400 <= address < 0x800: + if 0x400 <= address < 0x800 and display: self.display.update(address, value) From 7cc9e8bdad0b8024e0e6b73b24e6ec9cbdeba24c Mon Sep 17 00:00:00 2001 From: James Tauber Date: Sat, 13 Aug 2011 06:33:12 -0400 Subject: [PATCH 03/11] implemented LORES graphics --- applepy.py | 116 ++++++++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 111 insertions(+), 5 deletions(-) diff --git a/applepy.py b/applepy.py index 4f0c67a..e19bcd8 100644 --- a/applepy.py +++ b/applepy.py @@ -4,7 +4,7 @@ import pygame - +import colorsys def signed(x): if x > 0x7F: @@ -81,16 +81,79 @@ class Display: [0b00000, 0b01110, 0b10001, 0b00010, 0b00100, 0b00100, 0b00000, 0b00100] ] + lores_colours = [ + (0, 0, 0), # black + (208, 0, 48), # magenta / dark red + (0, 0, 128), # dark blue + (255, 0, 255), # purple / violet + (0, 128, 0), # dark green + (128, 128, 128), # gray 1 + (0, 0, 255), # medium blue / blue + (96, 160, 255), # light blue + (128, 80, 0), # brown / dark orange + (255, 128 ,0), # orange + (192, 192, 192), # gray 2 + (255, 144, 128), # pink / light red + (0, 255, 0), # light green / green + (255, 255, 0), # yellow / light orange + (64, 255, 144), # aquamarine / light green + (255, 255, 255), # white + ] + def __init__(self): self.screen = pygame.display.set_mode((560, 432)) pygame.display.set_caption("ApplePy") + def txtclr(self): + self.text = False + + def txtset(self): + self.text = True + + def mixclr(self): + self.mix = False + + def mixset(self): + self.mix = True + + def lowscr(self): + self.page = 1 + + def hiscr(self): + self.page = 2 + + def lores(self): + self.high_res = False + + def hires(self): + self.high_res = True + def update(self, address, value): - base = address - 0x400 + if self.page == 1 and 0x400 <= address <= 0x7FF: + if self.text: + self.update_text(address - 0x400, value, False) + elif self.mix: + self.update_lores(address - 0x400, value, True) + self.update_text(address - 0x400, value, True) + else: + self.update_lores(address - 0x400, value, False) + if self.page == 2 and 0x800 <= address <= 0xBFF: + if self.text: + self.update_text(address - 0x800, value, False) + elif self.mix: + self.update_lores(address - 0x400, value, True) + self.update_text(address - 0x400, value, True) + else: + self.update_lores(address - 0x800, value, False) + + def update_text(self, base, value, mixed): hi, lo = divmod(base, 0x80) row_group, column = divmod(lo, 0x28) row = hi + 8 * row_group + if mixed and row < 20: + return + # skip if writing to row group 3 if row_group == 3: return @@ -117,6 +180,28 @@ class Display: pixels[x][y] = on if bit else off pixels[x + 1][y] = on if bit else off del pixels + + def update_lores(self, base, value, mixed): + hi, lo = divmod(base, 0x80) + row_group, column = divmod(lo, 0x28) + row = hi + 8 * row_group + + if mixed and row >= 20: + return + + lower, upper = divmod(value, 0x10) + + pixels = pygame.PixelArray(self.screen) + for dx in range(14): + for dy in range(9): + x = column * 14 + dx + y = row * 18 + dy + pixels[x][y] = self.lores_colours[upper] + for dy in range(9, 18): + x = column * 14 + dx + y = row * 18 + dy + pixels[x][y] = self.lores_colours[lower] + del pixels class RAM: @@ -140,15 +225,36 @@ class RAM: class SoftSwitches: - def __init__(self): + def __init__(self, display): self.kbd = 0x00 + self.display = display def read_byte(self, address): assert 0xC000 <= address <= 0xCFFF if address == 0xC000: return self.kbd - if address == 0xC010: + elif address == 0xC010: self.kbd = self.kbd & 0x7F + elif address == 0xC030: + pass # toggle speaker + elif address == 0xC050: + self.display.txtclr() + elif address == 0xC051: + self.display.txtset() + elif address == 0xC052: + self.display.mixclr() + elif address == 0xC053: + self.display.mixset() + elif address == 0xC054: + self.display.lowscr() + elif address == 0xC055: + self.display.hiscr() + elif address == 0xC056: + self.display.lores() + elif address == 0xC057: + self.display.hires() + else: + pass # print "%04X" % address return 0x00 @@ -183,7 +289,7 @@ class Memory: self.rom.load_file(0xD000, "A2ROM.BIN") self.ram = RAM(0x0000, 0xC000) - self.softswitches = SoftSwitches() + self.softswitches = SoftSwitches(display) def load(self, address, data): if address < 0xC000: From 588f913eb20e230c9ef03b47073574b3542d3fac Mon Sep 17 00:00:00 2001 From: James Tauber Date: Sat, 13 Aug 2011 06:36:21 -0400 Subject: [PATCH 04/11] character heights are really 8 not 9 --- applepy.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/applepy.py b/applepy.py index e19bcd8..41d0315 100644 --- a/applepy.py +++ b/applepy.py @@ -101,7 +101,7 @@ class Display: ] def __init__(self): - self.screen = pygame.display.set_mode((560, 432)) + self.screen = pygame.display.set_mode((560, 384)) pygame.display.set_caption("ApplePy") def txtclr(self): @@ -175,7 +175,7 @@ class Display: b = self.characters[ch][line] for i in range(5): x = 2 * (column * 7 + (5 - i)) - y = 2 * (row * 9 + line) + y = 2 * (row * 8 + line) bit = (b >> i) % 2 pixels[x][y] = on if bit else off pixels[x + 1][y] = on if bit else off @@ -193,13 +193,13 @@ class Display: pixels = pygame.PixelArray(self.screen) for dx in range(14): - for dy in range(9): + for dy in range(8): x = column * 14 + dx - y = row * 18 + dy + y = row * 16 + dy pixels[x][y] = self.lores_colours[upper] - for dy in range(9, 18): + for dy in range(8, 16): x = column * 14 + dx - y = row * 18 + dy + y = row * 16 + dy pixels[x][y] = self.lores_colours[lower] del pixels From 9e92bbba97ad2c3e0b3d95c2a9114a1e92d1ba72 Mon Sep 17 00:00:00 2001 From: James Tauber Date: Sat, 13 Aug 2011 06:37:47 -0400 Subject: [PATCH 05/11] display full width of characters --- applepy.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/applepy.py b/applepy.py index 41d0315..c5a8dd5 100644 --- a/applepy.py +++ b/applepy.py @@ -172,8 +172,8 @@ class Display: pixels = pygame.PixelArray(self.screen) for line in range(8): - b = self.characters[ch][line] - for i in range(5): + b = self.characters[ch][line] << 1 + for i in range(7): x = 2 * (column * 7 + (5 - i)) y = 2 * (row * 8 + line) bit = (b >> i) % 2 From 38736cf24340f0057c6873c517659c095020fd51 Mon Sep 17 00:00:00 2001 From: James Tauber Date: Sat, 13 Aug 2011 07:06:11 -0400 Subject: [PATCH 06/11] refactored update_text and update_lores into a single method --- applepy.py | 120 ++++++++++++++++++++++------------------------------- 1 file changed, 50 insertions(+), 70 deletions(-) diff --git a/applepy.py b/applepy.py index c5a8dd5..ff57ee8 100644 --- a/applepy.py +++ b/applepy.py @@ -129,79 +129,59 @@ class Display: self.high_res = True def update(self, address, value): - if self.page == 1 and 0x400 <= address <= 0x7FF: - if self.text: - self.update_text(address - 0x400, value, False) - elif self.mix: - self.update_lores(address - 0x400, value, True) - self.update_text(address - 0x400, value, True) - else: - self.update_lores(address - 0x400, value, False) - if self.page == 2 and 0x800 <= address <= 0xBFF: - if self.text: - self.update_text(address - 0x800, value, False) - elif self.mix: - self.update_lores(address - 0x400, value, True) - self.update_text(address - 0x400, value, True) - else: - self.update_lores(address - 0x800, value, False) - - def update_text(self, base, value, mixed): - hi, lo = divmod(base, 0x80) - row_group, column = divmod(lo, 0x28) - row = hi + 8 * row_group - - if mixed and row < 20: + if self.page == 1: + start = 0x400 + elif self.page == 2: + start = 0x800 + else: return + + if start <= address <= start + 0x3FF: + base = address - start + hi, lo = divmod(base, 0x80) + row_group, column = divmod(lo, 0x28) + row = hi + 8 * row_group - # skip if writing to row group 3 - if row_group == 3: - return - - mode, ch = divmod(value, 0x40) - - if mode == 0: # inverse - on = (0, 0, 0) - off = (0, 200, 0) - elif mode == 1: # flash - on = (0, 0, 0) - off = (0, 200, 0) - else: # normal - on = (0, 200, 0) - off = (0, 0, 0) + if row_group == 3: + return - pixels = pygame.PixelArray(self.screen) - for line in range(8): - b = self.characters[ch][line] << 1 - for i in range(7): - x = 2 * (column * 7 + (5 - i)) - y = 2 * (row * 8 + line) - bit = (b >> i) % 2 - pixels[x][y] = on if bit else off - pixels[x + 1][y] = on if bit else off - del pixels - - def update_lores(self, base, value, mixed): - hi, lo = divmod(base, 0x80) - row_group, column = divmod(lo, 0x28) - row = hi + 8 * row_group - - if mixed and row >= 20: - return - - lower, upper = divmod(value, 0x10) - - pixels = pygame.PixelArray(self.screen) - for dx in range(14): - for dy in range(8): - x = column * 14 + dx - y = row * 16 + dy - pixels[x][y] = self.lores_colours[upper] - for dy in range(8, 16): - x = column * 14 + dx - y = row * 16 + dy - pixels[x][y] = self.lores_colours[lower] - del pixels + pixels = pygame.PixelArray(self.screen) + + if self.text or not self.mix or not row < 20: + mode, ch = divmod(value, 0x40) + + if mode == 0: # inverse + on = (0, 0, 0) + off = (0, 200, 0) + elif mode == 1: # flash + on = (0, 0, 0) + off = (0, 200, 0) + else: # normal + on = (0, 200, 0) + off = (0, 0, 0) + + for line in range(8): + b = self.characters[ch][line] << 1 + for i in range(7): + x = 2 * (column * 7 + (5 - i)) + y = 2 * (row * 8 + line) + bit = (b >> i) % 2 + pixels[x][y] = on if bit else off + pixels[x + 1][y] = on if bit else off + else: + lower, upper = divmod(value, 0x10) + + for dx in range(14): + for dy in range(8): + x = column * 14 + dx + y = row * 16 + dy + pixels[x][y] = self.lores_colours[upper] + for dy in range(8, 16): + x = column * 14 + dx + y = row * 16 + dy + pixels[x][y] = self.lores_colours[lower] + + del pixels class RAM: From 2f71ca90294bbf904d8f723c74031481a5062b6d Mon Sep 17 00:00:00 2001 From: James Tauber Date: Sat, 13 Aug 2011 07:22:10 -0400 Subject: [PATCH 07/11] in mixed mode, assume monitor is colour --- applepy.py | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/applepy.py b/applepy.py index ff57ee8..24a207b 100644 --- a/applepy.py +++ b/applepy.py @@ -103,18 +103,21 @@ class Display: def __init__(self): self.screen = pygame.display.set_mode((560, 384)) pygame.display.set_caption("ApplePy") + self.mix = False def txtclr(self): self.text = False def txtset(self): self.text = True + self.colour = False def mixclr(self): self.mix = False def mixset(self): self.mix = True + self.colour = True def lowscr(self): self.page = 1 @@ -150,15 +153,14 @@ class Display: if self.text or not self.mix or not row < 20: mode, ch = divmod(value, 0x40) - if mode == 0: # inverse - on = (0, 0, 0) - off = (0, 200, 0) - elif mode == 1: # flash - on = (0, 0, 0) - off = (0, 200, 0) - else: # normal + if self.colour: + on = (255, 255, 255) + else: on = (0, 200, 0) - off = (0, 0, 0) + off = (0, 0, 0) + + if mode == 0 or mode == 1: + on, off = off, on for line in range(8): b = self.characters[ch][line] << 1 From 8f3b64039310e92013535742331fc2549f688c64 Mon Sep 17 00:00:00 2001 From: James Tauber Date: Sat, 13 Aug 2011 07:24:23 -0400 Subject: [PATCH 08/11] always draw the spaces between scanlines --- applepy.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/applepy.py b/applepy.py index 24a207b..6607f29 100644 --- a/applepy.py +++ b/applepy.py @@ -170,6 +170,8 @@ class Display: bit = (b >> i) % 2 pixels[x][y] = on if bit else off pixels[x + 1][y] = on if bit else off + pixels[x][y + 1] = (0, 0, 0) + pixels[x + 1][y + 1] = (0, 0, 0) else: lower, upper = divmod(value, 0x10) From e37c4dcbcdaf667e91488ec1ccb37d1a22dfc8e4 Mon Sep 17 00:00:00 2001 From: James Tauber Date: Sat, 13 Aug 2011 07:52:17 -0400 Subject: [PATCH 09/11] added HIRES graphics support based on code from ghewgill: https://github.com/ghewgill/applepy/commit/5aa8ca2caa82cacdae08d0ffdbab2083b0f4c7a1 --- applepy.py | 60 +++++++++++++++++++++++++++++++++++++++--------------- 1 file changed, 44 insertions(+), 16 deletions(-) diff --git a/applepy.py b/applepy.py index 6607f29..a737063 100644 --- a/applepy.py +++ b/applepy.py @@ -133,14 +133,16 @@ class Display: def update(self, address, value): if self.page == 1: - start = 0x400 + start_text = 0x400 + start_hires = 0x2000 elif self.page == 2: - start = 0x800 + start_text = 0x800 + start_hires = 0x4000 else: return - if start <= address <= start + 0x3FF: - base = address - start + if start_text <= address <= start_text + 0x3FF: + base = address - start_text hi, lo = divmod(base, 0x80) row_group, column = divmod(lo, 0x28) row = hi + 8 * row_group @@ -173,19 +175,43 @@ class Display: pixels[x][y + 1] = (0, 0, 0) pixels[x + 1][y + 1] = (0, 0, 0) else: - lower, upper = divmod(value, 0x10) - - for dx in range(14): - for dy in range(8): - x = column * 14 + dx - y = row * 16 + dy - pixels[x][y] = self.lores_colours[upper] - for dy in range(8, 16): - x = column * 14 + dx - y = row * 16 + dy - pixels[x][y] = self.lores_colours[lower] - + if not self.high_res: + lower, upper = divmod(value, 0x10) + + for dx in range(14): + for dy in range(8): + x = column * 14 + dx + y = row * 16 + dy + pixels[x][y] = self.lores_colours[upper] + for dy in range(8, 16): + x = column * 14 + dx + y = row * 16 + dy + pixels[x][y] = self.lores_colours[lower] del pixels + + elif start_hires <= address <= start_hires + 0x1FFF: + if self.high_res: + base = address - start_hires + row8, b = divmod(base, 0x400) + hi, lo = divmod(b, 0x80) + row_group, column = divmod(lo, 0x28) + row = 8 * (hi + 8 * row_group) + row8 + + if self.mix and row >= 160: + return + + if row < 192 and column < 40: + + pixels = pygame.PixelArray(self.screen) + for b in range(7): + c = 0xFFFFFF if (value & (1 << b)) else 0 + x = 2 * (column * 7 + b) + y = 2 * row + pixels[x][y] = c + pixels[x + 1][y] = c + pixels[x][y + 1] = c + pixels[x + 1][y + 1] = c + del pixels class RAM: @@ -301,6 +327,8 @@ class Memory: self.ram.write_byte(address, value) if 0x400 <= address < 0x800 and display: self.display.update(address, value) + if 0x2000 <= address < 0x5FFF and display: + self.display.update(address, value) class Disassemble: From 5a8bf9a51638d9fdc8aced34aa39d5b5a764a104 Mon Sep 17 00:00:00 2001 From: Greg Hewgill Date: Sat, 13 Aug 2011 23:52:15 +1200 Subject: [PATCH 10/11] use pregenerated character bitmaps for text mode --- applepy.py | 44 +++++++++++++++++++++++--------------------- 1 file changed, 23 insertions(+), 21 deletions(-) diff --git a/applepy.py b/applepy.py index a737063..5ee625e 100644 --- a/applepy.py +++ b/applepy.py @@ -104,6 +104,25 @@ class Display: self.screen = pygame.display.set_mode((560, 384)) pygame.display.set_caption("ApplePy") self.mix = False + + self.chargen = [] + for c in self.characters: + chars = [[pygame.Surface((14, 16)), pygame.Surface((14, 16))], + [pygame.Surface((14, 16)), pygame.Surface((14, 16))]] + for colour in (0, 1): + hue = (255, 255, 255) if colour else (0, 200, 0) + for inv in (0, 1): + pixels = pygame.PixelArray(chars[colour][inv]) + off = hue if inv else (0, 0, 0) + on = (0, 0, 0) if inv else hue + for row in range(8): + b = c[row] << 1 + for col in range(7): + bit = (b >> (6 - col)) & 1 + pixels[2 * col][2 * row] = on if bit else off + pixels[2 * col + 1][2 * row] = on if bit else off + del pixels + self.chargen.append(chars) def txtclr(self): self.text = False @@ -150,31 +169,14 @@ class Display: if row_group == 3: return - pixels = pygame.PixelArray(self.screen) - if self.text or not self.mix or not row < 20: mode, ch = divmod(value, 0x40) - if self.colour: - on = (255, 255, 255) - else: - on = (0, 200, 0) - off = (0, 0, 0) + inv = mode in (0, 1) - if mode == 0 or mode == 1: - on, off = off, on - - for line in range(8): - b = self.characters[ch][line] << 1 - for i in range(7): - x = 2 * (column * 7 + (5 - i)) - y = 2 * (row * 8 + line) - bit = (b >> i) % 2 - pixels[x][y] = on if bit else off - pixels[x + 1][y] = on if bit else off - pixels[x][y + 1] = (0, 0, 0) - pixels[x + 1][y + 1] = (0, 0, 0) + self.screen.blit(self.chargen[ch][self.colour][inv], (2 * (column * 7), 2 * (row * 8))) else: + pixels = pygame.PixelArray(self.screen) if not self.high_res: lower, upper = divmod(value, 0x10) @@ -187,7 +189,7 @@ class Display: x = column * 14 + dx y = row * 16 + dy pixels[x][y] = self.lores_colours[lower] - del pixels + del pixels elif start_hires <= address <= start_hires + 0x1FFF: if self.high_res: From 1be14989caa714dcf1adc08e83cb5bfef60d27c8 Mon Sep 17 00:00:00 2001 From: James Tauber Date: Sat, 13 Aug 2011 09:11:46 -0400 Subject: [PATCH 11/11] implemented HIRES colour --- applepy.py | 34 ++++++++++++++++++++++++++++------ 1 file changed, 28 insertions(+), 6 deletions(-) diff --git a/applepy.py b/applepy.py index 5ee625e..7b1d211 100644 --- a/applepy.py +++ b/applepy.py @@ -205,14 +205,36 @@ class Display: if row < 192 and column < 40: pixels = pygame.PixelArray(self.screen) + msb = value // 0x80 + for b in range(7): - c = 0xFFFFFF if (value & (1 << b)) else 0 - x = 2 * (column * 7 + b) + c = value & (1 << b) + xx = (column * 7 + b) + x = 2 * xx y = 2 * row - pixels[x][y] = c - pixels[x + 1][y] = c - pixels[x][y + 1] = c - pixels[x + 1][y + 1] = c + + if msb: + if xx % 2: + pixels[x][y] = (0, 0, 0) + # orange + pixels[x + 1][y] = (255, 192, 0) if c else (0, 0, 0) + else: + # blue + pixels[x][y] = (0, 128, 224) if c else (0, 0, 0) + pixels[x + 1][y] = (0, 0, 0) + else: + if xx % 2: + pixels[x][y] = (0, 0, 0) + # green + pixels[x + 1][y] = (0, 255, 0) if c else (0, 0, 0) + else: + # violet + pixels[x][y] = (255, 0, 255) if c else (0, 0, 0) + pixels[x + 1][y] = (0, 0, 0) + + pixels[x][y + 1] = (0, 0, 0) + pixels[x + 1][y + 1] = (0, 0, 0) + del pixels