Magic Disk 64

home to index to html: MD9309-KURSE-FLOPPY_INTERN_5A.html
            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  vor-
stellen:                                
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 Directory-
routine,  die  beim  Lesen der BAM nicht
den Bereich ab $0800 zerstört!          
3.Read 41 + Write 41                    
Diese beiden Files beinhalten eine Lese-
und 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 abspei-
chern?                                  
 Von Modulen wie  z.B. die Action Replay
wissen wir, daß dies ohne weiteres funk-
tioniert.                               
  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 Speicher-
routine.                                
    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 Un-
bekannte. 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 System-
routinen 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 Pro-
gramm erfolgt,  muß man voller Wut fest-
stellen,  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 be-
nutzen, die nicht in den Programmbereich
ab $0800 schreibt.                      
 Die Routine  die  ich  Ihnen jetzt vor-
stelle,  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 Hi-und Lo-Byte der Hexzahl eintra-
gen.                                    
2. jsr $ab3b                            
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 um-
strittensten 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  unter-
dessen  nach  jeder  neuen Kopierschutz-
variante ein neues Kopierprogramm!  Hier
ein paar Varianten von Kopier-          
schuetzen:                              
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 über-
gehen,  so daß das Spiel von jedem X-be-
liebigen  Kopierprogramm  kopiert werden
konnte.                                 
 Es gab fortan also zwei Arten von Soft-
warefirmengegnern:                      
1.Die Raubkopierer -sie waren noch recht
  harmlos für die Firmen,  da nur wenige
  so gute Kopierprogramme besassen.     
2.Die Cracker-sie waren die eigentlichen
  Firmenschaedlinge, da  sie  den Schutz
  komplett  entfernten  und jeder es ko-
  pieren 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 Pro-
gramms 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   ($f5e9)          
C.Normalcode in GCRcode wandeln ($f78f) 
D.Headerblock suchen ($f510)            
E.9 Bytes GAP nach dem Headerblock      
  ueberlesen (Warteschleife)            
F.Port A auf Ausgang ($1c03)            
G.PCR auf Ausgabe umschalten ($1c0c)    
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   
  $01bb-$01ff zuerst geschrieben werden.
J.dann folgen die restlichen 256 Bytes  
  die von $0300 - $03ff stehen.         
  Die Adresse zum Lesen und Schreiben   
  von Bytes ist ($1c01).                
K.PCR auf Eingabe umschalten ($1c0c)    
L.Port A auf Eingang ($1c03)            
M.GCRcode in Normalcode wandeln ($f5f2) 
N.Programm beenden mit ($f969)          
Valid HTML 4.0 Transitional Valid CSS!