Floppy-Programmierung für Profis
Bevor wir loslegen möchte ich mich kurz
vorstellen: Ich heiße Frank Boldewin und
besitze bin seit 1985 Besitzer meines
C64' ers! Seit etwa zwei Jahren versuche
ich die letzten Geheimnisse der Floppy
zu ergründen und bin auch heute noch begeistert bei der Sache!
Da sie das erforderliche Basiswissen bereits von meinen Kollegen Uli Baster und
seinem überaus ausführlichen Floppy-Kurs
vermittelt bekommen haben, möchte ich, um lästige Wiederholungen zu vermeiden, mit meinem Kurs ganz andere Schwerpunkte
setzen. Wie werden uns in erster Linie auf die Programmierung von Routinen konzentrieren, die allgemein als kompliziert
angesehen werden, wie z. B. ein Fast-Loader
oder ein Kopierschutz.
Sie brauchen keine Angst zu haben, daß
dieser Kurs nur für Profis gemacht ist, die soweit fortgeschritten sind, daß man ihnen kaum noch etwas beibringen kann.
Jede Routinen die ich ihnen im Laufe
dieses Kurses vorstelle, wird genaustens
erklärt, so daß sie gegen Ende des Kurses
ganz allein in der Lage sein werden
ihren eigenen Fast-Loader zu schreiben.
Floppy Programmierer werden sich schwertun, um in den Besitz geeigneter Lektüre
zu gelangen. Verglichen mit dem geradezu
üppigen Literatur Angebot, daß für den
C64 vorzufinden ist, kann man das derzeit
für die Floppy vorliegende Angebot nur
als mager bezeichnen. Deshalb werde ich
in dieser und den nächsten Ausgaben versuchen, Ihnen die Kunst des Floppyprogrammierens von Grund auf zu vermitteln!
Anhand von vielen Beispielen, deteilierten Erklärungen und unter Vermeidung
langatmiger theoretischer Beschreibungen
dürfte es eigentlich kein Problem sein
ans gewünschte Ziel zu gelangen.
Zunächst aber eine kleine Übersicht über
den Inhalt des gesamten Kurses.
Inhalt:
Teil 1: 1.Block Befehle 2.User Befehle 3.Memory Befehle 4.der VIA 6522 Teil 2: 1.die BAM 2.Aufbau von Files 3.Laden+Speichern von Files 4.Zero-Page Adressen Teil 3: 1.Fehlerkanal lesen 2.Lesen+Schreiben eines Blocks 3.Jobspeicher 4.Jobcodes Teil 4: 1.die Floppy Zero-Page 2.SYNC Markierungen 3.Pruefsummen 4.Aufbau einer formatierten Disk Teil 5: 1.Whole Load+Save 2.DIR Routine 3.Kopierschutz Teil 6: 1.Diskcontroller 2.Buscontroller 3.Fastload
Soweit zum Kursinhalt. In diesem Teil
wollen noch einmal sämtliche Floppy-Befehle zusammenfassen und anhand von
Basic Routinen kurz erläutern.
In dem Nächsten un allen weiteren Kursen
muß ich leider zum besseren Verständnis
der abgedruckten Programme, etwas Erfahrung im Umgang mit einem Assembler
oder einem Monitor voraussetzen, denn
die Floppy lediglich in Basic zu programmieren ist für ein Vorhaben, wie das
Unsere praktisch unmöglich. In diesem
Teil des Kurses kommt es lediglich darauf an, den Sinn in die Anwendungsmöglichkeiten, der Floppy Kommandos zu verdeutlichen, da wir nicht noch einmal auf
jede Einzelheit eingehen können. Die
Profis unter Ihnen werden erst, in den
nächsten Teilen auf Ihre Kosten kommen, wenn wir mit einem ( extra für diesen
Kurs entwickelten) Machinensprachmonitor
der Floppy auf den Leib rücken.
Nach dieser Vorrede, möchten wir nun
endlich mit dem eigentlichen Kurs beginnen.
Die BLOCK-Befehle:
Voraussetzung für die sachgemäße Anwendung dieser Befehle ist die Kenntnis des
Diskettenaufbaus. Dieser wurde bereits
in dem Anfängerkurs deteilliert besprochen.
Der BLOCK-READ Befehl (B-R)
Angenommen Sie möchten gerne einen
einzelnen Block von der Diskette lesen!
Kein Problem, denn Abhilfe schafft der
BLOCK-READ Befehl! Er bewirkt, daß in
einen vorher definierten Puffer der gewünschte Track+ Sektor geschrieben wird!
Syntax:
print# Fn," br" ; Cn; Dn; T; S
Erklaerung der Abkuerzungen:
Fn (Filenumber 1-127) Cn (Channelnumber 2-14) Dn (Drivenumber 0) T+S(Track+Sektor)
Wollen wir also Track 18, Sektor 0 lesen, dann tippen Sie bitte folgende Befehle
ein:
OPEN1,8,2,"#" OPEN15,8,15 PRINT#15,"B-R 2 0 18 0" CLOSE1 CLOSE15
Nachdem dieser Befehl ausgeführt wurde, fragen Sie sich sicher, weshalb die
' OPEN' Befehle am Anfang.
OPEN1,8,2,"#"
Ist notwendig, da vor jedem Direktzugriff
ein Puffe r reserviert werden muß. Wir haben uns einen beliebigen gewählt, weil
es in dem Fall egal war! Wollen wir aber
einen bestimmten Puffer ansprechen, z. B.
Puffer 1, dann geben sie bitte folgendes
ein:
OPEN1,8,2,"#1"
Syntax:
open Fn, Dr, Cn,"#"
Bedeutungen der Abkuerzungen:
Fn (Filenumber 1-127) Dr (Devicenumber 8-11) Cn (Channelnumber 2-14) Fehlt also nur noch der andere 'OPEN' Befehl. OPEN15,8,15
Ist notwendig, um den Kommandokanal zu
öffnen, da alle BLOCK-MEMORY- und USER-Befehle Kommandos sind.
Zum B-R selbst muß man sagen, daß sich leider damit das erste Byte eines Blocks
nicht lesen läßt. Im Laufe dieses Kurs
werden wir aber noch einen anderen Befehl kennenlernen, der auch dieses Byte
lesen kan.
Ich möchte jedoch noch mal kurz auf die
Kanäle der Floppy zurückgreifen, da dort
dort sicherlich noch einige Fragen offen
geblieben sind.
Wahrscheinlich haben sie sich schon gefragt, warum man erst ab Kanal 2 mit
dem Block-Befehl arbeiten kann. Dies
liegt daran, weil die Kanäle 0+1 für das
Laden und Speichern schon verwendet
werden. Der Kanal 15 wird benötigt um
bestimmte Kommandos auszuführen, wie z. B.
format, scratch, init usw. !
Das gilt natürlich auch für alle anderen
Befehle!
Schauen wir uns als nächstes doch mal
den BLOCK-WRITE Befehl an.
Der BLOCK-WRITE Befehl (B-W)
Dieser Befehl ist das entsprechende Gegenstück zum B-R. Hierbei wird der Inhalt eines Buffers auf Diskette zurückgeschrieben.
Syntax:
print# Fn," bw" ; Cn; Dn; ; T; S
Beispiel:
OPEN1,8,2,"#" OPEN15,8,15 PRINT#15,"B-W 2 0 18 0" CLOSE1 CLOSE15
Man sieht schon das er in der Befehlsfolge fast identisch mit dem B-R Befehl
ist. Eine ausführliche Erläuterung der
Befehlsfolge erübrigt sich daher.
der BUFFER-POINTER (B-P)
Nehmen wir einmal an Sie möchten anstatt
eines ganzen Blocks, nur ein einzelnes
Byte aus der Floppy heraus lesen. Kein
Problem, den Abhilfe schafft der B-P
Befehl.
Dazu muß man wissen, daß ein jeder Buffer
einen bestimmten Pointer besitzt. In
diesen Pointer kann man nun eine Zahl
zwischen 0 und 255 schreiben. Diese Zahl
sagt der Floppy welches Byte sie aus der
Floppy holen soll. Natürlich muß die
Floppy auch wissen aus welchem Track und
Sektor. Zum besseren Verständnis nun
wieder ein kleines Beispiel mit der entsprechenden Syntax dazu!
Syntax:
Print# Fn," bp" ; Cn; Position
Beispiel:
OPEN1,8,2,"#0" OPEN15,8,15 PRINT#15,"B-R 2 0 18 0" PRINT#15,"B-P 2 2" GET#1,A$ A=ASC(A$+CHR$(0)) PRINT A CLOSE1 CLOSE15
Wie Sie sehen lesen wir den Directory-Block in den Floppy-Puffer und holen
uns das zweite Byte dieses Sektors mit
dem B-P Befehl. Anschliessend holen wir
uns durch den ' GET'- Befehl das Byte über
den Kommando-Kanal ab. Nun kann das Byte
auf dem Bildschirm ausgegeben werden!
Dies geschieht mit Hilfe von ' PRINT A' .
Dieses gelesene Byte hat eine besondere
Funktion auf die ich später im Kurs noch
zu sprechen komme!
Der BLOCK-EXECUTE Befehl (M-E)
------------------------------ Der B-E Befehl hat die selbe Syntax wie der B-R Befehl. Seine
zusätzliche Eigenschaft ist aber, daß er
den geladenen Block im Puffer der Floppy
als Maschinenprogramm ausführt. Es erübrigt sich deshalb die Syntax zu diesem
Befehl zu erläutern, da er sich wie der
B-R Befehl verhält!
B-A(Block Allocate) und B-F(Block-Free):
Stellen sie sich vor Sie haben ein Programm geschrieben, daß bestimmte Daten
verwaltet. Für diese Daten möchten Sie
jedoch nicht extra Files anlegen und
schreiben die Daten auf einen einzelnen
Sektor, mithilfe des Direktzugriffs.
Alles schön und gut, aber was passiert, wenn man jetzt noch zusätzlich ein Programm auf die selbe Diskette speichern
möchte? Sehr warscheinlich werden unsere
Daten überschrieben, da sie nicht ent- sprechend gekennzeichnet sind! Um sie
nun zu kennzeichnen muss
man also den B-A Befehl verwenden!
Wir wollen nun T 23, S 1 kennzeichnen!
Syntax:
print# Fn," ba" ; Dn; T; S
Beispiel:
print# Fn," ba 0231"
Wollen wir den Sektor wieder freigeben, so benutzen wir den B-F Befehl! Die Syntax zum diesem Befehl ist die selbe
wie beim B-A Befehl.
Die MEMORY-BEFEHLE
Als nächstes möchte ich mich nun den
MEMORY-Befehlen zuwenden. Diese Befehle
haben eine ähnliche Bedeutung wie der
' PEEK' und ' POKE' Befehl in Basic, nur mit dem wesentlichen Unterschied, daß
nicht die Bytes im Computerspeicher, sondern die im Floppyspeicher gelesen
und beschrieben werden können.
Der MEMORY-READ Befehl (M-R)
Mit diesem Befehl kann jede beliebige
Speicherstelle der Floppy ausgelesen
werden. Verglichen mit den Block-Befehlen
sind die Memory-Befehle etwas einfacher
zu handhaben, wie Ihnen das folgen Beispiel geleich zeigen wird.
Syntax:
print# Fn," M-R" Chr$( LB) Chr$( HB) chr$( B)
LB=Low Byte Adresse HB=Hi " " B =Anzahl der Bytes
Beispiel:
OPEN 15,8,15 PRINT#15,"M-R" chr$(18) chr$(0) chr$(2) GET#15,a$,b$ PRINT a$;b$ CLOSE1
Mit diesem Befehl wurden die ' ID' Bytes
des letzten Lesevorgangs herausgelesen.
Diese stehen in der Zeropage in den
Speicherstellen 18 und 19 . Wir sehen
schon, daß auch hier die entsprechenden
Werte mit ' get' abgeholt werden.
Der MEMORY-WRITE Befehl (M-W)
Der M-W Befehl ist das entsprechenden
Gegenstück zum M-R Befehl. Mit ihm kann theoretisch jede beliebige Speicherstelle beschrieben werden. Theoretisch
deshalb, weil immer nur der Speicherbereich eines Rechners beschrieben werden
kann, in dem sich auch tatsächlich RAM
befindet. Wie der Speicher der Floppy
im einzelnen aufgebaut ist, wird am
Schluß des Kursteils erläutert.
Auf die folgende Weise, können sie eine
oder mehrere Daten in den Floppy-Puffer
schreiben.
Syntax:
print# Fn," M-W" Chr$( LB) Chr$( HB) Chr$( B) Chr$( Data1) Chr$( Data2) . . . . . . . . .
open 15,8,15 print#15,"M-R" chr$(18) chr$(0) chr$(2) get#15,a$,b$ print a$;b$ close1
Der MEMORY-EXECUTE Befehl (M-E)
Der M-E Befehl entspricht dem SYS-Befehl
in Basic. Mit ihm lassen sich Maschinenprogramme im Speicher der Floppy starten
Man benutzt den ' M-E' sehr häufig im Zusammenhang mit dem ' M-W' Befehl, wobei
der ' M-W' die Bytefolge einer spezielle
Maschinenroutine ( Fast-Loader oder Kopierschutz) in den Floopy-Puffer schreibt
von wo aus, sie mit einem ' M-E' Befehl
gestartet oder initialisiert wird.
Die Syntax zum Starten einer Maschinenroutine lautet:
Syntax:
print# Fn," M-E" Chr$( LB) Chr$( HB)
Der USER Befehl
Nachdem wir auch diese Reihe besprochen
haben, wollen uns nun dem wohl am häufigsten benutzten Befehlen zu, den' USER' Befehlen.
Beginnen wir mit dem ' U1' . Mit diesem Befehl läßt sich ein Sektor in einen beliebigen Puffer lesen! Mit dem
' U1' kann man auch den ganze Puffer
lesen, was ja bei dem B-R Befehl nicht
der Fall war, da er das erste Byte des
Sektors nicht lesen konnte. Auch der' M-R' besitzt diese Fähigkeit! Nun schnell zur
Syntax!
Syntax:
print# Fn" u1" ; Cn; Dn; T; S
Beispiel:
print#15" u120180"
mit dem ' U2' Befehl lassen sich Daten
auf die Diskette zurueckschreiben! Da er
die gleiche Syntax besitzt wie der ' U1' möchte ich nicht länger darauf eingehen
und mich den U 3-8 zuwenden!
Sie entsprechen dem ' M-E' ! Der Vorteil
ist. Daß ' LO+ HI' Byte nicht mehr angegeben werden müssen, da jeder User 3-8 eine
vorgegebene Startadresse hat, die hier in
Tabellarischer Form wiedergegeben sind:
Befehl - Start
U3 $0500 U4 $0503 U5 $0506 U6 $0509 U7 $050c U8 $050f
Der Nachteil der U3-8 Befehle ist, daß
lediglich 6 verschiedene Start-Befehle
für ihr Programm zur Verfügung stehen.
Es sei deshalb ihnen überlassen, ob sie die ' U3-8' oder lieber den ' M-E' Befehl
benutzen ( bei dem sie ein Programm an jeder beliebigen Adresse starten können)
Der ' U9' Befehl ist in der Lage die
Floppystation zwischen dem C64(9+) und
dem VC20(9-) Betrieb umzuschalten!
Mit U: wird ein Reset in der Floppy ausgeloesst!
Zum Schluß dieses Kursteils möchte ich
noch schnell die wichtigsten Speicherinhalte des VIA6522 angeben:
$0000 - Zero Page $0100 - Stack $0145 - Page 1 $0200 - Befehlspuffer $0228 - Page 2 $0300 - Puffer 0 (Hauptspeicher) $0400 - Puffer 1 (Dirpuffer 2) $0500 - Puffer 2 (Benutzerpuffer) $0600 - Puffer 3 (Dirpuffer 1) $0700 - Puffer 4 (BAM) $0800 - nicht benutzt $1800 - serieller Bus $1c00 - Laufwerkssteuerung $c000 - 16 KByte ROm Betriebsystem
Okay damit wären wird mit der Einführung
am Ende.
Im nächsten Kursteil ist die professionelle Programmierung der Floppy dar, bei
der auch die Assembler-Freaks unter
ihnen auf ihre Kosten kommen werden.
Bis nächsten Monat dann also!( FB)
FLOPPY INTERN (Teil 2)
Willkommen zum zweiten Teil unseres
Floppykurses!
Da im ersten Teil dieses Kurses so ziemlich alle Möglichkeiten angesprochen und
abgehandelt wurden die bei der Floppyprogrammierung von BASIC aus zu realisieren sind, wollen wir ab diesem Kurs in
Assembler weiterprogrammieren, da die
Routinen, die wir im Laufe der Zeit entwickeln wollen, in Höchstgeschwindlichkeit ablaufen sollen.
Damit dürfte bereits gesagt sein, daß
dies kein reiner Einsteigerkurs sein
kann und soll. Erfahrungen im Ungang mit
einem Monitor oder Assembler und Beherschung der Maschinensprache sind erforderlich.
Zur Programmierung der Floppy ist außerdem noch ein ausgereifter Diskmonitor
erforderlich. Weil alle vorhandenen Diskmonitore unseren Ansprüchen nicht entsprachen, hatten wir keine andere Wahl, als uns hinzusetzen und einen eigenen zu
schreiben. Das Ergebnis unserer Arbeit
finden sie auf SEITE-1 dieser Ausgabe. Es
trägt die Bezeichnung " DISKPATCHER" . Da
er bereits in diesem Kursteil eingesetz
wird, sollten sie sich möglichsr schnell
mit seinen Funktionen vertraut machen.
Die Funktionen werden im Laufe dieses
Kurses erklärt.
Sollten sie bereits einen Diskmonitor
besitzen, mit dem sie gut zurechtskommen, können sie selbstverstänstlich weiterbenutzen.
Doch nun zum eigentlichen Kurs.
Die BAM
Gleich zu beginn wollen wir uns mit der
" BAM" der 1541 auseinandersetzen!
Die BAM ist der Sektorbelegungsplan der
Floppy und ist zu finden in Track 18 und
Sektor 0 ! Aufbau der BAM:
Byte: Bedeutung:
000 Tracknum. fuer Directorybeginn 001 Sektornum. " " 002 Formatkennzeichen (A) 003 nur fuer 1571 004 Freie Sektoren TRACk 1 005-007 Bitmuster Track 1 Bit=1 Sektor frei Bit=0 Sektor belegt Byte 005 - Belegung Sektor 0-7 " 006 - " " 8-16 " 007 - " " 17-23 008-011 genauso wie Byte 4-7 nur Track 2 ... 140-166 HEADER (Diskname+ID) 167-255 von der 1541 unbenutzt
Falls sie sich die BAM einmal näher anschauen wollen, können sie dies problemlos mit dem bereits erwähnten " DISK-PATCHER" tun, der ihnen Einblick in alle
Tracks und Sektoren der Diskette gebietet.
Bei der Benutung vom DISKPATCHER sollten
sie immer Bedenken, das wirkürliches
Ändern der Daten auf einer Diskette die
Vernichtng aller Daten nach sich ziehen
kann.
Legen Sie sich daher zunaechst einmal
eine neu formatierte( Experiementier) Diskette zu, da wir in nächster Zeit, viel
mit Direktzugriffen zu tun haben werden.
Das dabei auch mal was schiefgehen kann
ist auch verständlich!
Der DISKPATCHER bietet 4 Funktionen!
1 . Patchen der Diskette 2 . Directory anzeigen 3 . Floppykommandos senden ( s; n; i; r; etc.)4 . Verlassen des Menues
Da die Funktionen 2-4 sich praktisch von
selbst erklären, wollen wir uns einmal
den Patcher selbst zur Brust nehmen!
Drückt man die Taste 1, dann gelangt man
ins Patchermenue!
Über die Tasten ' T' und ' S' lassen sich
TRACK und SEKTOR einstellen! Sie werden
Hexadezimal dargestellt! Wollen wir uns
nun Track 18, Sektor 0 anschauen, müssen
wir den Track auf $12=#18 einstellen!
Drücken Sie nun ' R' um den Sektor zu
lesen! Es erscheint der Sektor auf dem
Bildschirm, den man nun mit Taste ' E' editieren kann, den Sektor beliebig verändern.
Durch die Tasten CRSR-UP + CRSR-DOWN
können Sie den Sektor hoch und runter
scrollen!
Durch drücken der RETURN-Taste, kommen
wir aus dem Editmenue wieder raus.
Die Funktion ' W' schreibt den gepatchten
( veraenderten) Sektor auf die Diskette
zurück! Durch ' Q' kommen Sie dann wieder
ins Hauptmenü!
Der Aufbau der Directory
Als nächstes möchte ich Sie mit dem Aufbau eines Directory-Blocks vertraut
machen!
In den einzelnen Directory-Blocks befinden sich die Filenamen, die sie beim
" Listen"( LOAD"$",8) der Directory erhalten. Sämtliche Directory-Blocks befinden sich auf TRACK 18 . Der erste
Directory-Block befindet sich auf TRACK
18+ SECTOR 1 . Dieser Sector ist forgendermaßen belegt.
Byte: Bedeutung:
000-001 T+ S fuer naechsten Dir-Block 002-031 Eintrag File 1( siehe unten)032-033 nicht benutzt
. . .
. . .
. . .
... 226-255 8.Eintrag
Natürlich möchten Sie nun wissen wie
wohl so ein Directoryeintrag aussieht!
Byte: Bedeutung:
000 Filetyp ( PRG; REL; SEQ; USR; DEL;)001-002 T+ S des Startsektors 003-018 Filename 019-020 Start erster Side-Sektor ( REL)021 Datensatzlaenge ( REL)022-025 nicht benutzt 026-027 Zwischenspeicher fuer DEL T+ S 028-029 Blocklaenge des Files
Die naechste Tabelle stellt den Aufbau eines Filetyp-Bytes dar:
BIT: Bedeutung:
0 0 1 0=DEL 0=SEQ 1=PRG 1=USR 0=REL 2 0 0 0 0 1 3 nicht benutzt 4 " 5 " 6 0=Normal 1=kein Scratch moeglich 7 0=File noch offen 1=File geschlossen
Das Laden eines Files in Assembler
Nachdem wir uns nun allerhand Tabellen
zu Gemüte geführt haben und wir die
grundlegenden Dinge kennen, schauen wir
uns nun die ROM-Routinen an, mit denen
wir den Direktzugriff auf die Floppy
machen wollen!
Nehmen wir einmal an, wir möchten ein
Programm laden! Kein Problem, werden Sie
jetzt sagen! Man tippt einfach,
LOAD" NAME",8,1 :
ein und schon wird das Programm geladen!
Wir wollen nun aber erkunden, was hinter
dem ' LOAD' Befehl steckt und schauen uns
die Assemblerroutine dazu an!
Sie brauchen hierzu einen SMON oder
einen ähnlichen Maschinensprachemonitor.
Hier also die Laderoutine:
lda#$01 (Filenumer) ldx#$08 (Geraeteadresse) ldy#$00 (Sekundaeradresse) jsr$fe00 (Fileparameter setzen) lda#$ (Laenge,max $10 Bytes) ldx#$ (LO-Byte Filename) ldy#$ (HI-Byte Filename) jsr$fdf9 (Filenamen setzen) lda#$00 (Load-Flag/1=Verify-Flag) ldx#$ (LO-Byte Startadresse) ldy#$ (HI-Byte Startadresse) jsr$f49e (Load) rts
Durch jsr $ fe00 werden die Fileparameter
gesetzt, damit die Floppy weiß von
welchem Gerät Sie laden soll und wohin!
Ist die Sekundäradresse nähmlich '0', wird das Progamm an eine Adresse geladen
die Sie angeben! Ist Sie '1', dann werden
die Informationen nach $0801 geladen wo
sich der Basicstart befindet, um die
Programme mit ' RUN' auszuführen!
Dieses ist natürlich nur dann möglich,
wenn Sie eine Ansprungsadresse gepoked haben!
Der Filename des zu ladenden Files kann
sich irgenwo im Speicher ihres Rechners abgelegt sein. Um das entsprechende File
zu laden, muß der Laderoutine im Akku
die Länge des Filenames und im Xund Y-Register die Adresse als LO+ HI Byte angegeben werden haben.
lda #$10 ldx #$80 ldy #$30 jsr $fdf9
Das bedeutet, daß der Filename $10 Bytes
lang ist und bei der Adresse $3080 zu
finden ist.
Durch jsr $ f49 e wird dann das Programm
geladen! Um zu testen, ob das File ' OK' ist, macht man ganz einfach ein ' verify' .
Man muss nur ' lda#$01' durch ' lda#$00' ersetzen und schon wird geprüft, ob ein
File ok oder defekt ist!
Um dieses herauszufinden koennen Sie das
sogenannte Statusbyte abfragen!
Es befindet sich in der Zeropage, bei der
Adresse $90 und hat folgende Belegung:
Bit: Bedeutung:
1 Zeitueberschreitung bei IEC-Eingabe
2"""- Ausgabe
3-5 nur fuer die Datasette 6 Uebertragung ist beendet und OK 7 Geraet meldet sich nicht
Soll ein File an eine bestimmte Adresse
geladen werden, dann müssen sie folgendes
eingeben:
lda #$00 ldx #$40 ldy #$10 jsr $f49e
Das File wird nun an die Adresse $1040
geladen, da in ' X' die LOund in ' Y' die
HI-Adresse angegeben werden muß!
Die folgende Routine bietet eine andere
Möglichkeit ein File zu laden:
lda#$01 ldx#$08 ldy#$00 jsr$fe00 lda#$ ldx#$ ldy#$ jsr$fdf9 jsr$f34a (open) ldx#$01 (chkin=auf jsr$f20e Empfang schalten) jsr$ee13 (Startadresse sta$ae LO+HI jsr$ee13 holen und sta$af speichern) ldy#$00 (Solange Bytes m02 jsr$ee13 vom Bus sta($ae),y holen inc$ae bis die bne$m01 Uebertragung inc$af komplett m01 bit$90 beendet bvc$m02 ist) lda#$01 (close jsr$f291 File) jsr$f333 (clrchk) rts
Nachdem das File mit jsr $ f34 a geöffnet
wurde, wird durch LDX#$01+ JSR$ f20 e die
Floppy auf Empfang geschaltet! Danach
liest man durch die ' IECIN' Routine
JSR $ ee13 die Startadresse ein und beginnt dann das File Byteweise zu Übertragen!
Zum Schluss wird das File noch durch
LDA#$01+ JSR$ f291 geschlossen, wobei die
'1' das zuerst geöffnete File schließt.
Wenn man also zwei Files öffnet muß
man darauf achten, welches File man
schließen möchte! Die Routine JSR$ f333 verursacht einen CLRCHK und schaltet die Floppy wieder zurÜck! Durch JSR$ f49 e
wird praktisch die Routine ab dem ' open' Befehl ersetzt!
Das Speichern eines Files in Assembler --------------------------------------
Als nächstes wollen wir uns einmal eine Routine ansehen, die ein File speichert.
Sie werden bemerken, daß der Aufbau der Speicherroutine große Ähnlichkeit mit dem der Laderoutine hat.
lda#$01 ldx#$08 ldy#$00 jsr$fe00 lda#$ ldx#$ ldy#$ jsr$fdf9 ldx#$ (LO-Startadresse) ldy#$ (HI-Startadresse) stx$fb (zwischen- sty$fc speichern) lda#$fb (Pointer zeigt zur Startadresse) ldx#$ (LO-Endadresse) ldy#$ (HI-Endadresse) jsr$f5dd (Save) rts
Nachdem die Fileparameter und der Name
übergeben wurden, wird in x und y die
Startadresse angegeben, um zu wissen ab
wo die Routine Speichern soll, und speichern diese in $ fb +$ fc zwischen.
Danach wird im Akku ein Zeiger auf die
Startadresse gelegt und in X und X wird
die Endadresse übergeben.
Ist das geschafft wird die Saveroutine
durch JSR$ f5 dd angesprungen.
Achten Sie beim angeben der Endadresse
darauf, daß Sie 1 Byte mehr angeben, da
sonst das letzte Byte nicht gespeichert wird!
Zum Schluss dieses Kursteiles noch
schnell eine Tabelle mit Zero-Page- Adr.
unter denen die Fileparameter und der
Name gespeichert werden:
Adresse: Bedeutung:
$90 Status-Flag $93 Flag fuer Load/Verify $98 Anzahl der offenen Files $99 Eingabegeraet fuer $ffcf $9a Ausgabegeraet fuer $ffd2 $ae/$af Zaehler Filebytes-$Start $b7 Laenge Filename $b8 Aktive Filenummer $b9 Sekundaeradresse $ba Geraeteadresse $bb/$bc Zeiger auf Filenamen
So, nun haben wir es für heute wieder
einmal geschafft. Ich hoffe es hat ihnen
Spass gemacht neue Erkenntnis über die Floppy zu sammeln.
Ich würde mich freuen, Sie auch beim
nächsten Mal wieder begrüßen zu dürfen!
Bis dahin, Ihr Frank Boldewin FLOPPY-INTERN (Teil 3)
Willkommen zur dritten Runde unseres
Floppykurses.
Nachdem wir im letzten Teil das Status-Flag und seine Belegung angesprochen
haben, möchten wir Ihnen diesmal ein
Programm vorstellen, daß den Fehlerkanal
ausließt.
lda #$00 ;Status-Flag sta $90 ;auf 0 setzen lda #$01 ;Filenummer ldx #$08 ;Geräteadresse ldy #$6f ;Sekundäradresse jsr $fe00 ;Fileparameterjump lda #$00 ;Länge des jsr $fdf9 ;Filenamens=0 jsr $f34a ;Open lda #$08 ;Geräteadresse jsr $ed09 ;auf Senden einstellen lda #$6f ;Sekundäradresse jsr $edc7 ;übertragen
m01 jsr $ ee13 ; Byte empfangen jsr $ f1 ca ; ausgeben bit $90 ; wenn Bit6=0 bvc $ m01 ; dann nächstes Byte lda #$08 ; Senden durch jsr $ edef ; Untalk beenden lda #$01 ; Filenummer auf 1 jsr $ f291 ; und Close rts Beim Starten dieser Routine, gibt Ihnen
die Floppy entweder den entsprechenden
Fehler aus oder meldet, daß alles ' ok' ist. Über die Subroutine " JSR $ EE13" wird
der die Fehlermeldung Byte für Byte von der Floppy zum Computer übertragen und
auf dem Bildschirm ausgegeben.
Über Bit 6 kann geprüft werden, wann das
Ende der Fehlermeldung erreicht ist. Ist
Bit 6=0, so bedeutet dies, daß noch
nicht alle Bytes der Fehlermeldung übertragen wurden. Es wird also solange zu
" JSR $ EE31" zurückgesprungen, bis die
die Floppy mit einem gesetzten Bit 6 das
Ende der Übertragung signalisiert.
Interne-Programmausführung
In dem folgenden Abschnitt wollen wir
uns mit der ganz besonderen Fähigkeit
der Floopy befassen, kleinere Routinen
" intern" auszuführen.
In den vorangegangenen Beispielen haben
wir immer nur einfache Floppy-Routinen
vom C64 aus gestartet. Doch damit sind
die Möglichkeiten der Floppy noch lange
nicht erschöpft. Man kann zB auch ganze
Programme in die Floppy transportieren, die diese dann selbständig ausführt. Dies
ist besonders dann wichtig, wenn man
einen eigenen Schnellader oder einen Kopierschutz schreiben will
Wie sie vieleicht wissen, handelt es
sich bei der VC1541 um ein intelligentes
Diskettenlaufwerk mit eigenem Prozessor
(6502), Speicherplatz ( RAM und ROM) und
Betriebsystem ( DOS) . Dadurch wird kein
Speicherplatz und keine Rechenzeit vom angeschlossenen C64 benötigt. Der C64 braucht der Floppy lediglich Befehle zu
übermitteln, die diese dann selbständig
ausführt. Im Grunde genommen, ist ihre
VC1541 nichts weiter als eine zweiter
Computer neben ihrem C64 . Sie haben also
nicht nur einen sondern gleich zwei Computer auf ihrem Schreibtisch stehen.
Im Normalbetrieb muß die Floppy drei
verschiedenen Aufgaben gleichzeitig erledigen. Dazu gehören:
1- Durchführung der Datenübertragung von
und zum C64 .
2- die Interpretation der Befehle und die
Verwaltung von Dateinen, der zugeordneten Übertragungskanäle und der Blockbuffer.
3- die hardwaremäßige Ansteuerung der Diskette.
Mit Hilfe einer ausgereiften IRQ-Technik
kann die Floppy diese drei Aufgaben
praktisch gleichzeitig ausführen.
Nachdem wir bereits in den letzten beiden Kursen auf den Aufbau der Diskette
eingegangen sind, wollen wir uns einmal
ansehen, wie das DOS seine Aufgaben erledigt.
Selbverstündlich darf man beim Schreiben
von eigenen Routinen im Floppybuffer
auch die vorhandenen Betetriebsystemroutinen verwenden. Ganz so einfach wie
im C64, geht es bei der Floppy jedoch
nicht.
Das Betriebssystem der Floppy kann man
in zwei Teile unterteilen. Der erste Teil
ist das Hauptprogramm, das in einer Endlosschleife läuft. Von diesem Teil aus
wird Hauptsächlich der serielle Bus verwaltet. Fast alle Unterprogrammaufrufe
werden mit absoluten Sprüngen ausgeführt
und müssen somit mit einem JMP-Befehl
zurück ins Hauptprogramm abgeschlossen
werden. Diese Routinen können nicht in
eigenen Programmen verwendet werden.
Der zweite Teil des Betriebsystems, ist
daher um so besser für eigene Programme
zu verwenden, denn es handelt sich dabei
um ein IRQ-Programm, welches auch als
" Jobschleife" bezeichnet wird.
Dieses Programm übernimmt die Leseund
Schreiboperationen auf und von Diskette.
Bei jedem Interrupt werden die Speicherstellen $0 bis $5 der ( Floopy) Zeropage, die die Schnittstelle, zwischen dem
Hauptprogramm herstellen, auf ihre Werte
überprüft. Alle Werte, die gleich oder
größer $80 sind werden als Befehle( Jobs) behandelt und ausgeführt. Jede dieser
Speicherstellen ( Job-Speicher) bezieht
sich auf einen bestimmten Speicherbereich. Zusätzlich gehören zu jedem Job-Speicher noch zwei Speicherstellen, die
den Track und den Sektor angeben, auf
die sich der Job( Befehl) bezieht.
Die nachfolgende Tabelle, verdeutlicht
den Zusammenhang zwischen Job( Adresse) Track-Sektorangabe und Speicherbereich.
-----+-------+--------+----------------- JOB | TRACK | SEKTOR | SPEICHERBEREICH | | | (Buffer) $00 | $06 | $07 | $0300-$03ff $01 | $08 | $09 | $0400-$04ff $02 | $0a | $0b | $0500-$05ff $03 | $0c | $0d | $0600-$06ff $04 | $0e | $0f | $0700-$07ff $05 | $10 | $11 | kein RAM -----+-------+--------+----------------- Die nächste Tabelle zeigt die Bedeutung der einzelnen Job-Codes. --------+------------------------------- JOB-CODE| AUFGABE $80 |Sektor lesen $90 |Sektor schreiben $a0 |Sektor verifizieren $b0 |Sektor suchen $c0 |Kopfanschlag $d0 |Programm im Puffer ausführen $e0 |Programm im Puffer ausführen, |vorher Laufwerksmotor ein- |schalten und Kopf positionieren --------+-------------------------------
Was man mit den Job-Codes anfangen, wollen wir anhand von einem Beispiel
zeigen.
Das nachfolgende Floppyprogramm soll
Sektor $00 von Track $12 in den Buffer 0 laden.
FLOPPYCODE: lda #$12 ;Tracknummer sta $06 ;übergeben) lda #$00 ;Sektornummer sta $07 ;übergeben) lda #$80 ;Jobcode lesen sta $00 ;in Jobspeicher EndSignal: lda $00 ;Rückmeldung bmi EndSignal;abwarten) rts
Dieses Programm muß natürlich erst in
die Floppy transportiert werden, damit es
ausgeführt werden kann. Diese Aufgabe
erledigt unser nächstes Programm.
lda #$01 ;FLOOPY INITIALISIEREN ldx #$08 ldy #$6f jsr $fe00 (Filparmeter übergeben) lda #$00 jsr $fdf9 (Filename=0) jsr $f34a (Open) lda #$08 jsr $ed0c (Listen) lda #$6f jsr $edb9 (Seclst) lda #"I" jsr $eddd (Init Floppy) lda #$08 jsr $edfe (Unlisten) ************************************** lda #$08 ;FCODE IN FBUFFER jsr $ed0c (Listen) lda #$6f jsr $edb9 (Seclst) lda #"M" jsr $eddd lda #"-" jsr $eddd lda #"W" jsr $eddd lda #$00 ;ADRESSE LO jsr $eddd lda #$05 ;ADRESSE HI jsr $eddd lda #$11 ;$11 Bytes kpieren jsr $eddd (m-w,nach $0500 ldy #$00 m01 lda FCODE,y jsr $eddd iny cpy #$11 bne $m01 (Floppyrout.in def. Puff lda #$08 jsr $edfe (Unlisten) ;*************************************** lda #$08 jsr $ed0c (Listen) lda #$6f jsr $edb9 (Seclst) lda #"M" jsr $eddd lda #"-" jsr $eddd lda #"E" jsr $eddd lda #$00 ;STARTADRESSE LO jsr $eddd lda #$05 ;SRARTADRESSE HI jsr $eddd (m-e,start $0500) lda #$08 jsr $edfe (Unlisten) ;*************************************** lda #$08 jsr $ed0c (Listen) lda #$6f jsr $edb9 (Seclst) lda #"M" jsr $eddd lda #"-" jsr $eddd lda #"R" jsr $eddd lda #$00 ;BUFFER ADRESSE jsr $eddd lda #$03 ;BUFFER ADRESSE jsr $eddd lda #$00 ;$00 = $0100 jsr $eddd (M-R,nach$0300 lda #$08 jsr $edfe (Unlisten) lda #$08 jsr $ed09 (Talk) lda #$6f jsr $edc7 (Sectlk) ldy #$00 m02 jsr $ee13 sta $0400,y iny bne $m02 (Sektor a.Screen ausgebe lda #$08 jsr $edef (Untalk) lda #$01 jsr $f291 (Close) rts FCode: lda #$12 sta $06 lda #$00 sta $07 lda #$80 sta $00 m03: lda $00 bmi $m03 rts
Was noch zu beachten wäre, ist daß Sie
immer nur $20 Hex-Bytes mit einem Schlag
in die Floppy übertragen können. Ist ihr
Floppyprogramm also länger, müssen sie es
schrittweise hineinschreiben.
Der Buffer für den Programmcode und der
Buffer für die Daten, dürfen nie gleich
sein, weil der Programmcode sich wärend
der Ausführung selbst überschreiben würde. Die Folge wäre ein Absturz der
Floppy.
Um die Routine nun noch besser zu verstehen, erkläre ich Ihnen kurz noch einmal wie ich vorgegangen bin.
1 . initialisieren der Floppy.
2 . in Puffer 2($0500), wird die Floppyroutine zum Lesen eines Blocks geschrieben.
3 . Start des Progamms in der Floppy.
4 . Einlesen des Blocks in P.0($0300) .
Von dort aus abholen und auf dem Bildschirm ausgeben.
Sie werden sich sicherlich gefragt haben
warum ich beim M-R $00 als Anzahl der
zu lesenden Bytes angegeben habe. Weil
die Angabe null Bytes zu lesen praktisch
gesehen einen sinnlose Aufgabe ist, wird
der Wert $00 intern in $100 umgewandelt.
Es werden also $0100 Bytes aus dem
Floppybuffer geladen.
Da mit diesem Beispiel die Grundstein zu
Job-Code Programmierung gelegt wurde, dürfte auch der Direktzugriff in Assembler für Sie kein Problem mehr darstellen
Mit diesen Grundlagen müßten Sie eigentlich auch mit den anderen Job-Codes zurecht kommen.
Beim Tüfteln wünsche ich Ihnen viel
Spass und verabschiede mich bis zum
nächsten Mal!( FB)
Floppy Intern (Teil IV)
Ich heisse Sie herzlich Willkommen zu
4 . Teil unseres Floppykurses.
Beginnen möchte ich mit den wichtigsten
Adressen, die die Floppy-Zeropage bietet.
Ich werde im folgenden nur einige Zeropageadressen erklären, da es einfach zu
aufwendig wäre, alle darzustellen.
Ich verweise Sie jedoch auf das Buch
' Floppy Intern', in dem die komplette
Zeropage beschrieben steht. Dieses Buch
ist normalerweise in guten Büchereien
zu haben.
Doch hier nun die wichtigsten Adressen:
Adresse: Bedeutung:
$0000 Jobspeicher für Puffer 0 $0001 " " " 1 $0002 " " " 2 $0003 " " " 3 $0004 " " " 4 $0005 " " " 5 $0006/7 T+S fuer Befehl in Puffer 0 $0008/9 " " " " " 1 $000a/b " " " " " 2 $000c/d " " " " " 3 $000e/f " " " " " 4 $0010/11 " " " " " 5
$0012/13 ID der Disk im ASCII-Format $0016-1 a Daten im aktuellen Blockheader $00161 . Zeichen der ID $00172 . Zeichen der ID $0018 Tracknummer des Blocks $0019 Sektornummer des Blocks $001 a Pruefsumme des Blockheaders $001 c Flag f. Schreibschutz auf Disk Soviel zu den Zeropageadressen.
Das Aufzeichnungsverfahren
In dem folgenden Abschnitt wollen wir
uns damit befassen, wie die Bits von der
Floppyhardware auf die Diskette geschrieben und von dort wieder gelesen
werden.
Nachdem eine Diskette formatiert wurde, ist sie in 35 Tracks unterteilt, die als
konzentrische Ringe angeordnet sind. Der
äußerste Track hat die Nummer 1 und der Innerste die Nummer 35 . Zum Ansteuern
der einzelnen Tracks hat das Laufwerk
einen sog. Steppermotor, mit dem der
Schreib/ Lesekopf über jeden Track positioniert werden kann.
Diese Tracks wiederum enthalten eine bestimmte Anzahl von Sektoren, die von Aussen nach innen abnehmen, da auf einen
äußeren Track mehr Sektoren passen als
auf einen Inneren.
Es stellt sich nun die Frage, wie man den
Anfang eines Sektors auf einem Track erkennt. Man müßte also bestimmte Byteoder Bitkombinationen bevorzugt erkennen
können, die als Daten-Bytes nicht vorkommen können. Mit 8 Bit ist es möglich
256 Bytekombinationen darzustellen, die
aber jedoch auch alle Datenbytes sein könnten. Der Schlüssel zur Lösung liegt
darin, ein Byte nicht durch 8, sondern
für die Diskettenaufzeichnung durch mehr
Bits darzustellen. Dieses Verfahren wird
als " Group Code Recording"( GCR) bezeichnet.
Jeder Sektor besteht aus einem BLOCK-HEADER und dem dazugehörigen DATENBLOCK.
Sowohl der Block-Header als auch der
Datenblock besitzen zu Beginn eine SYNC-Markierung.
Stößt der der Schreib/ Lesekopf auf eine
solche SYNC-Markierung, dann muß sie nur
noch feststellen ob es sich um einen
Blockheader oder Datenblock handelt.
Unterschieden werden sie durch das Byte
das sich gleich hinter Markierung befindet. Den Blockheader erkennt man an einem
$08 und den Datenblock an einem $07 Byte
Danach folgt noch die Prüfsumme die zur
Lesefehlerkontrolle dient. Die nachfolgende Tabelle zeigt den Aufbau eines
Headders und eines Datenblocks.
**************************************** * Sync * * * $08 * H * * Pruefsumme * e * * aktueller Sektor * a * * aktueller Track * d * * ID1 * e * * ID2 * r * * Luecke * * * * * **************************************** **************************************** * * D * * Sync * a * * $07 * t * * Track * e * * Sektor * n * * 254 Byte Daten * b * * Pruefsumme * l * * Luecke * o * * * c * * * k * ****************************************
Nachdem sie sich nun mit dem grundlegendem Aufbau der Diskette vertraut gemacht
haben, möchte ich etwas näher auf die
Synchronmarkierungen eingehen.
Wie wir schon wissen, bestehen die Syncs
aus 5$ ff Bytes. Stellen Sie sich nun
vor, man hätte einen Block voll mit $ ff
Bytes. Die Floppy könnte die Syncs von
den Datenbytes nicht mehr unterscheiden
und das Ergebnis wäre eine totales
Chaos bei der Datenorganisation. Aus
diesem Grund haben sich die Entwickler
der Floppystation die GCR-Codierung einfallen lassen.
Damit die Zusammenhaenge verstaendlich
werden möchte ich kurz auf die Technik
eingehen, die beim Lesen von Bytes geschieht.
Der Diskcontroller besitzt einen Timer
der in bestimmten Zeitabständen feststellt, ob ein Magnetisierungswechsel
stattgefunden hat.
Bei gleichbleibender Richtung wird ein
0- Bit, bei veränderter Richtung ein 1- Bit
dargestellt.
Wenn also ein Byte von der Diskette gelesen werden soll, so wartet der Diskcontroller eine bestimmte Zeit die zum
Lesen von 8- Bit erforderlich ist.
Leider kann ein Laufwerk nicht absolut
gleichmässig gedreht werden, deshalb
wird es notwendig nach jedem Magneti-- sierungswechsel den Timer neu einzu-- stellen, um Lesefehler zu vermeiden.
Logischerweise darf es also nicht passieren das zu viele $00 Bytes hintereinander folgen, da sonst zu lange keine
Laufwerkskontrolle mehr durchgeführt
wird.
Natürlich sind auch zu viele 1- Bit nicht
gestattet, so sonst ein Sync-Signal ausgelöst werden würde. Deshalb müssen die
Daten, bevor sie auf Diskette geschrieben
werden, GCR-Codiert werden.
Durch diese Technik wird ausgeschlossen, daß zu viele 0- Bit und 1- Bit direkt
hintereinander folgen und somit die
Schreibund Leseelektronik stören.
Lediglich Sync-Markierungen, also mehr
als 81- Bit, werden vom DOS uncodiert
auf die Diskette geschrieben. Es gibt
also zwei Schreibarten:
1 . Schreiben von Syncs Es werden 5$ ff Bytes hintereinander geschrieben, die der Orientierung dient.
2 . Schreiben von Daten Hier werden die Byte-Inhalte codiert, da
sie von den Syncs unterschieden werden
müssen. Hier nun die Umrechnungstabelle
für die Binär-GCR Umwandlung:
Hexadezimal: Binaer: GCR:
$0 0000 01010 $1 0001 01011 $2 0010 10010 $3 0011 10011 $4 0100 01110 $5 0101 01111 $6 0110 10110 $7 0111 10111 $8 1000 01001 $9 1001 11001 $a 1010 11010 $b 1011 11011 $c 1100 01101 $d 1101 11101 $e 1110 11110 $f 1111 10101
Wie sich erkennen laesst, handelt es sich
bei der GCR-Codierung um einen 5- Bit
Code. Jedes 4- Bit Nibble das umgewandelt
wird, wird praktisch zu einem 5- Bit GCR-Nibble, d. h. ein Byte was vorher aus
8- Bit bestand, wird durch die Codierung
zu 10- Bit.
Beim GCR-Codieren werden deshalb jeweils
immer 4 Byte gleichzeitig umgewandelt.
Als Ergebnis erhält man dann logischerweise 5 Byte.
Durch diese Technik erhält man für den
Diskcontroller ungefährliche Werte. Zum
Schluss fehlt eigentlich nur noch die
Prüfsumme, die ebenfalls zur Erkennung
von eventuellen Fehlern bestimmt ist.
Hier nun die Berechnung der Prüfsumme:
Es werden alle Bytes des Programms addiert und zum Ergebnis noch 2 Bytes der
Startadresse hinzugezählt. Dieses Ergebnis besteht aus einem Low - und Hibyte.
Das Lowbyte ist die Prüfsumme, zu der
noch der Übertrag im Hibyte addiert
werden muß. Das Endergebnis muß immer
kleiner als 256 sein. Damit sind wir mal
wieder am Ende des Kursteils angelangt.
Nachdem wir uns nun hervorragend mit dem
Aufbau und der grundlegenden Technik, die sich dahinter verbirgt, bestens
auskennen, möchte ich ab dem nächsten
Teil mit dem Entwickeln von nützlichen
Utilities beginnen.
Bis dahin, Ihr Frank Boldewin
Floppy Intern
Ich heisse Sie herzlich willkommen zum
5 . Teil unseres Floppykurses.
Da in den letzten 4 Teilen die Routinen
etwas zu kurz gekommen sind, möchte ich
Ihnen diesmal folgende Routinen vorstellen:
1 . Whole-Load + Whole-Save Diese beiden Files ermöglichen es auch
den Bereich ab $ d000 zu laden und zu
speichern!
2 . Directory Dieses File beschreibt eine Directoryroutine, die beim Lesen der BAM nicht
den Bereich ab $0800 zerstört!
3 . Read 41+ Write 41 Diese beiden Files beinhalten eine Leseund schreibe Routine fuer den Track 41 !
Diese Files befinden sich auf ihrer
Diskette und können mit $ CD00 gestartet
werden.
Beginnen möchte nun ich mit der Whole-Load Routine.
Wie Sie als Assemblerprogrammierer sehr
wahrlich wissen läßt sich auch der
Bereich :$a000-$c000 $d000-$ffff
nutzen, indem man in die Speicherstelle
$01 Werte zwischen $34 und $37 poked.
Wie aber läßt sich der Bereich abspeichern?
Von Modulen wie z. B. die Action Replay
wissen wir, daß dies ohne weiteres funktioniert.
Was aber ist wenn Sie zum Beispiel ein
Spiel geschrieben haben mit Highscore-Save und Sie nur noch einen Bereich bei
$ d000 frei haben?
Die normale Systemroutine zum laden und
Speichern von Files funktioniert hier
nicht und auch Ihr Modul kann Ihnen bei
diesem Problem nicht helfen!
Ich stelle Ihnen nun zuerst eine Routine
zum laden eines Files ab $ d000 vor
und danach die dazugehörige Speicherroutine.
lda #$01 ;Filenummer ldx #$08 ;Geraetenummer ldy #$00 ;Sekundaeradresse jsr $fe00 ;setzen lda #$ ;laenge Filename ldx #$ ;Lo- und ldy #$ ;Hi-Byte Filename jsr $fdf9 ;setzen jsr $f34a ;open ldx #$01 ;geraet auf jsr $f20e ;Empfang schalten jsr $ee13 ;startadresse sta $ae ;des jsr $ee13 ;Files sta $af ;holen m02 jsr $ee13 ;1 Byte lesen sei ;IRQ setzen ldy #$00 ;Zaehler auf null ldx #$34 ;kompletten stx $01 ;Speicher freigeben sta ($ae),y ;und abspeichern ldx #$37 ;Urzustand stx $01 ;wieder herstellen cli ;IRQ loeschen inc $ae ;Zaehler erhoehen bne $m01 ;schon Null? m01 inc $af ;dann naechster Block bit $90 ;Ende des Files schon bvc $m02 ;erreicht,sonst weiter jsr $f333 ;Empfang aus lda #$01 ;Close jmp $f291 ;File
Wie Sie sehen, bestand der Trick darin, daß wir das File byteweise reingeladen
und vor dem Poke in den Speicher einfach
den Vektor $01 verändert haben.
Somit stand uns der komplette Speicher
zur Verfügung.
Das dieser Trick auch beim Speichern
funktioniert versteht sich von selbst.
Hier nun die Speicherroutine:
lda #$01 ;Filenummer ldx #$08 ;Geraetenummer ldy #$00 ;Sekundaeradresse jsr $fe00 ;setzen lda #$ ;laenge Filename ldx #$ ;Lo- und ldy #$ ;Hi-Byte Filename jsr $fdf9 ;setzen lda #$61 ;Kanal 1+$60 fuer Save in sta $b9 ;Sekundaeradresse poken jsr $f3d5 ;IEC-Bus eroeffnen lda #$08 ;Geraeteadresse jsr $ed0c ;Listen lda #$61 ;Sekundaeradresse jsr $edb9 ;Seclst ldx #$ ;Lo- und ldy #$ ;Hi-Byte stx $ac ;der sty $ad ;Startadresse ldx #$ ;Lo- und ldy #$ ;Hi-Byte stx $ae ;der sty $af ;Endadresse lda $ac ;Startadresse jsr $eddd ;ins lda $ad ;File jsr $eddd ;schreiben m01 sei ;IRQ setzen ldy #$00 ;Zaehler=0 und kompletten sty $01 ;Speicher freigeben lda ($ac),y ;Byte holen ldy #$37 ;Urzustand wieder sty $01 ;herstellen cli ;IRQ loeschen jsr $eddd ;und Speichern jsr $fcdb ;diese Routinen werden im jsr $fcd1 ;Anschluss hieran bcc $m01 ;erklaert jsr $edfe ;Unlisten lda #$08 ;Geraeteadresse jsr $ed0c ;Listen lda #$e1 ;Sekundaeradresse + Bit 7 jsr $edb9 ;Seclst jmp $edfe ;Unlisten
In dieser Routine haben wir nun zwei Unbekannte. Zunächst mal die Kombination:
lda #$61 sta $b9 jsr $f3d5 lda #$08 jsr $ed0c lda #$61 jsr $edb9
Diese Routine ist eine andere Form der
' Open' Routine und dient lediglich der
neuen Erkenntnis!
Dann waren im Code noch 2 Systemadressen
die ich angesprungen habe.
jsr $fcdb +jsr $fcd1
In $ fcdb steht folgende Routine:
inc $ac bne $m01 inc $ad m01 rts
Hier werden eigentlich nur die Counter
für den Speicherbereich erhöht.
In $ fcd1 steht dann:
sec lda$ac sbc$ae lda$ad sbc$af rts
Hier werden die noch verbleibenden von
den schon geschriebenen Bytes abgezogen.
Damit die Routine so kurz wie möglich
bleibt, habe ich diese beiden Systemroutinen angesprungen!
Das File WholeSave speichert den Bereich
von $ d000-$ e000 ab und kann mit dem File
WholeLoad wieder reingeladen werden.
Das File das abgespeichert und geladen
werden kann habe ich ' TEST' genannt!
Nachdem wir nun über das Laden und
Speichern von Files bestens bescheid
wuessen, möchte ich Sie nun mit einer
neuen nützlichen Routine vertraut
machen, der Directory Routine!
Vor allem deshalb nützlich, weil diese
Routine bei einer längeren Directory
nicht in den eventuellen Programmbereich
ab $0800 reinschreibt!
Denn ich denke, jedem ist es schon mal
passiert, der gerade ein tolles Programm
geschrieben hat und jetzt gerne wissen
moechte, ob noch genug Platz auf der Disk
ist.
Die Directory wird geladen, zufrieden
stellt man fest:
Es ist ja noch genug Platz frei!
Als nun der letzte Blick auf das Programm erfolgt, muß man voller Wut feststellen, daß die Directory, das neue
Programm zum Teil überschrieben hat.
C-64 Besitzer die von Beginn an ein
Modul besessen haben, werden dieses
Dilemma nie erlebt haben, da eigentlich
alle Module eine Directory Routine benutzen, die nicht in den Programmbereich
ab $0800 schreibt.
Die Routine die ich Ihnen jetzt vorstelle, verhindert nicht nur, daß ein
Programm überschrieben wird, sondern
ist auch schneller und kürzer als die
System Routine!
ldx #$08 ;Geraeteadresse; ldy #$00 ;Sekundaeradresse; jsr $fe00 ;setzen; lda #$01 ;1 Byte ab; ldx #$60 ;$a360='$' fuer; ldy #$a3 ;BAM Zugriff; jsr $fdf9 ;setzen; jsr$f34a open; ldx#$01 Eingabegeraet; jsr$f20e setzen; jsr$f157 Header holen; jsr$f157 mit BASIN; m03 jsr$f157 Track + Sektor; jsr$f157 holen mit BASIN; lda$90 Status-Bit; bne$m01 testen; jsr$f157 in A/X 16-Bit; tax Blockzahl; jsr$f157 holen und in; jsr$bdcd Dezimal umrechnen; jsr$ab3b Space; m02 jsr$f157 1 Byte vom Filename; jsr$f1ca holen und ausgeben; bne$m02 Schon alle Bytes?; lda#$0d dann ASCII $0d fuer; jsr$f1ca Return ausgeben; lda$dc01 Komplette; cmp#$7f Directory schon; bne$m03 ausgegeben?; m01 lda#$01 dann; jsr$f291 Close;
jmp$ f333 aktiven Kanal schliessen;
Wie Sie sehen ist diese Routine gar
nicht so schwer zu verstehen.
Lediglich zwei neue System Routinen
habe ich benutzt!
1 . jsr $ bdcd Diese Routine wandelt eine Hexadezimale
Zahl in eine Dezimale Zahl um.
Vorher muß man nur in die Register Akku
und X Hiund Lo-Byte der Hexzahl eintragen.
2 . jsr $ ab3 b
Diese Systemroutine gibt ein Leerzeichen
auf dem Bildschirm aus, denn zwischen
Blockzahl und Filename ist stets eine
Leerstelle.
Kopierschutz
Das letzte Thema, mit dem wir uns heute
befassen werden ist wohl eines der umstrittensten in der C-64 Geschichte. Ich
spreche vom altbekannten Kopierschutz!
In den Jahren 1985-1988 lieferten sich
Softwarehaeuser und Raubkopierer ein
packendes Duell!
Die Softwarefirmen steckten sehr viel
Zeit und Geld in ihre Kopierschütze!
Die Raubkopierer entwicklelten unterdessen nach jeder neuen Kopierschutzvariante ein neues Kopierprogramm! Hier
ein paar Varianten von Kopierschuetzen:
1 . Halftracks ( der Kopf wird nur um einen halben Track
bewegt)
2 . Speedchange ( die Bitrate wurde auf eine andere
Geschwindigkeit eingestellt)
3 . Readerrors ( absichtliches erzeugen eines Fehlers)
4 . Format 41( eine Diskette wird statt 35 Tracks auf 41 Tracks formatiert.)
Vom Floppy-DOS aus sind dieses alles
Fehler, die nicht verarbeitet werden
koennen, folglich beim kopieren nicht
beruecksichtigt werden.
Die Kopie enthält also den absichtlich
erzeugten Fehler nicht mehr.
Hier genau ist der Trick eines Schutzes!
Denn fragte man diesen Fehler im Spiel
ab und er war nicht mehr vorhanden, waren
auf einmal entweder keine Sprites mehr
zu sehen oder das Spiel hing sich völlig
auf!
Der schlaue User kaufte sich deshalb
lieber ein Original um es auch 100% ig
Fehlerfrei spielen zu können!
Nicht aber die Raubkopierer, die sofort
versuchten ein besseres Kopierprogramm
zu schreiben, dass auch den neuen Schutz
kopierte!
Hiermit war das Programm zwar kopiert
und 100% ig lauffähig, nicht aber der
Schutz entfernt!
Später fingen dann ein paar Freaks an
das Programm nicht nur zu kopieren, sondern auch die Schutzabfrage zu übergehen, so daß das Spiel von jedem Xbe- liebigen Kopierprogramm kopiert werden
konnte.
Es gab fortan also zwei Arten von Softwarefirmengegnern:
1 . Die Raubkopierer - sie waren noch recht
harmlos für die Firmen, da nur wenige
so gute Kopierprogramme besassen.
2 . Die Crackersie waren die eigentlichen
Firmenschaedlinge, da sie den Schutz
komplett entfernten und jeder es kopieren konnte.
Soviel zur Geschichte!
Ich stelle Ihnen jetzt einen Schutz
aus dem oben genannten Sortiment vor.
Ich spreche vom Format 41 Schutz! Wie
schon erwähnt, muß die Diskette vorher
mit einem Disketteneditor auf 41 Tracks
formatiert werden.
Hier für eignet sich zum Beispiel der
Disk-Demon!
Nachdem nun die Diskette dementsprechend
formatiert wurde, müssen wir zunächst
mal eine Write-Routine für den Track 41 entwickeln.
Auf der Diskette befindet sich das dazu
gehörige Programm, welches auch die
Floppyroutine in die Floppy verfrachtet.
Da die Routine zum starten eines Programms in der Floppy eigentlich aus den
vergangenden Kursteilen bekannt sein
müßte, erkläre ich nun lediglich die
Floppyroutine:
lda#$03 Puffer ab sta$31 $0300 jsr$f5e9 Parity fuer Puffer sta$3a berechnen u. speichern jsr$f78f Puffer in GCR umrechnen jsr$f510 Headerblock suchen ldx#$09 m01 bvc$m01 Byte ready? clv dex 9 Bytes GAP nach Header- bne$m01 block ueberlesen lda#$ff Port A (Read/Writehead) sta$1c03 auf Ausgang lda$1c0c PCR auf and#$1f Ausgabe ora#$c0 umschalten sta$1c0c CB2 lo lda#$ff Sync ldx#$05 5x sta$1c01 auf die clv Diskette schreiben m02 bvc$m02 Byte ready? clv dex bne$m02 ldy#$bb Bytes $01bb bis $01ff m04 lda$0100,y =69 GCR Bytes m03 bvc$m03 auf die clv Diskette sta$1c01 schreiben iny bne$m04 m06 lda($30),y Datenpuffer 256 Bytes m05 bvc$m05 GCR-Code auf die clv Diskette schreiben sta$1c01 iny bne$m06 m07 bvc$m07 Byte ready? lda$1c0c PCR wieder ora#$e0 auf Eingabe umschalten sta$1c0c CB2 hi lda#$00 Port A (Read/Writehead) sta$1c03 auf Eingang jsr$f5f2 GCR in Normalcode wandeln lda#$01 Ok jmp$f969 Meldung!
Start der Floppy Routine:
ldx#$09 10 Bytes m08 lda text,x Text in sta$0300,x Writepuffer dex ab $0300 bpl$m08 poken ldx#$29 Track 41 ldy#$00 Sektor 0 stx$0a abspeichern sty$0b und lda#$e0 Programm sta$02 ab $0500 m09 lda$02 starten bmi$m09 und ausfuehren rts Ende
text." protect41 !"
Sehen wir uns nun zunächst mal den
Start der Floppyroutine an.
Hier wird ein Programm durch Jobcode $ E0 ab $0500 gestartet um einen Text, der
nach $0300 geschoben wurde, auf die Disk
zu schreiben ( auf Track 41, Sektor 0) .
Gehen wir nun noch mal die Schritte zum schreiben eines Blocks auf Diskette
durch:
A. Write Puffer angeben ($31) B. Paritaet berechnen ($ f5 e9) C. Normalcode in GCRcode wandeln ($ f78 f) D. Headerblock suchen ($ f510) E.9 Bytes GAP nach dem Headerblock ueberlesen ( Warteschleife) F. Port A auf Ausgang ($1 c03) G. PCR auf Ausgabe umschalten ($1 c0 c) H.5 Syncs (#$ ff) auf Diskette schreiben I. durch die GCR Umwandlung wurden aus 256,325 Bytes ( siehe Kurs 4), also 69 Bytes mehr im Ausweichpuffer von $01 bb-$01 ff zuerst geschrieben werden.
J. dann folgen die restlichen 256 Bytes die von $0300-$03 ff stehen.
Die Adresse zum Lesen und Schreiben von Bytes ist ($1 c01) .
K. PCR auf Eingabe umschalten ($1 c0 c) L. Port A auf Eingang ($1 c03) M. GCRcode in Normalcode wandeln ($ f5 f2) N. Programm beenden mit ($ f969)
Unsere Installationsroutine wäre damit
beendet!
Sehen uns nun als nächstes die Leseroutine bzw. die Schutzabfrage an.
lda#$03 Puffer sta$31 ab $0300 jsr$f50a Datenblockanfang suchen m01 bvc$m01 Byte ready? clv m03 lda$1c01 Datenbyte holen sta($30),y und 256 mal iny in Puffer bne$m01 schreiben ldy#$ba m02 bvc$m02 Byte ready? clv lda $1c01 Datenbyte holen sta $0100,y und 69 mal iny nach $01ba - $01ff bne $m02 schreiben jsr $f8e0 Daten aus GCR berechnen ldx #$00 Text mit m04 lda text,x gelesenen cmp $0300,x Daten vergleichen bne $m03 nicht gleich? inx sonst cpx #$0a noch ein Byte vergleiche bne $m04 bis alle verglichen lda #$01 ok jmp $f969 Meldung!
text." protect41 !"
Start der Floppyroutine:
ldx #$29 Track 41 ldy #$00 Sektor 0 stx $0a poken sty $0b und lda #$e0 Programm sta $02 bei $0500 m05 lda $02 starten und bmi $m05 ausführen rts Ende
Gehen wir nun wieder die einzelnen Schritte durch:
1 . Readpuffer ab $0300($30+$31)2 . Datenblockanfang suchen ($ f50 a)3 .256 Bytes nach $0300 holen und die restlichen Bytes nach $01 ba -$01 ff mit Adresse ($1 c01) werden Bytes von der Diskette abgeholt.
4 . GCRcode in Normalcode wandeln ($ f8 e0)5 . Abfrage ob richtiger Text im Speicher, wenn nein= Absturz der Floppy wenn ja = ok Meldung ($ f969)
Bevor sie die Routinen starten, sollten
sie die Floppy stets zuerst Reseten
und Initialisieren, da sonst unbeabsichtigt falsche Daten gelesen werden
könnten.
Sicherlich ist die Abfrage in der Leseroutine leicht zu finden und zu übergehen, für den geübten Cracker! Doch ich
denke das Grundprinzip eines Kopierschutzes ist erklärt und Ihnen stehen nun die Türen offen einen besseren, schwerer zu analysierenden Kopierschutz
zu entwickeln.
Ebenfalls haben sie leichtveränderte
Routinen kennengelernt, die das System
für die Jobcodes,$80- lesen und $90 schreiben, benutzt.
Beim naechsten Mal beschaeftigen wir uns
dann mit d er Speederprogrammierung und
schliessen damit auch gleichzeitig unsere Floppykursreihe ab!
Bis dahin, Frank Boldewin
Floppy Intern
( Teil 6)
Herzlich willkommen zum letzten Teil unseres Floppykurses.
Nach harter Vorarbeit, ist es endlich
soweit, sich als letzte Hürde den Floppyspeeder zu setzen. Dies ist ein Programm, welches es dem User ermöglich Daten mit
vielfacher Geschwindigkeit zu laden.
Ich werde dazu zunächst den Vorgang der
seriellen Programmierung erklären, was
mit Hilfe von bestimmten Registern geschiet.
Danach werden wir genaustens auf den
" Floppyspeeder" eigehen, der sich als
Objectcode auf Seite 1 dieser Magic Disk
befindet.
Zunächst die Tabelle über die CIA Zustände.
C64: Bit: Signal: Richtung: 1541: Bit:
$dd00 3 ATN => $1800 7
$dd00 5 DATA => $1800 0 $dd00 7 <= $1800 1
$d000 4 CLK => $1800 2 $dd00 6 <= $1800 3
Bei der Übertragung von Bytes wird zuzunächst die ATN ( Attention) Leitung auf
High geschaltet. Im C64 müssen zusätzlich
noch Bit 0+1 auf 1 und Bit 2 auf 0 stehen. Daraus ergibt sich also der Wert
11=$0 b, der in $ dd00 geschrieben werden
muß, um dem C64 mitzuteilen, daß gleich
Daten folgen.
Im C64 gibt es nur eine ATN-Leitung die
Ein - und Ausgang steuert.
In der Floppy hingegen ist Bit 4 für
den Ausgang und Bit 7 für den Eingang
des ATN Signals verantwortlich.
Da Daten von der Floppy zum C64 fließen
müssen wir also Bit 4( Ausgang) auf
High schalten.
In Port $1800 steht demnach der Wert $10 Dadurch weiß die Floppy, daß gleich
Daten herausgeschickt werden.
Wie Sie vieleicht schon bemerkt haben, lassen sich leider keine ganzen Bytes
übertragen, sondern jedes einzelne Bit
muß mühevoll durch die Leitung geschoben
werden. Daß dieser Vorgang lange Ladezeiten beschert, brauche ich wohl nicht
näher zu erklären.
Um nun die Daten sauber über die Data-Leitung zu bekommen, müssen diese auf
die Mikrosekunde genau getaktet werden.
Dieser Vorgang geschieht durch die Clock
Leitung. Hierdurch erspart man sich
komplizierte Zyklenausgleiche.
Ohne diese Leitung wäre beim zweiten
Bit die Übertragung beendet, da der VIC
die Arbeit des C64 regelmäßig für 40 Zyklen unterbricht, um den Bildschirm
aufzufrischen.
Dadurch würden C64 und 1541 nicht mehr
synchron arbeiten und die Chance, die
gewünschten Daten zu bekommen, dahin.
Um den Bildschirmaufbau zu verhindern, schreibt man einfach eine 0 in $ d011 .
Danach sperrt man noch schnell den IRQ
mit SEI.
Durch diesen Trick ist die Clock-Leitung
frei geworden und sie kann zusätzlich
zur Übertragung genutzt werden.
Das Timing zwischen C64 und 1541 bleibt
nun uns selbst überlassen.
Gesagt sei noch, daß in der Floppy die
Bits 1+3( Data+ Clock Ausgang) und im C64 die Bits 6+7( Data+ Clock Eingang) den
Datenverkehr regeln.
Im folgenden werde ich die C64 und 1541 Routine zur Übertragung eines Bytes erklären.
1541 Routine:( Beispiel Byte $ EA)
lda #$ea ;Byte sta $c1 ;merken m01 lda $1800 ;auf Attention bpl m01 ;warten lda #$10 ;Data sta $1800 ;setzen m02 lda $1800 ;auf C64 bmi m02 ;warten lda #$00 rol $c1 rol rol rol $c1 rol rol sta $1800 ;Bits 5 und 7 lda #$00 rol $c1 rol rol rol $c1 rol rol sta $1800 ;Bits 4 und 6 lda #$00 rol $c1 rol rol rol $c1 rol rol sta $1800 ;Bits 1 und 3 lda #$00 rol $c1 rol rol rol $c1 rol rol sta $1800 ;Bits 0 und 2 übertragen nop ;durch nop ;6 Taktzyklen nop ;ausgleichen lda #$0f ;ATN sta $1800 ;zurücksetzen rts ;Ende
Wie Sie vieleicht bemerkt haben, muß man
diese Routine sehr sorgfältig entwickeln
da die Clock Leitung ihrer eigentlichen Aufgabe entmächtigt wurde und nun als
zusätzliches Übertragungsbit dient.
Auch bei der C64 Routine ist der Zyklenausgleich nötig wie Sie gleich sehen
werden.
lda #$0b ;ATN sta $dd00 ;setzen m01 lda $dd00 ;auf Data Leitung bpl m01 ;warten lda #$03 ;ATN sta $dd00 ;zurücksetzen inc $d020 ;mit jsr m02 ;30 nop ;Takt- nop ;zyklen nop ;aus- dec $d020 ;gleichen lda $dd00 rol php rol rol $08 plp rol $08 ;Bits 5 und 7 lda $dd00 rol php rol rol $08 plp rol $08 ;Bits 4 und 6 lda $dd00 rol php rol rol $08 plp rol $08 ;Bits 1 und 3 lda $dd00 rol php rol rol $08 plp rol $08 ;Bits 0 und 2 übertragen lda $08 ;Byte eor #$ff ;invertieren m02 rts ;Ende
Sie werden sich vieleicht wundern, warum
zum Schluss der Routine der ganze Wert
invertiert wird.
Die Ursache liegt in der Hardware! Die
Entwickler haben keine Inverter vor die
Einund Ausgänge geschaltet, so daß jedes vollständig übertragene Bit softwaremässig invertiert werden muß.
Diese Routinen sind eigenständig und
können in der 1541 bzw. im C64 mit JSR
angesprungen werden.
Auf der Diskette befindet sich ein Fastloader, der sich bei genauerem Betrachten in 5 Teile aufteilen läßt.
1 . Eine Routine die das Floppyprogramm in die 1541 verfrachtet.
2 . Eine Routine die sich das File vom ersten bis zum letzten Byte in den
C64 Speicher holt.
3 . Die eben beschriebene Routine zur Uebertragung eines Bytes (1541- Routine) .
4 . Und die eben beschriebene Routine zur Uebertragung eines Bytes ( C64- Routine) .
5 . Eine Routine die sich das File in den 1541 Speicher holt.
Die Routinen 1 und 2 können wir uns
getrost sparen, denn solche Routinen
wurden schon in früheren Kursteilen entwickelt. Nummer 3 und 4 haben wir oben schon besprochen.
Lediglich Routine 5 bedarf einer kurzen
Erlaeuterung.
lda #$12 ;Zähler=0? sta $1c07 ;nächster Stepperschritt lda #$03 ;aktueller sta $31 ;Puffer 0 ($0300) jsr $f50a ;Datenblockanfang suchen m01 bvc m01 ;Ready? clv ;Flag loeschen lda $1c01 ;1 Byte lesen sta ($30),y ;und ab $0300 speichern iny ;Zaehler erhoehen bne m01 ;Puffer schon voll? ldy #$ba ;Überlaufpuffer benutzen m02 bvc m02 ;Ready? clv ;Flag löschen lda $1c01 ;1 Byte lesen sta $0100,y ;und ab $01ba speichern iny ;Zähler erhoehen bne m02 ;schon letztes Byte? jsr $f8e0 ;GCR-Code umwandeln rts ;Ende
Diese Routine macht eigentlich nichts
anderes als der Jobcode $80, der für das
Lesen von Sektoren verantwortlich ist.
Ich habe diese Routine deshalb verwendet
weil ein Blick hinter die Kulissen sehr
Lehrreich sein kann, wie Sie vieleicht
bemerkt haben.
Doch nun möchte ich noch ein paar Fragen
beanworten, die bei dem einen oder anderen noch offen sind.
Die im Code verwendete Adresse $1 c07 steht ursprünglich auf $3 a.
Dadurch, daß sie auf $12 gesetzt wurde, wird bewirkt, daß der Steppermotor
schneller reagiert, beim Trackwechsel.
Dieser Trick ist sehr nützlich bei vollen Disketten.
Die Zeropage-Adressen $30/$31 geben den
aktuellen Puffer an, mit dem gearbeitet
werden soll.
Die Port-Adresse $1 c01 ließt Bytes von
der Diskette.
Da diese Daten noch GCR codiert sind, reicht ein Puffer nicht aus und der Bereich $01 ba-$0200 wird mitbenutzt. Mit der Routine $ f8 e0 wird das ganze dann in
Normalcode umgewandelt.
Nun sind wir am Ende unseres Floppykurses angelangt und ich hoffe es hat
Ihnen Spass und Freude bereit, in die
Wunderwelt der Floppyprogrammierung einzutauchen.
Es verabschiedet sich, Frank Boldewin