Hallo Besucher, der Thread wurde 27k mal aufgerufen und enthält 167 Antworten

letzter Beitrag von olly am

CP/M Z80 Verständnisfrage

  • Zitat

    Man kann das auch verwenden, um eigenen Z80-Code ohne CP/M laufenzulassen


    Da musst du ja das ganze System in den Z80-Code umsetzen, da sonst nichts funktioniert.
    Das heißt dein eigenes OS schreiben und da landest du wieder beim CP/M ähnlichen System mit angepassten Routinen.



    Gruss

  • Hier gefunden Z80 ein und auschalten:
    graas.de/c128/z80a/cpu_umschalten.html

    Vielleicht fehlt mir da jetzt zuviel Grundwissen zum Aufbau des 128er. Aber ich versehe die Codebeispiele überhaupt nicht.


    Also 8502 und Z80 greifen auf den gleichen Bus und auf's gleiche ROM zu?
    Dann verstehe ich aber nicht, welche CPU wann an welcher Adresse startet.
    Der Z80 beginnt doch nach dem Reset an Adresse 0 und nicht irgendwo bei FFED oder so? :S


    Gibt es dazu irgendwo eine vollständige bzw. verständliche Erklärung?

  • Ich probier's mal:


    Also, wenn der C128 eingeschaltet oder resettet wird, läuft als allererstes die Z80-CPU. Der 8502 ist angehalten, und wartet zunächst darauf, daß er freigeschaltet wird, woraufhin er als allererstes seinen Reset-Vektor lesen würde.


    Der Z80 bekommt von der MMU das "Z80-ROM" ab $0000 (bis $0FFF) eingeblendet. Dieses ROM überlagert das RAM in Bank 0 und ist überhaupt nur für den Z80 sichtbar! Dort startet der Z80 wie erwartet ab Adresse 0 mit einer Reset-Routine. Und die macht nun folgendes, rein unter Registergebrauch und damit *ohne* Änderung irgendwelcher RAM-Adressen:


    Es wird gecheckt, ob die C=-Taste gedrückt ist, oder die /EXROM- oder /GAME-Leitung von einer C64-Cartridge "gezogen" werden. Diese Information wird über ein Register in der MMU zur Verfügung gestellt. Ist dies der Fall, schaltet der Z80 die MMU in den C64-Modus, wobei sich die MMU gleichzeitig ausblendet, den Z80 anhält, den 8502 freigibt und dieser den Reset-Vektor des C64-KERNALs holt, woraufhin der Rechner im C64-Modus durchstartet.


    Ansonsten schreibt der Z80 zwei "Handover"-Routinen (8502 -> Z80, Z80 -> 8502) ab $FFD0 in Bank 0. Dann springt der Z80 die Handover-Routine bei $FFE0 an und wird dann bei $FFED angehalten, woraufhin der 8502 seine Arbeit aufnimmt, den Reset-Vektor des C128-KERNALs holt und dann im C128-Modus ist.


    Der CP/M-Bootsektor macht nun nicht anderes, als in die vorbereitete Handover-Routine für 8502->Z80 bei $FFD0 zu springen, woraufhin der Z80 bei $FFEE normalerweise den RST #8 Befehl ausführt und dann im Z80-ROM den Boot-Vorgang von CP/M anwirft.


    ...


    Meine Routine in Beitrag #16 ändert nun die Handover-Routine Z80->8502 so, daß anstelle des CP/M-Bootvorgangs eigener Z80-Code kontrolliert ausgeführt wird. Endet der Z80-Code mit einem RET, so wird die Handover-Routine Z80->8502 wieder am Anfang eingesprungen und kehrt so zum 8502 zurück. Für den Handover 8502->Z80 kann man problemlos ein eigenes Exemplar hernehmen, nur sollte man sicherstellen, daß der Z80 immer ab $FFEE weitermacht, da das sozusagen der Fixpunkt aus Sicht von CP/M für eine Übergabe ist.


    ...


    Genaueres, siehe "128 intern". :D

  • Alles klar. Da passiert also einiges mehr als in dem Beitrag beschrieben wurde.


    Danke für die ausführliche Erklärung. Jetzt ist das etwas klarer geworden.


    Da bekomme ich schon Lust, mir einen 128er zu besorgen, weil ich früher viel 6502 und Z80 programmiert habe.
    Funktioniert das, wie von dir beschrieben, in Vice?

  • Nur mal so am Rande erwähnt:


    hier hat mal jemand das c64 Game "Joe Gunn" als Zwischenschritt einer Portierung auf ZX Spectrum, in Z80 code für den c128 konvertiert. So wie ich das verstehe, läuft das Programm bis auf wenige Ausnahmen komplett im "Z80-Modus".


    Garnicht mal schlecht. Da steckt m. E. mehr drin, als man vermutet.


    Link

  • Dann werde ich das in Vice mal bei Gelegenheit ausprobieren. Der 128er ist für mich komplettes Neuland.

  • Ich habe ergänzend zum bisher gesagten, noch einige tiefergehende Infos zusammengetragen.


    Die 8502-Routine bei $FFD0 setzt die RAM-Bank auf Bank 0.
    In RAM-Bank 0 ist die 8502-Routine bei $FFD0, um zum Z80 zu wechseln, und bei $ FFE0 eine Z80-Routine, um wieder auf den 8502 umzuschalten. @Mike hat´s ja schon beschrieben. Die
    Routinen wurden beim Start vom Z80-Boot-ROM kopiert. Wenn die Routine bei $ FFD0 aufgerufen wird, wacht der Z80 auf, und startet bei $FFEE, wo er standartmäßig angehalten wurde. An der
    Stelle, wo der Z80 aufwacht, gibt es einen RST 8 Befehl, der CP / M zum Booten bringt. Diesen Befehl ändert man in einen JP-Befehl um eigenen Z80-Code ausführen und C/PM bleibt außen vor.


    Die 8502-Routine bei $FFD0 setzt die RAM-Bank auf die Bank 0. In der RAM-Bank 0 bei aktiviertem Z80 ist das Z80-ROM (mit Rücksetz- und CP/M-Boot-Code) an der Adresse $0000-$0FFF
    eingeblendet. Es gibt aber einen Trick, dies zu ändern. Lt. C128 Literatur ist RAM Bank 2 zu Bank 0 identisch. Dies ist jedoch nicht der Fall, wenn der Z80 aktiv ist! Wenn man also RAM-Bank 2 statt
    Bank-0 auswählt, hat man durchgehendes RAM bei $0000-$FFFF wo man dann eigene Z80-Programme unterbringen kann. Die Routine bei $FFD0 ist so zu ändern, das RAM-Bank 2 eingestellt ist.


    Wenn der Z80-Prozessor aktiv ist, es I/O bei $D000-$DFFF und RAM-Bank 0 oder 2 im Rest des 64-kB-Adressraums gibt, liegt der Farb-RAM bei $1000-$13FF und nicht bei $D800-$DBFF,
    wo es normal beim C64 und dem C128 mit 8502 liegt. $1000-$13FF ist dann Teil des I/O-Bereichs $D000-$DFFF. Für den I/O verwendet man "OUT (C), A" um ein Byte zu
    schreiben und "IN A, (C)" um ein Byte zu lesen.


    Von den drei vom Z80 unterstützten Interruptmodi unterstützt der C128 die beiden Modi IM1 und IM2. IM0 wird nicht unterstützt. IM1 ist am einfachsten einzurichten, weil da klar ist, dass der Z80
    bei $0038 mit der Ausführung beginnt, wenn der Interrupt auftritt. Man darf nicht vergessen, dass beim Z80 in der Interruptroutine (mit EI) erneut Interrupts aktiviert werden müssen. Sonst werden
    keine Interrupts mehr generiert. Bei IM2 muss die Interruptroutine mit 257 Bytes mit der gleichen 16-Bit-Adresse gefüllt werden. Dazu muss das I-Register auf die Basis des 257-Byte-Blocks gesetzt
    werden. Umständlich!


    Bestimmte Systemspezifische Dinge gehen nur mit dem 8502, aber nicht mit dem Z80. Der Z80 hat zwar einen NMI-Eingang, dieser ist jedoch mit Masse verbunden. Das bedeutet, keine NMI-Interrupts
    zum Z80, wenn RESTORE gedrückt oder von CIA # 2 ausgelöst. Außerdem sind die E/A-Port-Register an den Adressen 0 und 1 8502-spezifisch, so dass nichts mit diesen Bits geändert werden
    kann, wenn der Z80 aktiv ist. Man kann also nicht einstellen, ob die CPU und der VIC den Farb-RAM in Bank 0 oder 1 sieht. Datasettenbetrieb ist nicht möglich. Der Zustand der CAPS LOCK-Taste
    kann nicht festgestellt werden.


    Beim C128 im 8502-Modus kann man bekanntlich entscheiden, ob man in allen 4 Bänken Zeichensatz-ROM haben möchte oder in keiner Bank. Im Z80-Modus kann das Zeichensatz-Shadow-ROM,
    nicht ausgeschaltet werden.


    Cheers :done:

  • Kleine Korrektur hier noch:

    Ansonsten schreibt der Z80 zwei "Handover"-Routinen (8502 -> Z80, Z80 -> 8502) ab $FFD0 in Bank 0. Dann springt der Z80 die Handover-Routine bei $FFE0 an und wird dann bei $FFED angehalten, woraufhin der 8502 seine Arbeit aufnimmt, den Reset-Vektor des C128-KERNALs holt und dann im C128-Modus ist.

    Ich hab' das noch mal mit dem 128 intern gegengecheckt, es ist am Ende noch etwas komplizierter.


    Da noch Bank 0 + I/O eingeschaltet sind, ist beim Einschalten des 8502 kein ROM da! An Stelle dessen schreibt der Z80 vorher noch ab $FFFA dreimal den Wert $1100, in den NMI-, Reset- und IRQ-Vektor - und eine kleine Routine nach $1100. Der 8502 holt sich also $1100 aus dem Reset-Vektor. Und ab $1100 steht folgende Routine:

    Code
    1. .1100 A9 00 LDA #$00
    2. .1102 8D 00 FF STA $FF00
    3. .1105 6C FC FF JMP ($FFFC)

    ... welche das ROM (+I/O) ab $4000 einschaltet und dann über $FFFC (im ROM!) *endlich* die Reset-Routine im KERNAL bei $FF3D anspringt. Die setzt $FF00 ebenfalls auf 0 (doppelt hält besser) und dann geht's ab $E000 richtig los.


    Jo. ... :drunk:

  • Also gibt es beim c128 nicht den Adressoffset z80 zu 6502 wie beim c64 cp/m Modul?

    Nein.

    Zitat

    Beide cpu sehen die gleichen Daten an der gleichen Adresse?

    Ja.


    Auch Commodore mußte nicht unbedingt jeden Blödsinn gleich zweimal machen. Beim C64-Z80-Modul war der Adreßoffset sicher irgendwelchen Eigenheiten geschuldet, die beim C128 dank MMU nicht mehr relevant waren.


    Allerdings wird eben ab $0000 in Bank 0 das Z80-ROM eingeblendet. Der 8502 bekommt das nie zu Gesicht. Warum aber im Z80-Betrieb das Farb-RAM auf einmal woanders ist, und nicht im I/O-Bereich angesprochen werden kann ... :nixwiss:


    Zitat von olly

    Gibt es außer dem Doubble-Ass noch andere brauchbare Assembler die beide Befehlssätze können? Oder ist Doubble-Ass tatsächlich das einzige Werkzeug.

    ca65 kann anscheinend mit einem kleinen include auch Z80-Mnemonics übersetzen. Gerade hier gefunden:


    http://forums.nesdev.com/viewtopic.php?p=122249


    Müßte man mal ausprobieren ...

  • "Beim C64-Z80-Modul war der Adreßoffset sicher irgendwelchen Eigenheiten geschuldet, die beim C128 dank MMU nicht mehr relevant waren."


    Nun, das haben die ganz einfach der Z-80 SoftCard von Microsoft für den Apple II nachgemacht. Da gab es den Trick wohl auch schon. Und ohne grosses Bankswitching im Jahre 1980. Da hatten die Computer noch nicht einmal 64 KB.


    https://en.wikipedia.org/wiki/Z-80_SoftCard