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.

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:
- 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.
- 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 |
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:
- 1010 + 1101 = AD
- (1010 1 + 101 01)
- 0110 + 1011 = 6B
- 0101 + 1010 = 5A
- 1101 + 0110 = D6
- 1011 + 0101 = B5
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$
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
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