Erstellt: 11. April 2013 (zuletzt geändert: 22. November 2021)

Ein Modul erstellen

Wie man eine Cartridge / ein Modul erstellen kann

C64 Studio, AMCE & TASM

Wer schon mal ein Steckmodul in den C64 gestöpselt hat, der fragt sich evtl. wie das Programm darauf, ohne die Eingabe eines Startbefehls, ausgeführt wird. Die Lösung ist eigentlich sehr simpel. Ab der Speicherstelle $8000 sind einige Bytes zu finden, die für den Modulstart ausschlaggebend sind (s. The Transactor Vol. 5, Issue 1, Page 74).

$8000 / $8001 : RESET-Einsprung (Vector) LSB/MSB
$8002 / $8003 : NMI-Einsprung   (Vector) LSB/MSB
$8004 - $8008 : CBM80 (bei den Buchstaben muss das 7. Bit gesetzt sein!)
$8009 - $9fff : Hier liegt das eigentliche Programm und die Daten vom Modul.

 

Für uns sind zunächst mal die ersten neun Bytes interessant.

  • $8000 & $8001 : Hier können wir die Startadresse für unser Programm auf dem Modul ablegen. Dann wird dieses immer ausgeführt, wenn ein RESET auftritt. Wie gewohnt wird die Adresse als LSB/MSB gespeichert.
  • $8002 & $8003 : In diesen beiden Bytes können wir eine Adresse (LSB/MSB) hinterlegen, die beim Auftritt eines NMI angesprungen wird, z. B. beim Drücken der RESTORE-Taste.
  • $8004 bis $8008 : Die Adressen für RESET und NMI von eben haben nur dann eine Auswirkung, wenn in den folgenden fünf Bytes der Text CBM80 steht. Dabei ist zu beachten, dass bei den drei Buchstaben CBM jeweils das 7. Bit gesetzt ist!

Ein kleines Beispielprogramm

Schauen wir uns jetzt mal ein kleines Programm an, das die eben gemachten Ausführungen in die Praxis umsetzt. Unser Programm soll bei einem RESET den Rahmen wild blinken lassen und beim Betätigen von RESTORE die Hintergundfarbe ändern.

*=$8000                             ;Startadresse fürs Modul
 !byte <reset, >reset               ;ab $8000 RESET-Vector 
 !byte <nmi, >nmi                   ;ab $8002 NMI-Vector   
 !byte $c3, $c2, $cd                ;ab $8004 CBM80 (bei den Buchstaben muss
 !text "80"                         ;                das 7. Bit gesetzt sein!) 



nmi                                 ;Einsprung bei einem NMI
 pha                                ;Akku, X und Y für RTI auf den Stack
 txa
 pha
 tya
 pha
 inc $d021                          ;Hintergrundfarbe ändern
 rti                                ;Interrupt beendet



reset                               ;Einsprung bei einem RESET
 stx $d016                          ;VIC aktivieren
 jsr $fda3                          ;Init CIA
 jsr $fd50                          ;RAM testen / löschen
 jsr $fd15                          ;Init Kernal Vektoren
 jsr $ff5b                          ;Init VIC
 cli                                ;Interrupts erlauben
;*** Hier folgt das eigentliche Programm
loop
 dec $d020                          ;Rahmenfarbe ändern
 jmp loop                           ;Endlos-Schleife

Wie ihr seht, laden wir das Programm nach $8000 und beginnen, wie so häufig, mit einigen Byte-Anweisungen. Dieses Mal steht hier aber keine BASIC-Startzeile, sondern wir füllen, wie eben erklärt, die Adressen $8000 bis $8008. Dahinter wird dann unser Hauptprogramm liegen.

Direkt nach dem Label reset führen wir einige Initialisierungen durch. Ohne diese kann es zu einem ungewollten Verhalten des Moduls kommen. Zum Schluß die Interrupts wieder freigeben und das Programm läuft dann in unsere Endlosschleife um die Rahmenfarbe zu ändern.

Wenn ihr dieses Programm jetzt startet, passiert zunächst nichts. Führt ihr aber einen RESET aus (in VICE ALT+R oder den entsprechenden Menüpunkt auswählen), dann blinkt der Rahmen wie wir es gewohnt sind. Drückt ihr nun die RESTORE-Taste (unter VICE normalerweise <Bild rauf>), dann ändert sich die Hintergrundfarbe und der Rahmen flimmert auch noch. Wir ihr euch sicher vorstellen könnt, läßt sich das Programm nicht mehr verlassen, wir haben ja RESET und RESTORE umgebogen. Unter VICE hilft z. B. der sog. harte RESET (STRG+ALT+R). Startet das Programm erneut und betätigt dann RESTORE, der Hintergrund ändert sich auch jetzt und wir können immer noch im BASIC weiterarbeiten.

Dieses Vorgehen könnt ihr z. B. auch nutzen um eure Programme gegen RESET und RESTORE abzusichern. Ihr kennt das bestimmt auch von Spielen (die nicht auf einem Modul sind), ein RESET startet das Spiel einfach erneut. Bei 1942 von Elite könnt ihr das schön sehen, da es aber verschiedene Kopien von dem Spiel gibt, muss das Verhalten nicht überall so sein! Solltet ihr das Spiel besitzen, startet es mal und drückt zum Beispiel mitten im Spiel dann RESET oder RUN/STOP + RESTORE.
Habt ihr eine Version die neustartet und die Möglichkeit einen Monitor aufzurufen (unter VICE ALT+M), dann findet ihr ab der Adresse $8000 folgenden Zeilen, die uns jetzt nicht mehr fremd sein sollten:

8000: 23 80        ;RESET Vector
8002: 23 80        ;NMI Vector (hier mit RESET identisch)
8004: C3 C2        ;CB
8006: CD 38 30     ;M80
8009: ...          ;ab hier liegt das Programm, der Einsprung
                   ;ist aber erst bei $8023 (s. oben)

Den Hardware-Teil findet ihr unter Ein EPROM brennen, hier geht es ja in erster Linie um die Programmierung, daher nur einige kurze Infos:
Wer nun einen EPROMinfoInfoE)rasable P)rogrammable R)ead O)nly M)emory Ein EPROM ist ein lösch- und programmierbarer ROM-Baustein. Der Inhalt läßt sich über ein 'Sichtfenster' per UV-Licht löschen. Daher findet ihr in der Regel einen lichtundurchlässigen Aufkleber auf solchen Bausteinen.-Brenner hat, der kann das fertige Programm direkt brennen und auf ein entsprechendes Modul packen. Brennt ihr am PC, dann müsst ihr aber darauf achten, dass ihr die ersten beiden Bytes einer .prg-Datei nicht mitbrennt! Hier steht die Ladeadresse, an der das Programm im Speicher abgelegt wird und diese darf nicht mit aufs Modul! Brennt ihr am C64 sollte eure Brenn-Software dies eigentlich erkennen und die beiden Bytes automatisch entfernen.

Wer jetzt plant sein geliebtes Spiel (z. B. Frogger) auf ein Modul zu packen, der muss (neben der Programmgröße) noch etwas beachten: Ist das Programm z. B. für die Startadresse $0801 ausgelegt, dann wird es im Modul (dort liegt es ja ab $8009) nicht laufen!! Ihr müsst eine Kopierroutine davor schalten. Diese kopiert alles vom Modul an die original Speicheradressen und springt dann zum Start direkt dorthin.

.crt Datei

Unser Programm läuft jetzt zwar und läßt sich, wie eben beschrieben, auch für einen C64 auf ein EPROM brennen, aber wollen wir es als Cartridge (.crt-Datei) im Emulator verwenden, dann ist noch etwas Arbeit nötig.

Dazu muss das Programm mit einem 80-BYTE umfassenden Header als .crt-Datei gespeichert werden. Im Netz finden sich entsprechende Programme und auch VICE stellt mit cartconv.exe ein Hilfsmittel zur Erstellung von .crt-Dateien zur Verfügung.
Da ich mir zur Übung aber einige eigene Tools schreiben wollte, habe ich mir die Dokumentation zum CCS64 geschnappt und auf Basis der Beschreibung meinen Dateiconverter RetroPrgFileWizard (C# .NET 4.5) begonnen. Dieser erlaubt es, eine .prg-Datei als .crt zu speichern. Aktuell kann man nur den Namen des Moduls eingeben, die anderen Felder sind noch gesperrt. Gespeichert wird immer im Verzeichnis in dem auch die .prg-Datei liegt, hier wird einfach .prg durch .crt ersetzt. Ich habe das Programm nur kurz zusammengezimmert, daher ist es weder besonders hübsch noch fängt es Fehler ab, liegt die .prg z. B. auf einer CD, dann fällt das Speichers eher schwer 😉

Unerwähnt soll natürlich nicht bleiben, dass ihr .crt-Dateien nicht nur mit VICE, sondern auch mit dem Turbo Chameleon 64 benutzen könnt. Somit lassen sich eure Modul-Programme, auch ohne EPROMMER, direkt am C64 starten.


Viel mehr gibt es zum Einstieg zur Programmierung von Modulen eigentlich nicht sagen. Wie oben erwähnt, plane ich noch einen Hardwareteil (dort wird dann z. B. auch das Bankswitching behandelt, sprich das Modul blendet sich in andere Speicherbereiche, statt nach $8000, ein und man kann größere Module erstellen). Wie das Brennen mit dem TINY-EPROMMER funktioniert, findet ihr unter Ein EPROM brennen.


Schrott!!Naja...Geht so...Ganz gut...SUPER! (3 Bewertungen | Ø 5,00 von 5 | 100,00%)

Loading...


ZurückWeiter

 

11 Gedanken zu „Ein Modul erstellen“

  1. ich will jetzt auch mal mein erstes Programm auf ein Modul bringen, habe dazu aber noch einen Frage. Wenn ich ein Basic Programm am C64 erstelle und speichere habe ich ja noch lange nicht den Maschinencode den ich fürs Modul brauche. Womit compiliert ihr das?

    1. Ich nutze die zwar nicht, aber es gibt für den C64 auch Basic-Compiler (z. B. „BASIC 64 Compiler“ von Data Becker oder „Basic-Boss“ von Markt & Technik).

  2. Ist die NMI-Routine von Zeile 10- 14 so richtig?
    pla – holt den Wert vom Stack in den Akku
    txa – kopiert den Wert von X in den Akku
    pla – siehe oben
    tya – kopiert den Wert von Y in den Akku
    pla – siehe oben

    Jedes mal wird der Akku neu beschrieben.
    Welchen Sinn hat dies?
    Oder sollte der Wert aus den Registern auf den Stack gelegt werden?
    Dazu bräuchte man doch den PHA – Befehl.

  3. Hallo,

    was kann ich machen wenn das Programm was auf ein Eprom soll größer als 8K ist. Ab $a000 liegt ja das BASIC ROM des 64er. Gibt es da auch eine Lösung?

    Sonst habe ich alles verstanden, vor allem weil das hier auch excelent erklärt wird.

    Danke dafür.

  4. Hallo ich würde gerne das TurboTape64 auf ein Cartdridge transferieren !
    Es hat ja einen Basickopf und eine Kopierroutine welche mit sys 3032 startet und das Programm nach 50000 kopiert !

    Habe dies auch im ASM mit JMP 3032 geändert !
    leider kommt nur der Ladestreifen des loaders und dann hängt sich der Rechner weg.

    Habe leider sehr wenig Erfahrung mit ASM !!
    Gruss Günter !

    1. Moin Günter,

      dein Problem sind folgende Befehle, die direkt beim Einsprung an $C350 (50000) liegen:
      C:c350 A9 5B LDA #$5B
      .C:c352 8D 08 03 STA $0308
      .C:c355 A9 C3 LDA #$C3
      .C:c357 8D 09 03 STA $0309
      .C:c35a 60 RTS

      Dorthin springt am Schluß auch die Kopierroutine von $0BD8 (3032).

      „Turbo Tape 64“ erweitert den BASIC-Befehlssatz, dazu wird der Vektor für die Befehlsausführung umgebogen. Dies geschieht durch obige Zeilen.
      Zum Schluß kommt ein einfaches RTS und das ist die eigentliche Ursache für deine Probleme. Damit will das Programm zurück ins BASIC, da es normalerweise entweder über den BASIC-Loader oder per SYS50000 gestartet wird. Vom Modul klappt das so aber nicht, da man sich dort in einem Interrupt (RESET oder NMI) befindet.

      Du musst also dafür sorgen, dass der Modul-Start das eben erwähnte RTS beachtet und kontrolliert ins BASIC zurückkehrt.

      Gruß,
      Jörn

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert

Protected by WP Anti Spam