Magic Disk 64

home to index
          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