Sophie

Sophie

distrib > Mandriva > 2010.2 > i586 > media > contrib-backports > by-pkgid > df29c83ca401d91ec9c00bfcf7fea4ea > files > 146

shedskin-0.8-2mdv2010.2.i586.rpm

#!/usr/bin/env python2
# I, Danny Milosavljevic, hereby place this file into the public domain.

import pygtk
pygtk.require("2.0")
import gtk
import gobject
import sys
import time
from c64 import c64, screens
from c64.symbols import S_A, S_X, S_Y, S_SP, S_PC
from optparse import OptionParser

def unpack_unsigned(value):
    return value

def to_signed_byte(value):
    return value if value < 0x80 else -(256 - value)

class StatusDialog(gtk.Dialog):
    def __init__(self, *args, **kwargs):
        gtk.Dialog.__init__(self, *args, **kwargs)
        self.size_group = gtk.SizeGroup(gtk.SIZE_GROUP_HORIZONTAL)
        self.add_button(gtk.STOCK_CLOSE, gtk.RESPONSE_CLOSE)
        self.controls = {}
        for ID in [S_A, S_X, S_Y, S_SP, S_PC]:
            self.add_line(ID)

    def add_line(self, ID):
        box = gtk.HBox()
        label = gtk.Label(chr(ID))
        self.size_group.add_widget(label)
        control = gtk.Label()
        box.pack_start(label, False, False)
        box.pack_start(control, True, True)
        self.vbox.pack_start(box, False, False)
        self.controls[ID] = control
        return control

    def set_value(self, ID, value):
        v = unpack_unsigned(value)
        text = "$%04X=%r=%r" % (v, v, to_signed_byte(value) if ID != S_PC else value)
        self.controls[ID].set_text(text)

class Controls(gtk.VBox):
    def __init__(self, c64):
        gtk.VBox.__init__(self)
        self.C64 = c64
        self.status_dialog = None
        keyboard_matrix = self.C64.CIA1.get_keyboard_matrix()
        self.hardware_keycodes = {} # keyval_name -> keycode
        self.keycode_names = {}
        self.keymap = gtk.gdk.keymap_get_default()
        self.screen_count = 0
        alternatives = { # C64_name: GDK_name
            "grave": "numbersign", # German
            "LeftArrow": "Escape",
            "pound": "F9",
            "/": "F8", # actually overwritten below :P
            "=": "F7", # eep.
            ";": "F6", # eep.
        }
        for row in keyboard_matrix:
            for cell in row:
                #print(cell)
                entries = self.keymap.get_entries_for_keyval(gtk.gdk.keyval_from_name(alternatives.get(cell) or cell) or ord(cell))
                if entries is None:
                    entries = self.keymap.get_entries_for_keyval(gtk.gdk.keyval_from_name(alternatives[cell]))
                    #print(cell)
                assert(entries)
                hardware_keycode = entries[0][0]
                self.hardware_keycodes[cell] = hardware_keycode
                self.keycode_names[hardware_keycode] = cell # for the C64, that is.
        self.hardware_keycodes["/"] = 20 # FIXME remove this.
        self.keycode_names[20] = "/" # FIXME remove this.
                
        status_button = gtk.Button("_Status")
        status_button.connect("clicked", self.show_status)
        pause_button = gtk.Button("_Pause")
        pause_button.connect("clicked", self.pause_CPU)
        read_memory_button = gtk.Button("_Read Memory...")
        read_memory_button.connect("clicked", self.dump_memory)
        toggle_disassembly_button = gtk.Button("_Toggle Disassembly")
        toggle_disassembly_button.connect("clicked", self.toggle_disassembly)
        self.pack_start(status_button, False)
        self.pack_start(pause_button, False)
        self.pack_start(read_memory_button, False)
        self.pack_start(toggle_disassembly_button, False)
        self.show_all()
    def set_timer(self):
        self.timer = gobject.timeout_add(16, self.fire_timer)
        #self.timer = gobject.timeout_add(90, self.fire_timer)
    def unset_timer(self):
        gobject.source_remove(self.timer)
        self.timer = 0
    def is_timer_running(self):
        return(self.timer != 0)
    def fire_timer(self):
        # FIXME self.C64.CIA1.pressed_keys = self.graphics_view.event_box.pressed_keys
        t0 = time.time()
        self.C64.fire_timer()
        #self.graphics_view.repaint()
        self.screen_count += 1
        if self.screen_count % 10 == 0:
            print 'drawing speed: %.2f fps' % (1 / (time.time()-t0))
        return True

    def show_status(self, *args, **kwargs):
        toplevel_widget = self.get_toplevel()
        if self.status_dialog is None:
            self.status_dialog = StatusDialog(parent = toplevel_widget)
            def unset_status_dialog(*args, **kwargs):
                self.status_dialog = None
            self.status_dialog.set_transient_for(toplevel_widget)
            self.status_dialog.connect("delete-event", unset_status_dialog)
            self.status_dialog.show_all()
            gobject.timeout_add(50, self.update_status) # FIXME don't do that too often.

        self.update_status()

    def pause_CPU(self, widget, *args, **kwargs):
        # FIXME abstract that properly.
        C64 = self.C64
        if self.is_timer_running():
            self.unset_timer()
            widget.set_label("_Continue")
        else:
            self.set_timer()
            widget.set_label("_Pause")

    def toggle_disassembly(self, *args, **kwargs):
        self.C64.CPU.B_disasm = not self.C64.CPU.B_disasm
        
    def dump_memory(self, *args, **kwargs):
        MMU = self.C64.CPU.MMU
        address = 0xF3 # 300
        sys.stdout.write("(%04X) " % address)
        for i in range(16):
            v = MMU.read_memory(address + i, 1)
            sys.stdout.write("%02X " % v)
        sys.stdout.write("\n")

    def update_status(self):
        if self.status_dialog is None:
            return False
        C64 = self.C64
        for register in [S_A, S_X, S_Y, S_SP, S_PC]:
            self.status_dialog.set_value(register, C64.CPU.read_register(register))
        return True

    def handle_key_press(self, keycode):
        n = self.keycode_names.get(keycode)
        if n:
            return self.C64.CIA1.handle_key_press(n)

    def handle_key_release(self, keycode):
        n = self.keycode_names.get(keycode)
        if n:
            return self.C64.CIA1.handle_key_release(n)

# TODO 3 bit row counter.

class EventBox(gtk.EventBox):
    def __init__(self, controls):
        gtk.EventBox.__init__(self)
        self.controls = controls
        self.props.can_focus = True
        #self.pressed_keys = set()
        #self.keymap = gtk.gdk.keymap_get_default()
        self.connect("key-press-event", self.handle_key_press)
        self.connect("key-release-event", self.handle_key_release)
        self.connect("button-press-event", self.handle_button_press)
    def handle_button_press(self, widget, event):
        self.grab_focus()
        return False
    def handle_key_press(self, widget, event):
        return self.controls.handle_key_press(event.hardware_keycode)
    def handle_key_release(self, widget, event):
        # hardware_keycode
        return self.controls.handle_key_release(event.hardware_keycode)
        #self.pressed_keys.discard(event.keycode)

class View(object): # graphical part.
    def __init__(self, c64, controls):
        self.screen = c64.VIC.screen
        native_pixbuf = self.screen.get_rendered_pixbuf()
        if native_pixbuf != 0:
            self.pixbuf = gobjectc.PyGObjectCPAI().pygobject_new(native_pixbuf)
            self.B_create_flip_pixbuf = False
        else:
            self.pixbuf = None
            self.B_create_flip_pixbuf = True
        #self.pixbuf = gtk.gdk.Pixbuf(gtk.gdk.COLORSPACE_RGB, True, 8, screens.WIDTH, screens.HEIGHT)
        #self.pixbuf.fill(0x000000FF)
        self.window = gtk.Window()
        self.event_box = EventBox(controls)
        self.drawing_area = gtk.DrawingArea()
        self.drawing_area.connect("realize", self.allocate_GC)
        self.drawing_area.connect("expose-event", self.repaint_X)
        self.drawing_area.set_size_request(screens.WIDTH, screens.HEIGHT) # FIXME make configurable.
        self.drawing_area.show()
        self.event_box.show()
        gobject.timeout_add(16, self.repaint_T)
        box = gtk.HBox()
        self.event_box.add(self.drawing_area)
        box.pack_start(self.event_box, False, False)
        box.pack_start(controls, False, False)
        box.show()
        self.window.add(box)
        self.window.show_all()
    def allocate_GC(self, widget, *args, **kwargs):
        self.GC = widget.window.new_gc()
    def repaint_X(self, widget, event):
        self.repaint()
    def repaint_T(self):
        self.repaint()
        return(True)
    def repaint(self):
        if self.B_create_flip_pixbuf:
            s = self.screen.pixbuf_obj.get_rendered_image()
            assert(len(s) == 439200)
            self.pixbuf = gtk.gdk.pixbuf_new_from_data(s, gtk.gdk.COLORSPACE_RGB, True, 8, screens.WIDTH, screens.HEIGHT, screens.WIDTH * 4) # TODO optimize!!
        widget = self.drawing_area
#        self.pixbuf = self.pixbuf.scale_simple(screens.WIDTH*2, screens.HEIGHT*2, gtk.gdk.INTERP_TILES)
        if widget.window: # window already realized
            #print("YEP", data)
            widget.window.draw_pixbuf(self.GC, self.pixbuf, 0, 0, 0, 0, screens.WIDTH, screens.HEIGHT, gtk.gdk.RGB_DITHER_NONE, 0, 0)
            #drawable(self.pixmap_GC, self.pixmap, 0, 0, 0, 0, -1, -1)

def main():
    parser = OptionParser()
    parser.add_option("-t", "--tape", dest="tape",help="load from T64 tape image", metavar="TAPE")
    parser.add_option("-p", "--prg", dest="prg", help="load from PRG file", metavar="PRG")
    (options, args) = parser.parse_args()
    c_64 = c64.C64()
    if options.tape:
        c_64.set_tape_image_name(options.tape, "T64")
        #c_64.set_tape_loader(loaders.t64.Loader.parse(open(options.tape, "rb"), options.tape))
    elif options.prg:
        c_64.set_tape_image_name(options.prg, "PRG")
        #c_64.set_tape_loader(loaders.t64.Loader.parse(open(options.prg, "rb"), options.prg))
    for i in range(50000): # boot a little first
        c_64.iterate()
    controls = Controls(c_64)
    assert(isinstance(controls, gtk.VBox))
    graphics_view = View(c_64, controls)
    controls.graphics_view = graphics_view
    controls.set_timer()
    gtk.main()

if __name__ == '__main__':
    main()