Hypra-Load/Quellcode 2.1
<< zurück zu Hypra-Load
Die folgenden Abschnitte stellen das vollständige, disassemblierte Programm Hypra-Load 2.1 dar. Sie sind gegliedert in einzelne Codeblöcke, die jeweils an unterschiedlichen Adressen in die Kopie des KERNAL-ROM eingebettet werden. Dort überschreiben sie Ansteuerungsroutinen für Datassette und RS232-Schnittstelle, so dass diese Geräte nach dem Aktivieren von Hypra-Load nicht mehr genutzt werden können.
Autostart-Header[Bearbeiten | Quelltext bearbeiten]
Der folgende, kurze Codeabschnitt sorgt dafür, dass Hypra-Load 2.1 nach dem Laden sofort startet und sich installiert. Er überschreibt während des Ladens den STOP-Vektor und biegt ihn auf die zuvor schon geladene Routine P_AA
um. Da während des Ladens an ROM-Adresse $F4F9 nach jedem Lesen eines Bytes die STOP-Taste über diesen Vektor abgefragt wird, wird anschließend sofort die Routine P_AA
aufgerufen. Diese sorgt zum einen dafür, dass das Laden des restlichen Programmcodes ab Adresse $0800 fortgesetzt wird, zum anderen biegt sie den CLALL-Vektor auf die Initialisierungsroutine P_AJ
von Hypra-Load und sorgt damit dafür, dass das Programm sofort nach dem Laden gestartet und installiert wird. Anschließend setzt die Routine noch den STOP-Vektor auf seinen Originalwert zurück, bevor sie zum "IEC-Load" zurückkehrt.
ORG $02ED DRIVE EQU $08 ; Geräteadresse 8 P_AA: LDA #$08 ; Adresse des nächsten zu speichernden Byte (high) STA *$AF ; ... auf BASIC-Programmspeicher richten LDA #$00 ; Adresse des nächsten zu speichernden Byte (low) STA *$AE ; ... auf BASIC-Programmspeicher richten LDA #<SOURCE2 ; Low-Byte der Startadresse für die Initialisierungsroutine STA $032C ; als CLALL-Vektor low LDA #>SOURCE2 ; High-Byte der Startadresse für die Initialisierungsroutine STA $032D ; als CLALL-Vektor high LDA #$ED ; STOP-Vektor low STA $0328 ; ... wiederherstellen (obsolet, da unverändert) LDA #$F6 ; STOP-Vektor high STA $0329 ; ... wiederherstellen RTS ; zurück zum "IEC-Load" ; Kopie des Speicherinhalts zwischen dem Ende von P_AA und dem STOP-Vektor DW $AE86 ; Vektor für Ausdruck auswerten DB $00 ; Akku für SYS-Befehl DB $00 ; X-Reg für SYS-Befehl DB $00 ; Y-Reg für SYS-Befehl DB $00 ; Status-Register für SYS-Befehl JMP $B248 ; JMP-Befehl für USR-Funktion (zeigt auf "?ILLEGAL QUANTITY") DB $00 DW $EA31 ; IRQ-Vektor DW $FE66 ; BRK-Vektor DW $FE47 ; NMI-Vektor DW $F34A ; OPEN-Vektor DW $F291 ; CLOSE-Vektor DW $F20E ; CHKIN-Vektor DW $F250 ; CKOUT-Vektor DW $F333 ; CLRCH-Vektor DW $F157 ; INPUT-Vektor DW $F1CA ; OUTPUT-Vektor DW P_AA ; Verbogener STOP-Vektor ($02ED statt $F6ED)
C64-seitige Schnelllade-Routinen[Bearbeiten | Quelltext bearbeiten]
Der folgende Code liegt im Kernal-ROM an Adresse TARGET0=$F72C
und überschreibt hier einen Teil der Routinen für die Datassette. Er beinhaltet zum einen die Schnelllade-Routinen, der auf dem C64 ablaufen, und zum anderen die Programmteile, die den eigentlichen Ladevorgang vorbereiten, indem sie die Floppy-seitigen Codeabschnitte in den Speicher des Diskettenlaufwerks übertragen und dort starten.
SOURCE0: P_AB: LDA #<BUFFER1 ; Quelladresse der Floppy-Routinen ab $EEBB LDX #>BUFFER1 STA *$A7 ; setzen STX *$A8 LDA #<TARGET1 ; Zieladresse $0300 im RAM der Floppy LDX #>TARGET1 STA *$A9 ; setzen STX *$AA ; Routinen in Abschnitten von 29 Bytes per Memory-Write in den ; Floppyspeicher ab Adresse TARGET1=$0300 übertragen AB00: LDA #DRIVE ; Geräteadresse JSR $ED0C ; LISTEN senden LDA #$6F ; Befehlskanal 15 als Sekundäradresse JSR $EDB9 ; Sekundäradresse nach LISTEN senden LDA #$4D ; 'M' JSR $EDDD ; IECOUT ein Byte auf IEC-Bus ausgeben LDA #$2D ; '-' JSR $EDDD ; IECOUT ein Byte auf IEC-Bus ausgeben LDA #$57 ; 'W' JSR $EDDD ; IECOUT ein Byte auf IEC-Bus ausgeben LDY #$00 LDA *$A9 ; Zieladresse für Schreiben low JSR $EDDD ; IECOUT ein Byte auf IEC-Bus ausgeben LDA *$AA ; Zieladresse für Schreiben high JSR $EDDD ; IECOUT ein Byte auf IEC-Bus ausgeben LDA #$1D ; Anzahl Zeichen pro Datenblock JSR $EDDD ; IECOUT ein Byte auf IEC-Bus ausgeben AB01: LDA ($A7),Y JSR $EDDD ; IECOUT ein Byte auf IEC-Bus ausgeben INY CPY #29 ; Blockgröße erreicht? BCC AB01 ; Rücksprung, falls noch nicht JSR $EDFE ; UNLISTEN senden ; Lesezeiger auf nächsten Block richten CLC LDA *$A7 ; Low-Byte des Lesezeigers ADC #29 ; um Blockgröße erhöhen STA *$A7 ; und zurückschreiben BCC AB02 ; Sprung falls kein Additionsübertrag INC *$A8 ; High-Byte des Lesezeigers erhöhen ; Schreibzeiger auf nächsten Block richten CLC AB02: LDA *$A9 ; Low-Byte des Schreibzeigers ADC #29 ; um Blockgröße erhöhen STA *$A9 ; und zurückschreiben BCC AB03 ; Sprung falls kein Additionsübertrag INC *$AA ; High-Byte des Schreibzeigers erhöhen AB03: LDA *$A9 ; Low-Byte des Schreibzeigers CMP #$D0 ; Zeigt Schreibzeiger auf $04D0 (16*29=464 Bytes geschrieben)? BNE AB00 ; Rücksprung falls noch nicht LDA #DRIVE JSR $ED0C ; LISTEN senden LDA #$6F JSR $EDB9 ; Sekundäradresse nach LISTEN senden LDA #$4D ; 'M' JSR $EDDD ; IECOUT ein Byte auf IEC-Bus ausgeben LDA #$2D ; '-' JSR $EDDD ; IECOUT ein Byte auf IEC-Bus ausgeben LDA #$45 ; 'E' JSR $EDDD ; IECOUT ein Byte auf IEC-Bus ausgeben LDA #<P_AG JSR $EDDD ; IECOUT ein Byte auf IEC-Bus ausgeben LDA #>P_AG JSR $EDDD ; IECOUT ein Byte auf IEC-Bus ausgeben JSR $EDFB ; UNTALK senden (müsste UNLISTEN sein) JSR $EEB3 ; 1 ms Verzögerung JSR $EEB3 ; 1 ms Verzögerung SEI LDA #$0B ; Bildschirm abschalten STA $D011 LDA #$00 ; Blockzähler initialisieren STA *$BB ; und merken AB04: LDA #$FE ; 254 Bytes STA *$BC ; als Zahl gültiger Datenbytes im Blocks merken JSR P_AC ; Synchronisationsbyte vom IEC-Bus holen CMP #$FF ; Test auf Fehlercode BEQ AB13 ; Sprung falls Fehler (Sprung sollte nach AB11 führen) JSR P_AC ; Erstes Byte (Spur des nächsten Blocks) vom IEC-Bus holen STA *$B7 ; und merken JSR P_AC ; Zweites Byte (Sektor des nächsten Blocks) vom IEC-Bus holen TAY ; in Y merken LDA *$B7 ; Spur des nächsten Blocks holen BNE AB05 ; Sprung wenn nicht letzter Block ; Letzten Block einer Datei behandeln DEY STY *$BC ; Zahl der gültigen Datenbytes in diesem Block merken AB05: LDA *$BB ; Blockzähler BNE AB06 ; Sprung wenn nicht erster Block DEC *$BC ; ansonsten zwei Datenbytes weniger im ersten Block DEC *$BC JSR P_AC ; Ladeadresse überlesen JSR P_AC AB06: LDY #$00 ; Schreibindex für byteweises Laden AB07: JSR P_AC ; Datenbyte vom IEC-Bus holen STA ($AE),Y ; und an die Ladeadresse im Speicher schreiben INY ; Schreibzeiger weiterbewegen CPY *$BC ; Schon alle gültigen Datenbytes geschrieben? BNE AB07 ; Rücksprung, falls noch nicht alle Bytes CLC LDA *$BC ; Low-Byte der Ladeadresse ADC *$AE ; um Anzahl der gültigen Bytes im aktuellen Block STA *$AE ; weiterbewegen BCC AB08 ; Sprung falls kein Additionsübertrag INC *$AF ; High-Byte der Ladeadresse erhöhen AB08: INC *$BB ; Blockzähler erhöhen LDA *$B7 ; Spur des nächsten Datenblocks holen BNE AB04 ; Rücksprung falls nicht letzter Datenblock DEC *$BB ; Blockzähler erniedrigen BNE AB09 ; Sprung, falls Programm aus mehr als einem Block bestand INC *$BC ; Anzahl noch zu überlesender Datenbytes um zwei erhöhen INC *$BC AB09: LDA *$BC ; Anzahl noch zu lesender Datenbytes holen CMP #$FE ; Schon alle restlichen Datenbytes empfangen? BEQ AB10 ; Sprung falls ja JSR P_AC ; Nächstes Datenbyte holen und ignorieren INC *$BC ; Anzahl gültiger Datenbytes im Block erhöhen CLC BCC AB09 ; Immer Rücksprung AB10: LDA #$00 ; Statusbyte "OK" DB $2C AB11: LDA #$1D ; "?LOAD ERROR" (nicht verwendet) STA *$90 ; Statusbyte schreiben JMP P_AD ; Ladevorgang abschließen AB12: LDA *$90 ; Statusbyte holen CMP #$01 ; "OK" löscht CF, alle anderen Werte setzen CF PHA ; Fehlercode auf Stack sichern PHP ; Fehlerflag CF auf Stack sichern AB13: TYA ; Anzahl gültiger Datenbytes im letzten Block LDX *$AE ; Programm-Endeadresse low LDY *$AF ; Programm-Endeadresse high JMP TARGET2 ; Datenbyte mit Hypra-Protokoll empfangen und in Akku zurückliefern P_AC: LDA #$23 ; DATA low STA $DD00 AC00: BIT $DD00 ; Warten auf CLOCK high ("bereit") BVC AC00 LDA #$03 ; DATA high STA $DD00 LDX #$07 ; Verzögerung AC01: DEX BNE AC01 LDA $DD00 ; DATA und CLOCK enthalten Bit 1 und 0 des Datenbyte ROL A ROL A ; CF=Bit 0 ROR *$B0 ; ... in Adresse $B0 schieben ROR A ; CF=Bit 1 ROR *$B0 ; ... in Adresse $B0 schieben NOP ; Verzögerung NOP LDA $DD00 ; DATA und CLOCK enthalten Bit 3 und 2 des Datenbyte ROL A ROL A ; CF=Bit 2 ROR *$B0 ; ... in Adresse $B0 schieben ROR A ; CF=Bit 3 ROR *$B0 ; ... in Adresse $B0 schieben NOP ; Verzögerung NOP LDA $DD00 ; DATA und CLOCK enthalten Bit 5 und 4 des Datenbyte ROL A ROL A ; CF=Bit 4 ROR *$B0 ; ... in Adresse $B0 schieben ROR A ; CF=Bit 5 ROR *$B0 ; ... in Adresse $B0 schieben NOP ; Verzögerung NOP LDA $DD00 ; DATA und CLOCK enthalten Bit 7 und 6 des Datenbyte ROL A ROL A ; CF=Bit 6 ROR *$B0 ; ... in Adresse $B0 schieben ROR A ; CF=Bit 7 ROR *$B0 ; ... in Adresse $B0 schieben LDA *$B0 ; Datenbyte holen EOR #$FF ; Invertieren (Floppy OUT invertiert, C64 IN nicht) LDX #$03 ; DATA und CLOCK auf high STX $DD00 RTS ; Abschluss des Ladevorgangs P_AD: PLA ; Low-Byte der Ladeadresse vom Stack holen TAY ; und nach Y PLA ; High-Byte der Ladeadresse vom Stack holen TAX ; und nach X PHA TYA PHA CPX #$E0 ; Kopie des KERNAL durch Laden überschrieben? BCC AD01 ; Sprung falls KERNAL nicht überschrieben ; Prüfsumme über die ersten 256 Bytes der BASIC-ROM-Kopie berechnen LDA #$00 TAY AD00: EOR $A000,Y INY BNE AD00 CMP #$80 ; Prüfsumme korrekt? BNE AD03 ; Sprung wenn Prüfsumme falsch ; Prüfsumme über die ersten 256 Bytes der Floppy-seitigen Routinen berechnen AD01: LDA #$00 TAY AD02: EOR BUFFER1,Y INY BNE AD02 CMP #$70 ; Prüfsumme korrekt? BNE AD03 ; Sprung wenn Prüfsumme falsch LDY #$35 ; Alle ROMs ausschalten, Hypra-Load bleibt aktiv DB $2C AD03: LDY #$37 ; Alle ROMs aktivieren und Hypra-Load deaktivieren
- Kurzen Programmabschnitt für Abschluss des Ladevorgangs an Adresse $TARGET2=$0061 kopieren
LDA #$85 ; "STA *$01" STA TARGET2+$00 LDA #$01 STA TARGET2+$01 LDA #$28 ; "PLP" holt Fehlerflag CF vom Stack STA TARGET2+$02 LDA #$68 ; "PLA" holt fehlercode vom Stack STA TARGET2+$03 LDA #$60 ; "RTS" Rückkehr in LOAD-Routine ($E178) STA TARGET2+$04 LDA #$1B ; Bildschirm wieder einschalten STA $D011 JMP AB12
Floppy-seitige Schnelllade-Routinen[Bearbeiten | Quelltext bearbeiten]
Der folgende Codeblock wird in der Kopie des Kernal ROM ab Adresse BUFFER1=$EEBB
bereitgehalten und überschreibt hier einen Teil der RS232-Routinen. Er wird vor jedem Ladevorgang ins FLOPPY-RAM ab Adresse TARGET1=$0300
kopiert.
SOURCE1: ; Kommentare übernommen aus den Büchern: ; Rainer Ellinger/Lothar Englisch/Ralph Gelfand/Norbert Sczcepanowski: ; "Das große Floppybuch zur 1541" ; Rainer Ellinger: ; "Commodore 1571 & 1570 - Das große Floppybuch" P_AE: LDA *$00 ; Jobrückmeldung holen AND #$06 CMP #$02 ; Fehler "Blockheader nicht gefunden"/"SYNC-Markierung nicht gefunden"? BEQ AE00 ; Sprung falls Fehler JMP $FD9E ; Fehler $01 ("00,OK") zurückgeben AE00: NOP LDA #$05 ; Maximale Anzahl Prüfsummenfehler STA *$09 ; merken AE01: LDX #$5A ; Zahl der Leseversuche STX *$4B ; festlegen LDX #$00 ; Zähler für Zahl der Headerbytes löschen LDA #$52 ; GCR-Kennzeichen für Blockheader STA *$24 ; merken AE02: JSR $F556 ; Auf nächste SYNC-Markierung warten AE03: BVC AE03 ; ist Leseelektronik bereit? CLV ; ja, Flag wieder zurücksetzen LDA $1C01 ; Headerkennzeichen von Diskette lesen CMP *$24 ; mit Kennzeichen für Block vergleichen BEQ AE04 ; liegt kein Blockheader vor? DEC *$4B ; Zähler für Leseversuche erniedrigen BNE AE02 ; 90 Leseversuche ausgeführt LDA #$0A ; Fehlernummer JMP $F969 ; ausgeben AE04: BVC AE04 ; doch, auf nächstes Byte warten CLV ; Leseelektronik wieder aktivieren LDA $1C01 ; Byte von Diskette lesen STA *$25,X ; und im Headerpuffer speichern INX ; Zähler erhöhen CPX #$07 ; mit Zahl der Headerbytes vergleichen BNE AE04 ; bereits ganzer eingelesen? JSR $F497 ; ja, Header von GCR nach Binär wandeln LDA *$16 ; Prüfsumme des Headers EOR *$17 ; berechnen EOR *$18 EOR *$19 EOR *$1A BEQ AE05 ; Prüfsummenfehler aufgetreten? DEC *$09 ; Zähler für Prüfsummenfehler erniedrigen BNE AE01 ; Sprung falls noch nicht 5 Prüfsummenfehler aufgetreten JMP $F41E ; Fehler $09 ("27,WRITE ERROR") zurückgeben AE05: LDA *$18 ; Spurnummer aus gelesenem Header CMP *$06 ; mit gesuchter Spurnummer vergleichen BEQ AE06 ; Sprung wenn richtige Spur gelesen JMP $F40B ; Fehler $02 ("20,READ ERROR") zurückgeben AE06: STA *$22 ; Als Spurnummer des aktuellen Jobs speichern LDA #$06 ; Puffer an Adresse $0600 STA *$31 ; als aktuellen Datenpuffer setzen JMP AF08 ; Geringfügig modifizierte Kopie des Floppy-ROM ab $F510 (Sektorheader suchen) P_AF: LDA *$12 ; Erstes Zeichen der ID LDX *$13 ; Zweites Zeichen der ID STA *$16 ; in Headerpuffer übertragen STX *$17 ; in Headerpuffer übertragen LDA *$06 ; Spurnummer holen STA *$18 ; und in Headerpuffer übertragen LDA *$07 ; Sektornummer holen STA *$19 ; und in Headerpuffer übertragen LDA #$00 ; Prüfsumme EOR *$16 ; des erstellten Sektorheaders EOR *$17 ; berechnen EOR *$18 ; und in den EOR *$19 ; Headerpuffer STA *$1A ; schreiben JSR $F934 ; Sektorheader in GCR-Bytes umwandeln LDX #$5A ; Zahl der Leseversuche festlegen (90) AF00: JSR $F556 ; Auf nächste SYNC-Markierung warten LDY #$00 ; Pufferzeiger löschen AF01: BVC AF01 ; auf Byte von Diskette warten CLV ; BYTE-READY Flag wieder bereit machen LDA $1C01 ; Byte vom Lesekopf holen CMP $0024,Y ; und m. hergestelltem Header vergleichen BEQ AF02 ; Werte nicht identisch? DEX ; Zähler der Leseversuche erniedrigen BNE AF00 ; noch einen Leseversuch durchführen? JMP $F551 ; Fehlermeldung ausgeben AF02: INY ; doch, Pufferzeiger auf nächstes Zeichen CPY #$08 ; mit Zahl der Headerbytes vergleichen BNE AF01 ; gesamter Header überprüft? JSR $F556 ; auf nächste SYNC-Markierung warten ; Geringfügig modifizierte Kopie des Code ab $F4D4 (Sektor lesen) AF03: BVC AF03 ; auf Byte von Diskette warten CLV ; Leseelektronik wieder bereit machen LDA $1C01 ; Byte vom Kopf lesen STA ($30),Y ; und in aktuellen Puffer schreiben INY ; Pufferzeiger auf nächstes Byte setzen BNE AF03 ; Puffer schon voll? LDY #$BA ; ja, Pufferzeiger auf Zusatzpuffer AF04: BVC AF04 ; auf nächstes Byte von Diskette warten CLV ; Flag wieder bereit machen LDA $1C01 ; Byte vom Lesekopf holen STA $0100,Y ; und in Zusatzpuffer schreiben INY ; Pufferzeiger auf nächstes Byte setzen BNE AF04 ; Zusatzpuffer voll? JSR $F8E0 ; ja, Sektor von GCR nach Binär wandeln LDA *$38 ; erstes Byte des Datenblock holen und CMP *$47 ; Kennzeichen für Datenblockheader BEQ AF05 ; Datenblock? JMP $F4F6 ; nein, Fehlermeldung AF05: JSR $F5E9 ; Prüfsumme der Daten berechnen CMP *$3A ; mit gelesenem Wert vergleichen BEQ AF06 ; beide identisch? JMP $F502 ; Fehler $05 ausgeben ; Datenblock an Adresse $0600 per Hypra-Load-Protokoll ausgeben AF06: LDY #$00 ; Zeiger auf aktuelles Datenbyte im Puffer LDA #$55 ; Synchronisationsbyte JSR P_AI ; $55 auf seriellem Bus senden AF07: LDA $0600,Y ; Byte aus Puffer holen JSR P_AI ; und auf seriellem Bus ausgeben INY ; Y auf nächstes Byte des Puffers richten BNE AF07 ; Rücksprung falls noch nicht letztes Datenbyte LDA $1C00 ; Floppy-LED umschalten EOR #$08 STA $1C00 AF08: LDA $0600 ; Letzter Sektor der Datei erreicht? BNE AF10 ; Sprung wenn nicht letzter Sektor AF09: JMP $FD9E ; Fehler $01 ("OK") zurückgeben AF10: CMP *$18 ; Mit Spurnummer im Header vergleichen BNE AF09 ; Sprung falls nicht aktuelle Spur STA *$06 ; Als Spur des nächsten Blocks speichern LDA $0601 ; Sektor des nächsten Blocks holen STA *$07 ; merken JMP P_AF ; Nächsten Sektor lesen ; Laderoutine im Floppy-Speicher P_AG: SEI LDA #$08 ; CLOCK auf low setzen ("nicht bereit") STA $1800 LDA *$18 ; Spurnummer des nächsten Datenblocks holen STA $0600 ; im ersten Byte des Datenpuffers speichern STA *$06 ; und als Spur für Puffer 0 LDA *$19 ; Sektornummer des nächsten Datenblocks holen STA $0601 ; im zweiten Byte des Datenpuffers speichern STA *$07 ; und als Sektor für Puffer 0 AG00: LDA #$04 ; Zähler für Kopfpositionierungen STA *$78 ; setzen LDA #$E2 ; Jobcode $Ex="Programm in Jobschleife einbinden" JSR P_AH ; Job in Puffer 0 (an Adresse $0300) ausführen CMP #$02 ; Rückmeldung="Kein Fehler aufgetreten"? BCC AG05 ; Sprung falls kein Fehler AG01: LDY #$00 ; Zähler für Kopfpositionierungen STY *$78 ; setzen AG02: LDY *$78 LDA $FEDB,Y ; Kopfbewegung bei Lesefehler BEQ AG03 ; Sprung falls keine weitere Bewegung CLI JSR $D676 ; Kopf um die im Akku angegebenen Halbspurschritte bewegen SEI LDA #$E2 ; Job $E2 ausführen JSR P_AH ; für Puffer an Adresse $0300 aufrufen CMP #$02 ; Rückmeldung="OK"? BCC AG05 ; Sprung falls kein Fehler INC *$78 ; Zähler für Kopfpositionierungen erhöhen BNE AG02 ; Sprung falls noch nicht 256 Versuche AG03: LDA #$C0 ; Job $C0 (Schreib-/Lesekopf auf Spur 0 fahren) ausführen JSR P_AH LDA #$E2 ; Job $E2 (Programm in Jobschleife einbinden) ausführen JSR P_AH ; für Puffer an Adresse $0300 aufrufen CMP #$02 ; Rückmeldung ="OK"? BCC AG05 ; Sprung falls kein Fehler LDA #$FF ; $FF senden ("LOAD ERROR") JSR P_AI AG04: JMP $EB22 ; Zeropage initialisieren AG05: LDA $0600 ; Spur des nächsten Datenblocks holen BEQ AG04 ; Sprung, falls letzter Datenblock erreicht CMP *$18 ; Nächster Datenblock in gleicher Spur? BEQ AG01 ; Sprung falls ja LDA $0600 ; Spur des nächsten Datenblocks nochmals holen (unnötig) STA *$06 ; und merken LDA $0601 ; Sektornummer des nächsten Datenblocks holen STA *$07 ; und merken JMP AG00 ; Neue Spur ansteuern und nächsten Datenblock einlesen ; Job <A> für Puffer 0 (Adresse $0300) ausführen lassen, Rückmeldung in A P_AH: STA *$00 ; Jobcode speichern CLI AH00: LDA *$00 ; Warten, bis Jobcode durch Rückmeldung ersetzt BMI AH00 SEI RTS ; Datenbyte aus <A> per Hypra-Load-Protokoll übertragen P_AI: STA *$77 ; Byte merken LDX #$01 ; Initialer Wert TXA ; A=1 AI00: BIT $1800 ; DATA testen BEQ AI00 ; Rücksprung falls high LDA #$00 ; CLOCK (und DATA) auf high ("bereit") STA $1800 ; setzen TXA ; A=1 AI01: BIT $1800 ; DATA testen BNE AI01 ; Rücksprung falls low LDX #$00 ; Initialer Wert TXA ; A=0 ROR *$77 ; Bit 0 des Datenbyte nach CF ROL A ROL A ROR *$77 ; Bit 1 des Datenbyte nach CF ROL A ROL A ; A=%0000x0y0, x=Bit 0, y=Bit 1 STA $1800 ; Bit 0 auf Clock, Bit 1 auf Data übertragen TXA ; A=0 ROR *$77 ; Bit 2 des Datenbyte nach CF ROL A ROL A ROR *$77 ; Bit 3 des Datenbyte nach CF ROL A ROL A ; A=%0000x0y0, x=Bit 2, y=Bit 3 STA $1800 ; Bit 2 auf CLOCK, Bit 3 auf DATA übertragen TXA ; A=0 ROR *$77 ; Bit 4 des Datenbyte nach CF ROL A ROL A ROR *$77 ; Bit 5 des Datenbyte nach CF ROL A ROL A ; A=%0000x0y0, x=Bit 4, y=Bit 5 STA $1800 ; Bit 4 auf Clock, Bit 5 auf DATA übertragen TXA ; A=0 ROR *$77 ; Bit 6 des Datenbyte nach CF ROL A ROL A ROR *$77 ; Bit 7 des Datenbyte nach CF ROL A ROL A ; A=%0000x0y0, x=Bit 6, y=Bit 7 STA $1800 ; Bit 6 auf CLOCK, Bit 7 auf DATA übertragen LDX #$02 ; Verzögerung AI02: DEX BNE AI02 LDA #$08 ; Stopbit: CLOCK auf low STA $1800 RTS
Initialisierung[Bearbeiten | Quelltext bearbeiten]
Die folgenden Routinen werden über den verbogegen CLALL-Vektor angesprungen und ausgeführt, sobald Hypra-Load vollständig geladen ist. Sie kopieren BASIC- und KERNAL-ROM des C64 in das darunterliegende RAM, deaktivieren dann die ROMs und übertragen die einzelnen Codeabschnitte von Hypra-Load an (hoffentlich) nicht benötigte Stellen des KERNAL-ROMs. Damit haben sie ihre Aufgabe erfüllt — durch den Aufruf des NEW-Befehls wird der von ihnen belegte Speicherplatz freigegeben, und üblicherweise von nächsten mittels Hypra-Load geladenen Programm überschrieben.
SOURCE2: ; Initialisierungscode ; Alle ROMs ins darunterliegende RAM kopieren P_AJ: LDY #<$A000 ; BASIC-ROM beginnt an Adresse $A000 STY *$61 LDA #>$A000 STA *$62 AJ00: LDA ($61),Y ; ROM auf sich selbst kopieren STA ($61),Y INC *$61 ; Low-Byte der Lese-/Schreibadresse erhöhen BNE AJ00 ; Rücksprung noch innerhalb der aktuelle Page INC *$62 ; High-Byte der Lese-Schreibadresse erhöhen BEQ AJ01 ; Sprung falls Ende des KERNAL-ROM erreicht LDA *$62 ; High-Byte der Lese-/Schreibadresse holen CMP #$C0 ; und mit Ende des BASIC-ROM vergleichen BNE AJ00 ; Sprung falls nicht Ende des BASIC-ROM LDA #$E0 ; Adresse auf Anfang des KERNAL-ROM setzen STA *$62 BNE AJ00 ; Immer zurückspringen ; Kopie des KERNAL-ROms patchen AJ01: LDA #$E5 ; ROMs ausgeschaltet, I/O sichtbar STA $FDD6 LDA #$4C ; JMP STA $F4F9+$00 ; Aus IEC-Load nach P_AB springen statt STOP-Taste abzufragen LDA #<P_AB STA $F4F9+$01 LDA #>P_AB STA $F4F9+$02 ; Datassetten-Routinen ab TARGET0=$F72C mit Codeblock SOURCE0 überschreiben LDX #$00 AJ02: LDA SOURCE0+$0000,X STA TARGET0+$0000,X INX BNE AJ02 AJ03: LDA SOURCE0+$0100,X STA TARGET0+$0100,X INX CPX #SOURCE0_LEN-$0100 BNE AJ03 ; RS232-Routinen ab BUFFER1=$EEBB mit Codeblock SOURCE1 überschreiben LDX #$00 AJ04: LDA SOURCE1+$0000,X STA BUFFER1+$0000,X INX BNE AJ04 AJ05: LDA SOURCE1+$0100,X STA BUFFER1+$0100,X INX CPX #SOURCE1_LEN-$0100 BNE AJ05 ; Default-Parameter für LOAD und SAVE setzen LDA #DRIVE ; Gerätenummer STA $E1DA ; als Default-LOAD/SAVE-Parameter setzen LDA #$01 ; Sekundäradresse STA $E1DC ; als Default-LOAD/SAVE-Parameter setzen LDA #$35 ; I/O und RAM einschalten STA *$01 LDY #$00 ; Lesezeiger für Dateinamen initialisieren LDA ($BB),Y ; Dateinamen zeichenweise lesen CMP #$5E ; und mit Pfeil nach oben vergleichen BEQ P_AK ; Sprung falls Pfeil nach oben gefunden ; Startmeldung anzeigen und zu BASIC zurückkehren, wenn kein Programm nachgeladen werden soll JSR $E453 ; BASIC-Vektoren laden JSR $E3BF ; RAM für BASIC initialisieren CLC JSR $FD15 ; Hardware und I/O Vektoren setzen LDA #<AJ06 LDY #>AJ06 JSR $AB1E ; String ausgeben JSR $A644 ; BASIC-Befehl NEW JMP $E39D ; Warmstart AJ06: DB $0D DB 'HYPRA-LOAD V2.1 (C) 1985 TRIBAR',$0D DB 'BORIS SCHNEIDER+KARSTEN SCHRAMM',$0D,$00 ; Autoload-Funktion P_AK: CLC LDA #$02 ; Um 2 Zeichen ADC *$BB ; den Zeiger auf den Dateinamen STA *$BB ; weiterbewegen BCC AK01 ; Sprung falls kein Additionsübertrag INC *$BC ; High-Byte des Zeigers auf den Dateinamen erhöhen AK01: DEC *$B7 ; Länge des Dateinamens um 2 vermindern DEC *$B7 NOP LDX #$00 ; AK02: LDA SOURCE3,X ; Routine P_AL an Adresse $02C0 umkopieren STA P_AL,X INX CPX #SOURCE3_LEN BNE AK02 JMP P_AL ; und ausführen
Nachlade-Routine[Bearbeiten | Quelltext bearbeiten]
Beim unmittelbaren Nachladen eines Programms wird der folgende Code an Adresse TARGET3=$02C0
umkopiert und dort ausgeführt. Dieses Umkopieren ist nötig, da vor dem Start des Ladevorgangs alle ROMs wieder aktiviert werden und dadurch die von Hypra-Load installierten Codeanschnitte anschließend unerreichbar sind.
SOURCE3: ; Unmittelbares Nachladen eines Programms P_AL: JSR $E453 ; BASIC-Vektoren laden JSR $E3BF ; RAM für BASIC initialisieren CLC JSR $FD15 ; Hardware und I/O Vektoren setzen JSR $A644 ; BASIC-Befehl NEW JSR $FFD5 ; BASIC-Befehl LOAD LDA #$37 ; I/O und alle ROMs einschalten STA *$01 LDA *$AE ; Programmende=Beginn der Variablen (low) STA *$2D LDA *$AF ; Programmende=Beginn der Variablen (high) STA *$2E JSR $A663 ; BASIC-Befehl CLR JSR $A68E ; Programmzeiger auf BASIC-Start JMP $A7AE ; Interpreterschleife DB $00,$31