Skip to content

Commit

Permalink
WIP: Just add dummy code for Vectrex
Browse files Browse the repository at this point in the history
  • Loading branch information
jedie committed Aug 31, 2014
1 parent 949fe0b commit 65539a7
Show file tree
Hide file tree
Showing 12 changed files with 579 additions and 56 deletions.
19 changes: 16 additions & 3 deletions README.creole
Expand Up @@ -33,6 +33,19 @@ Looks like this:
{{http://www.jensdiemer.de/static/jensdiemer.de/screenshots/20140820_DragonPy_BASIC_Editor_01.png|old screenshot BASIC Editor}}
(older version of the editor)


==== Vectrex

The [[https://en.wikipedia.org/wiki/Vectrex|Vectrex]] is a vector display-based video game console.
The Hardware are //only// the 6809 CPU, a 6522 Versatile Interface Adapter and the AY-3-8912 sound chip.

Current state is completely not usable. The 6522 is only a dummy implementation.
It makes only sense to display some trace lines, e.g.:
{{{
...path/to/DragonPy$ python2 DragonPy_CLI.py --verbosity 5 --machine=Vectrex run --trace --max_ops 1
}}}


=== BASIC Editor

Use "BASIC editor / open" in the main menu to open the editor.
Expand All @@ -46,7 +59,7 @@ The "renumbering" tool can be found in the editor window under "tools"
You can also run the BASIC Editor without the Emulator:

{{{
...path/to/DragonPy$ DragonPy_CLI.py editor
...path/to/DragonPy$ python2 DragonPy_CLI.py editor
}}}

A rudimentary BASIC source code highlighting is available and looks like this:
Expand Down Expand Up @@ -94,12 +107,12 @@ There is a simple shell script to automatic download and extract the Dragon ROMs

start Dragon 32:
{{{
...path/to/DragonPy$ DragonPy_CLI.py --machine=Dragon32 run
...path/to/DragonPy$ python2 DragonPy_CLI.py --machine=Dragon32 run
}}}

start Dragon 64:
{{{
...path/to/DragonPy$ DragonPy_CLI.py --machine=Dragon64 run
...path/to/DragonPy$ python2 DragonPy_CLI.py --machine=Dragon64 run
}}}

start CoCo with Extended Color Basic v1.1:
Expand Down
16 changes: 10 additions & 6 deletions dragonpy/DragonPy_CLI.py
Expand Up @@ -23,16 +23,20 @@
from dragonpy.Dragon32.machine import run_Dragon32
from dragonpy.Dragon64.config import Dragon64Cfg
from dragonpy.Dragon64.machine import run_Dragon64
from dragonpy.core import configs
from dragonpy.core.base_cli import Base_CLI
from dragonpy.core.configs import machine_dict
from dragonpy.vectrex.config import VectrexCfg
from dragonpy.vectrex.machine import run_Vectrex


machine_dict.register("Dragon32", (run_Dragon32, Dragon32Cfg), default=True)
machine_dict.register("Dragon64", (run_Dragon64, Dragon64Cfg))
machine_dict.register("CoCo2b", (run_CoCo2b,CoCo2bCfg))
# machine_dict.register("sbc09", SBC09Cfg)
# machine_dict.register("Simple6809", Simple6809Cfg)
# machine_dict.register("Multicomp6809", Multicomp6809Cfg)
machine_dict.register(configs.DRAGON32, (run_Dragon32, Dragon32Cfg), default=True)
machine_dict.register(configs.DRAGON64, (run_Dragon64, Dragon64Cfg))
machine_dict.register(configs.COCO2B, (run_CoCo2b, CoCo2bCfg))
# machine_dict.register(SBC09, SBC09Cfg)
# machine_dict.register(SIMPLE6809, Simple6809Cfg)
# machine_dict.register(MULTICOMP6809, Multicomp6809Cfg)
machine_dict.register(configs.VECTREX, (run_Vectrex, VectrexCfg))


@atexit.register
Expand Down
1 change: 1 addition & 0 deletions dragonpy/core/configs.py
Expand Up @@ -23,6 +23,7 @@
SBC09 = "sbc09"
SIMPLE6809 = "Simple6809"
MULTICOMP6809 = "Multicomp6809"
VECTREX = "Vectrex"


class MachineDict(dict):
Expand Down
103 changes: 56 additions & 47 deletions dragonpy/core/gui.py
Expand Up @@ -102,7 +102,7 @@ def write_byte(self, cpu_cycles, op_address, address, value):
self.canvas.itemconfigure(image_id, image=image)


class DragonTkinterGUI(object):
class BaseTkinterGUI(object):
"""
The complete Tkinter GUI window
"""
Expand All @@ -125,64 +125,26 @@ def __init__(self, cfg, display_queue, user_input_queue, cpu_status_queue, reque
self.last_cpu_cycle_update = time.time()

self.root = Tkinter.Tk(className="DragonPy")
machine_name = self.cfg.MACHINE_NAME
self.root.title(
"%s - Text Display 32 columns x 16 rows" % machine_name)

self.root.bind("<Key>", self.event_key_pressed)
self.root.bind("<<Paste>>", self.paste_clipboard)

self.display = MC6847_TextModeCanvas(self.root)
self.display.canvas.grid(row=0, column=0, columnspan=2) # , rowspan=2)

self.status = Tkinter.StringVar()
self.status_widget = Tkinter.Label(
self.root, textvariable=self.status, text="Info:", borderwidth=1)
self.status_widget.grid(row=1, column=0, columnspan=2)

menubar = Tkinter.Menu(self.root)
self.menubar = Tkinter.Menu(self.root)

filemenu = Tkinter.Menu(menubar, tearoff=0)
filemenu = Tkinter.Menu(self.menubar, tearoff=0)
filemenu.add_command(label="Exit", command=self.exit)
menubar.add_cascade(label="File", menu=filemenu)

editmenu = Tkinter.Menu(menubar, tearoff=0)
# editmenu.add_command(label="load BASIC program", command=self.load_program)
# editmenu.add_command(label="dump BASIC program", command=self.dump_program)
editmenu.add_command(label="open", command=self.open_basic_editor)
menubar.add_cascade(label="BASIC editor", menu=editmenu)
self.menubar.add_cascade(label="File", menu=filemenu)

# help menu
helpmenu = Tkinter.Menu(menubar, tearoff=0)
helpmenu = Tkinter.Menu(self.menubar, tearoff=0)
helpmenu.add_command(label="help", command=self.menu_event_help)
helpmenu.add_command(label="about", command=self.menu_event_about)
menubar.add_cascade(label="help", menu=helpmenu)

# display the menu
self.root.config(menu=menubar)
self.root.update()

self.editor_content = None
self._editor_window = None

def open_basic_editor(self):
self._editor_window = EditorWindow(self.cfg, self)

def dump_rnd(self):
start_addr = 0x0019
end_addr = 0x0020
dump, start_addr, end_addr = self.request_comm.request_memory_dump(
# start_addr=0x0115, end_addr=0x0119 # RND seed
start_addr, end_addr
)
def format_dump(dump, start_addr, end_addr):
lines = []
for addr, value in zip(xrange(start_addr, end_addr + 1), dump):
log.critical("$%04x: $%02x (dez.: %i)", addr, value, value)
lines.append("$%04x: $%02x (dez.: %i)" % (addr, value, value))
return lines
lines = format_dump(dump, start_addr, end_addr)
tkMessageBox.showinfo("TODO", "dump_program:\n%s" % "\n".join(lines))
self.menubar.add_cascade(label="help", menu=helpmenu)

def menu_event_about(self):
tkMessageBox.showinfo("DragonPy",
Expand All @@ -206,14 +168,14 @@ def exit(self):
def add_user_input(self, txt):
for char in txt:
self.user_input_queue.put(char)

def wait_until_input_queue_empty(self):
for count in xrange(4):
if self.user_input_queue.empty():
log.critical("user_input_queue is empty, after %.1f Sec., ok.", (0.1*count))
log.critical("user_input_queue is empty, after %.1f Sec., ok.", (0.1 * count))
return
time.sleep(0.25)
log.critical("user_input_queue not empty, after %.1f Sec.!", (0.1*count))
log.critical("user_input_queue not empty, after %.1f Sec.!", (0.1 * count))

def add_user_input_and_wait(self, txt):
self.add_user_input(txt)
Expand Down Expand Up @@ -303,6 +265,53 @@ def mainloop(self):
log.critical("root.mainloop() has quit!")


class DragonTkinterGUI(BaseTkinterGUI):
"""
The complete Tkinter GUI window
"""
def __init__(self, *args, **kwargs):
super(DragonTkinterGUI, self).__init__(*args, **kwargs)

machine_name = self.cfg.MACHINE_NAME
self.root.title(
"%s - Text Display 32 columns x 16 rows" % machine_name)

self.display = MC6847_TextModeCanvas(self.root)
self.display.canvas.grid(row=0, column=0, columnspan=2) # , rowspan=2)

self.editor_content = None
self._editor_window = None

editmenu = Tkinter.Menu(self.menubar, tearoff=0)
# editmenu.add_command(label="load BASIC program", command=self.load_program)
# editmenu.add_command(label="dump BASIC program", command=self.dump_program)
editmenu.add_command(label="open", command=self.open_basic_editor)
self.menubar.add_cascade(label="BASIC editor", menu=editmenu)

# display the menu
self.root.config(menu=self.menubar)
self.root.update()

def open_basic_editor(self):
self._editor_window = EditorWindow(self.cfg, self)

def dump_rnd(self):
start_addr = 0x0019
end_addr = 0x0020
dump, start_addr, end_addr = self.request_comm.request_memory_dump(
# start_addr=0x0115, end_addr=0x0119 # RND seed
start_addr, end_addr
)
def format_dump(dump, start_addr, end_addr):
lines = []
for addr, value in zip(xrange(start_addr, end_addr + 1), dump):
log.critical("$%04x: $%02x (dez.: %i)", addr, value, value)
lines.append("$%04x: $%02x (dez.: %i)" % (addr, value, value))
return lines
lines = format_dump(dump, start_addr, end_addr)
tkMessageBox.showinfo("TODO", "dump_program:\n%s" % "\n".join(lines))


def test_run_direct():
import subprocess
cmd_args = [
Expand Down
46 changes: 46 additions & 0 deletions dragonpy/vectrex/MOS6522.py
@@ -0,0 +1,46 @@
# encoding:utf8

"""
DragonPy
========
:created: 2014 by Jens Diemer - www.jensdiemer.de
:copyleft: 2014 by the DragonPy team, see AUTHORS for more details.
:license: GNU GPL v3 or above, see LICENSE for more details.
"""


from dragonlib.utils.logging_utils import log


class MOS6522VIA(object):
"""
MOS Technology 6522 Versatile Interface Adapter (VIA)
https://en.wikipedia.org/wiki/MOS_Technology_6522
$D000 - $D7FF 6522 interface adapter
$D800 - $DFFF 6522 / RAM ?!?
"""
def __init__(self, cfg, memory):
self.cfg = cfg
self.memory = memory

self.memory.add_read_byte_callback(
callback_func=self.read_byte,
start_addr=0xd000,
end_addr=0xdfff
)

self.memory.add_write_byte_callback(
callback_func=self.write_byte,
start_addr=0xd000,
end_addr=0xdfff
)

def read_byte(self, cpu_cycles, op_address, address):
log.error("%04x| TODO: 6522 read byte from $%04x - Send 0x00 back", op_address, address)
return 0x00

def write_byte(self, cpu_cycles, op_address, address, value):
log.error("%04x| TODO: 6522 write $%02x to $%04x", op_address, value, address)
Binary file added dragonpy/vectrex/SYSTEM.IMG
Binary file not shown.
Empty file added dragonpy/vectrex/__init__.py
Empty file.
88 changes: 88 additions & 0 deletions dragonpy/vectrex/config.py
@@ -0,0 +1,88 @@
# coding: utf-8

"""
DragonPy - Vectrex
==================
https://en.wikipedia.org/wiki/Vectrex
:created: 2014 by Jens Diemer - www.jensdiemer.de
:copyleft: 2014 by the DragonPy team, see AUTHORS for more details.
:license: GNU GPL v3 or above, see LICENSE for more details.
"""

import logging
import os

# from dragonlib.api import VectrexAPI
from dragonlib.utils.logging_utils import log
from dragonpy.core.configs import BaseConfig, VECTREX
from dragonpy.components.rom import ROMFile
from dragonpy.vectrex.mem_info import VectrexMemInfo


class VectrexCfg(BaseConfig):
"""
http://www.playvectrex.com/designit/chrissalo/toc.htm
$0000 - $7FFF Cartridge ROM
$8000 - $C7FF Unmapped space
$C800 - $CFFF RAM
$D000 - $D7FF 6522 interface adapter
$D800 - $DFFF 6522 / RAM ?!?
$E000 - $EFFF ROM - builtin Mine storm game
$F000 - $FFFF ROM - vectrex BIOS Executive
"""
CONFIG_NAME = VECTREX
MACHINE_NAME = "Vectrex"

RAM_START = 0xC800
RAM_END = 0xCFFF

ROM_START = 0xE000
ROM_END = 0xFFFF
ROM_SIZE = 0x2000

DEFAULT_ROMS = (
ROMFile(address=0xE000, # max_size=0x4000,
filepath=os.path.join(os.path.abspath(os.path.dirname(__file__)),
"SYSTEM.IMG"
)
),
)

# for unittests init:
# STARTUP_END_ADDR = 0xbbe5 # scan keyboard

def __init__(self, cmd_args):
self.ROM_SIZE = (self.ROM_END - self.ROM_START) + 1
self.RAM_SIZE = (self.RAM_END - self.RAM_START) + 1
super(VectrexCfg, self).__init__(cmd_args)

self.machine_api = None# VectrexAPI()

self.periphery_class = None# VectrexPeriphery

# TODO:
# http://www.playvectrex.com/designit/chrissalo/appendixa.htm#Other
if self.verbosity <= logging.ERROR:
self.mem_info = VectrexMemInfo(log.debug)


config = VectrexCfg


def test_run():
import sys
import os
import subprocess
cmd_args = [
sys.executable,
os.path.join("..", "DragonPy_CLI.py"),
"--machine", "Vectrex", "run",
]
print "Startup CLI with: %s" % " ".join(cmd_args[1:])
subprocess.Popen(cmd_args, cwd="..").wait()

if __name__ == "__main__":
test_run()

0 comments on commit 65539a7

Please sign in to comment.