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)