Magic Disk 64

home to index to text: MD9309-KURSE-FLOPPY_INTERN_5A.txt
            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)

Valid HTML 4.0 Transitional Valid CSS!