Skip to content

Commit

Permalink
cleanup and start to implement the 6809 CPU
Browse files Browse the repository at this point in the history
  • Loading branch information
jedie committed Sep 10, 2013
1 parent 1dd75b5 commit 591d2ed
Show file tree
Hide file tree
Showing 13 changed files with 1,254 additions and 2,449 deletions.
22 changes: 22 additions & 0 deletions AUTHORS
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@


origin code based on:
ApplePy - an Apple ][ emulator in Python
by James Tauber / http://jtauber.com/ / https://github.com/jtauber/applepy
originally written 2001, updated 2011
origin source code licensed under MIT License


PRIMARY AUTHORS are and/or have been (alphabetic order):

Diemer, Jens
ohloh.net profile: <http://www.ohloh.net/accounts/4179/>
Homepage: <http://www.jensdiemer.de/>


CONTRIBUTORS are and/or have been (alphabetic order):
...


Spezial thanks to the python-forum.de guys, particularly (in alphabetic order):
...
166 changes: 61 additions & 105 deletions DragonPy.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,16 @@
#!/usr/bin/env python

# ApplePy - an Apple ][ emulator in Python
# James Tauber / http://jtauber.com/
# originally written 2001, updated 2011
"""
DragonPy - Dragon 32 emulator in Python
=======================================
Based on:
ApplePy - an Apple ][ emulator in Python:
James Tauber / http://jtauber.com/ / https://github.com/jtauber/applepy
originally written 2001, updated 2011
origin source code licensed under MIT License
"""


import numpy
Expand All @@ -15,9 +23,11 @@
import time
import wave

from configs import Dragon32Cfg


class Display(object):

class Display:

characters = [
[0b00000, 0b01110, 0b10001, 0b10101, 0b10111, 0b10110, 0b10000, 0b01111],
[0b00000, 0b00100, 0b01010, 0b10001, 0b10001, 0b11111, 0b10001, 0b10001],
Expand Down Expand Up @@ -84,7 +94,7 @@ class Display:
[0b00000, 0b01000, 0b00100, 0b00010, 0b00001, 0b00010, 0b00100, 0b01000],
[0b00000, 0b01110, 0b10001, 0b00010, 0b00100, 0b00100, 0b00000, 0b00100]
]

lores_colours = [
(0, 0, 0), # black
(208, 0, 48), # magenta / dark red
Expand All @@ -103,7 +113,7 @@ class Display:
(64, 255, 144), # aquamarine / light green
(255, 255, 255), # white
]

def __init__(self):
self.screen = pygame.display.set_mode((560, 384))
pygame.display.set_caption("DragonPy")
Expand All @@ -115,7 +125,7 @@ def __init__(self):
self.page = 1
self.text = True
self.colour = False

self.chargen = []
for c in self.characters:
chars = [[pygame.Surface((14, 16)), pygame.Surface((14, 16))],
Expand All @@ -134,33 +144,33 @@ def __init__(self):
pixels[2 * col + 1][2 * row] = on if bit else off
del pixels
self.chargen.append(chars)

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

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):
if self.page == 1:
start_text = 0x400
Expand All @@ -170,33 +180,33 @@ def update(self, address, value):
start_hires = 0x4000
else:
return

if start_text <= address <= start_text + 0x3FF:
base = address - start_text
self.flash_chars[self.page - 1][base] = value
hi, lo = divmod(base, 0x80)
row_group, column = divmod(lo, 0x28)
row = hi + 8 * row_group

if row_group == 3:
return

if self.text or not self.mix or not row < 20:
mode, ch = divmod(value, 0x40)

if mode == 0:
inv = True
elif mode == 1:
inv = self.flash_on
else:
inv = False

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)

for dx in range(14):
for dy in range(8):
x = column * 14 + dx
Expand All @@ -207,29 +217,29 @@ def update(self, address, value):
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)
msb = value // 0x80

for b in range(7):
c = value & (1 << b)
xx = (column * 7 + b)
x = 2 * xx
y = 2 * row

if msb:
if xx % 2:
pixels[x][y] = (0, 0, 0)
Expand All @@ -252,10 +262,10 @@ def update(self, address, value):
pixels[x][y] = (255, 0, 255) if c else (0, 0, 0)
pixels[x + 1][y] = (0, 0, 0)
pixels[x + 1][y] = (255, 0, 255) if c else (0, 0, 0) # @@@

pixels[x][y + 1] = (0, 0, 0)
pixels[x + 1][y + 1] = (0, 0, 0)

del pixels

def flash(self):
Expand All @@ -268,34 +278,34 @@ def flash(self):


class Speaker:

CPU_CYCLES_PER_SAMPLE = 60
CHECK_INTERVAL = 1000

def __init__(self):
pygame.mixer.pre_init(11025, -16, 1)
pygame.init()
self.reset()

def toggle(self, cycle):
if self.last_toggle is not None:
l = (cycle - self.last_toggle) / Speaker.CPU_CYCLES_PER_SAMPLE
self.buffer.extend([0, 26000] if self.polarity else [0, -2600])
self.buffer.extend((l - 2) * [16384] if self.polarity else [-16384])
self.polarity = not self.polarity
self.last_toggle = cycle

def reset(self):
self.last_toggle = None
self.buffer = []
self.polarity = False

def play(self):
sample_array = numpy.int16(self.buffer)
sound = pygame.sndarray.make_sound(sample_array)
sound.play()
self.reset()

def update(self, cycle):
if self.buffer and (cycle - self.last_toggle) > self.CHECK_INTERVAL:
self.play()
Expand All @@ -322,13 +332,13 @@ def read_byte(self, cycle):


class SoftSwitches:

def __init__(self, display, speaker, cassette):
self.kbd = 0x00
self.display = display
self.speaker = speaker
self.cassette = cassette

def read_byte(self, cycle, address):
assert 0xC000 <= address <= 0xCFFF
if address == 0xC000:
Expand Down Expand Up @@ -362,9 +372,9 @@ def read_byte(self, cycle, address):
return 0x00


class Apple2:
class Dragon(object):

def __init__(self, options, display, speaker, cassette):
def __init__(self, cfg, display, speaker, cassette):
self.display = display
self.speaker = speaker
self.softswitches = SoftSwitches(display, speaker, cassette)
Expand All @@ -377,15 +387,15 @@ def __init__(self, options, display, speaker, cassette):
sys.executable,
"cpu6809.py",
"--bus", str(listener.getsockname()[1]),
"--rom", options.rom,
"--rom", cfg.rom,
]
if options.ram:
if cfg.ram:
args.extend([
"--ram", options.ram,
"--ram", cfg.ram,
])
if options.pc is not None:
if cfg.pc is not None:
args.extend([
"--pc", str(options.pc),
"--pc", str(cfg.pc),
])
self.core = subprocess.Popen(args)

Expand All @@ -409,11 +419,11 @@ def run(self):
self.display.update(addr, val)
else:
break

for event in pygame.event.get():
if event.type == pygame.QUIT:
quit = True

if event.type == pygame.KEYDOWN:
key = ord(event.unicode) if event.unicode else 0
if event.key == pygame.K_LEFT:
Expand All @@ -424,71 +434,17 @@ def run(self):
if key == 0x7F:
key = 0x08
self.softswitches.kbd = 0x80 + (key & 0x7F)

update_cycle += 1
if update_cycle >= 1024:
self.display.flash()
pygame.display.flip()
if self.speaker:
self.speaker.update(cycle)
update_cycle = 0


def usage():
print >>sys.stderr, "ApplePy - an Apple ][ emulator in Python"
print >>sys.stderr, "James Tauber / http://jtauber.com/"
print >>sys.stderr
print >>sys.stderr, "Usage: applepy.py [options]"
print >>sys.stderr
print >>sys.stderr, " -c, --cassette Cassette wav file to load"
print >>sys.stderr, " -R, --rom ROM file to use (default A2ROM.BIN)"
print >>sys.stderr, " -r, --ram RAM file to load (default none)"
print >>sys.stderr, " -p, --pc Initial PC value"
print >>sys.stderr, " -q, --quiet Quiet mode, no sounds (default sounds)"
sys.exit(1)


def get_options():
class Options:
def __init__(self):
self.cassette = None
self.rom = "Dragon 32 - IC17.ROM"
self.ram = None
self.pc = None
self.quiet = False

options = Options()
a = 1
while a < len(sys.argv):
if sys.argv[a].startswith("-"):
if sys.argv[a] in ("-c", "--cassette"):
a += 1
options.cassette = sys.argv[a]
elif sys.argv[a] in ("-R", "--rom"):
a += 1
options.rom = sys.argv[a]
elif sys.argv[a] in ("-r", "--ram"):
a += 1
options.ram = sys.argv[a]
elif sys.argv[a] in ("-p", "--pc"):
a += 1
options.pc = int(sys.argv[a])
elif sys.argv[a] in ("-q", "--quiet"):
options.quiet = True
else:
usage()
else:
usage()
a += 1

return options


if __name__ == "__main__":
options = get_options()
display = Display()
speaker = None if options.quiet else Speaker()
cassette = Cassette(options.cassette) if options.cassette else None

apple = Apple2(options, display, speaker, cassette)
apple.run()
print "Run DragonPy_CLI.py instead"
sys.exit(0)
Loading

0 comments on commit 591d2ed

Please sign in to comment.