C 64/VC 20
Floppy-Kurs

In die Geheimnisse der Floppy eingetaucht (Teil 7)

Dieser Teil zeigt wie das DOS codiert und physikalisch auf Diskette schreibt. Haben Sie gewußt, daß ein Block auf Diskette länger als 256 Byte ist?

Dieser Artikel bildet den Abschluß der festen Kursreihe. Ab jetzt soll der Floppy-Kurs in lockerer Reihenfolge fortgesetzt werden. Wir werden nun versuchen, auf die von Ihnen bevorzugten Themen einzugehen, um darüber dann in unregelmäßigen Abständen weitere Folgen zu bringen. Wir wollen Sie deshalb dazu anregen, uns Ihre Probleme und Sorgen mit der 1541 mitzuteilen.

An dieser Stelle soll aber noch ein wichtiger Sachverhalt besprochen werden, der bisher einfach unterschlagen wurde: die GCR-Codierung.

Was ist eine GCR-Codierung?

Wenn Sie den Floppy-Kurs schon länger verfolgen sind Ihnen bestimmt schon einige Ungereimtheiten aufgefallen, was den Direktzugriff auf die Diskette betrifft. Auch in der letzten Folge über das Formatieren waren zum Beispiel im Listing von S-Format einige Sprungbefehle, die nicht erklärt wurden.

Erinnern Sie sich noch an den Artikel, der sich das erste mal mit dem Schreiben von Daten auf die Diskette beschäftigte? Dort wurden, unter anderem, die SYNC-Markierungen auf der Diskette besprochen, die dem Disk-Controller als Positionsanzeiger dienen.

Ich schrieb damals, daß sich diese SYNC-Markierungen bei der 1541 aus fünf $FF-Bytes zusammensetzen, die hintereinander auf Diskette geschrieben werden. Was ist aber, wenn ein Datenblock geschrieben werden soll, der nur aus $FF-Bytes besteht? Eigentlich müßten dann diese Bytes als SYNC-Markierung wirksam werden und den gesamten Schreib- und Lesebetrieb stören. Wie die Praxis zeigt, tritt dieser Fehler nicht auf. Auch bei mehreren Blöcken aus $FF-Bytes kommt es zu keinen Komplikationen. Bei der Konstruktion der Floppy hat man sich nämlich eine Codierung der Daten einfallen lassen, die eine Eindeutigkeit der Daten schafft. Die Codierung heißt GCR, was nichts anderes als eine Abkürzung der englischen Wörter »Group Code Recording« ist.

Es stellt sich jetzt natürlich die Frage, was bei der GCR-Codierung passiert, damit eine Verwechselung zwischen SYNC- und Datenbytes unmöglich wird. Zur Beantwortung dieser Frage muß ein wenig intensiverauf das Lesen und Schreiben der Floppy eingegangen werden.

Was macht die GCR-Codierung

Das Lesen von Bytes durch den Lesekopfes steuert ein Timer des Disk-Controllers. Auf der Diskette selbst wird jedes »1«-Bit physikalisch durch einen Wechsel der Magnetisierungsrichtung dargestellt und ein »0«-Bit durch gleichbleibende Richtung der Magnetisierung. Bild 1 zeigt, was gemeint ist. Soll ein Byte von Diskette gelesen werden, so wartet der Disk-Controller einfach die Zeitspanne ab, die zum Lesen von acht Bits erforderlich ist. Innerhalb dieser Zeit liest der Schreib-/Lesekopf eine gewisse Folge von Magnetisierungswechseln und Nicht-Magnetisierungswechseln.

Bild 1. Die Aufzeichnung von Daten auf Diskette (schematisch).

Dazu ein Beispiel: Auf der Diskette steht ein $55-Byte. $55 wird binär durch die Kombination %01010101 dargestellt. Der Tonkopf stellt also während der Lesezeit die folgenden Magnetisierungswechsel fest:

Magnetisierung wechselt nicht, wechselt, wechselt nicht, wechselt, wechselt nicht, wechselt, wechselt nicht, wechselt.

Das Erkennen eines Bits geschieht dabei völlig zeitgesteuert. Der Disk-Controller »weiß«, daß er zum Lesen eines Bits eine bestimmte Zeit warten muß. Danach gilt das Bit als gelesen, und es wird eine »1« oder eine »0« bereitgestellt, je nachdem, ob ein Magnetisierungswechsel stattgefunden hat oder nicht.

Praktisch könnte man das folgendermaßen beschreiben: Sie machen mit einem Freund eine Zeit von 10 Sekunden aus. Er hat dann die Aufgabe innerhalb dieser 10 Sekunden entweder zu pfeifen oder nicht. Danach warten Sie diese 10 Sekunden ab. Hat er während dieser Zeit gepfiffen, dann entspricht das einem Magnetisierungswechsel. Hat er innerhalb der 10 Sekunden nicht gepfiffen, bedeutet das ein »0«-Bit, also keinen Magnetisierungswechsel. Da eine Diskette im Laufwerk nicht absolut gleichmäßig gedreht werden kann, also Drehzahlschwankungen unterliegt, muß noch für eine Kompensation der mechanischen Fehler gesorgt werden. Dazu wird der Timer, der die abzuwartende Zeit für jedes Bit bestimmt, bei jedem Magnetisierungswechsel neu getriggert (gestellt). Ein »1«-Bit hat also neben seinem Informationsgehalt noch die wichtige Aufgabe, Laufwerksschwankungen auszugleichen, um Lesefehler zu verhindern. Aus diesem Grund darf es zum Beipiel nicht passieren, daß mehrere $00-Bytes hintereinander auf der Diskette stehen, da sonst zu lange keine Laufwerkskontrolle mehr stattfinden könnte.

Aber auch zuviele »1«-Bits sind nicht gestattet, da mehr als acht »1«-Bits ein SYNC-Signal auslösen.

Aus den genannten Gründen werden alle Daten, die auf die Diskette geschrieben werden, vorher GCR-codiert. Mit dieser Codierung wird ausgeschlossen, daß mehr als acht »1«-Bits und mehr als zwei »0«-Bits direkt hintereinander auf die Diskette geschrieben werden und so die Schreib- und Lese-Elektronik durcheinanderbringen.

Einzig und allein die SYNC-Markierungen (mehr als acht »1«-Bits) werden vom DOS (Disk Operating System, Controller) uncodiert auf die Diskette geschrieben.

Es gibt zwei Schreibarten

Man kann also zwischen zwei Schreibarten auf Diskette unterscheiden:

  1. Schreiben von Markierungen. Hier werden fünf $FF-Bytes direkt hintereinander auf die Diskette geschrieben, um eine SYNC-Markierung zu bilden, die der Orientierung dient.
  2. Schreiben von Daten.

In diesem Modus werden Byte-Inhalte codiert, um sich von den Markierungen zu unterscheiden.

Sehen Sie sich jetzt einmal Tabelle 1 an, die Umwandlungstabelle für die Konvertierung Binär nach GCR und umgekehrt.

Wie Sie unschwer erkennen können, handelt es sich beim GCR-Code um einen 5-Bit-Code. Jedes 4-Bit-Nibble, das Sie umwandeln, wird zu einem 5-Bit-GCR-Nibble. Ein Byte, das vorher aus 8 Bits bestand wird also durch die Codierung 10 Bits lang. Allgemein nimmt die Länge der codierten Daten, um den Faktor 5/4 zu. Deshalb ist die Handhabung der GCR-Bytes nicht ganz einfach. Wandeln Sie doch einmal zwei Bytes in den GCR-Code um. Als Ergebnis erhalten Sie »zweieinhalb« Bytes, die sicherlich schwer zu behandeln sind.

Bei der GCR-Codierung geht man aus diesem Grund einen ganz einfachen Weg, um keine Format-Probleme zu bekommen: Es werden jeweils immer 4 Bytes gleichzeitig umgewandelt. Als Ergebnis erhält man 5 vollständige Bytes, die sich ohne Probleme weiterverarbeitet werden können.

Lassen Sie mich das einmal an einem Beipiel erläutern:

Nehmen wir einmal an, wir hätten vier Bytes mit dem Wert $FF. Eine Kombination also, die nicht direkt auf die Diskette geschrieben werden darf.

Hexadezimal Binär 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
Tabelle 1. Umrechnungstabelle für Binär-GCR-Umwandlung

Wir wandeln diese vier Hex-Bytes nun in die entsprechenden fünf GCR-Bytes um, indem wir in Tabelle 1 nachsehen, was die entsprechenden GCR-Äquivalente dieser Bytes sind. Wir kommen zu folgendem Ergebnis:

HEX BINÄR GCR-Gode
$FF 1111 1111 10101 10101
$FF 1111 1111 10101 10101
$FF 1111 1111 10101 10101
$FF 1111 1111 10101 10101

Die binär dargestellten GCR-Werte müssen wir jetzt nur noch zu fünf Bytes zusammenfassen, um auf folgendes Ergebnis zu kommen:

Vier $FF-Bytes werden also bei der GCR-Codierung in die fünf Bytes $AD, $6B, $5A, $D6 und $B5 umgewandelt, und Sie können sich jetzt leicht davon überzeugen, daß diese fünf Bytes für den Disk-Controller absolut ungefährlich und unkritisch sind, und daß sie die vorgeschriebenen Normen (nicht mehr als zwei »0«-Bytes und nicht mehr als acht »1«-Bytes) erfüllen.

Um Ihnen die Umwandlung der Bytes zu erleichtern, habe ich diesem Kurs zwei Programmlistings beigefügt. Listing 1 enthält ein Programm, das Ihnen vier Hex-Bytes in fünf GCR-Bytes umwandelt. In Listing 2 sehen Sie ein Programm abgedruckt, das die GCR-Codierung wieder rückgängig macht. Hier werden fünf GCR-Bytes in vier Hex-Bytes zurückverwandelt, wobei Sie mit unerlaubten Bitkombinationen vorsichtig sein sollten. Kann ein Byte nicht zurückverwandelt werden, so haben Sie eine unerlaubte GCR-Bitkombination, die sich im Ergebnis dadurch äußert, daß entsprechende Nibbles fehlen. Sie erhalten dann unter Umständen nur »halbe« Bytes.

Die Floppy hält übrigens für diesen Fall eine Fehlermeldung bereit, einen »24, READ ERROR«.

Damit Sie auch in Maschinensprache in der Lage sind, Hex-GCR-Konvertierungen durchzuführen, ist noch ein weiteres Listing (Listing 3) beigefügt. Dieses enthält die Originalroutinen des DOS zur Umwandlung von Hex-Bytes in GCR-Bytes und umgekehrt.

$F6D0: Dieses Programm holt vier Hex-Bytes aus den Speicherstellen $52 bis $55 und wandelt diese Bytes in die fünf entsprechenden GCR-Werte um. Diese fünf Bytes werden anschließend im Puffer der Adresse $30/31 (L,H) mit dem Pufferzeiger in $34 abgelegt.

Pufferadresse und Pufferzeiger müssen dabei vor Aufruf dieser Routine übergeben werden.

$F78F: Diese Routine wandelt einen gesamten Puffer, dessen Adresse in $30/31 (L,H) stehen muß, in GCR-Werte um und speichert diese in den Ausweichpuffer sowie den ursprünglichen Puffer zurück. Der Pufferinhalt vergrößert sich durch diese Umwandlung von 256 auf 324 Bytes.

$F7E6: Diese Routine wandelt fünf GCR-Bytes aus einem Puffer (dessen Adresse in $30/31 (L,H) und dessen Pufferzeiger in $34 steht) wieder in vier Hex-Bytes zurück, wobei diese dann in der Zeropage von $52 bis $55 abgespeichert werden.

$F8E0: Diese Routine decodiert einen gesamten GCR-Pufferinhalt in die ursprüngliche Form und legt diese 256 Bytes dann im Puffer mit der Adresse $30/31 (L,H) ab. Die vorherigen 324 GCR-Bytes müssen im gleichen Puffer und im Ausweichpuffer ($01BB bis $01FF) stehen.

Die Anwendungen dieser Routinen sind äußerst vielfältig. So können Sie diese Programme zum Beispiel für einen Disk-Monitor verwenden, in dem man zwischen der Anzeige von GCR-Bytes und der Anzeige von normalen Hex-Bytes hin- und herschalten kann. Die einzigen Änderungen, die Sie dazu machen müssen, bestehen in der Umrechnung der Adressen für die Speicherbereiche im Computer und der Angabe neuer Parameter als Puffer- und Zeropagebereiche. Ihrer Phantasie, was die Möglichkeiten des Monitors angeht, sind außer dem Speicherplatz im Computer keine Grenzen gesetzt.

Bis zu 365 Byte in einem Block

Durch die Verwendung der GCR-Codierung ergeben sich noch Konsequenzen. Wie sieht es beispielsweise in den Puffern der Floppy aus, wenn ein Puffer mit einem vollständigen Datenblock (also 256 Bytes) gefüllt wurde und dieser aufgezeichnet werden soll? Für dieses Problem hat der Controller einen speziellen Ausweichpuffer. Der Puffer hat eine Größe von 68 Bytes und befindet sich im Bereich von $01BB bis $01FF.

Wird nun ein Datenblock in Puffer 1 ($0400-$04FF) codiert, so werden die ersten 68 GCR-Bytes in den Ausweichpuffer übernommen. Die restlichen Bytes stehen in Puffer 1.

Aus den 256 Bytes an Information macht das DOS durch die Konvertierung also 324 Bytes, die einen gesamten Datenblock darstellen (inklusive Prüfsumme). Natürlich werden auch die Parameter im Datenblockheader (ID, Track, Sektor, Prüfsumme und Kennzeichen) vor dem Schreiben auf die Diskette in GCR-Bytes umgewandelt, wobei der Blockheader dann mit den zwei Lückenbytes auf eine Länge von zehn GCR-Bytes anwächst, da der Header aus ursprünglich acht Hex-Werten besteht.

Zusammenfassend besteht ein Sektor auf der Diskette aus den fünf Bytes der ersten SYNC-Markierung; danach folgen die zehn Bytes des Blockheaders. Vor der SYNC-Markierung des Datenblocks folgen jedoch noch neun $55-Bytes, die der GCR-Norm entsprechen und direkt auf die Diskette geschrieben werden. Sie dienen als Pufferlücke, in der dem Disk-Controller Zeit bleibt, zwischen Schreiben und Lesen umzuschalten.

Nach den fünf Bytes der SYNC-Markierung folgen die 324 Bytes des Datenblocks inklusive dessen Prüfsumme und anschließend noch die Lücke zwischen zwei Sektoren, die erfahrungsgemäß zwischen acht und zwölf Bytes lang ist. Wie Sie sehen hat also so ein Sektor auf der Diskette die stattliche Länge von 361 bis 365 Bytes.

Jetzt werden Ihnen bestimmt auch ein paar zweifelhafte JSR-Befehle in der letzten Folge des Floppy-Kurses klar: bei dem Formatiersystem in Ausgabe 5/1985, wird einmal ein Befehl JSR $FE30 und an anderer Stelle ein Befehl JSR $F78F ausgeführt. Diese Adressen sind die Einsprünge der Codier-Routinen.

Vielleicht kommt Ihnen auch noch einmal die Herstellung eines Killertracks in Erinnerung. Hier wird ein gesamter Track direkt mit $FF-Bytes vollgeschrieben und stellt so eine »Riesen-SYNC-Markierung« dar. Da eine solche Bitfolge jedoch unzulässig ist, kommt die Lese- und Schreibelektronik der Floppy völlig aus dem Konzept; der Controller »stürzt ab«.

Wenn Sie noch mehr über Ihre 1541, über schnelle Kopierprogramme und Kopierschutz-Methoden erfahren oder ein gut dokumentiertes DOS-Listing haben wollen, dann sollten Sie einmal in das M&T Floppy-Buch schauen.

(Karsten Schramm/hm)
10 rem programm zur konvertierung
20 rem von fuenf gcr-bytes in die
30 rem vier entsprechenden
40 rem hex-aequivalente
50 rem
60 rem
70 rem
80 rem (w) 1985 by karsten schramm
90 rem
100 a$="0123456789abcdef":dimg$(15):e$=""
110 g$(0)="01010"
120 g$(1)="01011"
130 g$(2)="10010"
140 g$(3)="10011"
150 g$(4)="01110"
160 g$(5)="01111"
170 g$(6)="10110"
180 g$(7)="10111"
190 g$(8)="01001"
200 g$(9)="11001"
210 g$(10)="11010"
220 g$(11)="11011"
230 g$(12)="01101"
240 g$(13)="11101"
250 g$(14)="11110"
260 g$(15)="10101"
270 print"{clr}gcr - hex - konvertierung":print
280 print:print"geben sie jetzt 5 gcr-bytes ein":print
290 input"{down}{down}";h$:gc$=""
300 x$="":forx=1tolen(h$)
310 ifmid$(h$,x,1)<>" "thenx$=x$+mid$(h$,x,1)
320 next
330 h$=x$
340 forx=1to10
350 x$=mid$(h$,x,1)
360 xx=val(x$):ifxx=0andx$<>"0"thenxx=asc(x$)-55
370 fory=0to3
380 yy=int(xx/2^(3-y)):xx=xx-yy*2^(3-y)
390 ifyythengc$=gc$+"1":goto410
400 gc$=gc$+"0"
410 nexty,x
420 hc$="":forx=1to8
430 x$=mid$(gc$,x*5-4,5)
440 fory=0to15
450 ifx$<>g$(y)thennexty
460 :
470 hc$=hc$+mid$(a$,y+1,1)
480 ifint(x/2)=x/2thenhc$=hc$+" "
490 nextx
500 print:print:print"hex: ";hc$
Listing 1. Umwandlung von Daten in GCR-Bytes
10 rem programm zur konvertierung
20 rem von vier hexbytes in die
30 rem fuenf entsprechenden
40 rem gcr-aequivalente
50 rem
60 rem
70 rem
80 rem (w) 1985 by karsten schramm
90 rem
100 a$="0123456789abcdef":dimg$(15):e$=""
110 g$(0)="01010"
120 g$(1)="01011"
130 g$(2)="10010"
140 g$(3)="10011"
150 g$(4)="01110"
160 g$(5)="01111"
170 g$(6)="10110"
180 g$(7)="10111"
190 g$(8)="01001"
200 g$(9)="11001"
210 g$(10)="11010"
220 g$(11)="11011"
230 g$(12)="01101"
240 g$(13)="11101"
250 g$(14)="11110"
260 g$(15)="10101"
270 print"{clr}hex - gcr - konvertierung":print
280 print:print"geben sie jetzt 4 hexbytes ein":print
290 print"z.b. ed 34 27 58":input"{down}{down}";h$:gc$=""
300 gosub470:forx=1to4
310 h1$=mid$(h$,x*2-1,1):h2$=mid$(h$,x*2,1)
320 h1=val(h1$):h2=val(h2$)
330 ifh1=0andh1$<>"0"thenh1=asc(h1$)-55
340 ifh2=0andh2$<>"0"thenh2=asc(h2$)-55
350 gc$=gc$+g$(h1)+g$(h2)
360 nextx
370 forx=1to10
380 b=0:b$=mid$(gc$,x*4-3,4)
390 fory=0to3
400 ifmid$(b$,y+1,1)="1"thenb=b+2^(3-y)
410 nexty
420 e$=e$+mid$(a$,b+1,1)
430 ifx/2=int(x/2)thene$=e$+" "
440 nextx
450 print:print:print"gcr: ";e$
460 end
470 x$="":forx=1tolen(h$)
480 ifmid$(h$,x,1)<>" "thenx$=x$+mid$(h$,x,1)
490 next
500 h$=x$:return
Listing 2. Umwandlung von GCR- in Daten-Bytes
Umwandlung von 4 Daten-Bytes
in 5 GCR-Bytes
f6d0  a9 00       lda #$00
f6d2  85 57       sta $57
f6d4  85 5a       sta $5a
; Pufferzeiger holen
f6d6  a4 34       ldy $34
; erstes Byte holen
f6d8  a5 52       lda $52
f6da  29 f0       and #$f0
f6dc  4a          lsr a
f6dd  4a          lsr a
f6de  4a          lsr a
f6df  4a          lsr a
f6e0  aa          tax
; und anhand der Tabelle
; umwandeln
f6e1  bd 7f f7    lda $f77f,x
f6e4  0a          asl a
f6e5  0a          asl a
f6e6  0a          asl a
f6e7  85 56       sta $56
f6e9  a5 52       lda $52
f6eb  29 0f       and #$0f
f6ed  aa          tax
f6ee  bd 7f f7    lda $f77f,x
f6f1  6a          ror a
f6f2  66 57       ror $57
f6f4  6a          ror a
f6f5  66 57       ror $57
f6f7  29 07       and #$07
f6f9  05 56       ora $56
; Byte in Puffer schreiben
f6fb  91 30       sta ($30),y
f6fd  c8          iny
; zweites Byte holen
f6fe  a5 53       lda $53
f700  29 f0       and #$f0
f702  4a          lsr a
f703  4a          lsr a
f704  4a          lsr a
f705  4a          lsr a
f706  aa          tax
f707  bd 7f f7    lda $f77f,x
; und codieren
f70a  0a          asl a
f70b  05 57       ora $57
f70d  85 57       sta $57
f70f  a5 53       lda $53
f711  29 0f       and #$0f
f713  aa          tax
f714  bd 7f f7    lda $f77f,x
f717  2a          rol a
f718  2a          rol a
f719  2a          rol a
f71a  2a          rol a
f71b  85 58       sta $58
f71d  2a          rol a
f71e  29 01       and #$01
f720  05 57       ora $57
; in Puffer schreiben
f722  91 30       sta ($30),y
f724  c8          iny
; drittes Byte holen
f725  a5 54       lda $54
f727  29 f0       and #$f0
f729  4a          lsr a
f72a  4a          lsr a
f72b  4a          lsr a
f72c  4a          lsr a
f72d  aa          tax
; codieren und in
f72e  bd 7f f7    lda $f77f,x
f731  18          clc
f732  6a          ror a
f733  05 58       ora $58
; Puffer schreiben
f735  91 30       sta ($30),y
f737  c8          iny
f738  6a          ror a
f739  29 80       and #$80
f73b  85 59       sta $59
f73d  a5 54       lda $54
f73f  29 0f       and #$0f
f741  aa          tax
f742  bd 7f f7    lda $f77f,x
f745  0a          asl a
f746  0a          asl a
f747  29 7c       and #$7c
f749  05 59       ora $59
f74b  85 59       sta $59
; viertes Byte holen
f74d  a5 55       lda $55
f74f  29 f0       and #$f0
f751  4a          lsr a
f752  4a          lsr a
f753  4a          lsr a
f754  4a          lsr a
f755  aa          tax
; codieren und in
f756  bd 7f f7    lda $f77f,x
f759  6a          ror a
f75a  66 5a       ror $5a
f75c  6a          ror a
f75d  66 5a       ror $5a
f75f  6a          ror a
f760  66 5a       ror $5a
f762  29 03       and #$03
f764  05 59       ora $59
; Puffer schreiben
f766  91 30       sta ($30),y
f768  c8          iny
f769  d0 04       bne $f76f
f76b  a5 2f       lda $2f
f76d  85 31       sta $31
f76f  a5 55       lda $55
f771  29 0f       and #$0f
f773  aa          tax
f774  bd 7f f7    lda $f77f,x
f777  05 5a       ora $5a
; Überlaufbyte ebenfalls
; in Puffer schreiben
f779  91 30       sta ($30),y
f77b  c8          iny
; Pufferzeiger merken
f77c  84 34       sty $34
f77e  60          rts
; Tabelle für die
; Umwandlung
; von HEX nach GCR-
; Werten
f77f  0a 0b 12 13 0e 0f 16 17
ff87  09 19 1a 1b 0d 1d 1e 15
-----------------------------
; Pufferdaten codieren
; Pufferadresse Lo
f78f  a9 00       lda #$00
f791  85 30       sta $30
f793  85 2e       sta $2e
; Pufferzeiger 2 setzen
f795  85 36       sta $36
; Pufferzeiger für
f797  a9 bb       lda #$bb
; Ausweichpuffer setzen
f799  85 34       sta $34
f79b  85 50       sta $50
; Pufferadresse Hi
f79d  a5 31       lda $31
; merken
f79f  85 2f       sta $2f
; Pufferadresse auf
f7a1  a9 01       lda #$01
; Ausweichpuffer
f7a3  85 31       sta $31
; Datenblockkennz. $07
; für Kodierung
; vorbereiten
f7a5  a5 47       lda $47
f7a7  85 52       sta $52
f7a9  a4 36       ldy $36
; Bytes aus normalem
; Puffer
f7ab  b1 2e       lda ($2e),y
; in Speicher für
; Codierung
f7ad  85 53       sta $53
f7af  c8          iny
f7b0  b1 2e       lda ($2e),y
f7b2  85 54       sta $54
f7b4  c8          iny
f7b5  b1 2e       lda ($2e),y
f7b7  85 55       sta $55
f7b9  c8          iny
; Pufferzeiger retten
f7ba  84 36       sty $36
; Bytes kodieren und in
; Ausweichpuffer
; schreiben
f7bc  20 d0 f6    jsr $f6d0
f7bf  a4 36       ldy $36
; weitere Bytes aus
; Puffer in
f7c1  b1 2e       lda ($2e),y
; Speicher für Codierung
-----------------------------
f7c3  85 52       sta $52
f7c5  c8          iny
f7c6  f0 11       beq $f7d9
f7c8  b1 2e       lda ($2e),y
f7ca  85 53       sta $53
f7cc  c8          iny
f7cd  b1 2e       lda ($2e),y
f7cf  85 54       sta $54
f7d1  c8          iny
f7d2  b1 2e       lda ($2e),y
f7d4  85 55       sta $55
f7d6  c8          iny
; und ggf. codieren
f7d7  d0 e1       bne $f7ba
f7d9  a5 3a       lda $3a
; ebenfalls codieren und
; in Puffer schreiben
f7db  85 53       sta $53
f7dd  a9 00       lda #$00
f7df  85 54       sta $54
; Leerbytes zum Auffüllen
f7e1  85 55       sta $55
; ebenfalls codieren
f7e3  4c d0 f6    jmp $f6d0
-----------------------------
Umwandlung von S GCR-Bytes
in 4 Daten-Bytes
; Pufferzeiger holen
f7e6  a4 34       ldy $34
; Byte aus Puffer holen
f7e8  b1 30       lda ($30),y
f7ea  29 f8       and #$f8
f7ec  4a          lsr a
f7ed  4a          lsr a
f7ee  4a          lsr a
f7ef  85 56       sta $56
; und decodieren;
; Zwischenspeichern
; für späteres
f7f1  b1 30       lda ($30),y
f7f3  29 07       and #$07
f7f5  0a          asl a
f7f6  0a          asl a
; zusammenschieben
f7f7  85 57       sta $57
f7f9  c8          iny
f7fa  d0 06       bne $f802
f7fc  a5 4e       lda $4e
f7fe  85 31       sta $31
f800  a4 4f       ldy $4f
; nächstes Byte holen
f802  b1 30       lda ($30),y
f804  29 c0       and #$c0
f806  2a          rol a
f807  2a          rol a
f808  2a          rol a
f809  05 57       ora $57
f80b  85 57       sta $57
; codieren und
f80d  b1 30       lda ($30),y
f80f  29 3e       and #$3e
f811  4a          lsr a
; zwischenspeichern
f812  85 58       sta $58
f814  b1 30       lda ($30),y
f816  29 01       and #$01
f818  0a          asl a
f819  0a          asl a
f81a  0a          asl a
f81b  0a          asl a
f81c  85 59       sta $59
f81e  c8          iny
f81f  b1 30       lda ($30),y
f821  29 f0       and #$f0
f823  4a          lsr a
f824  4a          lsr a
f825  4a          lsr a
f826  4a          lsr a
f827  05 59       ora $59
f829  85 59       sta $59
f82b  b1 30       lda ($30),y
f82d  29 0f       and #$0f
f82f  0a          asl a
f830  85 5a       sta $5a
f832  c8          iny
f833  b1 30       lda ($30),y
f835  29 80       and #$80
f837  18          clc
f838  2a          rol a
f839  2a          rol a
f83a  29 01       and #$01
f83c  05 5a       ora $5a
f83e  85 5a       sta $5a
f840  b1 30       lda ($30),y
f842  29 7c       and #$7c
f844  4a          lsr a
f845  4a          lsr a
f846  85 5b       sta $5b
f848  b1 30       lda ($30),y
f84a  29 03       and #$03
f84c  0a          asl a
f84d  0a          asl a
f84e  0a          asl a
f84f  85 5c       sta $5c
f851  c8          iny
f852  d0 06       bne $f85a
f854  a5 4e       lda $4e
f856  85 31       sta $31
f858  a4 4f       ldy $4f
f85a  b1 30       lda ($30),y
f85c  29 e0       and #$e0
f85e  2a          rol a
f85f  2a          rol a
f860  2a          rol a
f861  2a          rol a
f862  05 5c       ora $5c
f864  85 5c       sta $5c
f866  b1 30       lda ($30),y
f868  29 1f       and #$1f
f86a  85 5d       sta $5d
f86c  c8          iny
f86d  84 34       sty $34
; Bytes aus
; Zwischenspeicher
f86f  a6 56       ldx $56
; holen, gemäß Tabelle
; übersetzen und ab $52
; bis $55
f871  bd a0 f8    lda $f8a0,x
f874  a6 57       ldx $57
f876  1d c0 f8    ora $f8c0,x
; speichern für Übergabe
; 1. Byte
f879  85 52       sta $52
f87b  a6 58       ldx $58
f87d  bd a0 f8    lda $f8a0,x
f880  a6 59       ldx $59
f882  1d c0 f8    ora $f8c0,x
; 2. Byte
f885  85 53       sta $53
f887  a6 5a       ldx $5a
f889  bd a0 f8    lda $f8a0,x
f88c  a6 5b       ldx $5b
f88e  1d c0 f8    ora $f8c0,x
; 3. Byte
f891  85 54       sta $54
f893  a6 5c       ldx $5c
f895  bd a0 f8    lda $f8a0,x
f898  a6 5d       ldx $5d
f89a  1d c0 f8    ora $f8c0,x
; 4. Byte
f89d  85 55       sta $55
f89f  60          rts
; Tabelle dient der
; Decodierung der GCR-
; Bytes in die entspr.
; Hex-Werte.
; Die $FF-Bytes geben
; die Positionen der
; illegalen Bitkombina-
; tionen an. Sie veran-
; lassen ggf. einen
; »24, READ ERROR«.
f8a0  ff ff ff ff ff ff ff ff
f8a8  ff 80 00 10 ff c0 40 50
f8b0  ff ff 20 30 ff f0 60 70
f8b8  ff 90 a0 b0 ff d0 e0 ff
f8c0  ff ff ff ff ff ff ff ff
f8c8  ff 08 00 01 ff 0c 04 05
f8d0  ff ff 02 03 ff 0f 06 07
f8d8  ff 09 0a 0b ff 0d 0e ff
-----------------------------
Pufferinhalt decodieren
; Pufferzeiger auf Null
f8e0  a9 00       lda #$00
; setzen
f8e2  85 34       sta $34
f8e4  85 2e       sta $2e
; 2. Pufferzeiger
f8e6  85 36       sta $36
; Adresse für
; Ausweichpuffer
f8e8  a9 01       lda #$01
f8ea  85 4e       sta $4e
; nach $4e/4f
f8ec  a9 ba       lda #$ba
f8ee  85 4f       sta $4f
; Pufferadresse Hi retten
f8f0  a5 31       lda $31
f8f2  85 2f       sta $2f
; Bytes decodieren
f8f4  20 e6 f7    jsr $f7e6
; 1. Byte als Kennzeichen
f8f7  a5 52       lda $52
; für Datenblock
f8f9  85 38       sta $38
f8fb  a4 36       ldy $36
; restliche Bytes in
; Puffer
f8fd  a5 53       lda $53
f8ff  91 2e       sta ($2e),y
f901  c8          iny
f902  a5 54       lda $54
f904  91 2e       sta ($2e),y
f906  c8          iny
f907  a5 55       lda $55
f909  91 2e       sta ($2e),y
f90b  c8          iny
f90c  84 36       sty $36
; nächste Kolonne
; codieren
f90e  20 e6 f7    jsr $f7e6
f911  a4 36       ldy $36
f913  a5 52       lda $52
; Bytes in Puffer
; schreiben
f915  91 2e       sta ($2e),y
f917  c8          iny
f918  f0 11       beq $f92b
f91a  a5 53       lda $53
f91c  91 2e       sta ($2e),y
f91e  c8          iny
f91f  a5 54       lda $54
f921  91 2e       sta ($2e),y
f923  c8          iny
f924  a5 55       lda $55
f926  91 2e       sta ($2e),y
f928  c8          iny
; restliche Bytes ggf.
; codieren
f929  d0 e1       bne $f90c
; Prüfsumme Datenblock
; übernehmen
f92b  a5 53       lda $53
f92d  85 3a       sta $3a
; Pufferadresse Hi
; zurückholen
f92f  a5 2f       lda $2f
f931  85 31       sta $31
f933  60          rts
Listing 3. Die DOS-Routinen zur GCR-Codierung
PDF Diesen Artikel als PDF herunterladen
Mastodon Diesen Artikel auf Mastodon teilen
← Vorheriger ArtikelNächster Artikel →