Emulator in Python...

Wenn du dir nicht sicher bist, in welchem der anderen Foren du die Frage stellen sollst, dann bist du hier im Forum für allgemeine Fragen sicher richtig.
Antworten
Benutzeravatar
jens
Python-Forum Veteran
Beiträge: 8502
Registriert: Dienstag 10. August 2004, 09:40
Wohnort: duisburg
Kontaktdaten:

Hatte kürzlich mal meinen alten Homecomputer rausgekramt. Der Funktioniert noch. Ist ein DRAGON 32: http://de.wikipedia.org/wiki/Dragon_32/64

Dann hatte ich mal nach Emulatoren gesucht. Die zwei wichtigesten:
XRoar: http://www.6809.org.uk/dragon/xroar.shtml
MESS: http://mess.org/

XRoar kann nur Dragon und Tandy Colour Computer (CoCo) (weil sehr ähnlich)... MESS kann über 1700 Systeme, siehe: http://www.progettoemma.net/mess/sysset.php


Naja, dann hab ich mal nach "Emulator in Python" gesucht... Sehr Interessant: https://github.com/jtauber/applepy
Den habe ich mal ausprobiert und es scheint zu funktionieren! Dabei ist der insgesamt recht einfach aufgebaut, auf den ersten Blick.
Gibt auch ein sehr interessantes Video vom Entwickler: http://www.youtube.com/watch?v=EhK5JNx0irA

Nun werkelte bei Apple ][ ein 6502 CPU, siehe: https://de.wikipedia.org/wiki/6502
Im Dragon steckt ein 6809: http://de.wikipedia.org/wiki/Motorola_6809

Die beiden CPUs sind wohl ähnlich. Zum 6809 steht:
Er war eine verbesserte Version des Motorola 6800.
Zum 6502 steht:
Das Design des 6502 wurde an das des Motorola 6800 angelehnt...
Nun frage ich mich, wie viel Arbeit es ist aus dem apple ][ emulator ein dragon 32 Emulator zu basteln... Sinnlos, aber egal ;)

GitHub | Open HUB | Xing | Linked in
Bitcoins to: 1JEgSQepxGjdprNedC9tXQWLpS424AL8cd
Benutzeravatar
darktrym
User
Beiträge: 784
Registriert: Freitag 24. April 2009, 09:26

Basteln allein reicht da nicht. Selbst wenn der Prozessor sich ähnelt, fehlen noch andere Komponenen vom Mapping der ganzen Register ganz zu schweigen.
Sind denn die Opcodes und Timing identisch, also bleibt nur das durchackern der kaum vorhandenen Spez.
Im Übrigen gibts auch noch pyZX ein ZX Spectrum Emulator und spyn ein NES(mit 6502) Emulator.
„gcc finds bugs in Linux, NetBSD finds bugs in gcc.“[Michael Dexter, Systems 2008]
Bitbucket, Github
Sirius3
User
Beiträge: 17747
Registriert: Sonntag 21. Oktober 2012, 17:20

die reine CPU ist bei Emulatoren immer das kleinste Problem. Das richtige Verhalten der Peripherie (Grafik, Sound, Diskettencontroller, Timer, Interrupts, DMA, usw.) nachzubauen ist umso komplizierter, weil dazu oft auch eine ausreichende Dokumentation fehlt. Und ich denke, diese Komponenten sind in den verschiedenen Rechnern ganz andere.
Benutzeravatar
jens
Python-Forum Veteran
Beiträge: 8502
Registriert: Dienstag 10. August 2004, 09:40
Wohnort: duisburg
Kontaktdaten:

darktrym hat geschrieben:Im Übrigen gibts auch noch pyZX ein ZX Spectrum Emulator und spyn ein NES(mit 6502) Emulator.
Toll. Lasst uns mal sammeln! Hab mal die drei im Wiki verewigt: http://wiki.python-forum.de/Wer%20nutzt ... Emulatoren

GitHub | Open HUB | Xing | Linked in
Bitcoins to: 1JEgSQepxGjdprNedC9tXQWLpS424AL8cd
Benutzeravatar
darktrym
User
Beiträge: 784
Registriert: Freitag 24. April 2009, 09:26

„gcc finds bugs in Linux, NetBSD finds bugs in gcc.“[Michael Dexter, Systems 2008]
Bitbucket, Github
Benutzeravatar
jens
Python-Forum Veteran
Beiträge: 8502
Registriert: Dienstag 10. August 2004, 09:40
Wohnort: duisburg
Kontaktdaten:

jens hat geschrieben:Naja, dann hab ich mal nach "Emulator in Python" gesucht... Sehr Interessant: https://github.com/jtauber/applepy
Auch wenn es keinen Sinn macht, ich hab den mal geforked und ein wenig gespielt: https://github.com/jedie/DragonPy
Denke aber, mein Wissen reicht da nicht wirklich aus.

EDIT: Bin nicht der einzige der Interesse hätte, siehe: http://five.pairlist.net/pipermail/coco ... 70903.html (CoCo ist sehr ähnlich dem Dragon)

GitHub | Open HUB | Xing | Linked in
Bitcoins to: 1JEgSQepxGjdprNedC9tXQWLpS424AL8cd
Benutzeravatar
jens
Python-Forum Veteran
Beiträge: 8502
Registriert: Dienstag 10. August 2004, 09:40
Wohnort: duisburg
Kontaktdaten:

jens hat geschrieben:Auch wenn es keinen Sinn macht, ich hab den mal geforked und ein wenig gespielt: https://github.com/jedie/DragonPy
Hab mir überlegt, das ich lieber das Original nutzte. Es generisch machen, so das es einfacher wird parallel andere Maschinen zu unterstützten.

Deswegen neues repro: https://github.com/jedie/PyEmulator und dort der Branch split-generic: https://github.com/jedie/PyEmulator/tree/split-generic

Pull Request: https://github.com/jtauber/applepy/pull/19

GitHub | Open HUB | Xing | Linked in
Bitcoins to: 1JEgSQepxGjdprNedC9tXQWLpS424AL8cd
Benutzeravatar
jens
Python-Forum Veteran
Beiträge: 8502
Registriert: Dienstag 10. August 2004, 09:40
Wohnort: duisburg
Kontaktdaten:

Ach, was cool bei der Implementierung ist: Man kann eine Webseite basteln um mit der laufenden Emulation zu interagieren, siehe: https://github.com/ghewgill/applepy/com ... e1e0a173da :shock:

GitHub | Open HUB | Xing | Linked in
Bitcoins to: 1JEgSQepxGjdprNedC9tXQWLpS424AL8cd
Benutzeravatar
jens
Python-Forum Veteran
Beiträge: 8502
Registriert: Dienstag 10. August 2004, 09:40
Wohnort: duisburg
Kontaktdaten:

James Tauber hat ein neues repro angefangen und verschiedenen CPUs zu implementieren: https://github.com/jtauber/pycpu
Ein 6809 ist auch geplant :lol:

GitHub | Open HUB | Xing | Linked in
Bitcoins to: 1JEgSQepxGjdprNedC9tXQWLpS424AL8cd
Benutzeravatar
jens
Python-Forum Veteran
Beiträge: 8502
Registriert: Dienstag 10. August 2004, 09:40
Wohnort: duisburg
Kontaktdaten:

Auch wenn es die nächste never-ending-baustelle ist... Ich habe bei meinem applepy fork https://github.com/jedie/DragonPy/ weiter gemacht.
Allerdings hab ich nun einen großteil gelöscht und fange von Grundauf and den 6809 zu implementieren. Weil es doch irgendwie Spaß macht, herraus zu finden, wie diese relativ einfache CPU überhaupt funktioniert...

Bisher ist allerdings nur die op TFR implementiert: https://github.com/jedie/DragonPy/blob/ ... 09.py#L543
Dafür gibt es allerdings auch unittests: https://github.com/jedie/DragonPy/blob/ ... 809.py#L48

und da hätte ich auch schon was zum "optimieren":

Code: Alles auswählen

        self.index_x = 0 # X - 16 bit index register
        self.index_y = 0 # Y - 16 bit index register

        self.user_stack_pointer = 0 # U - 16 bit user-stack pointer
        self.stack_pointer = 0 # S - 16 bit system-stack pointer

        self.value_register = 0 # V - 16 bit variable inter-register

        self.program_counter = None # PC - 16 bit program counter register

        self.accumulator_a = 0 # A - 8 bit accumulator
        self.accumulator_b = 0 # B - 8 bit accumulator
        self.accumulator_e = 0 # E - 8 bit accumulator
        self.accumulator_f = 0 # F - 8 bit accumulator

        # CC - 8 bit condition code register as flags:
        self.entire_flag = 0 # E - bit 7
        self.firq_mask_flag = 0 # F - bit 6
        self.half_carry_flag = 0 # H - bit 5
        self.irq_mask_flag = 0 # I - bit 4
        self.negative_flag = 0 # N - bit 3
        self.zero_flag = 0 # Z - bit 2
        self.overflow_flag = 0 # V - bit 1
        self.carry_flag = 0 # C - bit 0

        self.mode_error = 0 # MD - 8 bit mode/error register
        self.condition_code = 0
        self.direct_page = 0 # DP - 8 bit direct page register

...

    def get_register(self, addr):
        log.debug("get register value from %s" % hex(addr))
        if addr == 0x00: # 0000 - D - 16 bit concatenated reg.(A B)
            return self.accumulator_a + self.accumulator_b
        elif addr == 0x01: # 0001 - X - 16 bit index register
            return self.index_x
        elif addr == 0x02: # 0010 - Y - 16 bit index register
            return self.index_y
        elif addr == 0x03: # 0011 - U - 16 bit user-stack pointer
            return self.user_stack_pointer
        elif addr == 0x04: # 0100 - S - 16 bit system-stack pointer
            return self.stack_pointer
        elif addr == 0x05: # 0101 - PC - 16 bit program counter register
            return self.program_counter
        elif addr == 0x08: # 1000 - A - 8 bit accumulator
            return self.accumulator_a
        elif addr == 0x09: # 1001 - B - 8 bit accumulator
            return self.accumulator_b
        elif addr == 0x0a: # 1010 - CC - 8 bit condition code register as flags
            return self.status_as_byte()
        elif addr == 0x0b: # 1011 - DP - 8 bit direct page register
            return self.direct_page
        else:
            raise RuntimeError("Register %s doesn't exists!" % hex(addr))

    def set_register(self, addr, value):
        log.debug("set register %s to %s" % (hex(addr), hex(value)))
        if addr == 0x00: # 0000 - D - 16 bit concatenated reg.(A B)
            self.accumulator_a, self.accumulator_b = divmod(value, 256)
        elif addr == 0x01: # 0001 - X - 16 bit index register
            self.index_x = value
        elif addr == 0x02: # 0010 - Y - 16 bit index register
            self.index_y = value
        elif addr == 0x03: # 0011 - U - 16 bit user-stack pointer
            self.user_stack_pointer = value
        elif addr == 0x04: # 0100 - S - 16 bit system-stack pointer
            self.stack_pointer = value
        elif addr == 0x05: # 0101 - PC - 16 bit program counter register
            self.program_counter = value
        elif addr == 0x08: # 1000 - A - 8 bit accumulator
            self.accumulator_a = value
        elif addr == 0x09: # 1001 - B - 8 bit accumulator
            self.accumulator_b = value
        elif addr == 0x0a: # 1010 - CC - 8 bit condition code register as flags
            self.status_from_byte(value)
        elif addr == 0x0b: # 1011 - DP - 8 bit direct page register
            self.direct_page = value
        else:
            raise RuntimeError("Register %s doesn't exists!" % hex(addr))
Eine Idee, wie man das "zusammenfassen" kann?

Mir würde nur einfallen, aus den einfachen variablen jeweils ein richtiges Objekt zu machen. Dann könnte man über ein einfaches dict get/set regeln. Also so:

Code: Alles auswählen

    def __init__(self,...):
        ...
        self.registers = {
            0x00: accumulator_d,
            0x01: index_x,
            0x02: index_y,
            ...
        }

    def get_register(self, addr):
        obj = self.registers[addr]
        return obj.get()
        
    def set_register(self, addr, value):
        obj = self.registers[addr]
        obj.set(value)

GitHub | Open HUB | Xing | Linked in
Bitcoins to: 1JEgSQepxGjdprNedC9tXQWLpS424AL8cd
Benutzeravatar
jens
Python-Forum Veteran
Beiträge: 8502
Registriert: Dienstag 10. August 2004, 09:40
Wohnort: duisburg
Kontaktdaten:

Habe ein paar deutschsprachige Folien über den 6809 gefunden. Sie sind von der Lehrveranstaltung "Technische Informatik I" der "Otto-von-Guericke-Universität Magdeburg" ( http://www.ovgu.de/ ):

http://eos.cs.ovgu.de/de/lecture/courses/ws1213/vl_gti/

Dort gibt es Vorlesungsfolien im PDF-Format und über den 6809 gibt es:
http://eos.cs.ovgu.de/wp-content/upload ... lssatz.pdf
http://eos.cs.ovgu.de/wp-content/upload ... ierung.pdf

Darüber hinnaus interessant:
http://eos.cs.ovgu.de/wp-content/upload ... tektur.pdf

Anscheinend wird der 6809 häufig in der Lehre genutzt.

GitHub | Open HUB | Xing | Linked in
Bitcoins to: 1JEgSQepxGjdprNedC9tXQWLpS424AL8cd
Benutzeravatar
jens
Python-Forum Veteran
Beiträge: 8502
Registriert: Dienstag 10. August 2004, 09:40
Wohnort: duisburg
Kontaktdaten:

Hab weiter rumgebastelt und ein paar OPs implementiert.

Dazu habe ich noch eine Menge Debug Ausgaben eingefügt. Dazu noch eine "Dragon Memory Info" klasse gebaut.

Aktuelle Ausgaben sehen dann so aus:

Code: Alles auswählen

    init 16384 Bytes ROM (0x8000 - 0xc000)
    Read 16383Bytes from d32.rom into ROM 0x8000-0xbfff
    init 32768 Bytes RAM (0x0 - 0x8000)
    CPU reset read word from 0xb3ba
     *** new op code: 0x0 (NEG_direct)
    SoftSwitches.read_byte (cycle: 0x17256) from 0x7fff: UNKNOWN
    no soft switch at 0x7fff (cycle: 0x17256)
     *** last op code 0 count: 15800 - new op code: 0x7e (JMP_extended)
    0x40bb - 0x7e JMP extended to: 0x40bb
     *** new op code: 0x0 (NEG_direct)
    SoftSwitches.read_byte (cycle: 0x23025) from 0x7fff: UNKNOWN
    no soft switch at 0x7fff (cycle: 0x23025)
     *** last op code 0 count: 8098 - new op code: 0xbb (ADDA_extended)
    0x8004 - 0xbb ADDA extended: Add 0x7e40 to accu A: 0x0
    0x8007 - 0xbb ADDA extended: Add 0x7e88 to accu A: 0x7e40
    0x800a - 0xbb ADDA extended: Add 0x7ee5 to accu A: 0xfcc8
    0x800d - 0xbb ADDA extended: Add 0x7eb5 to accu A: 0x17bad
     *** last op code 187 count: 3 - new op code: 0xbc (CMPX_extended)
    0x8010 - 0xbc CMPX extended: 0x0 - 0x7eab = -0x7eab (Set C to 0)
     *** new op code: 0xbd (JSR_extended)
    write byte 0x80 to 0x100:
     * 0x100-0x102 - SWI3 Secondary vector (Uninitialised)
    write byte 0x12 to 0x1ff:
     * 0x1da-0x2d8 - Cassette I/O default data buffer - 255 bytes
     * 0x1da-0x268 - D64 - 64K mode bootstrap routine is copied here to run
    0x7e1a - 0xbd JSR extended: push 0x7e19 to stack and jump to 0x7e1a
     *** new op code: 0x0 (NEG_direct)
    SoftSwitches.read_byte (cycle: 0x23600) from 0x7fff: UNKNOWN
    no soft switch at 0x7fff (cycle: 0x23600)
     *** last op code 0 count: 242 - new op code: 0x7e (JMP_extended)
    0x40bb - 0x7e JMP extended to: 0x40bb
     *** new op code: 0x0 (NEG_direct)
    SoftSwitches.read_byte (cycle: 0x2f3cf) from 0x7fff: UNKNOWN
    no soft switch at 0x7fff (cycle: 0x2f3cf)
     *** last op code 0 count: 8098 - new op code: 0xbb (ADDA_extended)
    0x8004 - 0xbb ADDA extended: Add 0x7e40 to accu A: 0x1fa62
    0x8007 - 0xbb ADDA extended: Add 0x7e88 to accu A: 0x278a2
    0x800a - 0xbb ADDA extended: Add 0x7ee5 to accu A: 0x2f72a
    0x800d - 0xbb ADDA extended: Add 0x7eb5 to accu A: 0x3760f
     *** last op code 187 count: 3 - new op code: 0xbc (CMPX_extended)
    0x8010 - 0xbc CMPX extended: 0x0 - 0x7eab = -0x7eab (Set C to 0)
     *** new op code: 0xbd (JSR_extended)
    write byte 0x80 to 0x1fe:
     * 0x1da-0x2d8 - Cassette I/O default data buffer - 255 bytes
     * 0x1da-0x268 - D64 - 64K mode bootstrap routine is copied here to run
    write byte 0x12 to 0x1fd:
     * 0x1da-0x2d8 - Cassette I/O default data buffer - 255 bytes
     * 0x1da-0x268 - D64 - 64K mode bootstrap routine is copied here to run
    0x7e1a - 0xbd JSR extended: push 0x7e19 to stack and jump to 0x7e1a
     *** new op code: 0x0 (NEG_direct)
    SoftSwitches.read_byte (cycle: 0x2f9aa) from 0x7fff: UNKNOWN
    no soft switch at 0x7fff (cycle: 0x2f9aa)
     *** last op code 0 count: 242 - new op code: 0x7e (JMP_extended)
    0x40bb - 0x7e JMP extended to: 0x40bb
     *** new op code: 0x0 (NEG_direct)
    SoftSwitches.read_byte (cycle: 0x3b779) from 0x7fff: UNKNOWN
    no soft switch at 0x7fff (cycle: 0x3b779)
     *** last op code 0 count: 8098 - new op code: 0xbb (ADDA_extended)
    0x8004 - 0xbb ADDA extended: Add 0x7e40 to accu A: 0x3f4c4
    0x8007 - 0xbb ADDA extended: Add 0x7e88 to accu A: 0x47304
    0x800a - 0xbb ADDA extended: Add 0x7ee5 to accu A: 0x4f18c
    0x800d - 0xbb ADDA extended: Add 0x7eb5 to accu A: 0x57071
     *** last op code 187 count: 3 - new op code: 0xbc (CMPX_extended)
    0x8010 - 0xbc CMPX extended: 0x0 - 0x7eab = -0x7eab (Set C to 0)
     *** new op code: 0xbd (JSR_extended)
    write byte 0x80 to 0x1fc:
     * 0x1da-0x2d8 - Cassette I/O default data buffer - 255 bytes
     * 0x1da-0x268 - D64 - 64K mode bootstrap routine is copied here to run
    write byte 0x12 to 0x1fb:
     * 0x1da-0x2d8 - Cassette I/O default data buffer - 255 bytes
     * 0x1da-0x268 - D64 - 64K mode bootstrap routine is copied here to run
    0x7e1a - 0xbd JSR extended: push 0x7e19 to stack and jump to 0x7e1a
     *** new op code: 0x0 (NEG_direct)
    SoftSwitches.read_byte (cycle: 0x3bd54) from 0x7fff: UNKNOWN
    no soft switch at 0x7fff (cycle: 0x3bd54)
     *** last op code 0 count: 242 - new op code: 0x7e (JMP_extended)
    0x40bb - 0x7e JMP extended to: 0x40bb
     *** new op code: 0x0 (NEG_direct)
    SoftSwitches.read_byte (cycle: 0x47b23) from 0x7fff: UNKNOWN
    no soft switch at 0x7fff (cycle: 0x47b23)
     *** last op code 0 count: 8098 - new op code: 0xbb (ADDA_extended)
    0x8004 - 0xbb ADDA extended: Add 0x7e40 to accu A: 0x5ef26
    0x8007 - 0xbb ADDA extended: Add 0x7e88 to accu A: 0x66d66
    0x800a - 0xbb ADDA extended: Add 0x7ee5 to accu A: 0x6ebee
    0x800d - 0xbb ADDA extended: Add 0x7eb5 to accu A: 0x76ad3
     *** last op code 187 count: 3 - new op code: 0xbc (CMPX_extended)
    0x8010 - 0xbc CMPX extended: 0x0 - 0x7eab = -0x7eab (Set C to 0)
     *** new op code: 0xbd (JSR_extended)
    write byte 0x80 to 0x1fa:
     * 0x1da-0x2d8 - Cassette I/O default data buffer - 255 bytes
     * 0x1da-0x268 - D64 - 64K mode bootstrap routine is copied here to run
    write byte 0x12 to 0x1f9:
     * 0x1da-0x2d8 - Cassette I/O default data buffer - 255 bytes
     * 0x1da-0x268 - D64 - 64K mode bootstrap routine is copied here to run
    0x7e1a - 0xbd JSR extended: push 0x7e19 to stack and jump to 0x7e1a
     *** new op code: 0x0 (NEG_direct)
    SoftSwitches.read_byte (cycle: 0x480fe) from 0x7fff: UNKNOWN
    no soft switch at 0x7fff (cycle: 0x480fe)
     *** last op code 0 count: 242 - new op code: 0x7e (JMP_extended)
    0x40bb - 0x7e JMP extended to: 0x40bb
     *** new op code: 0x0 (NEG_direct)
    SoftSwitches.read_byte (cycle: 0x53ecd) from 0x7fff: UNKNOWN
    no soft switch at 0x7fff (cycle: 0x53ecd)
     *** last op code 0 count: 8098 - new op code: 0xbb (ADDA_extended)
    0x8004 - 0xbb ADDA extended: Add 0x7e40 to accu A: 0x7e988
    0x8007 - 0xbb ADDA extended: Add 0x7e88 to accu A: 0x867c8
    0x800a - 0xbb ADDA extended: Add 0x7ee5 to accu A: 0x8e650
    0x800d - 0xbb ADDA extended: Add 0x7eb5 to accu A: 0x96535
     *** last op code 187 count: 3 - new op code: 0xbc (CMPX_extended)
    0x8010 - 0xbc CMPX extended: 0x0 - 0x7eab = -0x7eab (Set C to 0)
     *** new op code: 0xbd (JSR_extended)
    write byte 0x80 to 0x1f8:
     * 0x1da-0x2d8 - Cassette I/O default data buffer - 255 bytes
     * 0x1da-0x268 - D64 - 64K mode bootstrap routine is copied here to run
    write byte 0x12 to 0x1f7:
     * 0x1da-0x2d8 - Cassette I/O default data buffer - 255 bytes
     * 0x1da-0x268 - D64 - 64K mode bootstrap routine is copied here to run
    0x7e1a - 0xbd JSR extended: push 0x7e19 to stack and jump to 0x7e1a
     *** new op code: 0x0 (NEG_direct)
    SoftSwitches.read_byte (cycle: 0x544a8) from 0x7fff: UNKNOWN
    no soft switch at 0x7fff (cycle: 0x544a8)
     *** last op code 0 count: 242 - new op code: 0x7e (JMP_extended)
    0x40bb - 0x7e JMP extended to: 0x40bb
     *** new op code: 0x0 (NEG_direct)
    SoftSwitches.read_byte (cycle: 0x60277) from 0x7fff: UNKNOWN
    no soft switch at 0x7fff (cycle: 0x60277)
     *** last op code 0 count: 8098 - new op code: 0xbb (ADDA_extended)
    0x8004 - 0xbb ADDA extended: Add 0x7e40 to accu A: 0x9e3ea
    0x8007 - 0xbb ADDA extended: Add 0x7e88 to accu A: 0xa622a
    0x800a - 0xbb ADDA extended: Add 0x7ee5 to accu A: 0xae0b2
    0x800d - 0xbb ADDA extended: Add 0x7eb5 to accu A: 0xb5f97
     *** last op code 187 count: 3 - new op code: 0xbc (CMPX_extended)
    0x8010 - 0xbc CMPX extended: 0x0 - 0x7eab = -0x7eab (Set C to 0)
     *** new op code: 0xbd (JSR_extended)
    write byte 0x80 to 0x1f6:
     * 0x1da-0x2d8 - Cassette I/O default data buffer - 255 bytes
     * 0x1da-0x268 - D64 - 64K mode bootstrap routine is copied here to run
    write byte 0x12 to 0x1f5:
     * 0x1da-0x2d8 - Cassette I/O default data buffer - 255 bytes
     * 0x1da-0x268 - D64 - 64K mode bootstrap routine is copied here to run
    0x7e1a - 0xbd JSR extended: push 0x7e19 to stack and jump to 0x7e1a
     *** new op code: 0x0 (NEG_direct)
    SoftSwitches.read_byte (cycle: 0x60852) from 0x7fff: UNKNOWN
    no soft switch at 0x7fff (cycle: 0x60852)
     *** last op code 0 count: 242 - new op code: 0x7e (JMP_extended)
    0x40bb - 0x7e JMP extended to: 0x40bb
     *** new op code: 0x0 (NEG_direct)
    SoftSwitches.read_byte (cycle: 0x6c621) from 0x7fff: UNKNOWN
    no soft switch at 0x7fff (cycle: 0x6c621)
     *** last op code 0 count: 8098 - new op code: 0xbb (ADDA_extended)
    0x8004 - 0xbb ADDA extended: Add 0x7e40 to accu A: 0xbde4c
    0x8007 - 0xbb ADDA extended: Add 0x7e88 to accu A: 0xc5c8c
    0x800a - 0xbb ADDA extended: Add 0x7ee5 to accu A: 0xcdb14
    0x800d - 0xbb ADDA extended: Add 0x7eb5 to accu A: 0xd59f9
     *** last op code 187 count: 3 - new op code: 0xbc (CMPX_extended)
    0x8010 - 0xbc CMPX extended: 0x0 - 0x7eab = -0x7eab (Set C to 0)
     *** new op code: 0xbd (JSR_extended)
    write byte 0x80 to 0x1f4:
     * 0x1da-0x2d8 - Cassette I/O default data buffer - 255 bytes
     * 0x1da-0x268 - D64 - 64K mode bootstrap routine is copied here to run
    write byte 0x12 to 0x1f3:
     * 0x1da-0x2d8 - Cassette I/O default data buffer - 255 bytes
     * 0x1da-0x268 - D64 - 64K mode bootstrap routine is copied here to run
    0x7e1a - 0xbd JSR extended: push 0x7e19 to stack and jump to 0x7e1a
     *** new op code: 0x0 (NEG_direct)
    SoftSwitches.read_byte (cycle: 0x6cbfc) from 0x7fff: UNKNOWN
    no soft switch at 0x7fff (cycle: 0x6cbfc)
     *** last op code 0 count: 242 - new op code: 0x7e (JMP_extended)
    0x40bb - 0x7e JMP extended to: 0x40bb
     *** new op code: 0x0 (NEG_direct)
    SoftSwitches.read_byte (cycle: 0x789cb) from 0x7fff: UNKNOWN
    no soft switch at 0x7fff (cycle: 0x789cb)
     *** last op code 0 count: 8098 - new op code: 0xbb (ADDA_extended)
    0x8004 - 0xbb ADDA extended: Add 0x7e40 to accu A: 0xdd8ae
    0x8007 - 0xbb ADDA extended: Add 0x7e88 to accu A: 0xe56ee
    0x800a - 0xbb ADDA extended: Add 0x7ee5 to accu A: 0xed576
    0x800d - 0xbb ADDA extended: Add 0x7eb5 to accu A: 0xf545b
     *** last op code 187 count: 3 - new op code: 0xbc (CMPX_extended)
    0x8010 - 0xbc CMPX extended: 0x0 - 0x7eab = -0x7eab (Set C to 0)
     *** new op code: 0xbd (JSR_extended)
    write byte 0x80 to 0x1f2:
     * 0x1da-0x2d8 - Cassette I/O default data buffer - 255 bytes
     * 0x1da-0x268 - D64 - 64K mode bootstrap routine is copied here to run
    write byte 0x12 to 0x1f1:
     * 0x1da-0x2d8 - Cassette I/O default data buffer - 255 bytes
     * 0x1da-0x268 - D64 - 64K mode bootstrap routine is copied here to run
    0x7e1a - 0xbd JSR extended: push 0x7e19 to stack and jump to 0x7e1a
     *** new op code: 0x0 (NEG_direct)
    SoftSwitches.read_byte (cycle: 0x78fa6) from 0x7fff: UNKNOWN
    no soft switch at 0x7fff (cycle: 0x78fa6)
     *** last op code 0 count: 242 - new op code: 0x7e (JMP_extended)
    0x40bb - 0x7e JMP extended to: 0x40bb
     *** new op code: 0x0 (NEG_direct)
    SoftSwitches.read_byte (cycle: 0x84d75) from 0x7fff: UNKNOWN
    no soft switch at 0x7fff (cycle: 0x84d75)
     *** last op code 0 count: 8098 - new op code: 0xbb (ADDA_extended)
    0x8004 - 0xbb ADDA extended: Add 0x7e40 to accu A: 0xfd310
    0x8007 - 0xbb ADDA extended: Add 0x7e88 to accu A: 0x105150
    0x800a - 0xbb ADDA extended: Add 0x7ee5 to accu A: 0x10cfd8
    0x800d - 0xbb ADDA extended: Add 0x7eb5 to accu A: 0x114ebd
     *** last op code 187 count: 3 - new op code: 0xbc (CMPX_extended)
    0x8010 - 0xbc CMPX extended: 0x0 - 0x7eab = -0x7eab (Set C to 0)
     *** new op code: 0xbd (JSR_extended)
    write byte 0x80 to 0x1f0:
     * 0x1da-0x2d8 - Cassette I/O default data buffer - 255 bytes
     * 0x1da-0x268 - D64 - 64K mode bootstrap routine is copied here to run
    write byte 0x12 to 0x1ef:
     * 0x1da-0x2d8 - Cassette I/O default data buffer - 255 bytes
     * 0x1da-0x268 - D64 - 64K mode bootstrap routine is copied here to run
    0x7e1a - 0xbd JSR extended: push 0x7e19 to stack and jump to 0x7e1a
     *** new op code: 0x0 (NEG_direct)
    SoftSwitches.read_byte (cycle: 0x85350) from 0x7fff: UNKNOWN
    no soft switch at 0x7fff (cycle: 0x85350)
     *** last op code 0 count: 242 - new op code: 0x7e (JMP_extended)
    0x40bb - 0x7e JMP extended to: 0x40bb
     *** new op code: 0x0 (NEG_direct)
    SoftSwitches.read_byte (cycle: 0x9111f) from 0x7fff: UNKNOWN
    no soft switch at 0x7fff (cycle: 0x9111f)
     *** last op code 0 count: 8098 - new op code: 0xbb (ADDA_extended)
    0x8004 - 0xbb ADDA extended: Add 0x7e40 to accu A: 0x11cd72
    0x8007 - 0xbb ADDA extended: Add 0x7e88 to accu A: 0x124bb2
    0x800a - 0xbb ADDA extended: Add 0x7ee5 to accu A: 0x12ca3a
    0x800d - 0xbb ADDA extended: Add 0x7eb5 to accu A: 0x13491f
     *** last op code 187 count: 3 - new op code: 0xbc (CMPX_extended)
    0x8010 - 0xbc CMPX extended: 0x0 - 0x7eab = -0x7eab (Set C to 0)
     *** new op code: 0xbd (JSR_extended)
    write byte 0x80 to 0x1ee:
     * 0x1da-0x2d8 - Cassette I/O default data buffer - 255 bytes
     * 0x1da-0x268 - D64 - 64K mode bootstrap routine is copied here to run
    write byte 0x12 to 0x1ed:
     * 0x1da-0x2d8 - Cassette I/O default data buffer - 255 bytes
     * 0x1da-0x268 - D64 - 64K mode bootstrap routine is copied here to run
    0x7e1a - 0xbd JSR extended: push 0x7e19 to stack and jump to 0x7e1a
     *** new op code: 0x0 (NEG_direct)
    SoftSwitches.read_byte (cycle: 0x916fa) from 0x7fff: UNKNOWN
    no soft switch at 0x7fff (cycle: 0x916fa)
     *** last op code 0 count: 242 - new op code: 0x7e (JMP_extended)
    0x40bb - 0x7e JMP extended to: 0x40bb
     *** new op code: 0x0 (NEG_direct)

Wie man vielleicht sieht, ist es ein Loop ;)
Denke da habe ich noch viele Bugs produziert ;)

Code: https://github.com/jedie/DragonPy/

GitHub | Open HUB | Xing | Linked in
Bitcoins to: 1JEgSQepxGjdprNedC9tXQWLpS424AL8cd
Benutzeravatar
jens
Python-Forum Veteran
Beiträge: 8502
Registriert: Dienstag 10. August 2004, 09:40
Wohnort: duisburg
Kontaktdaten:

Bin ein Stückchen weiter.

Mit https://github.com/jedie/DragonPy/blob/ ... 09.py#L672 habe ich die sog. indexed addressing modes implementiert. Ist allerdings recht kompliziert. Von daher werden da sicherlich so einige Bugs drin sein :?

Die aktuellen debug Ausgaben sehen so aus:

Code: Alles auswählen

    init 16384 Bytes ROM (0x8000 - 0xc000)
    Read 16383Bytes from d32.rom into ROM 0x8000-0xbfff
    init 32768 Bytes RAM (0x0 - 0x8000)
    $b3ba *** new op code: $8e (LDX_immediate)
    $b3bd addressing 'immediate word' value: $401    | $b3bd: $a000-$bfff - CoCo - Color BASIC ROM
    $b3bd LDX immediate: set $401 to index X |: $b3bd: $a000-$bfff - CoCo - Color BASIC ROM
    $b3bd *** new op code: $6f (CLR_indexed)
    $b3bf indexed addressing mode: postbyte: $83 == 10000011
    $b3bf indexed addressing mode ea=$3ff
    write $0 to: $3ff: $3ff - D64 - %PRNSEL% selects default printer port 0x00 Parallel, non-0x00 Serial (0x00)
    $b3bf *** new op code: $30 (LEAX_indexed)
    $b3c1 indexed addressing mode: postbyte: $1 == 00000001
    $b3c1 LEAX indexed: set $402 to index X |: $b3c1: $a000-$bfff - CoCo - Color BASIC ROM
    $b3c1 *** UNKNOWN OP $26
Es gibt eigentlich keine 0x26 op... Von daher denke ich, da läuft einiges schief...

GitHub | Open HUB | Xing | Linked in
Bitcoins to: 1JEgSQepxGjdprNedC9tXQWLpS424AL8cd
Benutzeravatar
jens
Python-Forum Veteran
Beiträge: 8502
Registriert: Dienstag 10. August 2004, 09:40
Wohnort: duisburg
Kontaktdaten:

Jetzt, wo ich einen überblick hab, wie eine CPU überhaupt genau funktioniert und wie man es in Python implementieren könnte, will ich nochmal neu anfangen und systematischer herran gehen...

Dazu habe ich zwei "data scraping" skripte zusammen gehackt: https://github.com/jedie/DragonPy/commi ... 5f6e75d903

Diese sollen Informationen von diesen Seiten zusammenführen:
http://www.maddes.net/m6809pm/sections.htm#sec4_4
http://www.burgins.com/m6809.html
http://www.maddes.net/m6809pm/appendix_a.htm#appA

Dann soll, als Zwischenschritt, ein "Daten Skript" erzeugt werden, mit allen Informationen. Sieht dann ungefähr so aus:

Code: Alles auswählen

OP_DATA = (

    #### 8-Bit Accumulator and Memory Instructions

    {
        "opcode": 0x0, "instruction": "NEG", "mnemonic": "NEG", 
        "desc": "Negate accumulator or memory",
        "addr_mode": 1, "operant": None,
        "cycles": "6", "bytes": "2", "HNZVC": "uaaaa", "category": 0
    },
    {
        "opcode": 0x3, "instruction": "COM", "mnemonic": "COM", 
        "desc": "Complement accumulator or memory location",
        "addr_mode": 1, "operant": None,
        "cycles": "6", "bytes": "2", "HNZVC": "-aa01", "category": 0
    },
    {
        "opcode": 0x4, "instruction": "LSR", "mnemonic": "LSR", 
        "desc": "Logical shift right accumulator or memory location",
        "addr_mode": 1, "operant": None,
        "cycles": "6", "bytes": "2", "HNZVC": "-0a-s", "category": 0
    },
...
Daraus will ich dann ein Python Skript erzeugen, der so ähnlich aussieht:

Code: Alles auswählen

class CPU6809(object):

    #### 8-Bit Accumulator and Memory Instructions

    # ADC - Add memory to accumulator with carry
    @opcode((
        0x89, "ADCA", IMMEDIATE, operant=A
        0x99, "ADCA", DIRECT, operant=A
        0xa9, "ADCA", INDEXED, operant=A
        0xb9, "ADCA", EXTENDED, operant=A
        0xc9, "ADCB", IMMEDIATE, operant=B
        0xd9, "ADCB", DIRECT, operant=B
        0xe9, "ADCB", INDEXED, operant=B
        0xf9, "ADCB", EXTENDED, operant=B
    ))
    def ADC(self, op, ea=None, operant=None):
        raise NotImplementedError("TODO: $%x ADC") % op

    # ADD - Add memory to accumulator
    @opcode((
        0x8b, "ADDA", IMMEDIATE, operant=A
        0x9b, "ADDA", DIRECT, operant=A
        0xab, "ADDA", INDEXED, operant=A
        0xbb, "ADDA", EXTENDED, operant=A
        0xcb, "ADDB", IMMEDIATE, operant=B
        0xdb, "ADDB", DIRECT, operant=B
        0xeb, "ADDB", INDEXED, operant=B
        0xfb, "ADDB", EXTENDED, operant=B
    ))
    def ADD(self, op, ea=None, operant=None):
        raise NotImplementedError("TODO: $%x ADD") % op

    # AND - AND memory with accumulator
    @opcode((
        0x84, "ANDA", IMMEDIATE, operant=A
        0x94, "ANDA", DIRECT, operant=A
        0xa4, "ANDA", INDEXED, operant=A
        0xb4, "ANDA", EXTENDED, operant=A
        0xc4, "ANDB", IMMEDIATE, operant=B
        0xd4, "ANDB", DIRECT, operant=B
        0xe4, "ANDB", INDEXED, operant=B
        0xf4, "ANDB", EXTENDED, operant=B
    ))
    def AND(self, op, ea=None, operant=None):
        raise NotImplementedError("TODO: $%x AND") % op

...
Und dann geht es ans implementieren.

GitHub | Open HUB | Xing | Linked in
Bitcoins to: 1JEgSQepxGjdprNedC9tXQWLpS424AL8cd
BlackJack

@jens: Wenn man schon eine Datendatei hat, warum willst Du die Daten dann noch mal in Code umwandeln? Es würde ja reichen wenn man eine Abbildung von Maschinensprache-Befehl auf Methodennamen hat, dann kann man einfach eine Klasse mit entsprechend benannten Methoden schreiben und eine Funktion die Zuordnung der Daten vornehmen lassen.
Benutzeravatar
jens
Python-Forum Veteran
Beiträge: 8502
Registriert: Dienstag 10. August 2004, 09:40
Wohnort: duisburg
Kontaktdaten:

Die Zuordnung funktioniert z.Z. über den @opcode() decorator.

Aber du hast recht, das kann man auch separieren. Würde dann den Code auch übersichtlicher machen.

Danke für den Hinweis!

GitHub | Open HUB | Xing | Linked in
Bitcoins to: 1JEgSQepxGjdprNedC9tXQWLpS424AL8cd
Benutzeravatar
jens
Python-Forum Veteran
Beiträge: 8502
Registriert: Dienstag 10. August 2004, 09:40
Wohnort: duisburg
Kontaktdaten:

Hab weiter an meinem "code generator" geschraubt...

Ich hab mich dazu entschieden nicht ganz auf den @opcode() decorator zu verzichten. Ansonsten finde ich die nackten Methoden Definition ein wenig nüchtern...

Z.Z. sieht der generierte Code so aus:

Code: Alles auswählen

class CPU6809Skeleton(object):
    @opcode( # Add B accumulator to X (unsigned)
        0x3a, # ABX (inherent)
    )
    def instruction_ABX(self, opcode):
        """
        Add the 8-bit unsigned value in accumulator B into index register X.

        source code forms: ABX

        CC bits "HNZVC": -----
        """
        raise NotImplementedError("TODO: $%x ABX") % opcode

    @opcode( # Add memory to accumulator with carry
        0x89, 0x99, 0xa9, 0xb9, # ADCA (immediate, direct, indexed, extended)
        0xc9, 0xd9, 0xe9, 0xf9, # ADCB (immediate, direct, indexed, extended)
    )
    def instruction_ADC(self, opcode, ea=None, operand=None):
        """
        Adds the contents of the C (carry) bit and the memory byte into an 8-bit
        accumulator.

        source code forms: ADCA P; ADCB P

        CC bits "HNZVC": aaaaa
        """
        self.CC_HNZVC(a, b, r)
        raise NotImplementedError("TODO: $%x ADC") % opcode
...
Vollständiger code: https://github.com/jedie/DragonPy/blob/ ... keleton.py

Dennoch wird im @opcode() decorator auf Zusatzinformation aus dem "Daten Python Skript" zurück gegriffen.
So kann ich die Adressierungsart und die benötigten operatoren feststellen und der eigentlichen Funktion schon übergeben.

Die Info könnte man natürlich auch noch im @opcode() decorator einfügen, doch dann wird es IMHO recht unübersichtlich...

GitHub | Open HUB | Xing | Linked in
Bitcoins to: 1JEgSQepxGjdprNedC9tXQWLpS424AL8cd
Benutzeravatar
snafu
User
Beiträge: 6740
Registriert: Donnerstag 21. Februar 2008, 17:31
Wohnort: Gelsenkirchen

Wäre es nicht einfacher, ein `dict` zu erstellen, wo der jeweilige Zahlencode auf einen Methodenname abgebildet wird? Ein nicht registrierter Name würde dann zu einem `NotImplementedError` führen. In seiner jetzigen Form ist das jedenfalls ganz schön viel Boilerplate-Code, finde ich.
Benutzeravatar
jens
Python-Forum Veteran
Beiträge: 8502
Registriert: Dienstag 10. August 2004, 09:40
Wohnort: duisburg
Kontaktdaten:

Sowas wird im@opcode() decorator später auch gemacht.

Die NotImplementedError sollen natürlich später durch den richtigen code ersetzt werden. Den generiere ich per Hand ;)

GitHub | Open HUB | Xing | Linked in
Bitcoins to: 1JEgSQepxGjdprNedC9tXQWLpS424AL8cd
Benutzeravatar
jens
Python-Forum Veteran
Beiträge: 8502
Registriert: Dienstag 10. August 2004, 09:40
Wohnort: duisburg
Kontaktdaten:

Bin eine Ecke weiter: https://github.com/jedie/DragonPy/compa ... ...220b514

Das generierte Grundgerüst ist nun an der richtigen stelle.
Einige Instruktionen sind auch implementiert, z.B.:
COM: https://github.com/jedie/DragonPy/blob/ ... 1273-L1309
JMP: https://github.com/jedie/DragonPy/blob/ ... 1472-L1488
LDA,LDB: https://github.com/jedie/DragonPy/blob/ ... 1529-L1542

Wo ich mir allerdings sehr unsicher bin, sind nach wie vor die CC flags wie Overflow, carry usw. btw. das setzten der Flags. Aus den XRoar Emulator Sourcen werde ich nicht ganz schlau.
Für die Instruktion DEC hab ich mal die Sourcen von XRoar zusammen gefasst:

Code: Alles auswählen

 #define SET_Z(r) ( REG_CC |= ((r) ? 0 : CC_Z) )
#define SET_N8(r) ( REG_CC |= (r&0x80)>>4 )
#define SET_NZ8(r) ( SET_N8(r), SET_Z(r&0xff) )

#define CLR_NZV ( REG_CC &= ~(CC_N|CC_Z|CC_V) )

static uint8_t op_dec(struct MC6809 *cpu, uint8_t in) {
unsigned out = in - 1;
CLR_NZV;
SET_NZ8(out);
if (out == 0x7f) REG_CC |= CC_V;
return out;
}

tmp1 = op_dec(cpu, tmp1); break; // DEC, DECA, DECB
Meine Version ist dann zusammen kopiert das:

Code: Alles auswählen

    def set_Z8(self, r):
        self.Z = 1 if r & 0xff == 0 else 0

    def set_N8(self, r):
        self.N = 1 if signed8(r) < 0 else 0

    def update_NZ8(self, r):
        self.set_N8(r)
        self.set_Z8(r)

        r = a - 1
        self.cc.update_NZ8(r)
        if r == 0x7f:
            self.cc.V = 1
Der code ist hier her:
DEC: https://github.com/jedie/DragonPy/blob/ ... 1358-L1418
CC: https://github.com/jedie/DragonPy/blob/ ... #L114-L175

Ich muß am besten konkrete Test Werte für unittests haben...

GitHub | Open HUB | Xing | Linked in
Bitcoins to: 1JEgSQepxGjdprNedC9tXQWLpS424AL8cd
Antworten