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)